BakedOpRenderer.cpp revision 818c9fbf1d76d5df19253ba4eb964efa939ec9ec
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 "BakedOpRenderer.h"
18
19#include "Caches.h"
20#include "Glop.h"
21#include "GlopBuilder.h"
22#include "renderstate/RenderState.h"
23#include "utils/GLUtils.h"
24
25namespace android {
26namespace uirenderer {
27
28void BakedOpRenderer::Info::setViewport(uint32_t width, uint32_t height) {
29    viewportWidth = width;
30    viewportHeight = height;
31    orthoMatrix.loadOrtho(viewportWidth, viewportHeight);
32
33    renderState.setViewport(width, height);
34    renderState.blend().syncEnabled();
35}
36
37Texture* BakedOpRenderer::Info::getTexture(const SkBitmap* bitmap) {
38    Texture* texture = renderState.assetAtlas().getEntryTexture(bitmap);
39    if (!texture) {
40        return caches.textureCache.get(bitmap);
41    }
42    return texture;
43}
44
45void BakedOpRenderer::Info::renderGlop(const BakedOpState& state, const Glop& glop) {
46    bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None;
47    renderState.scissor().setEnabled(useScissor);
48    if (useScissor) {
49        const Rect& clip = state.computedState.clipRect;
50        renderState.scissor().set(clip.left, viewportHeight - clip.bottom,
51            clip.getWidth(), clip.getHeight());
52    }
53    renderState.render(glop, orthoMatrix);
54    didDraw = true;
55}
56
57Layer* BakedOpRenderer::startLayer(Info& info, uint32_t width, uint32_t height) {
58    info.caches.textureState().activateTexture(0);
59    Layer* layer = info.caches.layerCache.get(info.renderState, width, height);
60    LOG_ALWAYS_FATAL_IF(!layer, "need layer...");
61
62    info.layer = layer;
63    layer->texCoords.set(0.0f, width / float(layer->getHeight()),
64            height / float(layer->getWidth()), 0.0f);
65
66    layer->setFbo(info.renderState.genFramebuffer());
67    info.renderState.bindFramebuffer(layer->getFbo());
68    layer->bindTexture();
69
70    // Initialize the texture if needed
71    if (layer->isEmpty()) {
72        layer->allocateTexture();
73        layer->setEmpty(false);
74    }
75
76    // attach the texture to the FBO
77    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
78            layer->getTextureId(), 0);
79    LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "startLayer FAILED");
80    LOG_ALWAYS_FATAL_IF(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE,
81            "framebuffer incomplete!");
82
83    // Clear the FBO
84    info.renderState.scissor().setEnabled(false);
85    glClear(GL_COLOR_BUFFER_BIT);
86
87    // Change the viewport & ortho projection
88    info.setViewport(width, height);
89    return layer;
90}
91
92void BakedOpRenderer::endLayer(Info& info) {
93    Layer* layer = info.layer;
94    info.layer = nullptr;
95
96    // Detach the texture from the FBO
97    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
98    LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED");
99    layer->removeFbo(false);
100}
101
102void BakedOpRenderer::startFrame(Info& info, uint32_t width, uint32_t height) {
103    info.renderState.bindFramebuffer(0);
104    info.setViewport(width, height);
105    Caches::getInstance().clearGarbage();
106
107    if (!info.opaque) {
108        // TODO: partial invalidate!
109        info.renderState.scissor().setEnabled(false);
110        glClear(GL_COLOR_BUFFER_BIT);
111        info.didDraw = true;
112    }
113}
114void BakedOpRenderer::endFrame(Info& info) {
115    info.caches.pathCache.trim();
116    info.caches.tessellationCache.trim();
117
118#if DEBUG_OPENGL
119    GLUtils::dumpGLErrors();
120#endif
121
122#if DEBUG_MEMORY_USAGE
123    info.caches.dumpMemoryUsage();
124#else
125    if (Properties::debugLevel & kDebugMemory) {
126        info.caches.dumpMemoryUsage();
127    }
128#endif
129}
130
131void BakedOpRenderer::onRenderNodeOp(Info&, const RenderNodeOp&, const BakedOpState&) {
132    LOG_ALWAYS_FATAL("unsupported operation");
133}
134
135void BakedOpRenderer::onBitmapOp(Info& info, const BitmapOp& op, const BakedOpState& state) {
136    info.caches.textureState().activateTexture(0); // TODO: should this be automatic, and/or elsewhere?
137    Texture* texture = info.getTexture(op.bitmap);
138    if (!texture) return;
139    const AutoTexture autoCleanup(texture);
140
141    const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType)
142            ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
143    Glop glop;
144    GlopBuilder(info.renderState, info.caches, &glop)
145            .setRoundRectClipState(state.roundRectClipState)
146            .setMeshTexturedUnitQuad(texture->uvMapper)
147            .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
148            .setTransform(state.computedState.transform, TransformFlags::None)
149            .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
150            .build();
151    info.renderGlop(state, glop);
152}
153
154void BakedOpRenderer::onRectOp(Info& info, const RectOp& op, const BakedOpState& state) {
155    Glop glop;
156    GlopBuilder(info.renderState, info.caches, &glop)
157            .setRoundRectClipState(state.roundRectClipState)
158            .setMeshUnitQuad()
159            .setFillPaint(*op.paint, state.alpha)
160            .setTransform(state.computedState.transform, TransformFlags::None)
161            .setModelViewMapUnitToRect(op.unmappedBounds)
162            .build();
163    info.renderGlop(state, glop);
164}
165
166void BakedOpRenderer::onSimpleRectsOp(Info& info, const SimpleRectsOp& op, const BakedOpState& state) {
167    Glop glop;
168    GlopBuilder(info.renderState, info.caches, &glop)
169            .setRoundRectClipState(state.roundRectClipState)
170            .setMeshIndexedQuads(&op.vertices[0], op.vertexCount / 4)
171            .setFillPaint(*op.paint, state.alpha)
172            .setTransform(state.computedState.transform, TransformFlags::None)
173            .setModelViewOffsetRect(0, 0, op.unmappedBounds)
174            .build();
175    info.renderGlop(state, glop);
176}
177
178void BakedOpRenderer::onBeginLayerOp(Info& info, const BeginLayerOp& op, const BakedOpState& state) {
179    LOG_ALWAYS_FATAL("unsupported operation");
180}
181
182void BakedOpRenderer::onEndLayerOp(Info& info, const EndLayerOp& op, const BakedOpState& state) {
183    LOG_ALWAYS_FATAL("unsupported operation");
184}
185
186void BakedOpRenderer::onLayerOp(Info& info, const LayerOp& op, const BakedOpState& state) {
187    Layer* layer = *op.layerHandle;
188
189    // TODO: make this work for HW layers
190    layer->setPaint(op.paint);
191    layer->setBlend(true);
192    float layerAlpha = (layer->getAlpha() / 255.0f) * state.alpha;
193
194    const bool tryToSnap = state.computedState.transform.isPureTranslate();
195    Glop glop;
196    GlopBuilder(info.renderState, info.caches, &glop)
197            .setRoundRectClipState(state.roundRectClipState)
198            .setMeshTexturedUvQuad(nullptr, layer->texCoords)
199            .setFillLayer(layer->getTexture(), layer->getColorFilter(), layerAlpha, layer->getMode(), Blend::ModeOrderSwap::NoSwap)
200            .setTransform(state.computedState.transform, TransformFlags::None)
201            .setModelViewMapUnitToRectOptionalSnap(tryToSnap, op.unmappedBounds)
202            .build();
203    info.renderGlop(state, glop);
204
205    // return layer to cache, since each clipped savelayer is only drawn once.
206    layer->setConvexMask(nullptr);
207    if (!info.caches.layerCache.put(layer)) {
208        // Failing to add the layer to the cache should happen only if the layer is too large
209        LAYER_LOGD("Deleting layer");
210        layer->decStrong(nullptr);
211    }
212}
213
214} // namespace uirenderer
215} // namespace android
216