GlopBuilder.cpp revision 2f69d6d4fdd4994912e5515016421625d1e1c4ec
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, bool shadowInterp) { 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 214 mDescription.useShadowAlphaInterp = shadowInterp; 215 return *this; 216} 217 218GlopBuilder& GlopBuilder::setMeshPatchQuads(const Patch& patch) { 219 TRIGGER_STAGE(kMeshStage); 220 221 mOutGlop->mesh.primitiveMode = GL_TRIANGLES; 222 mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr }; 223 mOutGlop->mesh.vertices = { 224 mCaches.patchCache.getMeshBuffer(), 225 VertexAttribFlags::TextureCoord, 226 (void*)patch.positionOffset, (void*)patch.textureOffset, nullptr, 227 kTextureVertexStride }; 228 mOutGlop->mesh.elementCount = patch.indexCount; 229 return *this; 230} 231 232//////////////////////////////////////////////////////////////////////////////// 233// Fill 234//////////////////////////////////////////////////////////////////////////////// 235 236void GlopBuilder::setFill(int color, float alphaScale, 237 SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage, 238 const SkShader* shader, const SkColorFilter* colorFilter) { 239 if (mode != SkXfermode::kClear_Mode) { 240 float alpha = (SkColorGetA(color) / 255.0f) * alphaScale; 241 if (!shader) { 242 float colorScale = alpha / 255.0f; 243 mOutGlop->fill.color = { 244 colorScale * SkColorGetR(color), 245 colorScale * SkColorGetG(color), 246 colorScale * SkColorGetB(color), 247 alpha 248 }; 249 } else { 250 mOutGlop->fill.color = { 1, 1, 1, alpha }; 251 } 252 } else { 253 mOutGlop->fill.color = { 0, 0, 0, 1 }; 254 } 255 256 mOutGlop->blend = { GL_ZERO, GL_ZERO }; 257 if (mOutGlop->fill.color.a < 1.0f 258 || (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha) 259 || (mOutGlop->fill.texture.texture && mOutGlop->fill.texture.texture->blend) 260 || mOutGlop->roundRectClipState 261 || PaintUtils::isBlendedShader(shader) 262 || PaintUtils::isBlendedColorFilter(colorFilter) 263 || mode != SkXfermode::kSrcOver_Mode) { 264 if (CC_LIKELY(mode <= SkXfermode::kScreen_Mode)) { 265 Blend::getFactors(mode, modeUsage, 266 &mOutGlop->blend.src, &mOutGlop->blend.dst); 267 } else { 268 // These blend modes are not supported by OpenGL directly and have 269 // to be implemented using shaders. Since the shader will perform 270 // the blending, don't enable GL blending off here 271 // If the blend mode cannot be implemented using shaders, fall 272 // back to the default SrcOver blend mode instead 273 if (CC_UNLIKELY(mCaches.extensions().hasFramebufferFetch())) { 274 mDescription.framebufferMode = mode; 275 mDescription.swapSrcDst = (modeUsage == Blend::ModeOrderSwap::Swap); 276 // blending in shader, don't enable 277 } else { 278 // unsupported 279 Blend::getFactors(SkXfermode::kSrcOver_Mode, modeUsage, 280 &mOutGlop->blend.src, &mOutGlop->blend.dst); 281 } 282 } 283 } 284 mShader = shader; // shader resolved in ::build() 285 286 if (colorFilter) { 287 SkColor color; 288 SkXfermode::Mode mode; 289 SkScalar srcColorMatrix[20]; 290 if (colorFilter->asColorMode(&color, &mode)) { 291 mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::ColorFilterMode::Blend; 292 mDescription.colorMode = mode; 293 294 const float alpha = SkColorGetA(color) / 255.0f; 295 float colorScale = alpha / 255.0f; 296 mOutGlop->fill.filter.color = { 297 colorScale * SkColorGetR(color), 298 colorScale * SkColorGetG(color), 299 colorScale * SkColorGetB(color), 300 alpha, 301 }; 302 } else if (colorFilter->asColorMatrix(srcColorMatrix)) { 303 mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::ColorFilterMode::Matrix; 304 305 float* colorMatrix = mOutGlop->fill.filter.matrix.matrix; 306 memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float)); 307 memcpy(&colorMatrix[4], &srcColorMatrix[5], 4 * sizeof(float)); 308 memcpy(&colorMatrix[8], &srcColorMatrix[10], 4 * sizeof(float)); 309 memcpy(&colorMatrix[12], &srcColorMatrix[15], 4 * sizeof(float)); 310 311 // Skia uses the range [0..255] for the addition vector, but we need 312 // the [0..1] range to apply the vector in GLSL 313 float* colorVector = mOutGlop->fill.filter.matrix.vector; 314 colorVector[0] = srcColorMatrix[4] / 255.0f; 315 colorVector[1] = srcColorMatrix[9] / 255.0f; 316 colorVector[2] = srcColorMatrix[14] / 255.0f; 317 colorVector[3] = srcColorMatrix[19] / 255.0f; 318 } else { 319 LOG_ALWAYS_FATAL("unsupported ColorFilter"); 320 } 321 } else { 322 mOutGlop->fill.filterMode = ProgramDescription::ColorFilterMode::None; 323 } 324} 325 326GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture, 327 const int textureFillFlags, const SkPaint* paint, float alphaScale) { 328 TRIGGER_STAGE(kFillStage); 329 REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); 330 331 GLenum filter = (textureFillFlags & TextureFillFlags::ForceFilter) 332 ? GL_LINEAR : PaintUtils::getFilter(paint); 333 mOutGlop->fill.texture = { &texture, 334 GL_TEXTURE_2D, filter, GL_CLAMP_TO_EDGE, nullptr }; 335 336 if (paint) { 337 int color = paint->getColor(); 338 SkShader* shader = paint->getShader(); 339 340 if (!(textureFillFlags & TextureFillFlags::IsAlphaMaskTexture)) { 341 // Texture defines color, so disable shaders, and reset all non-alpha color channels 342 color |= 0x00FFFFFF; 343 shader = nullptr; 344 } 345 setFill(color, alphaScale, 346 PaintUtils::getXfermode(paint->getXfermode()), Blend::ModeOrderSwap::NoSwap, 347 shader, paint->getColorFilter()); 348 } else { 349 mOutGlop->fill.color = { alphaScale, alphaScale, alphaScale, alphaScale }; 350 351 if (alphaScale < 1.0f 352 || (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha) 353 || texture.blend 354 || mOutGlop->roundRectClipState) { 355 Blend::getFactors(SkXfermode::kSrcOver_Mode, Blend::ModeOrderSwap::NoSwap, 356 &mOutGlop->blend.src, &mOutGlop->blend.dst); 357 } else { 358 mOutGlop->blend = { GL_ZERO, GL_ZERO }; 359 } 360 } 361 362 if (textureFillFlags & TextureFillFlags::IsAlphaMaskTexture) { 363 mDescription.modulate = mOutGlop->fill.color.isNotBlack(); 364 mDescription.hasAlpha8Texture = true; 365 } else { 366 mDescription.modulate = mOutGlop->fill.color.a < 1.0f; 367 } 368 return *this; 369} 370 371GlopBuilder& GlopBuilder::setFillPaint(const SkPaint& paint, float alphaScale) { 372 TRIGGER_STAGE(kFillStage); 373 REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); 374 375 mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr }; 376 377 setFill(paint.getColor(), alphaScale, 378 PaintUtils::getXfermode(paint.getXfermode()), Blend::ModeOrderSwap::NoSwap, 379 paint.getShader(), paint.getColorFilter()); 380 mDescription.modulate = mOutGlop->fill.color.a < 1.0f; 381 return *this; 382} 383 384GlopBuilder& GlopBuilder::setFillPathTexturePaint(PathTexture& texture, 385 const SkPaint& paint, float alphaScale) { 386 TRIGGER_STAGE(kFillStage); 387 REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); 388 389 //specify invalid filter/clamp, since these are always static for PathTextures 390 mOutGlop->fill.texture = { &texture, GL_TEXTURE_2D, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr }; 391 392 setFill(paint.getColor(), alphaScale, 393 PaintUtils::getXfermode(paint.getXfermode()), Blend::ModeOrderSwap::NoSwap, 394 paint.getShader(), paint.getColorFilter()); 395 396 mDescription.hasAlpha8Texture = true; 397 mDescription.modulate = mOutGlop->fill.color.isNotBlack(); 398 return *this; 399} 400 401GlopBuilder& GlopBuilder::setFillShadowTexturePaint(ShadowTexture& texture, int shadowColor, 402 const SkPaint& paint, float alphaScale) { 403 TRIGGER_STAGE(kFillStage); 404 REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); 405 406 //specify invalid filter/clamp, since these are always static for ShadowTextures 407 mOutGlop->fill.texture = { &texture, GL_TEXTURE_2D, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr }; 408 409 const int ALPHA_BITMASK = SK_ColorBLACK; 410 const int COLOR_BITMASK = ~ALPHA_BITMASK; 411 if ((shadowColor & ALPHA_BITMASK) == ALPHA_BITMASK) { 412 // shadow color is fully opaque: override its alpha with that of paint 413 shadowColor &= paint.getColor() | COLOR_BITMASK; 414 } 415 416 setFill(shadowColor, alphaScale, 417 PaintUtils::getXfermode(paint.getXfermode()), Blend::ModeOrderSwap::NoSwap, 418 paint.getShader(), paint.getColorFilter()); 419 420 mDescription.hasAlpha8Texture = true; 421 mDescription.modulate = mOutGlop->fill.color.isNotBlack(); 422 return *this; 423} 424 425GlopBuilder& GlopBuilder::setFillBlack() { 426 TRIGGER_STAGE(kFillStage); 427 REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); 428 429 mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr }; 430 setFill(SK_ColorBLACK, 1.0f, SkXfermode::kSrcOver_Mode, Blend::ModeOrderSwap::NoSwap, 431 nullptr, nullptr); 432 return *this; 433} 434 435GlopBuilder& GlopBuilder::setFillClear() { 436 TRIGGER_STAGE(kFillStage); 437 REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); 438 439 mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr }; 440 setFill(SK_ColorBLACK, 1.0f, SkXfermode::kClear_Mode, Blend::ModeOrderSwap::NoSwap, 441 nullptr, nullptr); 442 return *this; 443} 444 445GlopBuilder& GlopBuilder::setFillLayer(Texture& texture, const SkColorFilter* colorFilter, 446 float alpha, SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage) { 447 TRIGGER_STAGE(kFillStage); 448 REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); 449 450 mOutGlop->fill.texture = { &texture, 451 GL_TEXTURE_2D, GL_LINEAR, GL_CLAMP_TO_EDGE, nullptr }; 452 453 setFill(SK_ColorWHITE, alpha, mode, modeUsage, nullptr, colorFilter); 454 455 mDescription.modulate = mOutGlop->fill.color.a < 1.0f; 456 return *this; 457} 458 459GlopBuilder& GlopBuilder::setFillTextureLayer(Layer& layer, float alpha) { 460 TRIGGER_STAGE(kFillStage); 461 REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); 462 463 mOutGlop->fill.texture = { &(layer.getTexture()), 464 layer.getRenderTarget(), GL_LINEAR, GL_CLAMP_TO_EDGE, &layer.getTexTransform() }; 465 466 setFill(SK_ColorWHITE, alpha, layer.getMode(), Blend::ModeOrderSwap::NoSwap, 467 nullptr, layer.getColorFilter()); 468 469 mDescription.modulate = mOutGlop->fill.color.a < 1.0f; 470 mDescription.hasTextureTransform = true; 471 return *this; 472} 473 474GlopBuilder& GlopBuilder::setFillExternalTexture(Texture& texture, Matrix4& textureTransform) { 475 TRIGGER_STAGE(kFillStage); 476 REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); 477 478 mOutGlop->fill.texture = { &texture, 479 GL_TEXTURE_EXTERNAL_OES, GL_LINEAR, GL_CLAMP_TO_EDGE, 480 &textureTransform }; 481 482 setFill(SK_ColorWHITE, 1.0f, SkXfermode::kSrc_Mode, Blend::ModeOrderSwap::NoSwap, 483 nullptr, nullptr); 484 485 mDescription.modulate = mOutGlop->fill.color.a < 1.0f; 486 mDescription.hasTextureTransform = true; 487 return *this; 488} 489 490//////////////////////////////////////////////////////////////////////////////// 491// Transform 492//////////////////////////////////////////////////////////////////////////////// 493 494GlopBuilder& GlopBuilder::setTransform(const Matrix4& canvas, const int transformFlags) { 495 TRIGGER_STAGE(kTransformStage); 496 497 mOutGlop->transform.canvas = canvas; 498 mOutGlop->transform.transformFlags = transformFlags; 499 return *this; 500} 501 502//////////////////////////////////////////////////////////////////////////////// 503// ModelView 504//////////////////////////////////////////////////////////////////////////////// 505 506GlopBuilder& GlopBuilder::setModelViewMapUnitToRect(const Rect destination) { 507 TRIGGER_STAGE(kModelViewStage); 508 509 mOutGlop->transform.modelView.loadTranslate(destination.left, destination.top, 0.0f); 510 mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f); 511#if !HWUI_NEW_OPS 512 mOutGlop->bounds = destination; 513#endif 514 return *this; 515} 516 517GlopBuilder& GlopBuilder::setModelViewMapUnitToRectSnap(const Rect destination) { 518 TRIGGER_STAGE(kModelViewStage); 519 REQUIRE_STAGES(kTransformStage | kFillStage); 520 521 float left = destination.left; 522 float top = destination.top; 523 524 const Matrix4& meshTransform = mOutGlop->transform.meshTransform(); 525 if (CC_LIKELY(meshTransform.isPureTranslate())) { 526 // snap by adjusting the model view matrix 527 const float translateX = meshTransform.getTranslateX(); 528 const float translateY = meshTransform.getTranslateY(); 529 530 left = (int) floorf(left + translateX + 0.5f) - translateX; 531 top = (int) floorf(top + translateY + 0.5f) - translateY; 532 mOutGlop->fill.texture.filter = GL_NEAREST; 533 } 534 535 mOutGlop->transform.modelView.loadTranslate(left, top, 0.0f); 536 mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f); 537#if !HWUI_NEW_OPS 538 mOutGlop->bounds = destination; 539#endif 540 return *this; 541} 542 543GlopBuilder& GlopBuilder::setModelViewOffsetRect(float offsetX, float offsetY, const Rect source) { 544 TRIGGER_STAGE(kModelViewStage); 545 546 mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f); 547#if !HWUI_NEW_OPS 548 mOutGlop->bounds = source; 549 mOutGlop->bounds.translate(offsetX, offsetY); 550#endif 551 return *this; 552} 553 554GlopBuilder& GlopBuilder::setModelViewOffsetRectSnap(float offsetX, float offsetY, const Rect source) { 555 TRIGGER_STAGE(kModelViewStage); 556 REQUIRE_STAGES(kTransformStage | kFillStage); 557 558 const Matrix4& meshTransform = mOutGlop->transform.meshTransform(); 559 if (CC_LIKELY(meshTransform.isPureTranslate())) { 560 // snap by adjusting the model view matrix 561 const float translateX = meshTransform.getTranslateX(); 562 const float translateY = meshTransform.getTranslateY(); 563 564 offsetX = (int) floorf(offsetX + translateX + source.left + 0.5f) - translateX - source.left; 565 offsetY = (int) floorf(offsetY + translateY + source.top + 0.5f) - translateY - source.top; 566 mOutGlop->fill.texture.filter = GL_NEAREST; 567 } 568 569 mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f); 570#if !HWUI_NEW_OPS 571 mOutGlop->bounds = source; 572 mOutGlop->bounds.translate(offsetX, offsetY); 573#endif 574 return *this; 575} 576 577//////////////////////////////////////////////////////////////////////////////// 578// RoundRectClip 579//////////////////////////////////////////////////////////////////////////////// 580 581GlopBuilder& GlopBuilder::setRoundRectClipState(const RoundRectClipState* roundRectClipState) { 582 TRIGGER_STAGE(kRoundRectClipStage); 583 584 mOutGlop->roundRectClipState = roundRectClipState; 585 mDescription.hasRoundRectClip = roundRectClipState != nullptr; 586 return *this; 587} 588 589//////////////////////////////////////////////////////////////////////////////// 590// Build 591//////////////////////////////////////////////////////////////////////////////// 592 593void verify(const ProgramDescription& description, const Glop& glop) { 594 if (glop.fill.texture.texture != nullptr) { 595 LOG_ALWAYS_FATAL_IF(((description.hasTexture && description.hasExternalTexture) 596 || (!description.hasTexture && !description.hasExternalTexture) 597 || ((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) == 0)), 598 "Texture %p, hT%d, hET %d, attribFlags %x", 599 glop.fill.texture.texture, 600 description.hasTexture, description.hasExternalTexture, 601 glop.mesh.vertices.attribFlags); 602 } else { 603 LOG_ALWAYS_FATAL_IF((description.hasTexture 604 || description.hasExternalTexture 605 || ((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) != 0)), 606 "No texture, hT%d, hET %d, attribFlags %x", 607 description.hasTexture, description.hasExternalTexture, 608 glop.mesh.vertices.attribFlags); 609 } 610 611 if ((glop.mesh.vertices.attribFlags & VertexAttribFlags::Alpha) 612 && glop.mesh.vertices.bufferObject) { 613 LOG_ALWAYS_FATAL("VBO and alpha attributes are not currently compatible"); 614 } 615 616 if (description.hasTextureTransform != (glop.fill.texture.textureTransform != nullptr)) { 617 LOG_ALWAYS_FATAL("Texture transform incorrectly specified"); 618 } 619} 620 621void GlopBuilder::build() { 622 REQUIRE_STAGES(kAllStages); 623 if (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) { 624 if (mOutGlop->fill.texture.target == GL_TEXTURE_2D) { 625 mDescription.hasTexture = true; 626 } else { 627 mDescription.hasExternalTexture = true; 628 } 629 } 630 631 mDescription.hasColors = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Color; 632 mDescription.hasVertexAlpha = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha; 633 634 // Enable debug highlight when what we're about to draw is tested against 635 // the stencil buffer and if stencil highlight debugging is on 636 mDescription.hasDebugHighlight = !Properties::debugOverdraw 637 && Properties::debugStencilClip == StencilClipDebug::ShowHighlight 638 && mRenderState.stencil().isTestEnabled(); 639 640 // serialize shader info into ShaderData 641 GLuint textureUnit = mOutGlop->fill.texture.texture ? 1 : 0; 642 643 if (CC_LIKELY(!mShader)) { 644 mOutGlop->fill.skiaShaderData.skiaShaderType = kNone_SkiaShaderType; 645 } else { 646 Matrix4 shaderMatrix; 647 if (mOutGlop->transform.transformFlags & TransformFlags::MeshIgnoresCanvasTransform) { 648 // canvas level transform was built into the modelView and geometry, 649 // so the shader matrix must reverse this 650 shaderMatrix.loadInverse(mOutGlop->transform.canvas); 651 shaderMatrix.multiply(mOutGlop->transform.modelView); 652 } else { 653 shaderMatrix = mOutGlop->transform.modelView; 654 } 655 SkiaShader::store(mCaches, *mShader, shaderMatrix, 656 &textureUnit, &mDescription, &(mOutGlop->fill.skiaShaderData)); 657 } 658 659 // duplicates ProgramCache's definition of color uniform presence 660 const bool singleColor = !mDescription.hasTexture 661 && !mDescription.hasExternalTexture 662 && !mDescription.hasGradient 663 && !mDescription.hasBitmap; 664 mOutGlop->fill.colorEnabled = mDescription.modulate || singleColor; 665 666 verify(mDescription, *mOutGlop); 667 668 // Final step: populate program and map bounds into render target space 669 mOutGlop->fill.program = mCaches.programCache.get(mDescription); 670#if !HWUI_NEW_OPS 671 mOutGlop->transform.meshTransform().mapRect(mOutGlop->bounds); 672#endif 673} 674 675void GlopBuilder::dump(const Glop& glop) { 676 ALOGD("Glop Mesh"); 677 const Glop::Mesh& mesh = glop.mesh; 678 ALOGD(" primitive mode: %d", mesh.primitiveMode); 679 ALOGD(" indices: buffer obj %x, indices %p", mesh.indices.bufferObject, mesh.indices.indices); 680 681 const Glop::Mesh::Vertices& vertices = glop.mesh.vertices; 682 ALOGD(" vertices: buffer obj %x, flags %x, pos %p, tex %p, clr %p, stride %d", 683 vertices.bufferObject, vertices.attribFlags, 684 vertices.position, vertices.texCoord, vertices.color, vertices.stride); 685 ALOGD(" element count: %d", mesh.elementCount); 686 687 ALOGD("Glop Fill"); 688 const Glop::Fill& fill = glop.fill; 689 ALOGD(" program %p", fill.program); 690 if (fill.texture.texture) { 691 ALOGD(" texture %p, target %d, filter %d, clamp %d", 692 fill.texture.texture, fill.texture.target, fill.texture.filter, fill.texture.clamp); 693 if (fill.texture.textureTransform) { 694 fill.texture.textureTransform->dump("texture transform"); 695 } 696 } 697 ALOGD_IF(fill.colorEnabled, " color (argb) %.2f %.2f %.2f %.2f", 698 fill.color.a, fill.color.r, fill.color.g, fill.color.b); 699 ALOGD_IF(fill.filterMode != ProgramDescription::ColorFilterMode::None, 700 " filterMode %d", (int)fill.filterMode); 701 ALOGD_IF(fill.skiaShaderData.skiaShaderType, " shader type %d", 702 fill.skiaShaderData.skiaShaderType); 703 704 ALOGD("Glop transform"); 705 glop.transform.modelView.dump(" model view"); 706 glop.transform.canvas.dump(" canvas"); 707 ALOGD_IF(glop.transform.transformFlags, " transformFlags 0x%x", glop.transform.transformFlags); 708 709 ALOGD_IF(glop.roundRectClipState, "Glop RRCS %p", glop.roundRectClipState); 710 711 ALOGD("Glop blend %d %d", glop.blend.src, glop.blend.dst); 712#if !HWUI_NEW_OPS 713 ALOGD("Glop bounds " RECT_STRING, RECT_ARGS(glop.bounds)); 714#endif 715} 716 717} /* namespace uirenderer */ 718} /* namespace android */ 719