diff options
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 |