blob: 7dbba25a0ec4ffa5d1a3aa787f9a812adb40d9bf [file] [log] [blame]
Chris Craikb565df12015-10-05 13:00:52 -07001/*
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
Chris Craik818c9fb2015-10-23 14:33:42 -070028void 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
Chris Craikb565df12015-10-05 13:00:52 -070037Texture* 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
Chris Craik818c9fb2015-10-23 14:33:42 -070057Layer* 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);
Chris Craikb565df12015-10-05 13:00:52 -0700105 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
Chris Craik6fe991e52015-10-20 09:39:42 -0700131void BakedOpRenderer::onRenderNodeOp(Info&, const RenderNodeOp&, const BakedOpState&) {
Chris Craikb565df12015-10-05 13:00:52 -0700132 LOG_ALWAYS_FATAL("unsupported operation");
133}
134
Chris Craik6fe991e52015-10-20 09:39:42 -0700135void 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);
Chris Craikb565df12015-10-05 13:00:52 -0700138 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;
Chris Craik6fe991e52015-10-20 09:39:42 -0700144 GlopBuilder(info.renderState, info.caches, &glop)
Chris Craikb565df12015-10-05 13:00:52 -0700145 .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();
Chris Craik6fe991e52015-10-20 09:39:42 -0700151 info.renderGlop(state, glop);
Chris Craikb565df12015-10-05 13:00:52 -0700152}
153
Chris Craik6fe991e52015-10-20 09:39:42 -0700154void BakedOpRenderer::onRectOp(Info& info, const RectOp& op, const BakedOpState& state) {
Chris Craikb565df12015-10-05 13:00:52 -0700155 Glop glop;
Chris Craik6fe991e52015-10-20 09:39:42 -0700156 GlopBuilder(info.renderState, info.caches, &glop)
Chris Craikb565df12015-10-05 13:00:52 -0700157 .setRoundRectClipState(state.roundRectClipState)
158 .setMeshUnitQuad()
159 .setFillPaint(*op.paint, state.alpha)
160 .setTransform(state.computedState.transform, TransformFlags::None)
161 .setModelViewMapUnitToRect(op.unmappedBounds)
162 .build();
Chris Craik6fe991e52015-10-20 09:39:42 -0700163 info.renderGlop(state, glop);
Chris Craikb565df12015-10-05 13:00:52 -0700164}
165
Chris Craik6fe991e52015-10-20 09:39:42 -0700166void BakedOpRenderer::onSimpleRectsOp(Info& info, const SimpleRectsOp& op, const BakedOpState& state) {
Chris Craikb565df12015-10-05 13:00:52 -0700167 Glop glop;
Chris Craik6fe991e52015-10-20 09:39:42 -0700168 GlopBuilder(info.renderState, info.caches, &glop)
Chris Craikb565df12015-10-05 13:00:52 -0700169 .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();
Chris Craik6fe991e52015-10-20 09:39:42 -0700175 info.renderGlop(state, glop);
Chris Craikb565df12015-10-05 13:00:52 -0700176}
177
Chris Craik6fe991e52015-10-20 09:39:42 -0700178void 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) {
Chris Craik818c9fb2015-10-23 14:33:42 -0700187 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 }
Chris Craik6fe991e52015-10-20 09:39:42 -0700212}
Chris Craikb565df12015-10-05 13:00:52 -0700213
214} // namespace uirenderer
215} // namespace android