summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/hwui/DisplayListRenderer.h2
-rw-r--r--libs/hwui/FontRenderer.cpp49
-rw-r--r--libs/hwui/Glop.h2
-rw-r--r--libs/hwui/GlopBuilder.cpp89
-rw-r--r--libs/hwui/GlopBuilder.h23
-rw-r--r--libs/hwui/JankTracker.cpp25
-rw-r--r--libs/hwui/JankTracker.h3
-rw-r--r--libs/hwui/Layer.cpp17
-rw-r--r--libs/hwui/Layer.h38
-rw-r--r--libs/hwui/LayerCache.cpp3
-rw-r--r--libs/hwui/LayerRenderer.cpp3
-rw-r--r--libs/hwui/OpenGLRenderer.cpp231
-rwxr-xr-xlibs/hwui/OpenGLRenderer.h4
-rw-r--r--libs/hwui/Patch.cpp34
-rw-r--r--libs/hwui/Patch.h19
-rw-r--r--libs/hwui/PatchCache.cpp32
-rw-r--r--libs/hwui/PatchCache.h2
-rw-r--r--libs/hwui/ProgramCache.cpp6
-rw-r--r--libs/hwui/Rect.h7
-rw-r--r--libs/hwui/SkiaCanvas.cpp1
-rw-r--r--libs/hwui/SkiaCanvasProxy.cpp15
-rw-r--r--libs/hwui/SkiaCanvasProxy.h10
-rw-r--r--libs/hwui/renderstate/RenderState.cpp12
-rw-r--r--libs/hwui/utils/Macros.h12
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); \
} \