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