OSDN Git Service

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