1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "GlopBuilder.h"
17 
18 #include "Caches.h"
19 #include "GlLayer.h"
20 #include "Glop.h"
21 #include "Layer.h"
22 #include "Matrix.h"
23 #include "Patch.h"
24 #include "PathCache.h"
25 #include "renderstate/MeshState.h"
26 #include "renderstate/RenderState.h"
27 #include "SkiaShader.h"
28 #include "Texture.h"
29 #include "utils/PaintUtils.h"
30 #include "VertexBuffer.h"
31 
32 #include <GLES2/gl2.h>
33 #include <SkPaint.h>
34 
35 #define DEBUG_GLOP_BUILDER 0
36 
37 #if DEBUG_GLOP_BUILDER
38 
39 #define TRIGGER_STAGE(stageFlag) \
40     LOG_ALWAYS_FATAL_IF((stageFlag) & mStageFlags, "Stage %d cannot be run twice", (stageFlag)); \
41     mStageFlags = static_cast<StageFlags>(mStageFlags | (stageFlag))
42 
43 #define REQUIRE_STAGES(requiredFlags) \
44     LOG_ALWAYS_FATAL_IF((mStageFlags & (requiredFlags)) != (requiredFlags), \
45             "not prepared for current stage")
46 
47 #else
48 
49 #define TRIGGER_STAGE(stageFlag) ((void)0)
50 #define REQUIRE_STAGES(requiredFlags) ((void)0)
51 
52 #endif
53 
54 namespace android {
55 namespace uirenderer {
56 
setUnitQuadTextureCoords(Rect uvs,TextureVertex * quadVertex)57 static void setUnitQuadTextureCoords(Rect uvs, TextureVertex* quadVertex) {
58     quadVertex[0] = {0, 0, uvs.left, uvs.top};
59     quadVertex[1] = {1, 0, uvs.right, uvs.top};
60     quadVertex[2] = {0, 1, uvs.left, uvs.bottom};
61     quadVertex[3] = {1, 1, uvs.right, uvs.bottom};
62 }
63 
GlopBuilder(RenderState & renderState,Caches & caches,Glop * outGlop)64 GlopBuilder::GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop)
65         : mRenderState(renderState)
66         , mCaches(caches)
67         , mShader(nullptr)
68         , mOutGlop(outGlop) {
69     mStageFlags = kInitialStage;
70 }
71 
72 ////////////////////////////////////////////////////////////////////////////////
73 // Mesh
74 ////////////////////////////////////////////////////////////////////////////////
75 
setMeshTexturedIndexedVbo(GLuint vbo,GLsizei elementCount)76 GlopBuilder& GlopBuilder::setMeshTexturedIndexedVbo(GLuint vbo, GLsizei elementCount) {
77     TRIGGER_STAGE(kMeshStage);
78 
79     mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
80     mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
81     mOutGlop->mesh.vertices = {
82             vbo,
83             VertexAttribFlags::TextureCoord,
84             nullptr, (const void*) kMeshTextureOffset, nullptr,
85             kTextureVertexStride };
86     mOutGlop->mesh.elementCount = elementCount;
87     return *this;
88 }
89 
setMeshUnitQuad()90 GlopBuilder& GlopBuilder::setMeshUnitQuad() {
91     TRIGGER_STAGE(kMeshStage);
92 
93     mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
94     mOutGlop->mesh.indices = { 0, nullptr };
95     mOutGlop->mesh.vertices = {
96             mRenderState.meshState().getUnitQuadVBO(),
97             VertexAttribFlags::None,
98             nullptr, nullptr, nullptr,
99             kTextureVertexStride };
100     mOutGlop->mesh.elementCount = 4;
101     return *this;
102 }
103 
setMeshTexturedUnitQuad(const UvMapper * uvMapper)104 GlopBuilder& GlopBuilder::setMeshTexturedUnitQuad(const UvMapper* uvMapper) {
105     if (uvMapper) {
106         // can't use unit quad VBO, so build UV vertices manually
107         return setMeshTexturedUvQuad(uvMapper, Rect(1, 1));
108     }
109 
110     TRIGGER_STAGE(kMeshStage);
111 
112     mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
113     mOutGlop->mesh.indices = { 0, nullptr };
114     mOutGlop->mesh.vertices = {
115             mRenderState.meshState().getUnitQuadVBO(),
116             VertexAttribFlags::TextureCoord,
117             nullptr, (const void*) kMeshTextureOffset, nullptr,
118             kTextureVertexStride };
119     mOutGlop->mesh.elementCount = 4;
120     return *this;
121 }
122 
setMeshTexturedUvQuad(const UvMapper * uvMapper,Rect uvs)123 GlopBuilder& GlopBuilder::setMeshTexturedUvQuad(const UvMapper* uvMapper, Rect uvs) {
124     TRIGGER_STAGE(kMeshStage);
125 
126     if (CC_UNLIKELY(uvMapper)) {
127         uvMapper->map(uvs);
128     }
129     setUnitQuadTextureCoords(uvs, &mOutGlop->mesh.mappedVertices[0]);
130 
131     const TextureVertex* textureVertex = mOutGlop->mesh.mappedVertices;
132     mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
133     mOutGlop->mesh.indices = { 0, nullptr };
134     mOutGlop->mesh.vertices = {
135             0,
136             VertexAttribFlags::TextureCoord,
137             &textureVertex[0].x, &textureVertex[0].u, nullptr,
138             kTextureVertexStride };
139     mOutGlop->mesh.elementCount = 4;
140     return *this;
141 }
142 
setMeshIndexedQuads(Vertex * vertexData,int quadCount)143 GlopBuilder& GlopBuilder::setMeshIndexedQuads(Vertex* vertexData, int quadCount) {
144     TRIGGER_STAGE(kMeshStage);
145 
146     mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
147     mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
148     mOutGlop->mesh.vertices = {
149             0,
150             VertexAttribFlags::None,
151             vertexData, nullptr, nullptr,
152             kVertexStride };
153     mOutGlop->mesh.elementCount = 6 * quadCount;
154     return *this;
155 }
156 
setMeshTexturedIndexedQuads(TextureVertex * vertexData,int elementCount)157 GlopBuilder& GlopBuilder::setMeshTexturedIndexedQuads(TextureVertex* vertexData, int elementCount) {
158     TRIGGER_STAGE(kMeshStage);
159 
160     mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
161     mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
162     mOutGlop->mesh.vertices = {
163             0,
164             VertexAttribFlags::TextureCoord,
165             &vertexData[0].x, &vertexData[0].u, nullptr,
166             kTextureVertexStride };
167     mOutGlop->mesh.elementCount = elementCount;
168     return *this;
169 }
170 
setMeshColoredTexturedMesh(ColorTextureVertex * vertexData,int elementCount)171 GlopBuilder& GlopBuilder::setMeshColoredTexturedMesh(ColorTextureVertex* vertexData, int elementCount) {
172     TRIGGER_STAGE(kMeshStage);
173 
174     mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
175     mOutGlop->mesh.indices = { 0, nullptr };
176     mOutGlop->mesh.vertices = {
177             0,
178             VertexAttribFlags::TextureCoord | VertexAttribFlags::Color,
179             &vertexData[0].x, &vertexData[0].u, &vertexData[0].r,
180             kColorTextureVertexStride };
181     mOutGlop->mesh.elementCount = elementCount;
182     return *this;
183 }
184 
setMeshVertexBuffer(const VertexBuffer & vertexBuffer)185 GlopBuilder& GlopBuilder::setMeshVertexBuffer(const VertexBuffer& vertexBuffer) {
186     TRIGGER_STAGE(kMeshStage);
187 
188     const VertexBuffer::MeshFeatureFlags flags = vertexBuffer.getMeshFeatureFlags();
189 
190     bool alphaVertex = flags & VertexBuffer::kAlpha;
191     bool indices = flags & VertexBuffer::kIndices;
192 
193     mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
194     mOutGlop->mesh.indices = { 0, vertexBuffer.getIndices() };
195     mOutGlop->mesh.vertices = {
196             0,
197             alphaVertex ? VertexAttribFlags::Alpha : VertexAttribFlags::None,
198             vertexBuffer.getBuffer(), nullptr, nullptr,
199             alphaVertex ? kAlphaVertexStride : kVertexStride };
200     mOutGlop->mesh.elementCount = indices
201                 ? vertexBuffer.getIndexCount() : vertexBuffer.getVertexCount();
202     return *this;
203 }
204 
setMeshPatchQuads(const Patch & patch)205 GlopBuilder& GlopBuilder::setMeshPatchQuads(const Patch& patch) {
206     TRIGGER_STAGE(kMeshStage);
207 
208     mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
209     mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
210     mOutGlop->mesh.vertices = {
211             mCaches.patchCache.getMeshBuffer(),
212             VertexAttribFlags::TextureCoord,
213             (void*)patch.positionOffset, (void*)patch.textureOffset, nullptr,
214             kTextureVertexStride };
215     mOutGlop->mesh.elementCount = patch.indexCount;
216     return *this;
217 }
218 
219 ////////////////////////////////////////////////////////////////////////////////
220 // Fill
221 ////////////////////////////////////////////////////////////////////////////////
222 
setFill(int color,float alphaScale,SkBlendMode mode,Blend::ModeOrderSwap modeUsage,const SkShader * shader,const SkColorFilter * colorFilter)223 void GlopBuilder::setFill(int color, float alphaScale,
224         SkBlendMode mode, Blend::ModeOrderSwap modeUsage,
225         const SkShader* shader, const SkColorFilter* colorFilter) {
226     if (mode != SkBlendMode::kClear) {
227         if (!shader) {
228             FloatColor c;
229             c.set(color);
230             c.r *= alphaScale;
231             c.g *= alphaScale;
232             c.b *= alphaScale;
233             c.a *= alphaScale;
234             mOutGlop->fill.color = c;
235         } else {
236             float alpha = (SkColorGetA(color) / 255.0f) * alphaScale;
237             mOutGlop->fill.color = { 1, 1, 1, alpha };
238         }
239     } else {
240         mOutGlop->fill.color = { 0, 0, 0, 1 };
241     }
242 
243     mOutGlop->blend = { GL_ZERO, GL_ZERO };
244     if (mOutGlop->fill.color.a < 1.0f
245             || (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha)
246             || (mOutGlop->fill.texture.texture && mOutGlop->fill.texture.texture->blend)
247             || mOutGlop->roundRectClipState
248             || PaintUtils::isBlendedShader(shader)
249             || PaintUtils::isBlendedColorFilter(colorFilter)
250             || mode != SkBlendMode::kSrcOver) {
251         if (CC_LIKELY(mode <= SkBlendMode::kScreen)) {
252             Blend::getFactors(mode, modeUsage,
253                     &mOutGlop->blend.src, &mOutGlop->blend.dst);
254         } else {
255             // These blend modes are not supported by OpenGL directly and have
256             // to be implemented using shaders. Since the shader will perform
257             // the blending, don't enable GL blending off here
258             // If the blend mode cannot be implemented using shaders, fall
259             // back to the default SrcOver blend mode instead
260             if (CC_UNLIKELY(mCaches.extensions().hasFramebufferFetch())) {
261                 mDescription.framebufferMode = mode;
262                 mDescription.swapSrcDst = (modeUsage == Blend::ModeOrderSwap::Swap);
263                 // blending in shader, don't enable
264             } else {
265                 // unsupported
266                 Blend::getFactors(SkBlendMode::kSrcOver, modeUsage,
267                         &mOutGlop->blend.src, &mOutGlop->blend.dst);
268             }
269         }
270     }
271     mShader = shader; // shader resolved in ::build()
272 
273     if (colorFilter) {
274         SkColor color;
275         SkBlendMode bmode;
276         SkScalar srcColorMatrix[20];
277         if (colorFilter->asColorMode(&color, &bmode)) {
278             mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::ColorFilterMode::Blend;
279             mDescription.colorMode = bmode;
280             mOutGlop->fill.filter.color.set(color);
281         } else if (colorFilter->asColorMatrix(srcColorMatrix)) {
282             mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::ColorFilterMode::Matrix;
283 
284             float* colorMatrix = mOutGlop->fill.filter.matrix.matrix;
285             memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float));
286             memcpy(&colorMatrix[4], &srcColorMatrix[5], 4 * sizeof(float));
287             memcpy(&colorMatrix[8], &srcColorMatrix[10], 4 * sizeof(float));
288             memcpy(&colorMatrix[12], &srcColorMatrix[15], 4 * sizeof(float));
289 
290             // Skia uses the range [0..255] for the addition vector, but we need
291             // the [0..1] range to apply the vector in GLSL
292             float* colorVector = mOutGlop->fill.filter.matrix.vector;
293             colorVector[0] = EOCF(srcColorMatrix[4]  / 255.0f);
294             colorVector[1] = EOCF(srcColorMatrix[9]  / 255.0f);
295             colorVector[2] = EOCF(srcColorMatrix[14] / 255.0f);
296             colorVector[3] =      srcColorMatrix[19] / 255.0f;  // alpha is linear
297         } else {
298             LOG_ALWAYS_FATAL("unsupported ColorFilter");
299         }
300     } else {
301         mOutGlop->fill.filterMode = ProgramDescription::ColorFilterMode::None;
302     }
303 }
304 
setFillTexturePaint(Texture & texture,const int textureFillFlags,const SkPaint * paint,float alphaScale)305 GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture,
306         const int textureFillFlags, const SkPaint* paint, float alphaScale) {
307     TRIGGER_STAGE(kFillStage);
308     REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
309 
310     GLenum filter = (textureFillFlags & TextureFillFlags::ForceFilter)
311             ? GL_LINEAR : PaintUtils::getFilter(paint);
312     mOutGlop->fill.texture = { &texture, filter, GL_CLAMP_TO_EDGE, nullptr };
313 
314     if (paint) {
315         int color = paint->getColor();
316         SkShader* shader = paint->getShader();
317 
318         if (!(textureFillFlags & TextureFillFlags::IsAlphaMaskTexture)) {
319             // Texture defines color, so disable shaders, and reset all non-alpha color channels
320             color |= 0x00FFFFFF;
321             shader = nullptr;
322         }
323         setFill(color, alphaScale,
324                 paint->getBlendMode(), Blend::ModeOrderSwap::NoSwap,
325                 shader, paint->getColorFilter());
326     } else {
327         mOutGlop->fill.color = { alphaScale, alphaScale, alphaScale, alphaScale };
328 
329         if (alphaScale < 1.0f
330                 || (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha)
331                 || texture.blend
332                 || mOutGlop->roundRectClipState) {
333             Blend::getFactors(SkBlendMode::kSrcOver, Blend::ModeOrderSwap::NoSwap,
334                     &mOutGlop->blend.src, &mOutGlop->blend.dst);
335         } else {
336             mOutGlop->blend = { GL_ZERO, GL_ZERO };
337         }
338     }
339 
340     if (textureFillFlags & TextureFillFlags::IsAlphaMaskTexture) {
341         mDescription.modulate = mOutGlop->fill.color.isNotBlack();
342         mDescription.hasAlpha8Texture = true;
343     } else {
344         mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
345     }
346     return *this;
347 }
348 
setFillPaint(const SkPaint & paint,float alphaScale,bool shadowInterp)349 GlopBuilder& GlopBuilder::setFillPaint(const SkPaint& paint, float alphaScale, bool shadowInterp) {
350     TRIGGER_STAGE(kFillStage);
351     REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
352 
353     if (CC_LIKELY(!shadowInterp)) {
354         mOutGlop->fill.texture = {
355                 nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
356     } else {
357         mOutGlop->fill.texture = {
358                 mCaches.textureState().getShadowLutTexture(),
359                 GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
360     }
361 
362     setFill(paint.getColor(), alphaScale,
363             paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap,
364             paint.getShader(), paint.getColorFilter());
365     mDescription.useShadowAlphaInterp = shadowInterp;
366     mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
367     return *this;
368 }
369 
setFillPathTexturePaint(PathTexture & texture,const SkPaint & paint,float alphaScale)370 GlopBuilder& GlopBuilder::setFillPathTexturePaint(PathTexture& texture,
371         const SkPaint& paint, float alphaScale) {
372     TRIGGER_STAGE(kFillStage);
373     REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
374 
375     //specify invalid filter/clamp, since these are always static for PathTextures
376     mOutGlop->fill.texture = { &texture, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
377 
378     setFill(paint.getColor(), alphaScale,
379             paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap,
380             paint.getShader(), paint.getColorFilter());
381 
382     mDescription.hasAlpha8Texture = true;
383     mDescription.modulate = mOutGlop->fill.color.isNotBlack();
384     return *this;
385 }
386 
setFillShadowTexturePaint(ShadowTexture & texture,int shadowColor,const SkPaint & paint,float alphaScale)387 GlopBuilder& GlopBuilder::setFillShadowTexturePaint(ShadowTexture& texture, int shadowColor,
388         const SkPaint& paint, float alphaScale) {
389     TRIGGER_STAGE(kFillStage);
390     REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
391 
392     //specify invalid filter/clamp, since these are always static for ShadowTextures
393     mOutGlop->fill.texture = { &texture, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
394 
395     const int ALPHA_BITMASK = SK_ColorBLACK;
396     const int COLOR_BITMASK = ~ALPHA_BITMASK;
397     if ((shadowColor & ALPHA_BITMASK) == ALPHA_BITMASK) {
398         // shadow color is fully opaque: override its alpha with that of paint
399         shadowColor &= paint.getColor() | COLOR_BITMASK;
400     }
401 
402     setFill(shadowColor, alphaScale,
403             paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap,
404             paint.getShader(), paint.getColorFilter());
405 
406     mDescription.hasAlpha8Texture = true;
407     mDescription.modulate = mOutGlop->fill.color.isNotBlack();
408     return *this;
409 }
410 
setFillBlack()411 GlopBuilder& GlopBuilder::setFillBlack() {
412     TRIGGER_STAGE(kFillStage);
413     REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
414 
415     mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
416     setFill(SK_ColorBLACK, 1.0f, SkBlendMode::kSrcOver, Blend::ModeOrderSwap::NoSwap,
417             nullptr, nullptr);
418     return *this;
419 }
420 
setFillClear()421 GlopBuilder& GlopBuilder::setFillClear() {
422     TRIGGER_STAGE(kFillStage);
423     REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
424 
425     mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
426     setFill(SK_ColorBLACK, 1.0f, SkBlendMode::kClear, Blend::ModeOrderSwap::NoSwap,
427             nullptr, nullptr);
428     return *this;
429 }
430 
setFillLayer(Texture & texture,const SkColorFilter * colorFilter,float alpha,SkBlendMode mode,Blend::ModeOrderSwap modeUsage)431 GlopBuilder& GlopBuilder::setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
432         float alpha, SkBlendMode mode, Blend::ModeOrderSwap modeUsage) {
433     TRIGGER_STAGE(kFillStage);
434     REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
435 
436     mOutGlop->fill.texture = { &texture, GL_LINEAR, GL_CLAMP_TO_EDGE, nullptr };
437 
438     setFill(SK_ColorWHITE, alpha, mode, modeUsage, nullptr, colorFilter);
439 
440     mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
441     return *this;
442 }
443 
setFillTextureLayer(GlLayer & layer,float alpha)444 GlopBuilder& GlopBuilder::setFillTextureLayer(GlLayer& layer, float alpha) {
445     TRIGGER_STAGE(kFillStage);
446     REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
447 
448     mOutGlop->fill.texture = { &(layer.getTexture()),
449             GL_LINEAR, GL_CLAMP_TO_EDGE, &layer.getTexTransform() };
450 
451     setFill(SK_ColorWHITE, alpha, layer.getMode(), Blend::ModeOrderSwap::NoSwap,
452             nullptr, layer.getColorFilter());
453 
454     mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
455     mDescription.hasTextureTransform = true;
456     return *this;
457 }
458 
setFillExternalTexture(Texture & texture,Matrix4 & textureTransform,bool requiresFilter)459 GlopBuilder& GlopBuilder::setFillExternalTexture(Texture& texture, Matrix4& textureTransform,
460         bool requiresFilter) {
461     TRIGGER_STAGE(kFillStage);
462     REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
463 
464     GLenum filter = requiresFilter ? GL_LINEAR : GL_NEAREST;
465     mOutGlop->fill.texture = { &texture, filter, GL_CLAMP_TO_EDGE, &textureTransform };
466 
467     setFill(SK_ColorWHITE, 1.0f, SkBlendMode::kSrc, Blend::ModeOrderSwap::NoSwap,
468             nullptr, nullptr);
469 
470     mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
471     mDescription.hasTextureTransform = true;
472     return *this;
473 }
474 
setGammaCorrection(bool enabled)475 GlopBuilder& GlopBuilder::setGammaCorrection(bool enabled) {
476     REQUIRE_STAGES(kFillStage);
477 
478     mDescription.hasGammaCorrection = enabled;
479     return *this;
480 }
481 
482 ////////////////////////////////////////////////////////////////////////////////
483 // Transform
484 ////////////////////////////////////////////////////////////////////////////////
485 
setTransform(const Matrix4 & canvas,const int transformFlags)486 GlopBuilder& GlopBuilder::setTransform(const Matrix4& canvas, const int transformFlags) {
487     TRIGGER_STAGE(kTransformStage);
488 
489     mOutGlop->transform.canvas = canvas;
490     mOutGlop->transform.transformFlags = transformFlags;
491     return *this;
492 }
493 
494 ////////////////////////////////////////////////////////////////////////////////
495 // ModelView
496 ////////////////////////////////////////////////////////////////////////////////
497 
setModelViewMapUnitToRect(const Rect destination)498 GlopBuilder& GlopBuilder::setModelViewMapUnitToRect(const Rect destination) {
499     TRIGGER_STAGE(kModelViewStage);
500 
501     mOutGlop->transform.modelView.loadTranslate(destination.left, destination.top, 0.0f);
502     mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
503     return *this;
504 }
505 
setModelViewMapUnitToRectSnap(const Rect destination)506 GlopBuilder& GlopBuilder::setModelViewMapUnitToRectSnap(const Rect destination) {
507     TRIGGER_STAGE(kModelViewStage);
508     REQUIRE_STAGES(kTransformStage | kFillStage);
509 
510     float left = destination.left;
511     float top = destination.top;
512 
513     const Matrix4& meshTransform = mOutGlop->transform.meshTransform();
514     if (CC_LIKELY(meshTransform.isPureTranslate())) {
515         // snap by adjusting the model view matrix
516         const float translateX = meshTransform.getTranslateX();
517         const float translateY = meshTransform.getTranslateY();
518 
519         left = (int) floorf(left + translateX + 0.5f) - translateX;
520         top = (int) floorf(top + translateY + 0.5f) - translateY;
521         mOutGlop->fill.texture.filter = GL_NEAREST;
522     }
523 
524     mOutGlop->transform.modelView.loadTranslate(left, top, 0.0f);
525     mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
526     return *this;
527 }
528 
setModelViewOffsetRect(float offsetX,float offsetY,const Rect source)529 GlopBuilder& GlopBuilder::setModelViewOffsetRect(float offsetX, float offsetY, const Rect source) {
530     TRIGGER_STAGE(kModelViewStage);
531 
532     mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
533     return *this;
534 }
535 
setModelViewOffsetRectSnap(float offsetX,float offsetY,const Rect source)536 GlopBuilder& GlopBuilder::setModelViewOffsetRectSnap(float offsetX, float offsetY, const Rect source) {
537     TRIGGER_STAGE(kModelViewStage);
538     REQUIRE_STAGES(kTransformStage | kFillStage);
539 
540     const Matrix4& meshTransform = mOutGlop->transform.meshTransform();
541     if (CC_LIKELY(meshTransform.isPureTranslate())) {
542         // snap by adjusting the model view matrix
543         const float translateX = meshTransform.getTranslateX();
544         const float translateY = meshTransform.getTranslateY();
545 
546         offsetX = (int) floorf(offsetX + translateX + source.left + 0.5f) - translateX - source.left;
547         offsetY = (int) floorf(offsetY + translateY + source.top + 0.5f) - translateY - source.top;
548         mOutGlop->fill.texture.filter = GL_NEAREST;
549     }
550 
551     mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
552     return *this;
553 }
554 
555 ////////////////////////////////////////////////////////////////////////////////
556 // RoundRectClip
557 ////////////////////////////////////////////////////////////////////////////////
558 
setRoundRectClipState(const RoundRectClipState * roundRectClipState)559 GlopBuilder& GlopBuilder::setRoundRectClipState(const RoundRectClipState* roundRectClipState) {
560     TRIGGER_STAGE(kRoundRectClipStage);
561 
562     mOutGlop->roundRectClipState = roundRectClipState;
563     mDescription.hasRoundRectClip = roundRectClipState != nullptr;
564     return *this;
565 }
566 
567 ////////////////////////////////////////////////////////////////////////////////
568 // Build
569 ////////////////////////////////////////////////////////////////////////////////
570 
verify(const ProgramDescription & description,const Glop & glop)571 void verify(const ProgramDescription& description, const Glop& glop) {
572     if (glop.fill.texture.texture != nullptr) {
573         LOG_ALWAYS_FATAL_IF(((description.hasTexture && description.hasExternalTexture)
574                         || (!description.hasTexture
575                                 && !description.hasExternalTexture
576                                 && !description.useShadowAlphaInterp)
577                         || ((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) == 0
578                                 && !description.useShadowAlphaInterp)),
579                 "Texture %p, hT%d, hET %d, attribFlags %x",
580                 glop.fill.texture.texture,
581                 description.hasTexture, description.hasExternalTexture,
582                 glop.mesh.vertices.attribFlags);
583     } else {
584         LOG_ALWAYS_FATAL_IF((description.hasTexture
585                         || description.hasExternalTexture
586                         || ((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) != 0)),
587                 "No texture, hT%d, hET %d, attribFlags %x",
588                 description.hasTexture, description.hasExternalTexture,
589                 glop.mesh.vertices.attribFlags);
590     }
591 
592     if ((glop.mesh.vertices.attribFlags & VertexAttribFlags::Alpha)
593             && glop.mesh.vertices.bufferObject) {
594         LOG_ALWAYS_FATAL("VBO and alpha attributes are not currently compatible");
595     }
596 
597     if (description.hasTextureTransform != (glop.fill.texture.textureTransform != nullptr)) {
598         LOG_ALWAYS_FATAL("Texture transform incorrectly specified");
599     }
600 }
601 
build()602 void GlopBuilder::build() {
603     REQUIRE_STAGES(kAllStages);
604     if (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) {
605         Texture* texture = mOutGlop->fill.texture.texture;
606         if (texture->target() == GL_TEXTURE_2D) {
607             mDescription.hasTexture = true;
608         } else {
609             mDescription.hasExternalTexture = true;
610         }
611         mDescription.hasLinearTexture = texture->isLinear();
612         mDescription.hasColorSpaceConversion = texture->hasColorSpaceConversion();
613         mDescription.transferFunction = texture->getTransferFunctionType();
614         mDescription.hasTranslucentConversion = texture->blend;
615     }
616 
617     mDescription.hasColors = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Color;
618     mDescription.hasVertexAlpha = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha;
619 
620     // Enable debug highlight when what we're about to draw is tested against
621     // the stencil buffer and if stencil highlight debugging is on
622     mDescription.hasDebugHighlight = !Properties::debugOverdraw
623             && Properties::debugStencilClip == StencilClipDebug::ShowHighlight
624             && mRenderState.stencil().isTestEnabled();
625 
626     // serialize shader info into ShaderData
627     GLuint textureUnit = mOutGlop->fill.texture.texture ? 1 : 0;
628 
629     if (CC_LIKELY(!mShader)) {
630         mOutGlop->fill.skiaShaderData.skiaShaderType = kNone_SkiaShaderType;
631     } else {
632         Matrix4 shaderMatrix;
633         if (mOutGlop->transform.transformFlags & TransformFlags::MeshIgnoresCanvasTransform) {
634             // canvas level transform was built into the modelView and geometry,
635             // so the shader matrix must reverse this
636             shaderMatrix.loadInverse(mOutGlop->transform.canvas);
637             shaderMatrix.multiply(mOutGlop->transform.modelView);
638         } else {
639             shaderMatrix = mOutGlop->transform.modelView;
640         }
641         SkiaShader::store(mCaches, *mShader, shaderMatrix,
642                 &textureUnit, &mDescription, &(mOutGlop->fill.skiaShaderData));
643     }
644 
645     // duplicates ProgramCache's definition of color uniform presence
646     const bool singleColor = !mDescription.hasTexture
647             && !mDescription.hasExternalTexture
648             && !mDescription.hasGradient
649             && !mDescription.hasBitmap;
650     mOutGlop->fill.colorEnabled = mDescription.modulate || singleColor;
651 
652     verify(mDescription, *mOutGlop);
653 
654     // Final step: populate program and map bounds into render target space
655     mOutGlop->fill.program = mCaches.programCache.get(mDescription);
656 }
657 
dump(const Glop & glop)658 void GlopBuilder::dump(const Glop& glop) {
659     ALOGD("Glop Mesh");
660     const Glop::Mesh& mesh = glop.mesh;
661     ALOGD("    primitive mode: %d", mesh.primitiveMode);
662     ALOGD("    indices: buffer obj %x, indices %p", mesh.indices.bufferObject, mesh.indices.indices);
663 
664     const Glop::Mesh::Vertices& vertices = glop.mesh.vertices;
665     ALOGD("    vertices: buffer obj %x, flags %x, pos %p, tex %p, clr %p, stride %d",
666             vertices.bufferObject, vertices.attribFlags,
667             vertices.position, vertices.texCoord, vertices.color, vertices.stride);
668     ALOGD("    element count: %d", mesh.elementCount);
669 
670     ALOGD("Glop Fill");
671     const Glop::Fill& fill = glop.fill;
672     ALOGD("    program %p", fill.program);
673     if (fill.texture.texture) {
674         ALOGD("    texture %p, target %d, filter %d, clamp %d",
675                 fill.texture.texture, fill.texture.texture->target(),
676                 fill.texture.filter, fill.texture.clamp);
677         if (fill.texture.textureTransform) {
678             fill.texture.textureTransform->dump("texture transform");
679         }
680     }
681     ALOGD_IF(fill.colorEnabled, "    color (argb) %.2f %.2f %.2f %.2f",
682             fill.color.a, fill.color.r, fill.color.g, fill.color.b);
683     ALOGD_IF(fill.filterMode != ProgramDescription::ColorFilterMode::None,
684             "    filterMode %d", (int)fill.filterMode);
685     ALOGD_IF(fill.skiaShaderData.skiaShaderType, "    shader type %d",
686             fill.skiaShaderData.skiaShaderType);
687 
688     ALOGD("Glop transform");
689     glop.transform.modelView.dump("  model view");
690     glop.transform.canvas.dump("  canvas");
691     ALOGD_IF(glop.transform.transformFlags, "  transformFlags 0x%x", glop.transform.transformFlags);
692 
693     ALOGD_IF(glop.roundRectClipState, "Glop RRCS %p", glop.roundRectClipState);
694 
695     ALOGD("Glop blend %d %d", glop.blend.src, glop.blend.dst);
696 }
697 
698 } /* namespace uirenderer */
699 } /* namespace android */
700