Layer.cpp revision 57998017ff137f7d4ec33df21b6596141f8c4547
1a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk/*
2a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk * Copyright (C) 2012 The Android Open Source Project
3a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk *
4a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk * Licensed under the Apache License, Version 2.0 (the "License");
5a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk * you may not use this file except in compliance with the License.
6a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk * You may obtain a copy of the License at
7a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk *
8a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk *      http://www.apache.org/licenses/LICENSE-2.0
9a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk *
10a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk * Unless required by applicable law or agreed to in writing, software
11a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk * distributed under the License is distributed on an "AS IS" BASIS,
12a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk * See the License for the specific language governing permissions and
14a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk * limitations under the License.
15a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk */
16a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk
17a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk#define LOG_TAG "OpenGLRenderer"
18a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk
19a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk#include <utils/Log.h>
20a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk
21a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk#include "Caches.h"
221cd84930b25bf12e094b416a0ea4ae5fe839f537Stephen Hines#include "DeferredDisplayList.h"
23a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk#include "Layer.h"
24a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk#include "LayerRenderer.h"
25a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk#include "OpenGLRenderer.h"
26a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk#include "RenderNode.h"
27a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk#include "RenderState.h"
28a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk#include "utils/TraceUtils.h"
29a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk
30a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk#define ATRACE_LAYER_WORK(label) \
31a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk    ATRACE_FORMAT("%s HW Layer DisplayList %s %ux%u", \
32a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk            label, \
33a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk            (renderNode.get() != NULL) ? renderNode->getName() : "", \
34a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk            getWidth(), getHeight())
35a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk
36a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouknamespace android {
37a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouknamespace uirenderer {
38a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk
39a94952436aeb251f587c1bccdf94c7f75285dfe2Alex SakhartchoukLayer::Layer(Type layerType, RenderState& renderState, const uint32_t layerWidth, const uint32_t layerHeight)
40a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk        : state(kState_Uncached)
41a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk        , caches(Caches::getInstance())
42a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk        , renderState(renderState)
43a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk        , texture(caches)
44a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk        , type(layerType) {
45a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk    // TODO: This is a violation of Android's typical ref counting, but it
46a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk    // preserves the old inc/dec ref locations. This should be changed...
47a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk    incStrong(0);
48a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk    mesh = NULL;
49a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk    meshElementCount = 0;
50a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk    cacheable = true;
51a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk    dirty = false;
52a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk    renderTarget = GL_TEXTURE_2D;
53a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk    texture.width = layerWidth;
54a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk    texture.height = layerHeight;
55a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk    colorFilter = NULL;
56a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk    deferredUpdateScheduled = false;
57a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk    renderer = NULL;
58a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk    renderNode = NULL;
59a94952436aeb251f587c1bccdf94c7f75285dfe2Alex Sakhartchouk    fbo = 0;
60    stencil = NULL;
61    debugDrawUpdate = false;
62    hasDrawnSinceUpdate = false;
63    forceFilter = false;
64    deferredList = NULL;
65    convexMask = NULL;
66    rendererLightPosDirty = true;
67    wasBuildLayered = false;
68    renderState.registerLayer(this);
69}
70
71Layer::~Layer() {
72    renderState.unregisterLayer(this);
73    SkSafeUnref(colorFilter);
74
75    if (stencil || fbo || texture.id) {
76        renderState.requireGLContext();
77        removeFbo();
78        deleteTexture();
79    }
80
81    delete[] mesh;
82    delete deferredList;
83    delete renderer;
84}
85
86void Layer::onGlContextLost() {
87    removeFbo();
88    deleteTexture();
89}
90
91uint32_t Layer::computeIdealWidth(uint32_t layerWidth) {
92    return uint32_t(ceilf(layerWidth / float(LAYER_SIZE)) * LAYER_SIZE);
93}
94
95uint32_t Layer::computeIdealHeight(uint32_t layerHeight) {
96    return uint32_t(ceilf(layerHeight / float(LAYER_SIZE)) * LAYER_SIZE);
97}
98
99void Layer::requireRenderer() {
100    if (!renderer) {
101        renderer = new LayerRenderer(renderState, this);
102        renderer->initProperties();
103    }
104}
105
106void Layer::updateLightPosFromRenderer(const OpenGLRenderer& rootRenderer) {
107    if (renderer && rendererLightPosDirty) {
108        // re-init renderer's light position, based upon last cached location in window
109        Vector3 lightPos = rootRenderer.getLightCenter();
110        cachedInvTransformInWindow.mapPoint3d(lightPos);
111        renderer->initLight(lightPos, rootRenderer.getLightRadius(),
112                rootRenderer.getAmbientShadowAlpha(), rootRenderer.getSpotShadowAlpha());
113        rendererLightPosDirty = false;
114    }
115}
116
117bool Layer::resize(const uint32_t width, const uint32_t height) {
118    uint32_t desiredWidth = computeIdealWidth(width);
119    uint32_t desiredHeight = computeIdealWidth(height);
120
121    if (desiredWidth <= getWidth() && desiredHeight <= getHeight()) {
122        return true;
123    }
124
125    ATRACE_NAME("resizeLayer");
126
127    const uint32_t maxTextureSize = caches.maxTextureSize;
128    if (desiredWidth > maxTextureSize || desiredHeight > maxTextureSize) {
129        ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)",
130                desiredWidth, desiredHeight, maxTextureSize, maxTextureSize);
131        return false;
132    }
133
134    uint32_t oldWidth = getWidth();
135    uint32_t oldHeight = getHeight();
136
137    setSize(desiredWidth, desiredHeight);
138
139    if (fbo) {
140        caches.activeTexture(0);
141        bindTexture();
142        allocateTexture();
143
144        if (glGetError() != GL_NO_ERROR) {
145            setSize(oldWidth, oldHeight);
146            return false;
147        }
148    }
149
150    if (stencil) {
151        stencil->bind();
152        stencil->resize(desiredWidth, desiredHeight);
153
154        if (glGetError() != GL_NO_ERROR) {
155            setSize(oldWidth, oldHeight);
156            return false;
157        }
158    }
159
160    return true;
161}
162
163void Layer::removeFbo(bool flush) {
164    if (stencil) {
165        GLuint previousFbo = renderState.getFramebuffer();
166        renderState.bindFramebuffer(fbo);
167        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
168        renderState.bindFramebuffer(previousFbo);
169
170        caches.renderBufferCache.put(stencil);
171        stencil = NULL;
172    }
173
174    if (fbo) {
175        if (flush) LayerRenderer::flushLayer(renderState, this);
176        // If put fails the cache will delete the FBO
177        caches.fboCache.put(fbo);
178        fbo = 0;
179    }
180}
181
182void Layer::updateDeferred(RenderNode* renderNode, int left, int top, int right, int bottom) {
183    requireRenderer();
184    this->renderNode = renderNode;
185    const Rect r(left, top, right, bottom);
186    dirtyRect.unionWith(r);
187    deferredUpdateScheduled = true;
188}
189
190void Layer::setPaint(const SkPaint* paint) {
191    OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
192    setColorFilter((paint) ? paint->getColorFilter() : NULL);
193}
194
195void Layer::setColorFilter(SkColorFilter* filter) {
196    SkRefCnt_SafeAssign(colorFilter, filter);
197}
198
199void Layer::bindTexture() const {
200    if (texture.id) {
201        caches.bindTexture(renderTarget, texture.id);
202    }
203}
204
205void Layer::bindStencilRenderBuffer() const {
206    if (stencil) {
207        stencil->bind();
208    }
209}
210
211void Layer::generateTexture() {
212    if (!texture.id) {
213        glGenTextures(1, &texture.id);
214    }
215}
216
217void Layer::deleteTexture() {
218    if (texture.id) {
219        texture.deleteTexture();
220        texture.id = 0;
221    }
222}
223
224void Layer::clearTexture() {
225    caches.unbindTexture(texture.id);
226    texture.id = 0;
227}
228
229void Layer::allocateTexture() {
230#if DEBUG_LAYERS
231    ALOGD("  Allocate layer: %dx%d", getWidth(), getHeight());
232#endif
233    if (texture.id) {
234        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
235        glTexImage2D(renderTarget, 0, GL_RGBA, getWidth(), getHeight(), 0,
236                GL_RGBA, GL_UNSIGNED_BYTE, NULL);
237    }
238}
239
240void Layer::defer(const OpenGLRenderer& rootRenderer) {
241    ATRACE_LAYER_WORK("Optimize");
242
243    updateLightPosFromRenderer(rootRenderer);
244    const float width = layer.getWidth();
245    const float height = layer.getHeight();
246
247    if (dirtyRect.isEmpty() || (dirtyRect.left <= 0 && dirtyRect.top <= 0 &&
248            dirtyRect.right >= width && dirtyRect.bottom >= height)) {
249        dirtyRect.set(0, 0, width, height);
250    }
251
252    delete deferredList;
253    deferredList = new DeferredDisplayList(dirtyRect);
254
255    DeferStateStruct deferredState(*deferredList, *renderer,
256            RenderNode::kReplayFlag_ClipChildren);
257
258    renderer->setViewport(width, height);
259    renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
260            dirtyRect.right, dirtyRect.bottom, !isBlend());
261
262    renderNode->computeOrdering();
263    renderNode->defer(deferredState, 0);
264
265    deferredUpdateScheduled = false;
266}
267
268void Layer::cancelDefer() {
269    renderNode = NULL;
270    deferredUpdateScheduled = false;
271    if (deferredList) {
272        delete deferredList;
273        deferredList = NULL;
274    }
275}
276
277void Layer::flush() {
278    // renderer is checked as layer may be destroyed/put in layer cache with flush scheduled
279    if (deferredList && renderer) {
280        ATRACE_LAYER_WORK("Issue");
281        renderer->startMark((renderNode.get() != NULL) ? renderNode->getName() : "Layer");
282
283        renderer->setViewport(layer.getWidth(), layer.getHeight());
284        renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
285                !isBlend());
286
287        deferredList->flush(*renderer, dirtyRect);
288
289        renderer->finish();
290
291        dirtyRect.setEmpty();
292        renderNode = NULL;
293
294        renderer->endMark();
295    }
296}
297
298void Layer::render(const OpenGLRenderer& rootRenderer) {
299    ATRACE_LAYER_WORK("Direct-Issue");
300
301    updateLightPosFromRenderer(rootRenderer);
302    renderer->setViewport(layer.getWidth(), layer.getHeight());
303    renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
304            !isBlend());
305
306    renderer->drawRenderNode(renderNode.get(), dirtyRect, RenderNode::kReplayFlag_ClipChildren);
307
308    renderer->finish();
309
310    dirtyRect.setEmpty();
311
312    deferredUpdateScheduled = false;
313    renderNode = NULL;
314}
315
316void Layer::postDecStrong() {
317    renderState.postDecStrong(this);
318}
319
320}; // namespace uirenderer
321}; // namespace android
322