BakedOpRenderer.cpp revision d3daa3198e2212c985c634821682d5819346b653
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 "VertexBuffer.h" 23#include "renderstate/RenderState.h" 24#include "utils/FatVector.h" 25#include "utils/GLUtils.h" 26 27namespace android { 28namespace uirenderer { 29 30//////////////////////////////////////////////////////////////////////////////// 31// OffscreenBuffer 32//////////////////////////////////////////////////////////////////////////////// 33 34OffscreenBuffer::OffscreenBuffer(RenderState& renderState, Caches& caches, 35 uint32_t textureWidth, uint32_t textureHeight, 36 uint32_t viewportWidth, uint32_t viewportHeight) 37 : renderState(renderState) 38 , viewportWidth(viewportWidth) 39 , viewportHeight(viewportHeight) 40 , texture(caches) { 41 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); 49 // not setting filter on texture, since it's set when rendering, based on transform 50 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); 54} 55 56void OffscreenBuffer::updateMeshFromRegion() { 57 // avoid T-junctions as they cause artifacts in between the resultant 58 // geometry when complex transforms occur. 59 // TODO: generate the safeRegion only if necessary based on rendering transform 60 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 97//////////////////////////////////////////////////////////////////////////////// 98// BakedOpRenderer 99//////////////////////////////////////////////////////////////////////////////// 100 101OffscreenBuffer* BakedOpRenderer::createOffscreenBuffer(RenderState& renderState, 102 uint32_t width, uint32_t height) { 103 // TODO: get from cache! 104 return new OffscreenBuffer(renderState, Caches::getInstance(), width, height, width, height); 105} 106 107void BakedOpRenderer::destroyOffscreenBuffer(OffscreenBuffer* offscreenBuffer) { 108 // TODO: return texture/offscreenbuffer to cache! 109 delete offscreenBuffer; 110} 111 112OffscreenBuffer* BakedOpRenderer::startTemporaryLayer(uint32_t width, uint32_t height) { 113 OffscreenBuffer* buffer = createOffscreenBuffer(mRenderState, width, height); 114 startRepaintLayer(buffer); 115 return buffer; 116} 117 118void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer) { 119 LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer..."); 120 121 mRenderTarget.offscreenBuffer = offscreenBuffer; 122 123 // create and bind framebuffer 124 mRenderTarget.frameBufferId = mRenderState.genFramebuffer(); 125 mRenderState.bindFramebuffer(mRenderTarget.frameBufferId); 126 127 // attach the texture to the FBO 128 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 129 offscreenBuffer->texture.id, 0); 130 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 135 mRenderState.scissor().setEnabled(false); 136 glClear(GL_COLOR_BUFFER_BIT); 137 138 // Change the viewport & ortho projection 139 setViewport(offscreenBuffer->viewportWidth, offscreenBuffer->viewportHeight); 140} 141 142void BakedOpRenderer::endLayer() { 143 mRenderTarget.offscreenBuffer->updateMeshFromRegion(); 144 mRenderTarget.offscreenBuffer = nullptr; 145 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"); 149 mRenderState.deleteFramebuffer(mRenderTarget.frameBufferId); 150 mRenderTarget.frameBufferId = -1; 151} 152 153void BakedOpRenderer::startFrame(uint32_t width, uint32_t height) { 154 mRenderState.bindFramebuffer(0); 155 setViewport(width, height); 156 mCaches.clearGarbage(); 157 158 if (!mOpaque) { 159 // TODO: partial invalidate! 160 mRenderState.scissor().setEnabled(false); 161 glClear(GL_COLOR_BUFFER_BIT); 162 mHasDrawn = true; 163 } 164} 165 166void BakedOpRenderer::endFrame() { 167 mCaches.pathCache.trim(); 168 mCaches.tessellationCache.trim(); 169 170#if DEBUG_OPENGL 171 GLUtils::dumpGLErrors(); 172#endif 173 174#if DEBUG_MEMORY_USAGE 175 mCaches.dumpMemoryUsage(); 176#else 177 if (Properties::debugLevel & kDebugMemory) { 178 mCaches.dumpMemoryUsage(); 179 } 180#endif 181} 182 183void 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 } 208 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 } 214 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&) { 223 LOG_ALWAYS_FATAL("unsupported operation"); 224} 225 226void 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 234void 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); 237 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; 243 GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 244 .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(); 250 renderer.renderGlop(state, glop); 251} 252 253void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, const BakedOpState& state) { 254 Glop glop; 255 GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 256 .setRoundRectClipState(state.roundRectClipState) 257 .setMeshUnitQuad() 258 .setFillPaint(*op.paint, state.alpha) 259 .setTransform(state.computedState.transform, TransformFlags::None) 260 .setModelViewMapUnitToRect(op.unmappedBounds) 261 .build(); 262 renderer.renderGlop(state, glop); 263} 264 265namespace 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 330void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op, const BakedOpState& state) { 331 Glop glop; 332 GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 333 .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(); 339 renderer.renderGlop(state, glop); 340} 341 342void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) { 343 OffscreenBuffer* buffer = *op.layerHandle; 344 345 // TODO: extend this to handle HW layers & paint properties which 346 // reside in node.properties().layerProperties() 347 float layerAlpha = op.alpha * state.alpha; 348 Glop glop; 349 GlopBuilder(renderer.renderState(), renderer.caches(), &glop) 350 .setRoundRectClipState(state.roundRectClipState) 351 .setMeshTexturedIndexedVbo(buffer->vbo, buffer->elementCount) 352 .setFillLayer(buffer->texture, op.colorFilter, layerAlpha, op.mode, Blend::ModeOrderSwap::NoSwap) 353 .setTransform(state.computedState.transform, TransformFlags::None) 354 .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top, 355 Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight())) 356 .build(); 357 renderer.renderGlop(state, glop); 358 359 if (op.destroy) { 360 BakedOpRenderer::destroyOffscreenBuffer(buffer); 361 } 362} 363 364} // namespace uirenderer 365} // namespace android 366