BakedOpDispatcher.cpp revision d7448e65e243754f31890baef29dff187dc2e5e5
19e7fcfda28fde747ba4e026772007cea77374e16Chris Craik/* 29e7fcfda28fde747ba4e026772007cea77374e16Chris Craik * Copyright (C) 2015 The Android Open Source Project 39e7fcfda28fde747ba4e026772007cea77374e16Chris Craik * 49e7fcfda28fde747ba4e026772007cea77374e16Chris Craik * Licensed under the Apache License, Version 2.0 (the "License"); 59e7fcfda28fde747ba4e026772007cea77374e16Chris Craik * you may not use this file except in compliance with the License. 69e7fcfda28fde747ba4e026772007cea77374e16Chris Craik * You may obtain a copy of the License at 79e7fcfda28fde747ba4e026772007cea77374e16Chris Craik * 89e7fcfda28fde747ba4e026772007cea77374e16Chris Craik * http://www.apache.org/licenses/LICENSE-2.0 99e7fcfda28fde747ba4e026772007cea77374e16Chris Craik * 109e7fcfda28fde747ba4e026772007cea77374e16Chris Craik * Unless required by applicable law or agreed to in writing, software 119e7fcfda28fde747ba4e026772007cea77374e16Chris Craik * distributed under the License is distributed on an "AS IS" BASIS, 129e7fcfda28fde747ba4e026772007cea77374e16Chris Craik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139e7fcfda28fde747ba4e026772007cea77374e16Chris Craik * See the License for the specific language governing permissions and 149e7fcfda28fde747ba4e026772007cea77374e16Chris Craik * limitations under the License. 159e7fcfda28fde747ba4e026772007cea77374e16Chris Craik */ 169e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 179e7fcfda28fde747ba4e026772007cea77374e16Chris Craik#include "BakedOpDispatcher.h" 189e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 199e7fcfda28fde747ba4e026772007cea77374e16Chris Craik#include "BakedOpRenderer.h" 209e7fcfda28fde747ba4e026772007cea77374e16Chris Craik#include "Caches.h" 219e7fcfda28fde747ba4e026772007cea77374e16Chris Craik#include "Glop.h" 229e7fcfda28fde747ba4e026772007cea77374e16Chris Craik#include "GlopBuilder.h" 23f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik#include "Patch.h" 24386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik#include "PathTessellator.h" 259e7fcfda28fde747ba4e026772007cea77374e16Chris Craik#include "renderstate/OffscreenBufferPool.h" 269e7fcfda28fde747ba4e026772007cea77374e16Chris Craik#include "renderstate/RenderState.h" 279e7fcfda28fde747ba4e026772007cea77374e16Chris Craik#include "utils/GLUtils.h" 289e7fcfda28fde747ba4e026772007cea77374e16Chris Craik#include "VertexBuffer.h" 299e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 309e7fcfda28fde747ba4e026772007cea77374e16Chris Craik#include <algorithm> 319e7fcfda28fde747ba4e026772007cea77374e16Chris Craik#include <math.h> 32386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik#include <SkPaintDefaults.h> 339e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 349e7fcfda28fde747ba4e026772007cea77374e16Chris Craiknamespace android { 359e7fcfda28fde747ba4e026772007cea77374e16Chris Craiknamespace uirenderer { 369e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 3715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craikstatic void storeTexturedRect(TextureVertex* vertices, const Rect& bounds, const Rect& texCoord) { 3815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik vertices[0] = { bounds.left, bounds.top, texCoord.left, texCoord.top }; 3915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik vertices[1] = { bounds.right, bounds.top, texCoord.right, texCoord.top }; 4015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik vertices[2] = { bounds.left, bounds.bottom, texCoord.left, texCoord.bottom }; 4115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik vertices[3] = { bounds.right, bounds.bottom, texCoord.right, texCoord.bottom }; 4215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik} 4315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik 4415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craikvoid BakedOpDispatcher::onMergedBitmapOps(BakedOpRenderer& renderer, 4515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik const MergedBakedOpList& opList) { 4615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik 4715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik const BakedOpState& firstState = *(opList.states[0]); 4815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik const SkBitmap* bitmap = (static_cast<const BitmapOp*>(opList.states[0]->op))->bitmap; 4915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik 5015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik AssetAtlas::Entry* entry = renderer.renderState().assetAtlas().getEntry(bitmap->pixelRef()); 5115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik Texture* texture = entry ? entry->texture : renderer.caches().textureCache.get(bitmap); 5215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik if (!texture) return; 5315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik const AutoTexture autoCleanup(texture); 5415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik 5515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik TextureVertex vertices[opList.count * 4]; 5615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik Rect texCoords(0, 0, 1, 1); 5715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik if (entry) { 5815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik entry->uvMapper.map(texCoords); 5915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik } 6015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik for (size_t i = 0; i < opList.count; i++) { 6115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik const BakedOpState& state = *(opList.states[i]); 6215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik TextureVertex* rectVerts = &vertices[i * 4]; 6315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik Rect opBounds = state.computedState.clippedBounds; 6415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik if (CC_LIKELY(state.computedState.transform.isPureTranslate())) { 6515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik // pure translate, so snap (same behavior as onBitmapOp) 6615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik opBounds.snapToPixelBoundaries(); 6715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik } 6815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik storeTexturedRect(rectVerts, opBounds, texCoords); 6915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik renderer.dirtyRenderTarget(opBounds); 7015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik } 7115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik 7215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType) 7315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None; 7415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik Glop glop; 7515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 7615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik .setRoundRectClipState(firstState.roundRectClipState) 7715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik .setMeshTexturedIndexedQuads(vertices, opList.count * 6) 7815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik .setFillTexturePaint(*texture, textureFillFlags, firstState.op->paint, firstState.alpha) 7915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik .setTransform(Matrix4::identity(), TransformFlags::None) 80f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setModelViewIdentityEmptyBounds() 81f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .build(); 82f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik renderer.renderGlop(nullptr, opList.clipSideFlags ? &opList.clip : nullptr, glop); 83f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik} 84f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 85f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craikvoid BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer, 86f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const MergedBakedOpList& opList) { 87f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const PatchOp& firstOp = *(static_cast<const PatchOp*>(opList.states[0]->op)); 88f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const BakedOpState& firstState = *(opList.states[0]); 89f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik AssetAtlas::Entry* entry = renderer.renderState().assetAtlas().getEntry( 90f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik firstOp.bitmap->pixelRef()); 91f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 92f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // Batches will usually contain a small number of items so it's 93f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // worth performing a first iteration to count the exact number 94f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // of vertices we need in the new mesh 95f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik uint32_t totalVertices = 0; 96f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 97f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik for (size_t i = 0; i < opList.count; i++) { 98f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const PatchOp& op = *(static_cast<const PatchOp*>(opList.states[i]->op)); 99f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 100f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // TODO: cache mesh lookups 101f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const Patch* opMesh = renderer.caches().patchCache.get( 102f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik entry, op.bitmap->width(), op.bitmap->height(), 103f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch); 104f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik totalVertices += opMesh->verticesCount; 105f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik } 106f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 107f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const bool dirtyRenderTarget = renderer.offscreenRenderTarget(); 108f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 109f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik uint32_t indexCount = 0; 110f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 111f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik TextureVertex vertices[totalVertices]; 112f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik TextureVertex* vertex = &vertices[0]; 113f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // Create a mesh that contains the transformed vertices for all the 114f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // 9-patch objects that are part of the batch. Note that onDefer() 115f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // enforces ops drawn by this function to have a pure translate or 116f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // identity matrix 117f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik for (size_t i = 0; i < opList.count; i++) { 118f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const PatchOp& op = *(static_cast<const PatchOp*>(opList.states[i]->op)); 119f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const BakedOpState& state = *opList.states[i]; 120f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 121f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // TODO: cache mesh lookups 122f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const Patch* opMesh = renderer.caches().patchCache.get( 123f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik entry, op.bitmap->width(), op.bitmap->height(), 124f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch); 125f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 126f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 127f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik uint32_t vertexCount = opMesh->verticesCount; 128f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik if (vertexCount == 0) continue; 129f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 130f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // We use the bounds to know where to translate our vertices 131f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // Using patchOp->state.mBounds wouldn't work because these 132f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // bounds are clipped 133f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const float tx = floorf(state.computedState.transform.getTranslateX() 134f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik + op.unmappedBounds.left + 0.5f); 135f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const float ty = floorf(state.computedState.transform.getTranslateY() 136f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik + op.unmappedBounds.top + 0.5f); 137f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 138f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // Copy & transform all the vertices for the current operation 139f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik TextureVertex* opVertices = opMesh->vertices.get(); 140f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik for (uint32_t j = 0; j < vertexCount; j++, opVertices++) { 141f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik TextureVertex::set(vertex++, 142f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik opVertices->x + tx, opVertices->y + ty, 143f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik opVertices->u, opVertices->v); 144f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik } 145f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 146f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // Dirty the current layer if possible. When the 9-patch does not 147f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // contain empty quads we can take a shortcut and simply set the 148f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // dirty rect to the object's bounds. 149f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik if (dirtyRenderTarget) { 150f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik if (!opMesh->hasEmptyQuads) { 151f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik renderer.dirtyRenderTarget(Rect(tx, ty, 152f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik tx + op.unmappedBounds.getWidth(), ty + op.unmappedBounds.getHeight())); 153f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik } else { 154f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const size_t count = opMesh->quads.size(); 155f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik for (size_t i = 0; i < count; i++) { 156f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const Rect& quadBounds = opMesh->quads[i]; 157f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const float x = tx + quadBounds.left; 158f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const float y = ty + quadBounds.top; 159f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik renderer.dirtyRenderTarget(Rect(x, y, 160f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik x + quadBounds.getWidth(), y + quadBounds.getHeight())); 161f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik } 162f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik } 163f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik } 164f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 165f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik indexCount += opMesh->indexCount; 166f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik } 167f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 168f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 169f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik Texture* texture = entry ? entry->texture : renderer.caches().textureCache.get(firstOp.bitmap); 170f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik if (!texture) return; 171f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const AutoTexture autoCleanup(texture); 172f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 173f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // 9 patches are built for stretching - always filter 174f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik int textureFillFlags = TextureFillFlags::ForceFilter; 175f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik if (firstOp.bitmap->colorType() == kAlpha_8_SkColorType) { 176f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture; 177f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik } 178f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik Glop glop; 179f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 180f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setRoundRectClipState(firstState.roundRectClipState) 181f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setMeshTexturedIndexedQuads(vertices, indexCount) 182f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setFillTexturePaint(*texture, textureFillFlags, firstOp.paint, firstState.alpha) 183f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setTransform(Matrix4::identity(), TransformFlags::None) 184f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setModelViewIdentityEmptyBounds() 18515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik .build(); 18615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik renderer.renderGlop(nullptr, opList.clipSideFlags ? &opList.clip : nullptr, glop); 18715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik} 18815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik 18915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craikstatic void renderTextShadow(BakedOpRenderer& renderer, FontRenderer& fontRenderer, 19015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik const TextOp& op, const BakedOpState& state) { 19115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik renderer.caches().textureState().activateTexture(0); 19215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik 19315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik PaintUtils::TextShadow textShadow; 19415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik if (!PaintUtils::getTextShadow(op.paint, &textShadow)) { 19515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik LOG_ALWAYS_FATAL("failed to query shadow attributes"); 19615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik } 19715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik 19815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik renderer.caches().dropShadowCache.setFontRenderer(fontRenderer); 19915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik ShadowTexture* texture = renderer.caches().dropShadowCache.get( 20015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik op.paint, (const char*) op.glyphs, 20115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik op.glyphCount, textShadow.radius, op.positions); 20215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik // If the drop shadow exceeds the max texture size or couldn't be 20315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik // allocated, skip drawing 20415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik if (!texture) return; 20515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik const AutoTexture autoCleanup(texture); 20615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik 20715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik const float sx = op.x - texture->left + textShadow.dx; 20815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik const float sy = op.y - texture->top + textShadow.dy; 20915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik 21015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik Glop glop; 21115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 21215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik .setRoundRectClipState(state.roundRectClipState) 21315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik .setMeshTexturedUnitQuad(nullptr) 21415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik .setFillShadowTexturePaint(*texture, textShadow.color, *op.paint, state.alpha) 21515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik .setTransform(state.computedState.transform, TransformFlags::None) 21615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width, sy + texture->height)) 21715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik .build(); 21815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik renderer.renderGlop(state, glop); 21915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik} 22015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik 22115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craikenum class TextRenderType { 22215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik Defer, 22315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik Flush 22415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik}; 22515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik 22615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craikstatic void renderTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state, 22715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik const Rect* renderClip, TextRenderType renderType) { 22815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer(); 22915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik 23015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik if (CC_UNLIKELY(PaintUtils::hasTextShadow(op.paint))) { 23115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik fontRenderer.setFont(op.paint, SkMatrix::I()); 23215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik renderTextShadow(renderer, fontRenderer, op, state); 23315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik } 23415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik 23515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik float x = op.x; 23615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik float y = op.y; 23715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik const Matrix4& transform = state.computedState.transform; 23815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik const bool pureTranslate = transform.isPureTranslate(); 23915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik if (CC_LIKELY(pureTranslate)) { 24015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik x = floorf(x + transform.getTranslateX() + 0.5f); 24115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik y = floorf(y + transform.getTranslateY() + 0.5f); 24215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik fontRenderer.setFont(op.paint, SkMatrix::I()); 24315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik fontRenderer.setTextureFiltering(false); 24415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik } else if (CC_UNLIKELY(transform.isPerspective())) { 24515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik fontRenderer.setFont(op.paint, SkMatrix::I()); 24615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik fontRenderer.setTextureFiltering(true); 24715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik } else { 24815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik // We only pass a partial transform to the font renderer. That partial 24915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik // matrix defines how glyphs are rasterized. Typically we want glyphs 25015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik // to be rasterized at their final size on screen, which means the partial 25115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik // matrix needs to take the scale factor into account. 25215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik // When a partial matrix is used to transform glyphs during rasterization, 25315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik // the mesh is generated with the inverse transform (in the case of scale, 25415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik // the mesh is generated at 1.0 / scale for instance.) This allows us to 25515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik // apply the full transform matrix at draw time in the vertex shader. 25615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik // Applying the full matrix in the shader is the easiest way to handle 25715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik // rotation and perspective and allows us to always generated quads in the 25815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik // font renderer which greatly simplifies the code, clipping in particular. 25915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik float sx, sy; 26015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik transform.decomposeScale(sx, sy); 26115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik fontRenderer.setFont(op.paint, SkMatrix::MakeScale( 26215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik roundf(std::max(1.0f, sx)), 26315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik roundf(std::max(1.0f, sy)))); 26415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik fontRenderer.setTextureFiltering(true); 26515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik } 26615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); 26715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik 26815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik int alpha = PaintUtils::getAlphaDirect(op.paint) * state.alpha; 26915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(op.paint); 27015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik TextDrawFunctor functor(&renderer, &state, renderClip, 27115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik x, y, pureTranslate, alpha, mode, op.paint); 27215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik 27315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik bool forceFinish = (renderType == TextRenderType::Flush); 27415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik bool mustDirtyRenderTarget = renderer.offscreenRenderTarget(); 27515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik const Rect* localOpClip = pureTranslate ? &state.computedState.clipRect : nullptr; 27615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik fontRenderer.renderPosText(op.paint, localOpClip, 27715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik (const char*) op.glyphs, op.glyphCount, x, y, 27815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik op.positions, mustDirtyRenderTarget ? &layerBounds : nullptr, &functor, forceFinish); 27915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik 28015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik if (mustDirtyRenderTarget) { 28115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik if (!pureTranslate) { 28215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik transform.mapRect(layerBounds); 28315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik } 28415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik renderer.dirtyRenderTarget(layerBounds); 28515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik } 28615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik} 28715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik 28815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craikvoid BakedOpDispatcher::onMergedTextOps(BakedOpRenderer& renderer, 28915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik const MergedBakedOpList& opList) { 29015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik const Rect* clip = opList.clipSideFlags ? &opList.clip : nullptr; 29115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik for (size_t i = 0; i < opList.count; i++) { 29215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik const BakedOpState& state = *(opList.states[i]); 29315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik const TextOp& op = *(static_cast<const TextOp*>(state.op)); 29415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik TextRenderType renderType = (i + 1 == opList.count) 29515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik ? TextRenderType::Flush : TextRenderType::Defer; 29615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik renderTextOp(renderer, op, state, clip, renderType); 29715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik } 29815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik} 29915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik 3009e7fcfda28fde747ba4e026772007cea77374e16Chris Craikvoid BakedOpDispatcher::onRenderNodeOp(BakedOpRenderer&, const RenderNodeOp&, const BakedOpState&) { 3019e7fcfda28fde747ba4e026772007cea77374e16Chris Craik LOG_ALWAYS_FATAL("unsupported operation"); 3029e7fcfda28fde747ba4e026772007cea77374e16Chris Craik} 3039e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 30415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craikvoid BakedOpDispatcher::onBeginLayerOp(BakedOpRenderer&, const BeginLayerOp&, const BakedOpState&) { 3059e7fcfda28fde747ba4e026772007cea77374e16Chris Craik LOG_ALWAYS_FATAL("unsupported operation"); 3069e7fcfda28fde747ba4e026772007cea77374e16Chris Craik} 3079e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 30815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craikvoid BakedOpDispatcher::onEndLayerOp(BakedOpRenderer&, const EndLayerOp&, const BakedOpState&) { 3099e7fcfda28fde747ba4e026772007cea77374e16Chris Craik LOG_ALWAYS_FATAL("unsupported operation"); 3109e7fcfda28fde747ba4e026772007cea77374e16Chris Craik} 3119e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 312268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid BakedOpDispatcher::onCirclePropsOp(BakedOpRenderer&, const CirclePropsOp&, const BakedOpState&) { 313268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik LOG_ALWAYS_FATAL("unsupported operation"); 314268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik} 315268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik 316268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid BakedOpDispatcher::onRoundRectPropsOp(BakedOpRenderer&, const RoundRectPropsOp&, const BakedOpState&) { 317268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik LOG_ALWAYS_FATAL("unsupported operation"); 318268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik} 319268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik 320386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craiknamespace VertexBufferRenderFlags { 321386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik enum { 322386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik Offset = 0x1, 323386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik ShadowInterp = 0x2, 324386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik }; 325386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik} 326386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik 327386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craikstatic void renderVertexBuffer(BakedOpRenderer& renderer, const BakedOpState& state, 328386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik const VertexBuffer& vertexBuffer, float translateX, float translateY, 329386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik const SkPaint& paint, int vertexBufferRenderFlags) { 330386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik if (CC_LIKELY(vertexBuffer.getVertexCount())) { 331386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik bool shadowInterp = vertexBufferRenderFlags & VertexBufferRenderFlags::ShadowInterp; 332386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik const int transformFlags = TransformFlags::OffsetByFudgeFactor; 333386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik Glop glop; 334386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 335386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik .setRoundRectClipState(state.roundRectClipState) 336386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik .setMeshVertexBuffer(vertexBuffer, shadowInterp) 337386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik .setFillPaint(paint, state.alpha) 338386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik .setTransform(state.computedState.transform, transformFlags) 339386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds()) 340386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik .build(); 341386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik renderer.renderGlop(state, glop); 342386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik } 343386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik} 344386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik 345386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craikstatic void renderConvexPath(BakedOpRenderer& renderer, const BakedOpState& state, 346386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik const SkPath& path, const SkPaint& paint) { 347386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik VertexBuffer vertexBuffer; 348386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik // TODO: try clipping large paths to viewport 349386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik PathTessellator::tessellatePath(path, &paint, state.computedState.transform, vertexBuffer); 350386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik renderVertexBuffer(renderer, state, vertexBuffer, 0.0f, 0.0f, paint, 0); 351386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik} 352386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik 353386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craikstatic void renderPathTexture(BakedOpRenderer& renderer, const BakedOpState& state, 354386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik PathTexture& texture, const RecordedOp& op) { 355386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik Rect dest(texture.width, texture.height); 356386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik dest.translate(texture.left + op.unmappedBounds.left - texture.offset, 357386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik texture.top + op.unmappedBounds.top - texture.offset); 358386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik Glop glop; 359386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 360386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik .setRoundRectClipState(state.roundRectClipState) 361386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik .setMeshTexturedUnitQuad(nullptr) 362386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik .setFillPathTexturePaint(texture, *(op.paint), state.alpha) 363386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik .setTransform(state.computedState.transform, TransformFlags::None) 364386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik .setModelViewMapUnitToRect(dest) 365386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik .build(); 366386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik renderer.renderGlop(state, glop); 367386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik} 368386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik 369386aa031793bb037ec43b6cdbd8908c343cc86cbChris CraikSkRect getBoundsOfFill(const RecordedOp& op) { 370386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik SkRect bounds = op.unmappedBounds.toSkRect(); 371386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik if (op.paint->getStyle() == SkPaint::kStrokeAndFill_Style) { 372386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik float outsetDistance = op.paint->getStrokeWidth() / 2; 373386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik bounds.outset(outsetDistance, outsetDistance); 374386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik } 375386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik return bounds; 376386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik} 377386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik 378386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craikvoid BakedOpDispatcher::onArcOp(BakedOpRenderer& renderer, const ArcOp& op, const BakedOpState& state) { 379386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180) 380386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik if (op.paint->getStyle() != SkPaint::kStroke_Style 381386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik || op.paint->getPathEffect() != nullptr 382386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik || op.useCenter) { 383386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik PathTexture* texture = renderer.caches().pathCache.getArc( 384386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), 385386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik op.startAngle, op.sweepAngle, op.useCenter, op.paint); 386386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik const AutoTexture holder(texture); 387386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik if (CC_LIKELY(holder.texture)) { 388386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik renderPathTexture(renderer, state, *texture, op); 389386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik } 390386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik } else { 391386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik SkRect rect = getBoundsOfFill(op); 392386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik SkPath path; 393386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik if (op.useCenter) { 394386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik path.moveTo(rect.centerX(), rect.centerY()); 395386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik } 396386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik path.arcTo(rect, op.startAngle, op.sweepAngle, !op.useCenter); 397386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik if (op.useCenter) { 398386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik path.close(); 399386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik } 400386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik renderConvexPath(renderer, state, path, *(op.paint)); 401386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik } 402386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik} 403386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik 4049e7fcfda28fde747ba4e026772007cea77374e16Chris Craikvoid BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op, const BakedOpState& state) { 4059e7fcfda28fde747ba4e026772007cea77374e16Chris Craik Texture* texture = renderer.getTexture(op.bitmap); 4069e7fcfda28fde747ba4e026772007cea77374e16Chris Craik if (!texture) return; 4079e7fcfda28fde747ba4e026772007cea77374e16Chris Craik const AutoTexture autoCleanup(texture); 4089e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 4099e7fcfda28fde747ba4e026772007cea77374e16Chris Craik const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType) 4109e7fcfda28fde747ba4e026772007cea77374e16Chris Craik ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None; 4119e7fcfda28fde747ba4e026772007cea77374e16Chris Craik Glop glop; 4129e7fcfda28fde747ba4e026772007cea77374e16Chris Craik GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 4139e7fcfda28fde747ba4e026772007cea77374e16Chris Craik .setRoundRectClipState(state.roundRectClipState) 4149e7fcfda28fde747ba4e026772007cea77374e16Chris Craik .setMeshTexturedUnitQuad(texture->uvMapper) 4159e7fcfda28fde747ba4e026772007cea77374e16Chris Craik .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha) 4169e7fcfda28fde747ba4e026772007cea77374e16Chris Craik .setTransform(state.computedState.transform, TransformFlags::None) 4175430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik .setModelViewMapUnitToRectSnap(Rect(texture->width, texture->height)) 4189e7fcfda28fde747ba4e026772007cea77374e16Chris Craik .build(); 4199e7fcfda28fde747ba4e026772007cea77374e16Chris Craik renderer.renderGlop(state, glop); 4209e7fcfda28fde747ba4e026772007cea77374e16Chris Craik} 4219e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 422f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craikvoid BakedOpDispatcher::onBitmapMeshOp(BakedOpRenderer& renderer, const BitmapMeshOp& op, const BakedOpState& state) { 423f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const static UvMapper defaultUvMapper; 424f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const uint32_t elementCount = op.meshWidth * op.meshHeight * 6; 425f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 426f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik std::unique_ptr<ColorTextureVertex[]> mesh(new ColorTextureVertex[elementCount]); 427f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik ColorTextureVertex* vertex = &mesh[0]; 428f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 429f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const int* colors = op.colors; 430f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik std::unique_ptr<int[]> tempColors; 431f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik if (!colors) { 432f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik uint32_t colorsCount = (op.meshWidth + 1) * (op.meshHeight + 1); 433f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik tempColors.reset(new int[colorsCount]); 434f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik memset(tempColors.get(), 0xff, colorsCount * sizeof(int)); 435f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik colors = tempColors.get(); 436f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik } 437f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 438f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik Texture* texture = renderer.renderState().assetAtlas().getEntryTexture(op.bitmap->pixelRef()); 439f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const UvMapper& mapper(texture && texture->uvMapper ? *texture->uvMapper : defaultUvMapper); 440f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 441f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik for (int32_t y = 0; y < op.meshHeight; y++) { 442f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik for (int32_t x = 0; x < op.meshWidth; x++) { 443f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik uint32_t i = (y * (op.meshWidth + 1) + x) * 2; 444f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 445f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik float u1 = float(x) / op.meshWidth; 446f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik float u2 = float(x + 1) / op.meshWidth; 447f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik float v1 = float(y) / op.meshHeight; 448f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik float v2 = float(y + 1) / op.meshHeight; 449f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 450f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik mapper.map(u1, v1, u2, v2); 451f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 452f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik int ax = i + (op.meshWidth + 1) * 2; 453f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik int ay = ax + 1; 454f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik int bx = i; 455f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik int by = bx + 1; 456f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik int cx = i + 2; 457f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik int cy = cx + 1; 458f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik int dx = i + (op.meshWidth + 1) * 2 + 2; 459f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik int dy = dx + 1; 460f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 461f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const float* vertices = op.vertices; 462f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]); 463f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]); 464f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]); 465f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 466f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]); 467f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]); 468f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]); 469f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik } 470f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik } 471f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 472f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik if (!texture) { 473f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik texture = renderer.caches().textureCache.get(op.bitmap); 474f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik if (!texture) { 475f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik return; 476f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik } 477f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik } 478f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const AutoTexture autoCleanup(texture); 479f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 480f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik /* 481f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik * TODO: handle alpha_8 textures correctly by applying paint color, but *not* 482f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik * shader in that case to mimic the behavior in SkiaCanvas::drawBitmapMesh. 483f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik */ 484f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const int textureFillFlags = TextureFillFlags::None; 485f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik Glop glop; 486f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 487f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setRoundRectClipState(state.roundRectClipState) 488f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setMeshColoredTexturedMesh(mesh.get(), elementCount) 489f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha) 490f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setTransform(state.computedState.transform, TransformFlags::None) 491f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setModelViewOffsetRect(0, 0, op.unmappedBounds) 492f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .build(); 493f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik renderer.renderGlop(state, glop); 494f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik} 495f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 496f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craikvoid BakedOpDispatcher::onBitmapRectOp(BakedOpRenderer& renderer, const BitmapRectOp& op, const BakedOpState& state) { 497f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik Texture* texture = renderer.getTexture(op.bitmap); 498f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik if (!texture) return; 499f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const AutoTexture autoCleanup(texture); 500f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 501f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik Rect uv(std::max(0.0f, op.src.left / texture->width), 502f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik std::max(0.0f, op.src.top / texture->height), 503f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik std::min(1.0f, op.src.right / texture->width), 504f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik std::min(1.0f, op.src.bottom / texture->height)); 505f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 506f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType) 507f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None; 508f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const bool tryToSnap = MathUtils::areEqual(op.src.getWidth(), op.unmappedBounds.getWidth()) 509f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik && MathUtils::areEqual(op.src.getHeight(), op.unmappedBounds.getHeight()); 510f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik Glop glop; 511f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 512f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setRoundRectClipState(state.roundRectClipState) 513f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setMeshTexturedUvQuad(texture->uvMapper, uv) 514f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha) 515f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setTransform(state.computedState.transform, TransformFlags::None) 516f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setModelViewMapUnitToRectOptionalSnap(tryToSnap, op.unmappedBounds) 517f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .build(); 518f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik renderer.renderGlop(state, glop); 519f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik} 520f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 521e29ce6f51d681af7649c0a7cddee97c471e43eb5Chris Craikvoid BakedOpDispatcher::onFunctorOp(BakedOpRenderer& renderer, const FunctorOp& op, const BakedOpState& state) { 522e29ce6f51d681af7649c0a7cddee97c471e43eb5Chris Craik renderer.renderFunctor(op, state); 523e29ce6f51d681af7649c0a7cddee97c471e43eb5Chris Craik} 524e29ce6f51d681af7649c0a7cddee97c471e43eb5Chris Craik 5259e7fcfda28fde747ba4e026772007cea77374e16Chris Craikvoid BakedOpDispatcher::onLinesOp(BakedOpRenderer& renderer, const LinesOp& op, const BakedOpState& state) { 526386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik VertexBuffer buffer; 527386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik PathTessellator::tessellateLines(op.points, op.floatCount, op.paint, 528386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik state.computedState.transform, buffer); 529386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik int displayFlags = op.paint->isAntiAlias() ? 0 : VertexBufferRenderFlags::Offset; 530386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik renderVertexBuffer(renderer, state, buffer, 0, 0, *(op.paint), displayFlags); 5319e7fcfda28fde747ba4e026772007cea77374e16Chris Craik} 5329e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 533386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craikvoid BakedOpDispatcher::onOvalOp(BakedOpRenderer& renderer, const OvalOp& op, const BakedOpState& state) { 534386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik if (op.paint->getPathEffect() != nullptr) { 535386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik PathTexture* texture = renderer.caches().pathCache.getOval( 536386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.paint); 537386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik const AutoTexture holder(texture); 538386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik if (CC_LIKELY(holder.texture)) { 539386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik renderPathTexture(renderer, state, *texture, op); 540386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik } 541386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik } else { 542386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik SkPath path; 543386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik SkRect rect = getBoundsOfFill(op); 544386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik path.addOval(rect); 545386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik renderConvexPath(renderer, state, path, *(op.paint)); 546386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik } 5479e7fcfda28fde747ba4e026772007cea77374e16Chris Craik} 5489e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 549f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craikvoid BakedOpDispatcher::onPatchOp(BakedOpRenderer& renderer, const PatchOp& op, const BakedOpState& state) { 550f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // 9 patches are built for stretching - always filter 551f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik int textureFillFlags = TextureFillFlags::ForceFilter; 552f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik if (op.bitmap->colorType() == kAlpha_8_SkColorType) { 553f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture; 554f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik } 555f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 556f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // TODO: avoid redoing the below work each frame: 557f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik AssetAtlas::Entry* entry = renderer.renderState().assetAtlas().getEntry(op.bitmap->pixelRef()); 558f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const Patch* mesh = renderer.caches().patchCache.get( 559f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik entry, op.bitmap->width(), op.bitmap->height(), 560f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch); 561f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 562f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik Texture* texture = entry ? entry->texture : renderer.caches().textureCache.get(op.bitmap); 563f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik if (!texture) return; 564f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik const AutoTexture autoCleanup(texture); 565f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik Glop glop; 566f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 567f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setRoundRectClipState(state.roundRectClipState) 568f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setMeshPatchQuads(*mesh) 569f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setMeshTexturedUnitQuad(texture->uvMapper) 570f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha) 571f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setTransform(state.computedState.transform, TransformFlags::None) 572f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top, 573f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight())) 574f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik .build(); 575f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik renderer.renderGlop(state, glop); 576f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik} 577f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 578386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craikvoid BakedOpDispatcher::onPathOp(BakedOpRenderer& renderer, const PathOp& op, const BakedOpState& state) { 579386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik PathTexture* texture = renderer.caches().pathCache.get(op.path, op.paint); 580386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik const AutoTexture holder(texture); 581386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik if (CC_LIKELY(holder.texture)) { 582386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik renderPathTexture(renderer, state, *texture, op); 583386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik } 5849e7fcfda28fde747ba4e026772007cea77374e16Chris Craik} 5859e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 586386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craikvoid BakedOpDispatcher::onPointsOp(BakedOpRenderer& renderer, const PointsOp& op, const BakedOpState& state) { 587386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik VertexBuffer buffer; 588386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik PathTessellator::tessellatePoints(op.points, op.floatCount, op.paint, 589386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik state.computedState.transform, buffer); 590386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik int displayFlags = op.paint->isAntiAlias() ? 0 : VertexBufferRenderFlags::Offset; 591386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik renderVertexBuffer(renderer, state, buffer, 0, 0, *(op.paint), displayFlags); 592386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik} 593386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik 594386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik// See SkPaintDefaults.h 595386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik#define SkPaintDefaults_MiterLimit SkIntToScalar(4) 596386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik 597386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craikvoid BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, const BakedOpState& state) { 598386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik if (op.paint->getStyle() != SkPaint::kFill_Style) { 599386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik // only fill + default miter is supported by drawConvexPath, since others must handle joins 600386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik static_assert(SkPaintDefaults_MiterLimit == 4.0f, "Miter limit has changed"); 601386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik if (CC_UNLIKELY(op.paint->getPathEffect() != nullptr 602386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik || op.paint->getStrokeJoin() != SkPaint::kMiter_Join 603386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik || op.paint->getStrokeMiter() != SkPaintDefaults_MiterLimit)) { 604386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik PathTexture* texture = renderer.caches().pathCache.getRect( 605386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.paint); 606386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik const AutoTexture holder(texture); 607386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik if (CC_LIKELY(holder.texture)) { 608386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik renderPathTexture(renderer, state, *texture, op); 609386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik } 610386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik } else { 611386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik SkPath path; 612386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik path.addRect(getBoundsOfFill(op)); 613386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik renderConvexPath(renderer, state, path, *(op.paint)); 614386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik } 615386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik } else { 616386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik if (op.paint->isAntiAlias() && !state.computedState.transform.isSimple()) { 617386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik SkPath path; 618386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik path.addRect(op.unmappedBounds.toSkRect()); 619386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik renderConvexPath(renderer, state, path, *(op.paint)); 620386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik } else { 621386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik // render simple unit quad, no tessellation required 622386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik Glop glop; 623386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 624386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik .setRoundRectClipState(state.roundRectClipState) 625386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik .setMeshUnitQuad() 626386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik .setFillPaint(*op.paint, state.alpha) 627386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik .setTransform(state.computedState.transform, TransformFlags::None) 628386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik .setModelViewMapUnitToRect(op.unmappedBounds) 629386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik .build(); 630386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik renderer.renderGlop(state, glop); 631386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik } 632386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik } 633386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik} 634386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik 635386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craikvoid BakedOpDispatcher::onRoundRectOp(BakedOpRenderer& renderer, const RoundRectOp& op, const BakedOpState& state) { 636386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik if (op.paint->getPathEffect() != nullptr) { 637386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik PathTexture* texture = renderer.caches().pathCache.getRoundRect( 638386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), 639386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik op.rx, op.ry, op.paint); 640386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik const AutoTexture holder(texture); 641386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik if (CC_LIKELY(holder.texture)) { 642386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik renderPathTexture(renderer, state, *texture, op); 643386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik } 644386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik } else { 645386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik const VertexBuffer* buffer = renderer.caches().tessellationCache.getRoundRect( 646386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik state.computedState.transform, *(op.paint), 647386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.rx, op.ry); 648386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik renderVertexBuffer(renderer, state, *buffer, 649386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik op.unmappedBounds.left, op.unmappedBounds.top, *(op.paint), 0); 6509e7fcfda28fde747ba4e026772007cea77374e16Chris Craik } 6519e7fcfda28fde747ba4e026772007cea77374e16Chris Craik} 6529e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 6539e7fcfda28fde747ba4e026772007cea77374e16Chris Craikstatic void renderShadow(BakedOpRenderer& renderer, const BakedOpState& state, float casterAlpha, 6549e7fcfda28fde747ba4e026772007cea77374e16Chris Craik const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) { 6559e7fcfda28fde747ba4e026772007cea77374e16Chris Craik SkPaint paint; 6569e7fcfda28fde747ba4e026772007cea77374e16Chris Craik paint.setAntiAlias(true); // want to use AlphaVertex 6579e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 6589e7fcfda28fde747ba4e026772007cea77374e16Chris Craik // The caller has made sure casterAlpha > 0. 6599e7fcfda28fde747ba4e026772007cea77374e16Chris Craik uint8_t ambientShadowAlpha = renderer.getLightInfo().ambientShadowAlpha; 6609e7fcfda28fde747ba4e026772007cea77374e16Chris Craik if (CC_UNLIKELY(Properties::overrideAmbientShadowStrength >= 0)) { 6619e7fcfda28fde747ba4e026772007cea77374e16Chris Craik ambientShadowAlpha = Properties::overrideAmbientShadowStrength; 6629e7fcfda28fde747ba4e026772007cea77374e16Chris Craik } 6639e7fcfda28fde747ba4e026772007cea77374e16Chris Craik if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) { 6649e7fcfda28fde747ba4e026772007cea77374e16Chris Craik paint.setAlpha((uint8_t)(casterAlpha * ambientShadowAlpha)); 6659e7fcfda28fde747ba4e026772007cea77374e16Chris Craik renderVertexBuffer(renderer, state, *ambientShadowVertexBuffer, 0, 0, 6669e7fcfda28fde747ba4e026772007cea77374e16Chris Craik paint, VertexBufferRenderFlags::ShadowInterp); 6679e7fcfda28fde747ba4e026772007cea77374e16Chris Craik } 6689e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 6699e7fcfda28fde747ba4e026772007cea77374e16Chris Craik uint8_t spotShadowAlpha = renderer.getLightInfo().spotShadowAlpha; 6709e7fcfda28fde747ba4e026772007cea77374e16Chris Craik if (CC_UNLIKELY(Properties::overrideSpotShadowStrength >= 0)) { 6719e7fcfda28fde747ba4e026772007cea77374e16Chris Craik spotShadowAlpha = Properties::overrideSpotShadowStrength; 6729e7fcfda28fde747ba4e026772007cea77374e16Chris Craik } 6739e7fcfda28fde747ba4e026772007cea77374e16Chris Craik if (spotShadowVertexBuffer && spotShadowAlpha > 0) { 6749e7fcfda28fde747ba4e026772007cea77374e16Chris Craik paint.setAlpha((uint8_t)(casterAlpha * spotShadowAlpha)); 6759e7fcfda28fde747ba4e026772007cea77374e16Chris Craik renderVertexBuffer(renderer, state, *spotShadowVertexBuffer, 0, 0, 6769e7fcfda28fde747ba4e026772007cea77374e16Chris Craik paint, VertexBufferRenderFlags::ShadowInterp); 6779e7fcfda28fde747ba4e026772007cea77374e16Chris Craik } 6789e7fcfda28fde747ba4e026772007cea77374e16Chris Craik} 6799e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 6809e7fcfda28fde747ba4e026772007cea77374e16Chris Craikvoid BakedOpDispatcher::onShadowOp(BakedOpRenderer& renderer, const ShadowOp& op, const BakedOpState& state) { 6819e7fcfda28fde747ba4e026772007cea77374e16Chris Craik TessellationCache::vertexBuffer_pair_t buffers; 6829e7fcfda28fde747ba4e026772007cea77374e16Chris Craik renderer.caches().tessellationCache.getShadowBuffers(&state.computedState.transform, 6839e7fcfda28fde747ba4e026772007cea77374e16Chris Craik op.localClipRect, op.casterAlpha >= 1.0f, op.casterPath, 6849e7fcfda28fde747ba4e026772007cea77374e16Chris Craik &op.shadowMatrixXY, &op.shadowMatrixZ, 6859e7fcfda28fde747ba4e026772007cea77374e16Chris Craik op.lightCenter, renderer.getLightInfo().lightRadius, 6869e7fcfda28fde747ba4e026772007cea77374e16Chris Craik buffers); 6879e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 6889e7fcfda28fde747ba4e026772007cea77374e16Chris Craik renderShadow(renderer, state, op.casterAlpha, buffers.first, buffers.second); 6899e7fcfda28fde747ba4e026772007cea77374e16Chris Craik} 6909e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 6919e7fcfda28fde747ba4e026772007cea77374e16Chris Craikvoid BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op, const BakedOpState& state) { 6929e7fcfda28fde747ba4e026772007cea77374e16Chris Craik Glop glop; 6939e7fcfda28fde747ba4e026772007cea77374e16Chris Craik GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 6949e7fcfda28fde747ba4e026772007cea77374e16Chris Craik .setRoundRectClipState(state.roundRectClipState) 6959e7fcfda28fde747ba4e026772007cea77374e16Chris Craik .setMeshIndexedQuads(&op.vertices[0], op.vertexCount / 4) 6969e7fcfda28fde747ba4e026772007cea77374e16Chris Craik .setFillPaint(*op.paint, state.alpha) 6979e7fcfda28fde747ba4e026772007cea77374e16Chris Craik .setTransform(state.computedState.transform, TransformFlags::None) 6989e7fcfda28fde747ba4e026772007cea77374e16Chris Craik .setModelViewOffsetRect(0, 0, op.unmappedBounds) 6999e7fcfda28fde747ba4e026772007cea77374e16Chris Craik .build(); 7009e7fcfda28fde747ba4e026772007cea77374e16Chris Craik renderer.renderGlop(state, glop); 7019e7fcfda28fde747ba4e026772007cea77374e16Chris Craik} 7029e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 7039e7fcfda28fde747ba4e026772007cea77374e16Chris Craikvoid BakedOpDispatcher::onTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state) { 70415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik const Rect* clip = state.computedState.clipSideFlags ? &state.computedState.clipRect : nullptr; 70515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik renderTextOp(renderer, op, state, clip, TextRenderType::Flush); 7069e7fcfda28fde747ba4e026772007cea77374e16Chris Craik} 7079e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 708d7448e65e243754f31890baef29dff187dc2e5e5Chris Craikvoid BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPathOp& op, const BakedOpState& state) { 709d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik // Note: can't trust clipSideFlags since we record with unmappedBounds == clip. 710d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik // TODO: respect clipSideFlags, once we record with bounds 711d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik const Rect* renderTargetClip = &state.computedState.clipRect; 712d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik 713d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer(); 714d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik fontRenderer.setFont(op.paint, SkMatrix::I()); 715d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik fontRenderer.setTextureFiltering(true); 716d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik 717d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); 718d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik 719d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik int alpha = PaintUtils::getAlphaDirect(op.paint) * state.alpha; 720d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(op.paint); 721d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik TextDrawFunctor functor(&renderer, &state, renderTargetClip, 722d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik 0.0f, 0.0f, false, alpha, mode, op.paint); 723d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik 724d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik bool mustDirtyRenderTarget = renderer.offscreenRenderTarget(); 725d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik const Rect localSpaceClip = state.computedState.computeLocalSpaceClip(); 726d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik if (fontRenderer.renderTextOnPath(op.paint, &localSpaceClip, 727d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik reinterpret_cast<const char*>(op.glyphs), op.glyphCount, 728d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik op.path, op.hOffset, op.vOffset, 729d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik mustDirtyRenderTarget ? &layerBounds : nullptr, &functor)) { 730d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik if (mustDirtyRenderTarget) { 731d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik // manually dirty render target, since TextDrawFunctor won't 732d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik state.computedState.transform.mapRect(layerBounds); 733d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik renderer.dirtyRenderTarget(layerBounds); 734d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik } 735d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik } 736d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik} 737d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik 7389e7fcfda28fde747ba4e026772007cea77374e16Chris Craikvoid BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) { 7399e7fcfda28fde747ba4e026772007cea77374e16Chris Craik OffscreenBuffer* buffer = *op.layerHandle; 7409e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 7419e7fcfda28fde747ba4e026772007cea77374e16Chris Craik float layerAlpha = op.alpha * state.alpha; 7429e7fcfda28fde747ba4e026772007cea77374e16Chris Craik Glop glop; 7439e7fcfda28fde747ba4e026772007cea77374e16Chris Craik GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 7449e7fcfda28fde747ba4e026772007cea77374e16Chris Craik .setRoundRectClipState(state.roundRectClipState) 7459e7fcfda28fde747ba4e026772007cea77374e16Chris Craik .setMeshTexturedIndexedVbo(buffer->vbo, buffer->elementCount) 7469e7fcfda28fde747ba4e026772007cea77374e16Chris Craik .setFillLayer(buffer->texture, op.colorFilter, layerAlpha, op.mode, Blend::ModeOrderSwap::NoSwap) 7479e7fcfda28fde747ba4e026772007cea77374e16Chris Craik .setTransform(state.computedState.transform, TransformFlags::None) 7489e7fcfda28fde747ba4e026772007cea77374e16Chris Craik .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top, 7499e7fcfda28fde747ba4e026772007cea77374e16Chris Craik Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight())) 7509e7fcfda28fde747ba4e026772007cea77374e16Chris Craik .build(); 7519e7fcfda28fde747ba4e026772007cea77374e16Chris Craik renderer.renderGlop(state, glop); 7529e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 7539e7fcfda28fde747ba4e026772007cea77374e16Chris Craik if (op.destroy) { 7549e7fcfda28fde747ba4e026772007cea77374e16Chris Craik renderer.renderState().layerPool().putOrDelete(buffer); 7559e7fcfda28fde747ba4e026772007cea77374e16Chris Craik } 7569e7fcfda28fde747ba4e026772007cea77374e16Chris Craik} 7579e7fcfda28fde747ba4e026772007cea77374e16Chris Craik 7589e7fcfda28fde747ba4e026772007cea77374e16Chris Craik} // namespace uirenderer 7599e7fcfda28fde747ba4e026772007cea77374e16Chris Craik} // namespace android 760