blob: 705583941067b1dad1df36fddcabf63ac944a4c2 [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 Craik5854b342015-10-26 15:49:56 -070028////////////////////////////////////////////////////////////////////////////////
29// OffscreenBuffer
30////////////////////////////////////////////////////////////////////////////////
Chris Craik818c9fb2015-10-23 14:33:42 -070031
Chris Craik5854b342015-10-26 15:49:56 -070032OffscreenBuffer::OffscreenBuffer(Caches& caches, uint32_t textureWidth, uint32_t textureHeight,
33 uint32_t viewportWidth, uint32_t viewportHeight)
Chris Craik0b7e8242015-10-28 16:50:44 -070034 : viewportWidth(viewportWidth)
35 , viewportHeight(viewportHeight)
36 , texture(caches)
Chris Craik5854b342015-10-26 15:49:56 -070037 , texCoords(0, viewportHeight / float(textureHeight), viewportWidth / float(textureWidth), 0) {
38 texture.width = textureWidth;
39 texture.height = textureHeight;
40
41 caches.textureState().activateTexture(0);
42 glGenTextures(1, &texture.id);
43 caches.textureState().bindTexture(GL_TEXTURE_2D, texture.id);
44
45 texture.setWrap(GL_CLAMP_TO_EDGE, false, false, GL_TEXTURE_2D);
46 // not setting filter on texture, since it's set when drawing, based on transform
47
48 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
49 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0,
50 GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
Chris Craik818c9fb2015-10-23 14:33:42 -070051}
52
Chris Craik5854b342015-10-26 15:49:56 -070053////////////////////////////////////////////////////////////////////////////////
54// BakedOpRenderer
55////////////////////////////////////////////////////////////////////////////////
Chris Craikb565df12015-10-05 13:00:52 -070056
Chris Craik0b7e8242015-10-28 16:50:44 -070057OffscreenBuffer* BakedOpRenderer::createOffscreenBuffer(uint32_t width, uint32_t height) {
58 // TODO: get from cache!
59 return new OffscreenBuffer(Caches::getInstance(), width, height, width, height);
60}
61
62void BakedOpRenderer::destroyOffscreenBuffer(OffscreenBuffer* offscreenBuffer) {
63 // destroy and delete, since each clipped saveLayer is only drawn once.
64 offscreenBuffer->texture.deleteTexture();
65
66 // TODO: return texture/offscreenbuffer to cache!
67 delete offscreenBuffer;
68}
69
70OffscreenBuffer* BakedOpRenderer::createLayer(uint32_t width, uint32_t height) {
Chris Craik5854b342015-10-26 15:49:56 -070071 LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");
Chris Craikb565df12015-10-05 13:00:52 -070072
Chris Craik0b7e8242015-10-28 16:50:44 -070073 OffscreenBuffer* buffer = createOffscreenBuffer(width, height);
74 startLayer(buffer);
75 return buffer;
76}
77
78void BakedOpRenderer::startLayer(OffscreenBuffer* offscreenBuffer) {
79 mRenderTarget.offscreenBuffer = offscreenBuffer;
Chris Craik818c9fb2015-10-23 14:33:42 -070080
Chris Craik5854b342015-10-26 15:49:56 -070081 // create and bind framebuffer
82 mRenderTarget.frameBufferId = mRenderState.genFramebuffer();
83 mRenderState.bindFramebuffer(mRenderTarget.frameBufferId);
Chris Craik818c9fb2015-10-23 14:33:42 -070084
85 // attach the texture to the FBO
86 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
Chris Craik0b7e8242015-10-28 16:50:44 -070087 offscreenBuffer->texture.id, 0);
Chris Craik818c9fb2015-10-23 14:33:42 -070088 LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "startLayer FAILED");
89 LOG_ALWAYS_FATAL_IF(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE,
90 "framebuffer incomplete!");
91
92 // Clear the FBO
Chris Craik5854b342015-10-26 15:49:56 -070093 mRenderState.scissor().setEnabled(false);
Chris Craik818c9fb2015-10-23 14:33:42 -070094 glClear(GL_COLOR_BUFFER_BIT);
95
96 // Change the viewport & ortho projection
Chris Craik0b7e8242015-10-28 16:50:44 -070097 setViewport(offscreenBuffer->viewportWidth, offscreenBuffer->viewportHeight);
Chris Craik818c9fb2015-10-23 14:33:42 -070098}
99
Chris Craik5854b342015-10-26 15:49:56 -0700100void BakedOpRenderer::endLayer() {
101 mRenderTarget.offscreenBuffer = nullptr;
Chris Craik818c9fb2015-10-23 14:33:42 -0700102
103 // Detach the texture from the FBO
104 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
105 LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED");
Chris Craik5854b342015-10-26 15:49:56 -0700106 mRenderState.deleteFramebuffer(mRenderTarget.frameBufferId);
107 mRenderTarget.frameBufferId = -1;
Chris Craik818c9fb2015-10-23 14:33:42 -0700108}
109
Chris Craik5854b342015-10-26 15:49:56 -0700110void BakedOpRenderer::startFrame(uint32_t width, uint32_t height) {
111 mRenderState.bindFramebuffer(0);
112 setViewport(width, height);
113 mCaches.clearGarbage();
Chris Craikb565df12015-10-05 13:00:52 -0700114
Chris Craik5854b342015-10-26 15:49:56 -0700115 if (!mOpaque) {
Chris Craikb565df12015-10-05 13:00:52 -0700116 // TODO: partial invalidate!
Chris Craik5854b342015-10-26 15:49:56 -0700117 mRenderState.scissor().setEnabled(false);
Chris Craikb565df12015-10-05 13:00:52 -0700118 glClear(GL_COLOR_BUFFER_BIT);
Chris Craik5854b342015-10-26 15:49:56 -0700119 mHasDrawn = true;
Chris Craikb565df12015-10-05 13:00:52 -0700120 }
121}
Chris Craik5854b342015-10-26 15:49:56 -0700122
123void BakedOpRenderer::endFrame() {
124 mCaches.pathCache.trim();
125 mCaches.tessellationCache.trim();
Chris Craikb565df12015-10-05 13:00:52 -0700126
127#if DEBUG_OPENGL
128 GLUtils::dumpGLErrors();
129#endif
130
131#if DEBUG_MEMORY_USAGE
Chris Craik5854b342015-10-26 15:49:56 -0700132 mCaches.dumpMemoryUsage();
Chris Craikb565df12015-10-05 13:00:52 -0700133#else
134 if (Properties::debugLevel & kDebugMemory) {
Chris Craik5854b342015-10-26 15:49:56 -0700135 mCaches.dumpMemoryUsage();
Chris Craikb565df12015-10-05 13:00:52 -0700136 }
137#endif
138}
139
Chris Craik5854b342015-10-26 15:49:56 -0700140void BakedOpRenderer::setViewport(uint32_t width, uint32_t height) {
141 mRenderTarget.viewportWidth = width;
142 mRenderTarget.viewportHeight = height;
143 mRenderTarget.orthoMatrix.loadOrtho(width, height);
144
145 mRenderState.setViewport(width, height);
146 mRenderState.blend().syncEnabled();
147}
148
149Texture* BakedOpRenderer::getTexture(const SkBitmap* bitmap) {
150 Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
151 if (!texture) {
152 return mCaches.textureCache.get(bitmap);
153 }
154 return texture;
155}
156
157void BakedOpRenderer::renderGlop(const BakedOpState& state, const Glop& glop) {
158 bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None;
159 mRenderState.scissor().setEnabled(useScissor);
160 if (useScissor) {
161 const Rect& clip = state.computedState.clipRect;
162 mRenderState.scissor().set(clip.left, mRenderTarget.viewportHeight - clip.bottom,
163 clip.getWidth(), clip.getHeight());
164 }
165 mRenderState.render(glop, mRenderTarget.orthoMatrix);
166 mHasDrawn = true;
167}
168
169////////////////////////////////////////////////////////////////////////////////
170// static BakedOpDispatcher methods
171////////////////////////////////////////////////////////////////////////////////
172
173void BakedOpDispatcher::onRenderNodeOp(BakedOpRenderer&, const RenderNodeOp&, const BakedOpState&) {
Chris Craikb565df12015-10-05 13:00:52 -0700174 LOG_ALWAYS_FATAL("unsupported operation");
175}
176
Chris Craik5854b342015-10-26 15:49:56 -0700177void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op, const BakedOpState& state) {
178 renderer.caches().textureState().activateTexture(0); // TODO: should this be automatic, and/or elsewhere?
179 Texture* texture = renderer.getTexture(op.bitmap);
Chris Craikb565df12015-10-05 13:00:52 -0700180 if (!texture) return;
181 const AutoTexture autoCleanup(texture);
182
183 const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType)
184 ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
185 Glop glop;
Chris Craik5854b342015-10-26 15:49:56 -0700186 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
Chris Craikb565df12015-10-05 13:00:52 -0700187 .setRoundRectClipState(state.roundRectClipState)
188 .setMeshTexturedUnitQuad(texture->uvMapper)
189 .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
190 .setTransform(state.computedState.transform, TransformFlags::None)
191 .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
192 .build();
Chris Craik5854b342015-10-26 15:49:56 -0700193 renderer.renderGlop(state, glop);
Chris Craikb565df12015-10-05 13:00:52 -0700194}
195
Chris Craik5854b342015-10-26 15:49:56 -0700196void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, const BakedOpState& state) {
Chris Craikb565df12015-10-05 13:00:52 -0700197 Glop glop;
Chris Craik5854b342015-10-26 15:49:56 -0700198 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
Chris Craikb565df12015-10-05 13:00:52 -0700199 .setRoundRectClipState(state.roundRectClipState)
200 .setMeshUnitQuad()
201 .setFillPaint(*op.paint, state.alpha)
202 .setTransform(state.computedState.transform, TransformFlags::None)
203 .setModelViewMapUnitToRect(op.unmappedBounds)
204 .build();
Chris Craik5854b342015-10-26 15:49:56 -0700205 renderer.renderGlop(state, glop);
Chris Craikb565df12015-10-05 13:00:52 -0700206}
207
Chris Craik5854b342015-10-26 15:49:56 -0700208void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op, const BakedOpState& state) {
Chris Craikb565df12015-10-05 13:00:52 -0700209 Glop glop;
Chris Craik5854b342015-10-26 15:49:56 -0700210 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
Chris Craikb565df12015-10-05 13:00:52 -0700211 .setRoundRectClipState(state.roundRectClipState)
212 .setMeshIndexedQuads(&op.vertices[0], op.vertexCount / 4)
213 .setFillPaint(*op.paint, state.alpha)
214 .setTransform(state.computedState.transform, TransformFlags::None)
215 .setModelViewOffsetRect(0, 0, op.unmappedBounds)
216 .build();
Chris Craik5854b342015-10-26 15:49:56 -0700217 renderer.renderGlop(state, glop);
Chris Craikb565df12015-10-05 13:00:52 -0700218}
219
Chris Craik5854b342015-10-26 15:49:56 -0700220void BakedOpDispatcher::onBeginLayerOp(BakedOpRenderer& renderer, const BeginLayerOp& op, const BakedOpState& state) {
Chris Craik6fe991e52015-10-20 09:39:42 -0700221 LOG_ALWAYS_FATAL("unsupported operation");
222}
223
Chris Craik5854b342015-10-26 15:49:56 -0700224void BakedOpDispatcher::onEndLayerOp(BakedOpRenderer& renderer, const EndLayerOp& op, const BakedOpState& state) {
Chris Craik6fe991e52015-10-20 09:39:42 -0700225 LOG_ALWAYS_FATAL("unsupported operation");
226}
227
Chris Craik5854b342015-10-26 15:49:56 -0700228void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) {
229 OffscreenBuffer* buffer = *op.layerHandle;
Chris Craik818c9fb2015-10-23 14:33:42 -0700230
Chris Craik5854b342015-10-26 15:49:56 -0700231 // TODO: extend this to handle HW layers & paint properties which
232 // reside in node.properties().layerProperties()
Chris Craik0b7e8242015-10-28 16:50:44 -0700233 float layerAlpha = op.alpha * state.alpha;
Chris Craik818c9fb2015-10-23 14:33:42 -0700234 const bool tryToSnap = state.computedState.transform.isPureTranslate();
235 Glop glop;
Chris Craik5854b342015-10-26 15:49:56 -0700236 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
Chris Craik818c9fb2015-10-23 14:33:42 -0700237 .setRoundRectClipState(state.roundRectClipState)
Chris Craik5854b342015-10-26 15:49:56 -0700238 .setMeshTexturedUvQuad(nullptr, buffer->texCoords)
Chris Craik0b7e8242015-10-28 16:50:44 -0700239 .setFillLayer(buffer->texture, op.colorFilter, layerAlpha, op.mode, Blend::ModeOrderSwap::NoSwap)
Chris Craik818c9fb2015-10-23 14:33:42 -0700240 .setTransform(state.computedState.transform, TransformFlags::None)
241 .setModelViewMapUnitToRectOptionalSnap(tryToSnap, op.unmappedBounds)
242 .build();
Chris Craik5854b342015-10-26 15:49:56 -0700243 renderer.renderGlop(state, glop);
Chris Craik818c9fb2015-10-23 14:33:42 -0700244
Chris Craik0b7e8242015-10-28 16:50:44 -0700245 if (op.destroy) {
246 BakedOpRenderer::destroyOffscreenBuffer(buffer);
247 }
Chris Craik6fe991e52015-10-20 09:39:42 -0700248}
Chris Craikb565df12015-10-05 13:00:52 -0700249
250} // namespace uirenderer
251} // namespace android