blob: 938099209148e9b07ba3f21b48f85e9816b92cda [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 Craikd3daa312015-11-06 10:59:56 -080022#include "VertexBuffer.h"
Chris Craikb565df12015-10-05 13:00:52 -070023#include "renderstate/RenderState.h"
Chris Craik8d2cf942015-11-02 14:52:21 -080024#include "utils/FatVector.h"
Chris Craikb565df12015-10-05 13:00:52 -070025#include "utils/GLUtils.h"
26
27namespace android {
28namespace uirenderer {
29
Chris Craik5854b342015-10-26 15:49:56 -070030////////////////////////////////////////////////////////////////////////////////
31// OffscreenBuffer
32////////////////////////////////////////////////////////////////////////////////
Chris Craik818c9fb2015-10-23 14:33:42 -070033
Chris Craik8d2cf942015-11-02 14:52:21 -080034OffscreenBuffer::OffscreenBuffer(RenderState& renderState, Caches& caches,
35 uint32_t textureWidth, uint32_t textureHeight,
Chris Craik5854b342015-10-26 15:49:56 -070036 uint32_t viewportWidth, uint32_t viewportHeight)
Chris Craik8d2cf942015-11-02 14:52:21 -080037 : renderState(renderState)
38 , viewportWidth(viewportWidth)
Chris Craik0b7e8242015-10-28 16:50:44 -070039 , viewportHeight(viewportHeight)
Chris Craik8d2cf942015-11-02 14:52:21 -080040 , texture(caches) {
Chris Craik5854b342015-10-26 15:49:56 -070041 texture.width = textureWidth;
42 texture.height = textureHeight;
43
44 caches.textureState().activateTexture(0);
45 glGenTextures(1, &texture.id);
46 caches.textureState().bindTexture(GL_TEXTURE_2D, texture.id);
47
48 texture.setWrap(GL_CLAMP_TO_EDGE, false, false, GL_TEXTURE_2D);
Chris Craikd3daa312015-11-06 10:59:56 -080049 // not setting filter on texture, since it's set when rendering, based on transform
Chris Craik5854b342015-10-26 15:49:56 -070050
51 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
52 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0,
53 GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
Chris Craik818c9fb2015-10-23 14:33:42 -070054}
55
Chris Craik8d2cf942015-11-02 14:52:21 -080056void OffscreenBuffer::updateMeshFromRegion() {
57 // avoid T-junctions as they cause artifacts in between the resultant
58 // geometry when complex transforms occur.
Chris Craikd3daa312015-11-06 10:59:56 -080059 // TODO: generate the safeRegion only if necessary based on rendering transform
Chris Craik8d2cf942015-11-02 14:52:21 -080060 Region safeRegion = Region::createTJunctionFreeRegion(region);
61
62 size_t count;
63 const android::Rect* rects = safeRegion.getArray(&count);
64
65 const float texX = 1.0f / float(viewportWidth);
66 const float texY = 1.0f / float(viewportHeight);
67
68 FatVector<TextureVertex, 64> meshVector(count * 4); // uses heap if more than 64 vertices needed
69 TextureVertex* mesh = &meshVector[0];
70 for (size_t i = 0; i < count; i++) {
71 const android::Rect* r = &rects[i];
72
73 const float u1 = r->left * texX;
74 const float v1 = (viewportHeight - r->top) * texY;
75 const float u2 = r->right * texX;
76 const float v2 = (viewportHeight - r->bottom) * texY;
77
78 TextureVertex::set(mesh++, r->left, r->top, u1, v1);
79 TextureVertex::set(mesh++, r->right, r->top, u2, v1);
80 TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
81 TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
82 }
83 elementCount = count * 6;
84 renderState.meshState().genOrUpdateMeshBuffer(&vbo,
85 sizeof(TextureVertex) * count * 4,
86 &meshVector[0],
87 GL_DYNAMIC_DRAW); // TODO: GL_STATIC_DRAW if savelayer
88}
89
90OffscreenBuffer::~OffscreenBuffer() {
91 texture.deleteTexture();
92 renderState.meshState().deleteMeshBuffer(vbo);
93 elementCount = 0;
94 vbo = 0;
95}
96
Chris Craik5854b342015-10-26 15:49:56 -070097////////////////////////////////////////////////////////////////////////////////
98// BakedOpRenderer
99////////////////////////////////////////////////////////////////////////////////
Chris Craikb565df12015-10-05 13:00:52 -0700100
Chris Craik8d2cf942015-11-02 14:52:21 -0800101OffscreenBuffer* BakedOpRenderer::createOffscreenBuffer(RenderState& renderState,
102 uint32_t width, uint32_t height) {
Chris Craik0b7e8242015-10-28 16:50:44 -0700103 // TODO: get from cache!
Chris Craik8d2cf942015-11-02 14:52:21 -0800104 return new OffscreenBuffer(renderState, Caches::getInstance(), width, height, width, height);
Chris Craik0b7e8242015-10-28 16:50:44 -0700105}
106
107void BakedOpRenderer::destroyOffscreenBuffer(OffscreenBuffer* offscreenBuffer) {
Chris Craik0b7e8242015-10-28 16:50:44 -0700108 // TODO: return texture/offscreenbuffer to cache!
109 delete offscreenBuffer;
110}
111
Chris Craikd3daa312015-11-06 10:59:56 -0800112OffscreenBuffer* BakedOpRenderer::startTemporaryLayer(uint32_t width, uint32_t height) {
Chris Craik8d2cf942015-11-02 14:52:21 -0800113 OffscreenBuffer* buffer = createOffscreenBuffer(mRenderState, width, height);
Chris Craikd3daa312015-11-06 10:59:56 -0800114 startRepaintLayer(buffer);
Chris Craik0b7e8242015-10-28 16:50:44 -0700115 return buffer;
116}
117
Chris Craikd3daa312015-11-06 10:59:56 -0800118void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer) {
119 LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");
120
Chris Craik0b7e8242015-10-28 16:50:44 -0700121 mRenderTarget.offscreenBuffer = offscreenBuffer;
Chris Craik818c9fb2015-10-23 14:33:42 -0700122
Chris Craik5854b342015-10-26 15:49:56 -0700123 // create and bind framebuffer
124 mRenderTarget.frameBufferId = mRenderState.genFramebuffer();
125 mRenderState.bindFramebuffer(mRenderTarget.frameBufferId);
Chris Craik818c9fb2015-10-23 14:33:42 -0700126
127 // attach the texture to the FBO
128 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
Chris Craik0b7e8242015-10-28 16:50:44 -0700129 offscreenBuffer->texture.id, 0);
Chris Craik818c9fb2015-10-23 14:33:42 -0700130 LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "startLayer FAILED");
131 LOG_ALWAYS_FATAL_IF(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE,
132 "framebuffer incomplete!");
133
134 // Clear the FBO
Chris Craik5854b342015-10-26 15:49:56 -0700135 mRenderState.scissor().setEnabled(false);
Chris Craik818c9fb2015-10-23 14:33:42 -0700136 glClear(GL_COLOR_BUFFER_BIT);
137
138 // Change the viewport & ortho projection
Chris Craik0b7e8242015-10-28 16:50:44 -0700139 setViewport(offscreenBuffer->viewportWidth, offscreenBuffer->viewportHeight);
Chris Craik818c9fb2015-10-23 14:33:42 -0700140}
141
Chris Craik5854b342015-10-26 15:49:56 -0700142void BakedOpRenderer::endLayer() {
Chris Craik8d2cf942015-11-02 14:52:21 -0800143 mRenderTarget.offscreenBuffer->updateMeshFromRegion();
Chris Craik5854b342015-10-26 15:49:56 -0700144 mRenderTarget.offscreenBuffer = nullptr;
Chris Craik818c9fb2015-10-23 14:33:42 -0700145
146 // Detach the texture from the FBO
147 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
148 LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED");
Chris Craik5854b342015-10-26 15:49:56 -0700149 mRenderState.deleteFramebuffer(mRenderTarget.frameBufferId);
150 mRenderTarget.frameBufferId = -1;
Chris Craik818c9fb2015-10-23 14:33:42 -0700151}
152
Chris Craik5854b342015-10-26 15:49:56 -0700153void BakedOpRenderer::startFrame(uint32_t width, uint32_t height) {
154 mRenderState.bindFramebuffer(0);
155 setViewport(width, height);
156 mCaches.clearGarbage();
Chris Craikb565df12015-10-05 13:00:52 -0700157
Chris Craik5854b342015-10-26 15:49:56 -0700158 if (!mOpaque) {
Chris Craikb565df12015-10-05 13:00:52 -0700159 // TODO: partial invalidate!
Chris Craik5854b342015-10-26 15:49:56 -0700160 mRenderState.scissor().setEnabled(false);
Chris Craikb565df12015-10-05 13:00:52 -0700161 glClear(GL_COLOR_BUFFER_BIT);
Chris Craik5854b342015-10-26 15:49:56 -0700162 mHasDrawn = true;
Chris Craikb565df12015-10-05 13:00:52 -0700163 }
164}
Chris Craik5854b342015-10-26 15:49:56 -0700165
166void BakedOpRenderer::endFrame() {
167 mCaches.pathCache.trim();
168 mCaches.tessellationCache.trim();
Chris Craikb565df12015-10-05 13:00:52 -0700169
170#if DEBUG_OPENGL
171 GLUtils::dumpGLErrors();
172#endif
173
174#if DEBUG_MEMORY_USAGE
Chris Craik5854b342015-10-26 15:49:56 -0700175 mCaches.dumpMemoryUsage();
Chris Craikb565df12015-10-05 13:00:52 -0700176#else
177 if (Properties::debugLevel & kDebugMemory) {
Chris Craik5854b342015-10-26 15:49:56 -0700178 mCaches.dumpMemoryUsage();
Chris Craikb565df12015-10-05 13:00:52 -0700179 }
180#endif
181}
182
Chris Craik5854b342015-10-26 15:49:56 -0700183void BakedOpRenderer::setViewport(uint32_t width, uint32_t height) {
184 mRenderTarget.viewportWidth = width;
185 mRenderTarget.viewportHeight = height;
186 mRenderTarget.orthoMatrix.loadOrtho(width, height);
187
188 mRenderState.setViewport(width, height);
189 mRenderState.blend().syncEnabled();
190}
191
192Texture* BakedOpRenderer::getTexture(const SkBitmap* bitmap) {
193 Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
194 if (!texture) {
195 return mCaches.textureCache.get(bitmap);
196 }
197 return texture;
198}
199
200void BakedOpRenderer::renderGlop(const BakedOpState& state, const Glop& glop) {
201 bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None;
202 mRenderState.scissor().setEnabled(useScissor);
203 if (useScissor) {
204 const Rect& clip = state.computedState.clipRect;
205 mRenderState.scissor().set(clip.left, mRenderTarget.viewportHeight - clip.bottom,
206 clip.getWidth(), clip.getHeight());
207 }
Chris Craik8d2cf942015-11-02 14:52:21 -0800208 if (mRenderTarget.offscreenBuffer) { // TODO: not with multi-draw
209 // register layer damage to draw-back region
210 const Rect& uiDirty = state.computedState.clippedBounds;
211 android::Rect dirty(uiDirty.left, uiDirty.top, uiDirty.right, uiDirty.bottom);
212 mRenderTarget.offscreenBuffer->region.orSelf(dirty);
213 }
Chris Craik5854b342015-10-26 15:49:56 -0700214 mRenderState.render(glop, mRenderTarget.orthoMatrix);
215 mHasDrawn = true;
216}
217
218////////////////////////////////////////////////////////////////////////////////
219// static BakedOpDispatcher methods
220////////////////////////////////////////////////////////////////////////////////
221
222void BakedOpDispatcher::onRenderNodeOp(BakedOpRenderer&, const RenderNodeOp&, const BakedOpState&) {
Chris Craikb565df12015-10-05 13:00:52 -0700223 LOG_ALWAYS_FATAL("unsupported operation");
224}
225
Chris Craik8d2cf942015-11-02 14:52:21 -0800226void BakedOpDispatcher::onBeginLayerOp(BakedOpRenderer& renderer, const BeginLayerOp& op, const BakedOpState& state) {
227 LOG_ALWAYS_FATAL("unsupported operation");
228}
229
230void BakedOpDispatcher::onEndLayerOp(BakedOpRenderer& renderer, const EndLayerOp& op, const BakedOpState& state) {
231 LOG_ALWAYS_FATAL("unsupported operation");
232}
233
Chris Craik5854b342015-10-26 15:49:56 -0700234void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op, const BakedOpState& state) {
235 renderer.caches().textureState().activateTexture(0); // TODO: should this be automatic, and/or elsewhere?
236 Texture* texture = renderer.getTexture(op.bitmap);
Chris Craikb565df12015-10-05 13:00:52 -0700237 if (!texture) return;
238 const AutoTexture autoCleanup(texture);
239
240 const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType)
241 ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
242 Glop glop;
Chris Craik5854b342015-10-26 15:49:56 -0700243 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
Chris Craikb565df12015-10-05 13:00:52 -0700244 .setRoundRectClipState(state.roundRectClipState)
245 .setMeshTexturedUnitQuad(texture->uvMapper)
246 .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
247 .setTransform(state.computedState.transform, TransformFlags::None)
248 .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
249 .build();
Chris Craik5854b342015-10-26 15:49:56 -0700250 renderer.renderGlop(state, glop);
Chris Craikb565df12015-10-05 13:00:52 -0700251}
252
Chris Craik5854b342015-10-26 15:49:56 -0700253void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, const BakedOpState& state) {
Chris Craikb565df12015-10-05 13:00:52 -0700254 Glop glop;
Chris Craik5854b342015-10-26 15:49:56 -0700255 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
Chris Craikb565df12015-10-05 13:00:52 -0700256 .setRoundRectClipState(state.roundRectClipState)
257 .setMeshUnitQuad()
258 .setFillPaint(*op.paint, state.alpha)
259 .setTransform(state.computedState.transform, TransformFlags::None)
260 .setModelViewMapUnitToRect(op.unmappedBounds)
261 .build();
Chris Craik5854b342015-10-26 15:49:56 -0700262 renderer.renderGlop(state, glop);
Chris Craikb565df12015-10-05 13:00:52 -0700263}
264
Chris Craikd3daa312015-11-06 10:59:56 -0800265namespace VertexBufferRenderFlags {
266 enum {
267 Offset = 0x1,
268 ShadowInterp = 0x2,
269 };
270}
271
272static void renderVertexBuffer(BakedOpRenderer& renderer, const BakedOpState& state,
273 const VertexBuffer& vertexBuffer, float translateX, float translateY,
274 SkPaint& paint, int vertexBufferRenderFlags) {
275 if (CC_LIKELY(vertexBuffer.getVertexCount())) {
276 bool shadowInterp = vertexBufferRenderFlags & VertexBufferRenderFlags::ShadowInterp;
277 const int transformFlags = TransformFlags::OffsetByFudgeFactor;
278 Glop glop;
279 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
280 .setRoundRectClipState(state.roundRectClipState)
281 .setMeshVertexBuffer(vertexBuffer, shadowInterp)
282 .setFillPaint(paint, state.alpha)
283 .setTransform(state.computedState.transform, transformFlags)
284 .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
285 .build();
286 renderer.renderGlop(state, glop);
287 }
288}
289
290static void renderShadow(BakedOpRenderer& renderer, const BakedOpState& state, float casterAlpha,
291 const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
292 SkPaint paint;
293 paint.setAntiAlias(true); // want to use AlphaVertex
294
295 // The caller has made sure casterAlpha > 0.
296 uint8_t ambientShadowAlpha = 128u; //TODO: mAmbientShadowAlpha;
297 if (CC_UNLIKELY(Properties::overrideAmbientShadowStrength >= 0)) {
298 ambientShadowAlpha = Properties::overrideAmbientShadowStrength;
299 }
300 if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) {
301 paint.setAlpha((uint8_t)(casterAlpha * ambientShadowAlpha));
302 renderVertexBuffer(renderer, state, *ambientShadowVertexBuffer, 0, 0,
303 paint, VertexBufferRenderFlags::ShadowInterp);
304 }
305
306 uint8_t spotShadowAlpha = 128u; //TODO: mSpotShadowAlpha;
307 if (CC_UNLIKELY(Properties::overrideSpotShadowStrength >= 0)) {
308 spotShadowAlpha = Properties::overrideSpotShadowStrength;
309 }
310 if (spotShadowVertexBuffer && spotShadowAlpha > 0) {
311 paint.setAlpha((uint8_t)(casterAlpha * spotShadowAlpha));
312 renderVertexBuffer(renderer, state, *spotShadowVertexBuffer, 0, 0,
313 paint, VertexBufferRenderFlags::ShadowInterp);
314 }
315}
316
317void BakedOpDispatcher::onShadowOp(BakedOpRenderer& renderer, const ShadowOp& op, const BakedOpState& state) {
318 TessellationCache::vertexBuffer_pair_t buffers;
319 Vector3 lightCenter = { 300, 300, 300 }; // TODO!
320 float lightRadius = 150; // TODO!
321
322 renderer.caches().tessellationCache.getShadowBuffers(&state.computedState.transform,
323 op.localClipRect, op.casterAlpha >= 1.0f, op.casterPath,
324 &op.shadowMatrixXY, &op.shadowMatrixZ, lightCenter, lightRadius,
325 buffers);
326
327 renderShadow(renderer, state, op.casterAlpha, buffers.first, buffers.second);
328}
329
Chris Craik5854b342015-10-26 15:49:56 -0700330void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op, const BakedOpState& state) {
Chris Craikb565df12015-10-05 13:00:52 -0700331 Glop glop;
Chris Craik5854b342015-10-26 15:49:56 -0700332 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
Chris Craikb565df12015-10-05 13:00:52 -0700333 .setRoundRectClipState(state.roundRectClipState)
334 .setMeshIndexedQuads(&op.vertices[0], op.vertexCount / 4)
335 .setFillPaint(*op.paint, state.alpha)
336 .setTransform(state.computedState.transform, TransformFlags::None)
337 .setModelViewOffsetRect(0, 0, op.unmappedBounds)
338 .build();
Chris Craik5854b342015-10-26 15:49:56 -0700339 renderer.renderGlop(state, glop);
Chris Craikb565df12015-10-05 13:00:52 -0700340}
341
Chris Craik5854b342015-10-26 15:49:56 -0700342void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) {
343 OffscreenBuffer* buffer = *op.layerHandle;
Chris Craik818c9fb2015-10-23 14:33:42 -0700344
Chris Craik5854b342015-10-26 15:49:56 -0700345 // TODO: extend this to handle HW layers & paint properties which
346 // reside in node.properties().layerProperties()
Chris Craik0b7e8242015-10-28 16:50:44 -0700347 float layerAlpha = op.alpha * state.alpha;
Chris Craik818c9fb2015-10-23 14:33:42 -0700348 Glop glop;
Chris Craik5854b342015-10-26 15:49:56 -0700349 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
Chris Craik818c9fb2015-10-23 14:33:42 -0700350 .setRoundRectClipState(state.roundRectClipState)
Chris Craik8d2cf942015-11-02 14:52:21 -0800351 .setMeshTexturedIndexedVbo(buffer->vbo, buffer->elementCount)
Chris Craik0b7e8242015-10-28 16:50:44 -0700352 .setFillLayer(buffer->texture, op.colorFilter, layerAlpha, op.mode, Blend::ModeOrderSwap::NoSwap)
Chris Craik818c9fb2015-10-23 14:33:42 -0700353 .setTransform(state.computedState.transform, TransformFlags::None)
Chris Craik8d2cf942015-11-02 14:52:21 -0800354 .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top,
355 Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight()))
Chris Craik818c9fb2015-10-23 14:33:42 -0700356 .build();
Chris Craik5854b342015-10-26 15:49:56 -0700357 renderer.renderGlop(state, glop);
Chris Craik818c9fb2015-10-23 14:33:42 -0700358
Chris Craik0b7e8242015-10-28 16:50:44 -0700359 if (op.destroy) {
360 BakedOpRenderer::destroyOffscreenBuffer(buffer);
361 }
Chris Craik6fe991e52015-10-20 09:39:42 -0700362}
Chris Craikb565df12015-10-05 13:00:52 -0700363
364} // namespace uirenderer
365} // namespace android