diff options
Diffstat (limited to 'libs/hwui')
-rw-r--r-- | libs/hwui/DeferredDisplayList.cpp | 30 | ||||
-rw-r--r-- | libs/hwui/DeferredDisplayList.h | 4 | ||||
-rw-r--r-- | libs/hwui/DisplayList.cpp | 9 | ||||
-rw-r--r-- | libs/hwui/DisplayListOp.h | 51 | ||||
-rw-r--r-- | libs/hwui/DisplayListRenderer.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/DisplayListRenderer.h | 6 | ||||
-rw-r--r--[-rwxr-xr-x] | libs/hwui/Dither.cpp | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | libs/hwui/Dither.h | 0 | ||||
-rw-r--r-- | libs/hwui/Layer.cpp | 28 | ||||
-rw-r--r-- | libs/hwui/Layer.h | 1 | ||||
-rw-r--r-- | libs/hwui/LayerRenderer.cpp | 25 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 80 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 22 | ||||
-rw-r--r-- | libs/hwui/PathTessellator.cpp | 1 |
14 files changed, 177 insertions, 84 deletions
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp index 020c1e9..fe51bf9 100644 --- a/libs/hwui/DeferredDisplayList.cpp +++ b/libs/hwui/DeferredDisplayList.cpp @@ -34,6 +34,9 @@ namespace android { namespace uirenderer { +// Depth of the save stack at the beginning of batch playback at flush time +#define FLUSH_SAVE_STACK_DEPTH 2 + ///////////////////////////////////////////////////////////////////////////////// // Operation Batches ///////////////////////////////////////////////////////////////////////////////// @@ -75,7 +78,7 @@ public: for (unsigned int i = 0; i < mOps.size(); i++) { DrawOp* op = mOps[i]; - renderer.restoreDisplayState(op->state, kStateDeferFlag_Draw); + renderer.restoreDisplayState(op->state); #if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS renderer.eventMark(op->name()); @@ -106,7 +109,7 @@ public: virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty) { DEFER_LOGD("replaying state op batch %p", this); - renderer.restoreDisplayState(mOp->state, 0); + renderer.restoreDisplayState(mOp->state); // use invalid save count because it won't be used at flush time - RestoreToCountOp is the // only one to use it, and we don't use that class at flush time, instead calling @@ -117,12 +120,12 @@ public: } private: - StateOp* mOp; + const StateOp* mOp; }; class RestoreToCountBatch : public DrawOpBatch { public: - RestoreToCountBatch(int restoreCount) : mRestoreCount(restoreCount) {} + RestoreToCountBatch(StateOp* op, int restoreCount) : mOp(op), mRestoreCount(restoreCount) {} bool intersects(Rect& rect) { // if something checks for intersection, it's trying to go backwards across a state op, @@ -133,11 +136,15 @@ public: virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty) { DEFER_LOGD("batch %p restoring to count %d", this, mRestoreCount); + + renderer.restoreDisplayState(mOp->state); renderer.restoreToCount(mRestoreCount); return DrawGlInfo::kStatusDone; } private: + // we use the state storage for the RestoreToCountOp, but don't replay the op itself + const StateOp* mOp; /* * The count used here represents the flush() time saveCount. This is as opposed to the * DisplayList record time, or defer() time values (which are RestoreToCountOp's mCount, and @@ -251,7 +258,8 @@ void DeferredDisplayList::addSave(OpenGLRenderer& renderer, SaveOp* op, int newS * Either will act as a barrier to draw operation reordering, as we want to play back layer * save/restore and complex canvas modifications (including save/restore) in order. */ -void DeferredDisplayList::addRestoreToCount(OpenGLRenderer& renderer, int newSaveCount) { +void DeferredDisplayList::addRestoreToCount(OpenGLRenderer& renderer, StateOp* op, + int newSaveCount) { DEFER_LOGD("%p addRestoreToCount %d", this, newSaveCount); if (recordingComplexClip() && newSaveCount <= mComplexClipStackStart) { @@ -265,7 +273,7 @@ void DeferredDisplayList::addRestoreToCount(OpenGLRenderer& renderer, int newSav while (!mSaveStack.isEmpty() && mSaveStack.top() >= newSaveCount) mSaveStack.pop(); - storeRestoreToCountBarrier(mSaveStack.size() + 1); + storeRestoreToCountBarrier(renderer, op, mSaveStack.size() + FLUSH_SAVE_STACK_DEPTH); } void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) { @@ -338,11 +346,15 @@ void DeferredDisplayList::storeStateOpBarrier(OpenGLRenderer& renderer, StateOp* resetBatchingState(); } -void DeferredDisplayList::storeRestoreToCountBarrier(int newSaveCount) { +void DeferredDisplayList::storeRestoreToCountBarrier(OpenGLRenderer& renderer, StateOp* op, + int newSaveCount) { DEFER_LOGD("%p adding restore to count %d barrier, pos %d", this, newSaveCount, mBatches.size()); - mBatches.add(new RestoreToCountBatch(newSaveCount)); + // store displayState for the restore operation, as it may be associated with a saveLayer that + // doesn't have kClip_SaveFlag set + renderer.storeDisplayState(op->state, getStateOpDeferFlags()); + mBatches.add(new RestoreToCountBatch(op, newSaveCount)); resetBatchingState(); } @@ -377,6 +389,8 @@ status_t DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty) { DrawModifiers restoreDrawModifiers = renderer.getDrawModifiers(); renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); + // NOTE: depth of the save stack at this point, before playback, should be reflected in + // FLUSH_SAVE_STACK_DEPTH, so that save/restores match up correctly status |= replayBatchList(mBatches, renderer, dirty); renderer.restoreToCount(1); diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h index 2afc8c1..3e450da 100644 --- a/libs/hwui/DeferredDisplayList.h +++ b/libs/hwui/DeferredDisplayList.h @@ -65,7 +65,7 @@ public: void addClip(OpenGLRenderer& renderer, ClipOp* op); void addSaveLayer(OpenGLRenderer& renderer, SaveLayerOp* op, int newSaveCount); void addSave(OpenGLRenderer& renderer, SaveOp* op, int newSaveCount); - void addRestoreToCount(OpenGLRenderer& renderer, int newSaveCount); + void addRestoreToCount(OpenGLRenderer& renderer, StateOp* op, int newSaveCount); /** * Add a draw op into the DeferredDisplayList, reordering as needed (for performance) if @@ -81,7 +81,7 @@ private: void resetBatchingState(); void storeStateOpBarrier(OpenGLRenderer& renderer, StateOp* op); - void storeRestoreToCountBarrier(int newSaveCount); + void storeRestoreToCountBarrier(OpenGLRenderer& renderer, StateOp* op, int newSaveCount); bool recordingComplexClip() const { return mComplexClipStackStart >= 0; } diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp index d985ad0..36c95f9 100644 --- a/libs/hwui/DisplayList.cpp +++ b/libs/hwui/DisplayList.cpp @@ -352,7 +352,9 @@ void DisplayList::outputViewProperties(const int level) { } } if (mAlpha < 1) { - if (mCaching || !mHasOverlappingRendering) { + if (mCaching) { + ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mAlpha); + } else if (!mHasOverlappingRendering) { ALOGD("%*sScaleAlpha %.2f", level * 2, "", mAlpha); } else { int flags = SkCanvas::kHasAlphaLayer_SaveFlag; @@ -400,7 +402,9 @@ void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler, } } if (mAlpha < 1) { - if (mCaching || !mHasOverlappingRendering) { + if (mCaching) { + renderer.setOverrideLayerAlpha(mAlpha); + } else if (!mHasOverlappingRendering) { renderer.scaleAlpha(mAlpha); } else { // TODO: should be able to store the size of a DL at record time and not @@ -513,6 +517,7 @@ void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo); handler(mRestoreToCountOp->reinit(restoreTo), PROPERTY_SAVECOUNT); renderer.restoreToCount(restoreTo); + renderer.setOverrideLayerAlpha(1.0f); } }; // namespace uirenderer diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index 4f2db69..a5dee9f 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -117,7 +117,7 @@ public: applyState(replayStruct.mRenderer, saveCount); } - virtual void applyState(OpenGLRenderer& renderer, int saveCount) = 0; + virtual void applyState(OpenGLRenderer& renderer, int saveCount) const = 0; }; class DrawOp : public DisplayListOp { @@ -165,7 +165,11 @@ public: return DeferredDisplayList::kOpBatch_None; } - float strokeWidthOutset() { return mPaint->getStrokeWidth() * 0.5f; } + float strokeWidthOutset() { + float width = mPaint->getStrokeWidth(); + if (width == 0) return 0.5f; // account for hairline + return width * 0.5f; + } protected: SkPaint* getPaint(OpenGLRenderer& renderer) { @@ -223,7 +227,7 @@ public: deferStruct.mDeferredList.addSave(deferStruct.mRenderer, this, newSaveCount); } - virtual void applyState(OpenGLRenderer& renderer, int saveCount) { + virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { renderer.save(mFlags); } @@ -251,11 +255,12 @@ public: : mCount(count) {} virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) { - deferStruct.mDeferredList.addRestoreToCount(deferStruct.mRenderer, saveCount + mCount); + deferStruct.mDeferredList.addRestoreToCount(deferStruct.mRenderer, + this, saveCount + mCount); deferStruct.mRenderer.restoreToCount(saveCount + mCount); } - virtual void applyState(OpenGLRenderer& renderer, int saveCount) { + virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { renderer.restoreToCount(saveCount + mCount); } @@ -293,7 +298,7 @@ public: mAlpha, mMode, mFlags); } - virtual void applyState(OpenGLRenderer& renderer, int saveCount) { + virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom, mAlpha, mMode, mFlags); } @@ -330,7 +335,7 @@ public: TranslateOp(float dx, float dy) : mDx(dx), mDy(dy) {} - virtual void applyState(OpenGLRenderer& renderer, int saveCount) { + virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { renderer.translate(mDx, mDy); } @@ -350,7 +355,7 @@ public: RotateOp(float degrees) : mDegrees(degrees) {} - virtual void applyState(OpenGLRenderer& renderer, int saveCount) { + virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { renderer.rotate(mDegrees); } @@ -369,7 +374,7 @@ public: ScaleOp(float sx, float sy) : mSx(sx), mSy(sy) {} - virtual void applyState(OpenGLRenderer& renderer, int saveCount) { + virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { renderer.scale(mSx, mSy); } @@ -389,7 +394,7 @@ public: SkewOp(float sx, float sy) : mSx(sx), mSy(sy) {} - virtual void applyState(OpenGLRenderer& renderer, int saveCount) { + virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { renderer.skew(mSx, mSy); } @@ -409,7 +414,7 @@ public: SetMatrixOp(SkMatrix* matrix) : mMatrix(matrix) {} - virtual void applyState(OpenGLRenderer& renderer, int saveCount) { + virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { renderer.setMatrix(mMatrix); } @@ -428,7 +433,7 @@ public: ConcatMatrixOp(SkMatrix* matrix) : mMatrix(matrix) {} - virtual void applyState(OpenGLRenderer& renderer, int saveCount) { + virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { renderer.concatMatrix(mMatrix); } @@ -471,7 +476,7 @@ public: ClipRectOp(float left, float top, float right, float bottom, SkRegion::Op op) : ClipOp(op), mArea(left, top, right, bottom) {} - virtual void applyState(OpenGLRenderer& renderer, int saveCount) { + virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { renderer.clipRect(mArea.left, mArea.top, mArea.right, mArea.bottom, mOp); } @@ -500,7 +505,7 @@ public: ClipPathOp(SkPath* path, SkRegion::Op op) : ClipOp(op), mPath(path) {} - virtual void applyState(OpenGLRenderer& renderer, int saveCount) { + virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { renderer.clipPath(mPath, mOp); } @@ -521,7 +526,7 @@ public: ClipRegionOp(SkRegion* region, SkRegion::Op op) : ClipOp(op), mRegion(region) {} - virtual void applyState(OpenGLRenderer& renderer, int saveCount) { + virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { renderer.clipRegion(mRegion, mOp); } @@ -540,7 +545,7 @@ private: class ResetShaderOp : public StateOp { public: - virtual void applyState(OpenGLRenderer& renderer, int saveCount) { + virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { renderer.resetShader(); } @@ -555,7 +560,7 @@ class SetupShaderOp : public StateOp { public: SetupShaderOp(SkiaShader* shader) : mShader(shader) {} - virtual void applyState(OpenGLRenderer& renderer, int saveCount) { + virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { renderer.setupShader(mShader); } @@ -571,7 +576,7 @@ private: class ResetColorFilterOp : public StateOp { public: - virtual void applyState(OpenGLRenderer& renderer, int saveCount) { + virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { renderer.resetColorFilter(); } @@ -587,7 +592,7 @@ public: SetupColorFilterOp(SkiaColorFilter* colorFilter) : mColorFilter(colorFilter) {} - virtual void applyState(OpenGLRenderer& renderer, int saveCount) { + virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { renderer.setupColorFilter(mColorFilter); } @@ -603,7 +608,7 @@ private: class ResetShadowOp : public StateOp { public: - virtual void applyState(OpenGLRenderer& renderer, int saveCount) { + virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { renderer.resetShadow(); } @@ -619,7 +624,7 @@ public: SetupShadowOp(float radius, float dx, float dy, int color) : mRadius(radius), mDx(dx), mDy(dy), mColor(color) {} - virtual void applyState(OpenGLRenderer& renderer, int saveCount) { + virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { renderer.setupShadow(mRadius, mDx, mDy, mColor); } @@ -638,7 +643,7 @@ private: class ResetPaintFilterOp : public StateOp { public: - virtual void applyState(OpenGLRenderer& renderer, int saveCount) { + virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { renderer.resetPaintFilter(); } @@ -654,7 +659,7 @@ public: SetupPaintFilterOp(int clearBits, int setBits) : mClearBits(clearBits), mSetBits(setBits) {} - virtual void applyState(OpenGLRenderer& renderer, int saveCount) { + virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { renderer.setupPaintFilter(mClearBits, mSetBits); } diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index 07daa3b..0b8f7e6 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -248,9 +248,7 @@ status_t DisplayListRenderer::drawDisplayList(DisplayList* displayList, } status_t DisplayListRenderer::drawLayer(Layer* layer, float x, float y) { - mLayers.add(layer); - mCaches.resourceCache.incrementRefcount(layer); - + layer = refLayer(layer); addDrawOp(new (alloc()) DrawLayerOp(layer, x, y)); return DrawGlInfo::kStatusDone; } diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index 50e552f..19f7eb6 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -271,6 +271,12 @@ private: return copy; } + inline Layer* refLayer(Layer* layer) { + mLayers.add(layer); + mCaches.resourceCache.incrementRefcount(layer); + return layer; + } + inline SkBitmap* refBitmap(SkBitmap* bitmap) { // Note that this assumes the bitmap is immutable. There are cases this won't handle // correctly, such as creating the bitmap from scratch, drawing with it, changing its diff --git a/libs/hwui/Dither.cpp b/libs/hwui/Dither.cpp index e80b325..e80b325 100755..100644 --- a/libs/hwui/Dither.cpp +++ b/libs/hwui/Dither.cpp diff --git a/libs/hwui/Dither.h b/libs/hwui/Dither.h index 34cf9bf..34cf9bf 100755..100644 --- a/libs/hwui/Dither.h +++ b/libs/hwui/Dither.h diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index 2998535..63bb73f 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -75,6 +75,13 @@ bool Layer::resize(const uint32_t width, const uint32_t height) { return true; } + const uint32_t maxTextureSize = Caches::getInstance().maxTextureSize; + if (desiredWidth > maxTextureSize || desiredHeight > maxTextureSize) { + ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)", + desiredWidth, desiredHeight, maxTextureSize, maxTextureSize); + return false; + } + uint32_t oldWidth = getWidth(); uint32_t oldHeight = getHeight(); @@ -158,10 +165,13 @@ void Layer::defer() { dirtyRect.right, dirtyRect.bottom, !isBlend()); displayList->defer(deferredState, 0); + + deferredUpdateScheduled = false; + displayList = NULL; } void Layer::flush() { - if (deferredList && !deferredList->isEmpty()) { + if (deferredList) { renderer->setViewport(layer.getWidth(), layer.getHeight()); renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom, !isBlend()); @@ -176,5 +186,21 @@ void Layer::flush() { } } +void Layer::render() { + renderer->setViewport(layer.getWidth(), layer.getHeight()); + renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom, + !isBlend()); + + renderer->drawDisplayList(displayList, dirtyRect, DisplayList::kReplayFlag_ClipChildren); + + renderer->finish(); + renderer = NULL; + + dirtyRect.setEmpty(); + + deferredUpdateScheduled = false; + displayList = NULL; +} + }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index 0e00191..27e0cf1 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -275,6 +275,7 @@ struct Layer { void defer(); void flush(); + void render(); /** * Bounds of the layer. diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index bb02286..8451048 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -222,6 +222,21 @@ Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque return NULL; } + // We first obtain a layer before comparing against the max texture size + // because layers are not allocated at the exact desired size. They are + // always created slighly larger to improve recycling + const uint32_t maxTextureSize = caches.maxTextureSize; + if (layer->getWidth() > maxTextureSize || layer->getHeight() > maxTextureSize) { + ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)", + width, height, maxTextureSize, maxTextureSize); + + // Creating a new layer always increment its refcount by 1, this allows + // us to destroy the layer object if one was created for us + Caches::getInstance().resourceCache.decrementRefcount(layer); + + return NULL; + } + layer->setFbo(fbo); layer->layer.set(0.0f, 0.0f, width, height); layer->texCoords.set(0.0f, height / float(layer->getHeight()), @@ -243,14 +258,11 @@ Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque layer->setEmpty(false); layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE); + // This should only happen if we run out of memory if (glGetError() != GL_NO_ERROR) { - ALOGD("Could not allocate texture for layer (fbo=%d %dx%d)", - fbo, width, height); - + ALOGE("Could not allocate texture for layer (fbo=%d %dx%d)", fbo, width, height); glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); - - Caches::getInstance().resourceCache.decrementRefcount(layer); - + caches.resourceCache.decrementRefcount(layer); return NULL; } } @@ -272,7 +284,6 @@ bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) { layer->texCoords.set(0.0f, height / float(layer->getHeight()), width / float(layer->getWidth()), 0.0f); } else { - Caches::getInstance().resourceCache.decrementRefcount(layer); return false; } } diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 2903bcd..1138998 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -114,6 +114,7 @@ OpenGLRenderer::OpenGLRenderer(): mCaches(Caches::getInstance()), mExtensions(Extensions::getInstance()) { mDrawModifiers.mShader = NULL; mDrawModifiers.mColorFilter = NULL; + mDrawModifiers.mOverrideLayerAlpha = 1.0f; mDrawModifiers.mHasShadow = false; mDrawModifiers.mHasDrawFilter = false; @@ -540,13 +541,7 @@ bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) { } if (CC_UNLIKELY(inFrame || mCaches.drawDeferDisabled)) { - OpenGLRenderer* renderer = layer->renderer; - renderer->setViewport(layer->layer.getWidth(), layer->layer.getHeight()); - renderer->prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, - !layer->isBlend()); - renderer->drawDisplayList(layer->displayList, dirty, - DisplayList::kReplayFlag_ClipChildren); - renderer->finish(); + layer->render(); } else { layer->defer(); } @@ -556,13 +551,6 @@ bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) { startTiling(mSnapshot); } - if (CC_UNLIKELY(inFrame || mCaches.drawDeferDisabled)) { - dirty.setEmpty(); - layer->renderer = NULL; - } - - layer->deferredUpdateScheduled = false; - layer->displayList = NULL; layer->debugDrawUpdate = mCaches.debugLayersUpdates; return true; @@ -609,11 +597,12 @@ void OpenGLRenderer::flushLayers() { // Note: it is very important to update the layers in reverse order for (int i = count - 1; i >= 0; i--) { sprintf(layerName, "Layer #%d", i); - startMark(layerName); { - Layer* layer = mLayerUpdates.itemAt(i); - layer->flush(); - mCaches.resourceCache.decrementRefcount(layer); - } + startMark(layerName); + + Layer* layer = mLayerUpdates.itemAt(i); + layer->flush(); + mCaches.resourceCache.decrementRefcount(layer); + endMark(); } @@ -626,6 +615,15 @@ void OpenGLRenderer::flushLayers() { void OpenGLRenderer::pushLayerUpdate(Layer* layer) { if (layer) { + // Make sure we don't introduce duplicates. + // SortedVector would do this automatically but we need to respect + // the insertion order. The linear search is not an issue since + // this list is usually very short (typically one item, at most a few) + for (int i = mLayerUpdates.size() - 1; i >= 0; i--) { + if (mLayerUpdates.itemAt(i) == layer) { + return; + } + } mLayerUpdates.push_back(layer); mCaches.resourceCache.incrementRefcount(layer); } @@ -696,7 +694,10 @@ bool OpenGLRenderer::restoreSnapshot() { } if (restoreLayer) { + endMark(); // Savelayer + startMark("ComposeLayer"); composeLayer(current, previous); + endMark(); } return restoreClip; @@ -874,6 +875,7 @@ bool OpenGLRenderer::createLayer(float left, float top, float right, float botto mSnapshot->flags |= Snapshot::kFlagIsLayer; mSnapshot->layer = layer; + startMark("SaveLayer"); if (fboLayer) { return createFboLayer(layer, bounds, clip, previousFbo); } else { @@ -1073,7 +1075,7 @@ void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) layer->setFilter(GL_LINEAR, true); } - float alpha = layer->getAlpha() / 255.0f * mSnapshot->alpha; + float alpha = getLayerAlpha(layer); bool blend = layer->isBlend() || alpha < 1.0f; drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(), layer->getTexture(), alpha, layer->getMode(), blend, @@ -1111,7 +1113,7 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { rects = safeRegion.getArray(&count); } - const float alpha = layer->getAlpha() / 255.0f * mSnapshot->alpha; + const float alpha = getLayerAlpha(layer); const float texX = 1.0f / float(layer->getWidth()); const float texY = 1.0f / float(layer->getHeight()); const float height = rect.getHeight(); @@ -1326,8 +1328,6 @@ bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDef } else { state.mBounds.set(currentClip); } - state.mDrawModifiers = mDrawModifiers; - state.mAlpha = mSnapshot->alpha; } if (stateDeferFlags & kStateDeferFlag_Clip) { @@ -1336,18 +1336,18 @@ bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDef state.mClip.setEmpty(); } - // transform always deferred + // Transform, drawModifiers, and alpha always deferred, since they are used by state operations + // (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything) state.mMatrix.load(currentMatrix); + state.mDrawModifiers = mDrawModifiers; + state.mAlpha = mSnapshot->alpha; return false; } -void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, int stateDeferFlags) { +void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state) { currentTransform().load(state.mMatrix); - - if (stateDeferFlags & kStateDeferFlag_Draw) { - mDrawModifiers = state.mDrawModifiers; - mSnapshot->alpha = state.mAlpha; - } + mDrawModifiers = state.mDrawModifiers; + mSnapshot->alpha = state.mAlpha; if (!state.mClip.isEmpty()) { mSnapshot->setClip(state.mClip.left, state.mClip.top, state.mClip.right, state.mClip.bottom); @@ -2238,7 +2238,7 @@ status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const float left, float top, float right, float bottom, SkPaint* paint) { int alpha; SkXfermode::Mode mode; - getAlphaAndModeDirect(paint, &alpha, &mode); + getAlphaAndMode(paint, &alpha, &mode); return drawPatch(bitmap, xDivs, yDivs, colors, width, height, numColors, left, top, right, bottom, alpha, mode); @@ -2991,7 +2991,7 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) { if (layer->region.isRect()) { composeLayerRect(layer, layer->regionRect); } else if (layer->mesh) { - const float a = layer->getAlpha() / 255.0f * mSnapshot->alpha; + const float a = getLayerAlpha(layer); setupDraw(); setupDrawWithTexture(); setupDrawColor(a, a, a, a); @@ -3447,10 +3447,24 @@ void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, flo TextureVertex::setUV(v++, u2, v2); } -void OpenGLRenderer::getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) { +void OpenGLRenderer::getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) const { getAlphaAndModeDirect(paint, alpha, mode); + if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) { + // if drawing a layer, ignore the paint's alpha + *alpha = mDrawModifiers.mOverrideLayerAlpha; + } *alpha *= mSnapshot->alpha; } +float OpenGLRenderer::getLayerAlpha(Layer* layer) const { + float alpha; + if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) { + alpha = mDrawModifiers.mOverrideLayerAlpha; + } else { + alpha = layer->getAlpha() / 255.0f; + } + return alpha * mSnapshot->alpha; +} + }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index b17bc3f..dd7a5a2 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -51,6 +51,7 @@ namespace uirenderer { struct DrawModifiers { SkiaShader* mShader; SkiaColorFilter* mColorFilter; + float mOverrideLayerAlpha; // Drop shadow bool mHasShadow; @@ -275,15 +276,17 @@ public: virtual void resetPaintFilter(); virtual void setupPaintFilter(int clearBits, int setBits); + // If this value is set to < 1.0, it overrides alpha set on layer (see drawBitmap, drawLayer) + void setOverrideLayerAlpha(float alpha) { mDrawModifiers.mOverrideLayerAlpha = alpha; } + SkPaint* filterPaint(SkPaint* paint); bool storeDisplayState(DeferredDisplayState& state, int stateDeferFlags); - void restoreDisplayState(const DeferredDisplayState& state, int stateDeferFlags); + void restoreDisplayState(const DeferredDisplayState& state); const DrawModifiers& getDrawModifiers() { return mDrawModifiers; } void setDrawModifiers(const DrawModifiers& drawModifiers) { mDrawModifiers = drawModifiers; } - // TODO: what does this mean? no perspective? no rotate? ANDROID_API bool isCurrentTransformSimple() { return mSnapshot->transform->isSimple(); } @@ -325,7 +328,8 @@ public: /** * Gets the alpha and xfermode out of a paint object. If the paint is null * alpha will be 255 and the xfermode will be SRC_OVER. This method does - * not multiply the paint's alpha by the current snapshot's alpha. + * not multiply the paint's alpha by the current snapshot's alpha, and does + * not replace the alpha with the overrideLayerAlpha * * @param paint The paint to extract values from * @param alpha Where to store the resulting alpha @@ -450,13 +454,21 @@ protected: /** * Gets the alpha and xfermode out of a paint object. If the paint is null - * alpha will be 255 and the xfermode will be SRC_OVER. + * alpha will be 255 and the xfermode will be SRC_OVER. Accounts for both + * snapshot alpha, and overrideLayerAlpha * * @param paint The paint to extract values from * @param alpha Where to store the resulting alpha * @param mode Where to store the resulting xfermode */ - inline void getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode); + inline void getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) const; + + /** + * Gets the alpha from a layer, accounting for snapshot alpha and overrideLayerAlpha + * + * @param layer The layer from which the alpha is extracted + */ + inline float getLayerAlpha(Layer* layer) const; /** * Safely retrieves the mode from the specified xfermode. If the specified diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp index 395bbf6..0879b1b 100644 --- a/libs/hwui/PathTessellator.cpp +++ b/libs/hwui/PathTessellator.cpp @@ -61,6 +61,7 @@ void PathTessellator::expandBoundsForStroke(SkRect& bounds, const SkPaint* paint bool forceExpand) { if (forceExpand || paint->getStyle() != SkPaint::kFill_Style) { float outset = paint->getStrokeWidth() * 0.5f; + if (outset == 0) outset = 0.5f; // account for hairline bounds.outset(outset, outset); } } |