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