BakedOpRenderer.cpp revision 9e7fcfda28fde747ba4e026772007cea77374e16
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
27#include <algorithm>
28
29namespace android {
30namespace uirenderer {
31
32OffscreenBuffer* BakedOpRenderer::startTemporaryLayer(uint32_t width, uint32_t height) {
33    LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");
34
35    OffscreenBuffer* buffer = mRenderState.layerPool().get(mRenderState, width, height);
36    startRepaintLayer(buffer, Rect(width, height));
37    return buffer;
38}
39
40void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) {
41    LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");
42
43    mRenderTarget.offscreenBuffer = offscreenBuffer;
44
45    // create and bind framebuffer
46    mRenderTarget.frameBufferId = mRenderState.genFramebuffer();
47    mRenderState.bindFramebuffer(mRenderTarget.frameBufferId);
48
49    // attach the texture to the FBO
50    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
51            offscreenBuffer->texture.id, 0);
52    LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "startLayer FAILED");
53    LOG_ALWAYS_FATAL_IF(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE,
54            "framebuffer incomplete!");
55
56    // Change the viewport & ortho projection
57    setViewport(offscreenBuffer->viewportWidth, offscreenBuffer->viewportHeight);
58
59    clearColorBuffer(repaintRect);
60}
61
62void BakedOpRenderer::endLayer() {
63    mRenderTarget.offscreenBuffer->updateMeshFromRegion();
64    mRenderTarget.offscreenBuffer = nullptr;
65
66    // Detach the texture from the FBO
67    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
68    LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED");
69    mRenderState.deleteFramebuffer(mRenderTarget.frameBufferId);
70    mRenderTarget.frameBufferId = -1;
71}
72
73void BakedOpRenderer::startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {
74    mRenderState.bindFramebuffer(0);
75    setViewport(width, height);
76    mCaches.clearGarbage();
77
78    if (!mOpaque) {
79        clearColorBuffer(repaintRect);
80    }
81}
82
83void BakedOpRenderer::endFrame() {
84    mCaches.pathCache.trim();
85    mCaches.tessellationCache.trim();
86
87#if DEBUG_OPENGL
88    GLUtils::dumpGLErrors();
89#endif
90
91#if DEBUG_MEMORY_USAGE
92    mCaches.dumpMemoryUsage();
93#else
94    if (Properties::debugLevel & kDebugMemory) {
95        mCaches.dumpMemoryUsage();
96    }
97#endif
98}
99
100void BakedOpRenderer::setViewport(uint32_t width, uint32_t height) {
101    mRenderTarget.viewportWidth = width;
102    mRenderTarget.viewportHeight = height;
103    mRenderTarget.orthoMatrix.loadOrtho(width, height);
104
105    mRenderState.setViewport(width, height);
106    mRenderState.blend().syncEnabled();
107}
108
109void BakedOpRenderer::clearColorBuffer(const Rect& rect) {
110    if (Rect(mRenderTarget.viewportWidth, mRenderTarget.viewportHeight).contains(rect)) {
111        // Full viewport is being cleared - disable scissor
112        mRenderState.scissor().setEnabled(false);
113    } else {
114        // Requested rect is subset of viewport - scissor to it to avoid over-clearing
115        mRenderState.scissor().setEnabled(true);
116        mRenderState.scissor().set(rect.left, mRenderTarget.viewportHeight - rect.bottom,
117                rect.getWidth(), rect.getHeight());
118    }
119    glClear(GL_COLOR_BUFFER_BIT);
120    if (!mRenderTarget.frameBufferId) mHasDrawn = true;
121}
122
123Texture* BakedOpRenderer::getTexture(const SkBitmap* bitmap) {
124    Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
125    if (!texture) {
126        return mCaches.textureCache.get(bitmap);
127    }
128    return texture;
129}
130
131void BakedOpRenderer::renderGlop(const BakedOpState& state, const Glop& glop) {
132    bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None;
133    mRenderState.scissor().setEnabled(useScissor);
134    if (useScissor) {
135        const Rect& clip = state.computedState.clipRect;
136        mRenderState.scissor().set(clip.left, mRenderTarget.viewportHeight - clip.bottom,
137            clip.getWidth(), clip.getHeight());
138    }
139    if (mRenderTarget.offscreenBuffer) { // TODO: not with multi-draw
140        // register layer damage to draw-back region
141        const Rect& uiDirty = state.computedState.clippedBounds;
142        android::Rect dirty(uiDirty.left, uiDirty.top, uiDirty.right, uiDirty.bottom);
143        mRenderTarget.offscreenBuffer->region.orSelf(dirty);
144    }
145    mRenderState.render(glop, mRenderTarget.orthoMatrix);
146    if (!mRenderTarget.frameBufferId) mHasDrawn = true;
147}
148
149} // namespace uirenderer
150} // namespace android
151