Replace StatefulBaseRenderer inheritance with CanvasState member

Incrementally disentangles DisplayListRenderer and OpenGLRenderer.
Introduces abstract CanvasStateClient class to share three functions
between the two.

Design doc at https://docs.google.com/a/google.com/document/d/1PY1JF7AfPEF2UOUAnETS5j_4_tnJShTAMExvpCJfP8o/edit?usp=sharing.

BUG:15672762
R=djsollen@google.com,ccraik@google.com,jreck@google.com

Change-Id: Ic9fdffe18808e7d921ad06d01ea1ca25b2ad6f23
This commit is contained in:
Tom Hudson
2014-10-10 13:38:16 -04:00
parent a5545d24c7
commit 984162fb7e
10 changed files with 511 additions and 356 deletions

View File

@@ -25,10 +25,9 @@ ifeq ($(USE_OPENGL_RENDERER),true)
Animator.cpp \
AnimatorManager.cpp \
AssetAtlas.cpp \
DamageAccumulator.cpp \
FontRenderer.cpp \
GammaFontRenderer.cpp \
Caches.cpp \
CanvasState.cpp \
DamageAccumulator.cpp \
DisplayList.cpp \
DeferredDisplayList.cpp \
DeferredLayerUpdater.cpp \
@@ -38,6 +37,8 @@ ifeq ($(USE_OPENGL_RENDERER),true)
DrawProfiler.cpp \
Extensions.cpp \
FboCache.cpp \
FontRenderer.cpp \
GammaFontRenderer.cpp \
GradientCache.cpp \
Image.cpp \
Interpolator.cpp \
@@ -62,7 +63,6 @@ ifeq ($(USE_OPENGL_RENDERER),true)
SkiaShader.cpp \
Snapshot.cpp \
SpotShadow.cpp \
StatefulBaseRenderer.cpp \
Stencil.cpp \
TessellationCache.cpp \
Texture.cpp \

View File

@@ -14,41 +14,45 @@
* limitations under the License.
*/
#define LOG_TAG "OpenGLRenderer"
#include <SkCanvas.h>
#include "StatefulBaseRenderer.h"
#include "CanvasState.h"
#include "utils/MathUtils.h"
namespace android {
namespace uirenderer {
StatefulBaseRenderer::StatefulBaseRenderer()
CanvasState::CanvasState(CanvasStateClient& renderer)
: mDirtyClip(false)
, mWidth(-1)
, mHeight(-1)
, mSaveCount(1)
, mFirstSnapshot(new Snapshot)
, mCanvas(renderer)
, mSnapshot(mFirstSnapshot) {
}
void StatefulBaseRenderer::initializeSaveStack(float clipLeft, float clipTop,
CanvasState::~CanvasState() {
}
void CanvasState::initializeSaveStack(float clipLeft, float clipTop,
float clipRight, float clipBottom, const Vector3& lightCenter) {
mSnapshot = new Snapshot(mFirstSnapshot,
SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
mSnapshot->setClip(clipLeft, clipTop, clipRight, clipBottom);
mSnapshot->fbo = getTargetFbo();
mSnapshot->fbo = mCanvas.onGetTargetFbo();
mSnapshot->setRelativeLightCenter(lightCenter);
mSaveCount = 1;
}
void StatefulBaseRenderer::setViewport(int width, int height) {
void CanvasState::setViewport(int width, int height) {
mWidth = width;
mHeight = height;
mFirstSnapshot->initializeViewport(width, height);
onViewportInitialized();
mCanvas.onViewportInitialized();
// create a temporary 1st snapshot, so old snapshots are released,
// and viewport can be queried safely.
@@ -63,24 +67,24 @@ void StatefulBaseRenderer::setViewport(int width, int height) {
///////////////////////////////////////////////////////////////////////////////
/**
* Non-virtual implementation of save, guaranteed to save without side-effects
* Guaranteed to save without side-effects
*
* The approach here and in restoreSnapshot(), allows subclasses to directly manipulate the save
* This approach, here and in restoreSnapshot(), allows subclasses to directly manipulate the save
* stack, and ensures restoreToCount() doesn't call back into subclass overrides.
*/
int StatefulBaseRenderer::saveSnapshot(int flags) {
int CanvasState::saveSnapshot(int flags) {
mSnapshot = new Snapshot(mSnapshot, flags);
return mSaveCount++;
}
int StatefulBaseRenderer::save(int flags) {
int CanvasState::save(int flags) {
return saveSnapshot(flags);
}
/**
* Non-virtual implementation of restore, guaranteed to restore without side-effects.
* Guaranteed to restore without side-effects.
*/
void StatefulBaseRenderer::restoreSnapshot() {
void CanvasState::restoreSnapshot() {
sp<Snapshot> toRemove = mSnapshot;
sp<Snapshot> toRestore = mSnapshot->previous;
@@ -88,16 +92,16 @@ void StatefulBaseRenderer::restoreSnapshot() {
mSnapshot = toRestore;
// subclass handles restore implementation
onSnapshotRestored(*toRemove, *toRestore);
mCanvas.onSnapshotRestored(*toRemove, *toRestore);
}
void StatefulBaseRenderer::restore() {
void CanvasState::restore() {
if (mSaveCount > 1) {
restoreSnapshot();
}
}
void StatefulBaseRenderer::restoreToCount(int saveCount) {
void CanvasState::restoreToCount(int saveCount) {
if (saveCount < 1) saveCount = 1;
while (mSaveCount > saveCount) {
@@ -109,40 +113,40 @@ void StatefulBaseRenderer::restoreToCount(int saveCount) {
// Matrix
///////////////////////////////////////////////////////////////////////////////
void StatefulBaseRenderer::getMatrix(SkMatrix* matrix) const {
void CanvasState::getMatrix(SkMatrix* matrix) const {
mSnapshot->transform->copyTo(*matrix);
}
void StatefulBaseRenderer::translate(float dx, float dy, float dz) {
void CanvasState::translate(float dx, float dy, float dz) {
mSnapshot->transform->translate(dx, dy, dz);
}
void StatefulBaseRenderer::rotate(float degrees) {
void CanvasState::rotate(float degrees) {
mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f);
}
void StatefulBaseRenderer::scale(float sx, float sy) {
void CanvasState::scale(float sx, float sy) {
mSnapshot->transform->scale(sx, sy, 1.0f);
}
void StatefulBaseRenderer::skew(float sx, float sy) {
void CanvasState::skew(float sx, float sy) {
mSnapshot->transform->skew(sx, sy);
}
void StatefulBaseRenderer::setMatrix(const SkMatrix& matrix) {
void CanvasState::setMatrix(const SkMatrix& matrix) {
mSnapshot->transform->load(matrix);
}
void StatefulBaseRenderer::setMatrix(const Matrix4& matrix) {
void CanvasState::setMatrix(const Matrix4& matrix) {
mSnapshot->transform->load(matrix);
}
void StatefulBaseRenderer::concatMatrix(const SkMatrix& matrix) {
void CanvasState::concatMatrix(const SkMatrix& matrix) {
mat4 transform(matrix);
mSnapshot->transform->multiply(transform);
}
void StatefulBaseRenderer::concatMatrix(const Matrix4& matrix) {
void CanvasState::concatMatrix(const Matrix4& matrix) {
mSnapshot->transform->multiply(matrix);
}
@@ -150,7 +154,7 @@ void StatefulBaseRenderer::concatMatrix(const Matrix4& matrix) {
// Clip
///////////////////////////////////////////////////////////////////////////////
bool StatefulBaseRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
bool CanvasState::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
if (CC_LIKELY(currentTransform()->rectToRect())) {
mDirtyClip |= mSnapshot->clip(left, top, right, bottom, op);
return !mSnapshot->clipRect->isEmpty();
@@ -159,10 +163,10 @@ bool StatefulBaseRenderer::clipRect(float left, float top, float right, float bo
SkPath path;
path.addRect(left, top, right, bottom);
return StatefulBaseRenderer::clipPath(&path, op);
return CanvasState::clipPath(&path, op);
}
bool StatefulBaseRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
bool CanvasState::clipPath(const SkPath* path, SkRegion::Op op) {
SkMatrix transform;
currentTransform()->copyTo(transform);
@@ -189,12 +193,12 @@ bool StatefulBaseRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
return !mSnapshot->clipRect->isEmpty();
}
bool StatefulBaseRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
bool CanvasState::clipRegion(const SkRegion* region, SkRegion::Op op) {
mDirtyClip |= mSnapshot->clipRegionTransformed(*region, op);
return !mSnapshot->clipRect->isEmpty();
}
void StatefulBaseRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
void CanvasState::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
Rect bounds;
float radius;
if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported
@@ -209,7 +213,7 @@ void StatefulBaseRenderer::setClippingOutline(LinearAllocator& allocator, const
}
}
void StatefulBaseRenderer::setClippingRoundRect(LinearAllocator& allocator,
void CanvasState::setClippingRoundRect(LinearAllocator& allocator,
const Rect& rect, float radius, bool highPriority) {
mSnapshot->setClippingRoundRect(allocator, rect, radius, highPriority);
}
@@ -229,7 +233,7 @@ void StatefulBaseRenderer::setClippingRoundRect(LinearAllocator& allocator,
* @param snapOut if set, the geometry will be treated as having an AA ramp.
* See Rect::snapGeometryToPixelBoundaries()
*/
bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top,
bool CanvasState::calculateQuickRejectForScissor(float left, float top,
float right, float bottom,
bool* clipRequired, bool* roundRectClipRequired,
bool snapOut) const {
@@ -259,18 +263,7 @@ bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top,
return false;
}
/**
* Returns false if drawing won't be clipped out.
*
* Makes the decision conservatively, by rounding out the mapped rect before comparing with the
* clipRect. To be used when perfect, pixel accuracy is not possible (esp. with tessellation) but
* rejection is still desired.
*
* This function, unlike quickRejectSetupScissor, should be used where precise geometry information
* isn't known (esp. when geometry adjusts based on scale). Generally, this will be first pass
* rejection where precise rejection isn't important, or precise information isn't available.
*/
bool StatefulBaseRenderer::quickRejectConservative(float left, float top,
bool CanvasState::quickRejectConservative(float left, float top,
float right, float bottom) const {
if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
return true;
@@ -288,5 +281,5 @@ bool StatefulBaseRenderer::quickRejectConservative(float left, float top,
return false;
}
}; // namespace uirenderer
}; // namespace android
} // namespace uirenderer
} // namespace android

196
libs/hwui/CanvasState.h Normal file
View File

@@ -0,0 +1,196 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_HWUI_CANVAS_STATE_H
#define ANDROID_HWUI_CANVAS_STATE_H
#include <SkMatrix.h>
#include <SkPath.h>
#include <SkRegion.h>
#include "Snapshot.h"
namespace android {
namespace uirenderer {
/**
* Abstract base class for any class containing CanvasState.
* Defines three mandatory callbacks.
*/
class CanvasStateClient {
public:
CanvasStateClient() { }
virtual ~CanvasStateClient() { }
/**
* Callback allowing embedder to take actions in the middle of a
* setViewport() call.
*/
virtual void onViewportInitialized() = 0;
/**
* Callback allowing embedder to take actions in the middle of a
* restore() call. May be called several times sequentially.
*/
virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) = 0;
/**
* Allows subclasses to control what value is stored in snapshot's
* fbo field in * initializeSaveStack.
*/
virtual GLuint onGetTargetFbo() const = 0;
}; // class CanvasStateClient
/**
* Implements Canvas state methods on behalf of Renderers.
*
* Manages the Snapshot stack, implementing matrix, save/restore, and clipping methods in the
* Renderer interface. Drawing and recording classes that include a CanvasState will have
* different use cases:
*
* Drawing subclasses (i.e. OpenGLRenderer) can query attributes (such as transform) or hook into
* changes (e.g. save/restore) with minimal surface area for manipulating the stack itself.
*
* Recording subclasses (i.e. DisplayListRenderer) can both record and pass through state operations
* to CanvasState, so that not only will querying operations work (getClip/Matrix), but so
* that quickRejection can also be used.
*/
class CanvasState {
public:
CanvasState(CanvasStateClient& renderer);
~CanvasState();
/**
* Initializes the first snapshot, computing the projection matrix,
* and stores the dimensions of the render target.
*/
void initializeSaveStack(float clipLeft, float clipTop, float clipRight, float clipBottom,
const Vector3& lightCenter);
void setViewport(int width, int height);
bool hasRectToRectTransform() const {
return CC_LIKELY(currentTransform()->rectToRect());
}
// Save (layer)
int getSaveCount() const { return mSaveCount; }
int save(int flags);
void restore();
void restoreToCount(int saveCount);
// Save/Restore without side-effects
int saveSnapshot(int flags);
void restoreSnapshot();
// Matrix
void getMatrix(SkMatrix* outMatrix) const;
void translate(float dx, float dy, float dz = 0.0f);
void rotate(float degrees);
void scale(float sx, float sy);
void skew(float sx, float sy);
void setMatrix(const SkMatrix& matrix);
void setMatrix(const Matrix4& matrix); // internal only convenience method
void concatMatrix(const SkMatrix& matrix);
void concatMatrix(const Matrix4& matrix); // internal only convenience method
// Clip
const Rect& getLocalClipBounds() const { return mSnapshot->getLocalClip(); }
const Rect& getRenderTargetClipBounds() const { return mSnapshot->getRenderTargetClip(); }
bool quickRejectConservative(float left, float top, float right, float bottom) const;
bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
bool clipPath(const SkPath* path, SkRegion::Op op);
bool clipRegion(const SkRegion* region, SkRegion::Op op);
bool isCurrentClipSimple() const {
return currentSnapshot()->clipRegion->isEmpty();
}
/**
* Sets a "clipping outline", which is independent from the regular clip.
* Currently only supports rectangles or rounded rectangles; passing in a
* more complicated outline fails silently. Replaces any previous clipping
* outline.
*/
void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
void setClippingRoundRect(LinearAllocator& allocator,
const Rect& rect, float radius, bool highPriority = true);
/**
* Returns true if drawing in the rectangle (left, top, right, bottom)
* will be clipped out. Is conservative: might return false when subpixel-
* perfect tests would return true.
*/
bool calculateQuickRejectForScissor(float left, float top, float right, float bottom,
bool* clipRequired, bool* roundRectClipRequired, bool snapOut) const;
void setDirtyClip(bool opaque) { mDirtyClip = opaque; }
bool getDirtyClip() const { return mDirtyClip; }
void scaleAlpha(float alpha) { mSnapshot->alpha *= alpha; }
void setEmpty(bool value) { mSnapshot->empty = value; }
void setInvisible(bool value) { mSnapshot->invisible = value; }
inline const mat4* currentTransform() const { return currentSnapshot()->transform; }
inline const Rect* currentClipRect() const { return currentSnapshot()->clipRect; }
inline Region* currentRegion() const { return currentSnapshot()->region; }
inline int currentFlags() const { return currentSnapshot()->flags; }
const Vector3& currentLightCenter() const { return currentSnapshot()->getRelativeLightCenter(); }
inline bool currentlyIgnored() const { return currentSnapshot()->isIgnored(); }
int getViewportWidth() const { return currentSnapshot()->getViewportWidth(); }
int getViewportHeight() const { return currentSnapshot()->getViewportHeight(); }
int getWidth() { return mWidth; }
int getHeight() { return mHeight; }
inline const Snapshot* currentSnapshot() const {
return mSnapshot != NULL ? mSnapshot.get() : mFirstSnapshot.get();
}
inline Snapshot* writableSnapshot() { return mSnapshot.get(); }
inline const Snapshot* firstSnapshot() const { return mFirstSnapshot.get(); }
private:
/// No default constructor - must supply a CanvasStateClient (mCanvas).
CanvasState();
/// indicates that the clip has been changed since the last time it was consumed
bool mDirtyClip;
/// Dimensions of the drawing surface
int mWidth, mHeight;
/// Number of saved states
int mSaveCount;
/// Base state
sp<Snapshot> mFirstSnapshot;
/// Host providing callbacks
CanvasStateClient& mCanvas;
/// Current state
sp<Snapshot> mSnapshot;
}; // class CanvasState
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_HWUI_CANVAS_STATE_H

View File

@@ -32,7 +32,8 @@ namespace android {
namespace uirenderer {
DisplayListRenderer::DisplayListRenderer()
: mCaches(Caches::getInstance())
: mState(*this)
, mCaches(Caches::getInstance())
, mDisplayListData(NULL)
, mTranslateX(0.0f)
, mTranslateY(0.0f)
@@ -66,10 +67,10 @@ void DisplayListRenderer::prepareDirty(float left, float top,
"prepareDirty called a second time during a recording!");
mDisplayListData = new DisplayListData();
initializeSaveStack(0, 0, getWidth(), getHeight(), Vector3());
mState.initializeSaveStack(0, 0, mState.getWidth(), mState.getHeight(), Vector3());
mDeferredBarrierType = kBarrier_InOrder;
mDirtyClip = opaque;
mState.setDirtyClip(opaque);
mRestoreSaveCount = -1;
}
@@ -93,7 +94,7 @@ void DisplayListRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) {
int DisplayListRenderer::save(int flags) {
addStateOp(new (alloc()) SaveOp(flags));
return StatefulBaseRenderer::save(flags);
return mState.save(flags);
}
void DisplayListRenderer::restore() {
@@ -104,13 +105,13 @@ void DisplayListRenderer::restore() {
mRestoreSaveCount--;
flushTranslate();
StatefulBaseRenderer::restore();
mState.restore();
}
void DisplayListRenderer::restoreToCount(int saveCount) {
mRestoreSaveCount = saveCount;
flushTranslate();
StatefulBaseRenderer::restoreToCount(saveCount);
mState.restoreToCount(saveCount);
}
int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom,
@@ -120,7 +121,7 @@ int DisplayListRenderer::saveLayer(float left, float top, float right, float bot
paint = refPaint(paint);
addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, paint, flags));
return StatefulBaseRenderer::save(flags);
return mState.save(flags);
}
void DisplayListRenderer::translate(float dx, float dy, float dz) {
@@ -129,50 +130,50 @@ void DisplayListRenderer::translate(float dx, float dy, float dz) {
mTranslateX += dx;
mTranslateY += dy;
flushRestoreToCount();
StatefulBaseRenderer::translate(dx, dy, dz);
mState.translate(dx, dy, dz);
}
void DisplayListRenderer::rotate(float degrees) {
addStateOp(new (alloc()) RotateOp(degrees));
StatefulBaseRenderer::rotate(degrees);
mState.rotate(degrees);
}
void DisplayListRenderer::scale(float sx, float sy) {
addStateOp(new (alloc()) ScaleOp(sx, sy));
StatefulBaseRenderer::scale(sx, sy);
mState.scale(sx, sy);
}
void DisplayListRenderer::skew(float sx, float sy) {
addStateOp(new (alloc()) SkewOp(sx, sy));
StatefulBaseRenderer::skew(sx, sy);
mState.skew(sx, sy);
}
void DisplayListRenderer::setMatrix(const SkMatrix& matrix) {
addStateOp(new (alloc()) SetMatrixOp(matrix));
StatefulBaseRenderer::setMatrix(matrix);
mState.setMatrix(matrix);
}
void DisplayListRenderer::concatMatrix(const SkMatrix& matrix) {
addStateOp(new (alloc()) ConcatMatrixOp(matrix));
StatefulBaseRenderer::concatMatrix(matrix);
mState.concatMatrix(matrix);
}
bool DisplayListRenderer::clipRect(float left, float top, float right, float bottom,
SkRegion::Op op) {
addStateOp(new (alloc()) ClipRectOp(left, top, right, bottom, op));
return StatefulBaseRenderer::clipRect(left, top, right, bottom, op);
return mState.clipRect(left, top, right, bottom, op);
}
bool DisplayListRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
path = refPath(path);
addStateOp(new (alloc()) ClipPathOp(path, op));
return StatefulBaseRenderer::clipPath(path, op);
return mState.clipPath(path, op);
}
bool DisplayListRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
region = refRegion(region);
addStateOp(new (alloc()) ClipRegionOp(region, op));
return StatefulBaseRenderer::clipRegion(region, op);
return mState.clipRegion(region, op);
}
void DisplayListRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t flags) {
@@ -180,7 +181,7 @@ void DisplayListRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, in
// dirty is an out parameter and should not be recorded,
// it matters only when replaying the display list
DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(renderNode, flags, *currentTransform());
DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(renderNode, flags, *mState.currentTransform());
addRenderNodeOp(op);
}

View File

@@ -25,9 +25,11 @@
#include <SkTLazy.h>
#include <cutils/compiler.h>
#include "CanvasState.h"
#include "DisplayList.h"
#include "DisplayListLogBuffer.h"
#include "StatefulBaseRenderer.h"
#include "RenderNode.h"
#include "Renderer.h"
namespace android {
namespace uirenderer {
@@ -57,7 +59,7 @@ class StateOp;
/**
* Records drawing commands in a display list for later playback into an OpenGLRenderer.
*/
class ANDROID_API DisplayListRenderer: public StatefulBaseRenderer {
class ANDROID_API DisplayListRenderer: public Renderer, public CanvasStateClient {
public:
DisplayListRenderer();
virtual ~DisplayListRenderer();
@@ -70,6 +72,9 @@ public:
// Frame state operations
// ----------------------------------------------------------------------------
virtual void prepareDirty(float left, float top, float right, float bottom, bool opaque);
virtual void prepare(bool opaque) {
prepareDirty(0.0f, 0.0f, mState.getWidth(), mState.getHeight(), opaque);
}
virtual bool finish();
virtual void interrupt();
virtual void resume();
@@ -77,7 +82,10 @@ public:
// ----------------------------------------------------------------------------
// Canvas state operations
// ----------------------------------------------------------------------------
virtual void setViewport(int width, int height) { mState.setViewport(width, height); }
// Save (layer)
virtual int getSaveCount() const { return mState.getSaveCount(); }
virtual int save(int flags);
virtual void restore();
virtual void restoreToCount(int saveCount);
@@ -85,6 +93,8 @@ public:
const SkPaint* paint, int flags);
// Matrix
virtual void getMatrix(SkMatrix* outMatrix) const { mState.getMatrix(outMatrix); }
virtual void translate(float dx, float dy, float dz = 0.0f);
virtual void rotate(float degrees);
virtual void scale(float sx, float sy);
@@ -100,9 +110,14 @@ public:
// Misc
virtual void setDrawFilter(SkDrawFilter* filter);
virtual const Rect& getLocalClipBounds() const { return mState.getLocalClipBounds(); }
const Rect& getRenderTargetClipBounds() const { return mState.getRenderTargetClipBounds(); }
virtual bool quickRejectConservative(float left, float top, float right, float bottom) const {
return mState.quickRejectConservative(left, top, right, bottom);
}
bool isCurrentTransformSimple() {
return currentTransform()->isSimple();
return mState.currentTransform()->isSimple();
}
// ----------------------------------------------------------------------------
@@ -163,7 +178,18 @@ public:
void setHighContrastText(bool highContrastText) {
mHighContrastText = highContrastText;
}
// ----------------------------------------------------------------------------
// CanvasState callbacks
// ----------------------------------------------------------------------------
virtual void onViewportInitialized() { }
virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) { }
virtual GLuint onGetTargetFbo() const { return -1; }
private:
CanvasState mState;
enum DeferredBarrierType {
kBarrier_None,
kBarrier_InOrder,

View File

@@ -91,7 +91,7 @@ bool LayerRenderer::finish() {
return retval;
}
GLuint LayerRenderer::getTargetFbo() const {
GLuint LayerRenderer::onGetTargetFbo() const {
return mLayer->getFbo();
}
@@ -116,7 +116,7 @@ void LayerRenderer::ensureStencilBuffer() {
///////////////////////////////////////////////////////////////////////////////
Region* LayerRenderer::getRegion() const {
if (currentSnapshot()->flags & Snapshot::kFlagFboTarget) {
if (mState.currentFlags() & Snapshot::kFlagFboTarget) {
return OpenGLRenderer::getRegion();
}
return &mLayer->region;

View File

@@ -68,7 +68,7 @@ protected:
virtual void ensureStencilBuffer();
virtual bool hasLayer() const;
virtual Region* getRegion() const;
virtual GLuint getTargetFbo() const;
virtual GLuint onGetTargetFbo() const;
virtual bool suppressErrorChecks() const;
private:

View File

@@ -147,7 +147,8 @@ static inline T min(T a, T b) {
///////////////////////////////////////////////////////////////////////////////
OpenGLRenderer::OpenGLRenderer(RenderState& renderState)
: mFrameStarted(false)
: mState(*this)
, mFrameStarted(false)
, mCaches(Caches::getInstance())
, mExtensions(Extensions::getInstance())
, mRenderState(renderState)
@@ -205,7 +206,7 @@ void OpenGLRenderer::onViewportInitialized() {
void OpenGLRenderer::setupFrameState(float left, float top,
float right, float bottom, bool opaque) {
mCaches.clearGarbage();
initializeSaveStack(left, top, right, bottom, mLightCenter);
mState.initializeSaveStack(left, top, right, bottom, mLightCenter);
mOpaque = opaque;
mTilingClip.set(left, top, right, bottom);
}
@@ -214,11 +215,11 @@ void OpenGLRenderer::startFrame() {
if (mFrameStarted) return;
mFrameStarted = true;
mDirtyClip = true;
mState.setDirtyClip(true);
discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom);
mRenderState.setViewport(getWidth(), getHeight());
mRenderState.setViewport(mState.getWidth(), mState.getHeight());
// Functors break the tiling extension in pretty spectacular ways
// This ensures we don't use tiling when a functor is going to be
@@ -257,8 +258,8 @@ void OpenGLRenderer::discardFramebuffer(float left, float top, float right, floa
// perform a discard to let the driver know we don't need to preserve
// the back buffer for this frame.
if (mExtensions.hasDiscardFramebuffer() &&
left <= 0.0f && top <= 0.0f && right >= getWidth() && bottom >= getHeight()) {
const bool isFbo = getTargetFbo() == 0;
left <= 0.0f && top <= 0.0f && right >= mState.getWidth() && bottom >= mState.getHeight()) {
const bool isFbo = onGetTargetFbo() == 0;
const GLenum attachments[] = {
isFbo ? (const GLenum) GL_COLOR_EXT : (const GLenum) GL_COLOR_ATTACHMENT0,
isFbo ? (const GLenum) GL_STENCIL_EXT : (const GLenum) GL_STENCIL_ATTACHMENT };
@@ -329,7 +330,7 @@ bool OpenGLRenderer::finish() {
// When finish() is invoked on FBO 0 we've reached the end
// of the current frame
if (getTargetFbo() == 0) {
if (onGetTargetFbo() == 0) {
mCaches.pathCache.trim();
mCaches.tessellationCache.trim();
}
@@ -363,9 +364,9 @@ void OpenGLRenderer::resumeAfterLayer() {
}
void OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
if (currentSnapshot()->isIgnored()) return;
if (mState.currentlyIgnored()) return;
Rect clip(*currentClipRect());
Rect clip(*mState.currentClipRect());
clip.snapToPixelBoundaries();
// Since we don't know what the functor will draw, let's dirty
@@ -384,9 +385,9 @@ void OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
info.height = getViewportHeight();
currentTransform()->copyTo(&info.transform[0]);
bool prevDirtyClip = mDirtyClip;
bool prevDirtyClip = mState.getDirtyClip();
// setup GL state for functor
if (mDirtyClip) {
if (mState.getDirtyClip()) {
setStencilFromClip(); // can issue draws, so must precede enableScissor()/interrupt()
}
if (mCaches.enableScissor() || prevDirtyClip) {
@@ -436,11 +437,11 @@ void OpenGLRenderer::debugOverdraw(bool enable, bool clear) {
}
void OpenGLRenderer::renderOverdraw() {
if (mCaches.debugOverdraw && getTargetFbo() == 0) {
if (mCaches.debugOverdraw && onGetTargetFbo() == 0) {
const Rect* clip = &mTilingClip;
mCaches.enableScissor();
mCaches.setScissor(clip->left, firstSnapshot()->getViewportHeight() - clip->bottom,
mCaches.setScissor(clip->left, mState.firstSnapshot()->getViewportHeight() - clip->bottom,
clip->right - clip->left, clip->bottom - clip->top);
// 1x overdraw
@@ -519,7 +520,7 @@ void OpenGLRenderer::updateLayers() {
if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
mLayerUpdates.clear();
mRenderState.bindFramebuffer(getTargetFbo());
mRenderState.bindFramebuffer(onGetTargetFbo());
}
endMark();
}
@@ -546,7 +547,7 @@ void OpenGLRenderer::flushLayers() {
}
mLayerUpdates.clear();
mRenderState.bindFramebuffer(getTargetFbo());
mRenderState.bindFramebuffer(onGetTargetFbo());
endMark();
}
@@ -628,9 +629,9 @@ int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
// force matrix/clip isolation for layer
flags |= SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag;
const int count = saveSnapshot(flags);
const int count = mState.saveSnapshot(flags);
if (!currentSnapshot()->isIgnored()) {
if (!mState.currentlyIgnored()) {
createLayer(left, top, right, bottom, paint, flags, convexMask);
}
@@ -643,7 +644,7 @@ void OpenGLRenderer::calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool
currentTransform()->mapRect(bounds);
// Layers only make sense if they are in the framebuffer's bounds
if (bounds.intersect(*currentClipRect())) {
if (bounds.intersect(*mState.currentClipRect())) {
// We cannot work with sub-pixels in this case
bounds.snapToPixelBoundaries();
@@ -677,17 +678,17 @@ void OpenGLRenderer::updateSnapshotIgnoreForLayer(const Rect& bounds, const Rect
if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize ||
bounds.getHeight() > mCaches.maxTextureSize ||
(fboLayer && clip.isEmpty())) {
mSnapshot->empty = fboLayer;
writableSnapshot()->empty = fboLayer;
} else {
mSnapshot->invisible = mSnapshot->invisible || (alpha <= 0 && fboLayer);
writableSnapshot()->invisible = writableSnapshot()->invisible || (alpha <= 0 && fboLayer);
}
}
int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float bottom,
const SkPaint* paint, int flags) {
const int count = saveSnapshot(flags);
const int count = mState.saveSnapshot(flags);
if (!currentSnapshot()->isIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) {
if (!mState.currentlyIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) {
// initialize the snapshot as though it almost represents an FBO layer so deferred draw
// operations will be able to store and restore the current clip and transform info, and
// quick rejection will be correct (for display lists)
@@ -697,11 +698,11 @@ int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float
calculateLayerBoundsAndClip(bounds, clip, true);
updateSnapshotIgnoreForLayer(bounds, clip, true, getAlphaDirect(paint));
if (!currentSnapshot()->isIgnored()) {
mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
mSnapshot->roundRectClipState = NULL;
if (!mState.currentlyIgnored()) {
writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f);
writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom);
writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight());
writableSnapshot()->roundRectClipState = NULL;
}
}
@@ -773,7 +774,7 @@ bool OpenGLRenderer::createLayer(float left, float top, float right, float botto
updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, getAlphaDirect(paint));
// Bail out if we won't draw in this snapshot
if (currentSnapshot()->isIgnored()) {
if (mState.currentlyIgnored()) {
return false;
}
@@ -793,8 +794,8 @@ bool OpenGLRenderer::createLayer(float left, float top, float right, float botto
layer->setConvexMask(convexMask); // note: the mask must be cleared before returning to the cache
// Save the layer in the snapshot
mSnapshot->flags |= Snapshot::kFlagIsLayer;
mSnapshot->layer = layer;
writableSnapshot()->flags |= Snapshot::kFlagIsLayer;
writableSnapshot()->layer = layer;
ATRACE_FORMAT_BEGIN("%ssaveLayer %ux%u",
fboLayer ? "" : "unclipped ",
@@ -832,13 +833,13 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
layer->clipRect.set(clip);
layer->setFbo(mCaches.fboCache.get());
mSnapshot->region = &mSnapshot->layer->region;
mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
mSnapshot->fbo = layer->getFbo();
mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
mSnapshot->roundRectClipState = NULL;
writableSnapshot()->region = &writableSnapshot()->layer->region;
writableSnapshot()->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
writableSnapshot()->fbo = layer->getFbo();
writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f);
writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom);
writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight());
writableSnapshot()->roundRectClipState = NULL;
endTiling();
debugOverdraw(false, false);
@@ -885,7 +886,7 @@ void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& resto
const bool fboLayer = removed.flags & Snapshot::kFlagIsFboLayer;
bool clipRequired = false;
calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom,
mState.calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom,
&clipRequired, NULL, false); // safely ignore return, should never be rejected
mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
@@ -930,7 +931,7 @@ void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& resto
save(0);
// the layer contains screen buffer content that shouldn't be alpha modulated
// (and any necessary alpha modulation was handled drawing into the layer)
mSnapshot->alpha = 1.0f;
writableSnapshot()->alpha = 1.0f;
composeLayerRect(layer, rect, true);
restore();
}
@@ -1038,13 +1039,13 @@ void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap)
* operations are correctly counted twice for overdraw. NOTE: assumes composeLayerRegion only used
* by saveLayer's restore
*/
#define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) { \
DRAW_COMMAND; \
if (CC_UNLIKELY(mCaches.debugOverdraw && getTargetFbo() == 0 && COND)) { \
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); \
DRAW_COMMAND; \
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); \
} \
#define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) { \
DRAW_COMMAND; \
if (CC_UNLIKELY(mCaches.debugOverdraw && onGetTargetFbo() == 0 && COND)) { \
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); \
DRAW_COMMAND; \
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); \
} \
}
#define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND)
@@ -1273,7 +1274,7 @@ void OpenGLRenderer::dirtyLayer(const float left, const float top,
}
void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
if (bounds.intersect(*currentClipRect())) {
if (bounds.intersect(*mState.currentClipRect())) {
bounds.snapToPixelBoundaries();
android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
if (!dirty.isEmpty()) {
@@ -1301,7 +1302,7 @@ void OpenGLRenderer::clearLayerRegions() {
const size_t count = mLayers.size();
if (count == 0) return;
if (!currentSnapshot()->isIgnored()) {
if (!mState.currentlyIgnored()) {
EVENT_LOGD("clearLayerRegions");
// Doing several glScissor/glClear here can negatively impact
// GPUs with a tiler architecture, instead we draw quads with
@@ -1357,7 +1358,7 @@ void OpenGLRenderer::clearLayerRegions() {
///////////////////////////////////////////////////////////////////////////////
bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) {
const Rect* currentClip = currentClipRect();
const Rect* currentClip = mState.currentClipRect();
const mat4* currentMatrix = currentTransform();
if (stateDeferFlags & kStateDeferFlag_Draw) {
@@ -1410,12 +1411,12 @@ bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDef
void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) {
setMatrix(state.mMatrix);
mSnapshot->alpha = state.mAlpha;
writableSnapshot()->alpha = state.mAlpha;
mDrawModifiers = state.mDrawModifiers;
mSnapshot->roundRectClipState = state.mRoundRectClipState;
writableSnapshot()->roundRectClipState = state.mRoundRectClipState;
if (state.mClipValid && !skipClipRestore) {
mSnapshot->setClip(state.mClip.left, state.mClip.top,
writableSnapshot()->setClip(state.mClip.left, state.mClip.top,
state.mClip.right, state.mClip.bottom);
dirtyClip();
}
@@ -1430,9 +1431,9 @@ void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool
*/
void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) {
if (clipRect != NULL) {
mSnapshot->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
writableSnapshot()->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
} else {
mSnapshot->setClip(0, 0, getWidth(), getHeight());
writableSnapshot()->setClip(0, 0, mState.getWidth(), mState.getHeight());
}
dirtyClip();
mCaches.setScissorEnabled(clipRect != NULL || mScissorOptimizationDisabled);
@@ -1443,12 +1444,12 @@ void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) {
///////////////////////////////////////////////////////////////////////////////
void OpenGLRenderer::setScissorFromClip() {
Rect clip(*currentClipRect());
Rect clip(*mState.currentClipRect());
clip.snapToPixelBoundaries();
if (mCaches.setScissor(clip.left, getViewportHeight() - clip.bottom,
clip.getWidth(), clip.getHeight())) {
mDirtyClip = false;
mState.setDirtyClip(false);
}
}
@@ -1484,7 +1485,7 @@ void OpenGLRenderer::setStencilFromClip() {
// NOTE: The order here is important, we must set dirtyClip to false
// before any draw call to avoid calling back into this method
mDirtyClip = false;
mState.setDirtyClip(false);
ensureStencilBuffer();
@@ -1553,7 +1554,7 @@ bool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right,
bool clipRequired = false;
bool roundRectClipRequired = false;
if (calculateQuickRejectForScissor(left, top, right, bottom,
if (mState.calculateQuickRejectForScissor(left, top, right, bottom,
&clipRequired, &roundRectClipRequired, snapOut)) {
return true;
}
@@ -1585,7 +1586,7 @@ void OpenGLRenderer::setupDraw(bool clearLayer) {
if (clearLayer) clearLayerRegions();
// Make sure setScissor & setStencil happen at the beginning of
// this method
if (mDirtyClip) {
if (mState.getDirtyClip()) {
if (mCaches.scissorEnabled) {
setScissorFromClip();
}
@@ -1723,7 +1724,7 @@ void OpenGLRenderer::setupDrawProgram() {
useProgram(mCaches.programCache.get(mDescription));
if (mDescription.hasRoundRectClip) {
// TODO: avoid doing this repeatedly, stashing state pointer in program
const RoundRectClipState* state = mSnapshot->roundRectClipState;
const RoundRectClipState* state = writableSnapshot()->roundRectClipState;
const Rect& innerRect = state->innerRect;
glUniform4f(mCaches.currentProgram->getUniform("roundRectInnerRectLTRB"),
innerRect.left, innerRect.top,
@@ -1751,7 +1752,7 @@ void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset,
bool dirty = right - left > 0.0f && bottom - top > 0.0f;
const Matrix4& transformMatrix = ignoreTransform ? Matrix4::identity() : *currentTransform();
mCaches.currentProgram->set(mSnapshot->getOrthoMatrix(), mModelViewMatrix, transformMatrix, offset);
mCaches.currentProgram->set(writableSnapshot()->getOrthoMatrix(), mModelViewMatrix, transformMatrix, offset);
if (dirty && mTrackDirtyRegions) {
if (!ignoreTransform) {
dirtyLayer(left, top, right, bottom, *currentTransform());
@@ -1942,7 +1943,7 @@ void OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t
return;
}
DeferredDisplayList deferredList(*currentClipRect());
DeferredDisplayList deferredList(*mState.currentClipRect());
DeferStateStruct deferStruct(deferredList, *this, replayFlags);
renderNode->defer(deferStruct, 0);
@@ -2056,7 +2057,7 @@ void OpenGLRenderer::drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint
void OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors, const SkPaint* paint) {
if (!vertices || currentSnapshot()->isIgnored()) {
if (!vertices || mState.currentlyIgnored()) {
return;
}
@@ -2369,7 +2370,7 @@ void OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
setupDraw();
setupDrawNoTexture();
if (isAA) setupDrawVertexAlpha((displayFlags & kVertexBuffer_ShadowInterp));
setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
setupDrawColor(color, ((color >> 24) & 0xFF) * writableSnapshot()->alpha);
setupDrawColorFilter(getColorFilter(paint));
setupDrawShader(getShader(paint));
setupDrawBlending(paint, isAA);
@@ -2445,7 +2446,7 @@ void OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint) {
* memory transfer by removing need for degenerate vertices.
*/
void OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* paint) {
if (currentSnapshot()->isIgnored() || count < 4) return;
if (mState.currentlyIgnored() || count < 4) return;
count &= ~0x3; // round down to nearest four
@@ -2462,7 +2463,7 @@ void OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* pa
}
void OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
if (currentSnapshot()->isIgnored() || count < 2) return;
if (mState.currentlyIgnored() || count < 2) return;
count &= ~0x1; // round down to nearest two
@@ -2482,9 +2483,9 @@ void OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* p
void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
// No need to check against the clip, we fill the clip region
if (currentSnapshot()->isIgnored()) return;
if (mState.currentlyIgnored()) return;
Rect clip(*currentClipRect());
Rect clip(*mState.currentClipRect());
clip.snapToPixelBoundaries();
SkPaint paint;
@@ -2511,7 +2512,7 @@ void OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture
void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
float rx, float ry, const SkPaint* p) {
if (currentSnapshot()->isIgnored()
if (mState.currentlyIgnored()
|| quickRejectSetupScissor(left, top, right, bottom, p)
|| paintWillNotDraw(*p)) {
return;
@@ -2530,7 +2531,7 @@ void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bot
}
void OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) {
if (currentSnapshot()->isIgnored()
if (mState.currentlyIgnored()
|| quickRejectSetupScissor(x - radius, y - radius, x + radius, y + radius, p)
|| paintWillNotDraw(*p)) {
return;
@@ -2552,7 +2553,7 @@ void OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p
void OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
const SkPaint* p) {
if (currentSnapshot()->isIgnored()
if (mState.currentlyIgnored()
|| quickRejectSetupScissor(left, top, right, bottom, p)
|| paintWillNotDraw(*p)) {
return;
@@ -2575,7 +2576,7 @@ void OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
void OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
float startAngle, float sweepAngle, bool useCenter, const SkPaint* p) {
if (currentSnapshot()->isIgnored()
if (mState.currentlyIgnored()
|| quickRejectSetupScissor(left, top, right, bottom, p)
|| paintWillNotDraw(*p)) {
return;
@@ -2610,7 +2611,7 @@ void OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
void OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
const SkPaint* p) {
if (currentSnapshot()->isIgnored()
if (mState.currentlyIgnored()
|| quickRejectSetupScissor(left, top, right, bottom, p)
|| paintWillNotDraw(*p)) {
return;
@@ -2669,7 +2670,7 @@ void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
const float sx = x - shadow->left + textShadow.dx;
const float sy = y - shadow->top + textShadow.dy;
const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * mSnapshot->alpha;
const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * writableSnapshot()->alpha;
if (getShader(paint)) {
textShadow.color = SK_ColorWHITE;
}
@@ -2693,13 +2694,13 @@ void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
}
bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * mSnapshot->alpha;
float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * currentSnapshot()->alpha;
return alpha == 0.0f && getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
}
void OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
const float* positions, const SkPaint* paint) {
if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint)) {
if (text == NULL || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) {
return;
}
@@ -2737,7 +2738,7 @@ void OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
}
fontRenderer.setTextureFiltering(linearFilter);
const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip();
const Rect* clip = pureTranslate ? writableSnapshot()->clipRect : &writableSnapshot()->getLocalClip();
Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
const bool hasActiveLayer = hasLayer();
@@ -2777,6 +2778,69 @@ bool OpenGLRenderer::findBestFontTransform(const mat4& transform, SkMatrix* outM
return true;
}
int OpenGLRenderer::getSaveCount() const {
return mState.getSaveCount();
}
int OpenGLRenderer::save(int flags) {
return mState.save(flags);
}
void OpenGLRenderer::restore() {
return mState.restore();
}
void OpenGLRenderer::restoreToCount(int saveCount) {
return mState.restoreToCount(saveCount);
}
void OpenGLRenderer::translate(float dx, float dy, float dz) {
return mState.translate(dx, dy, dz);
}
void OpenGLRenderer::rotate(float degrees) {
return mState.rotate(degrees);
}
void OpenGLRenderer::scale(float sx, float sy) {
return mState.scale(sx, sy);
}
void OpenGLRenderer::skew(float sx, float sy) {
return mState.skew(sx, sy);
}
void OpenGLRenderer::setMatrix(const Matrix4& matrix) {
mState.setMatrix(matrix);
}
void OpenGLRenderer::concatMatrix(const Matrix4& matrix) {
mState.concatMatrix(matrix);
}
bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
return mState.clipRect(left, top, right, bottom, op);
}
bool OpenGLRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
return mState.clipPath(path, op);
}
bool OpenGLRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
return mState.clipRegion(region, op);
}
void OpenGLRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
mState.setClippingOutline(allocator, outline);
}
void OpenGLRenderer::setClippingRoundRect(LinearAllocator& allocator,
const Rect& rect, float radius, bool highPriority) {
mState.setClippingRoundRect(allocator, rect, radius, highPriority);
}
void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
DrawOpMode drawOpMode) {
@@ -2784,7 +2848,7 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float
if (drawOpMode == kDrawOpMode_Immediate) {
// The checks for corner-case ignorable text and quick rejection is only done for immediate
// drawing as ops from DeferredDisplayList are already filtered for these
if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint) ||
if (text == NULL || count == 0 || mState.currentlyIgnored() || canSkipText(paint) ||
quickRejectSetupScissor(bounds)) {
return;
}
@@ -2834,7 +2898,7 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float
fontRenderer.setTextureFiltering(linearFilter);
// TODO: Implement better clipping for scaled/rotated text
const Rect* clip = !pureTranslate ? NULL : currentClipRect();
const Rect* clip = !pureTranslate ? NULL : mState.currentClipRect();
Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
bool status;
@@ -2866,7 +2930,7 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float
void OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) {
if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint)) {
if (text == NULL || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) {
return;
}
@@ -2882,7 +2946,7 @@ void OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
getAlphaAndMode(paint, &alpha, &mode);
TextSetupFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint);
const Rect* clip = &mSnapshot->getLocalClip();
const Rect* clip = &writableSnapshot()->getLocalClip();
Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
const bool hasActiveLayer = hasLayer();
@@ -2899,7 +2963,7 @@ void OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
}
void OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
if (currentSnapshot()->isIgnored()) return;
if (mState.currentlyIgnored()) return;
mCaches.activeTexture(0);
@@ -2929,7 +2993,7 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
}
bool clipRequired = false;
const bool rejected = calculateQuickRejectForScissor(x, y,
const bool rejected = mState.calculateQuickRejectForScissor(x, y,
x + layer->layer.getWidth(), y + layer->layer.getHeight(), &clipRequired, NULL, false);
if (rejected) {
@@ -3114,7 +3178,7 @@ void OpenGLRenderer::drawTextDecorations(float underlineWidth, float x, float y,
}
void OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
if (currentSnapshot()->isIgnored()) {
if (mState.currentlyIgnored()) {
return;
}
@@ -3131,7 +3195,7 @@ static void mapPointFakeZ(Vector3& point, const mat4& transformXY, const mat4& t
void OpenGLRenderer::drawShadow(float casterAlpha,
const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
if (currentSnapshot()->isIgnored()) return;
if (mState.currentlyIgnored()) return;
// TODO: use quickRejectWithScissor. For now, always force enable scissor.
mCaches.enableScissor();
@@ -3373,7 +3437,7 @@ void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, f
void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
ProgramDescription& description, bool swapSrcDst) {
if (mSnapshot->roundRectClipState != NULL /*&& !mSkipOutlineClip*/) {
if (writableSnapshot()->roundRectClipState != NULL /*&& !mSkipOutlineClip*/) {
blend = true;
mDescription.hasRoundRectClip = true;
}

View File

@@ -38,13 +38,14 @@
#include <androidfw/ResourceTypes.h>
#include "CanvasState.h"
#include "Debug.h"
#include "Extensions.h"
#include "Matrix.h"
#include "Program.h"
#include "Rect.h"
#include "Renderer.h"
#include "Snapshot.h"
#include "StatefulBaseRenderer.h"
#include "UvMapper.h"
#include "Vertex.h"
#include "Caches.h"
@@ -116,7 +117,7 @@ enum ModelViewMode {
/**
* OpenGL Renderer implementation.
*/
class OpenGLRenderer : public StatefulBaseRenderer {
class OpenGLRenderer : public Renderer, public CanvasStateClient {
public:
OpenGLRenderer(RenderState& renderState);
virtual ~OpenGLRenderer();
@@ -125,8 +126,10 @@ public:
void initLight(const Vector3& lightCenter, float lightRadius,
uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
virtual void onViewportInitialized();
virtual void prepareDirty(float left, float top, float right, float bottom, bool opaque);
virtual void prepare(bool opaque) {
prepareDirty(0.0f, 0.0f, mState.getWidth(), mState.getHeight(), opaque);
}
virtual bool finish();
virtual void callDrawGLFunction(Functor* functor, Rect& dirty);
@@ -218,20 +221,16 @@ public:
}
// simple rect clip
bool isCurrentClipSimple() {
return mSnapshot->clipRegion->isEmpty();
}
bool isCurrentClipSimple() { return mState.isCurrentClipSimple(); }
int getViewportWidth() { return currentSnapshot()->getViewportWidth(); }
int getViewportHeight() { return currentSnapshot()->getViewportHeight(); }
int getViewportWidth() { return mState.getViewportWidth(); }
int getViewportHeight() { return mState.getViewportHeight(); }
/**
* Scales the alpha on the current snapshot. This alpha value will be modulated
* with other alpha values when drawing primitives.
*/
void scaleAlpha(float alpha) {
mSnapshot->alpha *= alpha;
}
void scaleAlpha(float alpha) { mState.scaleAlpha(alpha); }
/**
* Inserts a named event marker in the stream of GL commands.
@@ -328,11 +327,63 @@ public:
}
#endif
const Vector3& getLightCenter() const { return currentSnapshot()->getRelativeLightCenter(); }
const Vector3& getLightCenter() const { return mState.currentLightCenter(); }
float getLightRadius() const { return mLightRadius; }
uint8_t getAmbientShadowAlpha() const { return mAmbientShadowAlpha; }
uint8_t getSpotShadowAlpha() const { return mSpotShadowAlpha; }
///////////////////////////////////////////////////////////////////
/// State manipulation
virtual void setViewport(int width, int height) { mState.setViewport(width, height); }
virtual int getSaveCount() const;
virtual int save(int flags);
virtual void restore();
virtual void restoreToCount(int saveCount);
virtual void getMatrix(SkMatrix* outMatrix) const { mState.getMatrix(outMatrix); }
virtual void setMatrix(const SkMatrix& matrix) { mState.setMatrix(matrix); }
virtual void concatMatrix(const SkMatrix& matrix) { mState.concatMatrix(matrix); }
virtual void translate(float dx, float dy, float dz = 0.0f);
virtual void rotate(float degrees);
virtual void scale(float sx, float sy);
virtual void skew(float sx, float sy);
void setMatrix(const Matrix4& matrix); // internal only convenience method
void concatMatrix(const Matrix4& matrix); // internal only convenience method
virtual const Rect& getLocalClipBounds() const { return mState.getLocalClipBounds(); }
const Rect& getRenderTargetClipBounds() const { return mState.getRenderTargetClipBounds(); }
virtual bool quickRejectConservative(float left, float top, float right, float bottom) const {
return mState.quickRejectConservative(left, top, right, bottom);
}
virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
virtual bool clipPath(const SkPath* path, SkRegion::Op op);
virtual bool clipRegion(const SkRegion* region, SkRegion::Op op);
/**
* Does not support different clipping Ops (that is, every call to setClippingOutline is
* effectively using SkRegion::kReplaceOp)
*
* The clipping outline is independent from the regular clip.
*/
void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
void setClippingRoundRect(LinearAllocator& allocator,
const Rect& rect, float radius, bool highPriority = true);
inline bool hasRectToRectTransform() const { return mState.hasRectToRectTransform(); }
inline const mat4* currentTransform() const { return mState.currentTransform(); }
///////////////////////////////////////////////////////////////////
/// CanvasStateClient interface
virtual void onViewportInitialized();
virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored);
virtual GLuint onGetTargetFbo() const { return 0; }
protected:
/**
* Perform the setup specific to a frame. This method does not
@@ -396,22 +447,16 @@ protected:
* Returns the region of the current layer.
*/
virtual Region* getRegion() const {
return mSnapshot->region;
return mState.currentRegion();
}
/**
* Indicates whether rendering is currently targeted at a layer.
*/
virtual bool hasLayer() const {
return (mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region;
return (mState.currentFlags() & Snapshot::kFlagFboTarget) && mState.currentRegion();
}
/**
* Returns the name of the FBO this renderer is rendering into.
*/
virtual GLuint getTargetFbo() const {
return 0;
}
/**
* Renders the specified layer as a textured quad.
@@ -464,6 +509,8 @@ protected:
inline RenderState& renderState() { return mRenderState; }
CanvasState mState;
private:
/**
* Discards the content of the framebuffer if supported by the driver.
@@ -499,8 +546,6 @@ private:
*/
void endTiling();
void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored);
/**
* Sets the clipping rectangle using glScissor. The clip is defined by
* the current snapshot's clipRect member.
@@ -916,9 +961,7 @@ private:
/**
* Should be invoked every time the glScissor is modified.
*/
inline void dirtyClip() {
mDirtyClip = true;
}
inline void dirtyClip() { mState.setDirtyClip(true); }
inline const UvMapper& getMapper(const Texture* texture) {
return texture && texture->uvMapper ? *texture->uvMapper : mUvMapper;
@@ -932,6 +975,8 @@ private:
Texture* getTexture(const SkBitmap* bitmap);
bool reportAndClearDirty() { bool ret = mDirty; mDirty = false; return ret; }
inline Snapshot* writableSnapshot() { return mState.writableSnapshot(); }
inline const Snapshot* currentSnapshot() const { return mState.currentSnapshot(); }
/**
* Model-view matrix used to position/size objects

View File

@@ -1,170 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_HWUI_STATEFUL_BASE_RENDERER_H
#define ANDROID_HWUI_STATEFUL_BASE_RENDERER_H
#include <utils/RefBase.h>
#include "Renderer.h"
#include "Snapshot.h"
namespace android {
namespace uirenderer {
/**
* Abstract Renderer subclass, which implements Canvas state methods.
*
* Manages the Snapshot stack, implementing matrix, save/restore, and clipping methods in the
* Renderer interface. Drawing and recording classes that extend StatefulBaseRenderer will have
* different use cases:
*
* Drawing subclasses (i.e. OpenGLRenderer) can query attributes (such as transform) or hook into
* changes (e.g. save/restore) with minimal surface area for manipulating the stack itself.
*
* Recording subclasses (i.e. DisplayListRenderer) can both record and pass through state operations
* to StatefulBaseRenderer, so that not only will querying operations work (getClip/Matrix), but so
* that quickRejection can also be used.
*/
class StatefulBaseRenderer : public Renderer {
public:
StatefulBaseRenderer();
virtual void prepare(bool opaque) {
prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque);
}
/**
* Initialize the first snapshot, computing the projection matrix, and stores the dimensions of
* the render target.
*/
virtual void setViewport(int width, int height);
void initializeSaveStack(float clipLeft, float clipTop, float clipRight, float clipBottom,
const Vector3& lightCenter);
// getters
bool hasRectToRectTransform() const {
return CC_LIKELY(currentTransform()->rectToRect());
}
// Save (layer)
virtual int getSaveCount() const { return mSaveCount; }
virtual int save(int flags);
virtual void restore();
virtual void restoreToCount(int saveCount);
//virtual int saveLayer(float left, float top, float right, float bottom,
// int alpha, SkXfermode::Mode mode, int flags);
// Matrix
virtual void getMatrix(SkMatrix* outMatrix) const;
virtual void translate(float dx, float dy, float dz = 0.0f);
virtual void rotate(float degrees);
virtual void scale(float sx, float sy);
virtual void skew(float sx, float sy);
virtual void setMatrix(const SkMatrix& matrix);
void setMatrix(const Matrix4& matrix); // internal only convenience method
virtual void concatMatrix(const SkMatrix& matrix);
void concatMatrix(const Matrix4& matrix); // internal only convenience method
// Clip
virtual const Rect& getLocalClipBounds() const { return mSnapshot->getLocalClip(); }
virtual bool quickRejectConservative(float left, float top, float right, float bottom) const;
virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
virtual bool clipPath(const SkPath* path, SkRegion::Op op);
virtual bool clipRegion(const SkRegion* region, SkRegion::Op op);
/**
* Does not support different clipping Ops (that is, every call to setClippingOutline is
* effectively using SkRegion::kReplaceOp)
*
* The clipping outline is independent from the regular clip.
*/
void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
void setClippingRoundRect(LinearAllocator& allocator,
const Rect& rect, float radius, bool highPriority = true);
inline const mat4* currentTransform() const {
return mSnapshot->transform;
}
protected:
const Rect& getRenderTargetClipBounds() const { return mSnapshot->getRenderTargetClip(); }
int getWidth() { return mWidth; }
int getHeight() { return mHeight; }
// Save
int saveSnapshot(int flags);
void restoreSnapshot();
// allows subclasses to control what value is stored in snapshot's fbo field in
// initializeSaveStack
virtual GLuint getTargetFbo() const {
return -1;
}
// Clip
bool calculateQuickRejectForScissor(float left, float top, float right, float bottom,
bool* clipRequired, bool* roundRectClipRequired, bool snapOut) const;
/**
* Called just after a restore has occurred. The 'removed' snapshot popped from the stack,
* 'restored' snapshot has become the top/current.
*
* Subclasses can override this method to handle layer restoration
*/
virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {};
virtual void onViewportInitialized() {};
inline const Rect* currentClipRect() const {
return mSnapshot->clipRect;
}
inline const Snapshot* currentSnapshot() const {
return mSnapshot != NULL ? mSnapshot.get() : mFirstSnapshot.get();
}
inline const Snapshot* firstSnapshot() const {
return mFirstSnapshot.get();
}
// indicites that the clip has been changed since the last time it was consumed
bool mDirtyClip;
private:
// Dimensions of the drawing surface
int mWidth, mHeight;
// Number of saved states
int mSaveCount;
// Base state
sp<Snapshot> mFirstSnapshot;
protected:
// Current state
// TODO: should become private, once hooks needed by OpenGLRenderer are added
sp<Snapshot> mSnapshot;
}; // class StatefulBaseRenderer
}; // namespace uirenderer
}; // namespace android
#endif // ANDROID_HWUI_STATEFUL_BASE_RENDERER_H