Layer.cpp revision 8c6e17c2a9b0ad7864a261cc9a30b9623e20bdcb
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    const float width = layer.getWidth();
192    const float height = layer.getHeight();
193
194    if (dirtyRect.isEmpty() || (dirtyRect.left <= 0 && dirtyRect.top <= 0 &&
195            dirtyRect.right >= width && dirtyRect.bottom >= height)) {
196        dirtyRect.set(0, 0, width, height);
197    }
198
199    if (deferredList) {
200        deferredList->reset(dirtyRect);
201    } else {
202        deferredList = new DeferredDisplayList(dirtyRect);
203    }
204    DeferStateStruct deferredState(*deferredList, *renderer,
205            DisplayList::kReplayFlag_ClipChildren);
206
207    renderer->initViewport(width, height);
208    renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
209            dirtyRect.right, dirtyRect.bottom, !isBlend());
210
211    displayList->defer(deferredState, 0);
212
213    deferredUpdateScheduled = false;
214}
215
216void Layer::flush() {
217    // renderer is checked as layer may be destroyed/put in layer cache with flush scheduled
218    if (deferredList && renderer) {
219        renderer->setViewport(layer.getWidth(), layer.getHeight());
220        renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
221                !isBlend());
222
223        deferredList->flush(*renderer, dirtyRect);
224
225        renderer->finish();
226        renderer = NULL;
227
228        dirtyRect.setEmpty();
229        displayList = NULL;
230    }
231}
232
233void Layer::render() {
234    renderer->setViewport(layer.getWidth(), layer.getHeight());
235    renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
236            !isBlend());
237
238    renderer->drawDisplayList(displayList, dirtyRect, DisplayList::kReplayFlag_ClipChildren);
239
240    renderer->finish();
241    renderer = NULL;
242
243    dirtyRect.setEmpty();
244
245    deferredUpdateScheduled = false;
246    displayList = NULL;
247}
248
249}; // namespace uirenderer
250}; // namespace android
251