Layer.cpp revision be1b127c7bec252e0c6ab0e06ed6babed07d496f
1/*
2 * Copyright (C) 2012 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#define LOG_TAG "OpenGLRenderer"
18
19#include <utils/Log.h>
20
21#include "DisplayList.h"
22#include "DeferredDisplayList.h"
23#include "Layer.h"
24#include "LayerRenderer.h"
25#include "OpenGLRenderer.h"
26#include "Caches.h"
27
28namespace android {
29namespace uirenderer {
30
31Layer::Layer(const uint32_t layerWidth, const uint32_t layerHeight):
32        caches(Caches::getInstance()), texture(caches) {
33    mesh = NULL;
34    meshIndices = NULL;
35    meshElementCount = 0;
36    cacheable = true;
37    dirty = false;
38    textureLayer = false;
39    renderTarget = GL_TEXTURE_2D;
40    texture.width = layerWidth;
41    texture.height = layerHeight;
42    colorFilter = NULL;
43    deferredUpdateScheduled = false;
44    renderer = NULL;
45    displayList = NULL;
46    fbo = 0;
47    stencil = NULL;
48    debugDrawUpdate = false;
49    hasDrawnSinceUpdate = false;
50    deferredList = NULL;
51    caches.resourceCache.incrementRefcount(this);
52}
53
54Layer::~Layer() {
55    if (colorFilter) caches.resourceCache.decrementRefcount(colorFilter);
56    removeFbo();
57    deleteTexture();
58
59    delete[] mesh;
60    delete[] meshIndices;
61    delete deferredList;
62}
63
64uint32_t Layer::computeIdealWidth(uint32_t layerWidth) {
65    return uint32_t(ceilf(layerWidth / float(LAYER_SIZE)) * LAYER_SIZE);
66}
67
68uint32_t Layer::computeIdealHeight(uint32_t layerHeight) {
69    return uint32_t(ceilf(layerHeight / float(LAYER_SIZE)) * LAYER_SIZE);
70}
71
72bool Layer::resize(const uint32_t width, const uint32_t height) {
73    uint32_t desiredWidth = computeIdealWidth(width);
74    uint32_t desiredHeight = computeIdealWidth(height);
75
76    if (desiredWidth <= getWidth() && desiredHeight <= getHeight()) {
77        return true;
78    }
79
80    const uint32_t maxTextureSize = caches.maxTextureSize;
81    if (desiredWidth > maxTextureSize || desiredHeight > maxTextureSize) {
82        ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)",
83                desiredWidth, desiredHeight, maxTextureSize, maxTextureSize);
84        return false;
85    }
86
87    uint32_t oldWidth = getWidth();
88    uint32_t oldHeight = getHeight();
89
90    setSize(desiredWidth, desiredHeight);
91
92    if (fbo) {
93        caches.activeTexture(0);
94        bindTexture();
95        allocateTexture();
96
97        if (glGetError() != GL_NO_ERROR) {
98            setSize(oldWidth, oldHeight);
99            return false;
100        }
101    }
102
103    if (stencil) {
104        stencil->bind();
105        stencil->resize(desiredWidth, desiredHeight);
106
107        if (glGetError() != GL_NO_ERROR) {
108            setSize(oldWidth, oldHeight);
109            return false;
110        }
111    }
112
113    return true;
114}
115
116void Layer::removeFbo(bool flush) {
117    if (stencil) {
118        GLuint previousFbo;
119        glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
120        if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, fbo);
121        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
122        if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
123
124        caches.renderBufferCache.put(stencil);
125        stencil = NULL;
126    }
127
128    if (fbo) {
129        if (flush) LayerRenderer::flushLayer(this);
130        // If put fails the cache will delete the FBO
131        caches.fboCache.put(fbo);
132        fbo = 0;
133    }
134}
135
136void Layer::setPaint(SkPaint* paint) {
137    OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
138}
139
140void Layer::setColorFilter(SkiaColorFilter* filter) {
141    if (colorFilter) {
142        caches.resourceCache.decrementRefcount(colorFilter);
143    }
144    colorFilter = filter;
145    if (colorFilter) {
146        caches.resourceCache.incrementRefcount(colorFilter);
147    }
148}
149
150void Layer::bindTexture() const {
151    if (texture.id) {
152        caches.bindTexture(renderTarget, texture.id);
153    }
154}
155
156void Layer::bindStencilRenderBuffer() const {
157    if (stencil) {
158        stencil->bind();
159    }
160}
161
162void Layer::generateTexture() {
163    if (!texture.id) {
164        glGenTextures(1, &texture.id);
165    }
166}
167
168void Layer::deleteTexture() {
169    if (texture.id) {
170        texture.deleteTexture();
171        texture.id = 0;
172    }
173}
174
175void Layer::clearTexture() {
176    texture.id = 0;
177}
178
179void Layer::allocateTexture() {
180#if DEBUG_LAYERS
181    ALOGD("  Allocate layer: %dx%d", getWidth(), getHeight());
182#endif
183    if (texture.id) {
184        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
185        glTexImage2D(renderTarget, 0, GL_RGBA, getWidth(), getHeight(), 0,
186                GL_RGBA, GL_UNSIGNED_BYTE, NULL);
187    }
188}
189
190void Layer::defer() {
191    if (!deferredList) {
192        deferredList = new DeferredDisplayList;
193    }
194    DeferStateStruct deferredState(*deferredList, *renderer,
195            DisplayList::kReplayFlag_ClipChildren);
196
197    const float width = layer.getWidth();
198    const float height = layer.getHeight();
199
200    if (dirtyRect.isEmpty() || (dirtyRect.left <= 0 && dirtyRect.top <= 0 &&
201            dirtyRect.right >= width && dirtyRect.bottom >= height)) {
202        dirtyRect.set(0, 0, width, height);
203    }
204
205    renderer->initViewport(width, height);
206    renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
207            dirtyRect.right, dirtyRect.bottom, !isBlend());
208
209    displayList->defer(deferredState, 0);
210
211    deferredUpdateScheduled = false;
212}
213
214void Layer::flush() {
215    if (deferredList) {
216        renderer->setViewport(layer.getWidth(), layer.getHeight());
217        renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
218                !isBlend());
219
220        deferredList->flush(*renderer, dirtyRect);
221
222        renderer->finish();
223        renderer = NULL;
224
225        dirtyRect.setEmpty();
226        displayList = NULL;
227    }
228}
229
230void Layer::render() {
231    renderer->setViewport(layer.getWidth(), layer.getHeight());
232    renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
233            !isBlend());
234
235    renderer->drawDisplayList(displayList, dirtyRect, DisplayList::kReplayFlag_ClipChildren);
236
237    renderer->finish();
238    renderer = NULL;
239
240    dirtyRect.setEmpty();
241
242    deferredUpdateScheduled = false;
243    displayList = NULL;
244}
245
246}; // namespace uirenderer
247}; // namespace android
248