BakedOpDispatcher.cpp revision 15c3f19a445b8df575911a16e8a6dba755a084b5
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 17#include "BakedOpDispatcher.h" 18 19#include "BakedOpRenderer.h" 20#include "Caches.h" 21#include "Glop.h" 22#include "GlopBuilder.h" 23#include "renderstate/OffscreenBufferPool.h" 24#include "renderstate/RenderState.h" 25#include "utils/GLUtils.h" 26#include "VertexBuffer.h" 27 28#include <algorithm> 29#include <math.h> 30 31namespace android { 32namespace uirenderer { 33 34static void storeTexturedRect(TextureVertex* vertices, const Rect& bounds, const Rect& texCoord) { 35 vertices[0] = { bounds.left, bounds.top, texCoord.left, texCoord.top }; 36 vertices[1] = { bounds.right, bounds.top, texCoord.right, texCoord.top }; 37 vertices[2] = { bounds.left, bounds.bottom, texCoord.left, texCoord.bottom }; 38 vertices[3] = { bounds.right, bounds.bottom, texCoord.right, texCoord.bottom }; 39} 40 41void BakedOpDispatcher::onMergedBitmapOps(BakedOpRenderer& renderer, 42 const MergedBakedOpList& opList) { 43 44 const BakedOpState& firstState = *(opList.states[0]); 45 const SkBitmap* bitmap = (static_cast<const BitmapOp*>(opList.states[0]->op))->bitmap; 46 47 AssetAtlas::Entry* entry = renderer.renderState().assetAtlas().getEntry(bitmap->pixelRef()); 48 Texture* texture = entry ? entry->texture : renderer.caches().textureCache.get(bitmap); 49 if (!texture) return; 50 const AutoTexture autoCleanup(texture); 51 52 TextureVertex vertices[opList.count * 4]; 53 Rect texCoords(0, 0, 1, 1); 54 if (entry) { 55 entry->uvMapper.map(texCoords); 56 } 57 // init to non-empty, so we can safely expandtoCoverRect 58 Rect totalBounds = firstState.computedState.clippedBounds; 59 for (size_t i = 0; i < opList.count; i++) { 60 const BakedOpState& state = *(opList.states[i]); 61 TextureVertex* rectVerts = &vertices[i * 4]; 62 Rect opBounds = state.computedState.clippedBounds; 63 if (CC_LIKELY(state.computedState.transform.isPureTranslate())) { 64 // pure translate, so snap (same behavior as onBitmapOp) 65 opBounds.snapToPixelBoundaries(); 66 } 67 storeTexturedRect(rectVerts, opBounds, texCoords); 68 renderer.dirtyRenderTarget(opBounds); 69 70 totalBounds.expandToCover(opBounds); 71 } 72 73 const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType) 74 ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None; 75 Glop glop; 76 GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 77 .setRoundRectClipState(firstState.roundRectClipState) 78 .setMeshTexturedIndexedQuads(vertices, opList.count * 6) 79 .setFillTexturePaint(*texture, textureFillFlags, firstState.op->paint, firstState.alpha) 80 .setTransform(Matrix4::identity(), TransformFlags::None) 81 .setModelViewOffsetRect(0, 0, totalBounds) // don't snap here, we snap per-quad above 82 .build(); 83 renderer.renderGlop(nullptr, opList.clipSideFlags ? &opList.clip : nullptr, glop); 84} 85 86static void renderTextShadow(BakedOpRenderer& renderer, FontRenderer& fontRenderer, 87 const TextOp& op, const BakedOpState& state) { 88 renderer.caches().textureState().activateTexture(0); 89 90 PaintUtils::TextShadow textShadow; 91 if (!PaintUtils::getTextShadow(op.paint, &textShadow)) { 92 LOG_ALWAYS_FATAL("failed to query shadow attributes"); 93 } 94 95 renderer.caches().dropShadowCache.setFontRenderer(fontRenderer); 96 ShadowTexture* texture = renderer.caches().dropShadowCache.get( 97 op.paint, (const char*) op.glyphs, 98 op.glyphCount, textShadow.radius, op.positions); 99 // If the drop shadow exceeds the max texture size or couldn't be 100 // allocated, skip drawing 101 if (!texture) return; 102 const AutoTexture autoCleanup(texture); 103 104 const float sx = op.x - texture->left + textShadow.dx; 105 const float sy = op.y - texture->top + textShadow.dy; 106 107 Glop glop; 108 GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 109 .setRoundRectClipState(state.roundRectClipState) 110 .setMeshTexturedUnitQuad(nullptr) 111 .setFillShadowTexturePaint(*texture, textShadow.color, *op.paint, state.alpha) 112 .setTransform(state.computedState.transform, TransformFlags::None) 113 .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width, sy + texture->height)) 114 .build(); 115 renderer.renderGlop(state, glop); 116} 117 118enum class TextRenderType { 119 Defer, 120 Flush 121}; 122 123static void renderTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state, 124 const Rect* renderClip, TextRenderType renderType) { 125 FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer(); 126 127 if (CC_UNLIKELY(PaintUtils::hasTextShadow(op.paint))) { 128 fontRenderer.setFont(op.paint, SkMatrix::I()); 129 renderTextShadow(renderer, fontRenderer, op, state); 130 } 131 132 float x = op.x; 133 float y = op.y; 134 const Matrix4& transform = state.computedState.transform; 135 const bool pureTranslate = transform.isPureTranslate(); 136 if (CC_LIKELY(pureTranslate)) { 137 x = floorf(x + transform.getTranslateX() + 0.5f); 138 y = floorf(y + transform.getTranslateY() + 0.5f); 139 fontRenderer.setFont(op.paint, SkMatrix::I()); 140 fontRenderer.setTextureFiltering(false); 141 } else if (CC_UNLIKELY(transform.isPerspective())) { 142 fontRenderer.setFont(op.paint, SkMatrix::I()); 143 fontRenderer.setTextureFiltering(true); 144 } else { 145 // We only pass a partial transform to the font renderer. That partial 146 // matrix defines how glyphs are rasterized. Typically we want glyphs 147 // to be rasterized at their final size on screen, which means the partial 148 // matrix needs to take the scale factor into account. 149 // When a partial matrix is used to transform glyphs during rasterization, 150 // the mesh is generated with the inverse transform (in the case of scale, 151 // the mesh is generated at 1.0 / scale for instance.) This allows us to 152 // apply the full transform matrix at draw time in the vertex shader. 153 // Applying the full matrix in the shader is the easiest way to handle 154 // rotation and perspective and allows us to always generated quads in the 155 // font renderer which greatly simplifies the code, clipping in particular. 156 float sx, sy; 157 transform.decomposeScale(sx, sy); 158 fontRenderer.setFont(op.paint, SkMatrix::MakeScale( 159 roundf(std::max(1.0f, sx)), 160 roundf(std::max(1.0f, sy)))); 161 fontRenderer.setTextureFiltering(true); 162 } 163 Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); 164 165 int alpha = PaintUtils::getAlphaDirect(op.paint) * state.alpha; 166 SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(op.paint); 167 TextDrawFunctor functor(&renderer, &state, renderClip, 168 x, y, pureTranslate, alpha, mode, op.paint); 169 170 bool forceFinish = (renderType == TextRenderType::Flush); 171 bool mustDirtyRenderTarget = renderer.offscreenRenderTarget(); 172 const Rect* localOpClip = pureTranslate ? &state.computedState.clipRect : nullptr; 173 fontRenderer.renderPosText(op.paint, localOpClip, 174 (const char*) op.glyphs, op.glyphCount, x, y, 175 op.positions, mustDirtyRenderTarget ? &layerBounds : nullptr, &functor, forceFinish); 176 177 if (mustDirtyRenderTarget) { 178 if (!pureTranslate) { 179 transform.mapRect(layerBounds); 180 } 181 renderer.dirtyRenderTarget(layerBounds); 182 } 183} 184 185void BakedOpDispatcher::onMergedTextOps(BakedOpRenderer& renderer, 186 const MergedBakedOpList& opList) { 187 const Rect* clip = opList.clipSideFlags ? &opList.clip : nullptr; 188 for (size_t i = 0; i < opList.count; i++) { 189 const BakedOpState& state = *(opList.states[i]); 190 const TextOp& op = *(static_cast<const TextOp*>(state.op)); 191 TextRenderType renderType = (i + 1 == opList.count) 192 ? TextRenderType::Flush : TextRenderType::Defer; 193 renderTextOp(renderer, op, state, clip, renderType); 194 } 195} 196 197void BakedOpDispatcher::onRenderNodeOp(BakedOpRenderer&, const RenderNodeOp&, const BakedOpState&) { 198 LOG_ALWAYS_FATAL("unsupported operation"); 199} 200 201void BakedOpDispatcher::onBeginLayerOp(BakedOpRenderer&, const BeginLayerOp&, const BakedOpState&) { 202 LOG_ALWAYS_FATAL("unsupported operation"); 203} 204 205void BakedOpDispatcher::onEndLayerOp(BakedOpRenderer&, const EndLayerOp&, const BakedOpState&) { 206 LOG_ALWAYS_FATAL("unsupported operation"); 207} 208 209void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op, const BakedOpState& state) { 210 Texture* texture = renderer.getTexture(op.bitmap); 211 if (!texture) return; 212 const AutoTexture autoCleanup(texture); 213 214 const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType) 215 ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None; 216 Glop glop; 217 GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 218 .setRoundRectClipState(state.roundRectClipState) 219 .setMeshTexturedUnitQuad(texture->uvMapper) 220 .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha) 221 .setTransform(state.computedState.transform, TransformFlags::None) 222 .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height)) 223 .build(); 224 renderer.renderGlop(state, glop); 225} 226 227void BakedOpDispatcher::onLinesOp(BakedOpRenderer& renderer, const LinesOp& op, const BakedOpState& state) { 228 LOG_ALWAYS_FATAL("todo"); 229} 230 231void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, const BakedOpState& state) { 232 Glop glop; 233 GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 234 .setRoundRectClipState(state.roundRectClipState) 235 .setMeshUnitQuad() 236 .setFillPaint(*op.paint, state.alpha) 237 .setTransform(state.computedState.transform, TransformFlags::None) 238 .setModelViewMapUnitToRect(op.unmappedBounds) 239 .build(); 240 renderer.renderGlop(state, glop); 241} 242 243namespace VertexBufferRenderFlags { 244 enum { 245 Offset = 0x1, 246 ShadowInterp = 0x2, 247 }; 248} 249 250static void renderVertexBuffer(BakedOpRenderer& renderer, const BakedOpState& state, 251 const VertexBuffer& vertexBuffer, float translateX, float translateY, 252 SkPaint& paint, int vertexBufferRenderFlags) { 253 if (CC_LIKELY(vertexBuffer.getVertexCount())) { 254 bool shadowInterp = vertexBufferRenderFlags & VertexBufferRenderFlags::ShadowInterp; 255 const int transformFlags = TransformFlags::OffsetByFudgeFactor; 256 Glop glop; 257 GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 258 .setRoundRectClipState(state.roundRectClipState) 259 .setMeshVertexBuffer(vertexBuffer, shadowInterp) 260 .setFillPaint(paint, state.alpha) 261 .setTransform(state.computedState.transform, transformFlags) 262 .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds()) 263 .build(); 264 renderer.renderGlop(state, glop); 265 } 266} 267 268static void renderShadow(BakedOpRenderer& renderer, const BakedOpState& state, float casterAlpha, 269 const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) { 270 SkPaint paint; 271 paint.setAntiAlias(true); // want to use AlphaVertex 272 273 // The caller has made sure casterAlpha > 0. 274 uint8_t ambientShadowAlpha = renderer.getLightInfo().ambientShadowAlpha; 275 if (CC_UNLIKELY(Properties::overrideAmbientShadowStrength >= 0)) { 276 ambientShadowAlpha = Properties::overrideAmbientShadowStrength; 277 } 278 if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) { 279 paint.setAlpha((uint8_t)(casterAlpha * ambientShadowAlpha)); 280 renderVertexBuffer(renderer, state, *ambientShadowVertexBuffer, 0, 0, 281 paint, VertexBufferRenderFlags::ShadowInterp); 282 } 283 284 uint8_t spotShadowAlpha = renderer.getLightInfo().spotShadowAlpha; 285 if (CC_UNLIKELY(Properties::overrideSpotShadowStrength >= 0)) { 286 spotShadowAlpha = Properties::overrideSpotShadowStrength; 287 } 288 if (spotShadowVertexBuffer && spotShadowAlpha > 0) { 289 paint.setAlpha((uint8_t)(casterAlpha * spotShadowAlpha)); 290 renderVertexBuffer(renderer, state, *spotShadowVertexBuffer, 0, 0, 291 paint, VertexBufferRenderFlags::ShadowInterp); 292 } 293} 294 295void BakedOpDispatcher::onShadowOp(BakedOpRenderer& renderer, const ShadowOp& op, const BakedOpState& state) { 296 TessellationCache::vertexBuffer_pair_t buffers; 297 renderer.caches().tessellationCache.getShadowBuffers(&state.computedState.transform, 298 op.localClipRect, op.casterAlpha >= 1.0f, op.casterPath, 299 &op.shadowMatrixXY, &op.shadowMatrixZ, 300 op.lightCenter, renderer.getLightInfo().lightRadius, 301 buffers); 302 303 renderShadow(renderer, state, op.casterAlpha, buffers.first, buffers.second); 304} 305 306void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op, const BakedOpState& state) { 307 Glop glop; 308 GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 309 .setRoundRectClipState(state.roundRectClipState) 310 .setMeshIndexedQuads(&op.vertices[0], op.vertexCount / 4) 311 .setFillPaint(*op.paint, state.alpha) 312 .setTransform(state.computedState.transform, TransformFlags::None) 313 .setModelViewOffsetRect(0, 0, op.unmappedBounds) 314 .build(); 315 renderer.renderGlop(state, glop); 316} 317 318void BakedOpDispatcher::onTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state) { 319 const Rect* clip = state.computedState.clipSideFlags ? &state.computedState.clipRect : nullptr; 320 renderTextOp(renderer, op, state, clip, TextRenderType::Flush); 321} 322 323void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) { 324 OffscreenBuffer* buffer = *op.layerHandle; 325 326 // TODO: extend this to handle HW layers & paint properties which 327 // reside in node.properties().layerProperties() 328 float layerAlpha = op.alpha * state.alpha; 329 Glop glop; 330 GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 331 .setRoundRectClipState(state.roundRectClipState) 332 .setMeshTexturedIndexedVbo(buffer->vbo, buffer->elementCount) 333 .setFillLayer(buffer->texture, op.colorFilter, layerAlpha, op.mode, Blend::ModeOrderSwap::NoSwap) 334 .setTransform(state.computedState.transform, TransformFlags::None) 335 .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top, 336 Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight())) 337 .build(); 338 renderer.renderGlop(state, glop); 339 340 if (op.destroy) { 341 renderer.renderState().layerPool().putOrDelete(buffer); 342 } 343} 344 345} // namespace uirenderer 346} // namespace android 347