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 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) 66 , mCaches(caches) 67 , mShader(nullptr) 68 , mOutGlop(outGlop) { 69 mStageFlags = kInitialStage; 70 } 71 72 //////////////////////////////////////////////////////////////////////////////// 73 // Mesh 74 //////////////////////////////////////////////////////////////////////////////// 75 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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