BakedOpRenderer.cpp revision 98787e6c9b2c10b1ab7820bdac168686025b924a
1/* 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/OffscreenBufferPool.h" 23#include "renderstate/RenderState.h" 24#include "utils/GLUtils.h" 25#include "VertexBuffer.h" 26 27namespace android { 28namespace uirenderer { 29 30//////////////////////////////////////////////////////////////////////////////// 31// BakedOpRenderer 32//////////////////////////////////////////////////////////////////////////////// 33 34OffscreenBuffer* BakedOpRenderer::startTemporaryLayer(uint32_t width, uint32_t height) { 35 LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer..."); 36 37 OffscreenBuffer* buffer = mRenderState.layerPool().get(mRenderState, width, height); 38 startRepaintLayer(buffer, Rect(width, height)); 39 return buffer; 40} 41 42void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) { 43 LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer..."); 44 45 mRenderTarget.offscreenBuffer = offscreenBuffer; 46 47 // create and bind framebuffer 48 mRenderTarget.frameBufferId = mRenderState.genFramebuffer(); 49 mRenderState.bindFramebuffer(mRenderTarget.frameBufferId); 50 51 // attach the texture to the FBO 52 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 53 offscreenBuffer->texture.id, 0); 54 LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "startLayer FAILED"); 55 LOG_ALWAYS_FATAL_IF(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE, 56 "framebuffer incomplete!"); 57 58 // Change the viewport & ortho projection 59 setViewport(offscreenBuffer->viewportWidth, offscreenBuffer->viewportHeight); 60 61 clearColorBuffer(repaintRect); 62} 63 64void BakedOpRenderer::endLayer() { 65 mRenderTarget.offscreenBuffer->updateMeshFromRegion(); 66 mRenderTarget.offscreenBuffer = nullptr; 67 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"); 71 mRenderState.deleteFramebuffer(mRenderTarget.frameBufferId); 72 mRenderTarget.frameBufferId = -1; 73} 74 75void BakedOpRenderer::startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) { 76 mRenderState.bindFramebuffer(0); 77 setViewport(width, height); 78 mCaches.clearGarbage(); 79 80 if (!mOpaque) { 81 clearColorBuffer(repaintRect); 82 } 83} 84 85void BakedOpRenderer::endFrame() { 86 mCaches.pathCache.trim(); 87 mCaches.tessellationCache.trim(); 88 89#if DEBUG_OPENGL 90 GLUtils::dumpGLErrors(); 91#endif 92 93#if DEBUG_MEMORY_USAGE 94 mCaches.dumpMemoryUsage(); 95#else 96 if (Properties::debugLevel & kDebugMemory) { 97 mCaches.dumpMemoryUsage(); 98 } 99#endif 100} 101 102void 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 111void 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 125Texture* 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 } 141 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 } 147 mRenderState.render(glop, mRenderTarget.orthoMatrix); 148 if (!mRenderTarget.frameBufferId) mHasDrawn = true; 149} 150 151//////////////////////////////////////////////////////////////////////////////// 152// static BakedOpDispatcher methods 153//////////////////////////////////////////////////////////////////////////////// 154 155void BakedOpDispatcher::onRenderNodeOp(BakedOpRenderer&, const RenderNodeOp&, const BakedOpState&) { 156 LOG_ALWAYS_FATAL("unsupported operation"); 157} 158 159void 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 167void 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); 170 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; 176 GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 177 .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(); 183 renderer.renderGlop(state, glop); 184} 185 186void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, const BakedOpState& state) { 187 Glop glop; 188 GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 189 .setRoundRectClipState(state.roundRectClipState) 190 .setMeshUnitQuad() 191 .setFillPaint(*op.paint, state.alpha) 192 .setTransform(state.computedState.transform, TransformFlags::None) 193 .setModelViewMapUnitToRect(op.unmappedBounds) 194 .build(); 195 renderer.renderGlop(state, glop); 196} 197 198namespace 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. 229 uint8_t ambientShadowAlpha = renderer.getLightInfo().ambientShadowAlpha; 230 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 239 uint8_t spotShadowAlpha = renderer.getLightInfo().spotShadowAlpha; 240 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; 252 renderer.caches().tessellationCache.getShadowBuffers(&state.computedState.transform, 253 op.localClipRect, op.casterAlpha >= 1.0f, op.casterPath, 254 &op.shadowMatrixXY, &op.shadowMatrixZ, 255 op.lightCenter, renderer.getLightInfo().lightRadius, 256 buffers); 257 258 renderShadow(renderer, state, op.casterAlpha, buffers.first, buffers.second); 259} 260 261void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op, const BakedOpState& state) { 262 Glop glop; 263 GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 264 .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(); 270 renderer.renderGlop(state, glop); 271} 272 273void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) { 274 OffscreenBuffer* buffer = *op.layerHandle; 275 276 // TODO: extend this to handle HW layers & paint properties which 277 // reside in node.properties().layerProperties() 278 float layerAlpha = op.alpha * state.alpha; 279 Glop glop; 280 GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 281 .setRoundRectClipState(state.roundRectClipState) 282 .setMeshTexturedIndexedVbo(buffer->vbo, buffer->elementCount) 283 .setFillLayer(buffer->texture, op.colorFilter, layerAlpha, op.mode, Blend::ModeOrderSwap::NoSwap) 284 .setTransform(state.computedState.transform, TransformFlags::None) 285 .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top, 286 Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight())) 287 .build(); 288 renderer.renderGlop(state, glop); 289 290 if (op.destroy) { 291 renderer.renderState().layerPool().putOrDelete(buffer); 292 } 293} 294 295} // namespace uirenderer 296} // namespace android 297