GlopBuilder.cpp revision 8cd3edfa15cc9cdbffa935d19ab894426b08d174
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 54namespace android { 55namespace uirenderer { 56 57static 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 64GlopBuilder::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 76GlopBuilder& 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 90GlopBuilder& 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 104GlopBuilder& 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 123GlopBuilder& 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 143GlopBuilder& 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 157GlopBuilder& 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 171GlopBuilder& 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 185GlopBuilder& 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 205GlopBuilder& 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 223void 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 305GlopBuilder& 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 349GlopBuilder& 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 370GlopBuilder& 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 387GlopBuilder& 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 411GlopBuilder& 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 421GlopBuilder& 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 431GlopBuilder& 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 444GlopBuilder& 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 459GlopBuilder& GlopBuilder::setFillExternalTexture(Texture& texture, Matrix4& textureTransform) { 460 TRIGGER_STAGE(kFillStage); 461 REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); 462 463 mOutGlop->fill.texture = { &texture, GL_LINEAR, GL_CLAMP_TO_EDGE, &textureTransform }; 464 465 setFill(SK_ColorWHITE, 1.0f, SkBlendMode::kSrc, Blend::ModeOrderSwap::NoSwap, 466 nullptr, nullptr); 467 468 mDescription.modulate = mOutGlop->fill.color.a < 1.0f; 469 mDescription.hasTextureTransform = true; 470 return *this; 471} 472 473GlopBuilder& GlopBuilder::setGammaCorrection(bool enabled) { 474 REQUIRE_STAGES(kFillStage); 475 476 mDescription.hasGammaCorrection = enabled; 477 return *this; 478} 479 480//////////////////////////////////////////////////////////////////////////////// 481// Transform 482//////////////////////////////////////////////////////////////////////////////// 483 484GlopBuilder& GlopBuilder::setTransform(const Matrix4& canvas, const int transformFlags) { 485 TRIGGER_STAGE(kTransformStage); 486 487 mOutGlop->transform.canvas = canvas; 488 mOutGlop->transform.transformFlags = transformFlags; 489 return *this; 490} 491 492//////////////////////////////////////////////////////////////////////////////// 493// ModelView 494//////////////////////////////////////////////////////////////////////////////// 495 496GlopBuilder& GlopBuilder::setModelViewMapUnitToRect(const Rect destination) { 497 TRIGGER_STAGE(kModelViewStage); 498 499 mOutGlop->transform.modelView.loadTranslate(destination.left, destination.top, 0.0f); 500 mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f); 501 return *this; 502} 503 504GlopBuilder& GlopBuilder::setModelViewMapUnitToRectSnap(const Rect destination) { 505 TRIGGER_STAGE(kModelViewStage); 506 REQUIRE_STAGES(kTransformStage | kFillStage); 507 508 float left = destination.left; 509 float top = destination.top; 510 511 const Matrix4& meshTransform = mOutGlop->transform.meshTransform(); 512 if (CC_LIKELY(meshTransform.isPureTranslate())) { 513 // snap by adjusting the model view matrix 514 const float translateX = meshTransform.getTranslateX(); 515 const float translateY = meshTransform.getTranslateY(); 516 517 left = (int) floorf(left + translateX + 0.5f) - translateX; 518 top = (int) floorf(top + translateY + 0.5f) - translateY; 519 mOutGlop->fill.texture.filter = GL_NEAREST; 520 } 521 522 mOutGlop->transform.modelView.loadTranslate(left, top, 0.0f); 523 mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f); 524 return *this; 525} 526 527GlopBuilder& GlopBuilder::setModelViewOffsetRect(float offsetX, float offsetY, const Rect source) { 528 TRIGGER_STAGE(kModelViewStage); 529 530 mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f); 531 return *this; 532} 533 534GlopBuilder& GlopBuilder::setModelViewOffsetRectSnap(float offsetX, float offsetY, const Rect source) { 535 TRIGGER_STAGE(kModelViewStage); 536 REQUIRE_STAGES(kTransformStage | kFillStage); 537 538 const Matrix4& meshTransform = mOutGlop->transform.meshTransform(); 539 if (CC_LIKELY(meshTransform.isPureTranslate())) { 540 // snap by adjusting the model view matrix 541 const float translateX = meshTransform.getTranslateX(); 542 const float translateY = meshTransform.getTranslateY(); 543 544 offsetX = (int) floorf(offsetX + translateX + source.left + 0.5f) - translateX - source.left; 545 offsetY = (int) floorf(offsetY + translateY + source.top + 0.5f) - translateY - source.top; 546 mOutGlop->fill.texture.filter = GL_NEAREST; 547 } 548 549 mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f); 550 return *this; 551} 552 553//////////////////////////////////////////////////////////////////////////////// 554// RoundRectClip 555//////////////////////////////////////////////////////////////////////////////// 556 557GlopBuilder& GlopBuilder::setRoundRectClipState(const RoundRectClipState* roundRectClipState) { 558 TRIGGER_STAGE(kRoundRectClipStage); 559 560 mOutGlop->roundRectClipState = roundRectClipState; 561 mDescription.hasRoundRectClip = roundRectClipState != nullptr; 562 return *this; 563} 564 565//////////////////////////////////////////////////////////////////////////////// 566// Build 567//////////////////////////////////////////////////////////////////////////////// 568 569void verify(const ProgramDescription& description, const Glop& glop) { 570 if (glop.fill.texture.texture != nullptr) { 571 LOG_ALWAYS_FATAL_IF(((description.hasTexture && description.hasExternalTexture) 572 || (!description.hasTexture 573 && !description.hasExternalTexture 574 && !description.useShadowAlphaInterp) 575 || ((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) == 0 576 && !description.useShadowAlphaInterp)), 577 "Texture %p, hT%d, hET %d, attribFlags %x", 578 glop.fill.texture.texture, 579 description.hasTexture, description.hasExternalTexture, 580 glop.mesh.vertices.attribFlags); 581 } else { 582 LOG_ALWAYS_FATAL_IF((description.hasTexture 583 || description.hasExternalTexture 584 || ((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) != 0)), 585 "No texture, hT%d, hET %d, attribFlags %x", 586 description.hasTexture, description.hasExternalTexture, 587 glop.mesh.vertices.attribFlags); 588 } 589 590 if ((glop.mesh.vertices.attribFlags & VertexAttribFlags::Alpha) 591 && glop.mesh.vertices.bufferObject) { 592 LOG_ALWAYS_FATAL("VBO and alpha attributes are not currently compatible"); 593 } 594 595 if (description.hasTextureTransform != (glop.fill.texture.textureTransform != nullptr)) { 596 LOG_ALWAYS_FATAL("Texture transform incorrectly specified"); 597 } 598} 599 600void GlopBuilder::build() { 601 REQUIRE_STAGES(kAllStages); 602 if (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) { 603 if (mOutGlop->fill.texture.texture->target() == GL_TEXTURE_2D) { 604 mDescription.hasTexture = true; 605 } else { 606 mDescription.hasExternalTexture = true; 607 } 608 } 609 610 mDescription.hasColors = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Color; 611 mDescription.hasVertexAlpha = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha; 612 613 // Enable debug highlight when what we're about to draw is tested against 614 // the stencil buffer and if stencil highlight debugging is on 615 mDescription.hasDebugHighlight = !Properties::debugOverdraw 616 && Properties::debugStencilClip == StencilClipDebug::ShowHighlight 617 && mRenderState.stencil().isTestEnabled(); 618 619 // serialize shader info into ShaderData 620 GLuint textureUnit = mOutGlop->fill.texture.texture ? 1 : 0; 621 622 if (CC_LIKELY(!mShader)) { 623 mOutGlop->fill.skiaShaderData.skiaShaderType = kNone_SkiaShaderType; 624 } else { 625 Matrix4 shaderMatrix; 626 if (mOutGlop->transform.transformFlags & TransformFlags::MeshIgnoresCanvasTransform) { 627 // canvas level transform was built into the modelView and geometry, 628 // so the shader matrix must reverse this 629 shaderMatrix.loadInverse(mOutGlop->transform.canvas); 630 shaderMatrix.multiply(mOutGlop->transform.modelView); 631 } else { 632 shaderMatrix = mOutGlop->transform.modelView; 633 } 634 SkiaShader::store(mCaches, *mShader, shaderMatrix, 635 &textureUnit, &mDescription, &(mOutGlop->fill.skiaShaderData)); 636 } 637 638 // duplicates ProgramCache's definition of color uniform presence 639 const bool singleColor = !mDescription.hasTexture 640 && !mDescription.hasExternalTexture 641 && !mDescription.hasGradient 642 && !mDescription.hasBitmap; 643 mOutGlop->fill.colorEnabled = mDescription.modulate || singleColor; 644 645 verify(mDescription, *mOutGlop); 646 647 // Final step: populate program and map bounds into render target space 648 mOutGlop->fill.program = mCaches.programCache.get(mDescription); 649} 650 651void GlopBuilder::dump(const Glop& glop) { 652 ALOGD("Glop Mesh"); 653 const Glop::Mesh& mesh = glop.mesh; 654 ALOGD(" primitive mode: %d", mesh.primitiveMode); 655 ALOGD(" indices: buffer obj %x, indices %p", mesh.indices.bufferObject, mesh.indices.indices); 656 657 const Glop::Mesh::Vertices& vertices = glop.mesh.vertices; 658 ALOGD(" vertices: buffer obj %x, flags %x, pos %p, tex %p, clr %p, stride %d", 659 vertices.bufferObject, vertices.attribFlags, 660 vertices.position, vertices.texCoord, vertices.color, vertices.stride); 661 ALOGD(" element count: %d", mesh.elementCount); 662 663 ALOGD("Glop Fill"); 664 const Glop::Fill& fill = glop.fill; 665 ALOGD(" program %p", fill.program); 666 if (fill.texture.texture) { 667 ALOGD(" texture %p, target %d, filter %d, clamp %d", 668 fill.texture.texture, fill.texture.texture->target(), 669 fill.texture.filter, fill.texture.clamp); 670 if (fill.texture.textureTransform) { 671 fill.texture.textureTransform->dump("texture transform"); 672 } 673 } 674 ALOGD_IF(fill.colorEnabled, " color (argb) %.2f %.2f %.2f %.2f", 675 fill.color.a, fill.color.r, fill.color.g, fill.color.b); 676 ALOGD_IF(fill.filterMode != ProgramDescription::ColorFilterMode::None, 677 " filterMode %d", (int)fill.filterMode); 678 ALOGD_IF(fill.skiaShaderData.skiaShaderType, " shader type %d", 679 fill.skiaShaderData.skiaShaderType); 680 681 ALOGD("Glop transform"); 682 glop.transform.modelView.dump(" model view"); 683 glop.transform.canvas.dump(" canvas"); 684 ALOGD_IF(glop.transform.transformFlags, " transformFlags 0x%x", glop.transform.transformFlags); 685 686 ALOGD_IF(glop.roundRectClipState, "Glop RRCS %p", glop.roundRectClipState); 687 688 ALOGD("Glop blend %d %d", glop.blend.src, glop.blend.dst); 689} 690 691} /* namespace uirenderer */ 692} /* namespace android */ 693