Layer.cpp revision 38e0c32852e3b9d8ca4a9d3791577f52536419cb
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#include "Layer.h"
18
19#include "Caches.h"
20#include "DeferredDisplayList.h"
21#include "LayerRenderer.h"
22#include "OpenGLRenderer.h"
23#include "RenderNode.h"
24#include "renderstate/RenderState.h"
25#include "utils/TraceUtils.h"
26
27#include <utils/Log.h>
28
29#define ATRACE_LAYER_WORK(label) \
30    ATRACE_FORMAT("%s HW Layer DisplayList %s %ux%u", \
31            label, \
32            (renderNode.get() != NULL) ? renderNode->getName() : "", \
33            getWidth(), getHeight())
34
35namespace android {
36namespace uirenderer {
37
38Layer::Layer(Type layerType, RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight)
39        : GpuMemoryTracker(GpuObjectType::Layer)
40        , state(State::Uncached)
41        , caches(Caches::getInstance())
42        , renderState(renderState)
43        , texture(caches)
44        , type(layerType) {
45    // TODO: This is a violation of Android's typical ref counting, but it
46    // preserves the old inc/dec ref locations. This should be changed...
47    incStrong(nullptr);
48    renderTarget = GL_TEXTURE_2D;
49    texture.mWidth = layerWidth;
50    texture.mHeight = layerHeight;
51    renderState.registerLayer(this);
52}
53
54Layer::~Layer() {
55    renderState.unregisterLayer(this);
56    SkSafeUnref(colorFilter);
57
58    if (stencil || fbo || texture.mId) {
59        renderState.requireGLContext();
60        removeFbo();
61        texture.deleteTexture();
62    }
63
64    delete[] mesh;
65}
66
67void Layer::onGlContextLost() {
68    removeFbo();
69    texture.deleteTexture();
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.reset(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(rootRenderer.getLightRadius(),
93                rootRenderer.getAmbientShadowAlpha(),
94                rootRenderer.getSpotShadowAlpha());
95        renderer->setLightCenter(lightPos);
96        rendererLightPosDirty = false;
97    }
98}
99
100bool Layer::resize(const uint32_t width, const uint32_t height) {
101    uint32_t desiredWidth = computeIdealWidth(width);
102    uint32_t desiredHeight = computeIdealWidth(height);
103
104    if (desiredWidth <= getWidth() && desiredHeight <= getHeight()) {
105        return true;
106    }
107
108    ATRACE_NAME("resizeLayer");
109
110    const uint32_t maxTextureSize = caches.maxTextureSize;
111    if (desiredWidth > maxTextureSize || desiredHeight > maxTextureSize) {
112        ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)",
113                desiredWidth, desiredHeight, maxTextureSize, maxTextureSize);
114        return false;
115    }
116
117    uint32_t oldWidth = getWidth();
118    uint32_t oldHeight = getHeight();
119
120    setSize(desiredWidth, desiredHeight);
121
122    if (fbo) {
123        caches.textureState().activateTexture(0);
124        bindTexture();
125        allocateTexture();
126
127        if (glGetError() != GL_NO_ERROR) {
128            setSize(oldWidth, oldHeight);
129            return false;
130        }
131    }
132
133    if (stencil) {
134        stencil->bind();
135        stencil->resize(desiredWidth, desiredHeight);
136
137        if (glGetError() != GL_NO_ERROR) {
138            setSize(oldWidth, oldHeight);
139            return false;
140        }
141    }
142
143    return true;
144}
145
146void Layer::removeFbo(bool flush) {
147    if (stencil) {
148        GLuint previousFbo = renderState.getFramebuffer();
149        renderState.bindFramebuffer(fbo);
150        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
151        renderState.bindFramebuffer(previousFbo);
152
153        caches.renderBufferCache.put(stencil);
154        stencil = nullptr;
155    }
156
157    if (fbo) {
158        if (flush) LayerRenderer::flushLayer(renderState, this);
159        renderState.deleteFramebuffer(fbo);
160        fbo = 0;
161    }
162}
163
164void Layer::updateDeferred(RenderNode* renderNode, int left, int top, int right, int bottom) {
165    requireRenderer();
166    this->renderNode = renderNode;
167    const Rect r(left, top, right, bottom);
168    dirtyRect.unionWith(r);
169    deferredUpdateScheduled = true;
170}
171
172void Layer::setPaint(const SkPaint* paint) {
173    alpha = PaintUtils::getAlphaDirect(paint);
174    mode = PaintUtils::getXfermodeDirect(paint);
175    setColorFilter((paint) ? paint->getColorFilter() : nullptr);
176}
177
178void Layer::setColorFilter(SkColorFilter* filter) {
179    SkRefCnt_SafeAssign(colorFilter, filter);
180}
181
182void Layer::bindTexture() const {
183    if (texture.mId) {
184        caches.textureState().bindTexture(renderTarget, texture.mId);
185    }
186}
187
188void Layer::bindStencilRenderBuffer() const {
189    if (stencil) {
190        stencil->bind();
191    }
192}
193
194void Layer::generateTexture() {
195    if (!texture.mId) {
196        glGenTextures(1, &texture.mId);
197    }
198}
199
200void Layer::clearTexture() {
201    caches.textureState().unbindTexture(texture.mId);
202    texture.mId = 0;
203}
204
205void Layer::allocateTexture() {
206#if DEBUG_LAYERS
207    ALOGD("  Allocate layer: %dx%d", getWidth(), getHeight());
208#endif
209    if (texture.mId) {
210        texture.updateSize(getWidth(), getHeight(), GL_RGBA);
211        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
212        glTexImage2D(renderTarget, 0, GL_RGBA, getWidth(), getHeight(), 0,
213                GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
214    }
215}
216
217void Layer::defer(const OpenGLRenderer& rootRenderer) {
218    ATRACE_LAYER_WORK("Optimize");
219
220    updateLightPosFromRenderer(rootRenderer);
221    const float width = layer.getWidth();
222    const float height = layer.getHeight();
223
224    if (dirtyRect.isEmpty() || (dirtyRect.left <= 0 && dirtyRect.top <= 0 &&
225            dirtyRect.right >= width && dirtyRect.bottom >= height)) {
226        dirtyRect.set(0, 0, width, height);
227    }
228
229    deferredList.reset(new DeferredDisplayList(dirtyRect));
230
231    DeferStateStruct deferredState(*deferredList, *renderer,
232            RenderNode::kReplayFlag_ClipChildren);
233
234    renderer->setupFrameState(width, height, dirtyRect.left, dirtyRect.top,
235            dirtyRect.right, dirtyRect.bottom, !isBlend());
236
237    renderNode->computeOrdering();
238    renderNode->defer(deferredState, 0);
239
240    deferredUpdateScheduled = false;
241}
242
243void Layer::cancelDefer() {
244    renderNode = nullptr;
245    deferredUpdateScheduled = false;
246    deferredList.reset(nullptr);
247}
248
249void Layer::flush() {
250    // renderer is checked as layer may be destroyed/put in layer cache with flush scheduled
251    if (deferredList && renderer) {
252        ATRACE_LAYER_WORK("Issue");
253        renderer->startMark((renderNode.get() != nullptr) ? renderNode->getName() : "Layer");
254
255        renderer->prepareDirty(layer.getWidth(), layer.getHeight(),
256                dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom, !isBlend());
257
258        deferredList->flush(*renderer, dirtyRect);
259
260        renderer->finish();
261
262        dirtyRect.setEmpty();
263        renderNode = nullptr;
264
265        renderer->endMark();
266    }
267}
268
269void Layer::render(const OpenGLRenderer& rootRenderer) {
270    ATRACE_LAYER_WORK("Direct-Issue");
271
272    updateLightPosFromRenderer(rootRenderer);
273    renderer->prepareDirty(layer.getWidth(), layer.getHeight(),
274            dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom, !isBlend());
275
276    renderer->drawRenderNode(renderNode.get(), dirtyRect, RenderNode::kReplayFlag_ClipChildren);
277
278    renderer->finish();
279
280    dirtyRect.setEmpty();
281
282    deferredUpdateScheduled = false;
283    renderNode = nullptr;
284}
285
286void Layer::postDecStrong() {
287    renderState.postDecStrong(this);
288}
289
290}; // namespace uirenderer
291}; // namespace android
292