diff options
author | Chris Craik <ccraik@google.com> | 2013-12-30 15:32:54 -0800 |
---|---|---|
committer | Chris Craik <ccraik@google.com> | 2014-01-01 13:59:13 -0800 |
commit | 14e513058ed4168c94e015638d16f5f87fd8063a (patch) | |
tree | 1e66d02d2986e211d9e003ea2a3d09b9920f0dec /libs | |
parent | 539394ec3aee7b5868c14e5e692684c8a875a3d4 (diff) | |
download | frameworks_base-14e513058ed4168c94e015638d16f5f87fd8063a.zip frameworks_base-14e513058ed4168c94e015638d16f5f87fd8063a.tar.gz frameworks_base-14e513058ed4168c94e015638d16f5f87fd8063a.tar.bz2 |
Move Snapshot management to intermediate StatefulBaseRenderer class
The eventual goal is for the StatefulBaseRenderer to serve as the
common base class between the DisplayListRenderer and OpenGLRenderer.
This will separate DisplayList recording, Snapshot stack management,
and the GL in OpenGLRenderer.
Additionally, avoid sp<> parameters, and use const parameters in
several places, with the intent of greatly reducing the surface area
where renderer subclasses can modify snapshot stack.
Next steps:
-move bulk of clipping logic into StatefulBaseRenderer
-disable direct snapshot access
Change-Id: Ibc3c6747134ec7daf8ea535866239fa73b874390
Diffstat (limited to 'libs')
-rw-r--r-- | libs/hwui/Android.mk | 1 | ||||
-rw-r--r-- | libs/hwui/DisplayListRenderer.cpp | 29 | ||||
-rw-r--r-- | libs/hwui/DisplayListRenderer.h | 69 | ||||
-rw-r--r-- | libs/hwui/FontRenderer.h | 2 | ||||
-rw-r--r-- | libs/hwui/LayerRenderer.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/LayerRenderer.h | 2 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 285 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 78 | ||||
-rw-r--r-- | libs/hwui/Renderer.h | 21 | ||||
-rw-r--r-- | libs/hwui/StatefulBaseRenderer.cpp | 206 | ||||
-rw-r--r-- | libs/hwui/StatefulBaseRenderer.h | 137 |
11 files changed, 492 insertions, 340 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 962d726..9d31232 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -42,6 +42,7 @@ ifeq ($(USE_OPENGL_RENDERER),true) SkiaColorFilter.cpp \ SkiaShader.cpp \ Snapshot.cpp \ + StatefulBaseRenderer.cpp \ Stencil.cpp \ Texture.cpp \ TextureCache.cpp \ diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index 31a7db6..9c5db6e 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -120,19 +120,14 @@ void DisplayListRenderer::setViewport(int width, int height) { // TODO: DisplayListRenderer shouldn't have a projection matrix, as it should never be used mViewProjMatrix.loadOrtho(0, width, height, 0, -1, 1); - mWidth = width; - mHeight = height; + initializeViewport(width, height); } status_t DisplayListRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) { - mSnapshot = new Snapshot(mFirstSnapshot, - SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); - mSaveCount = 1; + initializeSaveStack(0, 0, getWidth(), getHeight()); - mSnapshot->setClip(0.0f, 0.0f, mWidth, mHeight); mDirtyClip = opaque; - mRestoreSaveCount = -1; return DrawGlInfo::kStatusDone; // No invalidate needed at record-time @@ -158,7 +153,7 @@ status_t DisplayListRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) int DisplayListRenderer::save(int flags) { addStateOp(new (alloc()) SaveOp(flags)); - return OpenGLRenderer::save(flags); + return StatefulBaseRenderer::save(flags); } void DisplayListRenderer::restore() { @@ -169,19 +164,19 @@ void DisplayListRenderer::restore() { mRestoreSaveCount--; insertTranslate(); - OpenGLRenderer::restore(); + StatefulBaseRenderer::restore(); } void DisplayListRenderer::restoreToCount(int saveCount) { mRestoreSaveCount = saveCount; insertTranslate(); - OpenGLRenderer::restoreToCount(saveCount); + StatefulBaseRenderer::restoreToCount(saveCount); } int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom, int alpha, SkXfermode::Mode mode, int flags) { addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, alpha, mode, flags)); - return OpenGLRenderer::save(flags); + return StatefulBaseRenderer::save(flags); } void DisplayListRenderer::translate(float dx, float dy, float dz) { @@ -190,34 +185,34 @@ void DisplayListRenderer::translate(float dx, float dy, float dz) { mTranslateX += dx; mTranslateY += dy; insertRestoreToCount(); - OpenGLRenderer::translate(dx, dy, dz); + StatefulBaseRenderer::translate(dx, dy, dz); } void DisplayListRenderer::rotate(float degrees) { addStateOp(new (alloc()) RotateOp(degrees)); - OpenGLRenderer::rotate(degrees); + StatefulBaseRenderer::rotate(degrees); } void DisplayListRenderer::scale(float sx, float sy) { addStateOp(new (alloc()) ScaleOp(sx, sy)); - OpenGLRenderer::scale(sx, sy); + StatefulBaseRenderer::scale(sx, sy); } void DisplayListRenderer::skew(float sx, float sy) { addStateOp(new (alloc()) SkewOp(sx, sy)); - OpenGLRenderer::skew(sx, sy); + StatefulBaseRenderer::skew(sx, sy); } void DisplayListRenderer::setMatrix(SkMatrix* matrix) { matrix = refMatrix(matrix); addStateOp(new (alloc()) SetMatrixOp(matrix)); - OpenGLRenderer::setMatrix(matrix); + StatefulBaseRenderer::setMatrix(matrix); } void DisplayListRenderer::concatMatrix(SkMatrix* matrix) { matrix = refMatrix(matrix); addStateOp(new (alloc()) ConcatMatrixOp(matrix)); - OpenGLRenderer::concatMatrix(matrix); + StatefulBaseRenderer::concatMatrix(matrix); } bool DisplayListRenderer::clipRect(float left, float top, float right, float bottom, diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index b6244e4..b5d9924 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -65,22 +65,26 @@ public: virtual bool isRecording() { return true; } +// ---------------------------------------------------------------------------- +// Frame state operations +// ---------------------------------------------------------------------------- virtual void setViewport(int width, int height); virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque); virtual void finish(); - - virtual status_t callDrawGLFunction(Functor *functor, Rect& dirty); - virtual void interrupt(); virtual void resume(); +// ---------------------------------------------------------------------------- +// Canvas state operations +// ---------------------------------------------------------------------------- + // Save (layer) 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 translate(float dx, float dy, float dz); virtual void rotate(float degrees); virtual void scale(float sx, float sy); @@ -89,12 +93,30 @@ public: virtual void setMatrix(SkMatrix* matrix); virtual void concatMatrix(SkMatrix* matrix); + // Clip virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op); virtual bool clipPath(SkPath* path, SkRegion::Op op); virtual bool clipRegion(SkRegion* region, SkRegion::Op op); - virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags); - virtual status_t drawLayer(Layer* layer, float x, float y); + // Misc - should be implemented with SkPaint inspection + virtual void resetShader(); + virtual void setupShader(SkiaShader* shader); + + virtual void resetColorFilter(); + virtual void setupColorFilter(SkiaColorFilter* filter); + + virtual void resetShadow(); + virtual void setupShadow(float radius, float dx, float dy, int color); + + virtual void resetPaintFilter(); + virtual void setupPaintFilter(int clearBits, int setBits); + +// ---------------------------------------------------------------------------- +// Canvas draw operations +// ---------------------------------------------------------------------------- + virtual status_t drawColor(int color, SkXfermode::Mode mode); + + // Bitmap-based virtual status_t drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint); virtual status_t drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint); virtual status_t drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop, @@ -105,8 +127,10 @@ public: float* vertices, int* colors, SkPaint* paint); virtual status_t drawPatch(SkBitmap* bitmap, Res_png_9patch* patch, float left, float top, float right, float bottom, SkPaint* paint); - virtual status_t drawColor(int color, SkXfermode::Mode mode); + + // Shapes virtual status_t drawRect(float left, float top, float right, float bottom, SkPaint* paint); + virtual status_t drawRects(const float* rects, int count, SkPaint* paint); virtual status_t drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, SkPaint* paint); virtual status_t drawCircle(float x, float y, float radius, SkPaint* paint); @@ -116,28 +140,29 @@ public: virtual status_t drawPath(SkPath* path, SkPaint* paint); virtual status_t drawLines(float* points, int count, SkPaint* paint); virtual status_t drawPoints(float* points, int count, SkPaint* paint); + + // Text + virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y, + const float* positions, SkPaint* paint, float totalAdvance, const Rect& bounds, + DrawOpMode drawOpMode = kDrawOpMode_Immediate); virtual status_t drawTextOnPath(const char* text, int bytesCount, int count, SkPath* path, float hOffset, float vOffset, SkPaint* paint); virtual status_t drawPosText(const char* text, int bytesCount, int count, const float* positions, SkPaint* paint); - virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y, - const float* positions, SkPaint* paint, float totalAdvance, const Rect& bounds, - DrawOpMode drawOpMode); - - virtual status_t drawRects(const float* rects, int count, SkPaint* paint); - virtual void resetShader(); - virtual void setupShader(SkiaShader* shader); - - virtual void resetColorFilter(); - virtual void setupColorFilter(SkiaColorFilter* filter); - - virtual void resetShadow(); - virtual void setupShadow(float radius, float dx, float dy, int color); +// ---------------------------------------------------------------------------- +// Canvas draw operations - special +// ---------------------------------------------------------------------------- + virtual status_t drawLayer(Layer* layer, float x, float y); + virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, + int32_t replayFlags); - virtual void resetPaintFilter(); - virtual void setupPaintFilter(int clearBits, int setBits); + // TODO: rename for consistency + virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty); +// ---------------------------------------------------------------------------- +// DisplayList / resource management +// ---------------------------------------------------------------------------- ANDROID_API void reset(); sp<DisplayListData> getDisplayListData() const { diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h index aa7e776..db4e020 100644 --- a/libs/hwui/FontRenderer.h +++ b/libs/hwui/FontRenderer.h @@ -44,8 +44,6 @@ namespace RSC { } #endif -class Functor; - namespace android { namespace uirenderer { diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index f8076cc..35fd46e 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -92,7 +92,7 @@ void LayerRenderer::finish() { // who will invoke OpenGLRenderer::resume() } -GLint LayerRenderer::getTargetFbo() const { +GLuint LayerRenderer::getTargetFbo() const { return mLayer->getFbo(); } diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h index 5f86731..f24c8d4 100644 --- a/libs/hwui/LayerRenderer.h +++ b/libs/hwui/LayerRenderer.h @@ -67,7 +67,7 @@ protected: virtual void ensureStencilBuffer(); virtual bool hasLayer() const; virtual Region* getRegion() const; - virtual GLint getTargetFbo() const; + virtual GLuint getTargetFbo() const; virtual bool suppressErrorChecks() const; private: diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index c30d86f..a3a4432 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -129,7 +129,6 @@ OpenGLRenderer::OpenGLRenderer(): memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices)); - mFirstSnapshot = new Snapshot; mFrameStarted = false; mCountOverdraw = false; @@ -182,24 +181,15 @@ void OpenGLRenderer::initViewport(int width, int height) { mViewProjMatrix.loadOrtho(0, width, height, 0, -1, 1); } - mWidth = width; - mHeight = height; - - mFirstSnapshot->height = height; - mFirstSnapshot->viewport.set(0, 0, width, height); + initializeViewport(width, height); } void OpenGLRenderer::setupFrameState(float left, float top, float right, float bottom, bool opaque) { mCaches.clearGarbage(); + initializeSaveStack(left, top, right, bottom); mOpaque = opaque; - mSnapshot = new Snapshot(mFirstSnapshot, - SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); - mSnapshot->fbo = getTargetFbo(); - mSaveCount = 1; - - mSnapshot->setClip(left, top, right, bottom); mTilingClip.set(left, top, right, bottom); } @@ -211,14 +201,14 @@ status_t OpenGLRenderer::startFrame() { discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom); - glViewport(0, 0, mWidth, mHeight); + glViewport(0, 0, getWidth(), getHeight()); // Functors break the tiling extension in pretty spectacular ways // This ensures we don't use tiling when a functor is going to be // invoked during the frame mSuppressTiling = mCaches.hasRegisteredFunctors(); - startTiling(mSnapshot, true); + startTiling(*mSnapshot, true); debugOverdraw(true, true); @@ -226,10 +216,6 @@ status_t OpenGLRenderer::startFrame() { mTilingClip.right, mTilingClip.bottom, mOpaque); } -status_t OpenGLRenderer::prepare(bool opaque) { - return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque); -} - status_t OpenGLRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) { @@ -239,7 +225,7 @@ status_t OpenGLRenderer::prepareDirty(float left, float top, // The framebuffer renderer will first defer the display list // for each layer and wait until the first drawing command // to start the frame - if (mSnapshot->fbo == 0) { + if (currentSnapshot().fbo == 0) { syncState(); updateLayers(); } else { @@ -254,7 +240,7 @@ 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 >= mWidth && bottom >= mHeight) { + left <= 0.0f && top <= 0.0f && right >= getWidth() && bottom >= getHeight()) { const bool isFbo = getTargetFbo() == 0; const GLenum attachments[] = { isFbo ? (const GLenum) GL_COLOR_EXT : (const GLenum) GL_COLOR_ATTACHMENT0, @@ -266,7 +252,7 @@ void OpenGLRenderer::discardFramebuffer(float left, float top, float right, floa status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) { if (!opaque || mCountOverdraw) { mCaches.enableScissor(); - mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top); + mCaches.setScissor(left, currentSnapshot().height - bottom, right - left, bottom - top); glClear(GL_COLOR_BUFFER_BIT); return DrawGlInfo::kStatusDrew; } @@ -283,14 +269,14 @@ void OpenGLRenderer::syncState() { } } -void OpenGLRenderer::startTiling(const sp<Snapshot>& s, bool opaque) { +void OpenGLRenderer::startTiling(const Snapshot& s, bool opaque) { if (!mSuppressTiling) { - Rect* clip = &mTilingClip; - if (s->flags & Snapshot::kFlagFboTarget) { - clip = &(s->layer->clipRect); + const Rect* clip = &mTilingClip; + if (s.flags & Snapshot::kFlagFboTarget) { + clip = &(s.layer->clipRect); } - startTiling(*clip, s->height, opaque); + startTiling(*clip, s.height, opaque); } } @@ -369,9 +355,9 @@ void OpenGLRenderer::interrupt() { } void OpenGLRenderer::resume() { - sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot; - glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight()); - glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo); + const Snapshot& snapshot = currentSnapshot(); + glViewport(0, 0, snapshot.viewport.getWidth(), snapshot.viewport.getHeight()); + glBindFramebuffer(GL_FRAMEBUFFER, snapshot.fbo); debugOverdraw(true, false); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); @@ -391,9 +377,9 @@ void OpenGLRenderer::resume() { } void OpenGLRenderer::resumeAfterLayer() { - sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot; - glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight()); - glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo); + const Snapshot& snapshot = currentSnapshot(); + glViewport(0, 0, snapshot.viewport.getWidth(), snapshot.viewport.getHeight()); + glBindFramebuffer(GL_FRAMEBUFFER, snapshot.fbo); debugOverdraw(true, false); mCaches.resetScissor(); @@ -447,12 +433,12 @@ status_t OpenGLRenderer::invokeFunctors(Rect& dirty) { } status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) { - if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone; + if (currentSnapshot().isIgnored()) return DrawGlInfo::kStatusDone; detachFunctor(functor); - Rect clip(*mSnapshot->clipRect); + Rect clip(currentClipRect()); clip.snapToPixelBoundaries(); // Since we don't know what the functor will draw, let's dirty @@ -556,9 +542,9 @@ void OpenGLRenderer::renderOverdraw() { } void OpenGLRenderer::countOverdraw() { - size_t count = mWidth * mHeight; + size_t count = getWidth() * getHeight(); uint32_t* buffer = new uint32_t[count]; - glReadPixels(0, 0, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0]); + glReadPixels(0, 0, getWidth(), getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0]); size_t total = 0; for (size_t i = 0; i < count; i++) { @@ -594,7 +580,7 @@ bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) { if (inFrame) { resumeAfterLayer(); - startTiling(mSnapshot); + startTiling(*mSnapshot); } layer->debugDrawUpdate = mCaches.debugLayersUpdates; @@ -715,50 +701,17 @@ void OpenGLRenderer::flushLayerUpdates() { // State management /////////////////////////////////////////////////////////////////////////////// -int OpenGLRenderer::getSaveCount() const { - return mSaveCount; -} - -int OpenGLRenderer::save(int flags) { - return saveSnapshot(flags); -} - -void OpenGLRenderer::restore() { - if (mSaveCount > 1) { - restoreSnapshot(); - } -} - -void OpenGLRenderer::restoreToCount(int saveCount) { - if (saveCount < 1) saveCount = 1; - - while (mSaveCount > saveCount) { - restoreSnapshot(); - } -} - -int OpenGLRenderer::saveSnapshot(int flags) { - mSnapshot = new Snapshot(mSnapshot, flags); - return mSaveCount++; -} - -bool OpenGLRenderer::restoreSnapshot() { - bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet; - bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer; - bool restoreOrtho = mSnapshot->flags & Snapshot::kFlagDirtyOrtho; - - sp<Snapshot> current = mSnapshot; - sp<Snapshot> previous = mSnapshot->previous; +void OpenGLRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) { + bool restoreOrtho = removed.flags & Snapshot::kFlagDirtyOrtho; + bool restoreClip = removed.flags & Snapshot::kFlagClipSet; + bool restoreLayer = removed.flags & Snapshot::kFlagIsLayer; if (restoreOrtho) { - Rect& r = previous->viewport; + const Rect& r = restored.viewport; glViewport(r.left, r.top, r.right, r.bottom); - mViewProjMatrix.load(current->orthoMatrix); + mViewProjMatrix.load(removed.orthoMatrix); // todo: should ortho be stored in 'restored'? } - mSaveCount--; - mSnapshot = previous; - if (restoreClip) { dirtyClip(); } @@ -766,11 +719,9 @@ bool OpenGLRenderer::restoreSnapshot() { if (restoreLayer) { endMark(); // Savelayer startMark("ComposeLayer"); - composeLayer(current, previous); + composeLayer(removed, restored); endMark(); } - - return restoreClip; } /////////////////////////////////////////////////////////////////////////////// @@ -781,7 +732,7 @@ int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom, int alpha, SkXfermode::Mode mode, int flags) { const int count = saveSnapshot(flags); - if (!mSnapshot->isIgnored()) { + if (!currentSnapshot().isIgnored()) { createLayer(left, top, right, bottom, alpha, mode, flags); } @@ -794,14 +745,14 @@ 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(*mSnapshot->clipRect)) { + if (bounds.intersect(currentClipRect())) { // We cannot work with sub-pixels in this case bounds.snapToPixelBoundaries(); // When the layer is not an FBO, we may use glCopyTexImage so we // need to make sure the layer does not extend outside the bounds // of the framebuffer - if (!bounds.intersect(mSnapshot->previous->viewport)) { + if (!bounds.intersect(currentSnapshot().previous->viewport)) { bounds.setEmpty(); } else if (fboLayer) { clip.set(bounds); @@ -836,7 +787,7 @@ int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float int alpha, SkXfermode::Mode mode, int flags) { const int count = saveSnapshot(flags); - if (!mSnapshot->isIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) { + if (!currentSnapshot().isIgnored() && (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) @@ -846,7 +797,7 @@ int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float calculateLayerBoundsAndClip(bounds, clip, true); updateSnapshotIgnoreForLayer(bounds, clip, true, alpha); - if (!mSnapshot->isIgnored()) { + if (!currentSnapshot().isIgnored()) { mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f); mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom); mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight()); @@ -922,7 +873,7 @@ bool OpenGLRenderer::createLayer(float left, float top, float right, float botto updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, alpha); // Bail out if we won't draw in this snapshot - if (mSnapshot->isIgnored()) { + if (currentSnapshot().isIgnored()) { return false; } @@ -1001,7 +952,7 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) { glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, layer->getTexture(), 0); - startTiling(mSnapshot, true); + startTiling(*mSnapshot, true); // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering mCaches.enableScissor(); @@ -1023,15 +974,15 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) { /** * Read the documentation of createLayer() before doing anything in this method. */ -void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { - if (!current->layer) { +void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& restored) { + if (!removed.layer) { ALOGE("Attempting to compose a layer that does not exist"); return; } - Layer* layer = current->layer; + Layer* layer = removed.layer; const Rect& rect = layer->layer; - const bool fboLayer = current->flags & Snapshot::kFlagIsFboLayer; + const bool fboLayer = removed.flags & Snapshot::kFlagIsFboLayer; bool clipRequired = false; calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom, @@ -1047,10 +998,10 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { layer->removeFbo(false); // Unbind current FBO and restore previous one - glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo); + glBindFramebuffer(GL_FRAMEBUFFER, restored.fbo); debugOverdraw(true, false); - startTiling(previous); + startTiling(restored); } if (!fboLayer && layer->getAlpha() < 255) { @@ -1067,7 +1018,7 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { // When the layer is stored in an FBO, we can save a bit of fillrate by // drawing only the dirty region if (fboLayer) { - dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *previous->transform); + dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *restored.transform); if (layer->getColorFilter()) { setupColorFilter(layer->getColorFilter()); } @@ -1347,7 +1298,7 @@ void OpenGLRenderer::dirtyLayer(const float left, const float top, } void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) { - if (bounds.intersect(*mSnapshot->clipRect)) { + if (bounds.intersect(currentClipRect())) { bounds.snapToPixelBoundaries(); android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom); if (!dirty.isEmpty()) { @@ -1375,7 +1326,7 @@ void OpenGLRenderer::clearLayerRegions() { const size_t count = mLayers.size(); if (count == 0) return; - if (!mSnapshot->isIgnored()) { + if (!currentSnapshot().isIgnored()) { // Doing several glScissor/glClear here can negatively impact // GPUs with a tiler architecture, instead we draw quads with // the Clear blending mode @@ -1427,8 +1378,8 @@ void OpenGLRenderer::clearLayerRegions() { /////////////////////////////////////////////////////////////////////////////// bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) { - const Rect& currentClip = *(mSnapshot->clipRect); - const mat4& currentMatrix = *(mSnapshot->transform); + const Rect& currentClip = currentClipRect(); + const mat4& currentMatrix = currentTransform(); if (stateDeferFlags & kStateDeferFlag_Draw) { // state has bounds initialized in local coordinates @@ -1471,14 +1422,14 @@ bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDef // (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything) state.mMatrix.load(currentMatrix); state.mDrawModifiers = mDrawModifiers; - state.mAlpha = mSnapshot->alpha; + state.mAlpha = currentSnapshot().alpha; return false; } void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) { - currentTransform().load(state.mMatrix); - mDrawModifiers = state.mDrawModifiers; + setMatrix(state.mMatrix); mSnapshot->alpha = state.mAlpha; + mDrawModifiers = state.mDrawModifiers; if (state.mClipValid && !skipClipRestore) { mSnapshot->setClip(state.mClip.left, state.mClip.top, @@ -1498,62 +1449,21 @@ void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) { if (clipRect != NULL) { mSnapshot->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom); } else { - mSnapshot->setClip(0, 0, mWidth, mHeight); + mSnapshot->setClip(0, 0, getWidth(), getHeight()); } dirtyClip(); mCaches.setScissorEnabled(clipRect != NULL || mScissorOptimizationDisabled); } /////////////////////////////////////////////////////////////////////////////// -// Transforms -/////////////////////////////////////////////////////////////////////////////// - -void OpenGLRenderer::translate(float dx, float dy, float dz) { - currentTransform().translate(dx, dy, dz); -} - -void OpenGLRenderer::rotate(float degrees) { - currentTransform().rotate(degrees, 0.0f, 0.0f, 1.0f); -} - -void OpenGLRenderer::scale(float sx, float sy) { - currentTransform().scale(sx, sy, 1.0f); -} - -void OpenGLRenderer::skew(float sx, float sy) { - currentTransform().skew(sx, sy); -} - -void OpenGLRenderer::setMatrix(SkMatrix* matrix) { - if (matrix) { - currentTransform().load(*matrix); - } else { - currentTransform().loadIdentity(); - } -} - -bool OpenGLRenderer::hasRectToRectTransform() { - return CC_LIKELY(currentTransform().rectToRect()); -} - -void OpenGLRenderer::getMatrix(SkMatrix* matrix) const { - currentTransform().copyTo(*matrix); -} - -void OpenGLRenderer::concatMatrix(SkMatrix* matrix) { - mat4 transform(*matrix); - currentTransform().multiply(transform); -} - -/////////////////////////////////////////////////////////////////////////////// // Clipping /////////////////////////////////////////////////////////////////////////////// void OpenGLRenderer::setScissorFromClip() { - Rect clip(*mSnapshot->clipRect); + Rect clip(currentClipRect()); clip.snapToPixelBoundaries(); - if (mCaches.setScissor(clip.left, mSnapshot->height - clip.bottom, + if (mCaches.setScissor(clip.left, currentSnapshot().height - clip.bottom, clip.getWidth(), clip.getHeight())) { mDirtyClip = false; } @@ -1564,7 +1474,7 @@ void OpenGLRenderer::ensureStencilBuffer() { // cannot attach a stencil buffer to fbo0 dynamically. Let's // just hope we have one when hasLayer() returns false. if (hasLayer()) { - attachStencilBufferToLayer(mSnapshot->layer); + attachStencilBufferToLayer(currentSnapshot().layer); } } @@ -1586,7 +1496,7 @@ void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) { void OpenGLRenderer::setStencilFromClip() { if (!mCaches.debugOverdraw) { - if (!mSnapshot->clipRegion->isEmpty()) { + if (!currentSnapshot().clipRegion->isEmpty()) { // 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; @@ -1611,14 +1521,16 @@ void OpenGLRenderer::setStencilFromClip() { // The last parameter is important: we are not drawing in the color buffer // so we don't want to dirty the current layer, if any - drawRegionRects(*mSnapshot->clipRegion, 0xff000000, SkXfermode::kSrc_Mode, false); + drawRegionRects(*(currentSnapshot().clipRegion), + 0xff000000, SkXfermode::kSrc_Mode, false); mCaches.stencil.enableTest(); // Draw the region used to generate the stencil if the appropriate debug // mode is enabled if (mCaches.debugStencilClip == Caches::kStencilShowRegion) { - drawRegionRects(*mSnapshot->clipRegion, 0x7f0000ff, SkXfermode::kSrcOver_Mode); + drawRegionRects(*(currentSnapshot().clipRegion), + 0x7f0000ff, SkXfermode::kSrcOver_Mode); } } else { mCaches.stencil.disable(); @@ -1626,69 +1538,6 @@ void OpenGLRenderer::setStencilFromClip() { } } -const Rect& OpenGLRenderer::getClipBounds() const { - return mSnapshot->getLocalClip(); -} - -/** - * Calculates whether content drawn within the passed bounds would be outside of, or intersect with - * the clipRect. Does not modify the scissor. - * - * @param clipRequired if not null, will be set to true if element intersects clip - * (and wasn't rejected) - * - * @param snapOut if set, the geometry will be treated as having an AA ramp. - * See Rect::snapGeometryToPixelBoundaries() - */ -bool OpenGLRenderer::calculateQuickRejectForScissor(float left, float top, - float right, float bottom, bool* clipRequired, bool snapOut) const { - if (mSnapshot->isIgnored() || bottom <= top || right <= left) { - return true; - } - - Rect r(left, top, right, bottom); - currentTransform().mapRect(r); - r.snapGeometryToPixelBoundaries(snapOut); - - Rect clipRect(*mSnapshot->clipRect); - clipRect.snapToPixelBoundaries(); - - if (!clipRect.intersects(r)) return true; - - // clip is required if geometry intersects clip rect - if (clipRequired) *clipRequired = !clipRect.contains(r); - 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 OpenGLRenderer::quickRejectConservative(float left, float top, - float right, float bottom) const { - if (mSnapshot->isIgnored() || bottom <= top || right <= left) { - return true; - } - - Rect r(left, top, right, bottom); - currentTransform().mapRect(r); - r.roundOut(); // rounded out to be conservative - - Rect clipRect(*mSnapshot->clipRect); - clipRect.snapToPixelBoundaries(); - - if (!clipRect.intersects(r)) return true; - - return false; -} - /** * Returns false and sets scissor enable based upon bounds if drawing won't be clipped out. * @@ -1721,8 +1570,8 @@ bool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right, void OpenGLRenderer::debugClip() { #if DEBUG_CLIP_REGIONS - if (!isRecording() && !mSnapshot->clipRegion->isEmpty()) { - drawRegionRects(*mSnapshot->clipRegion, 0x7f00ff00, SkXfermode::kSrcOver_Mode); + if (!isRecording() && !currentSnapshot().clipRegion->isEmpty()) { + drawRegionRects(*(currentSnapshot().clipRegion), 0x7f00ff00, SkXfermode::kSrcOver_Mode); } #endif } @@ -1754,7 +1603,7 @@ bool OpenGLRenderer::clipPath(SkPath* path, SkRegion::Op op) { clip.setRegion(*mSnapshot->previous->clipRegion); } else { if (mSnapshot->previous == mFirstSnapshot) { - clip.setRect(0, 0, mWidth, mHeight); + clip.setRect(0, 0, getWidth(), getHeight()); } else { Rect* bounds = mSnapshot->previous->clipRect; clip.setRect(bounds->left, bounds->top, bounds->right, bounds->bottom); @@ -1779,10 +1628,6 @@ bool OpenGLRenderer::clipRegion(SkRegion* region, SkRegion::Op op) { return !mSnapshot->clipRect->isEmpty(); } -Rect* OpenGLRenderer::getClipRect() { - return mSnapshot->clipRect; -} - /////////////////////////////////////////////////////////////////////////////// // Drawing commands /////////////////////////////////////////////////////////////////////////////// @@ -2067,7 +1912,7 @@ status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, if (mCaches.propertyDirtyViewport) { // force recalc of view/proj matrices - setViewport(mWidth, mHeight); + setViewport(getWidth(), getHeight()); mCaches.propertyDirtyViewport = false; } @@ -3107,7 +2952,7 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) { transform = &layer->getTransform(); if (!transform->isIdentity()) { save(0); - currentTransform().multiply(*transform); + concatMatrix(*transform); } } diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 2d6a7e9..1325bf7 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -42,6 +42,7 @@ #include "Program.h" #include "Rect.h" #include "Renderer.h" +#include "StatefulBaseRenderer.h" #include "SkiaColorFilter.h" #include "Snapshot.h" #include "UvMapper.h" @@ -120,10 +121,9 @@ enum ModelViewMode { // Renderer /////////////////////////////////////////////////////////////////////////////// /** - * OpenGL renderer used to draw accelerated 2D graphics. The API is a - * simplified version of Skia's Canvas API. + * OpenGL Renderer implementation. */ -class OpenGLRenderer : public Renderer { +class OpenGLRenderer : public StatefulBaseRenderer { public: ANDROID_API OpenGLRenderer(); virtual ~OpenGLRenderer(); @@ -131,10 +131,7 @@ public: ANDROID_API void initProperties(); virtual void setViewport(int width, int height); - - virtual status_t prepare(bool opaque); virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque); - virtual void finish(); virtual void interrupt(); virtual void resume(); @@ -157,11 +154,6 @@ public: ANDROID_API void clearLayerUpdates(); ANDROID_API void flushLayerUpdates(); - ANDROID_API int getSaveCount() const; - virtual int save(int flags); - virtual void restore(); - virtual void restoreToCount(int saveCount); - ANDROID_API int saveLayer(float left, float top, float right, float bottom, SkPaint* paint, int flags) { SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode; @@ -178,28 +170,9 @@ public: int saveLayerDeferred(float left, float top, float right, float bottom, int alpha, SkXfermode::Mode mode, int flags); - virtual void translate(float dx, float dy, float dz = 0); - virtual void rotate(float degrees); - virtual void scale(float sx, float sy); - virtual void skew(float sx, float sy); - - bool hasRectToRectTransform(); - ANDROID_API void getMatrix(SkMatrix* matrix) const; - virtual void setMatrix(SkMatrix* matrix); - virtual void concatMatrix(SkMatrix* matrix); - virtual void concatMatrix(Matrix4& matrix) { - currentTransform().multiply(matrix); - } - - ANDROID_API const Rect& getClipBounds() const; - - ANDROID_API 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(SkPath* path, SkRegion::Op op); virtual bool clipRegion(SkRegion* region, SkRegion::Op op); - virtual Rect* getClipRect(); virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t replayFlags); virtual status_t drawLayer(Layer* layer, float x, float y); @@ -273,7 +246,7 @@ public: void setDrawModifiers(const DrawModifiers& drawModifiers) { mDrawModifiers = drawModifiers; } ANDROID_API bool isCurrentTransformSimple() { - return mSnapshot->transform->isSimple(); + return currentTransform().isSimple(); } Caches& getCaches() { @@ -400,9 +373,6 @@ protected: */ void attachStencilBufferToLayer(Layer* layer); - bool calculateQuickRejectForScissor(float left, float top, float right, float bottom, - bool* clipRequired, bool snapOut) const; - bool quickRejectSetupScissor(float left, float top, float right, float bottom, SkPaint* paint = NULL); bool quickRejectSetupScissor(const Rect& bounds, SkPaint* paint = NULL) { @@ -419,16 +389,13 @@ protected: * @param curent The current snapshot containing the layer to compose * @param previous The previous snapshot to compose the current layer with */ - virtual void composeLayer(sp<Snapshot> current, sp<Snapshot> previous); + virtual void composeLayer(const Snapshot& current, const Snapshot& previous); /** * Marks the specified region as dirty at the specified bounds. */ void dirtyLayerUnchecked(Rect& bounds, Region* region); - /** - * Returns the current snapshot. - */ sp<Snapshot> getSnapshot() const { return mSnapshot; } @@ -450,7 +417,7 @@ protected: /** * Returns the name of the FBO this renderer is rendering into. */ - virtual GLint getTargetFbo() const { + virtual GLuint getTargetFbo() const { return 0; } @@ -520,7 +487,7 @@ private: * This method needs to be invoked every time getTargetFbo() is * bound again. */ - void startTiling(const sp<Snapshot>& snapshot, bool opaque = false); + void startTiling(const Snapshot& snapshot, bool opaque = false); /** * Tells the GPU what part of the screen is about to be redrawn. @@ -535,23 +502,7 @@ private: */ void endTiling(); - /** - * Saves the current state of the renderer as a new snapshot. - * The new snapshot is saved in mSnapshot and the previous snapshot - * is linked from mSnapshot->previous. - * - * @param flags The save flags; see SkCanvas for more information - * - * @return The new save count. This value can be passed to #restoreToCount() - */ - int saveSnapshot(int flags); - - /** - * Restores the current snapshot; mSnapshot becomes mSnapshot->previous. - * - * @return True if the clip was modified. - */ - bool restoreSnapshot(); + void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored); /** * Sets the clipping rectangle using glScissor. The clip is defined by @@ -979,10 +930,6 @@ private: mDirtyClip = true; } - inline mat4& currentTransform() const { - return *mSnapshot->transform; - } - inline const UvMapper& getMapper(const Texture* texture) { return texture && texture->uvMapper ? *texture->uvMapper : mUvMapper; } @@ -994,9 +941,6 @@ private: */ Texture* getTexture(SkBitmap* bitmap); - // Dimensions of the drawing surface - int mWidth, mHeight; - // Matrix used for view/projection in shaders mat4 mViewProjMatrix; @@ -1016,12 +960,6 @@ private: */ mat4 mModelView; - // Number of saved states - int mSaveCount; - // Base state - sp<Snapshot> mFirstSnapshot; - // Current state - sp<Snapshot> mSnapshot; // State used to define the clipping region Rect mTilingClip; // Is the target render surface opaque diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h index ac216fe..faf663a 100644 --- a/libs/hwui/Renderer.h +++ b/libs/hwui/Renderer.h @@ -17,10 +17,18 @@ #ifndef ANDROID_HWUI_RENDERER_H #define ANDROID_HWUI_RENDERER_H +#include <SkRegion.h> + +#include <utils/String8.h> + #include "AssetAtlas.h" #include "SkPaint.h" namespace android { + +class Functor; +class Res_png_9patch; + namespace uirenderer { class DisplayList; @@ -152,12 +160,8 @@ public: // ---------------------------------------------------------------------------- // Canvas state operations // ---------------------------------------------------------------------------- - // getters + // Save (layer) virtual int getSaveCount() const = 0; - virtual void getMatrix(SkMatrix* outMatrix) const = 0; - virtual const Rect& getClipBounds() const = 0; - - // save (layer) virtual int save(int flags) = 0; virtual void restore() = 0; virtual void restoreToCount(int saveCount) = 0; @@ -180,6 +184,7 @@ public: int alpha, SkXfermode::Mode mode, int flags) = 0; // Matrix + virtual void getMatrix(SkMatrix* outMatrix) const = 0; virtual void translate(float dx, float dy, float dz = 0.0f) = 0; virtual void rotate(float degrees) = 0; virtual void scale(float sx, float sy) = 0; @@ -187,9 +192,11 @@ public: virtual void setMatrix(SkMatrix* matrix) = 0; virtual void concatMatrix(SkMatrix* matrix) = 0; - virtual void concatMatrix(Matrix4& matrix) = 0; - // Clip + // clip + virtual const Rect& getClipBounds() const = 0; + virtual bool quickRejectConservative(float left, float top, + float right, float bottom) const = 0; virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op) = 0; virtual bool clipPath(SkPath* path, SkRegion::Op op) = 0; virtual bool clipRegion(SkRegion* region, SkRegion::Op op) = 0; diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/StatefulBaseRenderer.cpp new file mode 100644 index 0000000..cc8b14f --- /dev/null +++ b/libs/hwui/StatefulBaseRenderer.cpp @@ -0,0 +1,206 @@ +/* + * 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. + */ + +#include <SkCanvas.h> + +#include "StatefulBaseRenderer.h" + +namespace android { +namespace uirenderer { + +StatefulBaseRenderer::StatefulBaseRenderer() : + mSaveCount(1), mFirstSnapshot(new Snapshot), mSnapshot(mFirstSnapshot) { +} + +void StatefulBaseRenderer::initializeSaveStack(float clipLeft, float clipTop, + float clipRight, float clipBottom) { + mSnapshot = new Snapshot(mFirstSnapshot, + SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); + mSnapshot->setClip(clipLeft, clipTop, clipRight, clipBottom); + mSnapshot->fbo = getTargetFbo(); + mSaveCount = 1; +} + +void StatefulBaseRenderer::initializeViewport(int width, int height) { + mWidth = width; + mHeight = height; + + mFirstSnapshot->height = height; + mFirstSnapshot->viewport.set(0, 0, width, height); +} + +/////////////////////////////////////////////////////////////////////////////// +// Save (layer) +/////////////////////////////////////////////////////////////////////////////// + +/** + * Non-virtual implementation of save, guaranteed to save without side-effects + * + * The 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) { + mSnapshot = new Snapshot(mSnapshot, flags); + return mSaveCount++; +} + +int StatefulBaseRenderer::save(int flags) { + return saveSnapshot(flags); +} + +/** + * Non-virtual implementation of restore, guaranteed to restore without side-effects. + */ +void StatefulBaseRenderer::restoreSnapshot() { + sp<Snapshot> toRemove = mSnapshot; + sp<Snapshot> toRestore = mSnapshot->previous; + + mSaveCount--; + mSnapshot = toRestore; + + // subclass handles restore implementation + onSnapshotRestored(*toRemove, *toRestore); +} + +void StatefulBaseRenderer::restore() { + if (mSaveCount > 1) { + restoreSnapshot(); + } +} + +void StatefulBaseRenderer::restoreToCount(int saveCount) { + if (saveCount < 1) saveCount = 1; + + while (mSaveCount > saveCount) { + restoreSnapshot(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Matrix +/////////////////////////////////////////////////////////////////////////////// + +void StatefulBaseRenderer::getMatrix(SkMatrix* matrix) const { + mSnapshot->transform->copyTo(*matrix); +} + +void StatefulBaseRenderer::translate(float dx, float dy, float dz) { + mSnapshot->transform->translate(dx, dy, dz); +} + +void StatefulBaseRenderer::rotate(float degrees) { + mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f); +} + +void StatefulBaseRenderer::scale(float sx, float sy) { + mSnapshot->transform->scale(sx, sy, 1.0f); +} + +void StatefulBaseRenderer::skew(float sx, float sy) { + mSnapshot->transform->skew(sx, sy); +} + +void StatefulBaseRenderer::setMatrix(SkMatrix* matrix) { + if (matrix) { + mSnapshot->transform->load(*matrix); + } else { + mSnapshot->transform->loadIdentity(); + } +} + +void StatefulBaseRenderer::setMatrix(const Matrix4& matrix) { + mSnapshot->transform->load(matrix); +} + +void StatefulBaseRenderer::concatMatrix(SkMatrix* matrix) { + mat4 transform(*matrix); + mSnapshot->transform->multiply(transform); +} + +void StatefulBaseRenderer::concatMatrix(const Matrix4& matrix) { + mSnapshot->transform->multiply(matrix); +} + +/////////////////////////////////////////////////////////////////////////////// +// Clip +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// Quick Rejection +/////////////////////////////////////////////////////////////////////////////// + +/** + * Calculates whether content drawn within the passed bounds would be outside of, or intersect with + * the clipRect. Does not modify the scissor. + * + * @param clipRequired if not null, will be set to true if element intersects clip + * (and wasn't rejected) + * + * @param snapOut if set, the geometry will be treated as having an AA ramp. + * See Rect::snapGeometryToPixelBoundaries() + */ +bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top, + float right, float bottom, bool* clipRequired, bool snapOut) const { + if (mSnapshot->isIgnored() || bottom <= top || right <= left) { + return true; + } + + Rect r(left, top, right, bottom); + currentTransform().mapRect(r); + r.snapGeometryToPixelBoundaries(snapOut); + + Rect clipRect(currentClipRect()); + clipRect.snapToPixelBoundaries(); + + if (!clipRect.intersects(r)) return true; + + // clip is required if geometry intersects clip rect + if (clipRequired) *clipRequired = !clipRect.contains(r); + 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, + float right, float bottom) const { + if (mSnapshot->isIgnored() || bottom <= top || right <= left) { + return true; + } + + Rect r(left, top, right, bottom); + currentTransform().mapRect(r); + r.roundOut(); // rounded out to be conservative + + Rect clipRect(currentClipRect()); + clipRect.snapToPixelBoundaries(); + + if (!clipRect.intersects(r)) return true; + + return false; +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/StatefulBaseRenderer.h b/libs/hwui/StatefulBaseRenderer.h new file mode 100644 index 0000000..2bd196e --- /dev/null +++ b/libs/hwui/StatefulBaseRenderer.h @@ -0,0 +1,137 @@ +/* + * 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 { + +/** + * Implementation for Renderer state methods + * + * Eventually, this class should have abstract protected methods + * for allowing subclasses to hook into save/saveLayer and restore + */ +class StatefulBaseRenderer : public Renderer { +public: + StatefulBaseRenderer(); + + virtual status_t prepare(bool opaque) { + return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque); + } + void initializeViewport(int width, int height); + void initializeSaveStack(float clipLeft, float clipTop, float clipRight, float clipBottom); + + // 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(SkMatrix* matrix); + void setMatrix(const Matrix4& matrix); // internal only convenience method + virtual void concatMatrix(SkMatrix* matrix); + void concatMatrix(const Matrix4& matrix); // internal only convenience method + + // Clip + const Rect& getClipBounds() const { return mSnapshot->getLocalClip(); } + virtual bool quickRejectConservative(float left, float top, float right, float bottom) const; + + // TODO: implement these with hooks to enable scissor/stencil usage in OpenGLRenderer + // virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op); + // virtual bool clipPath(SkPath* path, SkRegion::Op op); + // virtual bool clipRegion(SkRegion* region, SkRegion::Op op); + +protected: + 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 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) {}; + + inline const Rect& currentClipRect() const { + return *(mSnapshot->clipRect); + } + + inline const mat4& currentTransform() const { + return *(mSnapshot->transform); + } + + inline const Snapshot& currentSnapshot() const { + return mSnapshot != NULL ? *mSnapshot : *mFirstSnapshot; + } + + // TODO: below should be private so that snapshot stack manipulation + // goes though (mostly) public methods + + // Number of saved states + int mSaveCount; + + // Base state + sp<Snapshot> mFirstSnapshot; + + // Current state + sp<Snapshot> mSnapshot; + +private: + // Dimensions of the drawing surface + int mWidth, mHeight; + +}; // class StatefulBaseRenderer + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_HWUI_STATEFUL_BASE_RENDERER_H |