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