blob: d2d3285b71f8ee893aeeee1d0fe5802078240f84 [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"
Chris Craik9fded232015-11-11 16:42:34 -080022#include "renderstate/OffscreenBufferPool.h"
Chris Craikb565df12015-10-05 13:00:52 -070023#include "renderstate/RenderState.h"
24#include "utils/GLUtils.h"
Chris Craik9fded232015-11-11 16:42:34 -080025#include "VertexBuffer.h"
Chris Craikb565df12015-10-05 13:00:52 -070026
27namespace android {
28namespace uirenderer {
29
Chris Craik5854b342015-10-26 15:49:56 -070030////////////////////////////////////////////////////////////////////////////////
Chris Craik5854b342015-10-26 15:49:56 -070031// BakedOpRenderer
32////////////////////////////////////////////////////////////////////////////////
Chris Craikb565df12015-10-05 13:00:52 -070033
Chris Craikd3daa312015-11-06 10:59:56 -080034OffscreenBuffer* BakedOpRenderer::startTemporaryLayer(uint32_t width, uint32_t height) {
Chris Craik9fded232015-11-11 16:42:34 -080035 LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");
36
37 OffscreenBuffer* buffer = mRenderState.layerPool().get(mRenderState, width, height);
Chris Craik98787e62015-11-13 10:55:30 -080038 startRepaintLayer(buffer, Rect(width, height));
Chris Craik0b7e8242015-10-28 16:50:44 -070039 return buffer;
40}
41
Chris Craik98787e62015-11-13 10:55:30 -080042void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) {
Chris Craikd3daa312015-11-06 10:59:56 -080043 LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");
44
Chris Craik0b7e8242015-10-28 16:50:44 -070045 mRenderTarget.offscreenBuffer = offscreenBuffer;
Chris Craik818c9fb2015-10-23 14:33:42 -070046
Chris Craik5854b342015-10-26 15:49:56 -070047 // create and bind framebuffer
48 mRenderTarget.frameBufferId = mRenderState.genFramebuffer();
49 mRenderState.bindFramebuffer(mRenderTarget.frameBufferId);
Chris Craik818c9fb2015-10-23 14:33:42 -070050
51 // attach the texture to the FBO
52 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
Chris Craik0b7e8242015-10-28 16:50:44 -070053 offscreenBuffer->texture.id, 0);
Chris Craik818c9fb2015-10-23 14:33:42 -070054 LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "startLayer FAILED");
55 LOG_ALWAYS_FATAL_IF(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE,
56 "framebuffer incomplete!");
57
Chris Craik818c9fb2015-10-23 14:33:42 -070058 // Change the viewport & ortho projection
Chris Craik0b7e8242015-10-28 16:50:44 -070059 setViewport(offscreenBuffer->viewportWidth, offscreenBuffer->viewportHeight);
Chris Craik98787e62015-11-13 10:55:30 -080060
61 clearColorBuffer(repaintRect);
Chris Craik818c9fb2015-10-23 14:33:42 -070062}
63
Chris Craik5854b342015-10-26 15:49:56 -070064void BakedOpRenderer::endLayer() {
Chris Craik8d2cf942015-11-02 14:52:21 -080065 mRenderTarget.offscreenBuffer->updateMeshFromRegion();
Chris Craik5854b342015-10-26 15:49:56 -070066 mRenderTarget.offscreenBuffer = nullptr;
Chris Craik818c9fb2015-10-23 14:33:42 -070067
68 // Detach the texture from the FBO
69 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
70 LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED");
Chris Craik5854b342015-10-26 15:49:56 -070071 mRenderState.deleteFramebuffer(mRenderTarget.frameBufferId);
72 mRenderTarget.frameBufferId = -1;
Chris Craik818c9fb2015-10-23 14:33:42 -070073}
74
Chris Craik98787e62015-11-13 10:55:30 -080075void BakedOpRenderer::startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {
Chris Craik5854b342015-10-26 15:49:56 -070076 mRenderState.bindFramebuffer(0);
77 setViewport(width, height);
78 mCaches.clearGarbage();
Chris Craikb565df12015-10-05 13:00:52 -070079
Chris Craik5854b342015-10-26 15:49:56 -070080 if (!mOpaque) {
Chris Craik98787e62015-11-13 10:55:30 -080081 clearColorBuffer(repaintRect);
Chris Craikb565df12015-10-05 13:00:52 -070082 }
83}
Chris Craik5854b342015-10-26 15:49:56 -070084
85void BakedOpRenderer::endFrame() {
86 mCaches.pathCache.trim();
87 mCaches.tessellationCache.trim();
Chris Craikb565df12015-10-05 13:00:52 -070088
89#if DEBUG_OPENGL
90 GLUtils::dumpGLErrors();
91#endif
92
93#if DEBUG_MEMORY_USAGE
Chris Craik5854b342015-10-26 15:49:56 -070094 mCaches.dumpMemoryUsage();
Chris Craikb565df12015-10-05 13:00:52 -070095#else
96 if (Properties::debugLevel & kDebugMemory) {
Chris Craik5854b342015-10-26 15:49:56 -070097 mCaches.dumpMemoryUsage();
Chris Craikb565df12015-10-05 13:00:52 -070098 }
99#endif
100}
101
Chris Craik5854b342015-10-26 15:49:56 -0700102void BakedOpRenderer::setViewport(uint32_t width, uint32_t height) {
103 mRenderTarget.viewportWidth = width;
104 mRenderTarget.viewportHeight = height;
105 mRenderTarget.orthoMatrix.loadOrtho(width, height);
106
107 mRenderState.setViewport(width, height);
108 mRenderState.blend().syncEnabled();
109}
110
Chris Craik98787e62015-11-13 10:55:30 -0800111void BakedOpRenderer::clearColorBuffer(const Rect& rect) {
112 if (Rect(mRenderTarget.viewportWidth, mRenderTarget.viewportHeight).contains(rect)) {
113 // Full viewport is being cleared - disable scissor
114 mRenderState.scissor().setEnabled(false);
115 } else {
116 // Requested rect is subset of viewport - scissor to it to avoid over-clearing
117 mRenderState.scissor().setEnabled(true);
118 mRenderState.scissor().set(rect.left, mRenderTarget.viewportHeight - rect.bottom,
119 rect.getWidth(), rect.getHeight());
120 }
121 glClear(GL_COLOR_BUFFER_BIT);
122 if (!mRenderTarget.frameBufferId) mHasDrawn = true;
123}
124
Chris Craik5854b342015-10-26 15:49:56 -0700125Texture* BakedOpRenderer::getTexture(const SkBitmap* bitmap) {
126 Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
127 if (!texture) {
128 return mCaches.textureCache.get(bitmap);
129 }
130 return texture;
131}
132
133void BakedOpRenderer::renderGlop(const BakedOpState& state, const Glop& glop) {
134 bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None;
135 mRenderState.scissor().setEnabled(useScissor);
136 if (useScissor) {
137 const Rect& clip = state.computedState.clipRect;
138 mRenderState.scissor().set(clip.left, mRenderTarget.viewportHeight - clip.bottom,
139 clip.getWidth(), clip.getHeight());
140 }
Chris Craik8d2cf942015-11-02 14:52:21 -0800141 if (mRenderTarget.offscreenBuffer) { // TODO: not with multi-draw
142 // register layer damage to draw-back region
143 const Rect& uiDirty = state.computedState.clippedBounds;
144 android::Rect dirty(uiDirty.left, uiDirty.top, uiDirty.right, uiDirty.bottom);
145 mRenderTarget.offscreenBuffer->region.orSelf(dirty);
146 }
Chris Craik5854b342015-10-26 15:49:56 -0700147 mRenderState.render(glop, mRenderTarget.orthoMatrix);
Chris Craik98787e62015-11-13 10:55:30 -0800148 if (!mRenderTarget.frameBufferId) mHasDrawn = true;
Chris Craik5854b342015-10-26 15:49:56 -0700149}
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 Craik8d2cf942015-11-02 14:52:21 -0800159void BakedOpDispatcher::onBeginLayerOp(BakedOpRenderer& renderer, const BeginLayerOp& op, const BakedOpState& state) {
160 LOG_ALWAYS_FATAL("unsupported operation");
161}
162
163void BakedOpDispatcher::onEndLayerOp(BakedOpRenderer& renderer, const EndLayerOp& op, const BakedOpState& state) {
164 LOG_ALWAYS_FATAL("unsupported operation");
165}
166
Chris Craik5854b342015-10-26 15:49:56 -0700167void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op, const BakedOpState& state) {
168 renderer.caches().textureState().activateTexture(0); // TODO: should this be automatic, and/or elsewhere?
169 Texture* texture = renderer.getTexture(op.bitmap);
Chris Craikb565df12015-10-05 13:00:52 -0700170 if (!texture) return;
171 const AutoTexture autoCleanup(texture);
172
173 const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType)
174 ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
175 Glop glop;
Chris Craik5854b342015-10-26 15:49:56 -0700176 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
Chris Craikb565df12015-10-05 13:00:52 -0700177 .setRoundRectClipState(state.roundRectClipState)
178 .setMeshTexturedUnitQuad(texture->uvMapper)
179 .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
180 .setTransform(state.computedState.transform, TransformFlags::None)
181 .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
182 .build();
Chris Craik5854b342015-10-26 15:49:56 -0700183 renderer.renderGlop(state, glop);
Chris Craikb565df12015-10-05 13:00:52 -0700184}
185
Chris Craik5854b342015-10-26 15:49:56 -0700186void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, const BakedOpState& state) {
Chris Craikb565df12015-10-05 13:00:52 -0700187 Glop glop;
Chris Craik5854b342015-10-26 15:49:56 -0700188 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
Chris Craikb565df12015-10-05 13:00:52 -0700189 .setRoundRectClipState(state.roundRectClipState)
190 .setMeshUnitQuad()
191 .setFillPaint(*op.paint, state.alpha)
192 .setTransform(state.computedState.transform, TransformFlags::None)
193 .setModelViewMapUnitToRect(op.unmappedBounds)
194 .build();
Chris Craik5854b342015-10-26 15:49:56 -0700195 renderer.renderGlop(state, glop);
Chris Craikb565df12015-10-05 13:00:52 -0700196}
197
Chris Craikd3daa312015-11-06 10:59:56 -0800198namespace VertexBufferRenderFlags {
199 enum {
200 Offset = 0x1,
201 ShadowInterp = 0x2,
202 };
203}
204
205static void renderVertexBuffer(BakedOpRenderer& renderer, const BakedOpState& state,
206 const VertexBuffer& vertexBuffer, float translateX, float translateY,
207 SkPaint& paint, int vertexBufferRenderFlags) {
208 if (CC_LIKELY(vertexBuffer.getVertexCount())) {
209 bool shadowInterp = vertexBufferRenderFlags & VertexBufferRenderFlags::ShadowInterp;
210 const int transformFlags = TransformFlags::OffsetByFudgeFactor;
211 Glop glop;
212 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
213 .setRoundRectClipState(state.roundRectClipState)
214 .setMeshVertexBuffer(vertexBuffer, shadowInterp)
215 .setFillPaint(paint, state.alpha)
216 .setTransform(state.computedState.transform, transformFlags)
217 .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
218 .build();
219 renderer.renderGlop(state, glop);
220 }
221}
222
223static void renderShadow(BakedOpRenderer& renderer, const BakedOpState& state, float casterAlpha,
224 const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
225 SkPaint paint;
226 paint.setAntiAlias(true); // want to use AlphaVertex
227
228 // The caller has made sure casterAlpha > 0.
Chris Craik98787e62015-11-13 10:55:30 -0800229 uint8_t ambientShadowAlpha = renderer.getLightInfo().ambientShadowAlpha;
Chris Craikd3daa312015-11-06 10:59:56 -0800230 if (CC_UNLIKELY(Properties::overrideAmbientShadowStrength >= 0)) {
231 ambientShadowAlpha = Properties::overrideAmbientShadowStrength;
232 }
233 if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) {
234 paint.setAlpha((uint8_t)(casterAlpha * ambientShadowAlpha));
235 renderVertexBuffer(renderer, state, *ambientShadowVertexBuffer, 0, 0,
236 paint, VertexBufferRenderFlags::ShadowInterp);
237 }
238
Chris Craik98787e62015-11-13 10:55:30 -0800239 uint8_t spotShadowAlpha = renderer.getLightInfo().spotShadowAlpha;
Chris Craikd3daa312015-11-06 10:59:56 -0800240 if (CC_UNLIKELY(Properties::overrideSpotShadowStrength >= 0)) {
241 spotShadowAlpha = Properties::overrideSpotShadowStrength;
242 }
243 if (spotShadowVertexBuffer && spotShadowAlpha > 0) {
244 paint.setAlpha((uint8_t)(casterAlpha * spotShadowAlpha));
245 renderVertexBuffer(renderer, state, *spotShadowVertexBuffer, 0, 0,
246 paint, VertexBufferRenderFlags::ShadowInterp);
247 }
248}
249
250void BakedOpDispatcher::onShadowOp(BakedOpRenderer& renderer, const ShadowOp& op, const BakedOpState& state) {
251 TessellationCache::vertexBuffer_pair_t buffers;
Chris Craikd3daa312015-11-06 10:59:56 -0800252 renderer.caches().tessellationCache.getShadowBuffers(&state.computedState.transform,
253 op.localClipRect, op.casterAlpha >= 1.0f, op.casterPath,
Chris Craik98787e62015-11-13 10:55:30 -0800254 &op.shadowMatrixXY, &op.shadowMatrixZ,
255 op.lightCenter, renderer.getLightInfo().lightRadius,
Chris Craikd3daa312015-11-06 10:59:56 -0800256 buffers);
257
258 renderShadow(renderer, state, op.casterAlpha, buffers.first, buffers.second);
259}
260
Chris Craik5854b342015-10-26 15:49:56 -0700261void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op, const BakedOpState& state) {
Chris Craikb565df12015-10-05 13:00:52 -0700262 Glop glop;
Chris Craik5854b342015-10-26 15:49:56 -0700263 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
Chris Craikb565df12015-10-05 13:00:52 -0700264 .setRoundRectClipState(state.roundRectClipState)
265 .setMeshIndexedQuads(&op.vertices[0], op.vertexCount / 4)
266 .setFillPaint(*op.paint, state.alpha)
267 .setTransform(state.computedState.transform, TransformFlags::None)
268 .setModelViewOffsetRect(0, 0, op.unmappedBounds)
269 .build();
Chris Craik5854b342015-10-26 15:49:56 -0700270 renderer.renderGlop(state, glop);
Chris Craikb565df12015-10-05 13:00:52 -0700271}
272
Chris Craik5854b342015-10-26 15:49:56 -0700273void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) {
274 OffscreenBuffer* buffer = *op.layerHandle;
Chris Craik818c9fb2015-10-23 14:33:42 -0700275
Chris Craik5854b342015-10-26 15:49:56 -0700276 // TODO: extend this to handle HW layers & paint properties which
277 // reside in node.properties().layerProperties()
Chris Craik0b7e8242015-10-28 16:50:44 -0700278 float layerAlpha = op.alpha * state.alpha;
Chris Craik818c9fb2015-10-23 14:33:42 -0700279 Glop glop;
Chris Craik5854b342015-10-26 15:49:56 -0700280 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
Chris Craik818c9fb2015-10-23 14:33:42 -0700281 .setRoundRectClipState(state.roundRectClipState)
Chris Craik8d2cf942015-11-02 14:52:21 -0800282 .setMeshTexturedIndexedVbo(buffer->vbo, buffer->elementCount)
Chris Craik0b7e8242015-10-28 16:50:44 -0700283 .setFillLayer(buffer->texture, op.colorFilter, layerAlpha, op.mode, Blend::ModeOrderSwap::NoSwap)
Chris Craik818c9fb2015-10-23 14:33:42 -0700284 .setTransform(state.computedState.transform, TransformFlags::None)
Chris Craik8d2cf942015-11-02 14:52:21 -0800285 .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top,
286 Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight()))
Chris Craik818c9fb2015-10-23 14:33:42 -0700287 .build();
Chris Craik5854b342015-10-26 15:49:56 -0700288 renderer.renderGlop(state, glop);
Chris Craik818c9fb2015-10-23 14:33:42 -0700289
Chris Craik0b7e8242015-10-28 16:50:44 -0700290 if (op.destroy) {
Chris Craik9fded232015-11-11 16:42:34 -0800291 renderer.renderState().layerPool().putOrDelete(buffer);
Chris Craik0b7e8242015-10-28 16:50:44 -0700292 }
Chris Craik6fe991e52015-10-20 09:39:42 -0700293}
Chris Craikb565df12015-10-05 13:00:52 -0700294
295} // namespace uirenderer
296} // namespace android