GlopBuilder.cpp revision 8820fd1d82acaefda98ae73ccf61413d5044f9f3
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 32namespace android { 33namespace uirenderer { 34 35#define TRIGGER_STAGE(stageFlag) \ 36 LOG_ALWAYS_FATAL_IF((stageFlag) & mStageFlags, "Stage %d cannot be run twice", (stageFlag)); \ 37 mStageFlags = static_cast<StageFlags>(mStageFlags | (stageFlag)) 38 39#define REQUIRE_STAGES(requiredFlags) \ 40 LOG_ALWAYS_FATAL_IF((mStageFlags & (requiredFlags)) != (requiredFlags), \ 41 "not prepared for current stage") 42 43static void setUnitQuadTextureCoords(Rect uvs, TextureVertex* quadVertex) { 44 quadVertex[0] = {0, 0, uvs.left, uvs.top}; 45 quadVertex[1] = {1, 0, uvs.right, uvs.top}; 46 quadVertex[2] = {0, 1, uvs.left, uvs.bottom}; 47 quadVertex[3] = {1, 1, uvs.right, uvs.bottom}; 48} 49 50GlopBuilder::GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop) 51 : mRenderState(renderState) 52 , mCaches(caches) 53 , mShader(nullptr) 54 , mOutGlop(outGlop) { 55 mStageFlags = kInitialStage; 56} 57 58//////////////////////////////////////////////////////////////////////////////// 59// Mesh 60//////////////////////////////////////////////////////////////////////////////// 61 62GlopBuilder& GlopBuilder::setMeshUnitQuad() { 63 TRIGGER_STAGE(kMeshStage); 64 65 mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP; 66 mOutGlop->mesh.indices = { 0, nullptr }; 67 mOutGlop->mesh.vertices = { 68 mRenderState.meshState().getUnitQuadVBO(), 69 VertexAttribFlags::kNone, 70 nullptr, nullptr, nullptr, 71 kTextureVertexStride }; 72 mOutGlop->mesh.elementCount = 4; 73 return *this; 74} 75 76GlopBuilder& GlopBuilder::setMeshTexturedUnitQuad(const UvMapper* uvMapper) { 77 if (uvMapper) { 78 // can't use unit quad VBO, so build UV vertices manually 79 return setMeshTexturedUvQuad(uvMapper, Rect(0, 0, 1, 1)); 80 } 81 82 TRIGGER_STAGE(kMeshStage); 83 84 mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP; 85 mOutGlop->mesh.indices = { 0, nullptr }; 86 mOutGlop->mesh.vertices = { 87 mRenderState.meshState().getUnitQuadVBO(), 88 VertexAttribFlags::kTextureCoord, 89 nullptr, (const void*) kMeshTextureOffset, nullptr, 90 kTextureVertexStride }; 91 mOutGlop->mesh.elementCount = 4; 92 return *this; 93} 94 95GlopBuilder& GlopBuilder::setMeshTexturedUvQuad(const UvMapper* uvMapper, Rect uvs) { 96 TRIGGER_STAGE(kMeshStage); 97 98 if (CC_UNLIKELY(uvMapper)) { 99 uvMapper->map(uvs); 100 } 101 setUnitQuadTextureCoords(uvs, &mOutGlop->mesh.mappedVertices[0]); 102 103 const TextureVertex* textureVertex = mOutGlop->mesh.mappedVertices; 104 mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP; 105 mOutGlop->mesh.indices = { 0, nullptr }; 106 mOutGlop->mesh.vertices = { 107 0, 108 VertexAttribFlags::kTextureCoord, 109 &textureVertex[0].x, &textureVertex[0].u, nullptr, 110 kTextureVertexStride }; 111 mOutGlop->mesh.elementCount = 4; 112 return *this; 113} 114 115GlopBuilder& GlopBuilder::setMeshIndexedQuads(Vertex* vertexData, int quadCount) { 116 TRIGGER_STAGE(kMeshStage); 117 118 mOutGlop->mesh.primitiveMode = GL_TRIANGLES; 119 mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr }; 120 mOutGlop->mesh.vertices = { 121 0, 122 VertexAttribFlags::kNone, 123 vertexData, nullptr, nullptr, 124 kVertexStride }; 125 mOutGlop->mesh.elementCount = 6 * quadCount; 126 return *this; 127} 128 129GlopBuilder& GlopBuilder::setMeshTexturedIndexedQuads(TextureVertex* vertexData, int elementCount) { 130 TRIGGER_STAGE(kMeshStage); 131 132 mOutGlop->mesh.primitiveMode = GL_TRIANGLES; 133 mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr }; 134 mOutGlop->mesh.vertices = { 135 0, 136 VertexAttribFlags::kTextureCoord, 137 &vertexData[0].x, &vertexData[0].u, nullptr, 138 kTextureVertexStride }; 139 mOutGlop->mesh.elementCount = elementCount; 140 return *this; 141} 142 143GlopBuilder& GlopBuilder::setMeshTexturedMesh(TextureVertex* vertexData, int elementCount) { 144 TRIGGER_STAGE(kMeshStage); 145 146 mOutGlop->mesh.primitiveMode = GL_TRIANGLES; 147 mOutGlop->mesh.indices = { 0, nullptr }; 148 mOutGlop->mesh.vertices = { 149 0, 150 VertexAttribFlags::kTextureCoord, 151 &vertexData[0].x, &vertexData[0].u, nullptr, 152 kTextureVertexStride }; 153 mOutGlop->mesh.elementCount = elementCount; 154 return *this; 155} 156 157GlopBuilder& GlopBuilder::setMeshColoredTexturedMesh(ColorTextureVertex* vertexData, int elementCount) { 158 TRIGGER_STAGE(kMeshStage); 159 160 mOutGlop->mesh.primitiveMode = GL_TRIANGLES; 161 mOutGlop->mesh.indices = { 0, nullptr }; 162 mOutGlop->mesh.vertices = { 163 0, 164 static_cast<VertexAttribFlags>(VertexAttribFlags::kTextureCoord | VertexAttribFlags::kColor), 165 &vertexData[0].x, &vertexData[0].u, &vertexData[0].r, 166 kColorTextureVertexStride }; 167 mOutGlop->mesh.elementCount = elementCount; 168 return *this; 169} 170 171GlopBuilder& GlopBuilder::setMeshVertexBuffer(const VertexBuffer& vertexBuffer, bool shadowInterp) { 172 TRIGGER_STAGE(kMeshStage); 173 174 const VertexBuffer::MeshFeatureFlags flags = vertexBuffer.getMeshFeatureFlags(); 175 176 bool alphaVertex = flags & VertexBuffer::kAlpha; 177 bool indices = flags & VertexBuffer::kIndices; 178 179 mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP; 180 mOutGlop->mesh.indices = { 0, vertexBuffer.getIndices() }; 181 mOutGlop->mesh.vertices = { 182 0, 183 alphaVertex ? VertexAttribFlags::kAlpha : VertexAttribFlags::kNone, 184 vertexBuffer.getBuffer(), nullptr, nullptr, 185 alphaVertex ? kAlphaVertexStride : kVertexStride }; 186 mOutGlop->mesh.elementCount = indices 187 ? vertexBuffer.getIndexCount() : vertexBuffer.getVertexCount(); 188 189 mDescription.useShadowAlphaInterp = shadowInterp; 190 return *this; 191} 192 193GlopBuilder& GlopBuilder::setMeshPatchQuads(const Patch& patch) { 194 TRIGGER_STAGE(kMeshStage); 195 196 mOutGlop->mesh.primitiveMode = GL_TRIANGLES; 197 mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr }; 198 mOutGlop->mesh.vertices = { 199 mCaches.patchCache.getMeshBuffer(), 200 VertexAttribFlags::kTextureCoord, 201 (void*)patch.positionOffset, (void*)patch.textureOffset, nullptr, 202 kTextureVertexStride }; 203 mOutGlop->mesh.elementCount = patch.indexCount; 204 return *this; 205} 206 207//////////////////////////////////////////////////////////////////////////////// 208// Fill 209//////////////////////////////////////////////////////////////////////////////// 210 211void GlopBuilder::setFill(int color, float alphaScale, SkXfermode::Mode mode, 212 const SkShader* shader, const SkColorFilter* colorFilter) { 213 if (mode != SkXfermode::kClear_Mode) { 214 float alpha = (SkColorGetA(color) / 255.0f) * alphaScale; 215 if (!shader) { 216 float colorScale = alpha / 255.0f; 217 mOutGlop->fill.color = { 218 colorScale * SkColorGetR(color), 219 colorScale * SkColorGetG(color), 220 colorScale * SkColorGetB(color), 221 alpha 222 }; 223 } else { 224 mOutGlop->fill.color = { 1, 1, 1, alpha }; 225 } 226 } else { 227 mOutGlop->fill.color = { 0, 0, 0, 1 }; 228 } 229 const bool SWAP_SRC_DST = false; 230 231 mOutGlop->blend = { GL_ZERO, GL_ZERO }; 232 if (mOutGlop->fill.color.a < 1.0f 233 || (mOutGlop->mesh.vertices.flags & VertexAttribFlags::kAlpha) 234 || (mOutGlop->fill.texture.texture && mOutGlop->fill.texture.texture->blend) 235 || mOutGlop->roundRectClipState 236 || PaintUtils::isBlendedShader(shader) 237 || PaintUtils::isBlendedColorFilter(colorFilter) 238 || mode != SkXfermode::kSrcOver_Mode) { 239 if (CC_LIKELY(mode <= SkXfermode::kScreen_Mode)) { 240 Blend::getFactors(mode, SWAP_SRC_DST, 241 &mOutGlop->blend.src, &mOutGlop->blend.dst); 242 } else { 243 // These blend modes are not supported by OpenGL directly and have 244 // to be implemented using shaders. Since the shader will perform 245 // the blending, don't enable GL blending off here 246 // If the blend mode cannot be implemented using shaders, fall 247 // back to the default SrcOver blend mode instead 248 if (CC_UNLIKELY(mCaches.extensions().hasFramebufferFetch())) { 249 mDescription.framebufferMode = mode; 250 mDescription.swapSrcDst = SWAP_SRC_DST; 251 // blending in shader, don't enable 252 } else { 253 // unsupported 254 Blend::getFactors(SkXfermode::kSrcOver_Mode, SWAP_SRC_DST, 255 &mOutGlop->blend.src, &mOutGlop->blend.dst); 256 } 257 } 258 } 259 mShader = shader; // shader resolved in ::build() 260 261 if (colorFilter) { 262 SkColor color; 263 SkXfermode::Mode mode; 264 SkScalar srcColorMatrix[20]; 265 if (colorFilter->asColorMode(&color, &mode)) { 266 mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::kColorBlend; 267 mDescription.colorMode = mode; 268 269 const float alpha = SkColorGetA(color) / 255.0f; 270 float colorScale = alpha / 255.0f; 271 mOutGlop->fill.filter.color = { 272 colorScale * SkColorGetR(color), 273 colorScale * SkColorGetG(color), 274 colorScale * SkColorGetB(color), 275 alpha, 276 }; 277 } else if (colorFilter->asColorMatrix(srcColorMatrix)) { 278 mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::kColorMatrix; 279 280 float* colorMatrix = mOutGlop->fill.filter.matrix.matrix; 281 memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float)); 282 memcpy(&colorMatrix[4], &srcColorMatrix[5], 4 * sizeof(float)); 283 memcpy(&colorMatrix[8], &srcColorMatrix[10], 4 * sizeof(float)); 284 memcpy(&colorMatrix[12], &srcColorMatrix[15], 4 * sizeof(float)); 285 286 // Skia uses the range [0..255] for the addition vector, but we need 287 // the [0..1] range to apply the vector in GLSL 288 float* colorVector = mOutGlop->fill.filter.matrix.vector; 289 colorVector[0] = srcColorMatrix[4] / 255.0f; 290 colorVector[1] = srcColorMatrix[9] / 255.0f; 291 colorVector[2] = srcColorMatrix[14] / 255.0f; 292 colorVector[3] = srcColorMatrix[19] / 255.0f; 293 } else { 294 LOG_ALWAYS_FATAL("unsupported ColorFilter"); 295 } 296 } else { 297 mOutGlop->fill.filterMode = ProgramDescription::kColorNone; 298 } 299} 300 301GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture, int textureFillFlags, 302 const SkPaint* paint, float alphaScale) { 303 TRIGGER_STAGE(kFillStage); 304 REQUIRE_STAGES(kMeshStage); 305 306 GLenum filter = (textureFillFlags & TextureFillFlags::kForceFilter) 307 ? GL_LINEAR : PaintUtils::getFilter(paint); 308 mOutGlop->fill.texture = { &texture, 309 GL_TEXTURE_2D, filter, GL_CLAMP_TO_EDGE, nullptr }; 310 311 if (paint) { 312 int color = paint->getColor(); 313 SkShader* shader = paint->getShader(); 314 315 if (!(textureFillFlags & TextureFillFlags::kIsAlphaMaskTexture)) { 316 // Texture defines color, so disable shaders, and reset all non-alpha color channels 317 color |= 0x00FFFFFF; 318 shader = nullptr; 319 } 320 setFill(color, alphaScale, PaintUtils::getXfermode(paint->getXfermode()), 321 shader, paint->getColorFilter()); 322 } else { 323 mOutGlop->fill.color = { alphaScale, alphaScale, alphaScale, alphaScale }; 324 325 const bool SWAP_SRC_DST = false; 326 if (alphaScale < 1.0f 327 || (mOutGlop->mesh.vertices.flags & VertexAttribFlags::kAlpha) 328 || texture.blend 329 || mOutGlop->roundRectClipState) { 330 Blend::getFactors(SkXfermode::kSrcOver_Mode, SWAP_SRC_DST, 331 &mOutGlop->blend.src, &mOutGlop->blend.dst); 332 } else { 333 mOutGlop->blend = { GL_ZERO, GL_ZERO }; 334 } 335 } 336 337 if (textureFillFlags & TextureFillFlags::kIsAlphaMaskTexture) { 338 mDescription.modulate = mOutGlop->fill.color.isNotBlack(); 339 mDescription.hasAlpha8Texture = true; 340 } else { 341 mDescription.modulate = mOutGlop->fill.color.a < 1.0f; 342 } 343 return *this; 344} 345 346GlopBuilder& GlopBuilder::setFillPaint(const SkPaint& paint, float alphaScale) { 347 TRIGGER_STAGE(kFillStage); 348 REQUIRE_STAGES(kMeshStage); 349 350 mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr }; 351 352 setFill(paint.getColor(), alphaScale, PaintUtils::getXfermode(paint.getXfermode()), 353 paint.getShader(), paint.getColorFilter()); 354 mDescription.modulate = mOutGlop->fill.color.a < 1.0f; 355 return *this; 356} 357 358GlopBuilder& GlopBuilder::setFillPathTexturePaint(PathTexture& texture, 359 const SkPaint& paint, float alphaScale) { 360 TRIGGER_STAGE(kFillStage); 361 REQUIRE_STAGES(kMeshStage); 362 363 //specify invalid filter/clamp, since these are always static for PathTextures 364 mOutGlop->fill.texture = { &texture, GL_TEXTURE_2D, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr }; 365 366 setFill(paint.getColor(), alphaScale, PaintUtils::getXfermode(paint.getXfermode()), 367 paint.getShader(), paint.getColorFilter()); 368 369 mDescription.hasAlpha8Texture = true; 370 mDescription.modulate = mOutGlop->fill.color.isNotBlack(); 371 return *this; 372} 373 374GlopBuilder& GlopBuilder::setFillShadowTexturePaint(ShadowTexture& texture, int shadowColor, 375 const SkPaint& paint, float alphaScale) { 376 TRIGGER_STAGE(kFillStage); 377 REQUIRE_STAGES(kMeshStage); 378 379 //specify invalid filter/clamp, since these are always static for ShadowTextures 380 mOutGlop->fill.texture = { &texture, GL_TEXTURE_2D, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr }; 381 382 const int ALPHA_BITMASK = SK_ColorBLACK; 383 const int COLOR_BITMASK = ~ALPHA_BITMASK; 384 if ((shadowColor & ALPHA_BITMASK) == ALPHA_BITMASK) { 385 // shadow color is fully opaque: override its alpha with that of paint 386 shadowColor &= paint.getColor() | COLOR_BITMASK; 387 } 388 389 setFill(shadowColor, alphaScale, PaintUtils::getXfermode(paint.getXfermode()), 390 paint.getShader(), paint.getColorFilter()); 391 392 mDescription.hasAlpha8Texture = true; 393 mDescription.modulate = mOutGlop->fill.color.isNotBlack(); 394 return *this; 395} 396 397GlopBuilder& GlopBuilder::setFillBlack() { 398 TRIGGER_STAGE(kFillStage); 399 REQUIRE_STAGES(kMeshStage); 400 401 mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr }; 402 setFill(SK_ColorBLACK, 1.0f, SkXfermode::kSrcOver_Mode, nullptr, nullptr); 403 return *this; 404} 405 406GlopBuilder& GlopBuilder::setFillClear() { 407 TRIGGER_STAGE(kFillStage); 408 REQUIRE_STAGES(kMeshStage); 409 410 mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr }; 411 setFill(SK_ColorBLACK, 1.0f, SkXfermode::kClear_Mode, nullptr, nullptr); 412 return *this; 413} 414 415GlopBuilder& GlopBuilder::setFillLayer(Texture& texture, const SkColorFilter* colorFilter, 416 float alpha, SkXfermode::Mode mode) { 417 TRIGGER_STAGE(kFillStage); 418 REQUIRE_STAGES(kMeshStage); 419 420 mOutGlop->fill.texture = { &texture, 421 GL_TEXTURE_2D, GL_LINEAR, GL_CLAMP_TO_EDGE, nullptr }; 422 mOutGlop->fill.color = { alpha, alpha, alpha, alpha }; 423 424 setFill(SK_ColorWHITE, alpha, mode, nullptr, colorFilter); 425 426 mDescription.modulate = mOutGlop->fill.color.a < 1.0f; 427 return *this; 428} 429 430GlopBuilder& GlopBuilder::setFillTextureLayer(Layer& layer, float alpha) { 431 TRIGGER_STAGE(kFillStage); 432 REQUIRE_STAGES(kMeshStage); 433 434 mOutGlop->fill.texture = { &(layer.getTexture()), 435 layer.getRenderTarget(), GL_LINEAR, GL_CLAMP_TO_EDGE, &layer.getTexTransform() }; 436 mOutGlop->fill.color = { alpha, alpha, alpha, alpha }; 437 438 setFill(SK_ColorWHITE, alpha, layer.getMode(), nullptr, layer.getColorFilter()); 439 440 mDescription.modulate = mOutGlop->fill.color.a < 1.0f; 441 mDescription.hasTextureTransform = true; 442 return *this; 443} 444 445//////////////////////////////////////////////////////////////////////////////// 446// Transform 447//////////////////////////////////////////////////////////////////////////////// 448 449GlopBuilder& GlopBuilder::setTransform(const Matrix4& ortho, 450 const Matrix4& transform, bool fudgingOffset) { 451 TRIGGER_STAGE(kTransformStage); 452 453 mOutGlop->transform.ortho.load(ortho); 454 mOutGlop->transform.canvas.load(transform); 455 mOutGlop->transform.fudgingOffset = fudgingOffset; 456 return *this; 457} 458 459//////////////////////////////////////////////////////////////////////////////// 460// ModelView 461//////////////////////////////////////////////////////////////////////////////// 462 463GlopBuilder& GlopBuilder::setModelViewMapUnitToRect(const Rect destination) { 464 TRIGGER_STAGE(kModelViewStage); 465 466 mOutGlop->transform.modelView.loadTranslate(destination.left, destination.top, 0.0f); 467 mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f); 468 mOutGlop->bounds = destination; 469 return *this; 470} 471 472GlopBuilder& GlopBuilder::setModelViewMapUnitToRectSnap(const Rect destination) { 473 TRIGGER_STAGE(kModelViewStage); 474 REQUIRE_STAGES(kTransformStage | kFillStage); 475 476 float left = destination.left; 477 float top = destination.top; 478 479 const Matrix4& canvasTransform = mOutGlop->transform.canvas; 480 if (CC_LIKELY(canvasTransform.isPureTranslate())) { 481 // snap by adjusting the model view matrix 482 const float translateX = canvasTransform.getTranslateX(); 483 const float translateY = canvasTransform.getTranslateY(); 484 485 left = (int) floorf(left + translateX + 0.5f) - translateX; 486 top = (int) floorf(top + translateY + 0.5f) - translateY; 487 mOutGlop->fill.texture.filter = GL_NEAREST; 488 } 489 490 mOutGlop->transform.modelView.loadTranslate(left, top, 0.0f); 491 mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f); 492 mOutGlop->bounds = destination; 493 return *this; 494} 495 496GlopBuilder& GlopBuilder::setModelViewOffsetRect(float offsetX, float offsetY, const Rect source) { 497 TRIGGER_STAGE(kModelViewStage); 498 499 mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f); 500 mOutGlop->bounds = source; 501 mOutGlop->bounds.translate(offsetX, offsetY); 502 return *this; 503} 504 505GlopBuilder& GlopBuilder::setModelViewOffsetRectSnap(float offsetX, float offsetY, const Rect source) { 506 TRIGGER_STAGE(kModelViewStage); 507 REQUIRE_STAGES(kTransformStage | kFillStage); 508 509 const Matrix4& canvasTransform = mOutGlop->transform.canvas; 510 if (CC_LIKELY(canvasTransform.isPureTranslate())) { 511 // snap by adjusting the model view matrix 512 const float translateX = canvasTransform.getTranslateX(); 513 const float translateY = canvasTransform.getTranslateY(); 514 515 offsetX = (int) floorf(offsetX + translateX + source.left + 0.5f) - translateX - source.left; 516 offsetY = (int) floorf(offsetY + translateY + source.top + 0.5f) - translateY - source.top; 517 mOutGlop->fill.texture.filter = GL_NEAREST; 518 } 519 520 mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f); 521 mOutGlop->bounds = source; 522 mOutGlop->bounds.translate(offsetX, offsetY); 523 return *this; 524} 525 526//////////////////////////////////////////////////////////////////////////////// 527// RoundRectClip 528//////////////////////////////////////////////////////////////////////////////// 529 530GlopBuilder& GlopBuilder::setRoundRectClipState(const RoundRectClipState* roundRectClipState) { 531 TRIGGER_STAGE(kRoundRectClipStage); 532 533 mOutGlop->roundRectClipState = roundRectClipState; 534 mDescription.hasRoundRectClip = roundRectClipState != nullptr; 535 return *this; 536} 537 538//////////////////////////////////////////////////////////////////////////////// 539// Build 540//////////////////////////////////////////////////////////////////////////////// 541 542void verify(const ProgramDescription& description, const Glop& glop) { 543 bool hasTexture = glop.fill.texture.texture != nullptr; 544 LOG_ALWAYS_FATAL_IF(description.hasTexture && description.hasExternalTexture); 545 LOG_ALWAYS_FATAL_IF((description.hasTexture || description.hasExternalTexture )!= hasTexture); 546 LOG_ALWAYS_FATAL_IF((glop.mesh.vertices.flags & VertexAttribFlags::kTextureCoord) != hasTexture); 547 548 if ((glop.mesh.vertices.flags & VertexAttribFlags::kAlpha) && glop.mesh.vertices.bufferObject) { 549 LOG_ALWAYS_FATAL("VBO and alpha attributes are not currently compatible"); 550 } 551 552 if (description.hasTextureTransform != (glop.fill.texture.textureTransform != nullptr)) { 553 LOG_ALWAYS_FATAL("Texture transform incorrectly specified"); 554 } 555} 556 557void GlopBuilder::build() { 558 REQUIRE_STAGES(kAllStages); 559 if (mOutGlop->mesh.vertices.flags & VertexAttribFlags::kTextureCoord) { 560 mDescription.hasTexture = mOutGlop->fill.texture.target == GL_TEXTURE_2D; 561 mDescription.hasExternalTexture = mOutGlop->fill.texture.target == GL_TEXTURE_EXTERNAL_OES; 562 } 563 mDescription.hasColors = mOutGlop->mesh.vertices.flags & VertexAttribFlags::kColor; 564 mDescription.hasVertexAlpha = mOutGlop->mesh.vertices.flags & VertexAttribFlags::kAlpha; 565 566 // serialize shader info into ShaderData 567 GLuint textureUnit = mOutGlop->fill.texture.texture ? 1 : 0; 568 SkiaShader::store(mCaches, mShader, mOutGlop->transform.modelView, 569 &textureUnit, &mDescription, &(mOutGlop->fill.skiaShaderData)); 570 571 // duplicates ProgramCache's definition of color uniform presence 572 const bool singleColor = !mDescription.hasTexture 573 && !mDescription.hasExternalTexture 574 && !mDescription.hasGradient 575 && !mDescription.hasBitmap; 576 mOutGlop->fill.colorEnabled = mDescription.modulate || singleColor; 577 578 verify(mDescription, *mOutGlop); 579 580 // Final step: populate program and map bounds into render target space 581 mOutGlop->fill.program = mCaches.programCache.get(mDescription); 582 mOutGlop->transform.canvas.mapRect(mOutGlop->bounds); 583} 584 585} /* namespace uirenderer */ 586} /* namespace android */ 587