diff options
Diffstat (limited to 'libs')
-rw-r--r-- | libs/hwui/DisplayListRenderer.h | 2 | ||||
-rw-r--r-- | libs/hwui/FontRenderer.cpp | 49 | ||||
-rw-r--r-- | libs/hwui/Glop.h | 2 | ||||
-rw-r--r-- | libs/hwui/GlopBuilder.cpp | 89 | ||||
-rw-r--r-- | libs/hwui/GlopBuilder.h | 23 | ||||
-rw-r--r-- | libs/hwui/JankTracker.cpp | 25 | ||||
-rw-r--r-- | libs/hwui/JankTracker.h | 3 | ||||
-rw-r--r-- | libs/hwui/Layer.cpp | 17 | ||||
-rw-r--r-- | libs/hwui/Layer.h | 38 | ||||
-rw-r--r-- | libs/hwui/LayerCache.cpp | 3 | ||||
-rw-r--r-- | libs/hwui/LayerRenderer.cpp | 3 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 231 | ||||
-rwxr-xr-x | libs/hwui/OpenGLRenderer.h | 4 | ||||
-rw-r--r-- | libs/hwui/Patch.cpp | 34 | ||||
-rw-r--r-- | libs/hwui/Patch.h | 19 | ||||
-rw-r--r-- | libs/hwui/PatchCache.cpp | 32 | ||||
-rw-r--r-- | libs/hwui/PatchCache.h | 2 | ||||
-rw-r--r-- | libs/hwui/ProgramCache.cpp | 6 | ||||
-rw-r--r-- | libs/hwui/Rect.h | 7 | ||||
-rw-r--r-- | libs/hwui/SkiaCanvas.cpp | 1 | ||||
-rw-r--r-- | libs/hwui/SkiaCanvasProxy.cpp | 15 | ||||
-rw-r--r-- | libs/hwui/SkiaCanvasProxy.h | 10 | ||||
-rw-r--r-- | libs/hwui/renderstate/RenderState.cpp | 12 | ||||
-rw-r--r-- | libs/hwui/utils/Macros.h | 12 |
24 files changed, 370 insertions, 269 deletions
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index 71c1fc3bb7d7..d313c18077f8 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -216,7 +216,7 @@ public: virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount, const float* verts, const float* tex, const int* colors, const uint16_t* indices, int indexCount, const SkPaint& paint) override - { LOG_ALWAYS_FATAL("DisplayListRenderer does not support drawVertices()"); } + { /* DisplayListRenderer does not support drawVertices(); ignore */ } // Bitmap-based virtual void drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) override; diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 55b2d196b604..d1d2fccb55aa 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -24,6 +24,7 @@ #include "Rect.h" #include "renderstate/RenderState.h" #include "utils/Blur.h" +#include "utils/MathUtils.h" #include "utils/Timing.h" #include <SkGlyph.h> @@ -47,7 +48,6 @@ namespace uirenderer { // TextSetupFunctor /////////////////////////////////////////////////////////////////////////////// status_t TextSetupFunctor::setup(GLenum glyphFormat) { - renderer->setupDraw(); renderer->setupDrawTextGamma(paint); renderer->setupDrawDirtyRegionsDisabled(); @@ -94,20 +94,23 @@ status_t TextSetupFunctor::setup(GLenum glyphFormat) { static bool sLogFontRendererCreate = true; -FontRenderer::FontRenderer() : - mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity) { +FontRenderer::FontRenderer() + : mGammaTable(nullptr) + , mCurrentFont(nullptr) + , mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity) + , mCurrentCacheTexture(nullptr) + , mUploadTexture(false) + , mFunctor(nullptr) + , mClip(nullptr) + , mBounds(nullptr) + , mDrawn(false) + , mInitialized(false) + , mLinearFiltering(false) { if (sLogFontRendererCreate) { INIT_LOGD("Creating FontRenderer"); } - mGammaTable = nullptr; - mInitialized = false; - - mCurrentCacheTexture = nullptr; - - mLinearFiltering = false; - mSmallCacheWidth = DEFAULT_TEXT_SMALL_CACHE_WIDTH; mSmallCacheHeight = DEFAULT_TEXT_SMALL_CACHE_HEIGHT; mLargeCacheWidth = DEFAULT_TEXT_LARGE_CACHE_WIDTH; @@ -131,10 +134,11 @@ FontRenderer::FontRenderer() : } uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize; - mSmallCacheWidth = mSmallCacheWidth > maxTextureSize ? maxTextureSize : mSmallCacheWidth; - mSmallCacheHeight = mSmallCacheHeight > maxTextureSize ? maxTextureSize : mSmallCacheHeight; - mLargeCacheWidth = mLargeCacheWidth > maxTextureSize ? maxTextureSize : mLargeCacheWidth; - mLargeCacheHeight = mLargeCacheHeight > maxTextureSize ? maxTextureSize : mLargeCacheHeight; + + mSmallCacheWidth = MathUtils::min(mSmallCacheWidth, maxTextureSize); + mSmallCacheHeight = MathUtils::min(mSmallCacheHeight, maxTextureSize); + mLargeCacheWidth = MathUtils::min(mLargeCacheWidth, maxTextureSize); + mLargeCacheHeight = MathUtils::min(mLargeCacheHeight, maxTextureSize); if (sLogFontRendererCreate) { INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i", @@ -493,22 +497,19 @@ void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) { CacheTexture* texture = cacheTextures[i]; if (texture->canDraw()) { if (first) { - if (mFunctor) { - mFunctor->setup(texture->getFormat()); - } + mFunctor->setup(texture->getFormat()); checkTextureUpdate(); renderState.meshState().bindQuadIndicesBuffer(); - if (!mDrawn) { - // If returns true, a VBO was bound and we must - // rebind our vertex attrib pointers even if - // they have the same values as the current pointers - forceRebind = renderState.meshState().unbindMeshBuffer(); - } + // If returns true, a VBO was bound and we must + // rebind our vertex attrib pointers even if + // they have the same values as the current pointers + forceRebind = renderState.meshState().unbindMeshBuffer(); caches.textureState().activateTexture(0); first = false; + mDrawn = true; } caches.textureState().bindTexture(texture->getTextureId()); @@ -531,8 +532,6 @@ void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) { void FontRenderer::issueDrawCommand() { issueDrawCommand(mACacheTextures); issueDrawCommand(mRGBACacheTextures); - - mDrawn = true; } void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1, diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h index 62da6e086531..2c6f6c120d16 100644 --- a/libs/hwui/Glop.h +++ b/libs/hwui/Glop.h @@ -78,7 +78,7 @@ struct Glop { // TODO: enforce mutual exclusion with restricted setters and/or unions struct Vertices { GLuint bufferObject; - VertexAttribFlags flags; + int attribFlags; const void* position; const void* texCoord; const void* color; diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp index 3108a8dd42c3..1d0795166c95 100644 --- a/libs/hwui/GlopBuilder.cpp +++ b/libs/hwui/GlopBuilder.cpp @@ -18,6 +18,7 @@ #include "Caches.h" #include "Glop.h" #include "Matrix.h" +#include "Patch.h" #include "renderstate/MeshState.h" #include "renderstate/RenderState.h" #include "SkiaShader.h" @@ -65,7 +66,7 @@ GlopBuilder& GlopBuilder::setMeshUnitQuad() { mOutGlop->mesh.indices = { 0, nullptr }; mOutGlop->mesh.vertices = { mRenderState.meshState().getUnitQuadVBO(), - VertexAttribFlags::kNone, + static_cast<int>(VertexAttribFlags::kNone), nullptr, nullptr, nullptr, kTextureVertexStride }; mOutGlop->mesh.elementCount = 4; @@ -84,7 +85,7 @@ GlopBuilder& GlopBuilder::setMeshTexturedUnitQuad(const UvMapper* uvMapper) { mOutGlop->mesh.indices = { 0, nullptr }; mOutGlop->mesh.vertices = { mRenderState.meshState().getUnitQuadVBO(), - VertexAttribFlags::kTextureCoord, + static_cast<int>(VertexAttribFlags::kTextureCoord), nullptr, (const void*) kMeshTextureOffset, nullptr, kTextureVertexStride }; mOutGlop->mesh.elementCount = 4; @@ -104,7 +105,7 @@ GlopBuilder& GlopBuilder::setMeshTexturedUvQuad(const UvMapper* uvMapper, Rect u mOutGlop->mesh.indices = { 0, nullptr }; mOutGlop->mesh.vertices = { 0, - VertexAttribFlags::kTextureCoord, + static_cast<int>(VertexAttribFlags::kTextureCoord), &textureVertex[0].x, &textureVertex[0].u, nullptr, kTextureVertexStride }; mOutGlop->mesh.elementCount = 4; @@ -118,7 +119,7 @@ GlopBuilder& GlopBuilder::setMeshIndexedQuads(Vertex* vertexData, int quadCount) mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr }; mOutGlop->mesh.vertices = { 0, - VertexAttribFlags::kNone, + static_cast<int>(VertexAttribFlags::kNone), vertexData, nullptr, nullptr, kVertexStride }; mOutGlop->mesh.elementCount = 6 * quadCount; @@ -132,7 +133,21 @@ GlopBuilder& GlopBuilder::setMeshTexturedIndexedQuads(TextureVertex* vertexData, mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr }; mOutGlop->mesh.vertices = { 0, - VertexAttribFlags::kTextureCoord, + static_cast<int>(VertexAttribFlags::kTextureCoord), + &vertexData[0].x, &vertexData[0].u, nullptr, + kTextureVertexStride }; + mOutGlop->mesh.elementCount = elementCount; + return *this; +} + +GlopBuilder& GlopBuilder::setMeshTexturedMesh(TextureVertex* vertexData, int elementCount) { + TRIGGER_STAGE(kMeshStage); + + mOutGlop->mesh.primitiveMode = GL_TRIANGLES; + mOutGlop->mesh.indices = { 0, nullptr }; + mOutGlop->mesh.vertices = { + 0, + static_cast<int>(VertexAttribFlags::kTextureCoord), &vertexData[0].x, &vertexData[0].u, nullptr, kTextureVertexStride }; mOutGlop->mesh.elementCount = elementCount; @@ -146,7 +161,7 @@ GlopBuilder& GlopBuilder::setMeshColoredTexturedMesh(ColorTextureVertex* vertexD mOutGlop->mesh.indices = { 0, nullptr }; mOutGlop->mesh.vertices = { 0, - static_cast<VertexAttribFlags>(VertexAttribFlags::kTextureCoord | VertexAttribFlags::kColor), + VertexAttribFlags::kTextureCoord | VertexAttribFlags::kColor, &vertexData[0].x, &vertexData[0].u, &vertexData[0].r, kColorTextureVertexStride }; mOutGlop->mesh.elementCount = elementCount; @@ -165,7 +180,7 @@ GlopBuilder& GlopBuilder::setMeshVertexBuffer(const VertexBuffer& vertexBuffer, mOutGlop->mesh.indices = { 0, vertexBuffer.getIndices() }; mOutGlop->mesh.vertices = { 0, - alphaVertex ? VertexAttribFlags::kAlpha : VertexAttribFlags::kNone, + static_cast<int>(alphaVertex ? VertexAttribFlags::kAlpha : VertexAttribFlags::kNone), vertexBuffer.getBuffer(), nullptr, nullptr, alphaVertex ? kAlphaVertexStride : kVertexStride }; mOutGlop->mesh.elementCount = indices @@ -175,6 +190,20 @@ GlopBuilder& GlopBuilder::setMeshVertexBuffer(const VertexBuffer& vertexBuffer, return *this; } +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(), + static_cast<int>(VertexAttribFlags::kTextureCoord), + (void*)patch.positionOffset, (void*)patch.textureOffset, nullptr, + kTextureVertexStride }; + mOutGlop->mesh.elementCount = patch.indexCount; + return *this; +} + //////////////////////////////////////////////////////////////////////////////// // Fill //////////////////////////////////////////////////////////////////////////////// @@ -201,7 +230,7 @@ void GlopBuilder::setFill(int color, float alphaScale, SkXfermode::Mode mode, mOutGlop->blend = { GL_ZERO, GL_ZERO }; if (mOutGlop->fill.color.a < 1.0f - || (mOutGlop->mesh.vertices.flags & VertexAttribFlags::kAlpha) + || (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kAlpha) || (mOutGlop->fill.texture.texture && mOutGlop->fill.texture.texture->blend) || mOutGlop->roundRectClipState || PaintUtils::isBlendedShader(shader) @@ -269,19 +298,21 @@ void GlopBuilder::setFill(int color, float alphaScale, SkXfermode::Mode mode, } } -GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture, bool isAlphaMaskTexture, +GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture, int textureFillFlags, const SkPaint* paint, float alphaScale) { TRIGGER_STAGE(kFillStage); REQUIRE_STAGES(kMeshStage); + GLenum filter = (textureFillFlags & TextureFillFlags::kForceFilter) + ? GL_LINEAR : PaintUtils::getFilter(paint); mOutGlop->fill.texture = { &texture, - GL_TEXTURE_2D, PaintUtils::getFilter(paint), GL_CLAMP_TO_EDGE, nullptr }; + GL_TEXTURE_2D, filter, GL_CLAMP_TO_EDGE, nullptr }; if (paint) { int color = paint->getColor(); SkShader* shader = paint->getShader(); - if (!isAlphaMaskTexture) { + if (!(textureFillFlags & TextureFillFlags::kIsAlphaMaskTexture)) { // Texture defines color, so disable shaders, and reset all non-alpha color channels color |= 0x00FFFFFF; shader = nullptr; @@ -293,7 +324,7 @@ GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture, bool isAlphaMask const bool SWAP_SRC_DST = false; if (alphaScale < 1.0f - || (mOutGlop->mesh.vertices.flags & VertexAttribFlags::kAlpha) + || (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kAlpha) || texture.blend || mOutGlop->roundRectClipState) { Blend::getFactors(SkXfermode::kSrcOver_Mode, SWAP_SRC_DST, @@ -303,9 +334,9 @@ GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture, bool isAlphaMask } } - mDescription.hasAlpha8Texture = isAlphaMaskTexture; - if (isAlphaMaskTexture) { + if (textureFillFlags & TextureFillFlags::kIsAlphaMaskTexture) { mDescription.modulate = mOutGlop->fill.color.isNotBlack(); + mDescription.hasAlpha8Texture = true; } else { mDescription.modulate = mOutGlop->fill.color.a < 1.0f; } @@ -487,6 +518,7 @@ GlopBuilder& GlopBuilder::setModelViewOffsetRectSnap(float offsetX, float offset } mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f); + mOutGlop->bounds = source; mOutGlop->bounds.translate(offsetX, offsetY); return *this; } @@ -508,12 +540,25 @@ GlopBuilder& GlopBuilder::setRoundRectClipState(const RoundRectClipState* roundR //////////////////////////////////////////////////////////////////////////////// void verify(const ProgramDescription& description, const Glop& glop) { - bool hasTexture = glop.fill.texture.texture != nullptr; - LOG_ALWAYS_FATAL_IF(description.hasTexture && description.hasExternalTexture); - LOG_ALWAYS_FATAL_IF((description.hasTexture || description.hasExternalTexture )!= hasTexture); - LOG_ALWAYS_FATAL_IF((glop.mesh.vertices.flags & VertexAttribFlags::kTextureCoord) != hasTexture); + if (glop.fill.texture.texture != nullptr) { + LOG_ALWAYS_FATAL_IF(((description.hasTexture && description.hasExternalTexture) + || (!description.hasTexture && !description.hasExternalTexture) + || ((glop.mesh.vertices.attribFlags & VertexAttribFlags::kTextureCoord) == 0)), + "Texture %p, hT%d, hET %d, attribFlags %x", + glop.fill.texture.texture, + description.hasTexture, description.hasExternalTexture, + glop.mesh.vertices.attribFlags); + } else { + LOG_ALWAYS_FATAL_IF((description.hasTexture + || description.hasExternalTexture + || ((glop.mesh.vertices.attribFlags & VertexAttribFlags::kTextureCoord) != 0)), + "No texture, hT%d, hET %d, attribFlags %x", + description.hasTexture, description.hasExternalTexture, + glop.mesh.vertices.attribFlags); + } - if ((glop.mesh.vertices.flags & VertexAttribFlags::kAlpha) && glop.mesh.vertices.bufferObject) { + if ((glop.mesh.vertices.attribFlags & VertexAttribFlags::kAlpha) + && glop.mesh.vertices.bufferObject) { LOG_ALWAYS_FATAL("VBO and alpha attributes are not currently compatible"); } @@ -524,12 +569,12 @@ void verify(const ProgramDescription& description, const Glop& glop) { void GlopBuilder::build() { REQUIRE_STAGES(kAllStages); - if (mOutGlop->mesh.vertices.flags & VertexAttribFlags::kTextureCoord) { + if (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kTextureCoord) { mDescription.hasTexture = mOutGlop->fill.texture.target == GL_TEXTURE_2D; mDescription.hasExternalTexture = mOutGlop->fill.texture.target == GL_TEXTURE_EXTERNAL_OES; } - mDescription.hasColors = mOutGlop->mesh.vertices.flags & VertexAttribFlags::kColor; - mDescription.hasVertexAlpha = mOutGlop->mesh.vertices.flags & VertexAttribFlags::kAlpha; + mDescription.hasColors = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kColor; + mDescription.hasVertexAlpha = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kAlpha; // serialize shader info into ShaderData GLuint textureUnit = mOutGlop->fill.texture.texture ? 1 : 0; diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h index 4b871d5de564..74d4889dfdc4 100644 --- a/libs/hwui/GlopBuilder.h +++ b/libs/hwui/GlopBuilder.h @@ -33,6 +33,13 @@ class Texture; class VertexBuffer; struct Glop; +enum class TextureFillFlags { + kNone = 0, + kIsAlphaMaskTexture = 1 << 0, + kForceFilter = 1 << 1, +}; +MAKE_FLAGS_ENUM(TextureFillFlags); + class GlopBuilder { PREVENT_COPY_AND_ASSIGN(GlopBuilder); public: @@ -43,11 +50,13 @@ public: GlopBuilder& setMeshTexturedUvQuad(const UvMapper* uvMapper, const Rect uvs); GlopBuilder& setMeshVertexBuffer(const VertexBuffer& vertexBuffer, bool shadowInterp); GlopBuilder& setMeshIndexedQuads(Vertex* vertexData, int quadCount); - GlopBuilder& setMeshColoredTexturedMesh(ColorTextureVertex* vertexData, int elementCount); + GlopBuilder& setMeshTexturedMesh(TextureVertex* vertexData, int elementCount); // TODO: use indexed quads + GlopBuilder& setMeshColoredTexturedMesh(ColorTextureVertex* vertexData, int elementCount); // TODO: use indexed quads GlopBuilder& setMeshTexturedIndexedQuads(TextureVertex* vertexData, int elementCount); // TODO: take quadCount + GlopBuilder& setMeshPatchQuads(const Patch& patch); GlopBuilder& setFillPaint(const SkPaint& paint, float alphaScale); - GlopBuilder& setFillTexturePaint(Texture& texture, bool isAlphaMaskTexture, + GlopBuilder& setFillTexturePaint(Texture& texture, int textureFillFlags, const SkPaint* paint, float alphaScale); GlopBuilder& setFillPathTexturePaint(PathTexture& texture, const SkPaint& paint, float alphaScale); @@ -63,7 +72,7 @@ public: GlopBuilder& setModelViewMapUnitToRect(const Rect destination); GlopBuilder& setModelViewMapUnitToRectSnap(const Rect destination); - GlopBuilder& setModelViewMapUnitToRectOptionalSnap(bool snap, const Rect destination) { + GlopBuilder& setModelViewMapUnitToRectOptionalSnap(bool snap, const Rect& destination) { if (snap) { return setModelViewMapUnitToRectSnap(destination); } else { @@ -72,6 +81,14 @@ public: } GlopBuilder& setModelViewOffsetRect(float offsetX, float offsetY, const Rect source); GlopBuilder& setModelViewOffsetRectSnap(float offsetX, float offsetY, const Rect source); + GlopBuilder& setModelViewOffsetRectOptionalSnap(bool snap, + float offsetX, float offsetY, const Rect& source) { + if (snap) { + return setModelViewOffsetRectSnap(offsetX, offsetY, source); + } else { + return setModelViewOffsetRect(offsetX, offsetY, source); + } + } GlopBuilder& setRoundRectClipState(const RoundRectClipState* roundRectClipState); diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp index d0ea3a6dfa2d..46b094556ad7 100644 --- a/libs/hwui/JankTracker.cpp +++ b/libs/hwui/JankTracker.cpp @@ -15,6 +15,7 @@ */ #include "JankTracker.h" +#include <algorithm> #include <cstdio> #include <inttypes.h> @@ -95,7 +96,12 @@ void JankTracker::addFrame(const FrameInfo& frame) { // Fast-path for jank-free frames int64_t totalDuration = frame[FrameInfoIndex::kFrameCompleted] - frame[FrameInfoIndex::kIntendedVsync]; + uint32_t framebucket = std::min( + static_cast<typeof sizeof(mFrameCounts)>(ns2ms(totalDuration)), + sizeof(mFrameCounts) / sizeof(mFrameCounts[0])); + // Keep the fast path as fast as possible. if (CC_LIKELY(totalDuration < mFrameInterval)) { + mFrameCounts[framebucket]++; return; } @@ -103,6 +109,7 @@ void JankTracker::addFrame(const FrameInfo& frame) { return; } + mFrameCounts[framebucket]++; mJankFrameCount++; for (int i = 0; i < NUM_BUCKETS; i++) { @@ -119,6 +126,9 @@ void JankTracker::dump(int fd) { fprintf(file, "\n Total frames rendered: %u", mTotalFrameCount); fprintf(file, "\n Janky frames: %u (%.2f%%)", mJankFrameCount, (float) mJankFrameCount / (float) mTotalFrameCount * 100.0f); + fprintf(file, "\n 90th percentile: %ums", findPercentile(90)); + fprintf(file, "\n 95th percentile: %ums", findPercentile(95)); + fprintf(file, "\n 99th percentile: %ums", findPercentile(99)); for (int i = 0; i < NUM_BUCKETS; i++) { fprintf(file, "\n Number %s: %u", JANK_TYPE_NAMES[i], mBuckets[i].count); } @@ -127,10 +137,23 @@ void JankTracker::dump(int fd) { } void JankTracker::reset() { - memset(mBuckets, 0, sizeof(JankBucket) * NUM_BUCKETS); + memset(mBuckets, 0, sizeof(mBuckets)); + memset(mFrameCounts, 0, sizeof(mFrameCounts)); mTotalFrameCount = 0; mJankFrameCount = 0; } +uint32_t JankTracker::findPercentile(int percentile) { + int pos = percentile * mTotalFrameCount / 100; + int remaining = mTotalFrameCount - pos; + for (int i = sizeof(mFrameCounts) / sizeof(mFrameCounts[0]) - 1; i >= 0; i--) { + remaining -= mFrameCounts[i]; + if (remaining <= 0) { + return i; + } + } + return 0; +} + } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h index aa554cd65664..3d4929b215c6 100644 --- a/libs/hwui/JankTracker.h +++ b/libs/hwui/JankTracker.h @@ -54,8 +54,11 @@ public: void reset(); private: + uint32_t findPercentile(int p); + JankBucket mBuckets[NUM_BUCKETS]; int64_t mThresholds[NUM_BUCKETS]; + uint32_t mFrameCounts[128]; int64_t mFrameInterval; uint32_t mTotalFrameCount; diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index 7a026ef6b325..458f35b6b49b 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -37,7 +37,7 @@ namespace android { namespace uirenderer { -Layer::Layer(Type layerType, RenderState& renderState, const uint32_t layerWidth, const uint32_t layerHeight) +Layer::Layer(Type layerType, RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight) : state(kState_Uncached) , caches(Caches::getInstance()) , renderState(renderState) @@ -46,24 +46,9 @@ Layer::Layer(Type layerType, RenderState& renderState, const uint32_t layerWidth // TODO: This is a violation of Android's typical ref counting, but it // preserves the old inc/dec ref locations. This should be changed... incStrong(nullptr); - mesh = nullptr; - meshElementCount = 0; - cacheable = true; - dirty = false; renderTarget = GL_TEXTURE_2D; texture.width = layerWidth; texture.height = layerHeight; - colorFilter = nullptr; - deferredUpdateScheduled = false; - renderNode = nullptr; - fbo = 0; - stencil = nullptr; - debugDrawUpdate = false; - hasDrawnSinceUpdate = false; - forceFilter = false; - convexMask = nullptr; - rendererLightPosDirty = true; - wasBuildLayered = false; renderState.registerLayer(this); } diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index 3c1f1d1846dd..b670870ca55f 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -72,7 +72,7 @@ public: }; State state; // public for logging/debugging purposes - Layer(Type type, RenderState& renderState, const uint32_t layerWidth, const uint32_t layerHeight); + Layer(Type type, RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight); ~Layer(); static uint32_t computeIdealWidth(uint32_t layerWidth); @@ -324,19 +324,19 @@ public: /** * If the layer can be rendered as a mesh, this is non-null. */ - TextureVertex* mesh; - GLsizei meshElementCount; + TextureVertex* mesh = nullptr; + GLsizei meshElementCount = 0; /** * Used for deferred updates. */ - bool deferredUpdateScheduled; + bool deferredUpdateScheduled = false; std::unique_ptr<OpenGLRenderer> renderer; sp<RenderNode> renderNode; Rect dirtyRect; - bool debugDrawUpdate; - bool hasDrawnSinceUpdate; - bool wasBuildLayered; + bool debugDrawUpdate = false; + bool hasDrawnSinceUpdate = false; + bool wasBuildLayered = false; private: void requireRenderer(); @@ -350,17 +350,17 @@ private: * Name of the FBO used to render the layer. If the name is 0 * this layer is not backed by an FBO, but a simple texture. */ - GLuint fbo; + GLuint fbo = 0; /** * The render buffer used as the stencil buffer. */ - RenderBuffer* stencil; + RenderBuffer* stencil = nullptr; /** * Indicates whether this layer has been used already. */ - bool empty; + bool empty = true; /** * The texture backing this layer. @@ -370,7 +370,7 @@ private: /** * If set to true (by default), the layer can be reused. */ - bool cacheable; + bool cacheable = true; /** * Denotes whether the layer is a DisplayList, or Texture layer. @@ -381,32 +381,32 @@ private: * When set to true, this layer is dirty and should be cleared * before any rendering occurs. */ - bool dirty; + bool dirty = false; /** * Indicates the render target. */ - GLenum renderTarget; + GLenum renderTarget = GL_TEXTURE_2D; /** * Color filter used to draw this layer. Optional. */ - SkColorFilter* colorFilter; + SkColorFilter* colorFilter = nullptr; /** * Indicates raster data backing the layer is scaled, requiring filtration. */ - bool forceFilter; + bool forceFilter = false; /** * Opacity of the layer. */ - int alpha; + int alpha = 255; /** * Blending mode of the layer. */ - SkXfermode::Mode mode; + SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode; /** * Optional texture coordinates transform. @@ -422,7 +422,7 @@ private: * Cached transform of layer in window, updated only on creation / resize */ mat4 cachedInvTransformInWindow; - bool rendererLightPosDirty; + bool rendererLightPosDirty = true; /** * Used to defer display lists when the layer is updated with a @@ -435,7 +435,7 @@ private: * * Data not owned/managed by layer object. */ - const SkPath* convexMask; + const SkPath* convexMask = nullptr; }; // struct Layer diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp index 60d4f4fe6bb5..bcbd4129b7e7 100644 --- a/libs/hwui/LayerCache.cpp +++ b/libs/hwui/LayerCache.cpp @@ -116,9 +116,6 @@ Layer* LayerCache::get(RenderState& renderState, const uint32_t width, const uin layer = new Layer(Layer::kType_DisplayList, renderState, entry.mWidth, entry.mHeight); layer->setBlend(true); - layer->setEmpty(true); - layer->setFbo(0); - layer->generateTexture(); layer->bindTexture(); layer->setFilter(GL_NEAREST); diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index 13262063bc18..223bdf06dca9 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -275,9 +275,6 @@ Layer* LayerRenderer::createTextureLayer(RenderState& renderState) { Layer* layer = new Layer(Layer::kType_Texture, renderState, 0, 0); layer->setCacheable(false); - layer->setEmpty(true); - layer->setFbo(0); - layer->setAlpha(255, SkXfermode::kSrcOver_Mode); layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f); layer->texCoords.set(0.0f, 1.0f, 1.0f, 0.0f); layer->region.clear(); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index cef3326d1c02..a6f6e18a2a4e 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -883,8 +883,8 @@ void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) { && !layer->getForceFilter() && layer->getWidth() == (uint32_t) rect.getWidth() && layer->getHeight() == (uint32_t) rect.getHeight()) { - const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f); - const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f); + const float x = floorf(rect.left + currentTransform()->getTranslateX() + 0.5f); + const float y = floorf(rect.top + currentTransform()->getTranslateY() + 0.5f); layer->setFilter(GL_NEAREST); setupDrawModelView(kModelViewMode_TranslateAndScale, false, @@ -921,8 +921,8 @@ void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) if (simpleTransform) { // When we're swapping, the layer is already in screen coordinates if (!swap) { - x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f); - y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f); + x = floorf(rect.left + currentTransform()->getTranslateX() + 0.5f); + y = floorf(rect.top + currentTransform()->getTranslateY() + 0.5f); } layer->setFilter(GL_NEAREST, true); @@ -1076,8 +1076,8 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { setupDrawColorFilterUniforms(layer->getColorFilter()); setupDrawTexture(layer->getTextureId()); if (currentTransform()->isPureTranslate()) { - const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f); - const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f); + const float x = floorf(rect.left + currentTransform()->getTranslateX() + 0.5f); + const float y = floorf(rect.top + currentTransform()->getTranslateY() + 0.5f); layer->setFilter(GL_NEAREST); setupDrawModelView(kModelViewMode_Translate, false, @@ -1169,7 +1169,7 @@ void OpenGLRenderer::drawRegionRects(const SkRegion& region, const SkPaint& pain } void OpenGLRenderer::dirtyLayer(const float left, const float top, - const float right, const float bottom, const mat4 transform) { + const float right, const float bottom, const Matrix4& transform) { if (hasLayer()) { Rect bounds(left, top, right, bottom); transform.mapRect(bounds); @@ -2004,8 +2004,8 @@ void OpenGLRenderer::drawAlphaBitmap(Texture* texture, const SkPaint* paint) { bool ignoreTransform = false; if (currentTransform()->isPureTranslate()) { - x = (int) floorf(currentTransform()->getTranslateX() + 0.5f); - y = (int) floorf(currentTransform()->getTranslateY() + 0.5f); + x = floorf(currentTransform()->getTranslateX() + 0.5f); + y = floorf(currentTransform()->getTranslateY() + 0.5f); ignoreTransform = true; texture->setFilter(GL_NEAREST, true); @@ -2028,17 +2028,37 @@ void OpenGLRenderer::drawAlphaBitmap(Texture* texture, const SkPaint* paint) { void OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry, int bitmapCount, TextureVertex* vertices, bool pureTranslate, const Rect& bounds, const SkPaint* paint) { - mCaches.textureState().activateTexture(0); Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap); if (!texture) return; const AutoTexture autoCleanup(texture); + if (USE_GLOPS) { + // TODO: remove layer dirty in multi-draw callers + // TODO: snap doesn't need to touch transform, only texture filter. + bool snap = pureTranslate; + const float x = floorf(bounds.left + 0.5f); + const float y = floorf(bounds.top + 0.5f); + int textureFillFlags = static_cast<int>((bitmap->colorType() == kAlpha_8_SkColorType) + ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone); + Glop glop; + GlopBuilder(mRenderState, mCaches, &glop) + .setMeshTexturedMesh(vertices, bitmapCount * 6) + .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) + .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false) + .setModelViewOffsetRectOptionalSnap(snap, x, y, Rect(0, 0, bounds.getWidth(), bounds.getHeight())) + .setRoundRectClipState(currentSnapshot()->roundRectClipState) + .build(); + renderGlop(glop); + return; + } + + mCaches.textureState().activateTexture(0); texture->setWrap(GL_CLAMP_TO_EDGE, true); texture->setFilter(pureTranslate ? GL_NEAREST : PaintUtils::getFilter(paint), true); - const float x = (int) floorf(bounds.left + 0.5f); - const float y = (int) floorf(bounds.top + 0.5f); + const float x = floorf(bounds.left + 0.5f); + const float y = floorf(bounds.top + 0.5f); if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) { drawAlpha8TextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(), texture->id, paint, &vertices[0].x, &vertices[0].u, @@ -2065,11 +2085,12 @@ void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) { const AutoTexture autoCleanup(texture); if (USE_GLOPS) { - bool isAlpha8Texture = bitmap->colorType() == kAlpha_8_SkColorType; + int textureFillFlags = static_cast<int>((bitmap->colorType() == kAlpha_8_SkColorType) + ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone); Glop glop; GlopBuilder(mRenderState, mCaches, &glop) .setMeshTexturedUnitQuad(texture->uvMapper) - .setFillTexturePaint(*texture, isAlpha8Texture, paint, currentSnapshot()->alpha) + .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false) .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height)) .setRoundRectClipState(currentSnapshot()->roundRectClipState) @@ -2166,11 +2187,10 @@ void OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int m * TODO: handle alpha_8 textures correctly by applying paint color, but *not* * shader in that case to mimic the behavior in SkiaCanvas::drawBitmapMesh. */ - bool isAlpha8Texture = false; Glop glop; GlopBuilder(mRenderState, mCaches, &glop) .setMeshColoredTexturedMesh(mesh.get(), elementCount) - .setFillTexturePaint(*texture, isAlpha8Texture, paint, currentSnapshot()->alpha) + .setFillTexturePaint(*texture, static_cast<int>(TextureFillFlags::kNone), paint, currentSnapshot()->alpha) .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false) .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom)) .setRoundRectClipState(currentSnapshot()->roundRectClipState) @@ -2229,11 +2249,12 @@ void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst, cons fmin(1.0f, src.right / texture->width), fmin(1.0f, src.bottom / texture->height)); - bool isAlpha8Texture = bitmap->colorType() == kAlpha_8_SkColorType; + int textureFillFlags = static_cast<int>((bitmap->colorType() == kAlpha_8_SkColorType) + ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone); Glop glop; GlopBuilder(mRenderState, mCaches, &glop) .setMeshTexturedUvQuad(texture->uvMapper, uv) - .setFillTexturePaint(*texture, isAlpha8Texture, paint, currentSnapshot()->alpha) + .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false) .setModelViewMapUnitToRectSnap(dst) .setRoundRectClipState(currentSnapshot()->roundRectClipState) @@ -2266,8 +2287,8 @@ void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst, cons bool ignoreTransform = false; if (CC_LIKELY(currentTransform()->isPureTranslate())) { - float x = (int) floorf(dst.left + currentTransform()->getTranslateX() + 0.5f); - float y = (int) floorf(dst.top + currentTransform()->getTranslateY() + 0.5f); + float x = floorf(dst.left + currentTransform()->getTranslateX() + 0.5f); + float y = floorf(dst.top + currentTransform()->getTranslateY() + 0.5f); dst.right = x + (dst.right - dst.left); dst.bottom = y + (dst.bottom - dst.top); @@ -2298,70 +2319,74 @@ void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst, cons mDirty = true; } -void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch, - float left, float top, float right, float bottom, const SkPaint* paint) { - if (quickRejectSetupScissor(left, top, right, bottom)) { +void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh, + AssetAtlas::Entry* entry, float left, float top, float right, float bottom, + const SkPaint* paint) { + if (!mesh || !mesh->verticesCount || quickRejectSetupScissor(left, top, right, bottom)) { return; } - AssetAtlas::Entry* entry = mRenderState.assetAtlas().getEntry(bitmap); - const Patch* mesh = mCaches.patchCache.get(entry, bitmap->width(), bitmap->height(), - right - left, bottom - top, patch); - - drawPatch(bitmap, mesh, entry, left, top, right, bottom, paint); -} + Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap); + if (!texture) return; -void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh, - AssetAtlas::Entry* entry, float left, float top, float right, float bottom, - const SkPaint* paint) { - if (quickRejectSetupScissor(left, top, right, bottom)) { + if (USE_GLOPS) { + // 9 patches are built for stretching - always filter + int textureFillFlags = static_cast<int>(TextureFillFlags::kForceFilter); + if (bitmap->colorType() == kAlpha_8_SkColorType) { + textureFillFlags |= TextureFillFlags::kIsAlphaMaskTexture; + } + Glop glop; + GlopBuilder(mRenderState, mCaches, &glop) + .setMeshPatchQuads(*mesh) + .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) + .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false) + .setModelViewOffsetRectSnap(left, top, Rect(0, 0, right - left, bottom - top)) // TODO: get minimal bounds from patch + .setRoundRectClipState(currentSnapshot()->roundRectClipState) + .build(); + renderGlop(glop); return; } - if (CC_LIKELY(mesh && mesh->verticesCount > 0)) { - mCaches.textureState().activateTexture(0); - Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap); - if (!texture) return; - const AutoTexture autoCleanup(texture); - - texture->setWrap(GL_CLAMP_TO_EDGE, true); - texture->setFilter(GL_LINEAR, true); - - const bool pureTranslate = currentTransform()->isPureTranslate(); - // Mark the current layer dirty where we are going to draw the patch - if (hasLayer() && mesh->hasEmptyQuads) { - const float offsetX = left + currentTransform()->getTranslateX(); - const float offsetY = top + currentTransform()->getTranslateY(); - const size_t count = mesh->quads.size(); - for (size_t i = 0; i < count; i++) { - const Rect& bounds = mesh->quads.itemAt(i); - if (CC_LIKELY(pureTranslate)) { - const float x = (int) floorf(bounds.left + offsetX + 0.5f); - const float y = (int) floorf(bounds.top + offsetY + 0.5f); - dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight()); - } else { - dirtyLayer(left + bounds.left, top + bounds.top, - left + bounds.right, top + bounds.bottom, *currentTransform()); - } + mCaches.textureState().activateTexture(0); + const AutoTexture autoCleanup(texture); + + texture->setWrap(GL_CLAMP_TO_EDGE, true); + texture->setFilter(GL_LINEAR, true); + + const bool pureTranslate = currentTransform()->isPureTranslate(); + // Mark the current layer dirty where we are going to draw the patch + if (hasLayer() && mesh->hasEmptyQuads) { + const float offsetX = left + currentTransform()->getTranslateX(); + const float offsetY = top + currentTransform()->getTranslateY(); + const size_t count = mesh->quads.size(); + for (size_t i = 0; i < count; i++) { + const Rect& bounds = mesh->quads.itemAt(i); + if (CC_LIKELY(pureTranslate)) { + const float x = floorf(bounds.left + offsetX + 0.5f); + const float y = floorf(bounds.top + offsetY + 0.5f); + dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight()); + } else { + dirtyLayer(left + bounds.left, top + bounds.top, + left + bounds.right, top + bounds.bottom, *currentTransform()); } } + } - bool ignoreTransform = false; - if (CC_LIKELY(pureTranslate)) { - const float x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f); - const float y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f); + bool ignoreTransform = false; + if (CC_LIKELY(pureTranslate)) { + const float x = floorf(left + currentTransform()->getTranslateX() + 0.5f); + const float y = floorf(top + currentTransform()->getTranslateY() + 0.5f); - right = x + right - left; - bottom = y + bottom - top; - left = x; - top = y; - ignoreTransform = true; - } - drawIndexedTextureMesh(left, top, right, bottom, texture->id, paint, - texture->blend, (GLvoid*) mesh->offset, (GLvoid*) mesh->textureOffset, - GL_TRIANGLES, mesh->indexCount, false, ignoreTransform, - mCaches.patchCache.getMeshBuffer(), kModelViewMode_Translate, !mesh->hasEmptyQuads); + right = x + right - left; + bottom = y + bottom - top; + left = x; + top = y; + ignoreTransform = true; } + drawIndexedTextureMesh(left, top, right, bottom, texture->id, paint, + texture->blend, (GLvoid*) mesh->positionOffset, (GLvoid*) mesh->textureOffset, + GL_TRIANGLES, mesh->indexCount, false, ignoreTransform, + mCaches.patchCache.getMeshBuffer(), kModelViewMode_Translate, !mesh->hasEmptyQuads); mDirty = true; } @@ -2372,18 +2397,37 @@ void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh, * The caller is responsible for properly dirtying the current layer. */ void OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry, - TextureVertex* vertices, uint32_t indexCount, const SkPaint* paint) { + TextureVertex* vertices, uint32_t elementCount, const SkPaint* paint) { mCaches.textureState().activateTexture(0); Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap); if (!texture) return; const AutoTexture autoCleanup(texture); + if (USE_GLOPS) { + // TODO: get correct bounds from caller + // 9 patches are built for stretching - always filter + int textureFillFlags = static_cast<int>(TextureFillFlags::kForceFilter); + if (bitmap->colorType() == kAlpha_8_SkColorType) { + textureFillFlags |= TextureFillFlags::kIsAlphaMaskTexture; + } + Glop glop; + GlopBuilder(mRenderState, mCaches, &glop) + .setMeshTexturedIndexedQuads(vertices, elementCount) + .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) + .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false) + .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0)) + .setRoundRectClipState(currentSnapshot()->roundRectClipState) + .build(); + renderGlop(glop); + return; + } + texture->setWrap(GL_CLAMP_TO_EDGE, true); texture->setFilter(GL_LINEAR, true); drawIndexedTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, paint, texture->blend, &vertices[0].x, &vertices[0].u, - GL_TRIANGLES, indexCount, false, true, 0, kModelViewMode_Translate, false); + GL_TRIANGLES, elementCount, false, true, 0, kModelViewMode_Translate, false); mDirty = true; } @@ -2775,8 +2819,8 @@ void OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count, float y = 0.0f; const bool pureTranslate = currentTransform()->isPureTranslate(); if (pureTranslate) { - x = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f); - y = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f); + x = floorf(x + currentTransform()->getTranslateX() + 0.5f); + y = floorf(y + currentTransform()->getTranslateY() + 0.5f); } FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint); @@ -2801,20 +2845,13 @@ void OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count, const Rect& clip(pureTranslate ? writableSnapshot()->getClipRect() : writableSnapshot()->getLocalClip()); Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); - const bool hasActiveLayer = hasLayer(); - TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint); if (fontRenderer.renderPosText(paint, &clip, text, 0, bytesCount, count, x, y, - positions, hasActiveLayer ? &bounds : nullptr, &functor)) { - if (hasActiveLayer) { - if (!pureTranslate) { - currentTransform()->mapRect(bounds); - } - dirtyLayerUnchecked(bounds, getRegion()); - } + positions, hasLayer() ? &bounds : nullptr, &functor)) { + dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform()); + mDirty = true; } - mDirty = true; } bool OpenGLRenderer::findBestFontTransform(const mat4& transform, SkMatrix* outMatrix) const { @@ -2919,8 +2956,8 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float const bool pureTranslate = transform.isPureTranslate(); if (CC_LIKELY(pureTranslate)) { - x = (int) floorf(x + transform.getTranslateX() + 0.5f); - y = (int) floorf(y + transform.getTranslateY() + 0.5f); + x = floorf(x + transform.getTranslateX() + 0.5f); + y = floorf(y + transform.getTranslateY() + 0.5f); } int alpha; @@ -3007,17 +3044,11 @@ void OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count, const Rect* clip = &writableSnapshot()->getLocalClip(); Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); - const bool hasActiveLayer = hasLayer(); - if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path, - hOffset, vOffset, hasActiveLayer ? &bounds : nullptr, &functor)) { - if (hasActiveLayer) { - currentTransform()->mapRect(bounds); - dirtyLayerUnchecked(bounds, getRegion()); - } + hOffset, vOffset, hasLayer() ? &bounds : nullptr, &functor)) { + dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform()); + mDirty = true; } - - mDirty = true; } void OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) { @@ -3109,11 +3140,9 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y) { x + layer->layer.getWidth(), y + layer->layer.getHeight()); } - TextureVertex* mesh = &layer->mesh[0]; GLsizei elementsCount = layer->meshElementCount; - while (elementsCount > 0) { GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6); @@ -3437,8 +3466,8 @@ void OpenGLRenderer::drawTextureRect(Texture* texture, const SkPaint* paint) { } if (CC_LIKELY(currentTransform()->isPureTranslate())) { - const float x = (int) floorf(currentTransform()->getTranslateX() + 0.5f); - const float y = (int) floorf(currentTransform()->getTranslateY() + 0.5f); + const float x = floorf(currentTransform()->getTranslateX() + 0.5f); + const float y = floorf(currentTransform()->getTranslateY() + 0.5f); texture->setFilter(GL_NEAREST, true); drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id, diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 63a63b83efb5..f4acad068903 100755 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -206,8 +206,6 @@ public: const float* vertices, const int* colors, const SkPaint* paint); void drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry, TextureVertex* vertices, uint32_t indexCount, const SkPaint* paint); - void drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch, - float left, float top, float right, float bottom, const SkPaint* paint); void drawPatch(const SkBitmap* bitmap, const Patch* mesh, AssetAtlas::Entry* entry, float left, float top, float right, float bottom, const SkPaint* paint); void drawColor(int color, SkXfermode::Mode mode); @@ -677,7 +675,7 @@ private: * are transformed with the supplied matrix. */ void dirtyLayer(const float left, const float top, - const float right, const float bottom, const mat4 transform); + const float right, const float bottom, const Matrix4& transform); /** * Mark the layer as dirty at the specified coordinates. diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp index 8a4d65b7aeb9..f673c6a50a24 100644 --- a/libs/hwui/Patch.cpp +++ b/libs/hwui/Patch.cpp @@ -24,18 +24,12 @@ #include "Patch.h" #include "Properties.h" #include "UvMapper.h" +#include "utils/MathUtils.h" namespace android { namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// -// Constructors/destructor -/////////////////////////////////////////////////////////////////////////////// - -Patch::Patch(): vertices(), verticesCount(0), indexCount(0), hasEmptyQuads(false) { -} - -/////////////////////////////////////////////////////////////////////////////// // Vertices management /////////////////////////////////////////////////////////////////////////////// @@ -43,19 +37,11 @@ uint32_t Patch::getSize() const { return verticesCount * sizeof(TextureVertex); } -TextureVertex* Patch::createMesh(const float bitmapWidth, const float bitmapHeight, - float width, float height, const Res_png_9patch* patch) { - UvMapper mapper; - return createMesh(bitmapWidth, bitmapHeight, width, height, mapper, patch); -} - -TextureVertex* Patch::createMesh(const float bitmapWidth, const float bitmapHeight, - float width, float height, const UvMapper& mapper, const Res_png_9patch* patch) { - if (vertices) return vertices.get(); +Patch::Patch(const float bitmapWidth, const float bitmapHeight, + float width, float height, const UvMapper& mapper, const Res_png_9patch* patch) + : mColors(patch->getColors()) { int8_t emptyQuads = 0; - mColors = patch->getColors(); - const int8_t numColors = patch->numColors; if (uint8_t(numColors) < sizeof(uint32_t) * 4) { for (int8_t i = 0; i < numColors; i++) { @@ -71,7 +57,7 @@ TextureVertex* Patch::createMesh(const float bitmapWidth, const float bitmapHeig uint32_t yCount = patch->numYDivs; uint32_t maxVertices = ((xCount + 1) * (yCount + 1) - emptyQuads) * 4; - if (maxVertices == 0) return nullptr; + if (maxVertices == 0) return; vertices.reset(new TextureVertex[maxVertices]); TextureVertex* vertex = vertices.get(); @@ -158,8 +144,6 @@ TextureVertex* Patch::createMesh(const float bitmapWidth, const float bitmapHeig memcpy(reducedVertices.get(), vertices.get(), verticesCount * sizeof(TextureVertex)); vertices = std::move(reducedVertices); } - - return vertices.get(); } void Patch::generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex, @@ -207,10 +191,10 @@ void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, f const uint32_t oldQuadCount = quadCount; quadCount++; - if (x1 < 0.0f) x1 = 0.0f; - if (x2 < 0.0f) x2 = 0.0f; - if (y1 < 0.0f) y1 = 0.0f; - if (y2 < 0.0f) y2 = 0.0f; + x1 = MathUtils::max(x1, 0.0f); + x2 = MathUtils::max(x2, 0.0f); + y1 = MathUtils::max(y1, 0.0f); + y2 = MathUtils::max(y2, 0.0f); // Skip degenerate and transparent (empty) quads if ((mColors[oldQuadCount] == 0) || x1 >= x2 || y1 >= y2) { diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h index ea8c8c23d523..b63bd24456d3 100644 --- a/libs/hwui/Patch.h +++ b/libs/hwui/Patch.h @@ -39,7 +39,9 @@ struct TextureVertex; class Patch { public: - Patch(); + Patch(const float bitmapWidth, const float bitmapHeight, + float width, float height, + const UvMapper& mapper, const Res_png_9patch* patch); /** * Returns the size of this patch's mesh in bytes. @@ -47,18 +49,13 @@ public: uint32_t getSize() const; std::unique_ptr<TextureVertex[]> vertices; - uint32_t verticesCount; - uint32_t indexCount; - bool hasEmptyQuads; + uint32_t verticesCount = 0; + uint32_t indexCount = 0; + bool hasEmptyQuads = false; Vector<Rect> quads; - GLintptr offset; - GLintptr textureOffset; - - TextureVertex* createMesh(const float bitmapWidth, const float bitmapHeight, - float width, float height, const Res_png_9patch* patch); - TextureVertex* createMesh(const float bitmapWidth, const float bitmapHeight, - float width, float height, const UvMapper& mapper, const Res_png_9patch* patch); + GLintptr positionOffset = 0; + GLintptr textureOffset = 0; private: void generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex, diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp index af403b47e92b..27652624b498 100644 --- a/libs/hwui/PatchCache.cpp +++ b/libs/hwui/PatchCache.cpp @@ -162,7 +162,7 @@ void PatchCache::clearGarbage() { // Release the patch and mark the space in the free list Patch* patch = pair.getSecond(); - BufferBlock* block = new BufferBlock(patch->offset, patch->getSize()); + BufferBlock* block = new BufferBlock(patch->positionOffset, patch->getSize()); block->next = mFreeBlocks; mFreeBlocks = block; @@ -190,7 +190,7 @@ void PatchCache::createVertexBuffer() { * Sets the mesh's offsets and copies its associated vertices into * the mesh buffer (VBO). */ -void PatchCache::setupMesh(Patch* newMesh, TextureVertex* vertices) { +void PatchCache::setupMesh(Patch* newMesh) { // This call ensures the VBO exists and that it is bound init(); @@ -223,9 +223,9 @@ void PatchCache::setupMesh(Patch* newMesh, TextureVertex* vertices) { } // Copy the 9patch mesh in the VBO - newMesh->offset = (GLintptr) (block->offset); - newMesh->textureOffset = newMesh->offset + kMeshTextureOffset; - glBufferSubData(GL_ARRAY_BUFFER, newMesh->offset, size, vertices); + newMesh->positionOffset = (GLintptr) (block->offset); + newMesh->textureOffset = newMesh->positionOffset + kMeshTextureOffset; + glBufferSubData(GL_ARRAY_BUFFER, newMesh->positionOffset, size, newMesh->vertices.get()); // Remove the block since we've used it entirely if (block->size == size) { @@ -244,6 +244,8 @@ void PatchCache::setupMesh(Patch* newMesh, TextureVertex* vertices) { mSize += size; } +static const UvMapper sIdentity; + const Patch* PatchCache::get(const AssetAtlas::Entry* entry, const uint32_t bitmapWidth, const uint32_t bitmapHeight, const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch) { @@ -252,20 +254,12 @@ const Patch* PatchCache::get(const AssetAtlas::Entry* entry, const Patch* mesh = mCache.get(description); if (!mesh) { - Patch* newMesh = new Patch(); - TextureVertex* vertices; - - if (entry) { - // An atlas entry has a UV mapper - vertices = newMesh->createMesh(bitmapWidth, bitmapHeight, - pixelWidth, pixelHeight, entry->uvMapper, patch); - } else { - vertices = newMesh->createMesh(bitmapWidth, bitmapHeight, - pixelWidth, pixelHeight, patch); - } + const UvMapper& mapper = entry ? entry->uvMapper : sIdentity; + Patch* newMesh = new Patch(bitmapWidth, bitmapHeight, + pixelWidth, pixelHeight, mapper, patch); - if (vertices) { - setupMesh(newMesh, vertices); + if (newMesh->vertices) { + setupMesh(newMesh); } #if DEBUG_PATCHES @@ -284,7 +278,7 @@ void PatchCache::dumpFreeBlocks(const char* prefix) { String8 dump; BufferBlock* block = mFreeBlocks; while (block) { - dump.appendFormat("->(%d, %d)", block->offset, block->size); + dump.appendFormat("->(%d, %d)", block->positionOffset, block->size); block = block->next; } ALOGD("%s: Free blocks%s", prefix, dump.string()); diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h index e038720ae03f..387f79acf0ec 100644 --- a/libs/hwui/PatchCache.h +++ b/libs/hwui/PatchCache.h @@ -160,7 +160,7 @@ private: void clearCache(); void createVertexBuffer(); - void setupMesh(Patch* newMesh, TextureVertex* vertices); + void setupMesh(Patch* newMesh); void remove(Vector<patch_pair_t>& patchesToRemove, Res_png_9patch* patch); diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 8c6a91ccb309..e9b22e20bc18 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -380,9 +380,9 @@ const char* gBlendOps[18] = { // 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", - // Add + // Plus "return min(src + dst, 1.0);\n", - // Multiply + // Modulate "return src * dst;\n", // Screen "return src + dst - src * dst;\n", @@ -830,7 +830,7 @@ void ProgramCache::printLongString(const String8& shader) const { while ((index = shader.find("\n", index)) > -1) { String8 line(str, index - lastIndex); if (line.length() == 0) line.append("\n"); - PROGRAM_LOGD("%s", line.string()); + ALOGD("%s", line.string()); index++; str += (index - lastIndex); lastIndex = index; diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h index 1716cf0ccb91..c82082fe9727 100644 --- a/libs/hwui/Rect.h +++ b/libs/hwui/Rect.h @@ -252,6 +252,13 @@ public: bottom = fmaxf(bottom, y); } + void expandToCoverRect(float otherLeft, float otherTop, float otherRight, float otherBottom) { + left = fminf(left, otherLeft); + top = fminf(top, otherTop); + right = fmaxf(right, otherRight); + bottom = fmaxf(bottom, otherBottom); + } + SkRect toSkRect() const { return SkRect::MakeLTRB(left, top, right, bottom); } diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index efbb7094c96a..71088b7129a4 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -22,7 +22,6 @@ #include <SkDeque.h> #include <SkDrawFilter.h> #include <SkGraphics.h> -#include <SkPorterDuff.h> #include <SkShader.h> #include <SkTArray.h> #include <SkTemplates.h> diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp index 3c6570508546..ec1bb909e6f9 100644 --- a/libs/hwui/SkiaCanvasProxy.cpp +++ b/libs/hwui/SkiaCanvasProxy.cpp @@ -22,9 +22,10 @@ namespace android { namespace uirenderer { -SkiaCanvasProxy::SkiaCanvasProxy(Canvas* canvas) +SkiaCanvasProxy::SkiaCanvasProxy(Canvas* canvas, bool filterHwuiCalls) : INHERITED(canvas->width(), canvas->height()) - , mCanvas(canvas) {} + , mCanvas(canvas) + , mFilterHwuiCalls(filterHwuiCalls) {} void SkiaCanvasProxy::onDrawPaint(const SkPaint& paint) { mCanvas->drawPaint(paint); @@ -32,6 +33,10 @@ void SkiaCanvasProxy::onDrawPaint(const SkPaint& paint) { void SkiaCanvasProxy::onDrawPoints(PointMode pointMode, size_t count, const SkPoint pts[], const SkPaint& paint) { + if (!pts || count == 0) { + return; + } + // convert the SkPoints into floats SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats); const size_t floatCount = count << 1; @@ -118,6 +123,9 @@ void SkiaCanvasProxy::onDrawSprite(const SkBitmap& bitmap, int left, int top, void SkiaCanvasProxy::onDrawVertices(VertexMode mode, int vertexCount, const SkPoint vertices[], const SkPoint texs[], const SkColor colors[], SkXfermode*, const uint16_t indices[], int indexCount, const SkPaint& paint) { + if (mFilterHwuiCalls) { + return; + } // convert the SkPoints into floats SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats); const int floatCount = vertexCount << 1; @@ -312,6 +320,9 @@ void SkiaCanvasProxy::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScala void SkiaCanvasProxy::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) { + if (mFilterHwuiCalls) { + return; + } SkPatchUtils::VertexData data; SkMatrix matrix; diff --git a/libs/hwui/SkiaCanvasProxy.h b/libs/hwui/SkiaCanvasProxy.h index 4322fcf5edf5..0de965094e64 100644 --- a/libs/hwui/SkiaCanvasProxy.h +++ b/libs/hwui/SkiaCanvasProxy.h @@ -27,16 +27,19 @@ namespace uirenderer { /** * This class serves as a proxy between Skia's SkCanvas and Android Framework's - * Canvas. The class does not maintain any state and will pass through any request - * directly to the Canvas provided in the constructor. + * Canvas. The class does not maintain any draw-related state and will pass + * through most requests directly to the Canvas provided in the constructor. * * Upon construction it is expected that the provided Canvas has already been * prepared for recording and will continue to be in the recording state while * this proxy class is being used. + * + * If filterHwuiCalls is true, the proxy silently ignores away draw calls that + * aren't supported by HWUI. */ class ANDROID_API SkiaCanvasProxy : public SkCanvas { public: - SkiaCanvasProxy(Canvas* canvas); + SkiaCanvasProxy(Canvas* canvas, bool filterHwuiCalls = false); virtual ~SkiaCanvasProxy() {} protected: @@ -94,6 +97,7 @@ protected: private: Canvas* mCanvas; + bool mFilterHwuiCalls; typedef SkCanvas INHERITED; }; diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp index ca3a4c2f2f30..7b44d6db9a81 100644 --- a/libs/hwui/renderstate/RenderState.cpp +++ b/libs/hwui/renderstate/RenderState.cpp @@ -259,7 +259,7 @@ void RenderState::render(const Glop& glop) { // indices meshState().bindIndicesBufferInternal(indices.bufferObject); - if (vertices.flags & VertexAttribFlags::kTextureCoord) { + if (vertices.attribFlags & VertexAttribFlags::kTextureCoord) { const Glop::Fill::TextureData& texture = fill.texture; // texture always takes slot 0, shader samplers increment from there mCaches->textureState().activateTexture(0); @@ -283,13 +283,13 @@ void RenderState::render(const Glop& glop) { meshState().disableTexCoordsVertexArray(); } int colorLocation = -1; - if (vertices.flags & VertexAttribFlags::kColor) { + if (vertices.attribFlags & VertexAttribFlags::kColor) { colorLocation = fill.program->getAttrib("colors"); glEnableVertexAttribArray(colorLocation); glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, vertices.stride, vertices.color); } int alphaLocation = -1; - if (vertices.flags & VertexAttribFlags::kAlpha) { + if (vertices.attribFlags & VertexAttribFlags::kAlpha) { // NOTE: alpha vertex position is computed assuming no VBO const void* alphaCoords = ((const GLbyte*) vertices.position) + kVertexAlphaOffset; alphaLocation = fill.program->getAttrib("vtxAlpha"); @@ -317,7 +317,7 @@ void RenderState::render(const Glop& glop) { // rebind pointers without forcing, since initial bind handled above meshState().bindPositionVertexPointer(false, vertexData, vertices.stride); - if (vertices.flags & VertexAttribFlags::kTextureCoord) { + if (vertices.attribFlags & VertexAttribFlags::kTextureCoord) { meshState().bindTexCoordsVertexPointer(false, vertexData + kMeshTextureOffset, vertices.stride); } @@ -335,10 +335,10 @@ void RenderState::render(const Glop& glop) { // ----------------------------------- // ---------- Mesh teardown ---------- // ----------------------------------- - if (vertices.flags & VertexAttribFlags::kAlpha) { + if (vertices.attribFlags & VertexAttribFlags::kAlpha) { glDisableVertexAttribArray(alphaLocation); } - if (vertices.flags & VertexAttribFlags::kColor) { + if (vertices.attribFlags & VertexAttribFlags::kColor) { glDisableVertexAttribArray(colorLocation); } } diff --git a/libs/hwui/utils/Macros.h b/libs/hwui/utils/Macros.h index 2ed605ee83d2..9f7ac1c4a5cf 100644 --- a/libs/hwui/utils/Macros.h +++ b/libs/hwui/utils/Macros.h @@ -36,9 +36,21 @@ #Type " must have standard layout") #define MAKE_FLAGS_ENUM(enumType) \ + inline int operator|=(int lhs, enumType rhs) { \ + return lhs | static_cast<int>(rhs); \ + } \ + inline int operator|(int lhs, enumType rhs) { \ + return lhs | static_cast<int>(rhs); \ + } \ + inline int operator|(enumType lhs, int rhs) { \ + return static_cast<int>(lhs) | rhs; \ + } \ inline int operator|(enumType lhs, enumType rhs) { \ return static_cast<int>(lhs) | static_cast<int>(rhs); \ } \ + inline int operator&=(int lhs, enumType rhs) { \ + return lhs & static_cast<int>(rhs); \ + } \ inline int operator&(int lhs, enumType rhs) { \ return lhs & static_cast<int>(rhs); \ } \ |