diff options
36 files changed, 26 insertions, 5071 deletions
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 <cutils/ashmem.h> #include <hwui/Canvas.h> -#include <Caches.h> -#include <TextureCache.h> - 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 <Caches.h> #include <vector> #include <map> @@ -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<const BitmapOp*>(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<const PatchOp*>(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<const PatchOp*>(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<const PatchOp*>(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<ColorTextureVertex[]> mesh(new ColorTextureVertex[elementCount]); - ColorTextureVertex* vertex = &mesh[0]; - - const int* colors = op.colors; - std::unique_ptr<int[]> 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<BakedOpState>(allocator, snapshot, shadowOpPtr); -} - BakedOpState* BakedOpState::directConstruct(LinearAllocator& allocator, const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp) { return allocator.create_trivial<BakedOpState>(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<Layer*>::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 <stdlib.h> - -#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 <GLES2/gl2.h> - -#include <utils/SortedVector.h> - -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<GLuint> 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<TessellationCache::ShadowTask> task = mCaches.tessellationCache.getShadowTask( - mCanvasState.currentTransform(), mCanvasState.getLocalClipBounds(), - casterAlpha >= 1.0f, casterPath, &shadowMatrixXY, &shadowMatrixZ, - mCanvasState.currentSnapshot()->getRelativeLightCenter(), mLightRadius); - ShadowOp* shadowOp = mAllocator.create<ShadowOp>(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 <utils/JenkinsHash.h> - -#include "Caches.h" -#include "Debug.h" -#include "DeviceInfo.h" -#include "GradientCache.h" -#include "Properties.h" - -#include <cutils/properties.h> - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Functions -/////////////////////////////////////////////////////////////////////////////// - -template <typename T> -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<GradientCacheEntry, Texture*>::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 <memory> - -#include <GLES3/gl3.h> - -#include <SkShader.h> - -#include <utils/LruCache.h> -#include <utils/Mutex.h> - -#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<uint32_t[]> colors; - std::unique_ptr<float[]> 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<GradientCacheEntry, Texture*> { -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<GradientCacheEntry, Texture*> 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 <utils/JenkinsHash.h> -#include <utils/Log.h> - -#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<PatchDescription, Patch*>::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<PatchDescription, Patch*>::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<patch_pair_t>& patchesToRemove, Res_png_9patch* patch) { - LruCache<PatchDescription, Patch*>::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<patch_pair_t> 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 <GLES2/gl2.h> - -#include <utils/LruCache.h> - -#include <androidfw/ResourceTypes.h> - -#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<const PatchDescription*, Patch*> patch_pair_t; - - void clearCache(); - void createVertexBuffer(); - - void setupMesh(Patch* newMesh); - - void remove(Vector<patch_pair_t>& patchesToRemove, Res_png_9patch* patch); - -#if DEBUG_PATCHES - void dumpFreeBlocks(const char* prefix); -#endif - - RenderState& mRenderState; - const uint32_t mMaxSize; - uint32_t mSize; - - LruCache<PatchDescription, Patch*> 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<Res_png_9patch*> 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 <SkBitmap.h> -#include <SkCanvas.h> -#include <SkColor.h> -#include <SkColorFilter.h> -#include <SkMaskFilter.h> -#include <SkPaint.h> -#include <SkPath.h> -#include <SkPathEffect.h> -#include <SkRect.h> - -#include <utils/JenkinsHash.h> -#include <utils/Trace.h> - -#include "Caches.h" -#include "PathCache.h" - -#include "thread/Signal.h" -#include "thread/TaskProcessor.h" - -#include <cutils/properties.h> - -namespace android { -namespace uirenderer { - -static constexpr size_t PATH_CACHE_COUNT_LIMIT = 256; - -template <class T> -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<int>(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<Bitmap> 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 = 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<PathDescription, PathTexture*>::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<PathTask>& 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> 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<sk_sp<Bitmap> >(&caches.tasks), mMaxTextureSize(caches.maxTextureSize) {} - -void PathCache::PathProcessor::onProcess(const sp<Task<sk_sp<Bitmap> > >& task) { - PathTask* t = static_cast<PathTask*>(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<PathDescription> pathsToRemove; - - { // scope for the mutex - Mutex::Autolock l(mLock); - for (const uint32_t generationID : mGarbage) { - LruCache<PathDescription, PathTexture*>::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<PathTask>& 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> 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<PathTask> 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 <GLES2/gl2.h> -#include <SkPaint.h> -#include <SkPath.h> -#include <utils/LruCache.h> -#include <utils/Mutex.h> - -#include <vector> - -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<sk_sp<Bitmap>> { -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<PathTask> task() const { return mTask; } - - void setTask(const sp<PathTask>& task) { mTask = task; } - - void clearTask() { - if (mTask != nullptr) { - mTask.clear(); - } - } - -private: - sp<PathTask> 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<PathDescription, PathTexture*> { -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<sk_sp<Bitmap>> { - public: - explicit PathProcessor(Caches& caches); - ~PathProcessor() {} - - virtual void onProcess(const sp<Task<sk_sp<Bitmap>>>& task) override; - - private: - uint32_t mMaxTextureSize; - }; - - LruCache<PathDescription, PathTexture*> mCache; - uint32_t mSize; - const uint32_t mMaxSize; - GLuint mMaxTextureSize; - - bool mDebugEnabled; - - sp<PathProcessor> mProcessor; - - std::vector<uint32_t> 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 <utils/String8.h> - -#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>(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<int>(description.colorOp)]); - - if (description.hasColorSpaceConversion) { - shader.append(gFS_Uniforms_ColorSpaceConversion); - } - shader.append(gFS_Uniforms_TransferFunction[static_cast<int>(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<int>(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<int>(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 <utils/KeyedVector.h> -#include <utils/Log.h> -#include <utils/String8.h> -#include <map> - -#include <GLES2/gl2.h> - -#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<programid, std::unique_ptr<Program>> 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<TessellationCache::ShadowTask>& shadowTask, float casterAlpha) - : RecordedOp(RecordedOpId::ShadowOp, Rect(), Matrix4::identity(), nullptr, nullptr) - , shadowTask(shadowTask) - , casterAlpha(casterAlpha){}; - sp<TessellationCache::ShadowTask> 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 <utils/Log.h> - -#include <cstdlib> - -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 <GLES2/gl2.h> - -#include "RenderBuffer.h" - -#include <set> - -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<RenderBufferEntry> 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<const float*>(&color)); } @@ -80,106 +73,9 @@ static void computeScreenSpaceMatrix(mat4& screenSpace, const SkMatrix& unitMatr } /////////////////////////////////////////////////////////////////////////////// -// 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<SkColor[]> colorStorage(new SkColor[gradInfo.fColorCount]); - std::unique_ptr<SkScalar[]> 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*>(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 <utils/JenkinsHash.h> -#include <utils/Trace.h> - -#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<int>(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<VertexBuffer*> { -public: - TessellationTask(Tessellator tessellator, const Description& description) - : tessellator(tessellator), description(description) {} - - ~TessellationTask() {} - - Tessellator tessellator; - Description description; -}; - -class TessellationCache::TessellationProcessor : public TaskProcessor<VertexBuffer*> { -public: - explicit TessellationProcessor(Caches& caches) : TaskProcessor<VertexBuffer*>(&caches.tasks) {} - ~TessellationProcessor() {} - - virtual void onProcess(const sp<Task<VertexBuffer*> >& task) override { - TessellationTask* t = static_cast<TessellationTask*>(task.get()); - ATRACE_NAME("shape tessellation"); - VertexBuffer* buffer = t->tessellator(t->description); - t->setResult(buffer); - } -}; - -class TessellationCache::Buffer { -public: - explicit Buffer(const sp<Task<VertexBuffer*> >& 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<Task<VertexBuffer*> > 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<Vertex> 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<const Vector2*>(&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<TessellationCache::vertexBuffer_pair_t> { -public: - explicit ShadowProcessor(Caches& caches) - : TaskProcessor<TessellationCache::vertexBuffer_pair_t>(&caches.tasks) {} - ~ShadowProcessor() {} - - virtual void onProcess(const sp<Task<TessellationCache::vertexBuffer_pair_t> >& task) override { - TessellationCache::ShadowTask* t = static_cast<TessellationCache::ShadowTask*>(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<Description, Buffer*>::kUnlimitedCapacity) - , mShadowCache( - LruCache<ShadowDescription, Task<vertexBuffer_pair_t*>*>::kUnlimitedCapacity) { - mCache.setOnEntryRemovedListener(&mBufferRemovedListener); - mShadowCache.setOnEntryRemovedListener(&mBufferPairRemovedListener); - mDebugEnabled = Properties::debugLevel & kDebugCaches; -} - -TessellationCache::~TessellationCache() { - mCache.clear(); -} - -/////////////////////////////////////////////////////////////////////////////// -// Size management -/////////////////////////////////////////////////////////////////////////////// - -uint32_t TessellationCache::getSize() { - LruCache<Description, Buffer*>::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<ShadowTask> 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::ShadowTask> 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<ShadowTask*>(mShadowCache.get(key)); - if (!task) { - precacheShadows(drawTransform, localClip, opaque, casterPerimeter, transformXY, transformZ, - lightCenter, lightRadius); - task = static_cast<ShadowTask*>(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<TessellationTask> 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 <SkPaint.h> -#include <SkPath.h> - -#include <utils/LruCache.h> -#include <utils/Mutex.h> -#include <utils/StrongPointer.h> - -class SkBitmap; -class SkCanvas; -struct SkRect; - -namespace android { -namespace uirenderer { - -class Caches; -class VertexBuffer; - -/////////////////////////////////////////////////////////////////////////////// -// Classes -/////////////////////////////////////////////////////////////////////////////// - -class TessellationCache { -public: - typedef Pair<VertexBuffer*, VertexBuffer*> 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<vertexBuffer_pair_t> { - 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<ShadowTask> 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<TaskProcessor<VertexBuffer*> > mProcessor; - LruCache<Description, Buffer*> mCache; - class BufferRemovedListener : public OnEntryRemoved<Description, Buffer*> { - void operator()(Description& description, Buffer*& buffer) override; - }; - BufferRemovedListener mBufferRemovedListener; - - /////////////////////////////////////////////////////////////////////////////// - // Shadow tessellation caching - /////////////////////////////////////////////////////////////////////////////// - sp<TaskProcessor<vertexBuffer_pair_t> > mShadowProcessor; - - // holds a pointer, and implicit strong ref to each shadow task of the frame - LruCache<ShadowDescription, Task<vertexBuffer_pair_t>*> mShadowCache; - class BufferPairRemovedListener - : public OnEntryRemoved<ShadowDescription, Task<vertexBuffer_pair_t>*> { - void operator()(ShadowDescription& description, - Task<vertexBuffer_pair_t>*& 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 <GLES2/gl2.h> - -#include <utils/Mutex.h> - -#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<uint32_t, Texture*>::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<uint32_t, Texture*>::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>(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 <SkBitmap.h> - -#include <cutils/compiler.h> - -#include <utils/LruCache.h> -#include <utils/Mutex.h> - -#include "Debug.h" - -#include <unordered_map> -#include <vector> - -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<uint32_t, Texture*> { -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<uint32_t, Texture*> mCache; - - uint32_t mSize; - const uint32_t mMaxSize; - GLint mMaxTextureSize; - - const float mFlushRate; - - bool mDebugEnabled; - - std::unordered_map<uint32_t, std::unique_ptr<Texture>> 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 <benchmark/benchmark.h> - -#include "Matrix.h" -#include "Rect.h" -#include "TessellationCache.h" -#include "Vector.h" -#include "VertexBuffer.h" - -#include <SkPath.h> - -#include <memory> - -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<VertexBuffer> ambient(new VertexBuffer); - std::unique_ptr<VertexBuffer> 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 <SkColorFilter.h> #include <SkDrawLooper.h> +#include <SkPaint.h> #include <SkShader.h> namespace android { |