Layer.cpp revision 443a714fa7c0dd07fee3527cc5bc3d3ca1fb7d44
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 "Caches.h"
22#include "DeferredDisplayList.h"
23#include "RenderState.h"
24#include "Layer.h"
25#include "LayerRenderer.h"
26#include "OpenGLRenderer.h"
27#include "RenderNode.h"
28
29namespace android {
30namespace uirenderer {
31
32Layer::Layer(RenderState& renderState, const uint32_t layerWidth, const uint32_t layerHeight)
33        : caches(Caches::getInstance())
34        , renderState(renderState)
35        , texture(caches) {
36    mesh = NULL;
37    meshElementCount = 0;
38    cacheable = true;
39    dirty = false;
40    textureLayer = false;
41    renderTarget = GL_TEXTURE_2D;
42    texture.width = layerWidth;
43    texture.height = layerHeight;
44    colorFilter = NULL;
45    deferredUpdateScheduled = false;
46    renderer = NULL;
47    renderNode = NULL;
48    fbo = 0;
49    stencil = NULL;
50    debugDrawUpdate = false;
51    hasDrawnSinceUpdate = false;
52    forceFilter = false;
53    deferredList = NULL;
54    convexMask = NULL;
55    caches.resourceCache.incrementRefcount(this);
56    rendererLightPosDirty = true;
57    wasBuildLayered = false;
58    renderState.registerLayer(this);
59}
60
61Layer::~Layer() {
62    renderState.unregisterLayer(this);
63    SkSafeUnref(colorFilter);
64    removeFbo();
65    deleteTexture();
66
67    delete[] mesh;
68    delete deferredList;
69    delete renderer;
70}
71
72uint32_t Layer::computeIdealWidth(uint32_t layerWidth) {
73    return uint32_t(ceilf(layerWidth / float(LAYER_SIZE)) * LAYER_SIZE);
74}
75
76uint32_t Layer::computeIdealHeight(uint32_t layerHeight) {
77    return uint32_t(ceilf(layerHeight / float(LAYER_SIZE)) * LAYER_SIZE);
78}
79
80void Layer::requireRenderer() {
81    if (!renderer) {
82        renderer = new LayerRenderer(renderState, this);
83        renderer->initProperties();
84    }
85}
86
87void Layer::updateLightPosFromRenderer(const OpenGLRenderer& rootRenderer) {
88    if (renderer && rendererLightPosDirty) {
89        // re-init renderer's light position, based upon last cached location in window
90        Vector3 lightPos = rootRenderer.getLightCenter();
91        cachedInvTransformInWindow.mapPoint3d(lightPos);
92        renderer->initLight(lightPos, rootRenderer.getLightRadius(),
93                rootRenderer.getAmbientShadowAlpha(), rootRenderer.getSpotShadowAlpha());
94        rendererLightPosDirty = false;
95    }
96}
97
98bool Layer::resize(const uint32_t width, const uint32_t height) {
99    uint32_t desiredWidth = computeIdealWidth(width);
100    uint32_t desiredHeight = computeIdealWidth(height);
101
102    if (desiredWidth <= getWidth() && desiredHeight <= getHeight()) {
103        return true;
104    }
105
106    ATRACE_NAME("resizeLayer");
107
108    const uint32_t maxTextureSize = caches.maxTextureSize;
109    if (desiredWidth > maxTextureSize || desiredHeight > maxTextureSize) {
110        ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)",
111                desiredWidth, desiredHeight, maxTextureSize, maxTextureSize);
112        return false;
113    }
114
115    uint32_t oldWidth = getWidth();
116    uint32_t oldHeight = getHeight();
117
118    setSize(desiredWidth, desiredHeight);
119
120    if (fbo) {
121        caches.activeTexture(0);
122        bindTexture();
123        allocateTexture();
124
125        if (glGetError() != GL_NO_ERROR) {
126            setSize(oldWidth, oldHeight);
127            return false;
128        }
129    }
130
131    if (stencil) {
132        stencil->bind();
133        stencil->resize(desiredWidth, desiredHeight);
134
135        if (glGetError() != GL_NO_ERROR) {
136            setSize(oldWidth, oldHeight);
137            return false;
138        }
139    }
140
141    return true;
142}
143
144void Layer::removeFbo(bool flush) {
145    if (stencil) {
146        GLuint previousFbo = renderState.getFramebuffer();
147        renderState.bindFramebuffer(fbo);
148        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
149        renderState.bindFramebuffer(previousFbo);
150
151        caches.renderBufferCache.put(stencil);
152        stencil = NULL;
153    }
154
155    if (fbo) {
156        if (flush) LayerRenderer::flushLayer(renderState, this);
157        // If put fails the cache will delete the FBO
158        caches.fboCache.put(fbo);
159        fbo = 0;
160    }
161}
162
163void Layer::updateDeferred(RenderNode* renderNode, int left, int top, int right, int bottom) {
164    requireRenderer();
165    this->renderNode = renderNode;
166    const Rect r(left, top, right, bottom);
167    dirtyRect.unionWith(r);
168    deferredUpdateScheduled = true;
169}
170
171void Layer::setPaint(const SkPaint* paint) {
172    OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
173    setColorFilter((paint) ? paint->getColorFilter() : NULL);
174}
175
176void Layer::setColorFilter(SkColorFilter* filter) {
177    SkRefCnt_SafeAssign(colorFilter, filter);
178}
179
180void Layer::bindTexture() const {
181    if (texture.id) {
182        caches.bindTexture(renderTarget, texture.id);
183    }
184}
185
186void Layer::bindStencilRenderBuffer() const {
187    if (stencil) {
188        stencil->bind();
189    }
190}
191
192void Layer::generateTexture() {
193    if (!texture.id) {
194        glGenTextures(1, &texture.id);
195    }
196}
197
198void Layer::deleteTexture() {
199    if (texture.id) {
200        texture.deleteTexture();
201        texture.id = 0;
202    }
203}
204
205void Layer::clearTexture() {
206    caches.unbindTexture(texture.id);
207    texture.id = 0;
208}
209
210void Layer::allocateTexture() {
211#if DEBUG_LAYERS
212    ALOGD("  Allocate layer: %dx%d", getWidth(), getHeight());
213#endif
214    if (texture.id) {
215        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
216        glTexImage2D(renderTarget, 0, GL_RGBA, getWidth(), getHeight(), 0,
217                GL_RGBA, GL_UNSIGNED_BYTE, NULL);
218    }
219}
220
221void Layer::defer(const OpenGLRenderer& rootRenderer) {
222    updateLightPosFromRenderer(rootRenderer);
223    const float width = layer.getWidth();
224    const float height = layer.getHeight();
225
226    if (dirtyRect.isEmpty() || (dirtyRect.left <= 0 && dirtyRect.top <= 0 &&
227            dirtyRect.right >= width && dirtyRect.bottom >= height)) {
228        dirtyRect.set(0, 0, width, height);
229    }
230
231    delete deferredList;
232    deferredList = new DeferredDisplayList(dirtyRect);
233
234    DeferStateStruct deferredState(*deferredList, *renderer,
235            RenderNode::kReplayFlag_ClipChildren);
236
237    renderer->setViewport(width, height);
238    renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
239            dirtyRect.right, dirtyRect.bottom, !isBlend());
240
241    renderNode->computeOrdering();
242    renderNode->defer(deferredState, 0);
243
244    deferredUpdateScheduled = false;
245}
246
247void Layer::cancelDefer() {
248    renderNode = NULL;
249    deferredUpdateScheduled = false;
250    if (deferredList) {
251        delete deferredList;
252        deferredList = NULL;
253    }
254}
255
256void Layer::flush() {
257    // renderer is checked as layer may be destroyed/put in layer cache with flush scheduled
258    if (deferredList && renderer) {
259        renderer->setViewport(layer.getWidth(), layer.getHeight());
260        renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
261                !isBlend());
262
263        deferredList->flush(*renderer, dirtyRect);
264
265        renderer->finish();
266
267        dirtyRect.setEmpty();
268        renderNode = NULL;
269    }
270}
271
272void Layer::render(const OpenGLRenderer& rootRenderer) {
273    updateLightPosFromRenderer(rootRenderer);
274    renderer->setViewport(layer.getWidth(), layer.getHeight());
275    renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
276            !isBlend());
277
278    renderer->drawRenderNode(renderNode.get(), dirtyRect, RenderNode::kReplayFlag_ClipChildren);
279
280    renderer->finish();
281
282    dirtyRect.setEmpty();
283
284    deferredUpdateScheduled = false;
285    renderNode = NULL;
286}
287
288}; // namespace uirenderer
289}; // namespace android
290