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