BakedOpRenderer.cpp revision 9fded232a9548a304e0145011df8849fba0dcda7
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); 39 return buffer; 40} 41 42void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer) { 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 // Clear the FBO 59 mRenderState.scissor().setEnabled(false); 60 glClear(GL_COLOR_BUFFER_BIT); 61 62 // Change the viewport & ortho projection 63 setViewport(offscreenBuffer->viewportWidth, offscreenBuffer->viewportHeight); 64} 65 66void BakedOpRenderer::endLayer() { 67 mRenderTarget.offscreenBuffer->updateMeshFromRegion(); 68 mRenderTarget.offscreenBuffer = nullptr; 69 70 // Detach the texture from the FBO 71 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); 72 LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED"); 73 mRenderState.deleteFramebuffer(mRenderTarget.frameBufferId); 74 mRenderTarget.frameBufferId = -1; 75} 76 77void BakedOpRenderer::startFrame(uint32_t width, uint32_t height) { 78 mRenderState.bindFramebuffer(0); 79 setViewport(width, height); 80 mCaches.clearGarbage(); 81 82 if (!mOpaque) { 83 // TODO: partial invalidate! 84 mRenderState.scissor().setEnabled(false); 85 glClear(GL_COLOR_BUFFER_BIT); 86 mHasDrawn = true; 87 } 88} 89 90void BakedOpRenderer::endFrame() { 91 mCaches.pathCache.trim(); 92 mCaches.tessellationCache.trim(); 93 94#if DEBUG_OPENGL 95 GLUtils::dumpGLErrors(); 96#endif 97 98#if DEBUG_MEMORY_USAGE 99 mCaches.dumpMemoryUsage(); 100#else 101 if (Properties::debugLevel & kDebugMemory) { 102 mCaches.dumpMemoryUsage(); 103 } 104#endif 105} 106 107void BakedOpRenderer::setViewport(uint32_t width, uint32_t height) { 108 mRenderTarget.viewportWidth = width; 109 mRenderTarget.viewportHeight = height; 110 mRenderTarget.orthoMatrix.loadOrtho(width, height); 111 112 mRenderState.setViewport(width, height); 113 mRenderState.blend().syncEnabled(); 114} 115 116Texture* BakedOpRenderer::getTexture(const SkBitmap* bitmap) { 117 Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap); 118 if (!texture) { 119 return mCaches.textureCache.get(bitmap); 120 } 121 return texture; 122} 123 124void BakedOpRenderer::renderGlop(const BakedOpState& state, const Glop& glop) { 125 bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None; 126 mRenderState.scissor().setEnabled(useScissor); 127 if (useScissor) { 128 const Rect& clip = state.computedState.clipRect; 129 mRenderState.scissor().set(clip.left, mRenderTarget.viewportHeight - clip.bottom, 130 clip.getWidth(), clip.getHeight()); 131 } 132 if (mRenderTarget.offscreenBuffer) { // TODO: not with multi-draw 133 // register layer damage to draw-back region 134 const Rect& uiDirty = state.computedState.clippedBounds; 135 android::Rect dirty(uiDirty.left, uiDirty.top, uiDirty.right, uiDirty.bottom); 136 mRenderTarget.offscreenBuffer->region.orSelf(dirty); 137 } 138 mRenderState.render(glop, mRenderTarget.orthoMatrix); 139 mHasDrawn = true; 140} 141 142//////////////////////////////////////////////////////////////////////////////// 143// static BakedOpDispatcher methods 144//////////////////////////////////////////////////////////////////////////////// 145 146void BakedOpDispatcher::onRenderNodeOp(BakedOpRenderer&, const RenderNodeOp&, const BakedOpState&) { 147 LOG_ALWAYS_FATAL("unsupported operation"); 148} 149 150void BakedOpDispatcher::onBeginLayerOp(BakedOpRenderer& renderer, const BeginLayerOp& op, const BakedOpState& state) { 151 LOG_ALWAYS_FATAL("unsupported operation"); 152} 153 154void BakedOpDispatcher::onEndLayerOp(BakedOpRenderer& renderer, const EndLayerOp& op, const BakedOpState& state) { 155 LOG_ALWAYS_FATAL("unsupported operation"); 156} 157 158void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op, const BakedOpState& state) { 159 renderer.caches().textureState().activateTexture(0); // TODO: should this be automatic, and/or elsewhere? 160 Texture* texture = renderer.getTexture(op.bitmap); 161 if (!texture) return; 162 const AutoTexture autoCleanup(texture); 163 164 const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType) 165 ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None; 166 Glop glop; 167 GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 168 .setRoundRectClipState(state.roundRectClipState) 169 .setMeshTexturedUnitQuad(texture->uvMapper) 170 .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha) 171 .setTransform(state.computedState.transform, TransformFlags::None) 172 .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height)) 173 .build(); 174 renderer.renderGlop(state, glop); 175} 176 177void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, const BakedOpState& state) { 178 Glop glop; 179 GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 180 .setRoundRectClipState(state.roundRectClipState) 181 .setMeshUnitQuad() 182 .setFillPaint(*op.paint, state.alpha) 183 .setTransform(state.computedState.transform, TransformFlags::None) 184 .setModelViewMapUnitToRect(op.unmappedBounds) 185 .build(); 186 renderer.renderGlop(state, glop); 187} 188 189namespace VertexBufferRenderFlags { 190 enum { 191 Offset = 0x1, 192 ShadowInterp = 0x2, 193 }; 194} 195 196static void renderVertexBuffer(BakedOpRenderer& renderer, const BakedOpState& state, 197 const VertexBuffer& vertexBuffer, float translateX, float translateY, 198 SkPaint& paint, int vertexBufferRenderFlags) { 199 if (CC_LIKELY(vertexBuffer.getVertexCount())) { 200 bool shadowInterp = vertexBufferRenderFlags & VertexBufferRenderFlags::ShadowInterp; 201 const int transformFlags = TransformFlags::OffsetByFudgeFactor; 202 Glop glop; 203 GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 204 .setRoundRectClipState(state.roundRectClipState) 205 .setMeshVertexBuffer(vertexBuffer, shadowInterp) 206 .setFillPaint(paint, state.alpha) 207 .setTransform(state.computedState.transform, transformFlags) 208 .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds()) 209 .build(); 210 renderer.renderGlop(state, glop); 211 } 212} 213 214static void renderShadow(BakedOpRenderer& renderer, const BakedOpState& state, float casterAlpha, 215 const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) { 216 SkPaint paint; 217 paint.setAntiAlias(true); // want to use AlphaVertex 218 219 // The caller has made sure casterAlpha > 0. 220 uint8_t ambientShadowAlpha = 128u; //TODO: mAmbientShadowAlpha; 221 if (CC_UNLIKELY(Properties::overrideAmbientShadowStrength >= 0)) { 222 ambientShadowAlpha = Properties::overrideAmbientShadowStrength; 223 } 224 if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) { 225 paint.setAlpha((uint8_t)(casterAlpha * ambientShadowAlpha)); 226 renderVertexBuffer(renderer, state, *ambientShadowVertexBuffer, 0, 0, 227 paint, VertexBufferRenderFlags::ShadowInterp); 228 } 229 230 uint8_t spotShadowAlpha = 128u; //TODO: mSpotShadowAlpha; 231 if (CC_UNLIKELY(Properties::overrideSpotShadowStrength >= 0)) { 232 spotShadowAlpha = Properties::overrideSpotShadowStrength; 233 } 234 if (spotShadowVertexBuffer && spotShadowAlpha > 0) { 235 paint.setAlpha((uint8_t)(casterAlpha * spotShadowAlpha)); 236 renderVertexBuffer(renderer, state, *spotShadowVertexBuffer, 0, 0, 237 paint, VertexBufferRenderFlags::ShadowInterp); 238 } 239} 240 241void BakedOpDispatcher::onShadowOp(BakedOpRenderer& renderer, const ShadowOp& op, const BakedOpState& state) { 242 TessellationCache::vertexBuffer_pair_t buffers; 243 Vector3 lightCenter = { 300, 300, 300 }; // TODO! 244 float lightRadius = 150; // TODO! 245 246 renderer.caches().tessellationCache.getShadowBuffers(&state.computedState.transform, 247 op.localClipRect, op.casterAlpha >= 1.0f, op.casterPath, 248 &op.shadowMatrixXY, &op.shadowMatrixZ, lightCenter, lightRadius, 249 buffers); 250 251 renderShadow(renderer, state, op.casterAlpha, buffers.first, buffers.second); 252} 253 254void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op, const BakedOpState& state) { 255 Glop glop; 256 GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 257 .setRoundRectClipState(state.roundRectClipState) 258 .setMeshIndexedQuads(&op.vertices[0], op.vertexCount / 4) 259 .setFillPaint(*op.paint, state.alpha) 260 .setTransform(state.computedState.transform, TransformFlags::None) 261 .setModelViewOffsetRect(0, 0, op.unmappedBounds) 262 .build(); 263 renderer.renderGlop(state, glop); 264} 265 266void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) { 267 OffscreenBuffer* buffer = *op.layerHandle; 268 269 // TODO: extend this to handle HW layers & paint properties which 270 // reside in node.properties().layerProperties() 271 float layerAlpha = op.alpha * state.alpha; 272 Glop glop; 273 GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 274 .setRoundRectClipState(state.roundRectClipState) 275 .setMeshTexturedIndexedVbo(buffer->vbo, buffer->elementCount) 276 .setFillLayer(buffer->texture, op.colorFilter, layerAlpha, op.mode, Blend::ModeOrderSwap::NoSwap) 277 .setTransform(state.computedState.transform, TransformFlags::None) 278 .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top, 279 Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight())) 280 .build(); 281 renderer.renderGlop(state, glop); 282 283 if (op.destroy) { 284 renderer.renderState().layerPool().putOrDelete(buffer); 285 } 286} 287 288} // namespace uirenderer 289} // namespace android 290