Glop Bitmap and RoundRect clipping support
Change-Id: I4577546a5d2e5f084cc03f39a89db9231b8111ee
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 5373275..e56988c 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -33,19 +33,91 @@
#define TRIGGER_STAGE(stageFlag) \
LOG_ALWAYS_FATAL_IF(stageFlag & mStageFlags, "Stage %d cannot be run twice"); \
- mStageFlags = static_cast<StageFlags>(mStageFlags | stageFlag)
+ mStageFlags = static_cast<StageFlags>(mStageFlags | (stageFlag))
#define REQUIRE_STAGES(requiredFlags) \
- LOG_ALWAYS_FATAL_IF((mStageFlags & requiredFlags) != requiredFlags, \
+ LOG_ALWAYS_FATAL_IF((mStageFlags & (requiredFlags)) != (requiredFlags), \
"not prepared for current stage")
+static void setUnitQuadTextureCoords(Rect uvs, TextureVertex* quadVertex) {;
+ TextureVertex::setUV(quadVertex++, uvs.left, uvs.top);
+ TextureVertex::setUV(quadVertex++, uvs.right, uvs.top);
+ TextureVertex::setUV(quadVertex++, uvs.left, uvs.bottom);
+ TextureVertex::setUV(quadVertex++, uvs.right, uvs.bottom);
+}
+
GlopBuilder::GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop)
: mRenderState(renderState)
, mCaches(caches)
- , mOutGlop(outGlop){
+ , mOutGlop(outGlop) {
mStageFlags = kInitialStage;
}
+////////////////////////////////////////////////////////////////////////////////
+// Mesh
+////////////////////////////////////////////////////////////////////////////////
+
+GlopBuilder& GlopBuilder::setMeshUnitQuad() {
+ TRIGGER_STAGE(kMeshStage);
+
+ mOutGlop->mesh.vertexFlags = kNone_Attrib;
+ mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
+ mOutGlop->mesh.vertexBufferObject = mRenderState.meshState().getUnitQuadVBO();
+ mOutGlop->mesh.vertices = nullptr;
+ mOutGlop->mesh.indexBufferObject = 0;
+ mOutGlop->mesh.indices = nullptr;
+ mOutGlop->mesh.elementCount = 4;
+ mOutGlop->mesh.stride = kTextureVertexStride;
+ mOutGlop->mesh.texCoordOffset = nullptr;
+ return *this;
+}
+
+GlopBuilder& GlopBuilder::setMeshTexturedUnitQuad(const UvMapper* uvMapper,
+ bool isAlphaMaskTexture) {
+ TRIGGER_STAGE(kMeshStage);
+
+ mOutGlop->mesh.vertexFlags = kTextureCoord_Attrib;
+ mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
+
+ if (CC_UNLIKELY(uvMapper)) {
+ Rect uvs(0, 0, 1, 1);
+ uvMapper->map(uvs);
+ setUnitQuadTextureCoords(uvs, &mOutGlop->mesh.mappedVertices[0]);
+
+ mOutGlop->mesh.vertexBufferObject = 0;
+ mOutGlop->mesh.vertices = &mOutGlop->mesh.mappedVertices[0];
+ } else {
+ // standard UV coordinates, use regular unit quad VBO
+ mOutGlop->mesh.vertexBufferObject = mRenderState.meshState().getUnitQuadVBO();
+ mOutGlop->mesh.vertices = nullptr;
+ }
+ mOutGlop->mesh.indexBufferObject = 0;
+ mOutGlop->mesh.indices = nullptr;
+ mOutGlop->mesh.elementCount = 4;
+ mOutGlop->mesh.stride = kTextureVertexStride;
+ mOutGlop->mesh.texCoordOffset = (GLvoid*) kMeshTextureOffset;
+
+ mDescription.hasTexture = true;
+ mDescription.hasAlpha8Texture = isAlphaMaskTexture;
+ return *this;
+}
+
+GlopBuilder& GlopBuilder::setMeshIndexedQuads(void* vertexData, int quadCount) {
+ TRIGGER_STAGE(kMeshStage);
+
+ mOutGlop->mesh.vertexFlags = kNone_Attrib;
+ mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
+ mOutGlop->mesh.vertexBufferObject = 0;
+ mOutGlop->mesh.vertices = vertexData;
+ mOutGlop->mesh.indexBufferObject = mRenderState.meshState().getQuadListIBO();
+ mOutGlop->mesh.indices = nullptr;
+ mOutGlop->mesh.elementCount = 6 * quadCount;
+ mOutGlop->mesh.stride = kVertexStride;
+ mOutGlop->mesh.texCoordOffset = nullptr;
+
+ return *this;
+}
+
GlopBuilder& GlopBuilder::setMeshVertexBuffer(const VertexBuffer& vertexBuffer, bool shadowInterp) {
TRIGGER_STAGE(kMeshStage);
@@ -59,7 +131,7 @@
mOutGlop->mesh.vertices = vertexBuffer.getBuffer();
mOutGlop->mesh.indexBufferObject = 0;
mOutGlop->mesh.indices = vertexBuffer.getIndices();
- mOutGlop->mesh.vertexCount = indices
+ mOutGlop->mesh.elementCount = indices
? vertexBuffer.getIndexCount() : vertexBuffer.getVertexCount();
mOutGlop->mesh.stride = alphaVertex ? kAlphaVertexStride : kVertexStride;
@@ -68,115 +140,35 @@
return *this;
}
-GlopBuilder& GlopBuilder::setMeshUnitQuad() {
- TRIGGER_STAGE(kMeshStage);
+////////////////////////////////////////////////////////////////////////////////
+// Fill
+////////////////////////////////////////////////////////////////////////////////
- mOutGlop->mesh.vertexFlags = kNone_Attrib;
- mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
- mOutGlop->mesh.vertexBufferObject = mRenderState.meshState().getUnitQuadVBO();
- mOutGlop->mesh.vertices = nullptr;
- mOutGlop->mesh.indexBufferObject = 0;
- mOutGlop->mesh.indices = nullptr;
- mOutGlop->mesh.vertexCount = 4;
- mOutGlop->mesh.stride = kTextureVertexStride;
- return *this;
-}
-
-GlopBuilder& GlopBuilder::setMeshIndexedQuads(void* vertexData, int quadCount) {
- TRIGGER_STAGE(kMeshStage);
-
- mOutGlop->mesh.vertexFlags = kNone_Attrib;
- mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
- mOutGlop->mesh.vertexBufferObject = 0;
- mOutGlop->mesh.vertices = vertexData;
- mOutGlop->mesh.indexBufferObject = mRenderState.meshState().getQuadListIBO();
- mOutGlop->mesh.indices = nullptr;
- mOutGlop->mesh.vertexCount = 6 * quadCount;
- mOutGlop->mesh.stride = kVertexStride;
-
- return *this;
-}
-
-GlopBuilder& GlopBuilder::setTransform(const Matrix4& ortho,
- const Matrix4& transform, bool fudgingOffset) {
- TRIGGER_STAGE(kTransformStage);
-
- mOutGlop->transform.ortho.load(ortho);
- mOutGlop->transform.canvas.load(transform);
- mOutGlop->transform.fudgingOffset = fudgingOffset;
- return *this;
-}
-
-GlopBuilder& GlopBuilder::setModelViewMapUnitToRect(const Rect destination) {
- TRIGGER_STAGE(kModelViewStage);
-
- mOutGlop->transform.modelView.loadTranslate(destination.left, destination.top, 0.0f);
- mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
- mOutGlop->bounds = destination;
- return *this;
-}
-
-GlopBuilder& GlopBuilder::setModelViewOffsetRect(float offsetX, float offsetY, const Rect source) {
- TRIGGER_STAGE(kModelViewStage);
-
- mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
- mOutGlop->bounds = source;
- mOutGlop->bounds.translate(offsetX, offsetY);
- return *this;
-}
-
-GlopBuilder& GlopBuilder::setOptionalPaint(const SkPaint* paint, float alphaScale) {
- if (paint) {
- return setPaint(*paint, alphaScale);
- }
-
- TRIGGER_STAGE(kFillStage);
- REQUIRE_STAGES(kMeshStage);
-
- mOutGlop->fill.color = { alphaScale, alphaScale, alphaScale, alphaScale };
-
- const bool SWAP_SRC_DST = false;
- // TODO: account for texture blend
- if (alphaScale < 1.0f
- || (mOutGlop->mesh.vertexFlags & kAlpha_Attrib)) {
- Blend::getFactors(SkXfermode::kSrcOver_Mode, SWAP_SRC_DST,
- &mOutGlop->blend.src, &mOutGlop->blend.dst);
- } else {
- mOutGlop->blend = { GL_ZERO, GL_ZERO };
- }
-
- return *this;
-}
-GlopBuilder& GlopBuilder::setPaint(const SkPaint& paint, float alphaScale) {
- TRIGGER_STAGE(kFillStage);
- REQUIRE_STAGES(kMeshStage);
-
- const SkShader* shader = paint.getShader();
- const SkColorFilter* colorFilter = paint.getColorFilter();
-
- SkXfermode::Mode mode = PaintUtils::getXfermode(paint.getXfermode());
+void GlopBuilder::setFill(int color, float alphaScale, SkXfermode::Mode mode,
+ const SkShader* shader, const SkColorFilter* colorFilter) {
if (mode != SkXfermode::kClear_Mode) {
- int color = paint.getColor();
float alpha = (SkColorGetA(color) / 255.0f) * alphaScale;
if (!shader) {
float colorScale = alpha / 255.0f;
mOutGlop->fill.color = {
- alpha,
colorScale * SkColorGetR(color),
colorScale * SkColorGetG(color),
- colorScale * SkColorGetB(color)
+ colorScale * SkColorGetB(color),
+ alpha
};
} else {
- mOutGlop->fill.color = { alpha, 1, 1, 1 };
+ mOutGlop->fill.color = { 1, 1, 1, alpha };
}
} else {
- mOutGlop->fill.color = { 1, 0, 0, 0 };
+ mOutGlop->fill.color = { 0, 0, 0, 1 };
}
const bool SWAP_SRC_DST = false;
mOutGlop->blend = { GL_ZERO, GL_ZERO };
if (mOutGlop->fill.color.a < 1.0f
|| (mOutGlop->mesh.vertexFlags & kAlpha_Attrib)
+ || (mOutGlop->fill.texture && mOutGlop->fill.texture->blend)
+ || mOutGlop->roundRectClipState
|| PaintUtils::isBlendedShader(shader)
|| PaintUtils::isBlendedColorFilter(colorFilter)
|| mode != SkXfermode::kSrcOver_Mode) {
@@ -218,10 +210,10 @@
const float alpha = SkColorGetA(color) / 255.0f;
float colorScale = alpha / 255.0f;
mOutGlop->fill.filter.color = {
- alpha,
colorScale * SkColorGetR(color),
colorScale * SkColorGetG(color),
colorScale * SkColorGetB(color),
+ alpha,
};
} else if (colorFilter->asColorMatrix(srcColorMatrix)) {
mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::kColorMatrix;
@@ -245,18 +237,151 @@
} else {
mOutGlop->fill.filterMode = ProgramDescription::kColorNone;
}
+}
+GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture, bool isAlphaMaskTexture,
+ const SkPaint* paint, float alphaScale) {
+ TRIGGER_STAGE(kFillStage);
+ REQUIRE_STAGES(kMeshStage);
+
+ mOutGlop->fill.texture = &texture;
+ mOutGlop->fill.textureFilter = PaintUtils::getFilter(paint);
+
+ if (paint) {
+ int color = paint->getColor();
+ SkShader* shader = paint->getShader();
+
+ if (!isAlphaMaskTexture) {
+ // Texture defines color, so disable shaders, and reset all non-alpha color channels
+ color |= 0x00FFFFFF;
+ shader = nullptr;
+ }
+ setFill(color, alphaScale, PaintUtils::getXfermode(paint->getXfermode()),
+ shader, paint->getColorFilter());
+ } else {
+ mOutGlop->fill.color = { alphaScale, alphaScale, alphaScale, alphaScale };
+
+ const bool SWAP_SRC_DST = false;
+ if (alphaScale < 1.0f
+ || (mOutGlop->mesh.vertexFlags & kAlpha_Attrib)
+ || texture.blend
+ || mOutGlop->roundRectClipState) {
+ Blend::getFactors(SkXfermode::kSrcOver_Mode, SWAP_SRC_DST,
+ &mOutGlop->blend.src, &mOutGlop->blend.dst);
+ } else {
+ mOutGlop->blend = { GL_ZERO, GL_ZERO };
+ }
+ }
+
+ if (isAlphaMaskTexture) {
+ mDescription.modulate = mOutGlop->fill.color.a < 1.0f
+ || mOutGlop->fill.color.r > 0.0f
+ || mOutGlop->fill.color.g > 0.0f
+ || mOutGlop->fill.color.b > 0.0f;
+ } else {
+ mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
+ }
return *this;
}
+GlopBuilder& GlopBuilder::setFillPaint(const SkPaint& paint, float alphaScale) {
+ TRIGGER_STAGE(kFillStage);
+ REQUIRE_STAGES(kMeshStage);
+
+ mOutGlop->fill.texture = nullptr;
+ mOutGlop->fill.textureFilter = GL_NEAREST;
+
+ setFill(paint.getColor(), alphaScale, PaintUtils::getXfermode(paint.getXfermode()),
+ paint.getShader(), paint.getColorFilter());
+ mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
+ return *this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Transform
+////////////////////////////////////////////////////////////////////////////////
+
+GlopBuilder& GlopBuilder::setTransformClip(const Matrix4& ortho,
+ const Matrix4& transform, bool fudgingOffset) {
+ TRIGGER_STAGE(kTransformStage);
+
+ mOutGlop->transform.ortho.load(ortho);
+ mOutGlop->transform.canvas.load(transform);
+ mOutGlop->transform.fudgingOffset = fudgingOffset;
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// ModelView
+////////////////////////////////////////////////////////////////////////////////
+
+GlopBuilder& GlopBuilder::setModelViewMapUnitToRect(const Rect destination) {
+ TRIGGER_STAGE(kModelViewStage);
+
+ mOutGlop->transform.modelView.loadTranslate(destination.left, destination.top, 0.0f);
+ mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
+ mOutGlop->bounds = destination;
+ return *this;
+}
+
+GlopBuilder& GlopBuilder::setModelViewMapUnitToRectSnap(const Rect destination) {
+ TRIGGER_STAGE(kModelViewStage);
+ REQUIRE_STAGES(kTransformStage | kFillStage);
+
+ float left = destination.left;
+ float top = destination.top;
+
+ const Matrix4& canvasTransform = mOutGlop->transform.canvas;
+ if (CC_LIKELY(canvasTransform.isPureTranslate())) {
+ const float translateX = canvasTransform.getTranslateX();
+ const float translateY = canvasTransform.getTranslateY();
+
+ left = (int) floorf(left + translateX + 0.5f) - translateX;
+ top = (int) floorf(top + translateY + 0.5f) - translateY;
+ mOutGlop->fill.textureFilter = GL_NEAREST;
+ }
+
+ mOutGlop->transform.modelView.loadTranslate(left, top, 0.0f);
+ mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
+ mOutGlop->bounds = destination;
+ return *this;
+}
+
+GlopBuilder& GlopBuilder::setModelViewOffsetRect(float offsetX, float offsetY, const Rect source) {
+ TRIGGER_STAGE(kModelViewStage);
+
+ mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
+ mOutGlop->bounds = source;
+ mOutGlop->bounds.translate(offsetX, offsetY);
+ return *this;
+}
+
+GlopBuilder& GlopBuilder::setRoundRectClipState(const RoundRectClipState* roundRectClipState) {
+ TRIGGER_STAGE(kRoundRectClipStage);
+
+ mOutGlop->roundRectClipState = roundRectClipState;
+ mDescription.hasRoundRectClip = roundRectClipState != nullptr;
+ return *this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Build
+////////////////////////////////////////////////////////////////////////////////
+
void GlopBuilder::build() {
REQUIRE_STAGES(kAllStages);
- mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
mOutGlop->fill.program = mCaches.programCache.get(mDescription);
mOutGlop->transform.canvas.mapRect(mOutGlop->bounds);
+
+ // duplicates ProgramCache's definition of color uniform presence
+ const bool singleColor = !mDescription.hasTexture
+ && !mDescription.hasExternalTexture
+ && !mDescription.hasGradient
+ && !mDescription.hasBitmap;
+ mOutGlop->fill.colorEnabled = mDescription.modulate || singleColor;
}
} /* namespace uirenderer */
} /* namespace android */
-