blob: 086885320ccedcac9b2e39e23eaaa19aec279a7b [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)
34 : texture(caches)
35 , texCoords(0, viewportHeight / float(textureHeight), viewportWidth / float(textureWidth), 0) {
36 texture.width = textureWidth;
37 texture.height = textureHeight;
38
39 caches.textureState().activateTexture(0);
40 glGenTextures(1, &texture.id);
41 caches.textureState().bindTexture(GL_TEXTURE_2D, texture.id);
42
43 texture.setWrap(GL_CLAMP_TO_EDGE, false, false, GL_TEXTURE_2D);
44 // not setting filter on texture, since it's set when drawing, based on transform
45
46 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
47 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0,
48 GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
Chris Craik818c9fb2015-10-23 14:33:42 -070049}
50
Chris Craik5854b342015-10-26 15:49:56 -070051////////////////////////////////////////////////////////////////////////////////
52// BakedOpRenderer
53////////////////////////////////////////////////////////////////////////////////
Chris Craikb565df12015-10-05 13:00:52 -070054
Chris Craik5854b342015-10-26 15:49:56 -070055OffscreenBuffer* BakedOpRenderer::startLayer(uint32_t width, uint32_t height) {
56 LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");
Chris Craikb565df12015-10-05 13:00:52 -070057
Chris Craik5854b342015-10-26 15:49:56 -070058 // TODO: really should be caching these!
59 OffscreenBuffer* buffer = new OffscreenBuffer(mCaches, width, height, width, height);
60 mRenderTarget.offscreenBuffer = buffer;
Chris Craik818c9fb2015-10-23 14:33:42 -070061
Chris Craik5854b342015-10-26 15:49:56 -070062 // create and bind framebuffer
63 mRenderTarget.frameBufferId = mRenderState.genFramebuffer();
64 mRenderState.bindFramebuffer(mRenderTarget.frameBufferId);
Chris Craik818c9fb2015-10-23 14:33:42 -070065
66 // attach the texture to the FBO
67 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
Chris Craik5854b342015-10-26 15:49:56 -070068 buffer->texture.id, 0);
Chris Craik818c9fb2015-10-23 14:33:42 -070069 LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "startLayer FAILED");
70 LOG_ALWAYS_FATAL_IF(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE,
71 "framebuffer incomplete!");
72
73 // Clear the FBO
Chris Craik5854b342015-10-26 15:49:56 -070074 mRenderState.scissor().setEnabled(false);
Chris Craik818c9fb2015-10-23 14:33:42 -070075 glClear(GL_COLOR_BUFFER_BIT);
76
77 // Change the viewport & ortho projection
Chris Craik5854b342015-10-26 15:49:56 -070078 setViewport(width, height);
79 return buffer;
Chris Craik818c9fb2015-10-23 14:33:42 -070080}
81
Chris Craik5854b342015-10-26 15:49:56 -070082void BakedOpRenderer::endLayer() {
83 mRenderTarget.offscreenBuffer = nullptr;
Chris Craik818c9fb2015-10-23 14:33:42 -070084
85 // Detach the texture from the FBO
86 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
87 LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED");
Chris Craik5854b342015-10-26 15:49:56 -070088 mRenderState.deleteFramebuffer(mRenderTarget.frameBufferId);
89 mRenderTarget.frameBufferId = -1;
Chris Craik818c9fb2015-10-23 14:33:42 -070090}
91
Chris Craik5854b342015-10-26 15:49:56 -070092void BakedOpRenderer::startFrame(uint32_t width, uint32_t height) {
93 mRenderState.bindFramebuffer(0);
94 setViewport(width, height);
95 mCaches.clearGarbage();
Chris Craikb565df12015-10-05 13:00:52 -070096
Chris Craik5854b342015-10-26 15:49:56 -070097 if (!mOpaque) {
Chris Craikb565df12015-10-05 13:00:52 -070098 // TODO: partial invalidate!
Chris Craik5854b342015-10-26 15:49:56 -070099 mRenderState.scissor().setEnabled(false);
Chris Craikb565df12015-10-05 13:00:52 -0700100 glClear(GL_COLOR_BUFFER_BIT);
Chris Craik5854b342015-10-26 15:49:56 -0700101 mHasDrawn = true;
Chris Craikb565df12015-10-05 13:00:52 -0700102 }
103}
Chris Craik5854b342015-10-26 15:49:56 -0700104
105void BakedOpRenderer::endFrame() {
106 mCaches.pathCache.trim();
107 mCaches.tessellationCache.trim();
Chris Craikb565df12015-10-05 13:00:52 -0700108
109#if DEBUG_OPENGL
110 GLUtils::dumpGLErrors();
111#endif
112
113#if DEBUG_MEMORY_USAGE
Chris Craik5854b342015-10-26 15:49:56 -0700114 mCaches.dumpMemoryUsage();
Chris Craikb565df12015-10-05 13:00:52 -0700115#else
116 if (Properties::debugLevel & kDebugMemory) {
Chris Craik5854b342015-10-26 15:49:56 -0700117 mCaches.dumpMemoryUsage();
Chris Craikb565df12015-10-05 13:00:52 -0700118 }
119#endif
120}
121
Chris Craik5854b342015-10-26 15:49:56 -0700122void BakedOpRenderer::setViewport(uint32_t width, uint32_t height) {
123 mRenderTarget.viewportWidth = width;
124 mRenderTarget.viewportHeight = height;
125 mRenderTarget.orthoMatrix.loadOrtho(width, height);
126
127 mRenderState.setViewport(width, height);
128 mRenderState.blend().syncEnabled();
129}
130
131Texture* BakedOpRenderer::getTexture(const SkBitmap* bitmap) {
132 Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
133 if (!texture) {
134 return mCaches.textureCache.get(bitmap);
135 }
136 return texture;
137}
138
139void BakedOpRenderer::renderGlop(const BakedOpState& state, const Glop& glop) {
140 bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None;
141 mRenderState.scissor().setEnabled(useScissor);
142 if (useScissor) {
143 const Rect& clip = state.computedState.clipRect;
144 mRenderState.scissor().set(clip.left, mRenderTarget.viewportHeight - clip.bottom,
145 clip.getWidth(), clip.getHeight());
146 }
147 mRenderState.render(glop, mRenderTarget.orthoMatrix);
148 mHasDrawn = true;
149}
150
151////////////////////////////////////////////////////////////////////////////////
152// static BakedOpDispatcher methods
153////////////////////////////////////////////////////////////////////////////////
154
155void BakedOpDispatcher::onRenderNodeOp(BakedOpRenderer&, const RenderNodeOp&, const BakedOpState&) {
Chris Craikb565df12015-10-05 13:00:52 -0700156 LOG_ALWAYS_FATAL("unsupported operation");
157}
158
Chris Craik5854b342015-10-26 15:49:56 -0700159void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op, const BakedOpState& state) {
160 renderer.caches().textureState().activateTexture(0); // TODO: should this be automatic, and/or elsewhere?
161 Texture* texture = renderer.getTexture(op.bitmap);
Chris Craikb565df12015-10-05 13:00:52 -0700162 if (!texture) return;
163 const AutoTexture autoCleanup(texture);
164
165 const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType)
166 ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
167 Glop glop;
Chris Craik5854b342015-10-26 15:49:56 -0700168 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
Chris Craikb565df12015-10-05 13:00:52 -0700169 .setRoundRectClipState(state.roundRectClipState)
170 .setMeshTexturedUnitQuad(texture->uvMapper)
171 .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
172 .setTransform(state.computedState.transform, TransformFlags::None)
173 .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
174 .build();
Chris Craik5854b342015-10-26 15:49:56 -0700175 renderer.renderGlop(state, glop);
Chris Craikb565df12015-10-05 13:00:52 -0700176}
177
Chris Craik5854b342015-10-26 15:49:56 -0700178void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, const BakedOpState& state) {
Chris Craikb565df12015-10-05 13:00:52 -0700179 Glop glop;
Chris Craik5854b342015-10-26 15:49:56 -0700180 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
Chris Craikb565df12015-10-05 13:00:52 -0700181 .setRoundRectClipState(state.roundRectClipState)
182 .setMeshUnitQuad()
183 .setFillPaint(*op.paint, state.alpha)
184 .setTransform(state.computedState.transform, TransformFlags::None)
185 .setModelViewMapUnitToRect(op.unmappedBounds)
186 .build();
Chris Craik5854b342015-10-26 15:49:56 -0700187 renderer.renderGlop(state, glop);
Chris Craikb565df12015-10-05 13:00:52 -0700188}
189
Chris Craik5854b342015-10-26 15:49:56 -0700190void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op, const BakedOpState& state) {
Chris Craikb565df12015-10-05 13:00:52 -0700191 Glop glop;
Chris Craik5854b342015-10-26 15:49:56 -0700192 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
Chris Craikb565df12015-10-05 13:00:52 -0700193 .setRoundRectClipState(state.roundRectClipState)
194 .setMeshIndexedQuads(&op.vertices[0], op.vertexCount / 4)
195 .setFillPaint(*op.paint, state.alpha)
196 .setTransform(state.computedState.transform, TransformFlags::None)
197 .setModelViewOffsetRect(0, 0, op.unmappedBounds)
198 .build();
Chris Craik5854b342015-10-26 15:49:56 -0700199 renderer.renderGlop(state, glop);
Chris Craikb565df12015-10-05 13:00:52 -0700200}
201
Chris Craik5854b342015-10-26 15:49:56 -0700202void BakedOpDispatcher::onBeginLayerOp(BakedOpRenderer& renderer, const BeginLayerOp& op, const BakedOpState& state) {
Chris Craik6fe991e52015-10-20 09:39:42 -0700203 LOG_ALWAYS_FATAL("unsupported operation");
204}
205
Chris Craik5854b342015-10-26 15:49:56 -0700206void BakedOpDispatcher::onEndLayerOp(BakedOpRenderer& renderer, const EndLayerOp& op, const BakedOpState& state) {
Chris Craik6fe991e52015-10-20 09:39:42 -0700207 LOG_ALWAYS_FATAL("unsupported operation");
208}
209
Chris Craik5854b342015-10-26 15:49:56 -0700210void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) {
211 OffscreenBuffer* buffer = *op.layerHandle;
Chris Craik818c9fb2015-10-23 14:33:42 -0700212
Chris Craik5854b342015-10-26 15:49:56 -0700213 // TODO: extend this to handle HW layers & paint properties which
214 // reside in node.properties().layerProperties()
215 float layerAlpha = (op.paint->getAlpha() / 255.0f) * state.alpha;
Chris Craik818c9fb2015-10-23 14:33:42 -0700216 const bool tryToSnap = state.computedState.transform.isPureTranslate();
217 Glop glop;
Chris Craik5854b342015-10-26 15:49:56 -0700218 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
Chris Craik818c9fb2015-10-23 14:33:42 -0700219 .setRoundRectClipState(state.roundRectClipState)
Chris Craik5854b342015-10-26 15:49:56 -0700220 .setMeshTexturedUvQuad(nullptr, buffer->texCoords)
221 .setFillLayer(buffer->texture, op.paint->getColorFilter(), layerAlpha, PaintUtils::getXfermodeDirect(op.paint), Blend::ModeOrderSwap::NoSwap)
Chris Craik818c9fb2015-10-23 14:33:42 -0700222 .setTransform(state.computedState.transform, TransformFlags::None)
223 .setModelViewMapUnitToRectOptionalSnap(tryToSnap, op.unmappedBounds)
224 .build();
Chris Craik5854b342015-10-26 15:49:56 -0700225 renderer.renderGlop(state, glop);
Chris Craik818c9fb2015-10-23 14:33:42 -0700226
Chris Craik5854b342015-10-26 15:49:56 -0700227 // destroy and delete, since each clipped saveLayer is only drawn once.
228 buffer->texture.deleteTexture();
229
230 // TODO: return texture/offscreenbuffer to cache!
231 delete buffer;
Chris Craik6fe991e52015-10-20 09:39:42 -0700232}
Chris Craikb565df12015-10-05 13:00:52 -0700233
234} // namespace uirenderer
235} // namespace android