blob: 2fca5ea8b96285cc8991eb9e9108b3cb40ca0c43 [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"
Chris Craik8d2cf942015-11-02 14:52:21 -080023#include "utils/FatVector.h"
Chris Craikb565df12015-10-05 13:00:52 -070024#include "utils/GLUtils.h"
25
26namespace android {
27namespace uirenderer {
28
Chris Craik5854b342015-10-26 15:49:56 -070029////////////////////////////////////////////////////////////////////////////////
30// OffscreenBuffer
31////////////////////////////////////////////////////////////////////////////////
Chris Craik818c9fb2015-10-23 14:33:42 -070032
Chris Craik8d2cf942015-11-02 14:52:21 -080033OffscreenBuffer::OffscreenBuffer(RenderState& renderState, Caches& caches,
34 uint32_t textureWidth, uint32_t textureHeight,
Chris Craik5854b342015-10-26 15:49:56 -070035 uint32_t viewportWidth, uint32_t viewportHeight)
Chris Craik8d2cf942015-11-02 14:52:21 -080036 : renderState(renderState)
37 , viewportWidth(viewportWidth)
Chris Craik0b7e8242015-10-28 16:50:44 -070038 , viewportHeight(viewportHeight)
Chris Craik8d2cf942015-11-02 14:52:21 -080039 , texture(caches) {
Chris Craik5854b342015-10-26 15:49:56 -070040 texture.width = textureWidth;
41 texture.height = textureHeight;
42
43 caches.textureState().activateTexture(0);
44 glGenTextures(1, &texture.id);
45 caches.textureState().bindTexture(GL_TEXTURE_2D, texture.id);
46
47 texture.setWrap(GL_CLAMP_TO_EDGE, false, false, GL_TEXTURE_2D);
48 // not setting filter on texture, since it's set when drawing, based on transform
49
50 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
51 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0,
52 GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
Chris Craik818c9fb2015-10-23 14:33:42 -070053}
54
Chris Craik8d2cf942015-11-02 14:52:21 -080055void OffscreenBuffer::updateMeshFromRegion() {
56 // avoid T-junctions as they cause artifacts in between the resultant
57 // geometry when complex transforms occur.
58 // TODO: generate the safeRegion only if necessary based on drawing transform
59 Region safeRegion = Region::createTJunctionFreeRegion(region);
60
61 size_t count;
62 const android::Rect* rects = safeRegion.getArray(&count);
63
64 const float texX = 1.0f / float(viewportWidth);
65 const float texY = 1.0f / float(viewportHeight);
66
67 FatVector<TextureVertex, 64> meshVector(count * 4); // uses heap if more than 64 vertices needed
68 TextureVertex* mesh = &meshVector[0];
69 for (size_t i = 0; i < count; i++) {
70 const android::Rect* r = &rects[i];
71
72 const float u1 = r->left * texX;
73 const float v1 = (viewportHeight - r->top) * texY;
74 const float u2 = r->right * texX;
75 const float v2 = (viewportHeight - r->bottom) * texY;
76
77 TextureVertex::set(mesh++, r->left, r->top, u1, v1);
78 TextureVertex::set(mesh++, r->right, r->top, u2, v1);
79 TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
80 TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
81 }
82 elementCount = count * 6;
83 renderState.meshState().genOrUpdateMeshBuffer(&vbo,
84 sizeof(TextureVertex) * count * 4,
85 &meshVector[0],
86 GL_DYNAMIC_DRAW); // TODO: GL_STATIC_DRAW if savelayer
87}
88
89OffscreenBuffer::~OffscreenBuffer() {
90 texture.deleteTexture();
91 renderState.meshState().deleteMeshBuffer(vbo);
92 elementCount = 0;
93 vbo = 0;
94}
95
Chris Craik5854b342015-10-26 15:49:56 -070096////////////////////////////////////////////////////////////////////////////////
97// BakedOpRenderer
98////////////////////////////////////////////////////////////////////////////////
Chris Craikb565df12015-10-05 13:00:52 -070099
Chris Craik8d2cf942015-11-02 14:52:21 -0800100OffscreenBuffer* BakedOpRenderer::createOffscreenBuffer(RenderState& renderState,
101 uint32_t width, uint32_t height) {
Chris Craik0b7e8242015-10-28 16:50:44 -0700102 // TODO: get from cache!
Chris Craik8d2cf942015-11-02 14:52:21 -0800103 return new OffscreenBuffer(renderState, Caches::getInstance(), width, height, width, height);
Chris Craik0b7e8242015-10-28 16:50:44 -0700104}
105
106void BakedOpRenderer::destroyOffscreenBuffer(OffscreenBuffer* offscreenBuffer) {
Chris Craik0b7e8242015-10-28 16:50:44 -0700107 // TODO: return texture/offscreenbuffer to cache!
108 delete offscreenBuffer;
109}
110
111OffscreenBuffer* BakedOpRenderer::createLayer(uint32_t width, uint32_t height) {
Chris Craik5854b342015-10-26 15:49:56 -0700112 LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");
Chris Craikb565df12015-10-05 13:00:52 -0700113
Chris Craik8d2cf942015-11-02 14:52:21 -0800114 OffscreenBuffer* buffer = createOffscreenBuffer(mRenderState, width, height);
Chris Craik0b7e8242015-10-28 16:50:44 -0700115 startLayer(buffer);
116 return buffer;
117}
118
119void BakedOpRenderer::startLayer(OffscreenBuffer* offscreenBuffer) {
120 mRenderTarget.offscreenBuffer = offscreenBuffer;
Chris Craik818c9fb2015-10-23 14:33:42 -0700121
Chris Craik5854b342015-10-26 15:49:56 -0700122 // create and bind framebuffer
123 mRenderTarget.frameBufferId = mRenderState.genFramebuffer();
124 mRenderState.bindFramebuffer(mRenderTarget.frameBufferId);
Chris Craik818c9fb2015-10-23 14:33:42 -0700125
126 // attach the texture to the FBO
127 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
Chris Craik0b7e8242015-10-28 16:50:44 -0700128 offscreenBuffer->texture.id, 0);
Chris Craik818c9fb2015-10-23 14:33:42 -0700129 LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "startLayer FAILED");
130 LOG_ALWAYS_FATAL_IF(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE,
131 "framebuffer incomplete!");
132
133 // Clear the FBO
Chris Craik5854b342015-10-26 15:49:56 -0700134 mRenderState.scissor().setEnabled(false);
Chris Craik818c9fb2015-10-23 14:33:42 -0700135 glClear(GL_COLOR_BUFFER_BIT);
136
137 // Change the viewport & ortho projection
Chris Craik0b7e8242015-10-28 16:50:44 -0700138 setViewport(offscreenBuffer->viewportWidth, offscreenBuffer->viewportHeight);
Chris Craik818c9fb2015-10-23 14:33:42 -0700139}
140
Chris Craik5854b342015-10-26 15:49:56 -0700141void BakedOpRenderer::endLayer() {
Chris Craik8d2cf942015-11-02 14:52:21 -0800142 mRenderTarget.offscreenBuffer->updateMeshFromRegion();
Chris Craik5854b342015-10-26 15:49:56 -0700143 mRenderTarget.offscreenBuffer = nullptr;
Chris Craik818c9fb2015-10-23 14:33:42 -0700144
145 // Detach the texture from the FBO
146 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
147 LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED");
Chris Craik5854b342015-10-26 15:49:56 -0700148 mRenderState.deleteFramebuffer(mRenderTarget.frameBufferId);
149 mRenderTarget.frameBufferId = -1;
Chris Craik818c9fb2015-10-23 14:33:42 -0700150}
151
Chris Craik5854b342015-10-26 15:49:56 -0700152void BakedOpRenderer::startFrame(uint32_t width, uint32_t height) {
153 mRenderState.bindFramebuffer(0);
154 setViewport(width, height);
155 mCaches.clearGarbage();
Chris Craikb565df12015-10-05 13:00:52 -0700156
Chris Craik5854b342015-10-26 15:49:56 -0700157 if (!mOpaque) {
Chris Craikb565df12015-10-05 13:00:52 -0700158 // TODO: partial invalidate!
Chris Craik5854b342015-10-26 15:49:56 -0700159 mRenderState.scissor().setEnabled(false);
Chris Craikb565df12015-10-05 13:00:52 -0700160 glClear(GL_COLOR_BUFFER_BIT);
Chris Craik5854b342015-10-26 15:49:56 -0700161 mHasDrawn = true;
Chris Craikb565df12015-10-05 13:00:52 -0700162 }
163}
Chris Craik5854b342015-10-26 15:49:56 -0700164
165void BakedOpRenderer::endFrame() {
166 mCaches.pathCache.trim();
167 mCaches.tessellationCache.trim();
Chris Craikb565df12015-10-05 13:00:52 -0700168
169#if DEBUG_OPENGL
170 GLUtils::dumpGLErrors();
171#endif
172
173#if DEBUG_MEMORY_USAGE
Chris Craik5854b342015-10-26 15:49:56 -0700174 mCaches.dumpMemoryUsage();
Chris Craikb565df12015-10-05 13:00:52 -0700175#else
176 if (Properties::debugLevel & kDebugMemory) {
Chris Craik5854b342015-10-26 15:49:56 -0700177 mCaches.dumpMemoryUsage();
Chris Craikb565df12015-10-05 13:00:52 -0700178 }
179#endif
180}
181
Chris Craik5854b342015-10-26 15:49:56 -0700182void BakedOpRenderer::setViewport(uint32_t width, uint32_t height) {
183 mRenderTarget.viewportWidth = width;
184 mRenderTarget.viewportHeight = height;
185 mRenderTarget.orthoMatrix.loadOrtho(width, height);
186
187 mRenderState.setViewport(width, height);
188 mRenderState.blend().syncEnabled();
189}
190
191Texture* BakedOpRenderer::getTexture(const SkBitmap* bitmap) {
192 Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
193 if (!texture) {
194 return mCaches.textureCache.get(bitmap);
195 }
196 return texture;
197}
198
199void BakedOpRenderer::renderGlop(const BakedOpState& state, const Glop& glop) {
200 bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None;
201 mRenderState.scissor().setEnabled(useScissor);
202 if (useScissor) {
203 const Rect& clip = state.computedState.clipRect;
204 mRenderState.scissor().set(clip.left, mRenderTarget.viewportHeight - clip.bottom,
205 clip.getWidth(), clip.getHeight());
206 }
Chris Craik8d2cf942015-11-02 14:52:21 -0800207 if (mRenderTarget.offscreenBuffer) { // TODO: not with multi-draw
208 // register layer damage to draw-back region
209 const Rect& uiDirty = state.computedState.clippedBounds;
210 android::Rect dirty(uiDirty.left, uiDirty.top, uiDirty.right, uiDirty.bottom);
211 mRenderTarget.offscreenBuffer->region.orSelf(dirty);
212 }
Chris Craik5854b342015-10-26 15:49:56 -0700213 mRenderState.render(glop, mRenderTarget.orthoMatrix);
214 mHasDrawn = true;
215}
216
217////////////////////////////////////////////////////////////////////////////////
218// static BakedOpDispatcher methods
219////////////////////////////////////////////////////////////////////////////////
220
221void BakedOpDispatcher::onRenderNodeOp(BakedOpRenderer&, const RenderNodeOp&, const BakedOpState&) {
Chris Craikb565df12015-10-05 13:00:52 -0700222 LOG_ALWAYS_FATAL("unsupported operation");
223}
224
Chris Craik8d2cf942015-11-02 14:52:21 -0800225void BakedOpDispatcher::onBeginLayerOp(BakedOpRenderer& renderer, const BeginLayerOp& op, const BakedOpState& state) {
226 LOG_ALWAYS_FATAL("unsupported operation");
227}
228
229void BakedOpDispatcher::onEndLayerOp(BakedOpRenderer& renderer, const EndLayerOp& op, const BakedOpState& state) {
230 LOG_ALWAYS_FATAL("unsupported operation");
231}
232
Chris Craik5854b342015-10-26 15:49:56 -0700233void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op, const BakedOpState& state) {
234 renderer.caches().textureState().activateTexture(0); // TODO: should this be automatic, and/or elsewhere?
235 Texture* texture = renderer.getTexture(op.bitmap);
Chris Craikb565df12015-10-05 13:00:52 -0700236 if (!texture) return;
237 const AutoTexture autoCleanup(texture);
238
239 const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType)
240 ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
241 Glop glop;
Chris Craik5854b342015-10-26 15:49:56 -0700242 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
Chris Craikb565df12015-10-05 13:00:52 -0700243 .setRoundRectClipState(state.roundRectClipState)
244 .setMeshTexturedUnitQuad(texture->uvMapper)
245 .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
246 .setTransform(state.computedState.transform, TransformFlags::None)
247 .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
248 .build();
Chris Craik5854b342015-10-26 15:49:56 -0700249 renderer.renderGlop(state, glop);
Chris Craikb565df12015-10-05 13:00:52 -0700250}
251
Chris Craik5854b342015-10-26 15:49:56 -0700252void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, const BakedOpState& state) {
Chris Craikb565df12015-10-05 13:00:52 -0700253 Glop glop;
Chris Craik5854b342015-10-26 15:49:56 -0700254 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
Chris Craikb565df12015-10-05 13:00:52 -0700255 .setRoundRectClipState(state.roundRectClipState)
256 .setMeshUnitQuad()
257 .setFillPaint(*op.paint, state.alpha)
258 .setTransform(state.computedState.transform, TransformFlags::None)
259 .setModelViewMapUnitToRect(op.unmappedBounds)
260 .build();
Chris Craik5854b342015-10-26 15:49:56 -0700261 renderer.renderGlop(state, glop);
Chris Craikb565df12015-10-05 13:00:52 -0700262}
263
Chris Craik5854b342015-10-26 15:49:56 -0700264void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op, const BakedOpState& state) {
Chris Craikb565df12015-10-05 13:00:52 -0700265 Glop glop;
Chris Craik5854b342015-10-26 15:49:56 -0700266 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
Chris Craikb565df12015-10-05 13:00:52 -0700267 .setRoundRectClipState(state.roundRectClipState)
268 .setMeshIndexedQuads(&op.vertices[0], op.vertexCount / 4)
269 .setFillPaint(*op.paint, state.alpha)
270 .setTransform(state.computedState.transform, TransformFlags::None)
271 .setModelViewOffsetRect(0, 0, op.unmappedBounds)
272 .build();
Chris Craik5854b342015-10-26 15:49:56 -0700273 renderer.renderGlop(state, glop);
Chris Craikb565df12015-10-05 13:00:52 -0700274}
275
Chris Craik5854b342015-10-26 15:49:56 -0700276void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) {
277 OffscreenBuffer* buffer = *op.layerHandle;
Chris Craik818c9fb2015-10-23 14:33:42 -0700278
Chris Craik5854b342015-10-26 15:49:56 -0700279 // TODO: extend this to handle HW layers & paint properties which
280 // reside in node.properties().layerProperties()
Chris Craik0b7e8242015-10-28 16:50:44 -0700281 float layerAlpha = op.alpha * state.alpha;
Chris Craik818c9fb2015-10-23 14:33:42 -0700282 Glop glop;
Chris Craik5854b342015-10-26 15:49:56 -0700283 GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
Chris Craik818c9fb2015-10-23 14:33:42 -0700284 .setRoundRectClipState(state.roundRectClipState)
Chris Craik8d2cf942015-11-02 14:52:21 -0800285 .setMeshTexturedIndexedVbo(buffer->vbo, buffer->elementCount)
Chris Craik0b7e8242015-10-28 16:50:44 -0700286 .setFillLayer(buffer->texture, op.colorFilter, layerAlpha, op.mode, Blend::ModeOrderSwap::NoSwap)
Chris Craik818c9fb2015-10-23 14:33:42 -0700287 .setTransform(state.computedState.transform, TransformFlags::None)
Chris Craik8d2cf942015-11-02 14:52:21 -0800288 .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top,
289 Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight()))
Chris Craik818c9fb2015-10-23 14:33:42 -0700290 .build();
Chris Craik5854b342015-10-26 15:49:56 -0700291 renderer.renderGlop(state, glop);
Chris Craik818c9fb2015-10-23 14:33:42 -0700292
Chris Craik0b7e8242015-10-28 16:50:44 -0700293 if (op.destroy) {
294 BakedOpRenderer::destroyOffscreenBuffer(buffer);
295 }
Chris Craik6fe991e52015-10-20 09:39:42 -0700296}
Chris Craikb565df12015-10-05 13:00:52 -0700297
298} // namespace uirenderer
299} // namespace android