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 */ 728