BakedOpRenderer.cpp revision 818c9fbf1d76d5df19253ba4eb964efa939ec9ec
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/RenderState.h" 23#include "utils/GLUtils.h" 24 25namespace android { 26namespace uirenderer { 27 28void BakedOpRenderer::Info::setViewport(uint32_t width, uint32_t height) { 29 viewportWidth = width; 30 viewportHeight = height; 31 orthoMatrix.loadOrtho(viewportWidth, viewportHeight); 32 33 renderState.setViewport(width, height); 34 renderState.blend().syncEnabled(); 35} 36 37Texture* BakedOpRenderer::Info::getTexture(const SkBitmap* bitmap) { 38 Texture* texture = renderState.assetAtlas().getEntryTexture(bitmap); 39 if (!texture) { 40 return caches.textureCache.get(bitmap); 41 } 42 return texture; 43} 44 45void BakedOpRenderer::Info::renderGlop(const BakedOpState& state, const Glop& glop) { 46 bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None; 47 renderState.scissor().setEnabled(useScissor); 48 if (useScissor) { 49 const Rect& clip = state.computedState.clipRect; 50 renderState.scissor().set(clip.left, viewportHeight - clip.bottom, 51 clip.getWidth(), clip.getHeight()); 52 } 53 renderState.render(glop, orthoMatrix); 54 didDraw = true; 55} 56 57Layer* BakedOpRenderer::startLayer(Info& info, uint32_t width, uint32_t height) { 58 info.caches.textureState().activateTexture(0); 59 Layer* layer = info.caches.layerCache.get(info.renderState, width, height); 60 LOG_ALWAYS_FATAL_IF(!layer, "need layer..."); 61 62 info.layer = layer; 63 layer->texCoords.set(0.0f, width / float(layer->getHeight()), 64 height / float(layer->getWidth()), 0.0f); 65 66 layer->setFbo(info.renderState.genFramebuffer()); 67 info.renderState.bindFramebuffer(layer->getFbo()); 68 layer->bindTexture(); 69 70 // Initialize the texture if needed 71 if (layer->isEmpty()) { 72 layer->allocateTexture(); 73 layer->setEmpty(false); 74 } 75 76 // attach the texture to the FBO 77 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 78 layer->getTextureId(), 0); 79 LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "startLayer FAILED"); 80 LOG_ALWAYS_FATAL_IF(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE, 81 "framebuffer incomplete!"); 82 83 // Clear the FBO 84 info.renderState.scissor().setEnabled(false); 85 glClear(GL_COLOR_BUFFER_BIT); 86 87 // Change the viewport & ortho projection 88 info.setViewport(width, height); 89 return layer; 90} 91 92void BakedOpRenderer::endLayer(Info& info) { 93 Layer* layer = info.layer; 94 info.layer = nullptr; 95 96 // Detach the texture from the FBO 97 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); 98 LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED"); 99 layer->removeFbo(false); 100} 101 102void BakedOpRenderer::startFrame(Info& info, uint32_t width, uint32_t height) { 103 info.renderState.bindFramebuffer(0); 104 info.setViewport(width, height); 105 Caches::getInstance().clearGarbage(); 106 107 if (!info.opaque) { 108 // TODO: partial invalidate! 109 info.renderState.scissor().setEnabled(false); 110 glClear(GL_COLOR_BUFFER_BIT); 111 info.didDraw = true; 112 } 113} 114void BakedOpRenderer::endFrame(Info& info) { 115 info.caches.pathCache.trim(); 116 info.caches.tessellationCache.trim(); 117 118#if DEBUG_OPENGL 119 GLUtils::dumpGLErrors(); 120#endif 121 122#if DEBUG_MEMORY_USAGE 123 info.caches.dumpMemoryUsage(); 124#else 125 if (Properties::debugLevel & kDebugMemory) { 126 info.caches.dumpMemoryUsage(); 127 } 128#endif 129} 130 131void BakedOpRenderer::onRenderNodeOp(Info&, const RenderNodeOp&, const BakedOpState&) { 132 LOG_ALWAYS_FATAL("unsupported operation"); 133} 134 135void BakedOpRenderer::onBitmapOp(Info& info, const BitmapOp& op, const BakedOpState& state) { 136 info.caches.textureState().activateTexture(0); // TODO: should this be automatic, and/or elsewhere? 137 Texture* texture = info.getTexture(op.bitmap); 138 if (!texture) return; 139 const AutoTexture autoCleanup(texture); 140 141 const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType) 142 ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None; 143 Glop glop; 144 GlopBuilder(info.renderState, info.caches, &glop) 145 .setRoundRectClipState(state.roundRectClipState) 146 .setMeshTexturedUnitQuad(texture->uvMapper) 147 .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha) 148 .setTransform(state.computedState.transform, TransformFlags::None) 149 .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height)) 150 .build(); 151 info.renderGlop(state, glop); 152} 153 154void BakedOpRenderer::onRectOp(Info& info, const RectOp& op, const BakedOpState& state) { 155 Glop glop; 156 GlopBuilder(info.renderState, info.caches, &glop) 157 .setRoundRectClipState(state.roundRectClipState) 158 .setMeshUnitQuad() 159 .setFillPaint(*op.paint, state.alpha) 160 .setTransform(state.computedState.transform, TransformFlags::None) 161 .setModelViewMapUnitToRect(op.unmappedBounds) 162 .build(); 163 info.renderGlop(state, glop); 164} 165 166void BakedOpRenderer::onSimpleRectsOp(Info& info, const SimpleRectsOp& op, const BakedOpState& state) { 167 Glop glop; 168 GlopBuilder(info.renderState, info.caches, &glop) 169 .setRoundRectClipState(state.roundRectClipState) 170 .setMeshIndexedQuads(&op.vertices[0], op.vertexCount / 4) 171 .setFillPaint(*op.paint, state.alpha) 172 .setTransform(state.computedState.transform, TransformFlags::None) 173 .setModelViewOffsetRect(0, 0, op.unmappedBounds) 174 .build(); 175 info.renderGlop(state, glop); 176} 177 178void BakedOpRenderer::onBeginLayerOp(Info& info, const BeginLayerOp& op, const BakedOpState& state) { 179 LOG_ALWAYS_FATAL("unsupported operation"); 180} 181 182void BakedOpRenderer::onEndLayerOp(Info& info, const EndLayerOp& op, const BakedOpState& state) { 183 LOG_ALWAYS_FATAL("unsupported operation"); 184} 185 186void BakedOpRenderer::onLayerOp(Info& info, const LayerOp& op, const BakedOpState& state) { 187 Layer* layer = *op.layerHandle; 188 189 // TODO: make this work for HW layers 190 layer->setPaint(op.paint); 191 layer->setBlend(true); 192 float layerAlpha = (layer->getAlpha() / 255.0f) * state.alpha; 193 194 const bool tryToSnap = state.computedState.transform.isPureTranslate(); 195 Glop glop; 196 GlopBuilder(info.renderState, info.caches, &glop) 197 .setRoundRectClipState(state.roundRectClipState) 198 .setMeshTexturedUvQuad(nullptr, layer->texCoords) 199 .setFillLayer(layer->getTexture(), layer->getColorFilter(), layerAlpha, layer->getMode(), Blend::ModeOrderSwap::NoSwap) 200 .setTransform(state.computedState.transform, TransformFlags::None) 201 .setModelViewMapUnitToRectOptionalSnap(tryToSnap, op.unmappedBounds) 202 .build(); 203 info.renderGlop(state, glop); 204 205 // return layer to cache, since each clipped savelayer is only drawn once. 206 layer->setConvexMask(nullptr); 207 if (!info.caches.layerCache.put(layer)) { 208 // Failing to add the layer to the cache should happen only if the layer is too large 209 LAYER_LOGD("Deleting layer"); 210 layer->decStrong(nullptr); 211 } 212} 213 214} // namespace uirenderer 215} // namespace android 216