From ebf9ffce4781969bf19d39cb860aef72973be793 Mon Sep 17 00:00:00 2001 From: Mike Reed Date: Wed, 2 May 2018 11:20:38 -0400 Subject: remove (dead) Font code Test: make Change-Id: Icdb0f2fc356459718f02569054b91eadcd6a15c2 --- libs/hwui/FrameBuilder.cpp | 42 +++--------------------------------------- 1 file changed, 3 insertions(+), 39 deletions(-) (limited to 'libs/hwui/FrameBuilder.cpp') diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp index ced37ede0746..049cd450c822 100644 --- a/libs/hwui/FrameBuilder.cpp +++ b/libs/hwui/FrameBuilder.cpp @@ -722,48 +722,12 @@ void FrameBuilder::deferSimpleRectsOp(const SimpleRectsOp& op) { currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices); } -static batchid_t textBatchId(const SkPaint& paint) { - // TODO: better handling of shader (since we won't care about color then) - return paint.getColor() == SK_ColorBLACK ? OpBatchType::Text : OpBatchType::ColorText; -} - void FrameBuilder::deferTextOp(const TextOp& op) { - BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct( - mAllocator, *mCanvasState.writableSnapshot(), op, - BakedOpState::StrokeBehavior::StyleDefined, false); - if (!bakedState) return; // quick rejected - - batchid_t batchId = textBatchId(*(op.paint)); - if (bakedState->computedState.transform.isPureTranslate() && - PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver && - hasMergeableClip(*bakedState)) { - mergeid_t mergeId = reinterpret_cast(op.paint->getColor()); - currentLayer().deferMergeableOp(mAllocator, bakedState, batchId, mergeId); - } else { - currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId); - } - - FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(); - auto& totalTransform = bakedState->computedState.transform; - if (totalTransform.isPureTranslate() || totalTransform.isPerspective()) { - fontRenderer.precache(op.paint, op.glyphs, op.glyphCount, SkMatrix::I()); - } else { - // Partial transform case, see BakedOpDispatcher::renderTextOp - float sx, sy; - totalTransform.decomposeScale(sx, sy); - fontRenderer.precache( - op.paint, op.glyphs, op.glyphCount, - SkMatrix::MakeScale(roundf(std::max(1.0f, sx)), roundf(std::max(1.0f, sy)))); - } + // DEAD CODE } void FrameBuilder::deferTextOnPathOp(const TextOnPathOp& op) { - BakedOpState* bakedState = tryBakeUnboundedOpState(op); - if (!bakedState) return; // quick rejected - currentLayer().deferUnmergeableOp(mAllocator, bakedState, textBatchId(*(op.paint))); - - mCaches.fontRenderer.getFontRenderer().precache(op.paint, op.glyphs, op.glyphCount, - SkMatrix::I()); + // DEAD CODE } void FrameBuilder::deferTextureLayerOp(const TextureLayerOp& op) { @@ -969,7 +933,7 @@ void FrameBuilder::deferEndUnclippedLayerOp(const EndUnclippedLayerOp& /* ignore } void FrameBuilder::finishDefer() { - mCaches.fontRenderer.endPrecaching(); + // DEAD CODE } } // namespace uirenderer -- cgit v1.2.3-59-g8ed1b From 8cafcc628fc2eea5b25bb0409eb7ed2a76befb2b Mon Sep 17 00:00:00 2001 From: Mike Reed Date: Thu, 3 May 2018 11:32:46 -0400 Subject: remove (dead) caches from hwui Test: make Change-Id: I18bfe51896672272ce7d471eaead69b651399368 --- core/jni/android/graphics/Graphics.cpp | 3 - core/jni/android/graphics/Path.cpp | 5 - libs/hwui/Android.bp | 9 - libs/hwui/BakedOpDispatcher.cpp | 398 +------------ libs/hwui/BakedOpRenderer.cpp | 13 +- libs/hwui/BakedOpRenderer.h | 1 + libs/hwui/BakedOpState.cpp | 8 - libs/hwui/BakedOpState.h | 9 - libs/hwui/Caches.cpp | 56 +- libs/hwui/Caches.h | 18 +- libs/hwui/DisplayList.cpp | 3 - libs/hwui/FboCache.cpp | 82 --- libs/hwui/FboCache.h | 79 --- libs/hwui/FrameBuilder.cpp | 79 +-- libs/hwui/GlopBuilder.cpp | 28 +- libs/hwui/GradientCache.cpp | 272 --------- libs/hwui/GradientCache.h | 177 ------ libs/hwui/PatchCache.cpp | 264 --------- libs/hwui/PatchCache.h | 171 ------ libs/hwui/PathCache.cpp | 559 ------------------- libs/hwui/PathCache.h | 267 --------- libs/hwui/ProgramCache.cpp | 865 ----------------------------- libs/hwui/ProgramCache.h | 68 --- libs/hwui/RecordedOp.h | 19 - libs/hwui/RenderBufferCache.cpp | 161 ------ libs/hwui/RenderBufferCache.h | 115 ---- libs/hwui/ResourceCache.cpp | 4 +- libs/hwui/SkiaShader.cpp | 161 +----- libs/hwui/TessellationCache.cpp | 444 --------------- libs/hwui/TessellationCache.h | 225 -------- libs/hwui/TextureCache.cpp | 227 -------- libs/hwui/TextureCache.h | 144 ----- libs/hwui/font/CachedGlyphInfo.h | 56 -- libs/hwui/renderstate/RenderState.cpp | 5 +- libs/hwui/tests/microbench/ShadowBench.cpp | 101 ---- libs/hwui/utils/PaintUtils.h | 1 + 36 files changed, 26 insertions(+), 5071 deletions(-) delete mode 100644 libs/hwui/FboCache.cpp delete mode 100644 libs/hwui/FboCache.h delete mode 100644 libs/hwui/GradientCache.cpp delete mode 100644 libs/hwui/GradientCache.h delete mode 100644 libs/hwui/PatchCache.cpp delete mode 100644 libs/hwui/PatchCache.h delete mode 100644 libs/hwui/PathCache.cpp delete mode 100644 libs/hwui/PathCache.h delete mode 100644 libs/hwui/ProgramCache.cpp delete mode 100644 libs/hwui/ProgramCache.h delete mode 100644 libs/hwui/RenderBufferCache.cpp delete mode 100644 libs/hwui/RenderBufferCache.h delete mode 100644 libs/hwui/TessellationCache.cpp delete mode 100644 libs/hwui/TessellationCache.h delete mode 100644 libs/hwui/TextureCache.cpp delete mode 100644 libs/hwui/TextureCache.h delete mode 100644 libs/hwui/font/CachedGlyphInfo.h delete mode 100644 libs/hwui/tests/microbench/ShadowBench.cpp (limited to 'libs/hwui/FrameBuilder.cpp') diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index 90cc7bb72bfa..0933e98fe42d 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -15,9 +15,6 @@ #include #include -#include -#include - using namespace android; void doThrowNPE(JNIEnv* env) { diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp index 97abd82eaac5..aedb6acb2c04 100644 --- a/core/jni/android/graphics/Path.cpp +++ b/core/jni/android/graphics/Path.cpp @@ -28,7 +28,6 @@ #include "SkPathOps.h" #include "SkGeometry.h" // WARNING: Internal Skia Header -#include #include #include @@ -38,10 +37,6 @@ class SkPathGlue { public: static void finalizer(SkPath* obj) { - // Purge entries from the HWUI path cache if this path's data is unique - if (obj->unique() && android::uirenderer::Caches::hasInstance()) { - android::uirenderer::Caches::getInstance().pathCache.removeDeferred(obj); - } delete obj; } diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 3495c4f2acef..d716844b11c3 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -211,14 +211,12 @@ cc_defaults { "DeferredLayerUpdater.cpp", "DeviceInfo.cpp", "DisplayList.cpp", - "FboCache.cpp", "FrameBuilder.cpp", "FrameInfo.cpp", "FrameInfoVisualizer.cpp", "GlLayer.cpp", "GlopBuilder.cpp", "GpuMemoryTracker.cpp", - "GradientCache.cpp", "Image.cpp", "Interpolator.cpp", "JankTracker.cpp", @@ -229,8 +227,6 @@ cc_defaults { "OpDumper.cpp", "EglReadback.cpp", "Patch.cpp", - "PatchCache.cpp", - "PathCache.cpp", "PathParser.cpp", "PathTessellator.cpp", "PixelBuffer.cpp", @@ -238,12 +234,10 @@ cc_defaults { "ProfileDataContainer.cpp", "ProfileRenderer.cpp", "Program.cpp", - "ProgramCache.cpp", "Properties.cpp", "PropertyValuesAnimatorSet.cpp", "PropertyValuesHolder.cpp", "RecordingCanvas.cpp", - "RenderBufferCache.cpp", "RenderNode.cpp", "RenderProperties.cpp", "ResourceCache.cpp", @@ -253,9 +247,7 @@ cc_defaults { "SkiaShader.cpp", "Snapshot.cpp", "SpotShadow.cpp", - "TessellationCache.cpp", "Texture.cpp", - "TextureCache.cpp", "VectorDrawable.cpp", "VkLayer.cpp", "protos/graphicsstats.proto", @@ -411,7 +403,6 @@ cc_benchmark { "tests/microbench/LinearAllocatorBench.cpp", "tests/microbench/PathParserBench.cpp", "tests/microbench/RenderNodeBench.cpp", - "tests/microbench/ShadowBench.cpp", "tests/microbench/TaskManagerBench.cpp", ], } diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp index 2c7aab8b784e..1f931ed08c0d 100644 --- a/libs/hwui/BakedOpDispatcher.cpp +++ b/libs/hwui/BakedOpDispatcher.cpp @@ -36,153 +36,14 @@ namespace android { namespace uirenderer { -static void storeTexturedRect(TextureVertex* vertices, const Rect& bounds) { - vertices[0] = {bounds.left, bounds.top, 0, 0}; - vertices[1] = {bounds.right, bounds.top, 1, 0}; - vertices[2] = {bounds.left, bounds.bottom, 0, 1}; - vertices[3] = {bounds.right, bounds.bottom, 1, 1}; -} - void BakedOpDispatcher::onMergedBitmapOps(BakedOpRenderer& renderer, const MergedBakedOpList& opList) { - const BakedOpState& firstState = *(opList.states[0]); - Bitmap* bitmap = (static_cast(opList.states[0]->op))->bitmap; - - Texture* texture = renderer.caches().textureCache.get(bitmap); - if (!texture) return; - const AutoTexture autoCleanup(texture); - - TextureVertex vertices[opList.count * 4]; - for (size_t i = 0; i < opList.count; i++) { - const BakedOpState& state = *(opList.states[i]); - TextureVertex* rectVerts = &vertices[i * 4]; - - // calculate unclipped bounds, since they'll determine texture coordinates - Rect opBounds = state.op->unmappedBounds; - state.computedState.transform.mapRect(opBounds); - if (CC_LIKELY(state.computedState.transform.isPureTranslate())) { - // pure translate, so snap (same behavior as onBitmapOp) - opBounds.snapToPixelBoundaries(); - } - storeTexturedRect(rectVerts, opBounds); - renderer.dirtyRenderTarget(opBounds); - } - - const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType) - ? TextureFillFlags::IsAlphaMaskTexture - : TextureFillFlags::None; - Glop glop; - GlopBuilder(renderer.renderState(), renderer.caches(), &glop) - .setRoundRectClipState(firstState.roundRectClipState) - .setMeshTexturedIndexedQuads(vertices, opList.count * 6) - .setFillTexturePaint(*texture, textureFillFlags, firstState.op->paint, firstState.alpha) - .setTransform(Matrix4::identity(), TransformFlags::None) - .setModelViewIdentityEmptyBounds() - .build(); - ClipRect renderTargetClip(opList.clip); - const ClipBase* clip = opList.clipSideFlags ? &renderTargetClip : nullptr; - renderer.renderGlop(nullptr, clip, glop); + // DEAD CODE } void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer, const MergedBakedOpList& opList) { - const PatchOp& firstOp = *(static_cast(opList.states[0]->op)); - const BakedOpState& firstState = *(opList.states[0]); - - // Batches will usually contain a small number of items so it's - // worth performing a first iteration to count the exact number - // of vertices we need in the new mesh - uint32_t totalVertices = 0; - - for (size_t i = 0; i < opList.count; i++) { - const PatchOp& op = *(static_cast(opList.states[i]->op)); - - // TODO: cache mesh lookups - const Patch* opMesh = renderer.caches().patchCache.get( - op.bitmap->width(), op.bitmap->height(), op.unmappedBounds.getWidth(), - op.unmappedBounds.getHeight(), op.patch); - totalVertices += opMesh->verticesCount; - } - - const bool dirtyRenderTarget = renderer.offscreenRenderTarget(); - - uint32_t indexCount = 0; - - TextureVertex vertices[totalVertices]; - TextureVertex* vertex = &vertices[0]; - // Create a mesh that contains the transformed vertices for all the - // 9-patch objects that are part of the batch. Note that onDefer() - // enforces ops drawn by this function to have a pure translate or - // identity matrix - for (size_t i = 0; i < opList.count; i++) { - const PatchOp& op = *(static_cast(opList.states[i]->op)); - const BakedOpState& state = *opList.states[i]; - - // TODO: cache mesh lookups - const Patch* opMesh = renderer.caches().patchCache.get( - op.bitmap->width(), op.bitmap->height(), op.unmappedBounds.getWidth(), - op.unmappedBounds.getHeight(), op.patch); - - uint32_t vertexCount = opMesh->verticesCount; - if (vertexCount == 0) continue; - - // We use the bounds to know where to translate our vertices - // Using patchOp->state.mBounds wouldn't work because these - // bounds are clipped - const float tx = floorf(state.computedState.transform.getTranslateX() + - op.unmappedBounds.left + 0.5f); - const float ty = floorf(state.computedState.transform.getTranslateY() + - op.unmappedBounds.top + 0.5f); - - // Copy & transform all the vertices for the current operation - TextureVertex* opVertices = opMesh->vertices.get(); - for (uint32_t j = 0; j < vertexCount; j++, opVertices++) { - TextureVertex::set(vertex++, opVertices->x + tx, opVertices->y + ty, opVertices->u, - opVertices->v); - } - - // Dirty the current layer if possible. When the 9-patch does not - // contain empty quads we can take a shortcut and simply set the - // dirty rect to the object's bounds. - if (dirtyRenderTarget) { - if (!opMesh->hasEmptyQuads) { - renderer.dirtyRenderTarget(Rect(tx, ty, tx + op.unmappedBounds.getWidth(), - ty + op.unmappedBounds.getHeight())); - } else { - const size_t count = opMesh->quads.size(); - for (size_t i = 0; i < count; i++) { - const Rect& quadBounds = opMesh->quads[i]; - const float x = tx + quadBounds.left; - const float y = ty + quadBounds.top; - renderer.dirtyRenderTarget( - Rect(x, y, x + quadBounds.getWidth(), y + quadBounds.getHeight())); - } - } - } - - indexCount += opMesh->indexCount; - } - - Texture* texture = renderer.caches().textureCache.get(firstOp.bitmap); - if (!texture) return; - const AutoTexture autoCleanup(texture); - - // 9 patches are built for stretching - always filter - int textureFillFlags = TextureFillFlags::ForceFilter; - if (firstOp.bitmap->colorType() == kAlpha_8_SkColorType) { - textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture; - } - Glop glop; - GlopBuilder(renderer.renderState(), renderer.caches(), &glop) - .setRoundRectClipState(firstState.roundRectClipState) - .setMeshTexturedIndexedQuads(vertices, indexCount) - .setFillTexturePaint(*texture, textureFillFlags, firstOp.paint, firstState.alpha) - .setTransform(Matrix4::identity(), TransformFlags::None) - .setModelViewIdentityEmptyBounds() - .build(); - ClipRect renderTargetClip(opList.clip); - const ClipBase* clip = opList.clipSideFlags ? &renderTargetClip : nullptr; - renderer.renderGlop(nullptr, clip, glop); + // DEAD CODE } static void renderTextShadow(BakedOpRenderer& renderer, const TextOp& op, @@ -244,29 +105,6 @@ static void renderVertexBuffer(BakedOpRenderer& renderer, const BakedOpState& st } } -static void renderConvexPath(BakedOpRenderer& renderer, const BakedOpState& state, - const SkPath& path, const SkPaint& paint) { - VertexBuffer vertexBuffer; - // TODO: try clipping large paths to viewport - PathTessellator::tessellatePath(path, &paint, state.computedState.transform, vertexBuffer); - renderVertexBuffer(renderer, state, vertexBuffer, 0.0f, 0.0f, paint, 0); -} - -static void renderPathTexture(BakedOpRenderer& renderer, const BakedOpState& state, float xOffset, - float yOffset, PathTexture& texture, const SkPaint& paint) { - Rect dest(texture.width(), texture.height()); - dest.translate(xOffset + texture.left - texture.offset, yOffset + texture.top - texture.offset); - Glop glop; - GlopBuilder(renderer.renderState(), renderer.caches(), &glop) - .setRoundRectClipState(state.roundRectClipState) - .setMeshTexturedUnitQuad(nullptr) - .setFillPathTexturePaint(texture, paint, state.alpha) - .setTransform(state.computedState.transform, TransformFlags::None) - .setModelViewMapUnitToRect(dest) - .build(); - renderer.renderGlop(state, glop); -} - SkRect getBoundsOfFill(const RecordedOp& op) { SkRect bounds = op.unmappedBounds.toSkRect(); if (op.paint->getStyle() == SkPaint::kStrokeAndFill_Style) { @@ -278,29 +116,7 @@ SkRect getBoundsOfFill(const RecordedOp& op) { void BakedOpDispatcher::onArcOp(BakedOpRenderer& renderer, const ArcOp& op, const BakedOpState& state) { - // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180) - if (op.paint->getStyle() != SkPaint::kStroke_Style || op.paint->getPathEffect() != nullptr || - op.useCenter) { - PathTexture* texture = renderer.caches().pathCache.getArc( - op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.startAngle, - op.sweepAngle, op.useCenter, op.paint); - const AutoTexture holder(texture); - if (CC_LIKELY(holder.texture)) { - renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top, - *texture, *(op.paint)); - } - } else { - SkRect rect = getBoundsOfFill(op); - SkPath path; - if (op.useCenter) { - path.moveTo(rect.centerX(), rect.centerY()); - } - path.arcTo(rect, op.startAngle, op.sweepAngle, !op.useCenter); - if (op.useCenter) { - path.close(); - } - renderConvexPath(renderer, state, path, *(op.paint)); - } + // DEAD CODE } void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op, @@ -325,69 +141,7 @@ void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op void BakedOpDispatcher::onBitmapMeshOp(BakedOpRenderer& renderer, const BitmapMeshOp& op, const BakedOpState& state) { - Texture* texture = renderer.caches().textureCache.get(op.bitmap); - if (!texture) { - return; - } - const AutoTexture autoCleanup(texture); - - const uint32_t elementCount = op.meshWidth * op.meshHeight * 6; - - std::unique_ptr mesh(new ColorTextureVertex[elementCount]); - ColorTextureVertex* vertex = &mesh[0]; - - const int* colors = op.colors; - std::unique_ptr tempColors; - if (!colors) { - uint32_t colorsCount = (op.meshWidth + 1) * (op.meshHeight + 1); - tempColors.reset(new int[colorsCount]); - memset(tempColors.get(), 0xff, colorsCount * sizeof(int)); - colors = tempColors.get(); - } - - for (int32_t y = 0; y < op.meshHeight; y++) { - for (int32_t x = 0; x < op.meshWidth; x++) { - uint32_t i = (y * (op.meshWidth + 1) + x) * 2; - - float u1 = float(x) / op.meshWidth; - float u2 = float(x + 1) / op.meshWidth; - float v1 = float(y) / op.meshHeight; - float v2 = float(y + 1) / op.meshHeight; - - int ax = i + (op.meshWidth + 1) * 2; - int ay = ax + 1; - int bx = i; - int by = bx + 1; - int cx = i + 2; - int cy = cx + 1; - int dx = i + (op.meshWidth + 1) * 2 + 2; - int dy = dx + 1; - - const float* vertices = op.vertices; - ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]); - ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]); - ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]); - - ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]); - ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]); - ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]); - } - } - - /* - * TODO: handle alpha_8 textures correctly by applying paint color, but *not* - * shader in that case to mimic the behavior in SkiaCanvas::drawBitmapMesh. - */ - const int textureFillFlags = TextureFillFlags::None; - Glop glop; - GlopBuilder(renderer.renderState(), renderer.caches(), &glop) - .setRoundRectClipState(state.roundRectClipState) - .setMeshColoredTexturedMesh(mesh.get(), elementCount) - .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha) - .setTransform(state.computedState.transform, TransformFlags::None) - .setModelViewOffsetRect(0, 0, op.unmappedBounds) - .build(); - renderer.renderGlop(state, glop); + // DEAD CODE } void BakedOpDispatcher::onBitmapRectOp(BakedOpRenderer& renderer, const BitmapRectOp& op, @@ -450,67 +204,17 @@ void BakedOpDispatcher::onLinesOp(BakedOpRenderer& renderer, const LinesOp& op, void BakedOpDispatcher::onOvalOp(BakedOpRenderer& renderer, const OvalOp& op, const BakedOpState& state) { - if (op.paint->getPathEffect() != nullptr) { - PathTexture* texture = renderer.caches().pathCache.getOval( - op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.paint); - const AutoTexture holder(texture); - if (CC_LIKELY(holder.texture)) { - renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top, - *texture, *(op.paint)); - } - } else { - SkPath path; - SkRect rect = getBoundsOfFill(op); - path.addOval(rect); - - if (state.computedState.localProjectionPathMask != nullptr) { - // Mask the ripple path by the local space projection mask in local space. - // Note that this can create CCW paths. - Op(path, *state.computedState.localProjectionPathMask, kIntersect_SkPathOp, &path); - } - renderConvexPath(renderer, state, path, *(op.paint)); - } + // DEAD CODE } void BakedOpDispatcher::onPatchOp(BakedOpRenderer& renderer, const PatchOp& op, const BakedOpState& state) { - // 9 patches are built for stretching - always filter - int textureFillFlags = TextureFillFlags::ForceFilter; - if (op.bitmap->colorType() == kAlpha_8_SkColorType) { - textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture; - } - - // TODO: avoid redoing the below work each frame: - const Patch* mesh = renderer.caches().patchCache.get(op.bitmap->width(), op.bitmap->height(), - op.unmappedBounds.getWidth(), - op.unmappedBounds.getHeight(), op.patch); - - Texture* texture = renderer.caches().textureCache.get(op.bitmap); - if (CC_LIKELY(texture)) { - const AutoTexture autoCleanup(texture); - Glop glop; - GlopBuilder(renderer.renderState(), renderer.caches(), &glop) - .setRoundRectClipState(state.roundRectClipState) - .setMeshPatchQuads(*mesh) - .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha) - .setTransform(state.computedState.transform, TransformFlags::None) - .setModelViewOffsetRectSnap( - op.unmappedBounds.left, op.unmappedBounds.top, - Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight())) - .build(); - renderer.renderGlop(state, glop); - } + // DEAD CODE } void BakedOpDispatcher::onPathOp(BakedOpRenderer& renderer, const PathOp& op, const BakedOpState& state) { - PathTexture* texture = renderer.caches().pathCache.get(op.path, op.paint); - const AutoTexture holder(texture); - if (CC_LIKELY(holder.texture)) { - // Unlike other callers to renderPathTexture, no offsets are used because PathOp doesn't - // have any translate built in, other than what's in the SkPath itself - renderPathTexture(renderer, state, 0, 0, *texture, *(op.paint)); - } + // DEAD CODE } void BakedOpDispatcher::onPointsOp(BakedOpRenderer& renderer, const PointsOp& op, @@ -527,96 +231,12 @@ void BakedOpDispatcher::onPointsOp(BakedOpRenderer& renderer, const PointsOp& op void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, const BakedOpState& state) { - if (op.paint->getStyle() != SkPaint::kFill_Style) { - // only fill + default miter is supported by drawConvexPath, since others must handle joins - static_assert(SkPaintDefaults_MiterLimit == 4.0f, "Miter limit has changed"); - if (CC_UNLIKELY(op.paint->getPathEffect() != nullptr || - op.paint->getStrokeJoin() != SkPaint::kMiter_Join || - op.paint->getStrokeMiter() != SkPaintDefaults_MiterLimit)) { - PathTexture* texture = renderer.caches().pathCache.getRect( - op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.paint); - const AutoTexture holder(texture); - if (CC_LIKELY(holder.texture)) { - renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top, - *texture, *(op.paint)); - } - } else { - SkPath path; - path.addRect(getBoundsOfFill(op)); - renderConvexPath(renderer, state, path, *(op.paint)); - } - } else { - if (op.paint->isAntiAlias() && !state.computedState.transform.isSimple()) { - SkPath path; - path.addRect(op.unmappedBounds.toSkRect()); - renderConvexPath(renderer, state, path, *(op.paint)); - } else { - // render simple unit quad, no tessellation required - Glop glop; - GlopBuilder(renderer.renderState(), renderer.caches(), &glop) - .setRoundRectClipState(state.roundRectClipState) - .setMeshUnitQuad() - .setFillPaint(*op.paint, state.alpha) - .setTransform(state.computedState.transform, TransformFlags::None) - .setModelViewMapUnitToRect(op.unmappedBounds) - .build(); - renderer.renderGlop(state, glop); - } - } + // DEAD CODE } void BakedOpDispatcher::onRoundRectOp(BakedOpRenderer& renderer, const RoundRectOp& op, const BakedOpState& state) { - if (op.paint->getPathEffect() != nullptr) { - PathTexture* texture = renderer.caches().pathCache.getRoundRect( - op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.rx, op.ry, - op.paint); - const AutoTexture holder(texture); - if (CC_LIKELY(holder.texture)) { - renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top, - *texture, *(op.paint)); - } - } else { - const VertexBuffer* buffer = renderer.caches().tessellationCache.getRoundRect( - state.computedState.transform, *(op.paint), op.unmappedBounds.getWidth(), - op.unmappedBounds.getHeight(), op.rx, op.ry); - renderVertexBuffer(renderer, state, *buffer, op.unmappedBounds.left, op.unmappedBounds.top, - *(op.paint), 0); - } -} - -static void renderShadow(BakedOpRenderer& renderer, const BakedOpState& state, float casterAlpha, - const VertexBuffer* ambientShadowVertexBuffer, - const VertexBuffer* spotShadowVertexBuffer) { - SkPaint paint; - paint.setAntiAlias(true); // want to use AlphaVertex - - // The caller has made sure casterAlpha > 0. - uint8_t ambientShadowAlpha = renderer.getLightInfo().ambientShadowAlpha; - if (CC_UNLIKELY(Properties::overrideAmbientShadowStrength >= 0)) { - ambientShadowAlpha = Properties::overrideAmbientShadowStrength; - } - if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) { - paint.setAlpha((uint8_t)(casterAlpha * ambientShadowAlpha)); - renderVertexBuffer(renderer, state, *ambientShadowVertexBuffer, 0, 0, paint, - VertexBufferRenderFlags::ShadowInterp); - } - - uint8_t spotShadowAlpha = renderer.getLightInfo().spotShadowAlpha; - if (CC_UNLIKELY(Properties::overrideSpotShadowStrength >= 0)) { - spotShadowAlpha = Properties::overrideSpotShadowStrength; - } - if (spotShadowVertexBuffer && spotShadowAlpha > 0) { - paint.setAlpha((uint8_t)(casterAlpha * spotShadowAlpha)); - renderVertexBuffer(renderer, state, *spotShadowVertexBuffer, 0, 0, paint, - VertexBufferRenderFlags::ShadowInterp); - } -} - -void BakedOpDispatcher::onShadowOp(BakedOpRenderer& renderer, const ShadowOp& op, - const BakedOpState& state) { - TessellationCache::vertexBuffer_pair_t buffers = op.shadowTask->getResult(); - renderShadow(renderer, state, op.casterAlpha, buffers.first, buffers.second); + // DEAD CODE } void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op, diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp index 6b64b94d291e..0a3e3e470053 100644 --- a/libs/hwui/BakedOpRenderer.cpp +++ b/libs/hwui/BakedOpRenderer.cpp @@ -84,7 +84,6 @@ void BakedOpRenderer::endLayer() { // if stencil was used for clipping, detach it and return it to pool glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); GL_CHECKPOINT(MODERATE); - mCaches.renderBufferCache.put(mRenderTarget.stencil); mRenderTarget.stencil = nullptr; } mRenderTarget.lastStencilClip = nullptr; @@ -182,7 +181,7 @@ void BakedOpRenderer::clearColorBuffer(const Rect& rect) { } Texture* BakedOpRenderer::getTexture(Bitmap* bitmap) { - return mCaches.textureCache.get(bitmap); + return nullptr; } void BakedOpRenderer::drawRects(const float* rects, int count, const SkPaint* paint) { @@ -304,15 +303,7 @@ void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const ClipBase* cli // Stencil needed, but current stencil isn't up to date mRenderTarget.lastStencilClip = clip; - if (mRenderTarget.frameBufferId != 0 && !mRenderTarget.stencil) { - OffscreenBuffer* layer = mRenderTarget.offscreenBuffer; - mRenderTarget.stencil = mCaches.renderBufferCache.get( - Stencil::getLayerStencilFormat(), layer->texture.width(), - layer->texture.height()); - // stencil is bound + allocated - associate it with current FBO - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, mRenderTarget.stencil->getName()); - } + // DEAD CODE if (clip->mode == ClipMode::RectangleList) { setupStencilRectList(clip); diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h index 7c0590d7ab48..ae8928ea8461 100644 --- a/libs/hwui/BakedOpRenderer.h +++ b/libs/hwui/BakedOpRenderer.h @@ -26,6 +26,7 @@ namespace uirenderer { class Caches; struct Glop; class Layer; +struct RenderBuffer; class RenderState; struct ClipBase; diff --git a/libs/hwui/BakedOpState.cpp b/libs/hwui/BakedOpState.cpp index 63edf77279e3..0c673f315ded 100644 --- a/libs/hwui/BakedOpState.cpp +++ b/libs/hwui/BakedOpState.cpp @@ -149,14 +149,6 @@ BakedOpState* BakedOpState::tryStrokeableOpConstruct(LinearAllocator& allocator, return bakedState; } -BakedOpState* BakedOpState::tryShadowOpConstruct(LinearAllocator& allocator, Snapshot& snapshot, - const ShadowOp* shadowOpPtr) { - if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr; - - // clip isn't empty, so construct the op - return allocator.create_trivial(allocator, snapshot, shadowOpPtr); -} - BakedOpState* BakedOpState::directConstruct(LinearAllocator& allocator, const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp) { return allocator.create_trivial(clip, dstRect, recordedOp); diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h index e12dfbb18ea0..a50feff44fc0 100644 --- a/libs/hwui/BakedOpState.h +++ b/libs/hwui/BakedOpState.h @@ -120,9 +120,6 @@ public: StrokeBehavior strokeBehavior, bool expandForPathTexture); - static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator, Snapshot& snapshot, - const ShadowOp* shadowOpPtr); - static BakedOpState* directConstruct(LinearAllocator& allocator, const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp); @@ -154,12 +151,6 @@ private: , roundRectClipState(snapshot.roundRectClipState) , op(&recordedOp) {} - BakedOpState(LinearAllocator& allocator, Snapshot& snapshot, const ShadowOp* shadowOpPtr) - : computedState(allocator, snapshot) - , alpha(snapshot.alpha) - , roundRectClipState(snapshot.roundRectClipState) - , op(shadowOpPtr) {} - BakedOpState(const ClipRect* clipRect, const Rect& dstRect, const RecordedOp& recordedOp) : computedState(clipRect, dstRect) , alpha(1.0f) diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index 6aefb3564339..9c2ab5cd5cf3 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -46,10 +46,7 @@ Caches* Caches::sInstance = nullptr; /////////////////////////////////////////////////////////////////////////////// Caches::Caches(RenderState& renderState) - : gradientCache(extensions()) - , patchCache(renderState) - , programCache(extensions()) - , mRenderState(&renderState) + : mRenderState(&renderState) , mInitialized(false) { INIT_LOGD("Creating OpenGL renderer caches"); init(); @@ -102,13 +99,8 @@ void Caches::terminate() { if (!mInitialized) return; mRegionMesh.reset(nullptr); - fboCache.clear(); - - programCache.clear(); mProgram = nullptr; - patchCache.clear(); - clearGarbage(); delete mPixelBufferState; @@ -119,7 +111,7 @@ void Caches::terminate() { } void Caches::setProgram(const ProgramDescription& description) { - setProgram(programCache.get(description)); + // DEAD CODE } void Caches::setProgram(Program* program) { @@ -157,8 +149,6 @@ void Caches::dumpMemoryUsage() { void Caches::dumpMemoryUsage(String8& log) { uint32_t total = 0; log.appendFormat("Current memory usage / total memory usage (bytes):\n"); - log.appendFormat(" TextureCache %8d / %8d\n", textureCache.getSize(), - textureCache.getMaxSize()); if (mRenderState) { int memused = 0; for (std::set::iterator it = mRenderState->mActiveLayers.begin(); @@ -174,27 +164,6 @@ void Caches::dumpMemoryUsage(String8& log) { mRenderState->mActiveLayers.size()); total += memused; } - log.appendFormat(" RenderBufferCache %8d / %8d\n", renderBufferCache.getSize(), - renderBufferCache.getMaxSize()); - log.appendFormat(" GradientCache %8d / %8d\n", gradientCache.getSize(), - gradientCache.getMaxSize()); - log.appendFormat(" PathCache %8d / %8d\n", pathCache.getSize(), - pathCache.getMaxSize()); - log.appendFormat(" TessellationCache %8d / %8d\n", tessellationCache.getSize(), - tessellationCache.getMaxSize()); - log.appendFormat(" PatchCache %8d / %8d\n", patchCache.getSize(), - patchCache.getMaxSize()); - - log.appendFormat("Other:\n"); - log.appendFormat(" FboCache %8d / %8d\n", fboCache.getSize(), - fboCache.getMaxSize()); - - total += textureCache.getSize(); - total += renderBufferCache.getSize(); - total += gradientCache.getSize(); - total += pathCache.getSize(); - total += tessellationCache.getSize(); - total += patchCache.getSize(); log.appendFormat("Total memory usage:\n"); log.appendFormat(" %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f); @@ -205,30 +174,9 @@ void Caches::dumpMemoryUsage(String8& log) { /////////////////////////////////////////////////////////////////////////////// void Caches::clearGarbage() { - pathCache.clearGarbage(); - patchCache.clearGarbage(); } void Caches::flush(FlushMode mode) { - FLUSH_LOGD("Flushing caches (mode %d)", mode); - - switch (mode) { - case FlushMode::Full: - textureCache.clear(); - patchCache.clear(); - gradientCache.clear(); - fboCache.clear(); - // fall through - case FlushMode::Moderate: - textureCache.flush(); - pathCache.clear(); - tessellationCache.clear(); - // fall through - case FlushMode::Layers: - renderBufferCache.clear(); - break; - } - clearGarbage(); glFinish(); // Errors during cleanup should be considered non-fatal, dump them and diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index ed2d0b350d1b..4cb6aff02aa1 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -18,15 +18,8 @@ #include "DeviceInfo.h" #include "Extensions.h" -#include "FboCache.h" -#include "GradientCache.h" -#include "PatchCache.h" -#include "PathCache.h" -#include "ProgramCache.h" -#include "RenderBufferCache.h" +#include "Program.h" #include "ResourceCache.h" -#include "TessellationCache.h" -#include "TextureCache.h" #include "renderstate/PixelBufferState.h" #include "renderstate/TextureState.h" #include "thread/TaskManager.h" @@ -140,15 +133,6 @@ public: GLint maxTextureSize; public: - TextureCache textureCache; - RenderBufferCache renderBufferCache; - GradientCache gradientCache; - PatchCache patchCache; - PathCache pathCache; - ProgramCache programCache; - TessellationCache tessellationCache; - FboCache fboCache; - TaskManager tasks; bool gpuPixelBuffersEnabled; diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp index aa87aea8b374..f1f0d2ddfcff 100644 --- a/libs/hwui/DisplayList.cpp +++ b/libs/hwui/DisplayList.cpp @@ -64,9 +64,6 @@ void DisplayList::cleanupResources() { for (size_t i = 0; i < pathResources.size(); i++) { const SkPath* path = pathResources[i]; - if (path->unique() && Caches::hasInstance()) { - Caches::getInstance().pathCache.removeDeferred(path); - } delete path; } diff --git a/libs/hwui/FboCache.cpp b/libs/hwui/FboCache.cpp deleted file mode 100644 index 88302cc52c2b..000000000000 --- a/libs/hwui/FboCache.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2010 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 - -#include "Debug.h" -#include "FboCache.h" -#include "Properties.h" - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Constructors/destructor -/////////////////////////////////////////////////////////////////////////////// - -FboCache::FboCache() : mMaxSize(0) {} - -FboCache::~FboCache() { - clear(); -} - -/////////////////////////////////////////////////////////////////////////////// -// Size management -/////////////////////////////////////////////////////////////////////////////// - -uint32_t FboCache::getSize() { - return mCache.size(); -} - -uint32_t FboCache::getMaxSize() { - return mMaxSize; -} - -/////////////////////////////////////////////////////////////////////////////// -// Caching -/////////////////////////////////////////////////////////////////////////////// - -void FboCache::clear() { - for (size_t i = 0; i < mCache.size(); i++) { - const GLuint fbo = mCache.itemAt(i); - glDeleteFramebuffers(1, &fbo); - } - mCache.clear(); -} - -GLuint FboCache::get() { - GLuint fbo; - if (mCache.size() > 0) { - fbo = mCache.itemAt(mCache.size() - 1); - mCache.removeAt(mCache.size() - 1); - } else { - glGenFramebuffers(1, &fbo); - } - return fbo; -} - -bool FboCache::put(GLuint fbo) { - if (mCache.size() < mMaxSize) { - mCache.add(fbo); - return true; - } - - glDeleteFramebuffers(1, &fbo); - return false; -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/FboCache.h b/libs/hwui/FboCache.h deleted file mode 100644 index 5e8bb0c7a7a7..000000000000 --- a/libs/hwui/FboCache.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2010 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_FBO_CACHE_H -#define ANDROID_HWUI_FBO_CACHE_H - -#include - -#include - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Cache -/////////////////////////////////////////////////////////////////////////////// - -class FboCache { -public: - FboCache(); - ~FboCache(); - - /** - * Returns an FBO from the cache. If no FBO is available, a new one - * is created. If creating a new FBO fails, 0 is returned. - * - * When an FBO is obtained from the cache, it is removed and the - * total number of FBOs available in the cache decreases. - * - * @return The name of the FBO, or 0 if no FBO can be obtained. - */ - GLuint get(); - - /** - * Adds the specified FBO to the cache. - * - * @param fbo The FBO to add to the cache. - * - * @return True if the FBO was added, false otherwise. - */ - bool put(GLuint fbo); - - /** - * Clears the cache. This causes all FBOs to be deleted. - */ - void clear(); - - /** - * Returns the current size of the cache. - */ - uint32_t getSize(); - - /** - * Returns the maximum number of FBOs that the cache can hold. - */ - uint32_t getMaxSize(); - -private: - SortedVector mCache; - uint32_t mMaxSize; -}; // class FboCache - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_FBO_CACHE_H diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp index 049cd450c822..575aea524133 100644 --- a/libs/hwui/FrameBuilder.cpp +++ b/libs/hwui/FrameBuilder.cpp @@ -386,71 +386,7 @@ void FrameBuilder::defer3dChildren(const ClipBase* reorderClip, ChildrenSelectMo } void FrameBuilder::deferShadow(const ClipBase* reorderClip, const RenderNodeOp& casterNodeOp) { - auto& node = *casterNodeOp.renderNode; - auto& properties = node.properties(); - - if (properties.getAlpha() <= 0.0f || properties.getOutline().getAlpha() <= 0.0f || - !properties.getOutline().getPath() || properties.getScaleX() == 0 || - properties.getScaleY() == 0) { - // no shadow to draw - return; - } - - const SkPath* casterOutlinePath = properties.getOutline().getPath(); - const SkPath* revealClipPath = properties.getRevealClip().getPath(); - if (revealClipPath && revealClipPath->isEmpty()) return; - - float casterAlpha = properties.getAlpha() * properties.getOutline().getAlpha(); - - // holds temporary SkPath to store the result of intersections - SkPath* frameAllocatedPath = nullptr; - const SkPath* casterPath = casterOutlinePath; - - // intersect the shadow-casting path with the reveal, if present - if (revealClipPath) { - frameAllocatedPath = createFrameAllocatedPath(); - - Op(*casterPath, *revealClipPath, kIntersect_SkPathOp, frameAllocatedPath); - casterPath = frameAllocatedPath; - } - - // intersect the shadow-casting path with the clipBounds, if present - if (properties.getClippingFlags() & CLIP_TO_CLIP_BOUNDS) { - if (!frameAllocatedPath) { - frameAllocatedPath = createFrameAllocatedPath(); - } - Rect clipBounds; - properties.getClippingRectForFlags(CLIP_TO_CLIP_BOUNDS, &clipBounds); - SkPath clipBoundsPath; - clipBoundsPath.addRect(clipBounds.left, clipBounds.top, clipBounds.right, - clipBounds.bottom); - - Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, frameAllocatedPath); - casterPath = frameAllocatedPath; - } - - // apply reorder clip to shadow, so it respects clip at beginning of reorderable chunk - int restoreTo = mCanvasState.save(SaveFlags::MatrixClip); - mCanvasState.writableSnapshot()->applyClip(reorderClip, - *mCanvasState.currentSnapshot()->transform); - if (CC_LIKELY(!mCanvasState.getRenderTargetClipBounds().isEmpty())) { - Matrix4 shadowMatrixXY(casterNodeOp.localMatrix); - Matrix4 shadowMatrixZ(casterNodeOp.localMatrix); - node.applyViewPropertyTransforms(shadowMatrixXY, false); - node.applyViewPropertyTransforms(shadowMatrixZ, true); - - sp task = mCaches.tessellationCache.getShadowTask( - mCanvasState.currentTransform(), mCanvasState.getLocalClipBounds(), - casterAlpha >= 1.0f, casterPath, &shadowMatrixXY, &shadowMatrixZ, - mCanvasState.currentSnapshot()->getRelativeLightCenter(), mLightRadius); - ShadowOp* shadowOp = mAllocator.create(task, casterAlpha); - BakedOpState* bakedOpState = BakedOpState::tryShadowOpConstruct( - mAllocator, *mCanvasState.writableSnapshot(), shadowOp); - if (CC_LIKELY(bakedOpState)) { - currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Shadow); - } - } - mCanvasState.restoreToCount(restoreTo); + // DEAD CODE } void FrameBuilder::deferProjectedChildren(const RenderNode& renderNode) { @@ -682,10 +618,7 @@ void FrameBuilder::deferPatchOp(const PatchOp& op) { } void FrameBuilder::deferPathOp(const PathOp& op) { - auto state = deferStrokeableOp(op, OpBatchType::AlphaMaskTexture); - if (CC_LIKELY(state)) { - mCaches.pathCache.precache(op.path, op.paint); - } + /*auto state = */deferStrokeableOp(op, OpBatchType::AlphaMaskTexture); } void FrameBuilder::deferPointsOp(const PointsOp& op) { @@ -698,13 +631,7 @@ void FrameBuilder::deferRectOp(const RectOp& op) { } void FrameBuilder::deferRoundRectOp(const RoundRectOp& op) { - auto state = deferStrokeableOp(op, tessBatchId(op)); - if (CC_LIKELY(state && !op.paint->getPathEffect())) { - // TODO: consider storing tessellation task in BakedOpState - mCaches.tessellationCache.precacheRoundRect(state->computedState.transform, *(op.paint), - op.unmappedBounds.getWidth(), - op.unmappedBounds.getHeight(), op.rx, op.ry); - } + // DEAD CODE } void FrameBuilder::deferRoundRectPropsOp(const RoundRectPropsOp& op) { diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp index 941373d8ef5a..13a41123bc2f 100644 --- a/libs/hwui/GlopBuilder.cpp +++ b/libs/hwui/GlopBuilder.cpp @@ -21,7 +21,6 @@ #include "Layer.h" #include "Matrix.h" #include "Patch.h" -#include "PathCache.h" #include "SkiaShader.h" #include "Texture.h" #include "VertexBuffer.h" @@ -203,17 +202,7 @@ GlopBuilder& GlopBuilder::setMeshVertexBuffer(const VertexBuffer& vertexBuffer) } GlopBuilder& GlopBuilder::setMeshPatchQuads(const Patch& patch) { - TRIGGER_STAGE(kMeshStage); - - mOutGlop->mesh.primitiveMode = GL_TRIANGLES; - mOutGlop->mesh.indices = {mRenderState.meshState().getQuadListIBO(), nullptr}; - mOutGlop->mesh.vertices = {mCaches.patchCache.getMeshBuffer(), - VertexAttribFlags::TextureCoord, - (void*)patch.positionOffset, - (void*)patch.textureOffset, - nullptr, - kTextureVertexStride}; - mOutGlop->mesh.elementCount = patch.indexCount; + // DEAD CODE return *this; } @@ -365,17 +354,7 @@ GlopBuilder& GlopBuilder::setFillPaint(const SkPaint& paint, float alphaScale, b GlopBuilder& GlopBuilder::setFillPathTexturePaint(PathTexture& texture, const SkPaint& paint, float alphaScale) { - TRIGGER_STAGE(kFillStage); - REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); - - // specify invalid filter/clamp, since these are always static for PathTextures - mOutGlop->fill.texture = {&texture, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr}; - - setFill(paint.getColor(), alphaScale, paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap, - paint.getShader(), paint.getColorFilter()); - - mDescription.hasAlpha8Texture = true; - mDescription.modulate = mOutGlop->fill.color.isNotBlack(); + // DEAD CODE return *this; } @@ -625,9 +604,6 @@ void GlopBuilder::build() { mOutGlop->fill.colorEnabled = mDescription.modulate || singleColor; verify(mDescription, *mOutGlop); - - // Final step: populate program and map bounds into render target space - mOutGlop->fill.program = mCaches.programCache.get(mDescription); } void GlopBuilder::dump(const Glop& glop) { diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp deleted file mode 100644 index 21e3c730cbec..000000000000 --- a/libs/hwui/GradientCache.cpp +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (C) 2010 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 - -#include "Caches.h" -#include "Debug.h" -#include "DeviceInfo.h" -#include "GradientCache.h" -#include "Properties.h" - -#include - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Functions -/////////////////////////////////////////////////////////////////////////////// - -template -static inline T min(T a, T b) { - return a < b ? a : b; -} - -/////////////////////////////////////////////////////////////////////////////// -// Cache entry -/////////////////////////////////////////////////////////////////////////////// - -hash_t GradientCacheEntry::hash() const { - uint32_t hash = JenkinsHashMix(0, count); - for (uint32_t i = 0; i < count; i++) { - hash = JenkinsHashMix(hash, android::hash_type(colors[i])); - hash = JenkinsHashMix(hash, android::hash_type(positions[i])); - } - return JenkinsHashWhiten(hash); -} - -int GradientCacheEntry::compare(const GradientCacheEntry& lhs, const GradientCacheEntry& rhs) { - int deltaInt = int(lhs.count) - int(rhs.count); - if (deltaInt != 0) return deltaInt; - - deltaInt = memcmp(lhs.colors.get(), rhs.colors.get(), lhs.count * sizeof(uint32_t)); - if (deltaInt != 0) return deltaInt; - - return memcmp(lhs.positions.get(), rhs.positions.get(), lhs.count * sizeof(float)); -} - -/////////////////////////////////////////////////////////////////////////////// -// Constructors/destructor -/////////////////////////////////////////////////////////////////////////////// - -GradientCache::GradientCache(const Extensions& extensions) - : mCache(LruCache::kUnlimitedCapacity) - , mSize(0) - , mMaxSize(MB(1)) - , mUseFloatTexture(extensions.hasFloatTextures()) - , mHasNpot(extensions.hasNPot()) - , mHasLinearBlending(extensions.hasLinearBlending()) { - mMaxTextureSize = DeviceInfo::get()->maxTextureSize(); - - mCache.setOnEntryRemovedListener(this); -} - -GradientCache::~GradientCache() { - mCache.clear(); -} - -/////////////////////////////////////////////////////////////////////////////// -// Size management -/////////////////////////////////////////////////////////////////////////////// - -uint32_t GradientCache::getSize() { - return mSize; -} - -uint32_t GradientCache::getMaxSize() { - return mMaxSize; -} - -/////////////////////////////////////////////////////////////////////////////// -// Callbacks -/////////////////////////////////////////////////////////////////////////////// - -void GradientCache::operator()(GradientCacheEntry&, Texture*& texture) { - if (texture) { - mSize -= texture->objectSize(); - texture->deleteTexture(); - delete texture; - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Caching -/////////////////////////////////////////////////////////////////////////////// - -Texture* GradientCache::get(uint32_t* colors, float* positions, int count) { - GradientCacheEntry gradient(colors, positions, count); - Texture* texture = mCache.get(gradient); - - if (!texture) { - texture = addLinearGradient(gradient, colors, positions, count); - } - - return texture; -} - -void GradientCache::clear() { - mCache.clear(); -} - -void GradientCache::getGradientInfo(const uint32_t* colors, const int count, GradientInfo& info) { - uint32_t width = 256 * (count - 1); - - // If the npot extension is not supported we cannot use non-clamp - // wrap modes. We therefore find the nearest largest power of 2 - // unless width is already a power of 2 - if (!mHasNpot && (width & (width - 1)) != 0) { - width = 1 << (32 - __builtin_clz(width)); - } - - bool hasAlpha = false; - for (int i = 0; i < count; i++) { - if (((colors[i] >> 24) & 0xff) < 255) { - hasAlpha = true; - break; - } - } - - info.width = min(width, uint32_t(mMaxTextureSize)); - info.hasAlpha = hasAlpha; -} - -Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient, uint32_t* colors, - float* positions, int count) { - GradientInfo info; - getGradientInfo(colors, count, info); - - Texture* texture = new Texture(Caches::getInstance()); - texture->blend = info.hasAlpha; - texture->generation = 1; - - // Assume the cache is always big enough - const uint32_t size = info.width * 2 * bytesPerPixel(); - while (getSize() + size > mMaxSize) { - LOG_ALWAYS_FATAL_IF(!mCache.removeOldest(), - "Ran out of things to remove from the cache? getSize() = %" PRIu32 - ", size = %" PRIu32 ", mMaxSize = %" PRIu32 ", width = %" PRIu32, - getSize(), size, mMaxSize, info.width); - } - - generateTexture(colors, positions, info.width, 2, texture); - - mSize += size; - LOG_ALWAYS_FATAL_IF((int)size != texture->objectSize(), - "size != texture->objectSize(), size %" PRIu32 - ", objectSize %d" - " width = %" PRIu32 " bytesPerPixel() = %zu", - size, texture->objectSize(), info.width, bytesPerPixel()); - mCache.put(gradient, texture); - - return texture; -} - -size_t GradientCache::bytesPerPixel() const { - // We use 4 channels (RGBA) - return 4 * (mUseFloatTexture ? /* fp16 */ 2 : sizeof(uint8_t)); -} - -size_t GradientCache::sourceBytesPerPixel() const { - // We use 4 channels (RGBA) and upload from floats (not half floats) - return 4 * (mUseFloatTexture ? sizeof(float) : sizeof(uint8_t)); -} - -void GradientCache::mixBytes(const FloatColor& start, const FloatColor& end, float amount, - uint8_t*& dst) const { - float oppAmount = 1.0f - amount; - float a = start.a * oppAmount + end.a * amount; - *dst++ = uint8_t(OECF(start.r * oppAmount + end.r * amount) * 255.0f); - *dst++ = uint8_t(OECF(start.g * oppAmount + end.g * amount) * 255.0f); - *dst++ = uint8_t(OECF(start.b * oppAmount + end.b * amount) * 255.0f); - *dst++ = uint8_t(a * 255.0f); -} - -void GradientCache::mixFloats(const FloatColor& start, const FloatColor& end, float amount, - uint8_t*& dst) const { - float oppAmount = 1.0f - amount; - float a = start.a * oppAmount + end.a * amount; - float* d = (float*)dst; -#ifdef ANDROID_ENABLE_LINEAR_BLENDING - // We want to stay linear - *d++ = (start.r * oppAmount + end.r * amount); - *d++ = (start.g * oppAmount + end.g * amount); - *d++ = (start.b * oppAmount + end.b * amount); -#else - *d++ = OECF(start.r * oppAmount + end.r * amount); - *d++ = OECF(start.g * oppAmount + end.g * amount); - *d++ = OECF(start.b * oppAmount + end.b * amount); -#endif - *d++ = a; - dst += 4 * sizeof(float); -} - -void GradientCache::generateTexture(uint32_t* colors, float* positions, const uint32_t width, - const uint32_t height, Texture* texture) { - const GLsizei rowBytes = width * sourceBytesPerPixel(); - uint8_t pixels[rowBytes * height]; - - static ChannelMixer gMixers[] = { - // colors are stored gamma-encoded - &android::uirenderer::GradientCache::mixBytes, - // colors are stored in linear (linear blending on) - // or gamma-encoded (linear blending off) - &android::uirenderer::GradientCache::mixFloats, - }; - ChannelMixer mix = gMixers[mUseFloatTexture]; - - FloatColor start; - start.set(colors[0]); - - FloatColor end; - end.set(colors[1]); - - int currentPos = 1; - float startPos = positions[0]; - float distance = positions[1] - startPos; - - uint8_t* dst = pixels; - for (uint32_t x = 0; x < width; x++) { - float pos = x / float(width - 1); - if (pos > positions[currentPos]) { - start = end; - startPos = positions[currentPos]; - - currentPos++; - - end.set(colors[currentPos]); - distance = positions[currentPos] - startPos; - } - - float amount = (pos - startPos) / distance; - (this->*mix)(start, end, amount, dst); - } - - memcpy(pixels + rowBytes, pixels, rowBytes); - - if (mUseFloatTexture) { - texture->upload(GL_RGBA16F, width, height, GL_RGBA, GL_FLOAT, pixels); - } else { - GLint internalFormat = mHasLinearBlending ? GL_SRGB8_ALPHA8 : GL_RGBA; - texture->upload(internalFormat, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - } - - texture->setFilter(GL_LINEAR); - texture->setWrap(GL_CLAMP_TO_EDGE); -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h deleted file mode 100644 index ff426cd3425b..000000000000 --- a/libs/hwui/GradientCache.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2010 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_GRADIENT_CACHE_H -#define ANDROID_HWUI_GRADIENT_CACHE_H - -#include - -#include - -#include - -#include -#include - -#include "FloatColor.h" - -namespace android { -namespace uirenderer { - -class Texture; - -struct GradientCacheEntry { - GradientCacheEntry() { - count = 0; - colors = nullptr; - positions = nullptr; - } - - GradientCacheEntry(uint32_t* colors, float* positions, uint32_t count) { - copy(colors, positions, count); - } - - GradientCacheEntry(const GradientCacheEntry& entry) { - copy(entry.colors.get(), entry.positions.get(), entry.count); - } - - GradientCacheEntry& operator=(const GradientCacheEntry& entry) { - if (this != &entry) { - copy(entry.colors.get(), entry.positions.get(), entry.count); - } - - return *this; - } - - hash_t hash() const; - - static int compare(const GradientCacheEntry& lhs, const GradientCacheEntry& rhs); - - bool operator==(const GradientCacheEntry& other) const { return compare(*this, other) == 0; } - - bool operator!=(const GradientCacheEntry& other) const { return compare(*this, other) != 0; } - - std::unique_ptr colors; - std::unique_ptr positions; - uint32_t count; - -private: - void copy(uint32_t* colors, float* positions, uint32_t count) { - this->count = count; - this->colors.reset(new uint32_t[count]); - this->positions.reset(new float[count]); - - memcpy(this->colors.get(), colors, count * sizeof(uint32_t)); - memcpy(this->positions.get(), positions, count * sizeof(float)); - } - -}; // GradientCacheEntry - -// Caching support - -inline int strictly_order_type(const GradientCacheEntry& lhs, const GradientCacheEntry& rhs) { - return GradientCacheEntry::compare(lhs, rhs) < 0; -} - -inline int compare_type(const GradientCacheEntry& lhs, const GradientCacheEntry& rhs) { - return GradientCacheEntry::compare(lhs, rhs); -} - -inline hash_t hash_type(const GradientCacheEntry& entry) { - return entry.hash(); -} - -/** - * A simple LRU gradient cache. The cache has a maximum size expressed in bytes. - * Any texture added to the cache causing the cache to grow beyond the maximum - * allowed size will also cause the oldest texture to be kicked out. - */ -class GradientCache : public OnEntryRemoved { -public: - explicit GradientCache(const Extensions& extensions); - ~GradientCache(); - - /** - * Used as a callback when an entry is removed from the cache. - * Do not invoke directly. - */ - void operator()(GradientCacheEntry& shader, Texture*& texture) override; - - /** - * Returns the texture associated with the specified shader. - */ - Texture* get(uint32_t* colors, float* positions, int count); - - /** - * Clears the cache. This causes all textures to be deleted. - */ - void clear(); - - /** - * Returns the maximum size of the cache in bytes. - */ - uint32_t getMaxSize(); - /** - * Returns the current size of the cache in bytes. - */ - uint32_t getSize(); - -private: - /** - * Adds a new linear gradient to the cache. The generated texture is - * returned. - */ - Texture* addLinearGradient(GradientCacheEntry& gradient, uint32_t* colors, float* positions, - int count); - - void generateTexture(uint32_t* colors, float* positions, const uint32_t width, - const uint32_t height, Texture* texture); - - struct GradientInfo { - uint32_t width; - bool hasAlpha; - }; - - void getGradientInfo(const uint32_t* colors, const int count, GradientInfo& info); - - size_t bytesPerPixel() const; - size_t sourceBytesPerPixel() const; - - typedef void (GradientCache::*ChannelMixer)(const FloatColor& start, const FloatColor& end, - float amount, uint8_t*& dst) const; - - void mixBytes(const FloatColor& start, const FloatColor& end, float amount, - uint8_t*& dst) const; - void mixFloats(const FloatColor& start, const FloatColor& end, float amount, - uint8_t*& dst) const; - - LruCache mCache; - - uint32_t mSize; - const uint32_t mMaxSize; - - GLint mMaxTextureSize; - bool mUseFloatTexture; - bool mHasNpot; - bool mHasLinearBlending; - - mutable Mutex mLock; -}; // class GradientCache - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_GRADIENT_CACHE_H diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp deleted file mode 100644 index 673d73c5475d..000000000000 --- a/libs/hwui/PatchCache.cpp +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (C) 2010 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 -#include - -#include "Caches.h" -#include "Patch.h" -#include "PatchCache.h" -#include "Properties.h" -#include "renderstate/RenderState.h" - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Constructors/destructor -/////////////////////////////////////////////////////////////////////////////// - -PatchCache::PatchCache(RenderState& renderState) - : mRenderState(renderState) - , mMaxSize(KB(128)) - , mSize(0) - , mCache(LruCache::kUnlimitedCapacity) - , mMeshBuffer(0) - , mFreeBlocks(nullptr) {} - -PatchCache::~PatchCache() { - clear(); -} - -/////////////////////////////////////////////////////////////////////////////// -// Caching -/////////////////////////////////////////////////////////////////////////////// - -hash_t PatchCache::PatchDescription::hash() const { - uint32_t hash = JenkinsHashMix(0, android::hash_type(mPatch)); - hash = JenkinsHashMix(hash, mBitmapWidth); - hash = JenkinsHashMix(hash, mBitmapHeight); - hash = JenkinsHashMix(hash, mPixelWidth); - hash = JenkinsHashMix(hash, mPixelHeight); - return JenkinsHashWhiten(hash); -} - -int PatchCache::PatchDescription::compare(const PatchCache::PatchDescription& lhs, - const PatchCache::PatchDescription& rhs) { - return memcmp(&lhs, &rhs, sizeof(PatchDescription)); -} - -void PatchCache::clear() { - clearCache(); - - if (mMeshBuffer) { - mRenderState.meshState().deleteMeshBuffer(mMeshBuffer); - mMeshBuffer = 0; - mSize = 0; - } -} - -void PatchCache::clearCache() { - LruCache::Iterator i(mCache); - while (i.next()) { - delete i.value(); - } - mCache.clear(); - - BufferBlock* block = mFreeBlocks; - while (block) { - BufferBlock* next = block->next; - delete block; - block = next; - } - mFreeBlocks = nullptr; -} - -void PatchCache::remove(Vector& patchesToRemove, Res_png_9patch* patch) { - LruCache::Iterator i(mCache); - while (i.next()) { - const PatchDescription& key = i.key(); - if (key.getPatch() == patch) { - patchesToRemove.push(patch_pair_t(&key, i.value())); - } - } -} - -void PatchCache::removeDeferred(Res_png_9patch* patch) { - Mutex::Autolock _l(mLock); - - // Assert that patch is not already garbage - size_t count = mGarbage.size(); - for (size_t i = 0; i < count; i++) { - if (patch == mGarbage[i]) { - patch = nullptr; - break; - } - } - LOG_ALWAYS_FATAL_IF(patch == nullptr); - - mGarbage.push(patch); -} - -void PatchCache::clearGarbage() { - Vector patchesToRemove; - - { // scope for the mutex - Mutex::Autolock _l(mLock); - size_t count = mGarbage.size(); - for (size_t i = 0; i < count; i++) { - Res_png_9patch* patch = mGarbage[i]; - remove(patchesToRemove, patch); - // A Res_png_9patch is actually an array of byte that's larger - // than sizeof(Res_png_9patch). It must be freed as an array. - delete[](int8_t*) patch; - } - mGarbage.clear(); - } - - // TODO: We could sort patchesToRemove by offset to merge - // adjacent free blocks - for (size_t i = 0; i < patchesToRemove.size(); i++) { - const patch_pair_t& pair = patchesToRemove[i]; - - // Release the patch and mark the space in the free list - Patch* patch = pair.getSecond(); - BufferBlock* block = new BufferBlock(patch->positionOffset, patch->getSize()); - block->next = mFreeBlocks; - mFreeBlocks = block; - - mSize -= patch->getSize(); - - mCache.remove(*pair.getFirst()); - delete patch; - } - -#if DEBUG_PATCHES - if (patchesToRemove.size() > 0) { - dumpFreeBlocks("Removed garbage"); - } -#endif -} - -void PatchCache::createVertexBuffer() { - mRenderState.meshState().genOrUpdateMeshBuffer(&mMeshBuffer, mMaxSize, nullptr, - GL_DYNAMIC_DRAW); - mSize = 0; - mFreeBlocks = new BufferBlock(0, mMaxSize); -} - -/** - * Sets the mesh's offsets and copies its associated vertices into - * the mesh buffer (VBO). - */ -void PatchCache::setupMesh(Patch* newMesh) { - // This call ensures the VBO exists and that it is bound - if (!mMeshBuffer) { - createVertexBuffer(); - } - - // If we're running out of space, let's clear the entire cache - uint32_t size = newMesh->getSize(); - if (mSize + size > mMaxSize) { - clearCache(); - createVertexBuffer(); - } - - // Find a block where we can fit the mesh - BufferBlock* previous = nullptr; - BufferBlock* block = mFreeBlocks; - while (block) { - // The mesh fits - if (block->size >= size) { - break; - } - previous = block; - block = block->next; - } - - // We have enough space left in the buffer, but it's - // too fragmented, let's clear the cache - if (!block) { - clearCache(); - createVertexBuffer(); - previous = nullptr; - block = mFreeBlocks; - } - - // Copy the 9patch mesh in the VBO - newMesh->positionOffset = (GLintptr)(block->offset); - newMesh->textureOffset = newMesh->positionOffset + kMeshTextureOffset; - - mRenderState.meshState().updateMeshBufferSubData(mMeshBuffer, newMesh->positionOffset, size, - newMesh->vertices.get()); - - // Remove the block since we've used it entirely - if (block->size == size) { - if (previous) { - previous->next = block->next; - } else { - mFreeBlocks = block->next; - } - delete block; - } else { - // Resize the block now that it's occupied - block->offset += size; - block->size -= size; - } - - mSize += size; -} - -static const UvMapper sIdentity; - -const Patch* PatchCache::get(const uint32_t bitmapWidth, const uint32_t bitmapHeight, - const float pixelWidth, const float pixelHeight, - const Res_png_9patch* patch) { - const PatchDescription description(bitmapWidth, bitmapHeight, pixelWidth, pixelHeight, patch); - const Patch* mesh = mCache.get(description); - - if (!mesh) { - Patch* newMesh = - new Patch(bitmapWidth, bitmapHeight, pixelWidth, pixelHeight, sIdentity, patch); - - if (newMesh->vertices) { - setupMesh(newMesh); - } - -#if DEBUG_PATCHES - dumpFreeBlocks("Adding patch"); -#endif - - mCache.put(description, newMesh); - return newMesh; - } - - return mesh; -} - -#if DEBUG_PATCHES -void PatchCache::dumpFreeBlocks(const char* prefix) { - String8 dump; - BufferBlock* block = mFreeBlocks; - while (block) { - dump.appendFormat("->(%d, %d)", block->positionOffset, block->size); - block = block->next; - } - ALOGD("%s: Free blocks%s", prefix, dump.string()); -} -#endif - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h deleted file mode 100644 index 273c3f56f2cd..000000000000 --- a/libs/hwui/PatchCache.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#pragma once - -#include - -#include - -#include - -#include "Debug.h" -#include "utils/Pair.h" - -namespace android { -namespace uirenderer { - -class Patch; - -/////////////////////////////////////////////////////////////////////////////// -// Defines -/////////////////////////////////////////////////////////////////////////////// - -// Debug -#if DEBUG_PATCHES -#define PATCH_LOGD(...) ALOGD(__VA_ARGS__) -#else -#define PATCH_LOGD(...) -#endif - -/////////////////////////////////////////////////////////////////////////////// -// Cache -/////////////////////////////////////////////////////////////////////////////// - -class Caches; -class RenderState; - -class PatchCache { -public: - explicit PatchCache(RenderState& renderState); - ~PatchCache(); - - const Patch* get(const uint32_t bitmapWidth, const uint32_t bitmapHeight, - const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch); - void clear(); - - uint32_t getSize() const { return mSize; } - - uint32_t getMaxSize() const { return mMaxSize; } - - GLuint getMeshBuffer() const { return mMeshBuffer; } - - /** - * Removes the entries associated with the specified 9-patch. This is meant - * to be called from threads that are not the EGL context thread (GC thread - * on the VM side for instance.) - */ - void removeDeferred(Res_png_9patch* patch); - - /** - * Process deferred removals. - */ - void clearGarbage(); - -private: - struct PatchDescription { - PatchDescription() - : mPatch(nullptr) - , mBitmapWidth(0) - , mBitmapHeight(0) - , mPixelWidth(0) - , mPixelHeight(0) {} - - PatchDescription(const uint32_t bitmapWidth, const uint32_t bitmapHeight, - const float pixelWidth, const float pixelHeight, - const Res_png_9patch* patch) - : mPatch(patch) - , mBitmapWidth(bitmapWidth) - , mBitmapHeight(bitmapHeight) - , mPixelWidth(pixelWidth) - , mPixelHeight(pixelHeight) {} - - hash_t hash() const; - - const Res_png_9patch* getPatch() const { return mPatch; } - - static int compare(const PatchDescription& lhs, const PatchDescription& rhs); - - bool operator==(const PatchDescription& other) const { return compare(*this, other) == 0; } - - bool operator!=(const PatchDescription& other) const { return compare(*this, other) != 0; } - - friend inline int strictly_order_type(const PatchDescription& lhs, - const PatchDescription& rhs) { - return PatchDescription::compare(lhs, rhs) < 0; - } - - friend inline int compare_type(const PatchDescription& lhs, const PatchDescription& rhs) { - return PatchDescription::compare(lhs, rhs); - } - - friend inline hash_t hash_type(const PatchDescription& entry) { return entry.hash(); } - - private: - const Res_png_9patch* mPatch; - uint32_t mBitmapWidth; - uint32_t mBitmapHeight; - float mPixelWidth; - float mPixelHeight; - - }; // struct PatchDescription - - /** - * A buffer block represents an empty range in the mesh buffer - * that can be used to store vertices. - * - * The patch cache maintains a linked-list of buffer blocks - * to track available regions of memory in the VBO. - */ - struct BufferBlock { - BufferBlock(uint32_t offset, uint32_t size) : offset(offset), size(size), next(nullptr) {} - - uint32_t offset; - uint32_t size; - - BufferBlock* next; - }; // struct BufferBlock - - typedef Pair patch_pair_t; - - void clearCache(); - void createVertexBuffer(); - - void setupMesh(Patch* newMesh); - - void remove(Vector& patchesToRemove, Res_png_9patch* patch); - -#if DEBUG_PATCHES - void dumpFreeBlocks(const char* prefix); -#endif - - RenderState& mRenderState; - const uint32_t mMaxSize; - uint32_t mSize; - - LruCache mCache; - - GLuint mMeshBuffer; - // First available free block inside the mesh buffer - BufferBlock* mFreeBlocks; - - // Garbage tracking, required to handle GC events on the VM side - Vector mGarbage; - mutable Mutex mLock; -}; // class PatchCache - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp deleted file mode 100644 index e67c5bddd354..000000000000 --- a/libs/hwui/PathCache.cpp +++ /dev/null @@ -1,559 +0,0 @@ -/* - * Copyright (C) 2013 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "Caches.h" -#include "PathCache.h" - -#include "thread/Signal.h" -#include "thread/TaskProcessor.h" - -#include - -namespace android { -namespace uirenderer { - -static constexpr size_t PATH_CACHE_COUNT_LIMIT = 256; - -template -static bool compareWidthHeight(const T& lhs, const T& rhs) { - return (lhs.mWidth == rhs.mWidth) && (lhs.mHeight == rhs.mHeight); -} - -static bool compareRoundRects(const PathDescription::Shape::RoundRect& lhs, - const PathDescription::Shape::RoundRect& rhs) { - return compareWidthHeight(lhs, rhs) && lhs.mRx == rhs.mRx && lhs.mRy == rhs.mRy; -} - -static bool compareArcs(const PathDescription::Shape::Arc& lhs, - const PathDescription::Shape::Arc& rhs) { - return compareWidthHeight(lhs, rhs) && lhs.mStartAngle == rhs.mStartAngle && - lhs.mSweepAngle == rhs.mSweepAngle && lhs.mUseCenter == rhs.mUseCenter; -} - -/////////////////////////////////////////////////////////////////////////////// -// Cache entries -/////////////////////////////////////////////////////////////////////////////// - -PathDescription::PathDescription() - : type(ShapeType::None) - , join(SkPaint::kDefault_Join) - , cap(SkPaint::kDefault_Cap) - , style(SkPaint::kFill_Style) - , miter(4.0f) - , strokeWidth(1.0f) - , pathEffect(nullptr) { - // Shape bits should be set to zeroes, because they are used for hash calculation. - memset(&shape, 0, sizeof(Shape)); -} - -PathDescription::PathDescription(ShapeType type, const SkPaint* paint) - : type(type) - , join(paint->getStrokeJoin()) - , cap(paint->getStrokeCap()) - , style(paint->getStyle()) - , miter(paint->getStrokeMiter()) - , strokeWidth(paint->getStrokeWidth()) - , pathEffect(paint->getPathEffect()) { - // Shape bits should be set to zeroes, because they are used for hash calculation. - memset(&shape, 0, sizeof(Shape)); -} - -hash_t PathDescription::hash() const { - uint32_t hash = JenkinsHashMix(0, static_cast(type)); - hash = JenkinsHashMix(hash, join); - hash = JenkinsHashMix(hash, cap); - hash = JenkinsHashMix(hash, style); - hash = JenkinsHashMix(hash, android::hash_type(miter)); - hash = JenkinsHashMix(hash, android::hash_type(strokeWidth)); - hash = JenkinsHashMix(hash, android::hash_type(pathEffect)); - hash = JenkinsHashMixBytes(hash, (uint8_t*)&shape, sizeof(Shape)); - return JenkinsHashWhiten(hash); -} - -bool PathDescription::operator==(const PathDescription& rhs) const { - if (type != rhs.type) return false; - if (join != rhs.join) return false; - if (cap != rhs.cap) return false; - if (style != rhs.style) return false; - if (miter != rhs.miter) return false; - if (strokeWidth != rhs.strokeWidth) return false; - if (pathEffect != rhs.pathEffect) return false; - switch (type) { - case ShapeType::None: - return 0; - case ShapeType::Rect: - return compareWidthHeight(shape.rect, rhs.shape.rect); - case ShapeType::RoundRect: - return compareRoundRects(shape.roundRect, rhs.shape.roundRect); - case ShapeType::Circle: - return shape.circle.mRadius == rhs.shape.circle.mRadius; - case ShapeType::Oval: - return compareWidthHeight(shape.oval, rhs.shape.oval); - case ShapeType::Arc: - return compareArcs(shape.arc, rhs.shape.arc); - case ShapeType::Path: - return shape.path.mGenerationID == rhs.shape.path.mGenerationID; - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Utilities -/////////////////////////////////////////////////////////////////////////////// - -static void computePathBounds(const SkPath* path, const SkPaint* paint, PathTexture* texture, - uint32_t& width, uint32_t& height) { - const SkRect& bounds = path->getBounds(); - const float pathWidth = std::max(bounds.width(), 1.0f); - const float pathHeight = std::max(bounds.height(), 1.0f); - - texture->left = floorf(bounds.fLeft); - texture->top = floorf(bounds.fTop); - - texture->offset = (int)floorf(std::max(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f); - - width = uint32_t(pathWidth + texture->offset * 2.0 + 0.5); - height = uint32_t(pathHeight + texture->offset * 2.0 + 0.5); -} - -static void initPaint(SkPaint& paint) { - // Make sure the paint is opaque, color, alpha, filter, etc. - // will be applied later when compositing the alpha8 texture - paint.setColor(SK_ColorBLACK); - paint.setAlpha(255); - paint.setColorFilter(nullptr); - paint.setMaskFilter(nullptr); - paint.setShader(nullptr); - paint.setBlendMode(SkBlendMode::kSrc); -} - -static sk_sp drawPath(const SkPath* path, const SkPaint* paint, PathTexture* texture, - uint32_t maxTextureSize) { - uint32_t width, height; - computePathBounds(path, paint, texture, width, height); - if (width > maxTextureSize || height > maxTextureSize) { - ALOGW("Shape too large to be rendered into a texture (%dx%d, max=%dx%d)", width, height, - maxTextureSize, maxTextureSize); - return nullptr; - } - - sk_sp bitmap = Bitmap::allocateHeapBitmap(SkImageInfo::MakeA8(width, height)); - SkPaint pathPaint(*paint); - initPaint(pathPaint); - - SkBitmap skBitmap; - bitmap->getSkBitmap(&skBitmap); - skBitmap.eraseColor(0); - SkCanvas canvas(skBitmap); - canvas.translate(-texture->left + texture->offset, -texture->top + texture->offset); - canvas.drawPath(*path, pathPaint); - return bitmap; -} - -/////////////////////////////////////////////////////////////////////////////// -// Cache constructor/destructor -/////////////////////////////////////////////////////////////////////////////// - -PathCache::PathCache() - : mCache(LruCache::kUnlimitedCapacity) - , mSize(0) - , mMaxSize(DeviceInfo::multiplyByResolution(4)) { - mCache.setOnEntryRemovedListener(this); - mMaxTextureSize = DeviceInfo::get()->maxTextureSize(); - mDebugEnabled = Properties::debugLevel & kDebugCaches; -} - -PathCache::~PathCache() { - mCache.clear(); -} - -/////////////////////////////////////////////////////////////////////////////// -// Size management -/////////////////////////////////////////////////////////////////////////////// - -uint32_t PathCache::getSize() { - return mSize; -} - -uint32_t PathCache::getMaxSize() { - return mMaxSize; -} - -/////////////////////////////////////////////////////////////////////////////// -// Callbacks -/////////////////////////////////////////////////////////////////////////////// - -void PathCache::operator()(PathDescription& entry, PathTexture*& texture) { - removeTexture(texture); -} - -/////////////////////////////////////////////////////////////////////////////// -// Caching -/////////////////////////////////////////////////////////////////////////////// - -void PathCache::removeTexture(PathTexture* texture) { - if (texture) { - const uint32_t size = texture->width() * texture->height(); - - // If there is a pending task we must wait for it to return - // before attempting our cleanup - const sp& task = texture->task(); - if (task != nullptr) { - task->getResult(); - texture->clearTask(); - } else { - // If there is a pending task, the path was not added - // to the cache and the size wasn't increased - if (size > mSize) { - ALOGE("Removing path texture of size %d will leave " - "the cache in an inconsistent state", - size); - } - mSize -= size; - } - - PATH_LOGD("PathCache::delete name, size, mSize = %d, %d, %d", texture->id, size, mSize); - if (mDebugEnabled) { - ALOGD("Shape deleted, size = %d", size); - } - - texture->deleteTexture(); - delete texture; - } -} - -void PathCache::purgeCache(uint32_t width, uint32_t height) { - const uint32_t size = width * height; - // Don't even try to cache a bitmap that's bigger than the cache - if (size < mMaxSize) { - while (mSize + size > mMaxSize) { - mCache.removeOldest(); - } - } -} - -void PathCache::trim() { - while (mSize > mMaxSize || mCache.size() > PATH_CACHE_COUNT_LIMIT) { - LOG_ALWAYS_FATAL_IF(!mCache.size(), - "Inconsistent mSize! Ran out of items to remove!" - " mSize = %u, mMaxSize = %u", - mSize, mMaxSize); - mCache.removeOldest(); - } -} - -PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath* path, - const SkPaint* paint) { - ATRACE_NAME("Generate Path Texture"); - - PathTexture* texture = new PathTexture(Caches::getInstance(), path->getGenerationID()); - sk_sp bitmap(drawPath(path, paint, texture, mMaxTextureSize)); - if (!bitmap) { - delete texture; - return nullptr; - } - - purgeCache(bitmap->width(), bitmap->height()); - generateTexture(entry, *bitmap, texture); - return texture; -} - -void PathCache::generateTexture(const PathDescription& entry, Bitmap& bitmap, PathTexture* texture, - bool addToCache) { - generateTexture(bitmap, texture); - - // Note here that we upload to a texture even if it's bigger than mMaxSize. - // Such an entry in mCache will only be temporary, since it will be evicted - // immediately on trim, or on any other Path entering the cache. - uint32_t size = texture->width() * texture->height(); - mSize += size; - PATH_LOGD("PathCache::get/create: name, size, mSize = %d, %d, %d", texture->id, size, mSize); - if (mDebugEnabled) { - ALOGD("Shape created, size = %d", size); - } - if (addToCache) { - mCache.put(entry, texture); - } -} - -void PathCache::clear() { - mCache.clear(); -} - -void PathCache::generateTexture(Bitmap& bitmap, Texture* texture) { - ATRACE_NAME("Upload Path Texture"); - texture->upload(bitmap); - texture->setFilter(GL_LINEAR); -} - -/////////////////////////////////////////////////////////////////////////////// -// Path precaching -/////////////////////////////////////////////////////////////////////////////// - -PathCache::PathProcessor::PathProcessor(Caches& caches) - : TaskProcessor >(&caches.tasks), mMaxTextureSize(caches.maxTextureSize) {} - -void PathCache::PathProcessor::onProcess(const sp > >& task) { - PathTask* t = static_cast(task.get()); - ATRACE_NAME("pathPrecache"); - - t->setResult(drawPath(&t->path, &t->paint, t->texture, mMaxTextureSize)); -} - -/////////////////////////////////////////////////////////////////////////////// -// Paths -/////////////////////////////////////////////////////////////////////////////// - -void PathCache::removeDeferred(const SkPath* path) { - Mutex::Autolock l(mLock); - mGarbage.push_back(path->getGenerationID()); -} - -void PathCache::clearGarbage() { - Vector pathsToRemove; - - { // scope for the mutex - Mutex::Autolock l(mLock); - for (const uint32_t generationID : mGarbage) { - LruCache::Iterator iter(mCache); - while (iter.next()) { - const PathDescription& key = iter.key(); - if (key.type == ShapeType::Path && key.shape.path.mGenerationID == generationID) { - pathsToRemove.push(key); - } - } - } - mGarbage.clear(); - } - - for (size_t i = 0; i < pathsToRemove.size(); i++) { - mCache.remove(pathsToRemove.itemAt(i)); - } -} - -PathTexture* PathCache::get(const SkPath* path, const SkPaint* paint) { - PathDescription entry(ShapeType::Path, paint); - entry.shape.path.mGenerationID = path->getGenerationID(); - - PathTexture* texture = mCache.get(entry); - - if (!texture) { - texture = addTexture(entry, path, paint); - } else { - // A bitmap is attached to the texture, this means we need to - // upload it as a GL texture - const sp& task = texture->task(); - if (task != nullptr) { - // But we must first wait for the worker thread to be done - // producing the bitmap, so let's wait - sk_sp bitmap = task->getResult(); - if (bitmap) { - generateTexture(entry, *bitmap, texture, false); - texture->clearTask(); - } else { - texture->clearTask(); - texture = nullptr; - mCache.remove(entry); - } - } - } - - return texture; -} - -void PathCache::remove(const SkPath* path, const SkPaint* paint) { - PathDescription entry(ShapeType::Path, paint); - entry.shape.path.mGenerationID = path->getGenerationID(); - mCache.remove(entry); -} - -void PathCache::precache(const SkPath* path, const SkPaint* paint) { - if (!Caches::getInstance().tasks.canRunTasks()) { - return; - } - - PathDescription entry(ShapeType::Path, paint); - entry.shape.path.mGenerationID = path->getGenerationID(); - - PathTexture* texture = mCache.get(entry); - - bool generate = false; - if (!texture) { - generate = true; - } - - if (generate) { - // It is important to specify the generation ID so we do not - // attempt to precache the same path several times - texture = new PathTexture(Caches::getInstance(), path->getGenerationID()); - sp task = new PathTask(path, paint, texture); - texture->setTask(task); - - // During the precaching phase we insert path texture objects into - // the cache that do not point to any GL texture. They are instead - // treated as a task for the precaching worker thread. This is why - // we do not check the cache limit when inserting these objects. - // The conversion into GL texture will happen in get(), when a client - // asks for a path texture. This is also when the cache limit will - // be enforced. - mCache.put(entry, texture); - - if (mProcessor == nullptr) { - mProcessor = new PathProcessor(Caches::getInstance()); - } - mProcessor->add(task); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Rounded rects -/////////////////////////////////////////////////////////////////////////////// - -PathTexture* PathCache::getRoundRect(float width, float height, float rx, float ry, - const SkPaint* paint) { - PathDescription entry(ShapeType::RoundRect, paint); - entry.shape.roundRect.mWidth = width; - entry.shape.roundRect.mHeight = height; - entry.shape.roundRect.mRx = rx; - entry.shape.roundRect.mRy = ry; - - PathTexture* texture = get(entry); - - if (!texture) { - SkPath path; - SkRect r; - r.set(0.0f, 0.0f, width, height); - path.addRoundRect(r, rx, ry, SkPath::kCW_Direction); - - texture = addTexture(entry, &path, paint); - } - - return texture; -} - -/////////////////////////////////////////////////////////////////////////////// -// Circles -/////////////////////////////////////////////////////////////////////////////// - -PathTexture* PathCache::getCircle(float radius, const SkPaint* paint) { - PathDescription entry(ShapeType::Circle, paint); - entry.shape.circle.mRadius = radius; - - PathTexture* texture = get(entry); - - if (!texture) { - SkPath path; - path.addCircle(radius, radius, radius, SkPath::kCW_Direction); - - texture = addTexture(entry, &path, paint); - } - - return texture; -} - -/////////////////////////////////////////////////////////////////////////////// -// Ovals -/////////////////////////////////////////////////////////////////////////////// - -PathTexture* PathCache::getOval(float width, float height, const SkPaint* paint) { - PathDescription entry(ShapeType::Oval, paint); - entry.shape.oval.mWidth = width; - entry.shape.oval.mHeight = height; - - PathTexture* texture = get(entry); - - if (!texture) { - SkPath path; - SkRect r; - r.set(0.0f, 0.0f, width, height); - path.addOval(r, SkPath::kCW_Direction); - - texture = addTexture(entry, &path, paint); - } - - return texture; -} - -/////////////////////////////////////////////////////////////////////////////// -// Rects -/////////////////////////////////////////////////////////////////////////////// - -PathTexture* PathCache::getRect(float width, float height, const SkPaint* paint) { - PathDescription entry(ShapeType::Rect, paint); - entry.shape.rect.mWidth = width; - entry.shape.rect.mHeight = height; - - PathTexture* texture = get(entry); - - if (!texture) { - SkPath path; - SkRect r; - r.set(0.0f, 0.0f, width, height); - path.addRect(r, SkPath::kCW_Direction); - - texture = addTexture(entry, &path, paint); - } - - return texture; -} - -/////////////////////////////////////////////////////////////////////////////// -// Arcs -/////////////////////////////////////////////////////////////////////////////// - -PathTexture* PathCache::getArc(float width, float height, float startAngle, float sweepAngle, - bool useCenter, const SkPaint* paint) { - PathDescription entry(ShapeType::Arc, paint); - entry.shape.arc.mWidth = width; - entry.shape.arc.mHeight = height; - entry.shape.arc.mStartAngle = startAngle; - entry.shape.arc.mSweepAngle = sweepAngle; - entry.shape.arc.mUseCenter = useCenter; - - PathTexture* texture = get(entry); - - if (!texture) { - SkPath path; - SkRect r; - r.set(0.0f, 0.0f, width, height); - if (useCenter) { - path.moveTo(r.centerX(), r.centerY()); - } - path.arcTo(r, startAngle, sweepAngle, !useCenter); - if (useCenter) { - path.close(); - } - - texture = addTexture(entry, &path, paint); - } - - return texture; -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h deleted file mode 100644 index 28c8bbb8ca6e..000000000000 --- a/libs/hwui/PathCache.h +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (C) 2013 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_PATH_CACHE_H -#define ANDROID_HWUI_PATH_CACHE_H - -#include "Debug.h" -#include "Texture.h" -#include "hwui/Bitmap.h" -#include "thread/Task.h" -#include "thread/TaskProcessor.h" -#include "utils/Macros.h" -#include "utils/Pair.h" - -#include -#include -#include -#include -#include - -#include - -class SkCanvas; -class SkPaint; -struct SkRect; - -namespace android { -namespace uirenderer { - -class Caches; -/////////////////////////////////////////////////////////////////////////////// -// Defines -/////////////////////////////////////////////////////////////////////////////// - -// Debug -#if DEBUG_PATHS -#define PATH_LOGD(...) ALOGD(__VA_ARGS__) -#else -#define PATH_LOGD(...) -#endif - -/////////////////////////////////////////////////////////////////////////////// -// Classes -/////////////////////////////////////////////////////////////////////////////// - -struct PathTexture; -class PathTask : public Task> { -public: - PathTask(const SkPath* path, const SkPaint* paint, PathTexture* texture) - : path(*path), paint(*paint), texture(texture) {} - - // copied, since input path not guaranteed to survive for duration of task - const SkPath path; - - // copied, since input paint may not be immutable - const SkPaint paint; - PathTexture* texture; -}; - -/** - * Alpha texture used to represent a path. - */ -struct PathTexture : public Texture { - PathTexture(Caches& caches, int generation) : Texture(caches) { this->generation = generation; } - - ~PathTexture() { clearTask(); } - - /** - * Left coordinate of the path bounds. - */ - float left = 0; - /** - * Top coordinate of the path bounds. - */ - float top = 0; - /** - * Offset to draw the path at the correct origin. - */ - float offset = 0; - - sp task() const { return mTask; } - - void setTask(const sp& task) { mTask = task; } - - void clearTask() { - if (mTask != nullptr) { - mTask.clear(); - } - } - -private: - sp mTask; -}; // struct PathTexture - -enum class ShapeType { None, Rect, RoundRect, Circle, Oval, Arc, Path }; - -struct PathDescription { - HASHABLE_TYPE(PathDescription); - ShapeType type; - SkPaint::Join join; - SkPaint::Cap cap; - SkPaint::Style style; - float miter; - float strokeWidth; - SkPathEffect* pathEffect; - union Shape { - struct Path { - uint32_t mGenerationID; - } path; - struct RoundRect { - float mWidth; - float mHeight; - float mRx; - float mRy; - } roundRect; - struct Circle { - float mRadius; - } circle; - struct Oval { - float mWidth; - float mHeight; - } oval; - struct Rect { - float mWidth; - float mHeight; - } rect; - struct Arc { - float mWidth; - float mHeight; - float mStartAngle; - float mSweepAngle; - bool mUseCenter; - } arc; - } shape; - - PathDescription(); - PathDescription(ShapeType shapeType, const SkPaint* paint); -}; - -/** - * A simple LRU shape cache. The cache has a maximum size expressed in bytes. - * Any texture added to the cache causing the cache to grow beyond the maximum - * allowed size will also cause the oldest texture to be kicked out. - */ -class PathCache : public OnEntryRemoved { -public: - PathCache(); - ~PathCache(); - - /** - * Used as a callback when an entry is removed from the cache. - * Do not invoke directly. - */ - void operator()(PathDescription& path, PathTexture*& texture) override; - - /** - * Clears the cache. This causes all textures to be deleted. - */ - void clear(); - - /** - * Returns the maximum size of the cache in bytes. - */ - uint32_t getMaxSize(); - /** - * Returns the current size of the cache in bytes. - */ - uint32_t getSize(); - - PathTexture* getRoundRect(float width, float height, float rx, float ry, const SkPaint* paint); - PathTexture* getCircle(float radius, const SkPaint* paint); - PathTexture* getOval(float width, float height, const SkPaint* paint); - PathTexture* getRect(float width, float height, const SkPaint* paint); - PathTexture* getArc(float width, float height, float startAngle, float sweepAngle, - bool useCenter, const SkPaint* paint); - PathTexture* get(const SkPath* path, const SkPaint* paint); - void remove(const SkPath* path, const SkPaint* paint); - - /** - * Removes the specified path. This is meant to be called from threads - * that are not the EGL context thread. - */ - ANDROID_API void removeDeferred(const SkPath* path); - /** - * Process deferred removals. - */ - void clearGarbage(); - /** - * Trims the contents of the cache, removing items until it's under its - * specified limit. - * - * Trimming is used for caches that support pre-caching from a worker - * thread. During pre-caching the maximum limit of the cache can be - * exceeded for the duration of the frame. It is therefore required to - * trim the cache at the end of the frame to keep the total amount of - * memory used under control. - */ - void trim(); - - /** - * Precaches the specified path using background threads. - */ - void precache(const SkPath* path, const SkPaint* paint); - -private: - PathTexture* addTexture(const PathDescription& entry, const SkPath* path, const SkPaint* paint); - - /** - * Generates the texture from a bitmap into the specified texture structure. - */ - void generateTexture(Bitmap& bitmap, Texture* texture); - void generateTexture(const PathDescription& entry, Bitmap& bitmap, PathTexture* texture, - bool addToCache = true); - - PathTexture* get(const PathDescription& entry) { return mCache.get(entry); } - - /** - * Ensures there is enough space in the cache for a texture of the specified - * dimensions. - */ - void purgeCache(uint32_t width, uint32_t height); - - void removeTexture(PathTexture* texture); - - void init(); - - class PathProcessor : public TaskProcessor> { - public: - explicit PathProcessor(Caches& caches); - ~PathProcessor() {} - - virtual void onProcess(const sp>>& task) override; - - private: - uint32_t mMaxTextureSize; - }; - - LruCache mCache; - uint32_t mSize; - const uint32_t mMaxSize; - GLuint mMaxTextureSize; - - bool mDebugEnabled; - - sp mProcessor; - - std::vector mGarbage; - mutable Mutex mLock; -}; // class PathCache - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_PATH_CACHE_H diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp deleted file mode 100644 index 2839ed7307d5..000000000000 --- a/libs/hwui/ProgramCache.cpp +++ /dev/null @@ -1,865 +0,0 @@ -/* - * Copyright (C) 2010 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 - -#include "Caches.h" -#include "ProgramCache.h" -#include "Properties.h" - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Defines -/////////////////////////////////////////////////////////////////////////////// - -#define MODULATE_OP_NO_MODULATE 0 -#define MODULATE_OP_MODULATE 1 -#define MODULATE_OP_MODULATE_A8 2 - -#define STR(x) STR1(x) -#define STR1(x) #x - -/////////////////////////////////////////////////////////////////////////////// -// Vertex shaders snippets -/////////////////////////////////////////////////////////////////////////////// - -const char* gVS_Header_Start = - "#version 100\n" - "attribute vec4 position;\n"; -const char* gVS_Header_Attributes_TexCoords = "attribute vec2 texCoords;\n"; -const char* gVS_Header_Attributes_Colors = "attribute vec4 colors;\n"; -const char* gVS_Header_Attributes_VertexAlphaParameters = "attribute float vtxAlpha;\n"; -const char* gVS_Header_Uniforms_TextureTransform = "uniform mat4 mainTextureTransform;\n"; -const char* gVS_Header_Uniforms = - "uniform mat4 projection;\n" - "uniform mat4 transform;\n"; -const char* gVS_Header_Uniforms_HasGradient = "uniform mat4 screenSpace;\n"; -const char* gVS_Header_Uniforms_HasBitmap = - "uniform mat4 textureTransform;\n" - "uniform mediump vec2 textureDimension;\n"; -const char* gVS_Header_Uniforms_HasRoundRectClip = - "uniform mat4 roundRectInvTransform;\n" - "uniform mediump vec4 roundRectInnerRectLTWH;\n" - "uniform mediump float roundRectRadius;\n"; -const char* gVS_Header_Varyings_HasTexture = "varying highp vec2 outTexCoords;\n"; -const char* gVS_Header_Varyings_HasColors = "varying vec4 outColors;\n"; -const char* gVS_Header_Varyings_HasVertexAlpha = "varying float alpha;\n"; -const char* gVS_Header_Varyings_HasBitmap = "varying highp vec2 outBitmapTexCoords;\n"; -const char* gVS_Header_Varyings_HasGradient[6] = { - // Linear - "varying highp vec2 linear;\n", "varying float linear;\n", - - // Circular - "varying highp vec2 circular;\n", "varying highp vec2 circular;\n", - - // Sweep - "varying highp vec2 sweep;\n", "varying highp vec2 sweep;\n", -}; -const char* gVS_Header_Varyings_HasRoundRectClip = "varying mediump vec2 roundRectPos;\n"; -const char* gVS_Main = "\nvoid main(void) {\n"; -const char* gVS_Main_OutTexCoords = " outTexCoords = texCoords;\n"; -const char* gVS_Main_OutColors = " outColors = colors;\n"; -const char* gVS_Main_OutTransformedTexCoords = - " outTexCoords = (mainTextureTransform * vec4(texCoords, 0.0, 1.0)).xy;\n"; -const char* gVS_Main_OutGradient[6] = { - // Linear - " linear = vec2((screenSpace * position).x, 0.5);\n", - " linear = (screenSpace * position).x;\n", - - // Circular - " circular = (screenSpace * position).xy;\n", - " circular = (screenSpace * position).xy;\n", - - // Sweep - " sweep = (screenSpace * position).xy;\n", " sweep = (screenSpace * position).xy;\n"}; -const char* gVS_Main_OutBitmapTexCoords = - " outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n"; -const char* gVS_Main_Position = - " vec4 transformedPosition = projection * transform * position;\n" - " gl_Position = transformedPosition;\n"; - -const char* gVS_Main_VertexAlpha = " alpha = vtxAlpha;\n"; - -const char* gVS_Main_HasRoundRectClip = - " roundRectPos = ((roundRectInvTransform * transformedPosition).xy / roundRectRadius) - " - "roundRectInnerRectLTWH.xy;\n"; -const char* gVS_Footer = "}\n\n"; - -/////////////////////////////////////////////////////////////////////////////// -// Fragment shaders snippets -/////////////////////////////////////////////////////////////////////////////// - -const char* gFS_Header_Start = "#version 100\n"; -const char* gFS_Header_Extension_FramebufferFetch = - "#extension GL_NV_shader_framebuffer_fetch : enable\n\n"; -const char* gFS_Header_Extension_ExternalTexture = - "#extension GL_OES_EGL_image_external : require\n\n"; -const char* gFS_Header = "precision mediump float;\n\n"; -const char* gFS_Uniforms_Color = "uniform vec4 color;\n"; -const char* gFS_Uniforms_TextureSampler = "uniform sampler2D baseSampler;\n"; -const char* gFS_Uniforms_ExternalTextureSampler = "uniform samplerExternalOES baseSampler;\n"; -const char* gFS_Uniforms_GradientSampler[2] = { - "uniform vec2 screenSize;\n" - "uniform sampler2D gradientSampler;\n", - - "uniform vec2 screenSize;\n" - "uniform vec4 startColor;\n" - "uniform vec4 endColor;\n"}; -const char* gFS_Uniforms_BitmapSampler = "uniform sampler2D bitmapSampler;\n"; -const char* gFS_Uniforms_BitmapExternalSampler = "uniform samplerExternalOES bitmapSampler;\n"; -const char* gFS_Uniforms_ColorOp[3] = { - // None - "", - // Matrix - "uniform mat4 colorMatrix;\n" - "uniform vec4 colorMatrixVector;\n", - // PorterDuff - "uniform vec4 colorBlend;\n"}; - -const char* gFS_Uniforms_HasRoundRectClip = - "uniform mediump vec4 roundRectInnerRectLTWH;\n" - "uniform mediump float roundRectRadius;\n"; - -const char* gFS_Uniforms_ColorSpaceConversion = - // TODO: Should we use a 3D LUT to combine the matrix and transfer functions? - // 32x32x32 fp16 LUTs (for scRGB output) are large and heavy to generate... - "uniform mat3 colorSpaceMatrix;\n"; - -const char* gFS_Uniforms_TransferFunction[4] = { - // In this order: g, a, b, c, d, e, f - // See ColorSpace::TransferParameters - // We'll use hardware sRGB conversion as much as possible - "", "uniform float transferFunction[7];\n", "uniform float transferFunction[5];\n", - "uniform float transferFunctionGamma;\n"}; - -const char* gFS_OETF[2] = { - R"__SHADER__( - vec4 OETF(const vec4 linear) { - return linear; - } - )__SHADER__", - // We expect linear data to be scRGB so we mirror the gamma function - R"__SHADER__( - vec4 OETF(const vec4 linear) { - return vec4(sign(linear.rgb) * OETF_sRGB(abs(linear.rgb)), linear.a); - } - )__SHADER__"}; - -const char* gFS_ColorConvert[3] = { - // Just OETF - R"__SHADER__( - vec4 colorConvert(const vec4 color) { - return OETF(color); - } - )__SHADER__", - // Full color conversion for opaque bitmaps - R"__SHADER__( - vec4 colorConvert(const vec4 color) { - return OETF(vec4(colorSpaceMatrix * EOTF_Parametric(color.rgb), color.a)); - } - )__SHADER__", - // Full color conversion for translucent bitmaps - // Note: 0.5/256=0.0019 - R"__SHADER__( - vec4 colorConvert(in vec4 color) { - color.rgb /= color.a + 0.0019; - color = OETF(vec4(colorSpaceMatrix * EOTF_Parametric(color.rgb), color.a)); - color.rgb *= color.a + 0.0019; - return color; - } - )__SHADER__", -}; - -const char* gFS_sRGB_TransferFunctions = R"__SHADER__( - float OETF_sRGB(const float linear) { - // IEC 61966-2-1:1999 - return linear <= 0.0031308 ? linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055; - } - - vec3 OETF_sRGB(const vec3 linear) { - return vec3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b)); - } - - float EOTF_sRGB(float srgb) { - // IEC 61966-2-1:1999 - return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4); - } -)__SHADER__"; - -const char* gFS_TransferFunction[4] = { - // Conversion done by the texture unit (sRGB) - R"__SHADER__( - vec3 EOTF_Parametric(const vec3 x) { - return x; - } - )__SHADER__", - // Full transfer function - // TODO: We should probably use a 1D LUT (256x1 with texelFetch() since input is 8 bit) - // TODO: That would cause 3 dependent texture fetches. Is it worth it? - R"__SHADER__( - float EOTF_Parametric(float x) { - return x <= transferFunction[4] - ? transferFunction[3] * x + transferFunction[6] - : pow(transferFunction[1] * x + transferFunction[2], transferFunction[0]) - + transferFunction[5]; - } - - vec3 EOTF_Parametric(const vec3 x) { - return vec3(EOTF_Parametric(x.r), EOTF_Parametric(x.g), EOTF_Parametric(x.b)); - } - )__SHADER__", - // Limited transfer function, e = f = 0.0 - R"__SHADER__( - float EOTF_Parametric(float x) { - return x <= transferFunction[4] - ? transferFunction[3] * x - : pow(transferFunction[1] * x + transferFunction[2], transferFunction[0]); - } - - vec3 EOTF_Parametric(const vec3 x) { - return vec3(EOTF_Parametric(x.r), EOTF_Parametric(x.g), EOTF_Parametric(x.b)); - } - )__SHADER__", - // Gamma transfer function, e = f = 0.0 - R"__SHADER__( - vec3 EOTF_Parametric(const vec3 x) { - return vec3(pow(x.r, transferFunctionGamma), - pow(x.g, transferFunctionGamma), - pow(x.b, transferFunctionGamma)); - } - )__SHADER__"}; - -// Dithering must be done in the quantization space -// When we are writing to an sRGB framebuffer, we must do the following: -// EOTF(OETF(color) + dither) -// The dithering pattern is generated with a triangle noise generator in the range [-1.0,1.0] -// TODO: Handle linear fp16 render targets -const char* gFS_GradientFunctions = R"__SHADER__( - float triangleNoise(const highp vec2 n) { - highp vec2 p = fract(n * vec2(5.3987, 5.4421)); - p += dot(p.yx, p.xy + vec2(21.5351, 14.3137)); - highp float xy = p.x * p.y; - return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0; - } -)__SHADER__"; - -const char* gFS_GradientPreamble[2] = { - // Linear framebuffer - R"__SHADER__( - vec4 dither(const vec4 color) { - return color + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0); - } - )__SHADER__", - // sRGB framebuffer - R"__SHADER__( - vec4 dither(const vec4 color) { - vec3 dithered = sqrt(color.rgb) + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0); - return vec4(dithered * dithered, color.a); - } - )__SHADER__", -}; - -// Uses luminance coefficients from Rec.709 to choose the appropriate gamma -// The gamma() function assumes that bright text will be displayed on a dark -// background and that dark text will be displayed on bright background -// The gamma coefficient is chosen to thicken or thin the text accordingly -// The dot product used to compute the luminance could be approximated with -// a simple max(color.r, color.g, color.b) -const char* gFS_Gamma_Preamble = R"__SHADER__( - #define GAMMA (%.2f) - #define GAMMA_INV (%.2f) - - float gamma(float a, const vec3 color) { - float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722)); - return pow(a, luminance < 0.5 ? GAMMA_INV : GAMMA); - } -)__SHADER__"; - -const char* gFS_Main = - "\nvoid main(void) {\n" - " vec4 fragColor;\n"; - -const char* gFS_Main_AddDither = " fragColor = dither(fragColor);\n"; - -// General case -const char* gFS_Main_FetchColor = " fragColor = color;\n"; -const char* gFS_Main_ModulateColor = " fragColor *= color.a;\n"; -const char* gFS_Main_ApplyVertexAlphaLinearInterp = " fragColor *= alpha;\n"; -const char* gFS_Main_ApplyVertexAlphaShadowInterp = - // map alpha through shadow alpha sampler - " fragColor *= texture2D(baseSampler, vec2(alpha, 0.5)).a;\n"; -const char* gFS_Main_FetchTexture[2] = { - // Don't modulate - " fragColor = colorConvert(texture2D(baseSampler, outTexCoords));\n", - // Modulate - " fragColor = color * colorConvert(texture2D(baseSampler, outTexCoords));\n"}; -const char* gFS_Main_FetchA8Texture[4] = { - // Don't modulate - " fragColor = texture2D(baseSampler, outTexCoords);\n", - " fragColor = texture2D(baseSampler, outTexCoords);\n", - // Modulate - " fragColor = color * texture2D(baseSampler, outTexCoords).a;\n", - " fragColor = color * gamma(texture2D(baseSampler, outTexCoords).a, color.rgb);\n", -}; -const char* gFS_Main_FetchGradient[6] = { - // Linear - " vec4 gradientColor = texture2D(gradientSampler, linear);\n", - - " vec4 gradientColor = mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n", - - // Circular - " vec4 gradientColor = texture2D(gradientSampler, vec2(length(circular), 0.5));\n", - - " vec4 gradientColor = mix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n", - - // Sweep - " highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n" - " vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n", - - " highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n" - " vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, " - "1.0));\n"}; -const char* gFS_Main_FetchBitmap = - " vec4 bitmapColor = colorConvert(texture2D(bitmapSampler, outBitmapTexCoords));\n"; -const char* gFS_Main_FetchBitmapNpot = - " vec4 bitmapColor = colorConvert(texture2D(bitmapSampler, " - "wrap(outBitmapTexCoords)));\n"; -const char* gFS_Main_BlendShadersBG = " fragColor = blendShaders(gradientColor, bitmapColor)"; -const char* gFS_Main_BlendShadersGB = " fragColor = blendShaders(bitmapColor, gradientColor)"; -const char* gFS_Main_BlendShaders_Modulate[6] = { - // Don't modulate - ";\n", ";\n", - // Modulate - " * color.a;\n", " * color.a;\n", - // Modulate with alpha 8 texture - " * texture2D(baseSampler, outTexCoords).a;\n", - " * gamma(texture2D(baseSampler, outTexCoords).a, color.rgb);\n", -}; -const char* gFS_Main_GradientShader_Modulate[6] = { - // Don't modulate - " fragColor = gradientColor;\n", " fragColor = gradientColor;\n", - // Modulate - " fragColor = gradientColor * color.a;\n", " fragColor = gradientColor * color.a;\n", - // Modulate with alpha 8 texture - " fragColor = gradientColor * texture2D(baseSampler, outTexCoords).a;\n", - " fragColor = gradientColor * gamma(texture2D(baseSampler, outTexCoords).a, " - "gradientColor.rgb);\n", -}; -const char* gFS_Main_BitmapShader_Modulate[6] = { - // Don't modulate - " fragColor = bitmapColor;\n", " fragColor = bitmapColor;\n", - // Modulate - " fragColor = bitmapColor * color.a;\n", " fragColor = bitmapColor * color.a;\n", - // Modulate with alpha 8 texture - " fragColor = bitmapColor * texture2D(baseSampler, outTexCoords).a;\n", - " fragColor = bitmapColor * gamma(texture2D(baseSampler, outTexCoords).a, " - "bitmapColor.rgb);\n", -}; -const char* gFS_Main_FragColor = " gl_FragColor = fragColor;\n"; -const char* gFS_Main_FragColor_HasColors = " gl_FragColor *= outColors;\n"; -const char* gFS_Main_FragColor_Blend = - " gl_FragColor = blendFramebuffer(fragColor, gl_LastFragColor);\n"; -const char* gFS_Main_FragColor_Blend_Swap = - " gl_FragColor = blendFramebuffer(gl_LastFragColor, fragColor);\n"; -const char* gFS_Main_ApplyColorOp[3] = { - // None - "", - // Matrix - " fragColor.rgb /= (fragColor.a + 0.0019);\n" // un-premultiply - " fragColor *= colorMatrix;\n" - " fragColor += colorMatrixVector;\n" - " fragColor.rgb *= (fragColor.a + 0.0019);\n", // re-premultiply - // PorterDuff - " fragColor = blendColors(colorBlend, fragColor);\n"}; - -// Note: LTWH (left top width height) -> xyzw -// roundRectPos is now divided by roundRectRadius in vertex shader -// after we also subtract roundRectInnerRectLTWH.xy from roundRectPos -const char* gFS_Main_FragColor_HasRoundRectClip = - " mediump vec2 fragToLT = -roundRectPos;\n" - " mediump vec2 fragFromRB = roundRectPos - roundRectInnerRectLTWH.zw;\n" - - // since distance is divided by radius, it's in [0;1] so precision is not an issue - // this also lets us clamp(0.0, 1.0) instead of max() which is cheaper on GPUs - " mediump vec2 dist = clamp(max(fragToLT, fragFromRB), 0.0, 1.0);\n" - " mediump float linearDist = clamp(roundRectRadius - (length(dist) * roundRectRadius), " - "0.0, 1.0);\n" - " gl_FragColor *= linearDist;\n"; - -const char* gFS_Main_DebugHighlight = " gl_FragColor.rgb = vec3(0.0, gl_FragColor.a, 0.0);\n"; -const char* gFS_Footer = "}\n\n"; - -/////////////////////////////////////////////////////////////////////////////// -// PorterDuff snippets -/////////////////////////////////////////////////////////////////////////////// - -const char* gBlendOps[18] = { - // Clear - "return vec4(0.0, 0.0, 0.0, 0.0);\n", - // Src - "return src;\n", - // Dst - "return dst;\n", - // SrcOver - "return src + dst * (1.0 - src.a);\n", - // DstOver - "return dst + src * (1.0 - dst.a);\n", - // SrcIn - "return src * dst.a;\n", - // DstIn - "return dst * src.a;\n", - // SrcOut - "return src * (1.0 - dst.a);\n", - // DstOut - "return dst * (1.0 - src.a);\n", - // SrcAtop - "return vec4(src.rgb * dst.a + (1.0 - src.a) * dst.rgb, dst.a);\n", - // DstAtop - "return vec4(dst.rgb * src.a + (1.0 - dst.a) * src.rgb, src.a);\n", - // Xor - "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, " - "src.a + dst.a - 2.0 * src.a * dst.a);\n", - // Plus - "return min(src + dst, 1.0);\n", - // Modulate - "return src * dst;\n", - // Screen - "return src + dst - src * dst;\n", - // Overlay - "return clamp(vec4(mix(" - "2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), " - "src.a * dst.a - 2.0 * (dst.a - dst.rgb) * (src.a - src.rgb) + src.rgb * (1.0 - dst.a) + " - "dst.rgb * (1.0 - src.a), " - "step(dst.a, 2.0 * dst.rgb)), " - "src.a + dst.a - src.a * dst.a), 0.0, 1.0);\n", - // Darken - "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + " - "min(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n", - // Lighten - "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + " - "max(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n", -}; - -/////////////////////////////////////////////////////////////////////////////// -// Constructors/destructors -/////////////////////////////////////////////////////////////////////////////// - -ProgramCache::ProgramCache(const Extensions& extensions) - : mHasES3(extensions.getMajorGlVersion() >= 3) - , mHasLinearBlending(extensions.hasLinearBlending()) {} - -ProgramCache::~ProgramCache() { - clear(); -} - -/////////////////////////////////////////////////////////////////////////////// -// Cache management -/////////////////////////////////////////////////////////////////////////////// - -void ProgramCache::clear() { - PROGRAM_LOGD("Clearing program cache"); - mCache.clear(); -} - -Program* ProgramCache::get(const ProgramDescription& description) { - programid key = description.key(); - if (key == (PROGRAM_KEY_TEXTURE | PROGRAM_KEY_A8_TEXTURE)) { - // program for A8, unmodulated, texture w/o shader (black text/path textures) is equivalent - // to standard texture program (bitmaps, patches). Consider them equivalent. - key = PROGRAM_KEY_TEXTURE; - } - - auto iter = mCache.find(key); - Program* program = nullptr; - if (iter == mCache.end()) { - description.log("Could not find program"); - program = generateProgram(description, key); - mCache[key] = std::unique_ptr(program); - } else { - program = iter->second.get(); - } - return program; -} - -/////////////////////////////////////////////////////////////////////////////// -// Program generation -/////////////////////////////////////////////////////////////////////////////// - -Program* ProgramCache::generateProgram(const ProgramDescription& description, programid key) { - String8 vertexShader = generateVertexShader(description); - String8 fragmentShader = generateFragmentShader(description); - - return new Program(description, vertexShader.string(), fragmentShader.string()); -} - -static inline size_t gradientIndex(const ProgramDescription& description) { - return description.gradientType * 2 + description.isSimpleGradient; -} - -String8 ProgramCache::generateVertexShader(const ProgramDescription& description) { - // Add attributes - String8 shader(gVS_Header_Start); - if (description.hasTexture || description.hasExternalTexture) { - shader.append(gVS_Header_Attributes_TexCoords); - } - if (description.hasVertexAlpha) { - shader.append(gVS_Header_Attributes_VertexAlphaParameters); - } - if (description.hasColors) { - shader.append(gVS_Header_Attributes_Colors); - } - // Uniforms - shader.append(gVS_Header_Uniforms); - if (description.hasTextureTransform) { - shader.append(gVS_Header_Uniforms_TextureTransform); - } - if (description.hasGradient) { - shader.append(gVS_Header_Uniforms_HasGradient); - } - if (description.hasBitmap) { - shader.append(gVS_Header_Uniforms_HasBitmap); - } - if (description.hasRoundRectClip) { - shader.append(gVS_Header_Uniforms_HasRoundRectClip); - } - // Varyings - if (description.hasTexture || description.hasExternalTexture) { - shader.append(gVS_Header_Varyings_HasTexture); - } - if (description.hasVertexAlpha) { - shader.append(gVS_Header_Varyings_HasVertexAlpha); - } - if (description.hasColors) { - shader.append(gVS_Header_Varyings_HasColors); - } - if (description.hasGradient) { - shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]); - } - if (description.hasBitmap) { - shader.append(gVS_Header_Varyings_HasBitmap); - } - if (description.hasRoundRectClip) { - shader.append(gVS_Header_Varyings_HasRoundRectClip); - } - - // Begin the shader - shader.append(gVS_Main); - { - if (description.hasTextureTransform) { - shader.append(gVS_Main_OutTransformedTexCoords); - } else if (description.hasTexture || description.hasExternalTexture) { - shader.append(gVS_Main_OutTexCoords); - } - if (description.hasVertexAlpha) { - shader.append(gVS_Main_VertexAlpha); - } - if (description.hasColors) { - shader.append(gVS_Main_OutColors); - } - if (description.hasBitmap) { - shader.append(gVS_Main_OutBitmapTexCoords); - } - // Output transformed position - shader.append(gVS_Main_Position); - if (description.hasGradient) { - shader.append(gVS_Main_OutGradient[gradientIndex(description)]); - } - if (description.hasRoundRectClip) { - shader.append(gVS_Main_HasRoundRectClip); - } - } - // End the shader - shader.append(gVS_Footer); - - PROGRAM_LOGD("*** Generated vertex shader:\n\n%s", shader.string()); - - return shader; -} - -static bool shaderOp(const ProgramDescription& description, String8& shader, const int modulateOp, - const char** snippets) { - int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp; - op = op * 2 + description.hasGammaCorrection; - shader.append(snippets[op]); - return description.hasAlpha8Texture; -} - -String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) { - String8 shader(gFS_Header_Start); - - const bool blendFramebuffer = description.framebufferMode >= SkBlendMode::kPlus; - if (blendFramebuffer) { - shader.append(gFS_Header_Extension_FramebufferFetch); - } - if (description.hasExternalTexture || - (description.hasBitmap && description.isShaderBitmapExternal)) { - shader.append(gFS_Header_Extension_ExternalTexture); - } - - shader.append(gFS_Header); - - // Varyings - if (description.hasTexture || description.hasExternalTexture) { - shader.append(gVS_Header_Varyings_HasTexture); - } - if (description.hasVertexAlpha) { - shader.append(gVS_Header_Varyings_HasVertexAlpha); - } - if (description.hasColors) { - shader.append(gVS_Header_Varyings_HasColors); - } - if (description.hasGradient) { - shader.append(gVS_Header_Varyings_HasGradient[gradientIndex(description)]); - } - if (description.hasBitmap) { - shader.append(gVS_Header_Varyings_HasBitmap); - } - if (description.hasRoundRectClip) { - shader.append(gVS_Header_Varyings_HasRoundRectClip); - } - - // Uniforms - int modulateOp = MODULATE_OP_NO_MODULATE; - const bool singleColor = !description.hasTexture && !description.hasExternalTexture && - !description.hasGradient && !description.hasBitmap; - - if (description.modulate || singleColor) { - shader.append(gFS_Uniforms_Color); - if (!singleColor) modulateOp = MODULATE_OP_MODULATE; - } - if (description.hasTexture || description.useShadowAlphaInterp) { - shader.append(gFS_Uniforms_TextureSampler); - } else if (description.hasExternalTexture) { - shader.append(gFS_Uniforms_ExternalTextureSampler); - } - if (description.hasGradient) { - shader.append(gFS_Uniforms_GradientSampler[description.isSimpleGradient]); - } - if (description.hasRoundRectClip) { - shader.append(gFS_Uniforms_HasRoundRectClip); - } - - if (description.hasGammaCorrection) { - shader.appendFormat(gFS_Gamma_Preamble, Properties::textGamma, - 1.0f / Properties::textGamma); - } - - if (description.hasBitmap) { - if (description.isShaderBitmapExternal) { - shader.append(gFS_Uniforms_BitmapExternalSampler); - } else { - shader.append(gFS_Uniforms_BitmapSampler); - } - } - shader.append(gFS_Uniforms_ColorOp[static_cast(description.colorOp)]); - - if (description.hasColorSpaceConversion) { - shader.append(gFS_Uniforms_ColorSpaceConversion); - } - shader.append(gFS_Uniforms_TransferFunction[static_cast(description.transferFunction)]); - - // Generate required functions - if (description.hasGradient && description.hasBitmap) { - generateBlend(shader, "blendShaders", description.shadersMode); - } - if (description.colorOp == ProgramDescription::ColorFilterMode::Blend) { - generateBlend(shader, "blendColors", description.colorMode); - } - if (blendFramebuffer) { - generateBlend(shader, "blendFramebuffer", description.framebufferMode); - } - if (description.useShaderBasedWrap) { - generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT); - } - if (description.hasGradient || description.hasLinearTexture || - description.hasColorSpaceConversion) { - shader.append(gFS_sRGB_TransferFunctions); - } - if (description.hasBitmap || ((description.hasTexture || description.hasExternalTexture) && - !description.hasAlpha8Texture)) { - shader.append(gFS_TransferFunction[static_cast(description.transferFunction)]); - shader.append( - gFS_OETF[(description.hasLinearTexture || description.hasColorSpaceConversion) && - !mHasLinearBlending]); - shader.append(gFS_ColorConvert[description.hasColorSpaceConversion - ? 1 + description.hasTranslucentConversion - : 0]); - } - if (description.hasGradient) { - shader.append(gFS_GradientFunctions); - shader.append(gFS_GradientPreamble[mHasLinearBlending]); - } - - // Begin the shader - shader.append(gFS_Main); - { - // Stores the result in fragColor directly - if (description.hasTexture || description.hasExternalTexture) { - if (description.hasAlpha8Texture) { - if (!description.hasGradient && !description.hasBitmap) { - shader.append(gFS_Main_FetchA8Texture[modulateOp * 2 + - description.hasGammaCorrection]); - } - } else { - shader.append(gFS_Main_FetchTexture[modulateOp]); - } - } else { - if (!description.hasGradient && !description.hasBitmap) { - shader.append(gFS_Main_FetchColor); - } - } - if (description.hasGradient) { - shader.append(gFS_Main_FetchGradient[gradientIndex(description)]); - } - if (description.hasBitmap) { - if (!description.useShaderBasedWrap) { - shader.append(gFS_Main_FetchBitmap); - } else { - shader.append(gFS_Main_FetchBitmapNpot); - } - } - bool applyModulate = false; - // Case when we have two shaders set - if (description.hasGradient && description.hasBitmap) { - if (description.isBitmapFirst) { - shader.append(gFS_Main_BlendShadersBG); - } else { - shader.append(gFS_Main_BlendShadersGB); - } - applyModulate = - shaderOp(description, shader, modulateOp, gFS_Main_BlendShaders_Modulate); - } else { - if (description.hasGradient) { - applyModulate = - shaderOp(description, shader, modulateOp, gFS_Main_GradientShader_Modulate); - } else if (description.hasBitmap) { - applyModulate = - shaderOp(description, shader, modulateOp, gFS_Main_BitmapShader_Modulate); - } - } - - if (description.modulate && applyModulate) { - shader.append(gFS_Main_ModulateColor); - } - - // Apply the color op if needed - shader.append(gFS_Main_ApplyColorOp[static_cast(description.colorOp)]); - - if (description.hasVertexAlpha) { - if (description.useShadowAlphaInterp) { - shader.append(gFS_Main_ApplyVertexAlphaShadowInterp); - } else { - shader.append(gFS_Main_ApplyVertexAlphaLinearInterp); - } - } - - if (description.hasGradient) { - shader.append(gFS_Main_AddDither); - } - - // Output the fragment - if (!blendFramebuffer) { - shader.append(gFS_Main_FragColor); - } else { - shader.append(!description.swapSrcDst ? gFS_Main_FragColor_Blend - : gFS_Main_FragColor_Blend_Swap); - } - if (description.hasColors) { - shader.append(gFS_Main_FragColor_HasColors); - } - if (description.hasRoundRectClip) { - shader.append(gFS_Main_FragColor_HasRoundRectClip); - } - if (description.hasDebugHighlight) { - shader.append(gFS_Main_DebugHighlight); - } - } - // End the shader - shader.append(gFS_Footer); - -#if DEBUG_PROGRAMS - PROGRAM_LOGD("*** Generated fragment shader:\n\n"); - printLongString(shader); -#endif - - return shader; -} - -void ProgramCache::generateBlend(String8& shader, const char* name, SkBlendMode mode) { - shader.append("\nvec4 "); - shader.append(name); - shader.append("(vec4 src, vec4 dst) {\n"); - shader.append(" "); - shader.append(gBlendOps[(int)mode]); - shader.append("}\n"); -} - -void ProgramCache::generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT) { - shader.append("\nhighp vec2 wrap(highp vec2 texCoords) {\n"); - if (wrapS == GL_MIRRORED_REPEAT) { - shader.append(" highp float xMod2 = mod(texCoords.x, 2.0);\n"); - shader.append(" if (xMod2 > 1.0) xMod2 = 2.0 - xMod2;\n"); - } - if (wrapT == GL_MIRRORED_REPEAT) { - shader.append(" highp float yMod2 = mod(texCoords.y, 2.0);\n"); - shader.append(" if (yMod2 > 1.0) yMod2 = 2.0 - yMod2;\n"); - } - shader.append(" return vec2("); - switch (wrapS) { - case GL_CLAMP_TO_EDGE: - shader.append("texCoords.x"); - break; - case GL_REPEAT: - shader.append("mod(texCoords.x, 1.0)"); - break; - case GL_MIRRORED_REPEAT: - shader.append("xMod2"); - break; - } - shader.append(", "); - switch (wrapT) { - case GL_CLAMP_TO_EDGE: - shader.append("texCoords.y"); - break; - case GL_REPEAT: - shader.append("mod(texCoords.y, 1.0)"); - break; - case GL_MIRRORED_REPEAT: - shader.append("yMod2"); - break; - } - shader.append(");\n"); - shader.append("}\n"); -} - -void ProgramCache::printLongString(const String8& shader) const { - ssize_t index = 0; - ssize_t lastIndex = 0; - const char* str = shader.string(); - while ((index = shader.find("\n", index)) > -1) { - String8 line(str, index - lastIndex); - if (line.length() == 0) line.append("\n"); - ALOGD("%s", line.string()); - index++; - str += (index - lastIndex); - lastIndex = index; - } -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h deleted file mode 100644 index 488a4994ba95..000000000000 --- a/libs/hwui/ProgramCache.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2010 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_PROGRAM_CACHE_H -#define ANDROID_HWUI_PROGRAM_CACHE_H - -#include -#include -#include -#include - -#include - -#include "Debug.h" -#include "Program.h" - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Cache -/////////////////////////////////////////////////////////////////////////////// - -/** - * Generates and caches program. Programs are generated based on - * ProgramDescriptions. - */ -class ProgramCache { -public: - explicit ProgramCache(const Extensions& extensions); - ~ProgramCache(); - - Program* get(const ProgramDescription& description); - - void clear(); - -private: - Program* generateProgram(const ProgramDescription& description, programid key); - String8 generateVertexShader(const ProgramDescription& description); - String8 generateFragmentShader(const ProgramDescription& description); - void generateBlend(String8& shader, const char* name, SkBlendMode mode); - void generateTextureWrap(String8& shader, GLenum wrapS, GLenum wrapT); - - void printLongString(const String8& shader) const; - - std::map> mCache; - - const bool mHasES3; - const bool mHasLinearBlending; -}; // class ProgramCache - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_PROGRAM_CACHE_H diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h index f5146912ea37..a8f105d0e2db 100644 --- a/libs/hwui/RecordedOp.h +++ b/libs/hwui/RecordedOp.h @@ -20,7 +20,6 @@ #include "Matrix.h" #include "Rect.h" #include "RenderNode.h" -#include "TessellationCache.h" #include "Vector.h" #include "utils/LinearAllocator.h" #include "utils/PaintUtils.h" @@ -84,7 +83,6 @@ class Tree; PRE_RENDER_OP_FN(EndUnclippedLayerOp) \ PRE_RENDER_OP_FN(VectorDrawableOp) \ \ - RENDER_ONLY_OP_FN(ShadowOp) \ RENDER_ONLY_OP_FN(LayerOp) \ RENDER_ONLY_OP_FN(CopyToLayerOp) \ RENDER_ONLY_OP_FN(CopyFromLayerOp) \ @@ -333,23 +331,6 @@ struct VectorDrawableOp : RecordedOp { VectorDrawable::Tree* vectorDrawable; }; -/** - * Real-time, dynamic-lit shadow. - * - * Uses invalid/empty bounds and matrix since ShadowOp bounds aren't known at defer time, - * and are resolved dynamically, and transform isn't needed. - * - * State construction handles these properties specially, ignoring matrix/bounds. - */ -struct ShadowOp : RecordedOp { - ShadowOp(sp& shadowTask, float casterAlpha) - : RecordedOp(RecordedOpId::ShadowOp, Rect(), Matrix4::identity(), nullptr, nullptr) - , shadowTask(shadowTask) - , casterAlpha(casterAlpha){}; - sp shadowTask; - const float casterAlpha; -}; - struct SimpleRectsOp : RecordedOp { // Filled, no AA (TODO: better name?) SimpleRectsOp(BASE_PARAMS, Vertex* vertices, size_t vertexCount) : SUPER(SimpleRectsOp), vertices(vertices), vertexCount(vertexCount) {} diff --git a/libs/hwui/RenderBufferCache.cpp b/libs/hwui/RenderBufferCache.cpp deleted file mode 100644 index 98010d8da1bd..000000000000 --- a/libs/hwui/RenderBufferCache.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2013 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 "RenderBufferCache.h" -#include "Debug.h" -#include "DeviceInfo.h" -#include "Properties.h" - -#include - -#include - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Defines -/////////////////////////////////////////////////////////////////////////////// - -// Debug -#if DEBUG_RENDER_BUFFERS -#define RENDER_BUFFER_LOGD(...) ALOGD(__VA_ARGS__) -#else -#define RENDER_BUFFER_LOGD(...) -#endif - -static uint32_t calculateRboCacheSize() { - // TODO: Do we need to use extensions().has4BitStencil() here? - // The tuning guide recommends it, but all real devices are configured - // with a larger cache than necessary by 4x, so keep the 2x for now regardless - return DeviceInfo::multiplyByResolution(2); -} - -/////////////////////////////////////////////////////////////////////////////// -// Constructors/destructor -/////////////////////////////////////////////////////////////////////////////// - -RenderBufferCache::RenderBufferCache() : mSize(0), mMaxSize(calculateRboCacheSize()) {} - -RenderBufferCache::~RenderBufferCache() { - clear(); -} - -/////////////////////////////////////////////////////////////////////////////// -// Size management -/////////////////////////////////////////////////////////////////////////////// - -uint32_t RenderBufferCache::getSize() { - return mSize; -} - -uint32_t RenderBufferCache::getMaxSize() { - return mMaxSize; -} - -/////////////////////////////////////////////////////////////////////////////// -// Caching -/////////////////////////////////////////////////////////////////////////////// - -int RenderBufferCache::RenderBufferEntry::compare(const RenderBufferCache::RenderBufferEntry& lhs, - const RenderBufferCache::RenderBufferEntry& rhs) { - int deltaInt = int(lhs.mWidth) - int(rhs.mWidth); - if (deltaInt != 0) return deltaInt; - - deltaInt = int(lhs.mHeight) - int(rhs.mHeight); - if (deltaInt != 0) return deltaInt; - - return int(lhs.mFormat) - int(rhs.mFormat); -} - -void RenderBufferCache::deleteBuffer(RenderBuffer* buffer) { - if (buffer) { - RENDER_BUFFER_LOGD("Deleted %s render buffer (%dx%d)", - RenderBuffer::formatName(buffer->getFormat()), buffer->getWidth(), - buffer->getHeight()); - - mSize -= buffer->getSize(); - delete buffer; - } -} - -void RenderBufferCache::clear() { - for (auto entry : mCache) { - deleteBuffer(entry.mBuffer); - } - mCache.clear(); -} - -RenderBuffer* RenderBufferCache::get(GLenum format, const uint32_t width, const uint32_t height) { - RenderBuffer* buffer = nullptr; - - RenderBufferEntry entry(format, width, height); - auto iter = mCache.find(entry); - - if (iter != mCache.end()) { - entry = *iter; - mCache.erase(iter); - - buffer = entry.mBuffer; - mSize -= buffer->getSize(); - - RENDER_BUFFER_LOGD("Found %s render buffer (%dx%d)", RenderBuffer::formatName(format), - width, height); - } else { - buffer = new RenderBuffer(format, width, height); - - RENDER_BUFFER_LOGD("Created new %s render buffer (%dx%d)", RenderBuffer::formatName(format), - width, height); - } - - buffer->bind(); - buffer->allocate(); - - return buffer; -} - -bool RenderBufferCache::put(RenderBuffer* buffer) { - if (!buffer) return false; - - const uint32_t size = buffer->getSize(); - if (size < mMaxSize) { - while (mSize + size > mMaxSize) { - RenderBuffer* victim = mCache.begin()->mBuffer; - deleteBuffer(victim); - mCache.erase(mCache.begin()); - } - - RenderBufferEntry entry(buffer); - - mCache.insert(entry); - mSize += size; - - RENDER_BUFFER_LOGD("Added %s render buffer (%dx%d)", - RenderBuffer::formatName(buffer->getFormat()), buffer->getWidth(), - buffer->getHeight()); - - return true; - } else { - RENDER_BUFFER_LOGD("Deleted %s render buffer (%dx%d) Size=%d, MaxSize=%d", - RenderBuffer::formatName(buffer->getFormat()), buffer->getWidth(), - buffer->getHeight(), size, mMaxSize); - delete buffer; - } - return false; -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/RenderBufferCache.h b/libs/hwui/RenderBufferCache.h deleted file mode 100644 index c936a5283965..000000000000 --- a/libs/hwui/RenderBufferCache.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2013 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_RENDER_BUFFER_CACHE_H -#define ANDROID_HWUI_RENDER_BUFFER_CACHE_H - -#include - -#include "RenderBuffer.h" - -#include - -namespace android { -namespace uirenderer { - -class RenderBufferCache { -public: - RenderBufferCache(); - ~RenderBufferCache(); - - /** - * Returns a buffer with the exact specified dimensions. If no suitable - * buffer can be found, a new one is created and returned. If creating a - * new buffer fails, NULL is returned. - * - * When a buffer is obtained from the cache, it is removed and the total - * size of the cache goes down. - * - * The returned buffer is always allocated and bound - * (see RenderBuffer::isAllocated()). - * - * @param format The desired render buffer format - * @param width The desired width of the buffer - * @param height The desired height of the buffer - */ - RenderBuffer* get(GLenum format, const uint32_t width, const uint32_t height); - - /** - * Adds the buffer to the cache. The buffer will not be added if there is - * not enough space available. Adding a buffer can cause other buffer to - * be removed from the cache. - * - * @param buffer The render buffer to add to the cache - * - * @return True if the buffer was added, false otherwise. - */ - bool put(RenderBuffer* buffer); - /** - * Clears the cache. This causes all layers to be deleted. - */ - void clear(); - - /** - * Returns the maximum size of the cache in bytes. - */ - uint32_t getMaxSize(); - /** - * Returns the current size of the cache in bytes. - */ - uint32_t getSize(); - -private: - struct RenderBufferEntry { - RenderBufferEntry() : mBuffer(nullptr), mWidth(0), mHeight(0) {} - - RenderBufferEntry(GLenum format, const uint32_t width, const uint32_t height) - : mBuffer(nullptr), mFormat(format), mWidth(width), mHeight(height) {} - - explicit RenderBufferEntry(RenderBuffer* buffer) - : mBuffer(buffer) - , mFormat(buffer->getFormat()) - , mWidth(buffer->getWidth()) - , mHeight(buffer->getHeight()) {} - - static int compare(const RenderBufferEntry& lhs, const RenderBufferEntry& rhs); - - bool operator==(const RenderBufferEntry& other) const { return compare(*this, other) == 0; } - - bool operator!=(const RenderBufferEntry& other) const { return compare(*this, other) != 0; } - - bool operator<(const RenderBufferEntry& other) const { - return RenderBufferEntry::compare(*this, other) < 0; - } - - RenderBuffer* mBuffer; - GLenum mFormat; - uint32_t mWidth; - uint32_t mHeight; - }; // struct RenderBufferEntry - - void deleteBuffer(RenderBuffer* buffer); - - std::multiset mCache; - - uint32_t mSize; - uint32_t mMaxSize; -}; // class RenderBufferCache - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_RENDER_BUFFER_CACHE_H diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp index d60b99469368..464a58d0c0f8 100644 --- a/libs/hwui/ResourceCache.cpp +++ b/libs/hwui/ResourceCache.cpp @@ -113,7 +113,7 @@ void ResourceCache::destructorLocked(Res_png_9patch* resource) { if (ref == nullptr) { // If we're not tracking this resource, just delete it if (Caches::hasInstance()) { - Caches::getInstance().patchCache.removeDeferred(resource); + // DEAD CODE } else { // A Res_png_9patch is actually an array of byte that's larger // than sizeof(Res_png_9patch). It must be freed as an array. @@ -136,7 +136,7 @@ void ResourceCache::deleteResourceReferenceLocked(const void* resource, Resource switch (ref->resourceType) { case kNinePatch: { if (Caches::hasInstance()) { - Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*)resource); + // DEAD CODE } else { // A Res_png_9patch is actually an array of byte that's larger // than sizeof(Res_png_9patch). It must be freed as an array. diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp index df746554f306..6f7bb9b335aa 100644 --- a/libs/hwui/SkiaShader.cpp +++ b/libs/hwui/SkiaShader.cpp @@ -45,13 +45,6 @@ static_assert(gTileModes[SkShader::kRepeat_TileMode] == GL_REPEAT, static_assert(gTileModes[SkShader::kMirror_TileMode] == GL_MIRRORED_REPEAT, "SkShader TileModes have changed"); -/** - * This function does not work for n == 0. - */ -static inline bool isPowerOfTwo(unsigned int n) { - return !(n & (n - 1)); -} - static inline void bindUniformColor(int slot, FloatColor color) { glUniform4fv(slot, 1, reinterpret_cast(&color)); } @@ -79,107 +72,10 @@ static void computeScreenSpaceMatrix(mat4& screenSpace, const SkMatrix& unitMatr screenSpace.multiply(modelViewMatrix); } -/////////////////////////////////////////////////////////////////////////////// -// Gradient shader matrix helpers -/////////////////////////////////////////////////////////////////////////////// - -static void toLinearUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) { - SkVector vec = pts[1] - pts[0]; - const float mag = vec.length(); - const float inv = mag ? 1.0f / mag : 0; - - vec.scale(inv); - matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY); - matrix->postTranslate(-pts[0].fX, -pts[0].fY); - matrix->postScale(inv, inv); -} - -static void toCircularUnitMatrix(const float x, const float y, const float radius, - SkMatrix* matrix) { - const float inv = 1.0f / radius; - matrix->setTranslate(-x, -y); - matrix->postScale(inv, inv); -} - -static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) { - matrix->setTranslate(-x, -y); -} - -/////////////////////////////////////////////////////////////////////////////// -// Common gradient code -/////////////////////////////////////////////////////////////////////////////// - -static bool isSimpleGradient(const SkShader::GradientInfo& gradInfo) { - return gradInfo.fColorCount == 2 && gradInfo.fTileMode == SkShader::kClamp_TileMode; -} - /////////////////////////////////////////////////////////////////////////////// // Store / apply /////////////////////////////////////////////////////////////////////////////// -bool tryStoreGradient(Caches& caches, const SkShader& shader, const Matrix4 modelViewMatrix, - GLuint* textureUnit, ProgramDescription* description, - SkiaShaderData::GradientShaderData* outData) { - SkShader::GradientInfo gradInfo; - gradInfo.fColorCount = 0; - gradInfo.fColors = nullptr; - gradInfo.fColorOffsets = nullptr; - - SkMatrix unitMatrix; - switch (shader.asAGradient(&gradInfo)) { - case SkShader::kLinear_GradientType: - description->gradientType = ProgramDescription::kGradientLinear; - - toLinearUnitMatrix(gradInfo.fPoint, &unitMatrix); - break; - case SkShader::kRadial_GradientType: - description->gradientType = ProgramDescription::kGradientCircular; - - toCircularUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY, gradInfo.fRadius[0], - &unitMatrix); - break; - case SkShader::kSweep_GradientType: - description->gradientType = ProgramDescription::kGradientSweep; - - toSweepUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY, &unitMatrix); - break; - default: - // Do nothing. This shader is unsupported. - return false; - } - description->hasGradient = true; - description->isSimpleGradient = isSimpleGradient(gradInfo); - - computeScreenSpaceMatrix(outData->screenSpace, unitMatrix, shader.getLocalMatrix(), - modelViewMatrix); - - // re-query shader to get full color / offset data - std::unique_ptr colorStorage(new SkColor[gradInfo.fColorCount]); - std::unique_ptr colorOffsets(new SkScalar[gradInfo.fColorCount]); - gradInfo.fColors = &colorStorage[0]; - gradInfo.fColorOffsets = &colorOffsets[0]; - shader.asAGradient(&gradInfo); - - if (CC_UNLIKELY(!description->isSimpleGradient)) { - outData->gradientSampler = (*textureUnit)++; - -#ifndef SK_SCALAR_IS_FLOAT -#error Need to convert gradInfo.fColorOffsets to float! -#endif - outData->gradientTexture = caches.gradientCache.get( - gradInfo.fColors, gradInfo.fColorOffsets, gradInfo.fColorCount); - outData->wrapST = gTileModes[gradInfo.fTileMode]; - } else { - outData->gradientSampler = 0; - outData->gradientTexture = nullptr; - - outData->startColor.set(gradInfo.fColors[0]); - outData->endColor.set(gradInfo.fColors[1]); - } - - return true; -} - void applyGradient(Caches& caches, const SkiaShaderData::GradientShaderData& data, const GLsizei width, const GLsizei height) { if (CC_UNLIKELY(data.gradientTexture)) { @@ -199,52 +95,7 @@ void applyGradient(Caches& caches, const SkiaShaderData::GradientShaderData& dat bool tryStoreBitmap(Caches& caches, const SkShader& shader, const Matrix4& modelViewMatrix, GLuint* textureUnit, ProgramDescription* description, SkiaShaderData::BitmapShaderData* outData) { - SkBitmap bitmap; - SkShader::TileMode xy[2]; - if (!shader.isABitmap(&bitmap, nullptr, xy)) { - return false; - } - - // TODO: create hwui-owned BitmapShader. - Bitmap* hwuiBitmap = static_cast(bitmap.pixelRef()); - outData->bitmapTexture = caches.textureCache.get(hwuiBitmap); - if (!outData->bitmapTexture) return false; - - outData->bitmapSampler = (*textureUnit)++; - - const float width = outData->bitmapTexture->width(); - const float height = outData->bitmapTexture->height(); - - Texture* texture = outData->bitmapTexture; - - description->hasBitmap = true; - description->hasLinearTexture = texture->isLinear(); - description->hasColorSpaceConversion = texture->hasColorSpaceConversion(); - description->transferFunction = texture->getTransferFunctionType(); - description->hasTranslucentConversion = texture->blend; - description->isShaderBitmapExternal = hwuiBitmap->isHardware(); - // gralloc doesn't support non-clamp modes - if (hwuiBitmap->isHardware() || - (!caches.extensions().hasNPot() && (!isPowerOfTwo(width) || !isPowerOfTwo(height)) && - (xy[0] != SkShader::kClamp_TileMode || xy[1] != SkShader::kClamp_TileMode))) { - // need non-clamp mode, but it's not supported for this draw, - // so enable custom shader logic to mimic - description->useShaderBasedWrap = true; - description->bitmapWrapS = gTileModes[xy[0]]; - description->bitmapWrapT = gTileModes[xy[1]]; - - outData->wrapS = GL_CLAMP_TO_EDGE; - outData->wrapT = GL_CLAMP_TO_EDGE; - } else { - outData->wrapS = gTileModes[xy[0]]; - outData->wrapT = gTileModes[xy[1]]; - } - - computeScreenSpaceMatrix(outData->textureTransform, SkMatrix::I(), shader.getLocalMatrix(), - modelViewMatrix); - outData->textureDimension[0] = 1.0f / width; - outData->textureDimension[1] = 1.0f / height; - + // DEAD CODE return true; } @@ -287,9 +138,6 @@ void storeCompose(Caches& caches, const SkShader& bitmapShader, const SkShader& LOG_ALWAYS_FATAL_IF(!tryStoreBitmap(caches, bitmapShader, modelViewMatrix, textureUnit, description, &outData->bitmapData), "failed storing bitmap shader data"); - LOG_ALWAYS_FATAL_IF(!tryStoreGradient(caches, gradientShader, modelViewMatrix, textureUnit, - description, &outData->gradientData), - "failing storing gradient shader data"); } bool tryStoreCompose(Caches& caches, const SkShader& shader, const Matrix4& modelViewMatrix, @@ -323,12 +171,7 @@ bool tryStoreCompose(Caches& caches, const SkShader& shader, const Matrix4& mode void SkiaShader::store(Caches& caches, const SkShader& shader, const Matrix4& modelViewMatrix, GLuint* textureUnit, ProgramDescription* description, SkiaShaderData* outData) { - if (tryStoreGradient(caches, shader, modelViewMatrix, textureUnit, description, - &outData->gradientData)) { - outData->skiaShaderType = kGradient_SkiaShaderType; - return; - } - + // DEAD CODE if (tryStoreBitmap(caches, shader, modelViewMatrix, textureUnit, description, &outData->bitmapData)) { outData->skiaShaderType = kBitmap_SkiaShaderType; diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp deleted file mode 100644 index c7d93da718e7..000000000000 --- a/libs/hwui/TessellationCache.cpp +++ /dev/null @@ -1,444 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "Caches.h" -#include "PathTessellator.h" -#include "ShadowTessellator.h" -#include "TessellationCache.h" - -#include "thread/Signal.h" -#include "thread/Task.h" -#include "thread/TaskProcessor.h" - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Cache entries -/////////////////////////////////////////////////////////////////////////////// - -TessellationCache::Description::Description() - : type(Type::None) - , scaleX(1.0f) - , scaleY(1.0f) - , aa(false) - , cap(SkPaint::kDefault_Cap) - , style(SkPaint::kFill_Style) - , strokeWidth(1.0f) { - // Shape bits should be set to zeroes, because they are used for hash calculation. - memset(&shape, 0, sizeof(Shape)); -} - -TessellationCache::Description::Description(Type type, const Matrix4& transform, - const SkPaint& paint) - : type(type) - , aa(paint.isAntiAlias()) - , cap(paint.getStrokeCap()) - , style(paint.getStyle()) - , strokeWidth(paint.getStrokeWidth()) { - PathTessellator::extractTessellationScales(transform, &scaleX, &scaleY); - // Shape bits should be set to zeroes, because they are used for hash calculation. - memset(&shape, 0, sizeof(Shape)); -} - -bool TessellationCache::Description::operator==(const TessellationCache::Description& rhs) const { - if (type != rhs.type) return false; - if (scaleX != rhs.scaleX) return false; - if (scaleY != rhs.scaleY) return false; - if (aa != rhs.aa) return false; - if (cap != rhs.cap) return false; - if (style != rhs.style) return false; - if (strokeWidth != rhs.strokeWidth) return false; - if (type == Type::None) return true; - const Shape::RoundRect& lRect = shape.roundRect; - const Shape::RoundRect& rRect = rhs.shape.roundRect; - - if (lRect.width != rRect.width) return false; - if (lRect.height != rRect.height) return false; - if (lRect.rx != rRect.rx) return false; - return lRect.ry == rRect.ry; -} - -hash_t TessellationCache::Description::hash() const { - uint32_t hash = JenkinsHashMix(0, static_cast(type)); - hash = JenkinsHashMix(hash, aa); - hash = JenkinsHashMix(hash, cap); - hash = JenkinsHashMix(hash, style); - hash = JenkinsHashMix(hash, android::hash_type(strokeWidth)); - hash = JenkinsHashMix(hash, android::hash_type(scaleX)); - hash = JenkinsHashMix(hash, android::hash_type(scaleY)); - hash = JenkinsHashMixBytes(hash, (uint8_t*)&shape, sizeof(Shape)); - return JenkinsHashWhiten(hash); -} - -void TessellationCache::Description::setupMatrixAndPaint(Matrix4* matrix, SkPaint* paint) const { - matrix->loadScale(scaleX, scaleY, 1.0f); - paint->setAntiAlias(aa); - paint->setStrokeCap(cap); - paint->setStyle(style); - paint->setStrokeWidth(strokeWidth); -} - -TessellationCache::ShadowDescription::ShadowDescription() : nodeKey(nullptr) { - memset(&matrixData, 0, sizeof(matrixData)); -} - -TessellationCache::ShadowDescription::ShadowDescription(const SkPath* nodeKey, - const Matrix4* drawTransform) - : nodeKey(nodeKey) { - memcpy(&matrixData, drawTransform->data, sizeof(matrixData)); -} - -bool TessellationCache::ShadowDescription::operator==( - const TessellationCache::ShadowDescription& rhs) const { - return nodeKey == rhs.nodeKey && memcmp(&matrixData, &rhs.matrixData, sizeof(matrixData)) == 0; -} - -hash_t TessellationCache::ShadowDescription::hash() const { - uint32_t hash = JenkinsHashMixBytes(0, (uint8_t*)&nodeKey, sizeof(const void*)); - hash = JenkinsHashMixBytes(hash, (uint8_t*)&matrixData, sizeof(matrixData)); - return JenkinsHashWhiten(hash); -} - -/////////////////////////////////////////////////////////////////////////////// -// General purpose tessellation task processing -/////////////////////////////////////////////////////////////////////////////// - -class TessellationCache::TessellationTask : public Task { -public: - TessellationTask(Tessellator tessellator, const Description& description) - : tessellator(tessellator), description(description) {} - - ~TessellationTask() {} - - Tessellator tessellator; - Description description; -}; - -class TessellationCache::TessellationProcessor : public TaskProcessor { -public: - explicit TessellationProcessor(Caches& caches) : TaskProcessor(&caches.tasks) {} - ~TessellationProcessor() {} - - virtual void onProcess(const sp >& task) override { - TessellationTask* t = static_cast(task.get()); - ATRACE_NAME("shape tessellation"); - VertexBuffer* buffer = t->tessellator(t->description); - t->setResult(buffer); - } -}; - -class TessellationCache::Buffer { -public: - explicit Buffer(const sp >& task) : mTask(task), mBuffer(nullptr) {} - - ~Buffer() { - mTask.clear(); - delete mBuffer; - } - - unsigned int getSize() { - blockOnPrecache(); - return mBuffer->getSize(); - } - - const VertexBuffer* getVertexBuffer() { - blockOnPrecache(); - return mBuffer; - } - -private: - void blockOnPrecache() { - if (mTask != nullptr) { - mBuffer = mTask->getResult(); - LOG_ALWAYS_FATAL_IF(mBuffer == nullptr, "Failed to precache"); - mTask.clear(); - } - } - sp > mTask; - VertexBuffer* mBuffer; -}; - -/////////////////////////////////////////////////////////////////////////////// -// Shadow tessellation task processing -/////////////////////////////////////////////////////////////////////////////// - -static void mapPointFakeZ(Vector3& point, const mat4* transformXY, const mat4* transformZ) { - // map z coordinate with true 3d matrix - point.z = transformZ->mapZ(point); - - // map x,y coordinates with draw/Skia matrix - transformXY->mapPoint(point.x, point.y); -} - -static void reverseVertexArray(Vertex* polygon, int len) { - int n = len / 2; - for (int i = 0; i < n; i++) { - Vertex tmp = polygon[i]; - int k = len - 1 - i; - polygon[i] = polygon[k]; - polygon[k] = tmp; - } -} - -void tessellateShadows(const Matrix4* drawTransform, const Rect* localClip, bool isCasterOpaque, - const SkPath* casterPerimeter, const Matrix4* casterTransformXY, - const Matrix4* casterTransformZ, const Vector3& lightCenter, - float lightRadius, VertexBuffer& ambientBuffer, VertexBuffer& spotBuffer) { - // tessellate caster outline into a 2d polygon - std::vector casterVertices2d; - const float casterRefinementThreshold = 2.0f; - PathTessellator::approximatePathOutlineVertices(*casterPerimeter, casterRefinementThreshold, - casterVertices2d); - - // Shadow requires CCW for now. TODO: remove potential double-reverse - reverseVertexArray(&casterVertices2d.front(), casterVertices2d.size()); - - if (casterVertices2d.size() == 0) return; - - // map 2d caster poly into 3d - const int casterVertexCount = casterVertices2d.size(); - Vector3 casterPolygon[casterVertexCount]; - float minZ = FLT_MAX; - float maxZ = -FLT_MAX; - for (int i = 0; i < casterVertexCount; i++) { - const Vertex& point2d = casterVertices2d[i]; - casterPolygon[i] = (Vector3){point2d.x, point2d.y, 0}; - mapPointFakeZ(casterPolygon[i], casterTransformXY, casterTransformZ); - minZ = std::min(minZ, casterPolygon[i].z); - maxZ = std::max(maxZ, casterPolygon[i].z); - } - - // map the centroid of the caster into 3d - Vector2 centroid = ShadowTessellator::centroid2d( - reinterpret_cast(&casterVertices2d.front()), casterVertexCount); - Vector3 centroid3d = {centroid.x, centroid.y, 0}; - mapPointFakeZ(centroid3d, casterTransformXY, casterTransformZ); - - // if the caster intersects the z=0 plane, lift it in Z so it doesn't - if (minZ < SHADOW_MIN_CASTER_Z) { - float casterLift = SHADOW_MIN_CASTER_Z - minZ; - for (int i = 0; i < casterVertexCount; i++) { - casterPolygon[i].z += casterLift; - } - centroid3d.z += casterLift; - } - - // Check whether we want to draw the shadow at all by checking the caster's bounds against clip. - // We only have ortho projection, so we can just ignore the Z in caster for - // simple rejection calculation. - Rect casterBounds(casterPerimeter->getBounds()); - casterTransformXY->mapRect(casterBounds); - - // actual tessellation of both shadows - ShadowTessellator::tessellateAmbientShadow(isCasterOpaque, casterPolygon, casterVertexCount, - centroid3d, casterBounds, *localClip, maxZ, - ambientBuffer); - - ShadowTessellator::tessellateSpotShadow(isCasterOpaque, casterPolygon, casterVertexCount, - centroid3d, *drawTransform, lightCenter, lightRadius, - casterBounds, *localClip, spotBuffer); -} - -class ShadowProcessor : public TaskProcessor { -public: - explicit ShadowProcessor(Caches& caches) - : TaskProcessor(&caches.tasks) {} - ~ShadowProcessor() {} - - virtual void onProcess(const sp >& task) override { - TessellationCache::ShadowTask* t = static_cast(task.get()); - ATRACE_NAME("shadow tessellation"); - - tessellateShadows(&t->drawTransform, &t->localClip, t->opaque, &t->casterPerimeter, - &t->transformXY, &t->transformZ, t->lightCenter, t->lightRadius, - t->ambientBuffer, t->spotBuffer); - - t->setResult(TessellationCache::vertexBuffer_pair_t(&t->ambientBuffer, &t->spotBuffer)); - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// Cache constructor/destructor -/////////////////////////////////////////////////////////////////////////////// - -TessellationCache::TessellationCache() - : mMaxSize(MB(1)) - , mCache(LruCache::kUnlimitedCapacity) - , mShadowCache( - LruCache*>::kUnlimitedCapacity) { - mCache.setOnEntryRemovedListener(&mBufferRemovedListener); - mShadowCache.setOnEntryRemovedListener(&mBufferPairRemovedListener); - mDebugEnabled = Properties::debugLevel & kDebugCaches; -} - -TessellationCache::~TessellationCache() { - mCache.clear(); -} - -/////////////////////////////////////////////////////////////////////////////// -// Size management -/////////////////////////////////////////////////////////////////////////////// - -uint32_t TessellationCache::getSize() { - LruCache::Iterator iter(mCache); - uint32_t size = 0; - while (iter.next()) { - size += iter.value()->getSize(); - } - return size; -} - -uint32_t TessellationCache::getMaxSize() { - return mMaxSize; -} - -/////////////////////////////////////////////////////////////////////////////// -// Caching -/////////////////////////////////////////////////////////////////////////////// - -void TessellationCache::trim() { - uint32_t size = getSize(); - while (size > mMaxSize) { - size -= mCache.peekOldestValue()->getSize(); - mCache.removeOldest(); - } - mShadowCache.clear(); -} - -void TessellationCache::clear() { - mCache.clear(); - mShadowCache.clear(); -} - -/////////////////////////////////////////////////////////////////////////////// -// Callbacks -/////////////////////////////////////////////////////////////////////////////// - -void TessellationCache::BufferRemovedListener::operator()(Description& description, - Buffer*& buffer) { - delete buffer; -} - -/////////////////////////////////////////////////////////////////////////////// -// Shadows -/////////////////////////////////////////////////////////////////////////////// - -void TessellationCache::precacheShadows(const Matrix4* drawTransform, const Rect& localClip, - bool opaque, const SkPath* casterPerimeter, - const Matrix4* transformXY, const Matrix4* transformZ, - const Vector3& lightCenter, float lightRadius) { - ShadowDescription key(casterPerimeter, drawTransform); - - if (mShadowCache.get(key)) return; - sp task = new ShadowTask(drawTransform, localClip, opaque, casterPerimeter, - transformXY, transformZ, lightCenter, lightRadius); - if (mShadowProcessor == nullptr) { - mShadowProcessor = new ShadowProcessor(Caches::getInstance()); - } - mShadowProcessor->add(task); - task->incStrong(nullptr); // not using sp<>s, so manually ref while in the cache - mShadowCache.put(key, task.get()); -} - -sp TessellationCache::getShadowTask( - const Matrix4* drawTransform, const Rect& localClip, bool opaque, - const SkPath* casterPerimeter, const Matrix4* transformXY, const Matrix4* transformZ, - const Vector3& lightCenter, float lightRadius) { - ShadowDescription key(casterPerimeter, drawTransform); - ShadowTask* task = static_cast(mShadowCache.get(key)); - if (!task) { - precacheShadows(drawTransform, localClip, opaque, casterPerimeter, transformXY, transformZ, - lightCenter, lightRadius); - task = static_cast(mShadowCache.get(key)); - } - LOG_ALWAYS_FATAL_IF(task == nullptr, "shadow not precached"); - return task; -} - -/////////////////////////////////////////////////////////////////////////////// -// Tessellation precaching -/////////////////////////////////////////////////////////////////////////////// - -TessellationCache::Buffer* TessellationCache::getOrCreateBuffer(const Description& entry, - Tessellator tessellator) { - Buffer* buffer = mCache.get(entry); - if (!buffer) { - // not cached, enqueue a task to fill the buffer - sp task = new TessellationTask(tessellator, entry); - buffer = new Buffer(task); - - if (mProcessor == nullptr) { - mProcessor = new TessellationProcessor(Caches::getInstance()); - } - mProcessor->add(task); - bool inserted = mCache.put(entry, buffer); - // Note to the static analyzer that this insert should always succeed. - LOG_ALWAYS_FATAL_IF(!inserted, "buffers shouldn't spontaneously appear in the cache"); - } - return buffer; -} - -static VertexBuffer* tessellatePath(const TessellationCache::Description& description, - const SkPath& path) { - Matrix4 matrix; - SkPaint paint; - description.setupMatrixAndPaint(&matrix, &paint); - VertexBuffer* buffer = new VertexBuffer(); - PathTessellator::tessellatePath(path, &paint, matrix, *buffer); - return buffer; -} - -/////////////////////////////////////////////////////////////////////////////// -// RoundRect -/////////////////////////////////////////////////////////////////////////////// - -static VertexBuffer* tessellateRoundRect(const TessellationCache::Description& description) { - SkRect rect = - SkRect::MakeWH(description.shape.roundRect.width, description.shape.roundRect.height); - float rx = description.shape.roundRect.rx; - float ry = description.shape.roundRect.ry; - if (description.style == SkPaint::kStrokeAndFill_Style) { - float outset = description.strokeWidth / 2; - rect.outset(outset, outset); - rx += outset; - ry += outset; - } - SkPath path; - path.addRoundRect(rect, rx, ry); - return tessellatePath(description, path); -} - -TessellationCache::Buffer* TessellationCache::getRoundRectBuffer(const Matrix4& transform, - const SkPaint& paint, float width, - float height, float rx, float ry) { - Description entry(Description::Type::RoundRect, transform, paint); - entry.shape.roundRect.width = width; - entry.shape.roundRect.height = height; - entry.shape.roundRect.rx = rx; - entry.shape.roundRect.ry = ry; - return getOrCreateBuffer(entry, &tessellateRoundRect); -} -const VertexBuffer* TessellationCache::getRoundRect(const Matrix4& transform, const SkPaint& paint, - float width, float height, float rx, float ry) { - return getRoundRectBuffer(transform, paint, width, height, rx, ry)->getVertexBuffer(); -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/TessellationCache.h b/libs/hwui/TessellationCache.h deleted file mode 100644 index a0f0ed4653e0..000000000000 --- a/libs/hwui/TessellationCache.h +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -#pragma once - -#include "Debug.h" -#include "Matrix.h" -#include "Rect.h" -#include "Vector.h" -#include "VertexBuffer.h" -#include "thread/TaskProcessor.h" -#include "utils/Macros.h" -#include "utils/Pair.h" - -#include -#include - -#include -#include -#include - -class SkBitmap; -class SkCanvas; -struct SkRect; - -namespace android { -namespace uirenderer { - -class Caches; -class VertexBuffer; - -/////////////////////////////////////////////////////////////////////////////// -// Classes -/////////////////////////////////////////////////////////////////////////////// - -class TessellationCache { -public: - typedef Pair vertexBuffer_pair_t; - - struct Description { - HASHABLE_TYPE(Description); - enum class Type { - None, - RoundRect, - }; - - Type type; - float scaleX; - float scaleY; - bool aa; - SkPaint::Cap cap; - SkPaint::Style style; - float strokeWidth; - union Shape { - struct RoundRect { - float width; - float height; - float rx; - float ry; - } roundRect; - } shape; - - Description(); - Description(Type type, const Matrix4& transform, const SkPaint& paint); - void setupMatrixAndPaint(Matrix4* matrix, SkPaint* paint) const; - }; - - struct ShadowDescription { - HASHABLE_TYPE(ShadowDescription); - const SkPath* nodeKey; - float matrixData[16]; - - ShadowDescription(); - ShadowDescription(const SkPath* nodeKey, const Matrix4* drawTransform); - }; - - class ShadowTask : public Task { - public: - ShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque, - const SkPath* casterPerimeter, const Matrix4* transformXY, - const Matrix4* transformZ, const Vector3& lightCenter, float lightRadius) - : drawTransform(*drawTransform) - , localClip(localClip) - , opaque(opaque) - , casterPerimeter(*casterPerimeter) - , transformXY(*transformXY) - , transformZ(*transformZ) - , lightCenter(lightCenter) - , lightRadius(lightRadius) {} - - /* Note - we deep copy all task parameters, because *even though* pointers into Allocator - * controlled objects (like the SkPath and Matrix4s) should be safe for the entire frame, - * certain Allocators are destroyed before trim() is called to flush incomplete tasks. - * - * These deep copies could be avoided, long term, by canceling or flushing outstanding - * tasks before tearing down single-frame LinearAllocators. - */ - const Matrix4 drawTransform; - const Rect localClip; - bool opaque; - const SkPath casterPerimeter; - const Matrix4 transformXY; - const Matrix4 transformZ; - const Vector3 lightCenter; - const float lightRadius; - VertexBuffer ambientBuffer; - VertexBuffer spotBuffer; - }; - - TessellationCache(); - ~TessellationCache(); - - /** - * Clears the cache. This causes all TessellationBuffers to be deleted. - */ - void clear(); - /** - * Returns the maximum size of the cache in bytes. - */ - uint32_t getMaxSize(); - /** - * Returns the current size of the cache in bytes. - */ - uint32_t getSize(); - - /** - * Trims the contents of the cache, removing items until it's under its - * specified limit. - * - * Trimming is used for caches that support pre-caching from a worker - * thread. During pre-caching the maximum limit of the cache can be - * exceeded for the duration of the frame. It is therefore required to - * trim the cache at the end of the frame to keep the total amount of - * memory used under control. - * - * Also removes transient Shadow VertexBuffers, which aren't cached between frames. - */ - void trim(); - - // TODO: precache/get for Oval, Lines, Points, etc. - - void precacheRoundRect(const Matrix4& transform, const SkPaint& paint, float width, - float height, float rx, float ry) { - getRoundRectBuffer(transform, paint, width, height, rx, ry); - } - const VertexBuffer* getRoundRect(const Matrix4& transform, const SkPaint& paint, float width, - float height, float rx, float ry); - - sp getShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque, - const SkPath* casterPerimeter, const Matrix4* transformXY, - const Matrix4* transformZ, const Vector3& lightCenter, - float lightRadius); - -private: - class Buffer; - class TessellationTask; - class TessellationProcessor; - - typedef VertexBuffer* (*Tessellator)(const Description&); - - void precacheShadows(const Matrix4* drawTransform, const Rect& localClip, bool opaque, - const SkPath* casterPerimeter, const Matrix4* transformXY, - const Matrix4* transformZ, const Vector3& lightCenter, float lightRadius); - - Buffer* getRectBuffer(const Matrix4& transform, const SkPaint& paint, float width, - float height); - Buffer* getRoundRectBuffer(const Matrix4& transform, const SkPaint& paint, float width, - float height, float rx, float ry); - - Buffer* getOrCreateBuffer(const Description& entry, Tessellator tessellator); - - const uint32_t mMaxSize; - - bool mDebugEnabled; - - mutable Mutex mLock; - - /////////////////////////////////////////////////////////////////////////////// - // General tessellation caching - /////////////////////////////////////////////////////////////////////////////// - sp > mProcessor; - LruCache mCache; - class BufferRemovedListener : public OnEntryRemoved { - void operator()(Description& description, Buffer*& buffer) override; - }; - BufferRemovedListener mBufferRemovedListener; - - /////////////////////////////////////////////////////////////////////////////// - // Shadow tessellation caching - /////////////////////////////////////////////////////////////////////////////// - sp > mShadowProcessor; - - // holds a pointer, and implicit strong ref to each shadow task of the frame - LruCache*> mShadowCache; - class BufferPairRemovedListener - : public OnEntryRemoved*> { - void operator()(ShadowDescription& description, - Task*& bufferPairTask) override { - bufferPairTask->decStrong(nullptr); - } - }; - BufferPairRemovedListener mBufferPairRemovedListener; - -}; // class TessellationCache - -void tessellateShadows(const Matrix4* drawTransform, const Rect* localClip, bool isCasterOpaque, - const SkPath* casterPerimeter, const Matrix4* casterTransformXY, - const Matrix4* casterTransformZ, const Vector3& lightCenter, - float lightRadius, VertexBuffer& ambientBuffer, VertexBuffer& spotBuffer); - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp deleted file mode 100644 index 9d365fb29ebe..000000000000 --- a/libs/hwui/TextureCache.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2010 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 - -#include - -#include "Caches.h" -#include "DeviceInfo.h" -#include "Properties.h" -#include "Texture.h" -#include "TextureCache.h" -#include "hwui/Bitmap.h" -#include "utils/TraceUtils.h" - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Constructors/destructor -/////////////////////////////////////////////////////////////////////////////// - -TextureCache::TextureCache() - : mCache(LruCache::kUnlimitedCapacity) - , mSize(0) - , mMaxSize(DeviceInfo::multiplyByResolution(4 * 6)) // 6 screen-sized RGBA_8888 bitmaps - , mFlushRate(.4f) { - mCache.setOnEntryRemovedListener(this); - mMaxTextureSize = DeviceInfo::get()->maxTextureSize(); - mDebugEnabled = Properties::debugLevel & kDebugCaches; -} - -TextureCache::~TextureCache() { - this->clear(); -} - -/////////////////////////////////////////////////////////////////////////////// -// Size management -/////////////////////////////////////////////////////////////////////////////// - -uint32_t TextureCache::getSize() { - return mSize; -} - -uint32_t TextureCache::getMaxSize() { - return mMaxSize; -} - -/////////////////////////////////////////////////////////////////////////////// -// Callbacks -/////////////////////////////////////////////////////////////////////////////// - -void TextureCache::operator()(uint32_t&, Texture*& texture) { - // This will be called already locked - if (texture) { - mSize -= texture->bitmapSize; - TEXTURE_LOGD("TextureCache::callback: name, removed size, mSize = %d, %d, %d", texture->id, - texture->bitmapSize, mSize); - if (mDebugEnabled) { - ALOGD("Texture deleted, size = %d", texture->bitmapSize); - } - texture->deleteTexture(); - delete texture; - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Caching -/////////////////////////////////////////////////////////////////////////////// - -void TextureCache::resetMarkInUse(void* ownerToken) { - LruCache::Iterator iter(mCache); - while (iter.next()) { - if (iter.value()->isInUse == ownerToken) { - iter.value()->isInUse = nullptr; - } - } -} - -bool TextureCache::canMakeTextureFromBitmap(Bitmap* bitmap) { - if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) { - ALOGW("Bitmap too large to be uploaded into a texture (%dx%d, max=%dx%d)", bitmap->width(), - bitmap->height(), mMaxTextureSize, mMaxTextureSize); - return false; - } - return true; -} - -Texture* TextureCache::createTexture(Bitmap* bitmap) { - Texture* texture = new Texture(Caches::getInstance()); - texture->bitmapSize = bitmap->rowBytes() * bitmap->height(); - texture->generation = bitmap->getGenerationID(); - texture->upload(*bitmap); - return texture; -} - -// Returns a prepared Texture* that either is already in the cache or can fit -// in the cache (and is thus added to the cache) -Texture* TextureCache::getCachedTexture(Bitmap* bitmap) { - if (bitmap->isHardware()) { - auto textureIterator = mHardwareTextures.find(bitmap->getStableID()); - if (textureIterator == mHardwareTextures.end()) { - Texture* texture = createTexture(bitmap); - mHardwareTextures.insert( - std::make_pair(bitmap->getStableID(), std::unique_ptr(texture))); - if (mDebugEnabled) { - ALOGD("Texture created for hw bitmap size = %d", texture->bitmapSize); - } - return texture; - } - return textureIterator->second.get(); - } - - Texture* texture = mCache.get(bitmap->getStableID()); - - if (!texture) { - if (!canMakeTextureFromBitmap(bitmap)) { - return nullptr; - } - - const uint32_t size = bitmap->rowBytes() * bitmap->height(); - bool canCache = size < mMaxSize; - // Don't even try to cache a bitmap that's bigger than the cache - while (canCache && mSize + size > mMaxSize) { - Texture* oldest = mCache.peekOldestValue(); - if (oldest && !oldest->isInUse) { - mCache.removeOldest(); - } else { - canCache = false; - } - } - - if (canCache) { - texture = createTexture(bitmap); - mSize += size; - TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d", - bitmap, texture->id, size, mSize); - if (mDebugEnabled) { - ALOGD("Texture created, size = %d", size); - } - mCache.put(bitmap->getStableID(), texture); - } - } else if (!texture->isInUse && bitmap->getGenerationID() != texture->generation) { - // Texture was in the cache but is dirty, re-upload - // TODO: Re-adjust the cache size if the bitmap's dimensions have changed - texture->upload(*bitmap); - texture->generation = bitmap->getGenerationID(); - } - - return texture; -} - -bool TextureCache::prefetchAndMarkInUse(void* ownerToken, Bitmap* bitmap) { - Texture* texture = getCachedTexture(bitmap); - if (texture) { - texture->isInUse = ownerToken; - } - return texture; -} - -bool TextureCache::prefetch(Bitmap* bitmap) { - return getCachedTexture(bitmap); -} - -Texture* TextureCache::get(Bitmap* bitmap) { - Texture* texture = getCachedTexture(bitmap); - - if (!texture) { - if (!canMakeTextureFromBitmap(bitmap)) { - return nullptr; - } - texture = createTexture(bitmap); - texture->cleanup = true; - } - - return texture; -} - -bool TextureCache::destroyTexture(uint32_t pixelRefStableID) { - auto hardwareIter = mHardwareTextures.find(pixelRefStableID); - if (hardwareIter != mHardwareTextures.end()) { - hardwareIter->second->deleteTexture(); - mHardwareTextures.erase(hardwareIter); - return true; - } - return mCache.remove(pixelRefStableID); -} - -void TextureCache::clear() { - mCache.clear(); - for (auto& iter : mHardwareTextures) { - iter.second->deleteTexture(); - } - mHardwareTextures.clear(); - TEXTURE_LOGD("TextureCache:clear(), mSize = %d", mSize); -} - -void TextureCache::flush() { - if (mFlushRate >= 1.0f || mCache.size() == 0) return; - if (mFlushRate <= 0.0f) { - clear(); - return; - } - - uint32_t targetSize = uint32_t(mSize * mFlushRate); - TEXTURE_LOGD("TextureCache::flush: target size: %d", targetSize); - - while (mSize > targetSize) { - mCache.removeOldest(); - } -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h deleted file mode 100644 index 19e7bea99669..000000000000 --- a/libs/hwui/TextureCache.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2010 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_TEXTURE_CACHE_H -#define ANDROID_HWUI_TEXTURE_CACHE_H - -#include - -#include - -#include -#include - -#include "Debug.h" - -#include -#include - -namespace android { - -class Bitmap; - -namespace uirenderer { - -class Texture; - -/////////////////////////////////////////////////////////////////////////////// -// Defines -/////////////////////////////////////////////////////////////////////////////// - -// Debug -#if DEBUG_TEXTURES -#define TEXTURE_LOGD(...) ALOGD(__VA_ARGS__) -#else -#define TEXTURE_LOGD(...) -#endif - -/////////////////////////////////////////////////////////////////////////////// -// Classes -/////////////////////////////////////////////////////////////////////////////// - -/** - * A simple LRU texture cache. The cache has a maximum size expressed in bytes. - * Any texture added to the cache causing the cache to grow beyond the maximum - * allowed size will also cause the oldest texture to be kicked out. - */ -class TextureCache : public OnEntryRemoved { -public: - TextureCache(); - ~TextureCache(); - - /** - * Used as a callback when an entry is removed from the cache. - * Do not invoke directly. - */ - void operator()(uint32_t&, Texture*& texture) override; - - /** - * Resets all Textures to not be marked as in use - */ - void resetMarkInUse(void* ownerToken); - - /** - * Attempts to precache the SkBitmap. Returns true if a Texture was successfully - * acquired for the bitmap, false otherwise. If a Texture was acquired it is - * marked as in use. - */ - bool prefetchAndMarkInUse(void* ownerToken, Bitmap* bitmap); - - /** - * Attempts to precache the SkBitmap. Returns true if a Texture was successfully - * acquired for the bitmap, false otherwise. Does not mark the Texture - * as in use and won't update currently in-use Textures. - */ - bool prefetch(Bitmap* bitmap); - - /** - * Returns the texture associated with the specified bitmap from within the cache. - * If the texture cannot be found in the cache, a new texture is generated. - */ - Texture* get(Bitmap* bitmap); - - /** - * Removes the texture associated with the specified pixelRef. Must be called from RenderThread - * Returns true if a texture was destroyed, false if no texture with that id was found - */ - bool destroyTexture(uint32_t pixelRefStableID); - - /** - * Clears the cache. This causes all textures to be deleted. - */ - void clear(); - - /** - * Returns the maximum size of the cache in bytes. - */ - uint32_t getMaxSize(); - /** - * Returns the current size of the cache in bytes. - */ - uint32_t getSize(); - - /** - * Partially flushes the cache. The amount of memory freed by a flush - * is defined by the flush rate. - */ - void flush(); - -private: - bool canMakeTextureFromBitmap(Bitmap* bitmap); - - Texture* getCachedTexture(Bitmap* bitmap); - Texture* createTexture(Bitmap* bitmap); - - LruCache mCache; - - uint32_t mSize; - const uint32_t mMaxSize; - GLint mMaxTextureSize; - - const float mFlushRate; - - bool mDebugEnabled; - - std::unordered_map> mHardwareTextures; -}; // class TextureCache - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_TEXTURE_CACHE_H diff --git a/libs/hwui/font/CachedGlyphInfo.h b/libs/hwui/font/CachedGlyphInfo.h deleted file mode 100644 index 93bb823db512..000000000000 --- a/libs/hwui/font/CachedGlyphInfo.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2012 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_CACHED_GLYPH_INFO_H -#define ANDROID_HWUI_CACHED_GLYPH_INFO_H - -namespace android { -namespace uirenderer { - -class CacheTexture; - -struct CachedGlyphInfo { - // Has the cache been invalidated? - bool mIsValid; - // Location of the cached glyph in the bitmap - // in case we need to resize the texture or - // render to bitmap - uint32_t mStartX; - uint32_t mStartY; - uint32_t mBitmapWidth; - uint32_t mBitmapHeight; - // Also cache texture coords for the quad - float mBitmapMinU; - float mBitmapMinV; - float mBitmapMaxU; - float mBitmapMaxV; - // Minimize how much we call freetype - uint32_t mGlyphIndex; - float mAdvanceX; - float mAdvanceY; - // Values below contain a glyph's origin in the bitmap - int32_t mBitmapLeft; - int32_t mBitmapTop; - // Auto-kerning; represents a 2.6 fixed-point value with range [-1, 1]. - int8_t mLsbDelta; - int8_t mRsbDelta; - CacheTexture* mCacheTexture; -}; - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_CACHED_GLYPH_INFO_H diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp index 5e33353c3ac6..f173136d6f8d 100644 --- a/libs/hwui/renderstate/RenderState.cpp +++ b/libs/hwui/renderstate/RenderState.cpp @@ -125,10 +125,7 @@ void RenderState::flush(Caches::FlushMode mode) { } void RenderState::onBitmapDestroyed(uint32_t pixelRefId) { - if (mCaches && mCaches->textureCache.destroyTexture(pixelRefId)) { - glFlush(); - GL_CHECKPOINT(MODERATE); - } + // DEAD CODE } void RenderState::setViewport(GLsizei width, GLsizei height) { diff --git a/libs/hwui/tests/microbench/ShadowBench.cpp b/libs/hwui/tests/microbench/ShadowBench.cpp deleted file mode 100644 index 12da7837e2e9..000000000000 --- a/libs/hwui/tests/microbench/ShadowBench.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2015 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 - -#include "Matrix.h" -#include "Rect.h" -#include "TessellationCache.h" -#include "Vector.h" -#include "VertexBuffer.h" - -#include - -#include - -using namespace android; -using namespace android::uirenderer; - -struct ShadowTestData { - Matrix4 drawTransform; - Rect localClip; - Matrix4 casterTransformXY; - Matrix4 casterTransformZ; - Vector3 lightCenter; - float lightRadius; -}; - -void createShadowTestData(ShadowTestData* out) { - static float SAMPLE_DRAW_TRANSFORM[] = { - 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, - }; - static float SAMPLE_CASTERXY[] = { - 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 32, 32, 0, 1, - }; - static float SAMPLE_CASTERZ[] = { - 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 32, 32, 32, 1, - }; - static Rect SAMPLE_CLIP(0, 0, 1536, 2048); - static Vector3 SAMPLE_LIGHT_CENTER{768, -400, 1600}; - static float SAMPLE_LIGHT_RADIUS = 1600; - - out->drawTransform.load(SAMPLE_DRAW_TRANSFORM); - out->localClip = SAMPLE_CLIP; - out->casterTransformXY.load(SAMPLE_CASTERXY); - out->casterTransformZ.load(SAMPLE_CASTERZ); - out->lightCenter = SAMPLE_LIGHT_CENTER; - out->lightRadius = SAMPLE_LIGHT_RADIUS; -} - -static inline void tessellateShadows(ShadowTestData& testData, bool opaque, const SkPath& shape, - VertexBuffer* ambient, VertexBuffer* spot) { - tessellateShadows(&testData.drawTransform, &testData.localClip, opaque, &shape, - &testData.casterTransformXY, &testData.casterTransformZ, testData.lightCenter, - testData.lightRadius, *ambient, *spot); -} - -void BM_TessellateShadows_roundrect_opaque(benchmark::State& state) { - ShadowTestData shadowData; - createShadowTestData(&shadowData); - SkPath path; - path.addRoundRect(SkRect::MakeWH(100, 100), 5, 5); - - while (state.KeepRunning()) { - VertexBuffer ambient; - VertexBuffer spot; - tessellateShadows(shadowData, true, path, &ambient, &spot); - benchmark::DoNotOptimize(&ambient); - benchmark::DoNotOptimize(&spot); - } -} -BENCHMARK(BM_TessellateShadows_roundrect_opaque); - -void BM_TessellateShadows_roundrect_translucent(benchmark::State& state) { - ShadowTestData shadowData; - createShadowTestData(&shadowData); - SkPath path; - path.reset(); - path.addRoundRect(SkRect::MakeLTRB(0, 0, 100, 100), 5, 5); - - while (state.KeepRunning()) { - std::unique_ptr ambient(new VertexBuffer); - std::unique_ptr spot(new VertexBuffer); - tessellateShadows(shadowData, false, path, ambient.get(), spot.get()); - benchmark::DoNotOptimize(ambient.get()); - benchmark::DoNotOptimize(spot.get()); - } -} -BENCHMARK(BM_TessellateShadows_roundrect_translucent); diff --git a/libs/hwui/utils/PaintUtils.h b/libs/hwui/utils/PaintUtils.h index 233adae1df24..f8e8a0a18284 100644 --- a/libs/hwui/utils/PaintUtils.h +++ b/libs/hwui/utils/PaintUtils.h @@ -20,6 +20,7 @@ #include #include +#include #include namespace android { -- cgit v1.2.3-59-g8ed1b From d9d7f127b5f07df9434aff67374a0012b1750cd4 Mon Sep 17 00:00:00 2001 From: John Reck Date: Thu, 3 May 2018 14:40:56 -0700 Subject: Delete a bunch of code This removes the duality of DisplayList, removing a small amount of overhead Test: buids & hwuiunit passes Change-Id: I8bb3a20e9ead1caec4b4a8a3e9f2c08f717a7096 --- libs/hwui/Android.bp | 4 - libs/hwui/Animator.h | 4 +- libs/hwui/BakedOpRenderer.h | 11 +- libs/hwui/DisplayList.cpp | 142 ---- libs/hwui/DisplayList.h | 133 +--- libs/hwui/FrameBuilder.cpp | 867 --------------------- libs/hwui/FrameBuilder.h | 251 ------ libs/hwui/Lighting.h | 38 + libs/hwui/RecordingCanvas.cpp | 631 --------------- libs/hwui/RecordingCanvas.h | 320 -------- libs/hwui/RenderNode.cpp | 72 -- libs/hwui/RenderNode.h | 5 - libs/hwui/VectorDrawable.h | 2 + libs/hwui/hwui/Canvas.cpp | 1 - libs/hwui/hwui/Canvas.h | 10 +- libs/hwui/pipeline/skia/GLFunctorDrawable.h | 4 +- libs/hwui/pipeline/skia/RenderNodeDrawable.cpp | 14 +- libs/hwui/pipeline/skia/RenderNodeDrawable.h | 8 +- libs/hwui/pipeline/skia/SkiaDisplayList.h | 42 +- libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp | 5 +- libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h | 4 +- libs/hwui/pipeline/skia/SkiaPipeline.cpp | 5 +- libs/hwui/pipeline/skia/SkiaPipeline.h | 10 +- libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp | 4 +- libs/hwui/pipeline/skia/SkiaVulkanPipeline.h | 4 +- libs/hwui/renderstate/RenderState.cpp | 1 + libs/hwui/renderthread/CanvasContext.h | 8 +- libs/hwui/renderthread/DrawFrameTask.h | 1 - libs/hwui/renderthread/IRenderPipeline.h | 11 +- libs/hwui/renderthread/RenderProxy.cpp | 5 +- libs/hwui/tests/common/TestUtils.h | 15 +- libs/hwui/tests/common/scenes/TestSceneBase.h | 2 +- .../tests/microbench/DisplayListCanvasBench.cpp | 8 +- libs/hwui/tests/microbench/FrameBuilderBench.cpp | 149 ---- libs/hwui/tests/unit/SkiaCanvasTests.cpp | 1 - libs/hwui/tests/unit/SkiaPipelineTests.cpp | 4 +- libs/hwui/utils/TestWindowContext.cpp | 6 +- 37 files changed, 143 insertions(+), 2659 deletions(-) delete mode 100644 libs/hwui/DisplayList.cpp delete mode 100644 libs/hwui/FrameBuilder.cpp delete mode 100644 libs/hwui/FrameBuilder.h create mode 100644 libs/hwui/Lighting.h delete mode 100644 libs/hwui/RecordingCanvas.cpp delete mode 100644 libs/hwui/RecordingCanvas.h delete mode 100644 libs/hwui/tests/microbench/FrameBuilderBench.cpp (limited to 'libs/hwui/FrameBuilder.cpp') diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index d716844b11c3..1ad40ec68622 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -210,8 +210,6 @@ cc_defaults { "DamageAccumulator.cpp", "DeferredLayerUpdater.cpp", "DeviceInfo.cpp", - "DisplayList.cpp", - "FrameBuilder.cpp", "FrameInfo.cpp", "FrameInfoVisualizer.cpp", "GlLayer.cpp", @@ -237,7 +235,6 @@ cc_defaults { "Properties.cpp", "PropertyValuesAnimatorSet.cpp", "PropertyValuesHolder.cpp", - "RecordingCanvas.cpp", "RenderNode.cpp", "RenderProperties.cpp", "ResourceCache.cpp", @@ -399,7 +396,6 @@ cc_benchmark { srcs: [ "tests/microbench/main.cpp", "tests/microbench/DisplayListCanvasBench.cpp", - "tests/microbench/FrameBuilderBench.cpp", "tests/microbench/LinearAllocatorBench.cpp", "tests/microbench/PathParserBench.cpp", "tests/microbench/RenderNodeBench.cpp", diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h index 42f4cf8828bd..ed7b6eb1cf4a 100644 --- a/libs/hwui/Animator.h +++ b/libs/hwui/Animator.h @@ -16,6 +16,8 @@ #ifndef ANIMATOR_H #define ANIMATOR_H +#include "CanvasProperty.h" + #include #include #include @@ -31,8 +33,6 @@ namespace uirenderer { class AnimationContext; class BaseRenderNodeAnimator; -class CanvasPropertyPrimitive; -class CanvasPropertyPaint; class Interpolator; class RenderNode; class RenderProperties; diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h index ae8928ea8461..72c93650a83b 100644 --- a/libs/hwui/BakedOpRenderer.h +++ b/libs/hwui/BakedOpRenderer.h @@ -17,6 +17,7 @@ #pragma once #include "BakedOpState.h" +#include "Lighting.h" #include "Matrix.h" #include "utils/Macros.h" @@ -42,16 +43,6 @@ struct ClipBase; class BakedOpRenderer { public: typedef void (*GlopReceiver)(BakedOpRenderer&, const Rect*, const ClipBase*, const Glop&); - /** - * Position agnostic shadow lighting info. Used with all shadow ops in scene. - */ - struct LightInfo { - LightInfo() : LightInfo(0, 0) {} - LightInfo(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) - : ambientShadowAlpha(ambientShadowAlpha), spotShadowAlpha(spotShadowAlpha) {} - uint8_t ambientShadowAlpha; - uint8_t spotShadowAlpha; - }; BakedOpRenderer(Caches& caches, RenderState& renderState, bool opaque, bool wideColorGamut, const LightInfo& lightInfo) diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp deleted file mode 100644 index f1f0d2ddfcff..000000000000 --- a/libs/hwui/DisplayList.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2013 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 -#include - -#include - -#include "DamageAccumulator.h" -#include "Debug.h" -#include "DisplayList.h" -#include "OpDumper.h" -#include "RecordedOp.h" -#include "RenderNode.h" -#include "VectorDrawable.h" -#include "renderthread/CanvasContext.h" - -namespace android { -namespace uirenderer { - -DisplayList::DisplayList() - : projectionReceiveIndex(-1) - , stdAllocator(allocator) - , chunks(stdAllocator) - , ops(stdAllocator) - , children(stdAllocator) - , bitmapResources(stdAllocator) - , pathResources(stdAllocator) - , patchResources(stdAllocator) - , paints(stdAllocator) - , regions(stdAllocator) - , referenceHolders(stdAllocator) - , functors(stdAllocator) - , vectorDrawables(stdAllocator) {} - -DisplayList::~DisplayList() { - cleanupResources(); -} - -void DisplayList::cleanupResources() { - if (CC_UNLIKELY(patchResources.size())) { - ResourceCache& resourceCache = ResourceCache::getInstance(); - resourceCache.lock(); - - for (size_t i = 0; i < patchResources.size(); i++) { - resourceCache.decrementRefcountLocked(patchResources[i]); - } - - resourceCache.unlock(); - } - - for (size_t i = 0; i < pathResources.size(); i++) { - const SkPath* path = pathResources[i]; - delete path; - } - - for (auto& iter : functors) { - if (iter.listener) { - iter.listener->onGlFunctorReleased(iter.functor); - } - } - - patchResources.clear(); - pathResources.clear(); - paints.clear(); - regions.clear(); -} - -size_t DisplayList::addChild(NodeOpType* op) { - referenceHolders.push_back(op->renderNode); - size_t index = children.size(); - children.push_back(op); - return index; -} - -void DisplayList::syncContents() { - for (auto& iter : functors) { - (*iter.functor)(DrawGlInfo::kModeSync, nullptr); - } - for (auto& vectorDrawable : vectorDrawables) { - vectorDrawable->syncProperties(); - } -} - -void DisplayList::updateChildren(std::function updateFn) { - for (auto&& child : children) { - updateFn(child->renderNode); - } -} - -bool DisplayList::prepareListAndChildren( - TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer, - std::function childFn) { - info.prepareTextures = info.canvasContext.pinImages(bitmapResources); - - for (auto&& op : children) { - RenderNode* childNode = op->renderNode; - info.damageAccumulator->pushTransform(&op->localMatrix); - bool childFunctorsNeedLayer = - functorsNeedLayer; // TODO! || op->mRecordedWithPotentialStencilClip; - childFn(childNode, observer, info, childFunctorsNeedLayer); - info.damageAccumulator->popTransform(); - } - - bool isDirty = false; - for (auto& vectorDrawable : vectorDrawables) { - // If any vector drawable in the display list needs update, damage the node. - if (vectorDrawable->isDirty()) { - isDirty = true; - } - vectorDrawable->setPropertyChangeWillBeConsumed(true); - } - return isDirty; -} - -void DisplayList::output(std::ostream& output, uint32_t level) { - for (auto&& op : getOps()) { - OpDumper::dump(*op, output, level + 1); - if (op->opId == RecordedOpId::RenderNodeOp) { - auto rnOp = reinterpret_cast(op); - rnOp->renderNode->output(output, level + 1); - } else { - output << std::endl; - } - } -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index 7a9c65dd365b..a952cc23e1ef 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -16,149 +16,20 @@ #pragma once -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include - -#include - -#include "CanvasProperty.h" -#include "Debug.h" -#include "GlFunctorLifecycleListener.h" -#include "Matrix.h" -#include "RenderProperties.h" -#include "TreeInfo.h" -#include "hwui/Bitmap.h" - -#include - -class SkBitmap; -class SkPaint; -class SkPath; -class SkRegion; +#include "pipeline/skia/SkiaDisplayList.h" namespace android { namespace uirenderer { -struct ClipBase; -class Rect; -class Layer; - -struct RecordedOp; -struct RenderNodeOp; - -typedef RecordedOp BaseOpType; -typedef RenderNodeOp NodeOpType; - namespace VectorDrawable { class Tree; }; typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot; -struct FunctorContainer { - Functor* functor; - GlFunctorLifecycleListener* listener; -}; - /** * Data structure that holds the list of commands used in display list stream */ -class DisplayList { - friend class RecordingCanvas; - -public: - struct Chunk { - // range of included ops in DisplayList::ops() - size_t beginOpIndex; - size_t endOpIndex; - - // range of included children in DisplayList::children() - size_t beginChildIndex; - size_t endChildIndex; - - // whether children with non-zero Z in the chunk should be reordered - bool reorderChildren; - - // clip at the beginning of a reorder section, applied to reordered children - const ClipBase* reorderClip; - }; - - DisplayList(); - virtual ~DisplayList(); - - // index of DisplayListOp restore, after which projected descendants should be drawn - int projectionReceiveIndex; - - const LsaVector& getChunks() const { return chunks; } - const LsaVector& getOps() const { return ops; } - - const LsaVector& getChildren() const { return children; } - - const LsaVector>& getBitmapResources() const { return bitmapResources; } - - size_t addChild(NodeOpType* childOp); - - void ref(VirtualLightRefBase* prop) { referenceHolders.push_back(prop); } - - size_t getUsedSize() { return allocator.usedSize(); } - - virtual bool isEmpty() const { return ops.empty(); } - virtual bool hasFunctor() const { return !functors.empty(); } - virtual bool hasVectorDrawables() const { return !vectorDrawables.empty(); } - virtual bool isSkiaDL() const { return false; } - virtual bool reuseDisplayList(RenderNode* node, renderthread::CanvasContext* context) { - return false; - } - - virtual void syncContents(); - virtual void updateChildren(std::function updateFn); - virtual bool prepareListAndChildren( - TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer, - std::function childFn); - - virtual void output(std::ostream& output, uint32_t level); - -protected: - // allocator into which all ops and LsaVector arrays allocated - LinearAllocator allocator; - LinearStdAllocator stdAllocator; - -private: - LsaVector chunks; - LsaVector ops; - - // list of Ops referring to RenderNode children for quick, non-drawing traversal - LsaVector children; - - // Resources - Skia objects + 9 patches referred to by this DisplayList - LsaVector> bitmapResources; - LsaVector pathResources; - LsaVector patchResources; - LsaVector> paints; - LsaVector> regions; - LsaVector> referenceHolders; - - // List of functors - LsaVector functors; - - // List of VectorDrawables that need to be notified of pushStaging. Note that this list gets - // nothing - // but a callback during sync DisplayList, unlike the list of functors defined above, which - // gets special treatment exclusive for webview. - LsaVector vectorDrawables; - - void cleanupResources(); -}; +using DisplayList = skiapipeline::SkiaDisplayList; }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp deleted file mode 100644 index 575aea524133..000000000000 --- a/libs/hwui/FrameBuilder.cpp +++ /dev/null @@ -1,867 +0,0 @@ -/* - * Copyright (C) 2016 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 "FrameBuilder.h" - -#include "DeferredLayerUpdater.h" -#include "LayerUpdateQueue.h" -#include "RenderNode.h" -#include "VectorDrawable.h" -#include "hwui/Canvas.h" -#include "renderstate/OffscreenBufferPool.h" -#include "utils/FatVector.h" -#include "utils/PaintUtils.h" -#include "utils/TraceUtils.h" - -#include -#include - -namespace android { -namespace uirenderer { - -FrameBuilder::FrameBuilder(const SkRect& clip, uint32_t viewportWidth, uint32_t viewportHeight, - const LightGeometry& lightGeometry, Caches& caches) - : mStdAllocator(mAllocator) - , mLayerBuilders(mStdAllocator) - , mLayerStack(mStdAllocator) - , mCanvasState(*this) - , mCaches(caches) - , mLightRadius(lightGeometry.radius) - , mDrawFbo0(true) { - // Prepare to defer Fbo0 - auto fbo0 = mAllocator.create(viewportWidth, viewportHeight, Rect(clip)); - mLayerBuilders.push_back(fbo0); - mLayerStack.push_back(0); - mCanvasState.initializeSaveStack(viewportWidth, viewportHeight, clip.fLeft, clip.fTop, - clip.fRight, clip.fBottom, lightGeometry.center); -} - -FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const LightGeometry& lightGeometry, - Caches& caches) - : mStdAllocator(mAllocator) - , mLayerBuilders(mStdAllocator) - , mLayerStack(mStdAllocator) - , mCanvasState(*this) - , mCaches(caches) - , mLightRadius(lightGeometry.radius) - , mDrawFbo0(false) { - // TODO: remove, with each layer on its own save stack - - // Prepare to defer Fbo0 (which will be empty) - auto fbo0 = mAllocator.create(1, 1, Rect(1, 1)); - mLayerBuilders.push_back(fbo0); - mLayerStack.push_back(0); - mCanvasState.initializeSaveStack(1, 1, 0, 0, 1, 1, lightGeometry.center); - - deferLayers(layers); -} - -void FrameBuilder::deferLayers(const LayerUpdateQueue& layers) { - // Render all layers to be updated, in order. Defer in reverse order, so that they'll be - // updated in the order they're passed in (mLayerBuilders are issued to Renderer in reverse) - for (int i = layers.entries().size() - 1; i >= 0; i--) { - RenderNode* layerNode = layers.entries()[i].renderNode.get(); - // only schedule repaint if node still on layer - possible it may have been - // removed during a dropped frame, but layers may still remain scheduled so - // as not to lose info on what portion is damaged - OffscreenBuffer* layer = layerNode->getLayer(); - if (CC_LIKELY(layer)) { - ATRACE_FORMAT("Optimize HW Layer DisplayList %s %ux%u", layerNode->getName(), - layerNode->getWidth(), layerNode->getHeight()); - - Rect layerDamage = layers.entries()[i].damage; - // TODO: ensure layer damage can't be larger than layer - layerDamage.doIntersect(0, 0, layer->viewportWidth, layer->viewportHeight); - layerNode->computeOrdering(); - - // map current light center into RenderNode's coordinate space - Vector3 lightCenter = mCanvasState.currentSnapshot()->getRelativeLightCenter(); - layer->inverseTransformInWindow.mapPoint3d(lightCenter); - - saveForLayer(layerNode->getWidth(), layerNode->getHeight(), 0, 0, layerDamage, - lightCenter, nullptr, layerNode); - - if (layerNode->getDisplayList()) { - deferNodeOps(*layerNode); - } - restoreForLayer(); - } - } -} - -void FrameBuilder::deferRenderNode(RenderNode& renderNode) { - renderNode.computeOrdering(); - - mCanvasState.save(SaveFlags::MatrixClip); - deferNodePropsAndOps(renderNode); - mCanvasState.restore(); -} - -void FrameBuilder::deferRenderNode(float tx, float ty, Rect clipRect, RenderNode& renderNode) { - renderNode.computeOrdering(); - - mCanvasState.save(SaveFlags::MatrixClip); - mCanvasState.translate(tx, ty); - mCanvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, - SkClipOp::kIntersect); - deferNodePropsAndOps(renderNode); - mCanvasState.restore(); -} - -static Rect nodeBounds(RenderNode& node) { - auto& props = node.properties(); - return Rect(props.getLeft(), props.getTop(), props.getRight(), props.getBottom()); -} - -void FrameBuilder::deferRenderNodeScene(const std::vector >& nodes, - const Rect& contentDrawBounds) { - if (nodes.size() < 1) return; - if (nodes.size() == 1) { - if (!nodes[0]->nothingToDraw()) { - deferRenderNode(*nodes[0]); - } - return; - } - // It there are multiple render nodes, they are laid out as follows: - // #0 - backdrop (content + caption) - // #1 - content (local bounds are at (0,0), will be translated and clipped to backdrop) - // #2 - additional overlay nodes - // Usually the backdrop cannot be seen since it will be entirely covered by the content. While - // resizing however it might become partially visible. The following render loop will crop the - // backdrop against the content and draw the remaining part of it. It will then draw the content - // cropped to the backdrop (since that indicates a shrinking of the window). - // - // Additional nodes will be drawn on top with no particular clipping semantics. - - // Usually the contents bounds should be mContentDrawBounds - however - we will - // move it towards the fixed edge to give it a more stable appearance (for the moment). - // If there is no content bounds we ignore the layering as stated above and start with 2. - - // Backdrop bounds in render target space - const Rect backdrop = nodeBounds(*nodes[0]); - - // Bounds that content will fill in render target space (note content node bounds may be bigger) - Rect content(contentDrawBounds.getWidth(), contentDrawBounds.getHeight()); - content.translate(backdrop.left, backdrop.top); - if (!content.contains(backdrop) && !nodes[0]->nothingToDraw()) { - // Content doesn't entirely overlap backdrop, so fill around content (right/bottom) - - // Note: in the future, if content doesn't snap to backdrop's left/top, this may need to - // also fill left/top. Currently, both 2up and freeform position content at the top/left of - // the backdrop, so this isn't necessary. - if (content.right < backdrop.right) { - // draw backdrop to right side of content - deferRenderNode(0, 0, - Rect(content.right, backdrop.top, backdrop.right, backdrop.bottom), - *nodes[0]); - } - if (content.bottom < backdrop.bottom) { - // draw backdrop to bottom of content - // Note: bottom fill uses content left/right, to avoid overdrawing left/right fill - deferRenderNode(0, 0, - Rect(content.left, content.bottom, content.right, backdrop.bottom), - *nodes[0]); - } - } - - if (!nodes[1]->nothingToDraw()) { - if (!backdrop.isEmpty()) { - // content node translation to catch up with backdrop - float dx = contentDrawBounds.left - backdrop.left; - float dy = contentDrawBounds.top - backdrop.top; - - Rect contentLocalClip = backdrop; - contentLocalClip.translate(dx, dy); - deferRenderNode(-dx, -dy, contentLocalClip, *nodes[1]); - } else { - deferRenderNode(*nodes[1]); - } - } - - // remaining overlay nodes, simply defer - for (size_t index = 2; index < nodes.size(); index++) { - if (!nodes[index]->nothingToDraw()) { - deferRenderNode(*nodes[index]); - } - } -} - -void FrameBuilder::onViewportInitialized() {} - -void FrameBuilder::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {} - -void FrameBuilder::deferNodePropsAndOps(RenderNode& node) { - const RenderProperties& properties = node.properties(); - const Outline& outline = properties.getOutline(); - if (properties.getAlpha() <= 0 || (outline.getShouldClip() && outline.isEmpty()) || - properties.getScaleX() == 0 || properties.getScaleY() == 0) { - return; // rejected - } - - if (properties.getLeft() != 0 || properties.getTop() != 0) { - mCanvasState.translate(properties.getLeft(), properties.getTop()); - } - if (properties.getStaticMatrix()) { - mCanvasState.concatMatrix(*properties.getStaticMatrix()); - } else if (properties.getAnimationMatrix()) { - mCanvasState.concatMatrix(*properties.getAnimationMatrix()); - } - if (properties.hasTransformMatrix()) { - if (properties.isTransformTranslateOnly()) { - mCanvasState.translate(properties.getTranslationX(), properties.getTranslationY()); - } else { - mCanvasState.concatMatrix(*properties.getTransformMatrix()); - } - } - - const int width = properties.getWidth(); - const int height = properties.getHeight(); - - Rect saveLayerBounds; // will be set to non-empty if saveLayer needed - const bool isLayer = properties.effectiveLayerType() != LayerType::None; - int clipFlags = properties.getClippingFlags(); - if (properties.getAlpha() < 1) { - if (isLayer) { - clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer - } - if (CC_LIKELY(isLayer || !properties.getHasOverlappingRendering())) { - // simply scale rendering content's alpha - mCanvasState.scaleAlpha(properties.getAlpha()); - } else { - // schedule saveLayer by initializing saveLayerBounds - saveLayerBounds.set(0, 0, width, height); - if (clipFlags) { - properties.getClippingRectForFlags(clipFlags, &saveLayerBounds); - clipFlags = 0; // all clipping done by savelayer - } - } - - if (CC_UNLIKELY(ATRACE_ENABLED() && properties.promotedToLayer())) { - // pretend alpha always causes savelayer to warn about - // performance problem affecting old versions - ATRACE_FORMAT("%s alpha caused saveLayer %dx%d", node.getName(), width, height); - } - } - if (clipFlags) { - Rect clipRect; - properties.getClippingRectForFlags(clipFlags, &clipRect); - mCanvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, - SkClipOp::kIntersect); - } - - if (properties.getRevealClip().willClip()) { - Rect bounds; - properties.getRevealClip().getBounds(&bounds); - mCanvasState.setClippingRoundRect(mAllocator, bounds, - properties.getRevealClip().getRadius()); - } else if (properties.getOutline().willClip()) { - mCanvasState.setClippingOutline(mAllocator, &(properties.getOutline())); - } - - bool quickRejected = mCanvasState.currentSnapshot()->getRenderTargetClip().isEmpty() || - (properties.getClipToBounds() && - mCanvasState.quickRejectConservative(0, 0, width, height)); - if (!quickRejected) { - // not rejected, so defer render as either Layer, or direct (possibly wrapped in saveLayer) - if (node.getLayer()) { - // HW layer - LayerOp* drawLayerOp = mAllocator.create_trivial(node); - BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp); - if (bakedOpState) { - // Node's layer already deferred, schedule it to render into parent layer - currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Bitmap); - } - } else if (CC_UNLIKELY(!saveLayerBounds.isEmpty())) { - // draw DisplayList contents within temporary, since persisted layer could not be used. - // (temp layers are clipped to viewport, since they don't persist offscreen content) - SkPaint saveLayerPaint; - saveLayerPaint.setAlpha(properties.getAlpha()); - deferBeginLayerOp(*mAllocator.create_trivial( - saveLayerBounds, Matrix4::identity(), - nullptr, // no record-time clip - need only respect defer-time one - &saveLayerPaint)); - deferNodeOps(node); - deferEndLayerOp(*mAllocator.create_trivial()); - } else { - deferNodeOps(node); - } - } -} - -typedef key_value_pair_t ZRenderNodeOpPair; - -template -static void buildZSortedChildList(V* zTranslatedNodes, const DisplayList& displayList, - const DisplayList::Chunk& chunk) { - if (chunk.beginChildIndex == chunk.endChildIndex) return; - - for (size_t i = chunk.beginChildIndex; i < chunk.endChildIndex; i++) { - RenderNodeOp* childOp = displayList.getChildren()[i]; - RenderNode* child = childOp->renderNode; - float childZ = child->properties().getZ(); - - if (!MathUtils::isZero(childZ) && chunk.reorderChildren) { - zTranslatedNodes->push_back(ZRenderNodeOpPair(childZ, childOp)); - childOp->skipInOrderDraw = true; - } else if (!child->properties().getProjectBackwards()) { - // regular, in order drawing DisplayList - childOp->skipInOrderDraw = false; - } - } - - // Z sort any 3d children (stable-ness makes z compare fall back to standard drawing order) - std::stable_sort(zTranslatedNodes->begin(), zTranslatedNodes->end()); -} - -template -static size_t findNonNegativeIndex(const V& zTranslatedNodes) { - for (size_t i = 0; i < zTranslatedNodes.size(); i++) { - if (zTranslatedNodes[i].key >= 0.0f) return i; - } - return zTranslatedNodes.size(); -} - -template -void FrameBuilder::defer3dChildren(const ClipBase* reorderClip, ChildrenSelectMode mode, - const V& zTranslatedNodes) { - const int size = zTranslatedNodes.size(); - if (size == 0 || (mode == ChildrenSelectMode::Negative && zTranslatedNodes[0].key > 0.0f) || - (mode == ChildrenSelectMode::Positive && zTranslatedNodes[size - 1].key < 0.0f)) { - // no 3d children to draw - return; - } - - /** - * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters - * with very similar Z heights to draw together. - * - * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are - * underneath both, and neither's shadow is drawn on top of the other. - */ - const size_t nonNegativeIndex = findNonNegativeIndex(zTranslatedNodes); - size_t drawIndex, shadowIndex, endIndex; - if (mode == ChildrenSelectMode::Negative) { - drawIndex = 0; - endIndex = nonNegativeIndex; - shadowIndex = endIndex; // draw no shadows - } else { - drawIndex = nonNegativeIndex; - endIndex = size; - shadowIndex = drawIndex; // potentially draw shadow for each pos Z child - } - - float lastCasterZ = 0.0f; - while (shadowIndex < endIndex || drawIndex < endIndex) { - if (shadowIndex < endIndex) { - const RenderNodeOp* casterNodeOp = zTranslatedNodes[shadowIndex].value; - const float casterZ = zTranslatedNodes[shadowIndex].key; - // attempt to render the shadow if the caster about to be drawn is its caster, - // OR if its caster's Z value is similar to the previous potential caster - if (shadowIndex == drawIndex || casterZ - lastCasterZ < 0.1f) { - deferShadow(reorderClip, *casterNodeOp); - - lastCasterZ = casterZ; // must do this even if current caster not casting a shadow - shadowIndex++; - continue; - } - } - - const RenderNodeOp* childOp = zTranslatedNodes[drawIndex].value; - deferRenderNodeOpImpl(*childOp); - drawIndex++; - } -} - -void FrameBuilder::deferShadow(const ClipBase* reorderClip, const RenderNodeOp& casterNodeOp) { - // DEAD CODE -} - -void FrameBuilder::deferProjectedChildren(const RenderNode& renderNode) { - int count = mCanvasState.save(SaveFlags::MatrixClip); - const SkPath* projectionReceiverOutline = renderNode.properties().getOutline().getPath(); - - SkPath transformedMaskPath; // on stack, since BakedOpState makes a deep copy - if (projectionReceiverOutline) { - // transform the mask for this projector into render target space - // TODO: consider combining both transforms by stashing transform instead of applying - SkMatrix skCurrentTransform; - mCanvasState.currentTransform()->copyTo(skCurrentTransform); - projectionReceiverOutline->transform(skCurrentTransform, &transformedMaskPath); - mCanvasState.setProjectionPathMask(&transformedMaskPath); - } - - for (size_t i = 0; i < renderNode.mProjectedNodes.size(); i++) { - RenderNodeOp* childOp = renderNode.mProjectedNodes[i]; - RenderNode& childNode = *childOp->renderNode; - - // Draw child if it has content, but ignore state in childOp - matrix already applied to - // transformFromCompositingAncestor, and record-time clip is ignored when projecting - if (!childNode.nothingToDraw()) { - int restoreTo = mCanvasState.save(SaveFlags::MatrixClip); - - // Apply transform between ancestor and projected descendant - mCanvasState.concatMatrix(childOp->transformFromCompositingAncestor); - - deferNodePropsAndOps(childNode); - - mCanvasState.restoreToCount(restoreTo); - } - } - mCanvasState.restoreToCount(count); -} - -/** - * Used to define a list of lambdas referencing private FrameBuilder::onXX::defer() methods. - * - * This allows opIds embedded in the RecordedOps to be used for dispatching to these lambdas. - * E.g. a BitmapOp op then would be dispatched to FrameBuilder::onBitmapOp(const BitmapOp&) - */ -#define OP_RECEIVER(Type) \ - [](FrameBuilder& frameBuilder, const RecordedOp& op) { \ - frameBuilder.defer##Type(static_cast(op)); \ - }, -void FrameBuilder::deferNodeOps(const RenderNode& renderNode) { - typedef void (*OpDispatcher)(FrameBuilder & frameBuilder, const RecordedOp& op); - static OpDispatcher receivers[] = BUILD_DEFERRABLE_OP_LUT(OP_RECEIVER); - - // can't be null, since DL=null node rejection happens before deferNodePropsAndOps - const DisplayList& displayList = *(renderNode.getDisplayList()); - for (auto& chunk : displayList.getChunks()) { - FatVector zTranslatedNodes; - buildZSortedChildList(&zTranslatedNodes, displayList, chunk); - - defer3dChildren(chunk.reorderClip, ChildrenSelectMode::Negative, zTranslatedNodes); - for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) { - const RecordedOp* op = displayList.getOps()[opIndex]; - receivers[op->opId](*this, *op); - - if (CC_UNLIKELY(!renderNode.mProjectedNodes.empty() && - displayList.projectionReceiveIndex >= 0 && - static_cast(opIndex) == displayList.projectionReceiveIndex)) { - deferProjectedChildren(renderNode); - } - } - defer3dChildren(chunk.reorderClip, ChildrenSelectMode::Positive, zTranslatedNodes); - } -} - -void FrameBuilder::deferRenderNodeOpImpl(const RenderNodeOp& op) { - if (op.renderNode->nothingToDraw()) return; - int count = mCanvasState.save(SaveFlags::MatrixClip); - - // apply state from RecordedOp (clip first, since op's clip is transformed by current matrix) - mCanvasState.writableSnapshot()->applyClip(op.localClip, - *mCanvasState.currentSnapshot()->transform); - mCanvasState.concatMatrix(op.localMatrix); - - // then apply state from node properties, and defer ops - deferNodePropsAndOps(*op.renderNode); - - mCanvasState.restoreToCount(count); -} - -void FrameBuilder::deferRenderNodeOp(const RenderNodeOp& op) { - if (!op.skipInOrderDraw) { - deferRenderNodeOpImpl(op); - } -} - -/** - * Defers an unmergeable, strokeable op, accounting correctly - * for paint's style on the bounds being computed. - */ -BakedOpState* FrameBuilder::deferStrokeableOp(const RecordedOp& op, batchid_t batchId, - BakedOpState::StrokeBehavior strokeBehavior, - bool expandForPathTexture) { - // Note: here we account for stroke when baking the op - BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct( - mAllocator, *mCanvasState.writableSnapshot(), op, strokeBehavior, expandForPathTexture); - if (!bakedState) return nullptr; // quick rejected - - if (op.opId == RecordedOpId::RectOp && op.paint->getStyle() != SkPaint::kStroke_Style) { - bakedState->setupOpacity(op.paint); - } - - currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId); - return bakedState; -} - -/** - * Returns batch id for tessellatable shapes, based on paint. Checks to see if path effect/AA will - * be used, since they trigger significantly different rendering paths. - * - * Note: not used for lines/points, since they don't currently support path effects. - */ -static batchid_t tessBatchId(const RecordedOp& op) { - const SkPaint& paint = *(op.paint); - return paint.getPathEffect() - ? OpBatchType::AlphaMaskTexture - : (paint.isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices); -} - -void FrameBuilder::deferArcOp(const ArcOp& op) { - // Pass true below since arcs have a tendency to draw outside their expected bounds within - // their path textures. Passing true makes it more likely that we'll scissor, instead of - // corrupting the frame by drawing outside of clip bounds. - deferStrokeableOp(op, tessBatchId(op), BakedOpState::StrokeBehavior::StyleDefined, true); -} - -static bool hasMergeableClip(const BakedOpState& state) { - return !state.computedState.clipState || - state.computedState.clipState->mode == ClipMode::Rectangle; -} - -void FrameBuilder::deferBitmapOp(const BitmapOp& op) { - BakedOpState* bakedState = tryBakeOpState(op); - if (!bakedState) return; // quick rejected - - if (op.bitmap->isOpaque()) { - bakedState->setupOpacity(op.paint); - } - - // Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation - // Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in - // MergingDrawBatch::canMergeWith() - if (bakedState->computedState.transform.isSimple() && - bakedState->computedState.transform.positiveScale() && - PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver && - op.bitmap->colorType() != kAlpha_8_SkColorType && hasMergeableClip(*bakedState)) { - mergeid_t mergeId = reinterpret_cast(op.bitmap->getGenerationID()); - currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::Bitmap, mergeId); - } else { - currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); - } -} - -void FrameBuilder::deferBitmapMeshOp(const BitmapMeshOp& op) { - BakedOpState* bakedState = tryBakeOpState(op); - if (!bakedState) return; // quick rejected - currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); -} - -void FrameBuilder::deferBitmapRectOp(const BitmapRectOp& op) { - BakedOpState* bakedState = tryBakeOpState(op); - if (!bakedState) return; // quick rejected - currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); -} - -void FrameBuilder::deferVectorDrawableOp(const VectorDrawableOp& op) { - Bitmap& bitmap = op.vectorDrawable->getBitmapUpdateIfDirty(); - SkPaint* paint = op.vectorDrawable->getPaint(); - const BitmapRectOp* resolvedOp = mAllocator.create_trivial( - op.unmappedBounds, op.localMatrix, op.localClip, paint, &bitmap, - Rect(bitmap.width(), bitmap.height())); - deferBitmapRectOp(*resolvedOp); -} - -void FrameBuilder::deferCirclePropsOp(const CirclePropsOp& op) { - // allocate a temporary oval op (with mAllocator, so it persists until render), so the - // renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple. - float x = *(op.x); - float y = *(op.y); - float radius = *(op.radius); - Rect unmappedBounds(x - radius, y - radius, x + radius, y + radius); - const OvalOp* resolvedOp = mAllocator.create_trivial(unmappedBounds, op.localMatrix, - op.localClip, op.paint); - deferOvalOp(*resolvedOp); -} - -void FrameBuilder::deferColorOp(const ColorOp& op) { - BakedOpState* bakedState = tryBakeUnboundedOpState(op); - if (!bakedState) return; // quick rejected - currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices); -} - -void FrameBuilder::deferFunctorOp(const FunctorOp& op) { - BakedOpState* bakedState = tryBakeUnboundedOpState(op); - if (!bakedState) return; // quick rejected - currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Functor); -} - -void FrameBuilder::deferLinesOp(const LinesOp& op) { - batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices; - deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced); -} - -void FrameBuilder::deferOvalOp(const OvalOp& op) { - deferStrokeableOp(op, tessBatchId(op)); -} - -void FrameBuilder::deferPatchOp(const PatchOp& op) { - BakedOpState* bakedState = tryBakeOpState(op); - if (!bakedState) return; // quick rejected - - if (bakedState->computedState.transform.isPureTranslate() && - PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver && - hasMergeableClip(*bakedState)) { - mergeid_t mergeId = reinterpret_cast(op.bitmap->getGenerationID()); - - // Only use the MergedPatch batchId when merged, so Bitmap+Patch don't try to merge together - currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::MergedPatch, mergeId); - } else { - // Use Bitmap batchId since Bitmap+Patch use same shader - currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); - } -} - -void FrameBuilder::deferPathOp(const PathOp& op) { - /*auto state = */deferStrokeableOp(op, OpBatchType::AlphaMaskTexture); -} - -void FrameBuilder::deferPointsOp(const PointsOp& op) { - batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices; - deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced); -} - -void FrameBuilder::deferRectOp(const RectOp& op) { - deferStrokeableOp(op, tessBatchId(op)); -} - -void FrameBuilder::deferRoundRectOp(const RoundRectOp& op) { - // DEAD CODE -} - -void FrameBuilder::deferRoundRectPropsOp(const RoundRectPropsOp& op) { - // allocate a temporary round rect op (with mAllocator, so it persists until render), so the - // renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple. - const RoundRectOp* resolvedOp = mAllocator.create_trivial( - Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)), op.localMatrix, op.localClip, - op.paint, *op.rx, *op.ry); - deferRoundRectOp(*resolvedOp); -} - -void FrameBuilder::deferSimpleRectsOp(const SimpleRectsOp& op) { - BakedOpState* bakedState = tryBakeOpState(op); - if (!bakedState) return; // quick rejected - currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices); -} - -void FrameBuilder::deferTextOp(const TextOp& op) { - // DEAD CODE -} - -void FrameBuilder::deferTextOnPathOp(const TextOnPathOp& op) { - // DEAD CODE -} - -void FrameBuilder::deferTextureLayerOp(const TextureLayerOp& op) { - GlLayer* layer = static_cast(op.layerHandle->backingLayer()); - if (CC_UNLIKELY(!layer || !layer->isRenderable())) return; - - const TextureLayerOp* textureLayerOp = &op; - // Now safe to access transform (which was potentially unready at record time) - if (!layer->getTransform().isIdentity()) { - // non-identity transform present, so 'inject it' into op by copying + replacing matrix - Matrix4 combinedMatrix(op.localMatrix); - combinedMatrix.multiply(layer->getTransform()); - textureLayerOp = mAllocator.create(op, combinedMatrix); - } - BakedOpState* bakedState = tryBakeOpState(*textureLayerOp); - - if (!bakedState) return; // quick rejected - currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::TextureLayer); -} - -void FrameBuilder::saveForLayer(uint32_t layerWidth, uint32_t layerHeight, float contentTranslateX, - float contentTranslateY, const Rect& repaintRect, - const Vector3& lightCenter, const BeginLayerOp* beginLayerOp, - RenderNode* renderNode) { - mCanvasState.save(SaveFlags::MatrixClip); - mCanvasState.writableSnapshot()->initializeViewport(layerWidth, layerHeight); - mCanvasState.writableSnapshot()->roundRectClipState = nullptr; - mCanvasState.writableSnapshot()->setRelativeLightCenter(lightCenter); - mCanvasState.writableSnapshot()->transform->loadTranslate(contentTranslateX, contentTranslateY, - 0); - mCanvasState.writableSnapshot()->setClip(repaintRect.left, repaintRect.top, repaintRect.right, - repaintRect.bottom); - - // create a new layer repaint, and push its index on the stack - mLayerStack.push_back(mLayerBuilders.size()); - auto newFbo = mAllocator.create(layerWidth, layerHeight, repaintRect, - beginLayerOp, renderNode); - mLayerBuilders.push_back(newFbo); -} - -void FrameBuilder::restoreForLayer() { - // restore canvas, and pop finished layer off of the stack - mCanvasState.restore(); - mLayerStack.pop_back(); -} - -// TODO: defer time rejection (when bounds become empty) + tests -// Option - just skip layers with no bounds at playback + defer? -void FrameBuilder::deferBeginLayerOp(const BeginLayerOp& op) { - uint32_t layerWidth = (uint32_t)op.unmappedBounds.getWidth(); - uint32_t layerHeight = (uint32_t)op.unmappedBounds.getHeight(); - - auto previous = mCanvasState.currentSnapshot(); - Vector3 lightCenter = previous->getRelativeLightCenter(); - - // Combine all transforms used to present saveLayer content: - // parent content transform * canvas transform * bounds offset - Matrix4 contentTransform(*(previous->transform)); - contentTransform.multiply(op.localMatrix); - contentTransform.translate(op.unmappedBounds.left, op.unmappedBounds.top); - - Matrix4 inverseContentTransform; - inverseContentTransform.loadInverse(contentTransform); - - // map the light center into layer-relative space - inverseContentTransform.mapPoint3d(lightCenter); - - // Clip bounds of temporary layer to parent's clip rect, so: - Rect saveLayerBounds(layerWidth, layerHeight); - // 1) transform Rect(width, height) into parent's space - // note: left/top offsets put in contentTransform above - contentTransform.mapRect(saveLayerBounds); - // 2) intersect with parent's clip - saveLayerBounds.doIntersect(previous->getRenderTargetClip()); - // 3) and transform back - inverseContentTransform.mapRect(saveLayerBounds); - saveLayerBounds.doIntersect(Rect(layerWidth, layerHeight)); - saveLayerBounds.roundOut(); - - // if bounds are reduced, will clip the layer's area by reducing required bounds... - layerWidth = saveLayerBounds.getWidth(); - layerHeight = saveLayerBounds.getHeight(); - // ...and shifting drawing content to account for left/top side clipping - float contentTranslateX = -saveLayerBounds.left; - float contentTranslateY = -saveLayerBounds.top; - - saveForLayer(layerWidth, layerHeight, contentTranslateX, contentTranslateY, - Rect(layerWidth, layerHeight), lightCenter, &op, nullptr); -} - -void FrameBuilder::deferEndLayerOp(const EndLayerOp& /* ignored */) { - const BeginLayerOp& beginLayerOp = *currentLayer().beginLayerOp; - int finishedLayerIndex = mLayerStack.back(); - - restoreForLayer(); - - // saveLayer will clip & translate the draw contents, so we need - // to translate the drawLayer by how much the contents was translated - // TODO: Unify this with beginLayerOp so we don't have to calculate this - // twice - uint32_t layerWidth = (uint32_t)beginLayerOp.unmappedBounds.getWidth(); - uint32_t layerHeight = (uint32_t)beginLayerOp.unmappedBounds.getHeight(); - - auto previous = mCanvasState.currentSnapshot(); - Vector3 lightCenter = previous->getRelativeLightCenter(); - - // Combine all transforms used to present saveLayer content: - // parent content transform * canvas transform * bounds offset - Matrix4 contentTransform(*(previous->transform)); - contentTransform.multiply(beginLayerOp.localMatrix); - contentTransform.translate(beginLayerOp.unmappedBounds.left, beginLayerOp.unmappedBounds.top); - - Matrix4 inverseContentTransform; - inverseContentTransform.loadInverse(contentTransform); - - // map the light center into layer-relative space - inverseContentTransform.mapPoint3d(lightCenter); - - // Clip bounds of temporary layer to parent's clip rect, so: - Rect saveLayerBounds(layerWidth, layerHeight); - // 1) transform Rect(width, height) into parent's space - // note: left/top offsets put in contentTransform above - contentTransform.mapRect(saveLayerBounds); - // 2) intersect with parent's clip - saveLayerBounds.doIntersect(previous->getRenderTargetClip()); - // 3) and transform back - inverseContentTransform.mapRect(saveLayerBounds); - saveLayerBounds.doIntersect(Rect(layerWidth, layerHeight)); - saveLayerBounds.roundOut(); - - Matrix4 localMatrix(beginLayerOp.localMatrix); - localMatrix.translate(saveLayerBounds.left, saveLayerBounds.top); - - // record the draw operation into the previous layer's list of draw commands - // uses state from the associated beginLayerOp, since it has all the state needed for drawing - LayerOp* drawLayerOp = mAllocator.create_trivial( - beginLayerOp.unmappedBounds, localMatrix, beginLayerOp.localClip, beginLayerOp.paint, - &(mLayerBuilders[finishedLayerIndex]->offscreenBuffer)); - BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp); - - if (bakedOpState) { - // Layer will be drawn into parent layer (which is now current, since we popped mLayerStack) - currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Bitmap); - } else { - // Layer won't be drawn - delete its drawing batches to prevent it from doing any work - // TODO: need to prevent any render work from being done - // - create layerop earlier for reject purposes? - mLayerBuilders[finishedLayerIndex]->clear(); - return; - } -} - -void FrameBuilder::deferBeginUnclippedLayerOp(const BeginUnclippedLayerOp& op) { - Matrix4 boundsTransform(*(mCanvasState.currentSnapshot()->transform)); - boundsTransform.multiply(op.localMatrix); - - Rect dstRect(op.unmappedBounds); - boundsTransform.mapRect(dstRect); - dstRect.roundOut(); - dstRect.doIntersect(mCanvasState.currentSnapshot()->getRenderTargetClip()); - - if (dstRect.isEmpty()) { - // Unclipped layer rejected - push a null op, so next EndUnclippedLayerOp is ignored - currentLayer().activeUnclippedSaveLayers.push_back(nullptr); - } else { - // Allocate a holding position for the layer object (copyTo will produce, copyFrom will - // consume) - OffscreenBuffer** layerHandle = mAllocator.create(nullptr); - - /** - * First, defer an operation to copy out the content from the rendertarget into a layer. - */ - auto copyToOp = mAllocator.create_trivial(op, layerHandle); - BakedOpState* bakedState = BakedOpState::directConstruct( - mAllocator, &(currentLayer().repaintClip), dstRect, *copyToOp); - currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::CopyToLayer); - - /** - * Defer a clear rect, so that clears from multiple unclipped layers can be drawn - * both 1) simultaneously, and 2) as long after the copyToLayer executes as possible - */ - currentLayer().deferLayerClear(dstRect); - - /** - * And stash an operation to copy that layer back under the rendertarget until - * a balanced EndUnclippedLayerOp is seen - */ - auto copyFromOp = mAllocator.create_trivial(op, layerHandle); - bakedState = BakedOpState::directConstruct(mAllocator, &(currentLayer().repaintClip), - dstRect, *copyFromOp); - currentLayer().activeUnclippedSaveLayers.push_back(bakedState); - } -} - -void FrameBuilder::deferEndUnclippedLayerOp(const EndUnclippedLayerOp& /* ignored */) { - LOG_ALWAYS_FATAL_IF(currentLayer().activeUnclippedSaveLayers.empty(), "no layer to end!"); - - BakedOpState* copyFromLayerOp = currentLayer().activeUnclippedSaveLayers.back(); - currentLayer().activeUnclippedSaveLayers.pop_back(); - if (copyFromLayerOp) { - currentLayer().deferUnmergeableOp(mAllocator, copyFromLayerOp, OpBatchType::CopyFromLayer); - } -} - -void FrameBuilder::finishDefer() { - // DEAD CODE -} - -} // namespace uirenderer -} // namespace android diff --git a/libs/hwui/FrameBuilder.h b/libs/hwui/FrameBuilder.h deleted file mode 100644 index 974daf8a17bb..000000000000 --- a/libs/hwui/FrameBuilder.h +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (C) 2016 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. - */ - -#pragma once - -#include "BakedOpState.h" -#include "CanvasState.h" -#include "DisplayList.h" -#include "LayerBuilder.h" -#include "RecordedOp.h" -#include "utils/GLUtils.h" - -#include -#include - -struct SkRect; - -namespace android { -namespace uirenderer { - -class BakedOpState; -class LayerUpdateQueue; -class OffscreenBuffer; -class Rect; - -/** - * Processes, optimizes, and stores rendering commands from RenderNodes and - * LayerUpdateQueue, building content needed to render a frame. - * - * Resolves final drawing state for each operation (including clip, alpha and matrix), and then - * reorder and merge each op as it is resolved for drawing efficiency. Each layer of content (either - * from the LayerUpdateQueue, or temporary layers created by saveLayer operations in the - * draw stream) will create different reorder contexts, each in its own LayerBuilder. - * - * Then the prepared or 'baked' drawing commands can be issued by calling the templated - * replayBakedOps() function, which will dispatch them (including any created merged op collections) - * to a Dispatcher and Renderer. See BakedOpDispatcher for how these baked drawing operations are - * resolved into Glops and rendered via BakedOpRenderer. - * - * This class is also the authoritative source for traversing RenderNodes, both for standard op - * traversal within a DisplayList, and for out of order RenderNode traversal for Z and projection. - */ -class FrameBuilder : public CanvasStateClient { -public: - struct LightGeometry { - Vector3 center; - float radius; - }; - - FrameBuilder(const SkRect& clip, uint32_t viewportWidth, uint32_t viewportHeight, - const LightGeometry& lightGeometry, Caches& caches); - - FrameBuilder(const LayerUpdateQueue& layerUpdateQueue, const LightGeometry& lightGeometry, - Caches& caches); - - void deferLayers(const LayerUpdateQueue& layers); - - void deferRenderNode(RenderNode& renderNode); - - void deferRenderNode(float tx, float ty, Rect clipRect, RenderNode& renderNode); - - void deferRenderNodeScene(const std::vector >& nodes, - const Rect& contentDrawBounds); - - virtual ~FrameBuilder() {} - - /** - * replayBakedOps() is templated based on what class will receive ops being replayed. - * - * It constructs a lookup array of lambdas, which allows a recorded BakeOpState to use - * state->op->opId to lookup a receiver that will be called when the op is replayed. - */ - template - void replayBakedOps(Renderer& renderer) { - std::vector temporaryLayers; - finishDefer(); -/** - * Defines a LUT of lambdas which allow a recorded BakedOpState to use state->op->opId to - * dispatch the op via a method on a static dispatcher when the op is replayed. - * - * For example a BitmapOp would resolve, via the lambda lookup, to calling: - * - * StaticDispatcher::onBitmapOp(Renderer& renderer, const BitmapOp& op, const BakedOpState& state); - */ -#define X(Type) \ - [](void* renderer, const BakedOpState& state) { \ - StaticDispatcher::on##Type(*(static_cast(renderer)), \ - static_cast(*(state.op)), state); \ - }, - static BakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(X); -#undef X - -/** - * Defines a LUT of lambdas which allow merged arrays of BakedOpState* to be passed to a - * static dispatcher when the group of merged ops is replayed. - */ -#define X(Type) \ - [](void* renderer, const MergedBakedOpList& opList) { \ - StaticDispatcher::onMerged##Type##s(*(static_cast(renderer)), opList); \ - }, - static MergedOpReceiver mergedReceivers[] = BUILD_MERGEABLE_OP_LUT(X); -#undef X - - // Relay through layers in reverse order, since layers - // later in the list will be drawn by earlier ones - for (int i = mLayerBuilders.size() - 1; i >= 1; i--) { - GL_CHECKPOINT(MODERATE); - LayerBuilder& layer = *(mLayerBuilders[i]); - if (layer.renderNode) { - // cached HW layer - can't skip layer if empty - renderer.startRepaintLayer(layer.offscreenBuffer, layer.repaintRect); - GL_CHECKPOINT(MODERATE); - layer.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers); - GL_CHECKPOINT(MODERATE); - renderer.endLayer(); - } else if (!layer.empty()) { - // save layer - skip entire layer if empty (in which case, LayerOp has null layer). - layer.offscreenBuffer = renderer.startTemporaryLayer(layer.width, layer.height); - temporaryLayers.push_back(layer.offscreenBuffer); - GL_CHECKPOINT(MODERATE); - layer.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers); - GL_CHECKPOINT(MODERATE); - renderer.endLayer(); - } - } - - GL_CHECKPOINT(MODERATE); - if (CC_LIKELY(mDrawFbo0)) { - const LayerBuilder& fbo0 = *(mLayerBuilders[0]); - renderer.startFrame(fbo0.width, fbo0.height, fbo0.repaintRect); - GL_CHECKPOINT(MODERATE); - fbo0.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers); - GL_CHECKPOINT(MODERATE); - renderer.endFrame(fbo0.repaintRect); - } - - for (auto& temporaryLayer : temporaryLayers) { - renderer.recycleTemporaryLayer(temporaryLayer); - } - } - - void dump() const { - for (auto&& layer : mLayerBuilders) { - layer->dump(); - } - } - - /////////////////////////////////////////////////////////////////// - /// CanvasStateClient interface - /////////////////////////////////////////////////////////////////// - virtual void onViewportInitialized() override; - virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) override; - virtual GLuint getTargetFbo() const override { return 0; } - -private: - void finishDefer(); - enum class ChildrenSelectMode { Negative, Positive }; - void saveForLayer(uint32_t layerWidth, uint32_t layerHeight, float contentTranslateX, - float contentTranslateY, const Rect& repaintRect, const Vector3& lightCenter, - const BeginLayerOp* beginLayerOp, RenderNode* renderNode); - void restoreForLayer(); - - LayerBuilder& currentLayer() { return *(mLayerBuilders[mLayerStack.back()]); } - - BakedOpState* tryBakeOpState(const RecordedOp& recordedOp) { - return BakedOpState::tryConstruct(mAllocator, *mCanvasState.writableSnapshot(), recordedOp); - } - BakedOpState* tryBakeUnboundedOpState(const RecordedOp& recordedOp) { - return BakedOpState::tryConstructUnbounded(mAllocator, *mCanvasState.writableSnapshot(), - recordedOp); - } - - // should always be surrounded by a save/restore pair, and not called if DisplayList is null - void deferNodePropsAndOps(RenderNode& node); - - template - void defer3dChildren(const ClipBase* reorderClip, ChildrenSelectMode mode, - const V& zTranslatedNodes); - - void deferShadow(const ClipBase* reorderClip, const RenderNodeOp& casterOp); - - void deferProjectedChildren(const RenderNode& renderNode); - - void deferNodeOps(const RenderNode& renderNode); - - void deferRenderNodeOpImpl(const RenderNodeOp& op); - - void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers); - - SkPath* createFrameAllocatedPath() { return mAllocator.create(); } - - BakedOpState* deferStrokeableOp(const RecordedOp& op, batchid_t batchId, - BakedOpState::StrokeBehavior strokeBehavior = - BakedOpState::StrokeBehavior::StyleDefined, - bool expandForPathTexture = false); - -/** - * Declares all FrameBuilder::deferXXXXOp() methods for every RecordedOp type. - * - * These private methods are called from within deferImpl to defer each individual op - * type differently. - */ -#define X(Type) void defer##Type(const Type& op); - MAP_DEFERRABLE_OPS(X) -#undef X - - // contains single-frame objects, such as BakedOpStates, LayerBuilders, Batches - LinearAllocator mAllocator; - LinearStdAllocator mStdAllocator; - - // List of every deferred layer's render state. Replayed in reverse order to render a frame. - LsaVector mLayerBuilders; - - /* - * Stack of indices within mLayerBuilders representing currently active layers. If drawing - * layerA within a layerB, will contain, in order: - * - 0 (representing FBO 0, always present) - * - layerB's index - * - layerA's index - * - * Note that this doesn't vector doesn't always map onto all values of mLayerBuilders. When a - * layer is finished deferring, it will still be represented in mLayerBuilders, but it's index - * won't be in mLayerStack. This is because it can be replayed, but can't have any more drawing - * ops added to it. - */ - LsaVector mLayerStack; - - CanvasState mCanvasState; - - Caches& mCaches; - - float mLightRadius; - - const bool mDrawFbo0; -}; - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/Lighting.h b/libs/hwui/Lighting.h new file mode 100644 index 000000000000..d972c2181aea --- /dev/null +++ b/libs/hwui/Lighting.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "Vector.h" + +namespace android { +namespace uirenderer { + +struct LightGeometry { + Vector3 center; + float radius; +}; + +struct LightInfo { + LightInfo() : LightInfo(0, 0) {} + LightInfo(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) + : ambientShadowAlpha(ambientShadowAlpha), spotShadowAlpha(spotShadowAlpha) {} + uint8_t ambientShadowAlpha; + uint8_t spotShadowAlpha; +}; + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp deleted file mode 100644 index e1df1e7725b5..000000000000 --- a/libs/hwui/RecordingCanvas.cpp +++ /dev/null @@ -1,631 +0,0 @@ -/* - * Copyright (C) 2015 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 "RecordingCanvas.h" - -#include "DeferredLayerUpdater.h" -#include "RecordedOp.h" -#include "RenderNode.h" -#include "VectorDrawable.h" -#include "hwui/MinikinUtils.h" - -namespace android { -namespace uirenderer { - -RecordingCanvas::RecordingCanvas(size_t width, size_t height) - : mState(*this), mResourceCache(ResourceCache::getInstance()) { - resetRecording(width, height); -} - -RecordingCanvas::~RecordingCanvas() { - LOG_ALWAYS_FATAL_IF(mDisplayList, "Destroyed a RecordingCanvas during a record!"); -} - -void RecordingCanvas::resetRecording(int width, int height, RenderNode* node) { - LOG_ALWAYS_FATAL_IF(mDisplayList, "prepareDirty called a second time during a recording!"); - mDisplayList = new DisplayList(); - - mState.initializeRecordingSaveStack(width, height); - - mDeferredBarrierType = DeferredBarrierType::InOrder; -} - -DisplayList* RecordingCanvas::finishRecording() { - restoreToCount(1); - mPaintMap.clear(); - mRegionMap.clear(); - mPathMap.clear(); - DisplayList* displayList = mDisplayList; - mDisplayList = nullptr; - mSkiaCanvasProxy.reset(nullptr); - return displayList; -} - -void RecordingCanvas::insertReorderBarrier(bool enableReorder) { - if (enableReorder) { - mDeferredBarrierType = DeferredBarrierType::OutOfOrder; - mDeferredBarrierClip = getRecordedClip(); - } else { - mDeferredBarrierType = DeferredBarrierType::InOrder; - mDeferredBarrierClip = nullptr; - } -} - -SkCanvas* RecordingCanvas::asSkCanvas() { - LOG_ALWAYS_FATAL_IF(!mDisplayList, "attempting to get an SkCanvas when we are not recording!"); - if (!mSkiaCanvasProxy) { - mSkiaCanvasProxy.reset(new SkiaCanvasProxy(this)); - } - - // SkCanvas instances default to identity transform, but should inherit - // the state of this Canvas; if this code was in the SkiaCanvasProxy - // constructor, we couldn't cache mSkiaCanvasProxy. - SkMatrix parentTransform; - getMatrix(&parentTransform); - mSkiaCanvasProxy.get()->setMatrix(parentTransform); - - return mSkiaCanvasProxy.get(); -} - -// ---------------------------------------------------------------------------- -// CanvasStateClient implementation -// ---------------------------------------------------------------------------- - -void RecordingCanvas::onViewportInitialized() {} - -void RecordingCanvas::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) { - if (removed.flags & Snapshot::kFlagIsFboLayer) { - addOp(alloc().create_trivial()); - } else if (removed.flags & Snapshot::kFlagIsLayer) { - addOp(alloc().create_trivial()); - } -} - -// ---------------------------------------------------------------------------- -// android/graphics/Canvas state operations -// ---------------------------------------------------------------------------- -// Save (layer) -int RecordingCanvas::save(SaveFlags::Flags flags) { - return mState.save((int)flags); -} - -void RecordingCanvas::RecordingCanvas::restore() { - mState.restore(); -} - -void RecordingCanvas::restoreToCount(int saveCount) { - mState.restoreToCount(saveCount); -} - -int RecordingCanvas::saveLayer(float left, float top, float right, float bottom, - const SkPaint* paint, SaveFlags::Flags flags) { - // force matrix/clip isolation for layer - flags |= SaveFlags::MatrixClip; - bool clippedLayer = flags & SaveFlags::ClipToLayer; - - const Snapshot& previous = *mState.currentSnapshot(); - - // 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) - - Rect unmappedBounds(left, top, right, bottom); - unmappedBounds.roundOut(); - - // determine clipped bounds relative to previous viewport. - Rect visibleBounds = unmappedBounds; - previous.transform->mapRect(visibleBounds); - - if (CC_UNLIKELY(!clippedLayer && previous.transform->rectToRect() && - visibleBounds.contains(previous.getRenderTargetClip()))) { - // unlikely case where an unclipped savelayer is recorded with a clip it can use, - // as none of its unaffected/unclipped area is visible - clippedLayer = true; - flags |= SaveFlags::ClipToLayer; - } - - visibleBounds.doIntersect(previous.getRenderTargetClip()); - visibleBounds.snapToPixelBoundaries(); - visibleBounds.doIntersect(Rect(previous.getViewportWidth(), previous.getViewportHeight())); - - // Map visible bounds back to layer space, and intersect with parameter bounds - Rect layerBounds = visibleBounds; - if (CC_LIKELY(!layerBounds.isEmpty())) { - // if non-empty, can safely map by the inverse transform - Matrix4 inverse; - inverse.loadInverse(*previous.transform); - inverse.mapRect(layerBounds); - layerBounds.doIntersect(unmappedBounds); - } - - int saveValue = mState.save((int)flags); - Snapshot& snapshot = *mState.writableSnapshot(); - - // layerBounds is in original bounds space, but clipped by current recording clip - if (!layerBounds.isEmpty() && !unmappedBounds.isEmpty()) { - if (CC_LIKELY(clippedLayer)) { - auto previousClip = getRecordedClip(); // capture before new snapshot clip has changed - if (addOp(alloc().create_trivial( - unmappedBounds, - *previous.transform, // transform to *draw* with - previousClip, // clip to *draw* with - refPaint(paint))) >= 0) { - snapshot.flags |= Snapshot::kFlagIsLayer | Snapshot::kFlagIsFboLayer; - snapshot.initializeViewport(unmappedBounds.getWidth(), unmappedBounds.getHeight()); - snapshot.transform->loadTranslate(-unmappedBounds.left, -unmappedBounds.top, 0.0f); - - Rect clip = layerBounds; - clip.translate(-unmappedBounds.left, -unmappedBounds.top); - snapshot.resetClip(clip.left, clip.top, clip.right, clip.bottom); - snapshot.roundRectClipState = nullptr; - return saveValue; - } - } else { - if (addOp(alloc().create_trivial( - unmappedBounds, *mState.currentSnapshot()->transform, getRecordedClip(), - refPaint(paint))) >= 0) { - snapshot.flags |= Snapshot::kFlagIsLayer; - return saveValue; - } - } - } - - // Layer not needed, so skip recording it... - if (CC_LIKELY(clippedLayer)) { - // ... and set empty clip to reject inner content, if possible - snapshot.resetClip(0, 0, 0, 0); - } - return saveValue; -} - -// Matrix -void RecordingCanvas::rotate(float degrees) { - if (degrees == 0) return; - - mState.rotate(degrees); -} - -void RecordingCanvas::scale(float sx, float sy) { - if (sx == 1 && sy == 1) return; - - mState.scale(sx, sy); -} - -void RecordingCanvas::skew(float sx, float sy) { - mState.skew(sx, sy); -} - -void RecordingCanvas::translate(float dx, float dy) { - if (dx == 0 && dy == 0) return; - - mState.translate(dx, dy, 0); -} - -// Clip -bool RecordingCanvas::getClipBounds(SkRect* outRect) const { - *outRect = mState.getLocalClipBounds().toSkRect(); - return !(outRect->isEmpty()); -} -bool RecordingCanvas::quickRejectRect(float left, float top, float right, float bottom) const { - return mState.quickRejectConservative(left, top, right, bottom); -} -bool RecordingCanvas::quickRejectPath(const SkPath& path) const { - SkRect bounds = path.getBounds(); - return mState.quickRejectConservative(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom); -} -bool RecordingCanvas::clipRect(float left, float top, float right, float bottom, SkClipOp op) { - return mState.clipRect(left, top, right, bottom, op); -} -bool RecordingCanvas::clipPath(const SkPath* path, SkClipOp op) { - return mState.clipPath(path, op); -} - -// ---------------------------------------------------------------------------- -// android/graphics/Canvas draw operations -// ---------------------------------------------------------------------------- -void RecordingCanvas::drawColor(int color, SkBlendMode mode) { - addOp(alloc().create_trivial(getRecordedClip(), color, mode)); -} - -void RecordingCanvas::drawPaint(const SkPaint& paint) { - SkRect bounds; - if (getClipBounds(&bounds)) { - drawRect(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, paint); - } -} - -static Rect calcBoundsOfPoints(const float* points, int floatCount) { - Rect unmappedBounds(points[0], points[1], points[0], points[1]); - for (int i = 2; i < floatCount; i += 2) { - unmappedBounds.expandToCover(points[i], points[i + 1]); - } - return unmappedBounds; -} - -// Geometry -void RecordingCanvas::drawPoints(const float* points, int floatCount, const SkPaint& paint) { - if (CC_UNLIKELY(floatCount < 2 || paint.nothingToDraw())) return; - floatCount &= ~0x1; // round down to nearest two - - addOp(alloc().create_trivial( - calcBoundsOfPoints(points, floatCount), *mState.currentSnapshot()->transform, - getRecordedClip(), refPaint(&paint), refBuffer(points, floatCount), floatCount)); -} - -void RecordingCanvas::drawLines(const float* points, int floatCount, const SkPaint& paint) { - if (CC_UNLIKELY(floatCount < 4 || paint.nothingToDraw())) return; - floatCount &= ~0x3; // round down to nearest four - - addOp(alloc().create_trivial( - calcBoundsOfPoints(points, floatCount), *mState.currentSnapshot()->transform, - getRecordedClip(), refPaint(&paint), refBuffer(points, floatCount), floatCount)); -} - -void RecordingCanvas::drawRect(float left, float top, float right, float bottom, - const SkPaint& paint) { - if (CC_UNLIKELY(paint.nothingToDraw())) return; - - addOp(alloc().create_trivial(Rect(left, top, right, bottom), - *(mState.currentSnapshot()->transform), getRecordedClip(), - refPaint(&paint))); -} - -void RecordingCanvas::drawSimpleRects(const float* rects, int vertexCount, const SkPaint* paint) { - if (rects == nullptr) return; - - Vertex* rectData = (Vertex*)mDisplayList->allocator.create_trivial_array(vertexCount); - Vertex* vertex = rectData; - - float left = FLT_MAX; - float top = FLT_MAX; - float right = FLT_MIN; - float bottom = FLT_MIN; - for (int index = 0; index < vertexCount; index += 4) { - float l = rects[index + 0]; - float t = rects[index + 1]; - float r = rects[index + 2]; - float b = rects[index + 3]; - - Vertex::set(vertex++, l, t); - Vertex::set(vertex++, r, t); - Vertex::set(vertex++, l, b); - Vertex::set(vertex++, r, b); - - left = std::min(left, l); - top = std::min(top, t); - right = std::max(right, r); - bottom = std::max(bottom, b); - } - addOp(alloc().create_trivial( - Rect(left, top, right, bottom), *(mState.currentSnapshot()->transform), - getRecordedClip(), refPaint(paint), rectData, vertexCount)); -} - -void RecordingCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) { - if (CC_UNLIKELY(paint.nothingToDraw())) return; - - if (paint.getStyle() == SkPaint::kFill_Style && - (!paint.isAntiAlias() || mState.currentTransform()->isSimple())) { - int count = 0; - Vector rects; - SkRegion::Iterator it(region); - while (!it.done()) { - const SkIRect& r = it.rect(); - rects.push(r.fLeft); - rects.push(r.fTop); - rects.push(r.fRight); - rects.push(r.fBottom); - count += 4; - it.next(); - } - drawSimpleRects(rects.array(), count, &paint); - } else { - SkRegion::Iterator it(region); - while (!it.done()) { - const SkIRect& r = it.rect(); - drawRect(r.fLeft, r.fTop, r.fRight, r.fBottom, paint); - it.next(); - } - } -} - -void RecordingCanvas::drawRoundRect(float left, float top, float right, float bottom, float rx, - float ry, const SkPaint& paint) { - if (CC_UNLIKELY(paint.nothingToDraw())) return; - - if (CC_LIKELY(MathUtils::isPositive(rx) || MathUtils::isPositive(ry))) { - addOp(alloc().create_trivial(Rect(left, top, right, bottom), - *(mState.currentSnapshot()->transform), - getRecordedClip(), refPaint(&paint), rx, ry)); - } else { - drawRect(left, top, right, bottom, paint); - } -} - -void RecordingCanvas::drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top, - CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom, - CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry, - CanvasPropertyPaint* paint) { - mDisplayList->ref(left); - mDisplayList->ref(top); - mDisplayList->ref(right); - mDisplayList->ref(bottom); - mDisplayList->ref(rx); - mDisplayList->ref(ry); - mDisplayList->ref(paint); - refBitmapsInShader(paint->value.getShader()); - addOp(alloc().create_trivial( - *(mState.currentSnapshot()->transform), getRecordedClip(), &paint->value, &left->value, - &top->value, &right->value, &bottom->value, &rx->value, &ry->value)); -} - -void RecordingCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) { - // TODO: move to Canvas.h - if (CC_UNLIKELY(radius <= 0 || paint.nothingToDraw())) return; - - drawOval(x - radius, y - radius, x + radius, y + radius, paint); -} - -void RecordingCanvas::drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y, - CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) { - mDisplayList->ref(x); - mDisplayList->ref(y); - mDisplayList->ref(radius); - mDisplayList->ref(paint); - refBitmapsInShader(paint->value.getShader()); - addOp(alloc().create_trivial(*(mState.currentSnapshot()->transform), - getRecordedClip(), &paint->value, &x->value, - &y->value, &radius->value)); -} - -void RecordingCanvas::drawOval(float left, float top, float right, float bottom, - const SkPaint& paint) { - if (CC_UNLIKELY(paint.nothingToDraw())) return; - - addOp(alloc().create_trivial(Rect(left, top, right, bottom), - *(mState.currentSnapshot()->transform), getRecordedClip(), - refPaint(&paint))); -} - -void RecordingCanvas::drawArc(float left, float top, float right, float bottom, float startAngle, - float sweepAngle, bool useCenter, const SkPaint& paint) { - if (CC_UNLIKELY(paint.nothingToDraw())) return; - - if (fabs(sweepAngle) >= 360.0f) { - drawOval(left, top, right, bottom, paint); - } else { - addOp(alloc().create_trivial( - Rect(left, top, right, bottom), *(mState.currentSnapshot()->transform), - getRecordedClip(), refPaint(&paint), startAngle, sweepAngle, useCenter)); - } -} - -void RecordingCanvas::drawPath(const SkPath& path, const SkPaint& paint) { - if (CC_UNLIKELY(paint.nothingToDraw())) return; - - addOp(alloc().create_trivial(Rect(path.getBounds()), - *(mState.currentSnapshot()->transform), getRecordedClip(), - refPaint(&paint), refPath(&path))); -} - -void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) { - mDisplayList->ref(tree); - mDisplayList->vectorDrawables.push_back(tree); - addOp(alloc().create_trivial( - tree, Rect(tree->stagingProperties()->getBounds()), - *(mState.currentSnapshot()->transform), getRecordedClip())); -} - -// Bitmap-based -void RecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) { - save(SaveFlags::Matrix); - translate(left, top); - drawBitmap(bitmap, paint); - restore(); -} - -void RecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) { - if (matrix.isIdentity()) { - drawBitmap(bitmap, paint); - } else if (!(matrix.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) && - MathUtils::isPositive(matrix.getScaleX()) && - MathUtils::isPositive(matrix.getScaleY())) { - // SkMatrix::isScaleTranslate() not available in L - SkRect src; - SkRect dst; - bitmap.getBounds(&src); - matrix.mapRect(&dst, src); - drawBitmap(bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom, dst.fLeft, dst.fTop, - dst.fRight, dst.fBottom, paint); - } else { - save(SaveFlags::Matrix); - concat(matrix); - drawBitmap(bitmap, paint); - restore(); - } -} - -void RecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight, - float srcBottom, float dstLeft, float dstTop, float dstRight, - float dstBottom, const SkPaint* paint) { - if (srcLeft == 0 && srcTop == 0 && srcRight == bitmap.width() && srcBottom == bitmap.height() && - (srcBottom - srcTop == dstBottom - dstTop) && (srcRight - srcLeft == dstRight - dstLeft)) { - // transform simple rect to rect drawing case into position bitmap ops, since they merge - save(SaveFlags::Matrix); - translate(dstLeft, dstTop); - drawBitmap(bitmap, paint); - restore(); - } else { - addOp(alloc().create_trivial( - Rect(dstLeft, dstTop, dstRight, dstBottom), *(mState.currentSnapshot()->transform), - getRecordedClip(), refPaint(paint), refBitmap(bitmap), - Rect(srcLeft, srcTop, srcRight, srcBottom))); - } -} - -void RecordingCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight, - const float* vertices, const int* colors, - const SkPaint* paint) { - int vertexCount = (meshWidth + 1) * (meshHeight + 1); - addOp(alloc().create_trivial( - calcBoundsOfPoints(vertices, vertexCount * 2), *(mState.currentSnapshot()->transform), - getRecordedClip(), refPaint(paint), refBitmap(bitmap), meshWidth, meshHeight, - refBuffer(vertices, vertexCount * 2), // 2 floats per vertex - refBuffer(colors, vertexCount))); // 1 color per vertex -} - -void RecordingCanvas::drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& patch, - float dstLeft, float dstTop, float dstRight, float dstBottom, - const SkPaint* paint) { - addOp(alloc().create_trivial(Rect(dstLeft, dstTop, dstRight, dstBottom), - *(mState.currentSnapshot()->transform), getRecordedClip(), - refPaint(paint), refBitmap(bitmap), refPatch(&patch))); -} - -double RecordingCanvas::drawAnimatedImage(AnimatedImageDrawable*) { - // Unimplemented - return 0; -} - -// Text -void RecordingCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int glyphCount, const SkPaint& paint, - float x, float y, float boundsLeft, float boundsTop, - float boundsRight, float boundsBottom, float totalAdvance) { - if (glyphCount <= 0 || paint.nothingToDraw()) return; - uint16_t* glyphs = (glyph_t*)alloc().alloc(glyphCount * sizeof(glyph_t)); - float* positions = (float*)alloc().alloc(2 * glyphCount * sizeof(float)); - glyphFunc(glyphs, positions); - - // TODO: either must account for text shadow in bounds, or record separate ops for text shadows - addOp(alloc().create_trivial(Rect(boundsLeft, boundsTop, boundsRight, boundsBottom), - *(mState.currentSnapshot()->transform), getRecordedClip(), - refPaint(&paint), glyphs, positions, glyphCount, x, y)); - drawTextDecorations(x, y, totalAdvance, paint); -} - -void RecordingCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset, - const SkPaint& paint, const SkPath& path, size_t start, - size_t end) { - uint16_t glyphs[1]; - for (size_t i = start; i < end; i++) { - glyphs[0] = layout.getGlyphId(i); - float x = hOffset + layout.getX(i); - float y = vOffset + layout.getY(i); - if (paint.nothingToDraw()) return; - const uint16_t* tempGlyphs = refBuffer(glyphs, 1); - addOp(alloc().create_trivial(*(mState.currentSnapshot()->transform), - getRecordedClip(), refPaint(&paint), tempGlyphs, - 1, refPath(&path), x, y)); - } -} - -void RecordingCanvas::drawBitmap(Bitmap& bitmap, const SkPaint* paint) { - addOp(alloc().create_trivial(Rect(bitmap.width(), bitmap.height()), - *(mState.currentSnapshot()->transform), - getRecordedClip(), refPaint(paint), refBitmap(bitmap))); -} - -void RecordingCanvas::drawRenderNode(RenderNode* renderNode) { - auto&& stagingProps = renderNode->stagingProperties(); - RenderNodeOp* op = alloc().create_trivial( - Rect(stagingProps.getWidth(), stagingProps.getHeight()), - *(mState.currentSnapshot()->transform), getRecordedClip(), renderNode); - int opIndex = addOp(op); - if (CC_LIKELY(opIndex >= 0)) { - int childIndex = mDisplayList->addChild(op); - - // update the chunk's child indices - DisplayList::Chunk& chunk = mDisplayList->chunks.back(); - chunk.endChildIndex = childIndex + 1; - - if (renderNode->stagingProperties().isProjectionReceiver()) { - // use staging property, since recording on UI thread - mDisplayList->projectionReceiveIndex = opIndex; - } - } -} - -void RecordingCanvas::drawLayer(DeferredLayerUpdater* layerHandle) { - // We ref the DeferredLayerUpdater due to its thread-safe ref-counting semantics. - mDisplayList->ref(layerHandle); - - LOG_ALWAYS_FATAL_IF(layerHandle->getBackingLayerApi() != Layer::Api::OpenGL); - // Note that the backing layer has *not* yet been updated, so don't trust - // its width, height, transform, etc...! - addOp(alloc().create_trivial( - Rect(layerHandle->getWidth(), layerHandle->getHeight()), - *(mState.currentSnapshot()->transform), getRecordedClip(), layerHandle)); -} - -void RecordingCanvas::callDrawGLFunction(Functor* functor, GlFunctorLifecycleListener* listener) { - mDisplayList->functors.push_back({functor, listener}); - mDisplayList->ref(listener); - addOp(alloc().create_trivial(*(mState.currentSnapshot()->transform), - getRecordedClip(), functor)); -} - -int RecordingCanvas::addOp(RecordedOp* op) { - // skip op with empty clip - if (op->localClip && op->localClip->rect.isEmpty()) { - // NOTE: this rejection happens after op construction/content ref-ing, so content ref'd - // and held by renderthread isn't affected by clip rejection. - // Could rewind alloc here if desired, but callers would have to not touch op afterwards. - return -1; - } - - int insertIndex = mDisplayList->ops.size(); - mDisplayList->ops.push_back(op); - if (mDeferredBarrierType != DeferredBarrierType::None) { - // op is first in new chunk - mDisplayList->chunks.emplace_back(); - DisplayList::Chunk& newChunk = mDisplayList->chunks.back(); - newChunk.beginOpIndex = insertIndex; - newChunk.endOpIndex = insertIndex + 1; - newChunk.reorderChildren = (mDeferredBarrierType == DeferredBarrierType::OutOfOrder); - newChunk.reorderClip = mDeferredBarrierClip; - - int nextChildIndex = mDisplayList->children.size(); - newChunk.beginChildIndex = newChunk.endChildIndex = nextChildIndex; - mDeferredBarrierType = DeferredBarrierType::None; - } else { - // standard case - append to existing chunk - mDisplayList->chunks.back().endOpIndex = insertIndex + 1; - } - return insertIndex; -} - -void RecordingCanvas::refBitmapsInShader(const SkShader* shader) { - if (!shader) return; - - // If this paint has an SkShader that has an SkBitmap add - // it to the bitmap pile - SkBitmap bitmap; - SkShader::TileMode xy[2]; - if (shader->isABitmap(&bitmap, nullptr, xy)) { - Bitmap* hwuiBitmap = static_cast(bitmap.pixelRef()); - refBitmap(*hwuiBitmap); - return; - } - SkShader::ComposeRec rec; - if (shader->asACompose(&rec)) { - refBitmapsInShader(rec.fShaderA); - refBitmapsInShader(rec.fShaderB); - return; - } -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h deleted file mode 100644 index e663402a80f3..000000000000 --- a/libs/hwui/RecordingCanvas.h +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (C) 2015 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_RECORDING_CANVAS_H -#define ANDROID_HWUI_RECORDING_CANVAS_H - -#include "CanvasState.h" -#include "DisplayList.h" -#include "ResourceCache.h" -#include "SkiaCanvasProxy.h" -#include "Snapshot.h" -#include "hwui/Bitmap.h" -#include "hwui/Canvas.h" -#include "utils/LinearAllocator.h" -#include "utils/Macros.h" - -#include -#include -#include - -#include - -namespace android { -namespace uirenderer { - -struct ClipBase; -class DeferredLayerUpdater; -struct RecordedOp; - -class ANDROID_API RecordingCanvas : public Canvas, public CanvasStateClient { - enum class DeferredBarrierType { - None, - InOrder, - OutOfOrder, - }; - -public: - RecordingCanvas(size_t width, size_t height); - virtual ~RecordingCanvas(); - - virtual void resetRecording(int width, int height, RenderNode* node = nullptr) override; - virtual WARN_UNUSED_RESULT DisplayList* finishRecording() override; - // ---------------------------------------------------------------------------- - // MISC HWUI OPERATIONS - TODO: CATEGORIZE - // ---------------------------------------------------------------------------- - virtual void insertReorderBarrier(bool enableReorder) override; - - virtual void drawLayer(DeferredLayerUpdater* layerHandle) override; - virtual void drawRenderNode(RenderNode* renderNode) override; - virtual void callDrawGLFunction(Functor* functor, - GlFunctorLifecycleListener* listener) override; - - // ---------------------------------------------------------------------------- - // CanvasStateClient interface - // ---------------------------------------------------------------------------- - virtual void onViewportInitialized() override; - virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) override; - virtual GLuint getTargetFbo() const override { return -1; } - - // ---------------------------------------------------------------------------- - // HWUI Canvas draw operations - // ---------------------------------------------------------------------------- - - virtual void drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top, - CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom, - CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry, - CanvasPropertyPaint* paint) override; - virtual void drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y, - CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) override; - - // ---------------------------------------------------------------------------- - // android/graphics/Canvas interface - // ---------------------------------------------------------------------------- - virtual SkCanvas* asSkCanvas() override; - - virtual void setBitmap(const SkBitmap& bitmap) override { - LOG_ALWAYS_FATAL("RecordingCanvas is not backed by a bitmap."); - } - - virtual bool isOpaque() override { return false; } - virtual int width() override { return mState.getWidth(); } - virtual int height() override { return mState.getHeight(); } - - // ---------------------------------------------------------------------------- - // android/graphics/Canvas state operations - // ---------------------------------------------------------------------------- - // Save (layer) - virtual int getSaveCount() const override { return mState.getSaveCount(); } - virtual int save(SaveFlags::Flags flags) override; - virtual void restore() override; - virtual void restoreToCount(int saveCount) override; - - virtual int saveLayer(float left, float top, float right, float bottom, const SkPaint* paint, - SaveFlags::Flags flags) override; - virtual int saveLayerAlpha(float left, float top, float right, float bottom, int alpha, - SaveFlags::Flags flags) override { - SkPaint paint; - paint.setAlpha(alpha); - return saveLayer(left, top, right, bottom, &paint, flags); - } - - // Matrix - virtual void getMatrix(SkMatrix* outMatrix) const override { mState.getMatrix(outMatrix); } - virtual void setMatrix(const SkMatrix& matrix) override { mState.setMatrix(matrix); } - - virtual void concat(const SkMatrix& matrix) override { mState.concatMatrix(matrix); } - virtual void rotate(float degrees) override; - virtual void scale(float sx, float sy) override; - virtual void skew(float sx, float sy) override; - virtual void translate(float dx, float dy) override; - - // Clip - virtual bool getClipBounds(SkRect* outRect) const override; - virtual bool quickRejectRect(float left, float top, float right, float bottom) const override; - virtual bool quickRejectPath(const SkPath& path) const override; - - virtual bool clipRect(float left, float top, float right, float bottom, SkClipOp op) override; - virtual bool clipPath(const SkPath* path, SkClipOp op) override; - - // Misc - virtual SkDrawFilter* getDrawFilter() override { return mDrawFilter.get(); } - virtual void setDrawFilter(SkDrawFilter* filter) override { - mDrawFilter.reset(SkSafeRef(filter)); - } - - // ---------------------------------------------------------------------------- - // android/graphics/Canvas draw operations - // ---------------------------------------------------------------------------- - virtual void drawColor(int color, SkBlendMode mode) override; - virtual void drawPaint(const SkPaint& paint) override; - - // Geometry - virtual void drawPoint(float x, float y, const SkPaint& paint) override { - float points[2] = {x, y}; - drawPoints(points, 2, paint); - } - virtual void drawPoints(const float* points, int floatCount, const SkPaint& paint) override; - virtual void drawLine(float startX, float startY, float stopX, float stopY, - const SkPaint& paint) override { - float points[4] = {startX, startY, stopX, stopY}; - drawLines(points, 4, paint); - } - virtual void drawLines(const float* points, int floatCount, const SkPaint& paint) override; - virtual void drawRect(float left, float top, float right, float bottom, - const SkPaint& paint) override; - virtual void drawRegion(const SkRegion& region, const SkPaint& paint) override; - virtual void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, - const SkPaint& paint) override; - virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) override; - virtual void drawOval(float left, float top, float right, float bottom, - const SkPaint& paint) override; - virtual void drawArc(float left, float top, float right, float bottom, float startAngle, - float sweepAngle, bool useCenter, const SkPaint& paint) override; - virtual void drawPath(const SkPath& path, const SkPaint& paint) override; - virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint& paint) - override { /* RecordingCanvas does not support drawVertices(); ignore */ - } - - virtual void drawVectorDrawable(VectorDrawableRoot* tree) override; - - // Bitmap-based - virtual void drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) override; - virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) override; - virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight, - float srcBottom, float dstLeft, float dstTop, float dstRight, - float dstBottom, const SkPaint* paint) override; - virtual void drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight, - const float* vertices, const int* colors, - const SkPaint* paint) override; - virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft, - float dstTop, float dstRight, float dstBottom, - const SkPaint* paint) override; - virtual double drawAnimatedImage(AnimatedImageDrawable*) override; - - // Text - virtual bool drawTextAbsolutePos() const override { return false; } - -protected: - virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& paint, float x, - float y, float boundsLeft, float boundsTop, float boundsRight, - float boundsBottom, float totalAdvance) override; - virtual void drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset, - const SkPaint& paint, const SkPath& path, size_t start, - size_t end) override; - -private: - const ClipBase* getRecordedClip() { - return mState.writableSnapshot()->mutateClipArea().serializeClip(alloc()); - } - - void drawBitmap(Bitmap& bitmap, const SkPaint* paint); - void drawSimpleRects(const float* rects, int vertexCount, const SkPaint* paint); - - int addOp(RecordedOp* op); - // ---------------------------------------------------------------------------- - // lazy object copy - // ---------------------------------------------------------------------------- - LinearAllocator& alloc() { return mDisplayList->allocator; } - - void refBitmapsInShader(const SkShader* shader); - - template - inline const T* refBuffer(const T* srcBuffer, int32_t count) { - if (!srcBuffer) return nullptr; - - T* dstBuffer = (T*)mDisplayList->allocator.alloc(count * sizeof(T)); - memcpy(dstBuffer, srcBuffer, count * sizeof(T)); - return dstBuffer; - } - - inline const SkPath* refPath(const SkPath* path) { - if (!path) return nullptr; - - // The points/verbs within the path are refcounted so this copy operation - // is inexpensive and maintains the generationID of the original path. - const SkPath* cachedPath = new SkPath(*path); - mDisplayList->pathResources.push_back(cachedPath); - return cachedPath; - } - - /** - * Returns a RenderThread-safe, const copy of the SkPaint parameter passed in - * (with deduping based on paint hash / equality check) - */ - inline const SkPaint* refPaint(const SkPaint* paint) { - if (!paint) return nullptr; - - // If there is a draw filter apply it here and store the modified paint - // so that we don't need to modify the paint every time we access it. - SkTLazy filteredPaint; - if (mDrawFilter.get()) { - filteredPaint.set(*paint); - mDrawFilter->filter(filteredPaint.get(), SkDrawFilter::kPaint_Type); - paint = filteredPaint.get(); - } - - // compute the hash key for the paint and check the cache. - const uint32_t key = paint->getHash(); - const SkPaint* cachedPaint = mPaintMap.valueFor(key); - // In the unlikely event that 2 unique paints have the same hash we do a - // object equality check to ensure we don't erroneously dedup them. - if (cachedPaint == nullptr || *cachedPaint != *paint) { - cachedPaint = new SkPaint(*paint); - mDisplayList->paints.emplace_back(cachedPaint); - // replaceValueFor() performs an add if the entry doesn't exist - mPaintMap.replaceValueFor(key, cachedPaint); - refBitmapsInShader(cachedPaint->getShader()); - } - - return cachedPaint; - } - - inline const SkRegion* refRegion(const SkRegion* region) { - if (!region) { - return region; - } - - const SkRegion* cachedRegion = mRegionMap.valueFor(region); - // TODO: Add generation ID to SkRegion - if (cachedRegion == nullptr) { - std::unique_ptr copy(new SkRegion(*region)); - cachedRegion = copy.get(); - mDisplayList->regions.push_back(std::move(copy)); - - // replaceValueFor() performs an add if the entry doesn't exist - mRegionMap.replaceValueFor(region, cachedRegion); - } - - return cachedRegion; - } - - inline Bitmap* refBitmap(Bitmap& 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 - // contents, and drawing again. The only fix would be to always copy it the first time, - // which doesn't seem worth the extra cycles for this unlikely case. - - // this is required because sk_sp's ctor adopts the pointer, - // but does not increment the refcount, - bitmap.ref(); - mDisplayList->bitmapResources.emplace_back(&bitmap); - return &bitmap; - } - - inline const Res_png_9patch* refPatch(const Res_png_9patch* patch) { - mDisplayList->patchResources.push_back(patch); - mResourceCache.incrementRefcount(patch); - return patch; - } - - DefaultKeyedVector mPaintMap; - DefaultKeyedVector mPathMap; - DefaultKeyedVector mRegionMap; - - CanvasState mState; - std::unique_ptr mSkiaCanvasProxy; - ResourceCache& mResourceCache; - DeferredBarrierType mDeferredBarrierType = DeferredBarrierType::None; - const ClipBase* mDeferredBarrierClip = nullptr; - DisplayList* mDisplayList = nullptr; - sk_sp mDrawFilter; -}; // class RecordingCanvas - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_RECORDING_CANVAS_H diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 62b80c43ebb7..e9039001bd53 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -381,78 +381,6 @@ void RenderNode::applyViewPropertyTransforms(mat4& matrix, bool true3dTransform) } } -/** - * Organizes the DisplayList hierarchy to prepare for background projection reordering. - * - * This should be called before a call to defer() or drawDisplayList() - * - * Each DisplayList that serves as a 3d root builds its list of composited children, - * which are flagged to not draw in the standard draw loop. - */ -void RenderNode::computeOrdering() { - ATRACE_CALL(); - mProjectedNodes.clear(); - - // TODO: create temporary DDLOp and call computeOrderingImpl on top DisplayList so that - // transform properties are applied correctly to top level children - if (mDisplayList == nullptr) return; - for (unsigned int i = 0; i < mDisplayList->getChildren().size(); i++) { - RenderNodeOp* childOp = mDisplayList->getChildren()[i]; - childOp->renderNode->computeOrderingImpl(childOp, &mProjectedNodes, &mat4::identity()); - } -} - -void RenderNode::computeOrderingImpl( - RenderNodeOp* opState, std::vector* compositedChildrenOfProjectionSurface, - const mat4* transformFromProjectionSurface) { - mProjectedNodes.clear(); - if (mDisplayList == nullptr || mDisplayList->isEmpty()) return; - - // TODO: should avoid this calculation in most cases - // TODO: just calculate single matrix, down to all leaf composited elements - Matrix4 localTransformFromProjectionSurface(*transformFromProjectionSurface); - localTransformFromProjectionSurface.multiply(opState->localMatrix); - - if (properties().getProjectBackwards()) { - // composited projectee, flag for out of order draw, save matrix, and store in proj surface - opState->skipInOrderDraw = true; - opState->transformFromCompositingAncestor = localTransformFromProjectionSurface; - compositedChildrenOfProjectionSurface->push_back(opState); - } else { - // standard in order draw - opState->skipInOrderDraw = false; - } - - if (mDisplayList->getChildren().size() > 0) { - const bool isProjectionReceiver = mDisplayList->projectionReceiveIndex >= 0; - bool haveAppliedPropertiesToProjection = false; - for (unsigned int i = 0; i < mDisplayList->getChildren().size(); i++) { - RenderNodeOp* childOp = mDisplayList->getChildren()[i]; - RenderNode* child = childOp->renderNode; - - std::vector* projectionChildren = nullptr; - const mat4* projectionTransform = nullptr; - if (isProjectionReceiver && !child->properties().getProjectBackwards()) { - // if receiving projections, collect projecting descendant - - // Note that if a direct descendant is projecting backwards, we pass its - // grandparent projection collection, since it shouldn't project onto its - // parent, where it will already be drawing. - projectionChildren = &mProjectedNodes; - projectionTransform = &mat4::identity(); - } else { - if (!haveAppliedPropertiesToProjection) { - applyViewPropertyTransforms(localTransformFromProjectionSurface); - haveAppliedPropertiesToProjection = true; - } - projectionChildren = compositedChildrenOfProjectionSurface; - projectionTransform = &localTransformFromProjectionSurface; - } - child->computeOrderingImpl(childOp, projectionChildren, projectionTransform); - } - } -} - const SkPath* RenderNode::getClippedOutline(const SkRect& clipRect) const { const SkPath* outlinePath = properties().getOutline().getPath(); const uint32_t outlineID = outlinePath->getGenerationID(); diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index 1e0d4e2c2254..45a53f9a37df 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -48,8 +48,6 @@ namespace android { namespace uirenderer { class CanvasState; -class DisplayListOp; -class FrameBuilder; class OffscreenBuffer; class Rect; class SkiaShader; @@ -76,7 +74,6 @@ class RenderNode; */ class RenderNode : public VirtualLightRefBase { friend class TestUtils; // allow TestUtils to access syncDisplayList / syncProperties - friend class FrameBuilder; public: enum DirtyPropertyMask { @@ -104,8 +101,6 @@ public: ANDROID_API void setStagingDisplayList(DisplayList* newData); - void computeOrdering(); - ANDROID_API void output(); ANDROID_API int getDebugSize(); diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h index da52a9503377..e84b9acffca7 100644 --- a/libs/hwui/VectorDrawable.h +++ b/libs/hwui/VectorDrawable.h @@ -718,6 +718,8 @@ private: } // namespace VectorDrawable typedef VectorDrawable::Path::Data PathData; +typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot; + } // namespace uirenderer } // namespace android diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp index b453227ba770..30f6f12b424e 100644 --- a/libs/hwui/hwui/Canvas.cpp +++ b/libs/hwui/hwui/Canvas.cpp @@ -19,7 +19,6 @@ #include "MinikinUtils.h" #include "Paint.h" #include "Properties.h" -#include "RecordingCanvas.h" #include "RenderNode.h" #include "Typeface.h" #include "pipeline/skia/SkiaRecordingCanvas.h" diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h index f341cf96120d..341b0c56a50c 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -44,8 +44,16 @@ namespace uirenderer { class CanvasPropertyPaint; class CanvasPropertyPrimitive; class DeferredLayerUpdater; -class DisplayList; class RenderNode; + +namespace skiapipeline { +class SkiaDisplayList; +} + +/** + * Data structure that holds the list of commands used in display list stream + */ +using DisplayList = skiapipeline::SkiaDisplayList; } namespace SaveFlags { diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.h b/libs/hwui/pipeline/skia/GLFunctorDrawable.h index af57d7d33c2c..d9e65c95444e 100644 --- a/libs/hwui/pipeline/skia/GLFunctorDrawable.h +++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.h @@ -16,6 +16,8 @@ #pragma once +#include "GlFunctorLifecycleListener.h" + #include #include @@ -25,8 +27,6 @@ namespace android { namespace uirenderer { -class GlFunctorLifecycleListener; - namespace skiapipeline { /** diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp index 6c04d7862979..1b816febf846 100644 --- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp +++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp @@ -25,6 +25,19 @@ namespace android { namespace uirenderer { namespace skiapipeline { +RenderNodeDrawable::RenderNodeDrawable(RenderNode* node, SkCanvas* canvas, bool composeLayer, + bool inReorderingSection) + : mRenderNode(node) + , mRecordedTransform(canvas->getTotalMatrix()) + , mComposeLayer(composeLayer) + , mInReorderingSection(inReorderingSection) {} + +RenderNodeDrawable::~RenderNodeDrawable() { + // Just here to move the destructor into the cpp file where we can access RenderNode. + + // TODO: Detangle the header nightmare. +} + void RenderNodeDrawable::drawBackwardsProjectedNodes(SkCanvas* canvas, const SkiaDisplayList& displayList, int nestLevel) { @@ -115,7 +128,6 @@ void RenderNodeDrawable::forceDraw(SkCanvas* canvas) { return; } - SkASSERT(renderNode->getDisplayList()->isSkiaDL()); SkiaDisplayList* displayList = (SkiaDisplayList*)renderNode->getDisplayList(); SkAutoCanvasRestore acr(canvas, true); diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.h b/libs/hwui/pipeline/skia/RenderNodeDrawable.h index ef21cd8a29b5..6594bd22c0b1 100644 --- a/libs/hwui/pipeline/skia/RenderNodeDrawable.h +++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.h @@ -47,11 +47,9 @@ public: * layer into the canvas. */ explicit RenderNodeDrawable(RenderNode* node, SkCanvas* canvas, bool composeLayer = true, - bool inReorderingSection = false) - : mRenderNode(node) - , mRecordedTransform(canvas->getTotalMatrix()) - , mComposeLayer(composeLayer) - , mInReorderingSection(inReorderingSection) {} + bool inReorderingSection = false); + + ~RenderNodeDrawable(); /** * Draws into the canvas this render node and its children. If the node is marked as a diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h index 818ec114a5b3..58b9242e087f 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.h +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h @@ -16,10 +16,11 @@ #pragma once -#include "DisplayList.h" #include "hwui/AnimatedImageDrawable.h" #include "GLFunctorDrawable.h" #include "RenderNodeDrawable.h" +#include "TreeInfo.h" +#include "utils/LinearAllocator.h" #include #include @@ -28,8 +29,17 @@ namespace android { namespace uirenderer { +namespace renderthread { +class CanvasContext; +} + class Outline; +namespace VectorDrawable { +class Tree; +}; +typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot; + namespace skiapipeline { /** @@ -38,10 +48,14 @@ namespace skiapipeline { * runtime. The downside of this inheritance is that we pay for the overhead * of the parent class construction/destruction without any real benefit. */ -class SkiaDisplayList : public DisplayList { +class SkiaDisplayList { public: - SkiaDisplayList() { SkASSERT(projectionReceiveIndex == -1); } - virtual ~SkiaDisplayList() { + // index of DisplayListOp restore, after which projected descendants should be drawn + int projectionReceiveIndex = -1; + + size_t getUsedSize() { return allocator.usedSize(); } + + ~SkiaDisplayList() { /* Given that we are using a LinearStdAllocator to store some of the * SkDrawable contents we must ensure that any other object that is * holding a reference to those drawables is destroyed prior to their @@ -68,29 +82,27 @@ public: return allocator.create(std::forward(params)...); } - bool isSkiaDL() const override { return true; } - /** * Returns true if the DisplayList does not have any recorded content */ - bool isEmpty() const override { return mDisplayList.empty(); } + bool isEmpty() const { return mDisplayList.empty(); } /** * Returns true if this list directly contains a GLFunctor drawing command. */ - bool hasFunctor() const override { return !mChildFunctors.empty(); } + bool hasFunctor() const { return !mChildFunctors.empty(); } /** * Returns true if this list directly contains a VectorDrawable drawing command. */ - bool hasVectorDrawables() const override { return !mVectorDrawables.empty(); } + bool hasVectorDrawables() const { return !mVectorDrawables.empty(); } /** * Attempts to reset and reuse this DisplayList. * * @return true if the displayList will be reused and therefore should not be deleted */ - bool reuseDisplayList(RenderNode* node, renderthread::CanvasContext* context) override; + bool reuseDisplayList(RenderNode* node, renderthread::CanvasContext* context); /** * ONLY to be called by RenderNode::syncDisplayList so that we can notify any @@ -99,7 +111,7 @@ public: * NOTE: This function can be folded into RenderNode when we no longer need * to subclass from DisplayList */ - void syncContents() override; + void syncContents(); /** * ONLY to be called by RenderNode::prepareTree in order to prepare this @@ -116,12 +128,12 @@ public: bool prepareListAndChildren( TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer, - std::function childFn) override; + std::function childFn); /** * Calls the provided function once for each child of this DisplayList */ - void updateChildren(std::function updateFn) override; + void updateChildren(std::function updateFn); /** * Returns true if there is a child render node that is a projection receiver. @@ -134,7 +146,9 @@ public: void draw(SkCanvas* canvas) { mDisplayList.draw(canvas); } - void output(std::ostream& output, uint32_t level) override; + void output(std::ostream& output, uint32_t level); + + LinearAllocator allocator; /** * We use std::deque here because (1) we need to iterate through these diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index cfcfd2b74a5a..15277f175350 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -25,6 +25,7 @@ #include "renderstate/RenderState.h" #include "renderthread/EglManager.h" #include "renderthread/Frame.h" +#include "utils/GLUtils.h" #include "utils/TraceUtils.h" #include @@ -58,10 +59,10 @@ Frame SkiaOpenGLPipeline::getFrame() { } bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty, - const FrameBuilder::LightGeometry& lightGeometry, + const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds, bool opaque, bool wideColorGamut, - const BakedOpRenderer::LightInfo& lightInfo, + const LightInfo& lightInfo, const std::vector>& renderNodes, FrameInfoVisualizer* profiler) { mEglManager.damageFrame(frame, dirty); diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h index ef5d9347a3ea..04b68f5e3278 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h @@ -33,9 +33,9 @@ public: renderthread::MakeCurrentResult makeCurrent() override; renderthread::Frame getFrame() override; bool draw(const renderthread::Frame& frame, const SkRect& screenDirty, const SkRect& dirty, - const FrameBuilder::LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, + const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds, bool opaque, bool wideColorGamut, - const BakedOpRenderer::LightInfo& lightInfo, + const LightInfo& lightInfo, const std::vector >& renderNodes, FrameInfoVisualizer* profiler) override; bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty, diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index d66cba12ad99..988981d65775 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -81,9 +81,9 @@ void SkiaPipeline::onPrepareTree() { mVectorDrawables.clear(); } -void SkiaPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry, +void SkiaPipeline::renderLayers(const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, bool opaque, - bool wideColorGamut, const BakedOpRenderer::LightInfo& lightInfo) { + bool wideColorGamut, const LightInfo& lightInfo) { updateLighting(lightGeometry, lightInfo); ATRACE_NAME("draw layers"); renderVectorDrawableCache(); @@ -103,7 +103,6 @@ void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque, // as not to lose info on what portion is damaged if (CC_LIKELY(layerNode->getLayerSurface() != nullptr)) { SkASSERT(layerNode->getLayerSurface()); - SkASSERT(layerNode->getDisplayList()->isSkiaDL()); SkiaDisplayList* displayList = (SkiaDisplayList*)layerNode->getDisplayList(); if (!displayList || displayList->isEmpty()) { SkDEBUGF(("%p drawLayers(%s) : missing drawable", layerNode, layerNode->getName())); diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h index 38ad9c09a8aa..8c9c80381b84 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaPipeline.h @@ -17,7 +17,7 @@ #pragma once #include -#include "FrameBuilder.h" +#include "Lighting.h" #include "hwui/AnimatedImageDrawable.h" #include "renderthread/CanvasContext.h" #include "renderthread/IRenderPipeline.h" @@ -42,9 +42,9 @@ public: void unpinImages() override; void onPrepareTree() override; - void renderLayers(const FrameBuilder::LightGeometry& lightGeometry, + void renderLayers(const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut, - const BakedOpRenderer::LightInfo& lightInfo) override; + const LightInfo& lightInfo) override; bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator, bool wideColorGamut, ErrorHandler* errorHandler) override; @@ -97,8 +97,8 @@ public: return mLightCenter; } - static void updateLighting(const FrameBuilder::LightGeometry& lightGeometry, - const BakedOpRenderer::LightInfo& lightInfo) { + static void updateLighting(const LightGeometry& lightGeometry, + const LightInfo& lightInfo) { mLightRadius = lightGeometry.radius; mAmbientShadowAlpha = lightInfo.ambientShadowAlpha; mSpotShadowAlpha = lightInfo.spotShadowAlpha; diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index 5825060f902a..b2519fe59891 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -62,10 +62,10 @@ Frame SkiaVulkanPipeline::getFrame() { } bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty, - const FrameBuilder::LightGeometry& lightGeometry, + const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds, bool opaque, bool wideColorGamut, - const BakedOpRenderer::LightInfo& lightInfo, + const LightInfo& lightInfo, const std::vector>& renderNodes, FrameInfoVisualizer* profiler) { sk_sp backBuffer = mVkSurface->getBackBufferSurface(); diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h index 03b4c79f2beb..7806b42e03dc 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h @@ -31,9 +31,9 @@ public: renderthread::MakeCurrentResult makeCurrent() override; renderthread::Frame getFrame() override; bool draw(const renderthread::Frame& frame, const SkRect& screenDirty, const SkRect& dirty, - const FrameBuilder::LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, + const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds, bool opaque, bool wideColorGamut, - const BakedOpRenderer::LightInfo& lightInfo, + const LightInfo& lightInfo, const std::vector >& renderNodes, FrameInfoVisualizer* profiler) override; bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty, diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp index f173136d6f8d..a60e2b5c815e 100644 --- a/libs/hwui/renderstate/RenderState.cpp +++ b/libs/hwui/renderstate/RenderState.cpp @@ -18,6 +18,7 @@ #include "DeferredLayerUpdater.h" #include "GlLayer.h" #include "VkLayer.h" +#include "Snapshot.h" #include "renderthread/CanvasContext.h" #include "renderthread/EglManager.h" diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index aaef85a5b1bc..358b842cee20 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -16,10 +16,8 @@ #pragma once -#include "BakedOpDispatcher.h" -#include "BakedOpRenderer.h" #include "DamageAccumulator.h" -#include "FrameBuilder.h" +#include "Lighting.h" #include "FrameInfo.h" #include "FrameInfoVisualizer.h" #include "FrameMetricsReporter.h" @@ -231,8 +229,8 @@ private: bool mOpaque; bool mWideColorGamut = false; - BakedOpRenderer::LightInfo mLightInfo; - FrameBuilder::LightGeometry mLightGeometry = {{0, 0, 0}, 0}; + LightInfo mLightInfo; + LightGeometry mLightGeometry = {{0, 0, 0}, 0}; bool mHaveNewSurface = false; DamageAccumulator mDamageAccumulator; diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h index d8c43e0d8ca8..0037a0f4306d 100644 --- a/libs/hwui/renderthread/DrawFrameTask.h +++ b/libs/hwui/renderthread/DrawFrameTask.h @@ -32,7 +32,6 @@ namespace android { namespace uirenderer { class DeferredLayerUpdater; -class DisplayList; class RenderNode; namespace renderthread { diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h index b1de49733c09..b94a7588a507 100644 --- a/libs/hwui/renderthread/IRenderPipeline.h +++ b/libs/hwui/renderthread/IRenderPipeline.h @@ -17,7 +17,10 @@ #pragma once #include "FrameInfoVisualizer.h" +#include "LayerUpdateQueue.h" #include "SwapBehavior.h" +#include "hwui/Bitmap.h" +#include "thread/TaskManager.h" #include #include @@ -50,9 +53,9 @@ public: virtual MakeCurrentResult makeCurrent() = 0; virtual Frame getFrame() = 0; virtual bool draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty, - const FrameBuilder::LightGeometry& lightGeometry, + const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds, - bool opaque, bool wideColorGamut, const BakedOpRenderer::LightInfo& lightInfo, + bool opaque, bool wideColorGamut, const LightInfo& lightInfo, const std::vector>& renderNodes, FrameInfoVisualizer* profiler) = 0; virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty, @@ -64,9 +67,9 @@ public: virtual bool isSurfaceReady() = 0; virtual bool isContextReady() = 0; virtual void onDestroyHardwareResources() = 0; - virtual void renderLayers(const FrameBuilder::LightGeometry& lightGeometry, + virtual void renderLayers(const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut, - const BakedOpRenderer::LightInfo& lightInfo) = 0; + const LightInfo& lightInfo) = 0; virtual TaskManager* getTaskManager() = 0; virtual bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator, bool wideColorGamut, ErrorHandler* errorHandler) = 0; diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 0caf59b42202..4d1e1e8fb04b 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -66,10 +66,7 @@ void RenderProxy::setSwapBehavior(SwapBehavior swapBehavior) { bool RenderProxy::loadSystemProperties() { return mRenderThread.queue().runSync([this]() -> bool { - bool needsRedraw = false; - if (Caches::hasInstance()) { - needsRedraw = Properties::load(); - } + bool needsRedraw = Properties::load(); if (mContext->profiler().consumeProperties()) { needsRedraw = true; } diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h index ca5a88bc5904..13fb5285bc31 100644 --- a/libs/hwui/tests/common/TestUtils.h +++ b/libs/hwui/tests/common/TestUtils.h @@ -29,7 +29,6 @@ #include #include -#include #include @@ -335,16 +334,10 @@ private: } auto displayList = node->getDisplayList(); if (displayList) { - if (displayList->isSkiaDL()) { - for (auto&& childDr : static_cast( - const_cast(displayList)) - ->mChildNodes) { - syncHierarchyPropertiesAndDisplayListImpl(childDr.getRenderNode()); - } - } else { - for (auto&& childOp : displayList->getChildren()) { - syncHierarchyPropertiesAndDisplayListImpl(childOp->renderNode); - } + for (auto&& childDr : static_cast( + const_cast(displayList)) + ->mChildNodes) { + syncHierarchyPropertiesAndDisplayListImpl(childDr.getRenderNode()); } } } diff --git a/libs/hwui/tests/common/scenes/TestSceneBase.h b/libs/hwui/tests/common/scenes/TestSceneBase.h index 792312a6a7a4..6f76a502ae3e 100644 --- a/libs/hwui/tests/common/scenes/TestSceneBase.h +++ b/libs/hwui/tests/common/scenes/TestSceneBase.h @@ -16,7 +16,7 @@ #pragma once -#include "RecordingCanvas.h" +#include "hwui/Canvas.h" #include "RenderNode.h" #include "tests/common/TestContext.h" #include "tests/common/TestScene.h" diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp index 0aaf7731c927..9388c2062736 100644 --- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp +++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp @@ -16,8 +16,10 @@ #include +#include "CanvasState.h" #include "DisplayList.h" -#include "RecordingCanvas.h" +#include "hwui/Canvas.h" +#include "pipeline/skia/SkiaDisplayList.h" #include "tests/common/TestUtils.h" using namespace android; @@ -25,7 +27,7 @@ using namespace android::uirenderer; void BM_DisplayList_alloc(benchmark::State& benchState) { while (benchState.KeepRunning()) { - auto displayList = new DisplayList(); + auto displayList = new skiapipeline::SkiaDisplayList(); benchmark::DoNotOptimize(displayList); delete displayList; } @@ -34,7 +36,7 @@ BENCHMARK(BM_DisplayList_alloc); void BM_DisplayList_alloc_theoretical(benchmark::State& benchState) { while (benchState.KeepRunning()) { - auto displayList = new char[sizeof(DisplayList)]; + auto displayList = new char[sizeof(skiapipeline::SkiaDisplayList)]; benchmark::DoNotOptimize(displayList); delete[] displayList; } diff --git a/libs/hwui/tests/microbench/FrameBuilderBench.cpp b/libs/hwui/tests/microbench/FrameBuilderBench.cpp deleted file mode 100644 index b6217665d743..000000000000 --- a/libs/hwui/tests/microbench/FrameBuilderBench.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2016 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 - -#include "BakedOpDispatcher.h" -#include "BakedOpRenderer.h" -#include "BakedOpState.h" -#include "FrameBuilder.h" -#include "LayerUpdateQueue.h" -#include "RecordedOp.h" -#include "RecordingCanvas.h" -#include "Vector.h" -#include "tests/common/TestContext.h" -#include "tests/common/TestScene.h" -#include "tests/common/TestUtils.h" - -#include - -using namespace android; -using namespace android::uirenderer; -using namespace android::uirenderer::renderthread; -using namespace android::uirenderer::test; - -const FrameBuilder::LightGeometry sLightGeometry = {{100, 100, 100}, 50}; -const BakedOpRenderer::LightInfo sLightInfo = {128, 128}; - -static sp createTestNode() { - auto node = TestUtils::createNode( - 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) { - sk_sp bitmap(TestUtils::createBitmap(10, 10)); - SkPaint paint; - - // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects. - // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group. - canvas.save(SaveFlags::MatrixClip); - for (int i = 0; i < 30; i++) { - canvas.translate(0, 10); - canvas.drawRect(0, 0, 10, 10, paint); - canvas.drawBitmap(*bitmap, 5, 0, nullptr); - } - canvas.restore(); - }); - TestUtils::syncHierarchyPropertiesAndDisplayList(node); - return node; -} - -void BM_FrameBuilder_defer(benchmark::State& state) { - TestUtils::runOnRenderThread([&state](RenderThread& thread) { - auto node = createTestNode(); - while (state.KeepRunning()) { - FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*node); - benchmark::DoNotOptimize(&frameBuilder); - } - }); -} -BENCHMARK(BM_FrameBuilder_defer); - -void BM_FrameBuilder_deferAndRender(benchmark::State& state) { - TestUtils::runOnRenderThread([&state](RenderThread& thread) { - auto node = createTestNode(); - - RenderState& renderState = thread.renderState(); - Caches& caches = Caches::getInstance(); - - while (state.KeepRunning()) { - FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200, sLightGeometry, caches); - frameBuilder.deferRenderNode(*node); - - BakedOpRenderer renderer(caches, renderState, true, false, sLightInfo); - frameBuilder.replayBakedOps(renderer); - benchmark::DoNotOptimize(&renderer); - } - }); -} -BENCHMARK(BM_FrameBuilder_deferAndRender); - -static sp getSyncedSceneNode(const char* sceneName) { - gDisplay = getBuiltInDisplay(); // switch to real display if present - - TestContext testContext; - TestScene::Options opts; - std::unique_ptr scene(TestScene::testMap()[sceneName].createScene(opts)); - - sp rootNode = TestUtils::createNode( - 0, 0, gDisplay.w, gDisplay.h, - [&scene](RenderProperties& props, RecordingCanvas& canvas) { - scene->createContent(gDisplay.w, gDisplay.h, canvas); - }); - - TestUtils::syncHierarchyPropertiesAndDisplayList(rootNode); - return rootNode; -} - -static auto SCENES = { - "listview", -}; - -void BM_FrameBuilder_defer_scene(benchmark::State& state) { - TestUtils::runOnRenderThread([&state](RenderThread& thread) { - const char* sceneName = *(SCENES.begin() + state.range(0)); - state.SetLabel(sceneName); - auto node = getSyncedSceneNode(sceneName); - while (state.KeepRunning()) { - FrameBuilder frameBuilder(SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, - gDisplay.h, sLightGeometry, Caches::getInstance()); - frameBuilder.deferRenderNode(*node); - benchmark::DoNotOptimize(&frameBuilder); - } - }); -} -BENCHMARK(BM_FrameBuilder_defer_scene)->DenseRange(0, SCENES.size() - 1); - -void BM_FrameBuilder_deferAndRender_scene(benchmark::State& state) { - TestUtils::runOnRenderThread([&state](RenderThread& thread) { - const char* sceneName = *(SCENES.begin() + state.range(0)); - state.SetLabel(sceneName); - auto node = getSyncedSceneNode(sceneName); - - RenderState& renderState = thread.renderState(); - Caches& caches = Caches::getInstance(); - - while (state.KeepRunning()) { - FrameBuilder frameBuilder(SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, - gDisplay.h, sLightGeometry, Caches::getInstance()); - frameBuilder.deferRenderNode(*node); - - BakedOpRenderer renderer(caches, renderState, true, false, sLightInfo); - frameBuilder.replayBakedOps(renderer); - benchmark::DoNotOptimize(&renderer); - } - }); -} -BENCHMARK(BM_FrameBuilder_deferAndRender_scene)->DenseRange(0, SCENES.size() - 1); diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp index 2e4de0bac755..634ceffe0741 100644 --- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp +++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp @@ -16,7 +16,6 @@ #include "tests/common/TestUtils.h" -#include #include #include #include diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp index 42a92fcc7d89..26b6000a91e6 100644 --- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp +++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp @@ -167,10 +167,10 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderLayer) { ASSERT_EQ(layerUpdateQueue.entries().size(), 2UL); bool opaque = true; - FrameBuilder::LightGeometry lightGeometry; + LightGeometry lightGeometry; lightGeometry.radius = 1.0f; lightGeometry.center = {0.0f, 0.0f, 0.0f}; - BakedOpRenderer::LightInfo lightInfo; + LightInfo lightInfo; auto pipeline = std::make_unique(renderThread); pipeline->renderLayers(lightGeometry, &layerUpdateQueue, opaque, false, lightInfo); ASSERT_EQ(TestUtils::getColor(surfaceLayer1, 0, 0), SK_ColorRED); diff --git a/libs/hwui/utils/TestWindowContext.cpp b/libs/hwui/utils/TestWindowContext.cpp index 700d3b3cf000..8ac6e1f2d39a 100644 --- a/libs/hwui/utils/TestWindowContext.cpp +++ b/libs/hwui/utils/TestWindowContext.cpp @@ -17,7 +17,6 @@ #include "AnimationContext.h" #include "IContextFactory.h" -#include "RecordingCanvas.h" #include "RenderNode.h" #include "SkTypes.h" #include "gui/BufferQueue.h" @@ -25,6 +24,7 @@ #include "gui/IGraphicBufferConsumer.h" #include "gui/IGraphicBufferProducer.h" #include "gui/Surface.h" +#include "hwui/Canvas.h" #include "renderthread/RenderProxy.h" #include @@ -81,7 +81,7 @@ public: android::uirenderer::Vector3 lightVector{lightX, -200.0f, 800.0f}; mProxy->setup(800.0f, 255 * 0.075f, 255 * 0.15f); mProxy->setLightCenter(lightVector); - mCanvas.reset(new android::uirenderer::RecordingCanvas(mSize.width(), mSize.height())); + mCanvas.reset(Canvas::create_recording_canvas(mSize.width(), mSize.height(), mRootNode.get())); } SkCanvas* prepareToDraw() { @@ -155,7 +155,7 @@ public: private: std::unique_ptr mRootNode; std::unique_ptr mProxy; - std::unique_ptr mCanvas; + std::unique_ptr mCanvas; android::sp mProducer; android::sp mConsumer; android::sp mCpuConsumer; -- cgit v1.2.3-59-g8ed1b