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