GlopBuilder.cpp revision 253f2c213f6ecda63b6872aee77bd30d5ec07c82
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 SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage, 224 const SkShader* shader, const SkColorFilter* colorFilter) { 225 if (mode != SkXfermode::kClear_Mode) { 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 != SkXfermode::kSrcOver_Mode) { 250 if (CC_LIKELY(mode <= SkXfermode::kScreen_Mode)) { 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(SkXfermode::kSrcOver_Mode, 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 SkXfermode::Mode mode; 275 SkScalar srcColorMatrix[20]; 276 if (colorFilter->asColorMode(&color, &mode)) { 277 mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::ColorFilterMode::Blend; 278 mDescription.colorMode = mode; 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_sRGB(srcColorMatrix[4] / 255.0f); 293 colorVector[1] = EOCF_sRGB(srcColorMatrix[9] / 255.0f); 294 colorVector[2] = EOCF_sRGB(srcColorMatrix[14] / 255.0f); 295 colorVector[3] = EOCF_sRGB(srcColorMatrix[19] / 255.0f); 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, 312 GL_TEXTURE_2D, 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 PaintUtils::getXfermode(paint->getXfermode()), 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(SkXfermode::kSrcOver_Mode, 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, GL_INVALID_ENUM, nullptr }; 356 } else { 357 mOutGlop->fill.texture = { 358 mCaches.textureState().getShadowLutTexture(), GL_TEXTURE_2D, 359 GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr }; 360 } 361 362 setFill(paint.getColor(), alphaScale, 363 PaintUtils::getXfermode(paint.getXfermode()), 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_TEXTURE_2D, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr }; 377 378 setFill(paint.getColor(), alphaScale, 379 PaintUtils::getXfermode(paint.getXfermode()), 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_TEXTURE_2D, 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 PaintUtils::getXfermode(paint.getXfermode()), 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, GL_INVALID_ENUM, nullptr }; 416 setFill(SK_ColorBLACK, 1.0f, SkXfermode::kSrcOver_Mode, 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, GL_INVALID_ENUM, nullptr }; 426 setFill(SK_ColorBLACK, 1.0f, SkXfermode::kClear_Mode, Blend::ModeOrderSwap::NoSwap, 427 nullptr, nullptr); 428 return *this; 429} 430 431GlopBuilder& GlopBuilder::setFillLayer(Texture& texture, const SkColorFilter* colorFilter, 432 float alpha, SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage) { 433 TRIGGER_STAGE(kFillStage); 434 REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); 435 436 mOutGlop->fill.texture = { &texture, 437 GL_TEXTURE_2D, GL_LINEAR, GL_CLAMP_TO_EDGE, nullptr }; 438 439 setFill(SK_ColorWHITE, alpha, mode, modeUsage, nullptr, colorFilter); 440 441 mDescription.modulate = mOutGlop->fill.color.a < 1.0f; 442 return *this; 443} 444 445GlopBuilder& GlopBuilder::setFillTextureLayer(Layer& layer, float alpha) { 446 TRIGGER_STAGE(kFillStage); 447 REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); 448 449 mOutGlop->fill.texture = { &(layer.getTexture()), 450 layer.getRenderTarget(), GL_LINEAR, GL_CLAMP_TO_EDGE, &layer.getTexTransform() }; 451 452 setFill(SK_ColorWHITE, alpha, layer.getMode(), Blend::ModeOrderSwap::NoSwap, 453 nullptr, layer.getColorFilter()); 454 455 mDescription.modulate = mOutGlop->fill.color.a < 1.0f; 456 mDescription.hasTextureTransform = true; 457 return *this; 458} 459 460GlopBuilder& GlopBuilder::setFillExternalTexture(Texture& texture, Matrix4& textureTransform) { 461 TRIGGER_STAGE(kFillStage); 462 REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); 463 464 mOutGlop->fill.texture = { &texture, 465 GL_TEXTURE_EXTERNAL_OES, GL_LINEAR, GL_CLAMP_TO_EDGE, 466 &textureTransform }; 467 468 setFill(SK_ColorWHITE, 1.0f, SkXfermode::kSrc_Mode, Blend::ModeOrderSwap::NoSwap, 469 nullptr, nullptr); 470 471 mDescription.modulate = mOutGlop->fill.color.a < 1.0f; 472 mDescription.hasTextureTransform = true; 473 return *this; 474} 475 476GlopBuilder& GlopBuilder::setGammaCorrection(bool enabled) { 477 REQUIRE_STAGES(kFillStage); 478 479 mDescription.hasGammaCorrection = enabled; 480 return *this; 481} 482 483//////////////////////////////////////////////////////////////////////////////// 484// Transform 485//////////////////////////////////////////////////////////////////////////////// 486 487GlopBuilder& GlopBuilder::setTransform(const Matrix4& canvas, const int transformFlags) { 488 TRIGGER_STAGE(kTransformStage); 489 490 mOutGlop->transform.canvas = canvas; 491 mOutGlop->transform.transformFlags = transformFlags; 492 return *this; 493} 494 495//////////////////////////////////////////////////////////////////////////////// 496// ModelView 497//////////////////////////////////////////////////////////////////////////////// 498 499GlopBuilder& GlopBuilder::setModelViewMapUnitToRect(const Rect destination) { 500 TRIGGER_STAGE(kModelViewStage); 501 502 mOutGlop->transform.modelView.loadTranslate(destination.left, destination.top, 0.0f); 503 mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f); 504 return *this; 505} 506 507GlopBuilder& GlopBuilder::setModelViewMapUnitToRectSnap(const Rect destination) { 508 TRIGGER_STAGE(kModelViewStage); 509 REQUIRE_STAGES(kTransformStage | kFillStage); 510 511 float left = destination.left; 512 float top = destination.top; 513 514 const Matrix4& meshTransform = mOutGlop->transform.meshTransform(); 515 if (CC_LIKELY(meshTransform.isPureTranslate())) { 516 // snap by adjusting the model view matrix 517 const float translateX = meshTransform.getTranslateX(); 518 const float translateY = meshTransform.getTranslateY(); 519 520 left = (int) floorf(left + translateX + 0.5f) - translateX; 521 top = (int) floorf(top + translateY + 0.5f) - translateY; 522 mOutGlop->fill.texture.filter = GL_NEAREST; 523 } 524 525 mOutGlop->transform.modelView.loadTranslate(left, top, 0.0f); 526 mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f); 527 return *this; 528} 529 530GlopBuilder& GlopBuilder::setModelViewOffsetRect(float offsetX, float offsetY, const Rect source) { 531 TRIGGER_STAGE(kModelViewStage); 532 533 mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f); 534 return *this; 535} 536 537GlopBuilder& GlopBuilder::setModelViewOffsetRectSnap(float offsetX, float offsetY, const Rect source) { 538 TRIGGER_STAGE(kModelViewStage); 539 REQUIRE_STAGES(kTransformStage | kFillStage); 540 541 const Matrix4& meshTransform = mOutGlop->transform.meshTransform(); 542 if (CC_LIKELY(meshTransform.isPureTranslate())) { 543 // snap by adjusting the model view matrix 544 const float translateX = meshTransform.getTranslateX(); 545 const float translateY = meshTransform.getTranslateY(); 546 547 offsetX = (int) floorf(offsetX + translateX + source.left + 0.5f) - translateX - source.left; 548 offsetY = (int) floorf(offsetY + translateY + source.top + 0.5f) - translateY - source.top; 549 mOutGlop->fill.texture.filter = GL_NEAREST; 550 } 551 552 mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f); 553 return *this; 554} 555 556//////////////////////////////////////////////////////////////////////////////// 557// RoundRectClip 558//////////////////////////////////////////////////////////////////////////////// 559 560GlopBuilder& GlopBuilder::setRoundRectClipState(const RoundRectClipState* roundRectClipState) { 561 TRIGGER_STAGE(kRoundRectClipStage); 562 563 mOutGlop->roundRectClipState = roundRectClipState; 564 mDescription.hasRoundRectClip = roundRectClipState != nullptr; 565 return *this; 566} 567 568//////////////////////////////////////////////////////////////////////////////// 569// Build 570//////////////////////////////////////////////////////////////////////////////// 571 572void verify(const ProgramDescription& description, const Glop& glop) { 573 if (glop.fill.texture.texture != nullptr) { 574 LOG_ALWAYS_FATAL_IF(((description.hasTexture && description.hasExternalTexture) 575 || (!description.hasTexture 576 && !description.hasExternalTexture 577 && !description.useShadowAlphaInterp) 578 || ((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) == 0 579 && !description.useShadowAlphaInterp)), 580 "Texture %p, hT%d, hET %d, attribFlags %x", 581 glop.fill.texture.texture, 582 description.hasTexture, description.hasExternalTexture, 583 glop.mesh.vertices.attribFlags); 584 } else { 585 LOG_ALWAYS_FATAL_IF((description.hasTexture 586 || description.hasExternalTexture 587 || ((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) != 0)), 588 "No texture, hT%d, hET %d, attribFlags %x", 589 description.hasTexture, description.hasExternalTexture, 590 glop.mesh.vertices.attribFlags); 591 } 592 593 if ((glop.mesh.vertices.attribFlags & VertexAttribFlags::Alpha) 594 && glop.mesh.vertices.bufferObject) { 595 LOG_ALWAYS_FATAL("VBO and alpha attributes are not currently compatible"); 596 } 597 598 if (description.hasTextureTransform != (glop.fill.texture.textureTransform != nullptr)) { 599 LOG_ALWAYS_FATAL("Texture transform incorrectly specified"); 600 } 601} 602 603void GlopBuilder::build() { 604 REQUIRE_STAGES(kAllStages); 605 if (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) { 606 if (mOutGlop->fill.texture.target == GL_TEXTURE_2D) { 607 mDescription.hasTexture = true; 608 } else { 609 mDescription.hasExternalTexture = true; 610 } 611 } 612 613 mDescription.hasColors = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Color; 614 mDescription.hasVertexAlpha = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha; 615 616 // Enable debug highlight when what we're about to draw is tested against 617 // the stencil buffer and if stencil highlight debugging is on 618 mDescription.hasDebugHighlight = !Properties::debugOverdraw 619 && Properties::debugStencilClip == StencilClipDebug::ShowHighlight 620 && mRenderState.stencil().isTestEnabled(); 621 622 // serialize shader info into ShaderData 623 GLuint textureUnit = mOutGlop->fill.texture.texture ? 1 : 0; 624 625 if (CC_LIKELY(!mShader)) { 626 mOutGlop->fill.skiaShaderData.skiaShaderType = kNone_SkiaShaderType; 627 } else { 628 Matrix4 shaderMatrix; 629 if (mOutGlop->transform.transformFlags & TransformFlags::MeshIgnoresCanvasTransform) { 630 // canvas level transform was built into the modelView and geometry, 631 // so the shader matrix must reverse this 632 shaderMatrix.loadInverse(mOutGlop->transform.canvas); 633 shaderMatrix.multiply(mOutGlop->transform.modelView); 634 } else { 635 shaderMatrix = mOutGlop->transform.modelView; 636 } 637 SkiaShader::store(mCaches, *mShader, shaderMatrix, 638 &textureUnit, &mDescription, &(mOutGlop->fill.skiaShaderData)); 639 } 640 641 // duplicates ProgramCache's definition of color uniform presence 642 const bool singleColor = !mDescription.hasTexture 643 && !mDescription.hasExternalTexture 644 && !mDescription.hasGradient 645 && !mDescription.hasBitmap; 646 mOutGlop->fill.colorEnabled = mDescription.modulate || singleColor; 647 648 verify(mDescription, *mOutGlop); 649 650 // Final step: populate program and map bounds into render target space 651 mOutGlop->fill.program = mCaches.programCache.get(mDescription); 652} 653 654void GlopBuilder::dump(const Glop& glop) { 655 ALOGD("Glop Mesh"); 656 const Glop::Mesh& mesh = glop.mesh; 657 ALOGD(" primitive mode: %d", mesh.primitiveMode); 658 ALOGD(" indices: buffer obj %x, indices %p", mesh.indices.bufferObject, mesh.indices.indices); 659 660 const Glop::Mesh::Vertices& vertices = glop.mesh.vertices; 661 ALOGD(" vertices: buffer obj %x, flags %x, pos %p, tex %p, clr %p, stride %d", 662 vertices.bufferObject, vertices.attribFlags, 663 vertices.position, vertices.texCoord, vertices.color, vertices.stride); 664 ALOGD(" element count: %d", mesh.elementCount); 665 666 ALOGD("Glop Fill"); 667 const Glop::Fill& fill = glop.fill; 668 ALOGD(" program %p", fill.program); 669 if (fill.texture.texture) { 670 ALOGD(" texture %p, target %d, filter %d, clamp %d", 671 fill.texture.texture, fill.texture.target, fill.texture.filter, fill.texture.clamp); 672 if (fill.texture.textureTransform) { 673 fill.texture.textureTransform->dump("texture transform"); 674 } 675 } 676 ALOGD_IF(fill.colorEnabled, " color (argb) %.2f %.2f %.2f %.2f", 677 fill.color.a, fill.color.r, fill.color.g, fill.color.b); 678 ALOGD_IF(fill.filterMode != ProgramDescription::ColorFilterMode::None, 679 " filterMode %d", (int)fill.filterMode); 680 ALOGD_IF(fill.skiaShaderData.skiaShaderType, " shader type %d", 681 fill.skiaShaderData.skiaShaderType); 682 683 ALOGD("Glop transform"); 684 glop.transform.modelView.dump(" model view"); 685 glop.transform.canvas.dump(" canvas"); 686 ALOGD_IF(glop.transform.transformFlags, " transformFlags 0x%x", glop.transform.transformFlags); 687 688 ALOGD_IF(glop.roundRectClipState, "Glop RRCS %p", glop.roundRectClipState); 689 690 ALOGD("Glop blend %d %d", glop.blend.src, glop.blend.dst); 691} 692 693} /* namespace uirenderer */ 694} /* namespace android */ 695