• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 #define ATRACE_TAG ATRACE_TAG_VIEW
19 
20 #include <ui/Rect.h>
21 
22 #include <private/hwui/DrawGlInfo.h>
23 
24 #include "RenderState.h"
25 #include "LayerCache.h"
26 #include "LayerRenderer.h"
27 #include "Matrix.h"
28 #include "Properties.h"
29 #include "Rect.h"
30 
31 namespace android {
32 namespace uirenderer {
33 
34 ///////////////////////////////////////////////////////////////////////////////
35 // Rendering
36 ///////////////////////////////////////////////////////////////////////////////
37 
LayerRenderer(RenderState & renderState,Layer * layer)38 LayerRenderer::LayerRenderer(RenderState& renderState, Layer* layer)
39         : OpenGLRenderer(renderState)
40         , mLayer(layer) {
41 }
42 
~LayerRenderer()43 LayerRenderer::~LayerRenderer() {
44 }
45 
prepareDirty(float left,float top,float right,float bottom,bool opaque)46 status_t LayerRenderer::prepareDirty(float left, float top, float right, float bottom,
47         bool opaque) {
48     LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->getFbo());
49 
50     renderState().bindFramebuffer(mLayer->getFbo());
51 
52     const float width = mLayer->layer.getWidth();
53     const float height = mLayer->layer.getHeight();
54 
55     Rect dirty(left, top, right, bottom);
56     if (dirty.isEmpty() || (dirty.left <= 0 && dirty.top <= 0 &&
57             dirty.right >= width && dirty.bottom >= height)) {
58         mLayer->region.clear();
59         dirty.set(0.0f, 0.0f, width, height);
60     } else {
61         dirty.intersect(0.0f, 0.0f, width, height);
62         android::Rect r(dirty.left, dirty.top, dirty.right, dirty.bottom);
63         mLayer->region.subtractSelf(r);
64     }
65     mLayer->clipRect.set(dirty);
66 
67     return OpenGLRenderer::prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, opaque);
68 }
69 
clear(float left,float top,float right,float bottom,bool opaque)70 status_t LayerRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
71     if (mLayer->isDirty()) {
72         getCaches().disableScissor();
73         glClear(GL_COLOR_BUFFER_BIT);
74 
75         getCaches().resetScissor();
76         mLayer->setDirty(false);
77 
78         return DrawGlInfo::kStatusDone;
79     }
80 
81     return OpenGLRenderer::clear(left, top, right, bottom, opaque);
82 }
83 
finish()84 void LayerRenderer::finish() {
85     OpenGLRenderer::finish();
86 
87     generateMesh();
88 
89     LAYER_RENDERER_LOGD("Finished rendering into layer, fbo = %d", mLayer->getFbo());
90 
91     // No need to unbind our FBO, this will be taken care of by the caller
92     // who will invoke OpenGLRenderer::resume()
93 }
94 
getTargetFbo() const95 GLuint LayerRenderer::getTargetFbo() const {
96     return mLayer->getFbo();
97 }
98 
suppressErrorChecks() const99 bool LayerRenderer::suppressErrorChecks() const {
100     return true;
101 }
102 
103 ///////////////////////////////////////////////////////////////////////////////
104 // Layer support
105 ///////////////////////////////////////////////////////////////////////////////
106 
hasLayer() const107 bool LayerRenderer::hasLayer() const {
108     return true;
109 }
110 
ensureStencilBuffer()111 void LayerRenderer::ensureStencilBuffer() {
112     attachStencilBufferToLayer(mLayer);
113 }
114 
115 ///////////////////////////////////////////////////////////////////////////////
116 // Dirty region tracking
117 ///////////////////////////////////////////////////////////////////////////////
118 
getRegion() const119 Region* LayerRenderer::getRegion() const {
120     if (currentSnapshot()->flags & Snapshot::kFlagFboTarget) {
121         return OpenGLRenderer::getRegion();
122     }
123     return &mLayer->region;
124 }
125 
126 // TODO: This implementation uses a very simple approach to fixing T-junctions which keeps the
127 //       results as rectangles, and is thus not necessarily efficient in the geometry
128 //       produced. Eventually, it may be better to develop triangle-based mechanism.
generateMesh()129 void LayerRenderer::generateMesh() {
130     if (mLayer->region.isRect() || mLayer->region.isEmpty()) {
131         if (mLayer->mesh) {
132             delete[] mLayer->mesh;
133             mLayer->mesh = NULL;
134             mLayer->meshElementCount = 0;
135         }
136 
137         mLayer->setRegionAsRect();
138         return;
139     }
140 
141     // avoid T-junctions as they cause artifacts in between the resultant
142     // geometry when complex transforms occur.
143     // TODO: generate the safeRegion only if necessary based on drawing transform (see
144     // OpenGLRenderer::composeLayerRegion())
145     Region safeRegion = Region::createTJunctionFreeRegion(mLayer->region);
146 
147     size_t count;
148     const android::Rect* rects = safeRegion.getArray(&count);
149 
150     GLsizei elementCount = count * 6;
151 
152     if (mLayer->mesh && mLayer->meshElementCount < elementCount) {
153         delete[] mLayer->mesh;
154         mLayer->mesh = NULL;
155     }
156 
157     if (!mLayer->mesh) {
158         mLayer->mesh = new TextureVertex[count * 4];
159     }
160     mLayer->meshElementCount = elementCount;
161 
162     const float texX = 1.0f / float(mLayer->getWidth());
163     const float texY = 1.0f / float(mLayer->getHeight());
164     const float height = mLayer->layer.getHeight();
165 
166     TextureVertex* mesh = mLayer->mesh;
167 
168     for (size_t i = 0; i < count; i++) {
169         const android::Rect* r = &rects[i];
170 
171         const float u1 = r->left * texX;
172         const float v1 = (height - r->top) * texY;
173         const float u2 = r->right * texX;
174         const float v2 = (height - r->bottom) * texY;
175 
176         TextureVertex::set(mesh++, r->left, r->top, u1, v1);
177         TextureVertex::set(mesh++, r->right, r->top, u2, v1);
178         TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
179         TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
180     }
181 }
182 
183 ///////////////////////////////////////////////////////////////////////////////
184 // Layers management
185 ///////////////////////////////////////////////////////////////////////////////
186 
createRenderLayer(RenderState & renderState,uint32_t width,uint32_t height)187 Layer* LayerRenderer::createRenderLayer(RenderState& renderState, uint32_t width, uint32_t height) {
188     ATRACE_CALL();
189     LAYER_RENDERER_LOGD("Requesting new render layer %dx%d", width, height);
190 
191     Caches& caches = Caches::getInstance();
192     GLuint fbo = caches.fboCache.get();
193     if (!fbo) {
194         ALOGW("Could not obtain an FBO");
195         return NULL;
196     }
197 
198     caches.activeTexture(0);
199     Layer* layer = caches.layerCache.get(renderState, width, height);
200     if (!layer) {
201         ALOGW("Could not obtain a layer");
202         return NULL;
203     }
204 
205     // We first obtain a layer before comparing against the max texture size
206     // because layers are not allocated at the exact desired size. They are
207     // always created slighly larger to improve recycling
208     const uint32_t maxTextureSize = caches.maxTextureSize;
209     if (layer->getWidth() > maxTextureSize || layer->getHeight() > maxTextureSize) {
210         ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)",
211                 width, height, maxTextureSize, maxTextureSize);
212 
213         // Creating a new layer always increment its refcount by 1, this allows
214         // us to destroy the layer object if one was created for us
215         Caches::getInstance().resourceCache.decrementRefcount(layer);
216 
217         return NULL;
218     }
219 
220     layer->setFbo(fbo);
221     layer->layer.set(0.0f, 0.0f, width, height);
222     layer->texCoords.set(0.0f, height / float(layer->getHeight()),
223             width / float(layer->getWidth()), 0.0f);
224     layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
225     layer->setColorFilter(NULL);
226     layer->setDirty(true);
227     layer->region.clear();
228 
229     GLuint previousFbo = renderState.getFramebuffer();
230 
231     renderState.bindFramebuffer(layer->getFbo());
232     layer->bindTexture();
233 
234     // Initialize the texture if needed
235     if (layer->isEmpty()) {
236         layer->setEmpty(false);
237         layer->allocateTexture();
238 
239         // This should only happen if we run out of memory
240         if (glGetError() != GL_NO_ERROR) {
241             ALOGE("Could not allocate texture for layer (fbo=%d %dx%d)", fbo, width, height);
242             renderState.bindFramebuffer(previousFbo);
243             caches.resourceCache.decrementRefcount(layer);
244             return NULL;
245         }
246     }
247 
248     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
249             layer->getTexture(), 0);
250 
251     renderState.bindFramebuffer(previousFbo);
252 
253     return layer;
254 }
255 
resizeLayer(Layer * layer,uint32_t width,uint32_t height)256 bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) {
257     if (layer) {
258         LAYER_RENDERER_LOGD("Resizing layer fbo = %d to %dx%d", layer->getFbo(), width, height);
259 
260         if (layer->resize(width, height)) {
261             layer->layer.set(0.0f, 0.0f, width, height);
262             layer->texCoords.set(0.0f, height / float(layer->getHeight()),
263                     width / float(layer->getWidth()), 0.0f);
264         } else {
265             return false;
266         }
267     }
268 
269     return true;
270 }
271 
createTextureLayer(RenderState & renderState)272 Layer* LayerRenderer::createTextureLayer(RenderState& renderState) {
273     LAYER_RENDERER_LOGD("Creating new texture layer");
274 
275     Layer* layer = new Layer(Layer::kType_Texture, renderState, 0, 0);
276     layer->setCacheable(false);
277     layer->setEmpty(true);
278     layer->setFbo(0);
279     layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
280     layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f);
281     layer->texCoords.set(0.0f, 1.0f, 1.0f, 0.0f);
282     layer->region.clear();
283     layer->setRenderTarget(GL_NONE); // see ::updateTextureLayer()
284 
285     Caches::getInstance().activeTexture(0);
286     layer->generateTexture();
287 
288     return layer;
289 }
290 
updateTextureLayer(Layer * layer,uint32_t width,uint32_t height,bool isOpaque,bool forceFilter,GLenum renderTarget,float * textureTransform)291 void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
292         bool isOpaque, bool forceFilter, GLenum renderTarget, float* textureTransform) {
293     if (layer) {
294         layer->setBlend(!isOpaque);
295         layer->setForceFilter(forceFilter);
296         layer->setSize(width, height);
297         layer->layer.set(0.0f, 0.0f, width, height);
298         layer->region.set(width, height);
299         layer->regionRect.set(0.0f, 0.0f, width, height);
300         layer->getTexTransform().load(textureTransform);
301 
302         if (renderTarget != layer->getRenderTarget()) {
303             layer->setRenderTarget(renderTarget);
304             layer->bindTexture();
305             layer->setFilter(GL_NEAREST, false, true);
306             layer->setWrap(GL_CLAMP_TO_EDGE, false, true);
307         }
308     }
309 }
310 
destroyLayer(Layer * layer)311 void LayerRenderer::destroyLayer(Layer* layer) {
312     if (layer) {
313         ATRACE_CALL();
314         LAYER_RENDERER_LOGD("Recycling layer, %dx%d fbo = %d",
315                 layer->getWidth(), layer->getHeight(), layer->getFbo());
316 
317         if (!Caches::getInstance().layerCache.put(layer)) {
318             LAYER_RENDERER_LOGD("  Destroyed!");
319             Caches::getInstance().resourceCache.decrementRefcount(layer);
320         } else {
321             LAYER_RENDERER_LOGD("  Cached!");
322 #if DEBUG_LAYER_RENDERER
323             Caches::getInstance().layerCache.dump();
324 #endif
325             layer->removeFbo();
326             layer->region.clear();
327         }
328     }
329 }
330 
destroyLayerDeferred(Layer * layer)331 void LayerRenderer::destroyLayerDeferred(Layer* layer) {
332     if (layer) {
333         LAYER_RENDERER_LOGD("Deferring layer destruction, fbo = %d", layer->getFbo());
334 
335         Caches::getInstance().deleteLayerDeferred(layer);
336     }
337 }
338 
flushLayer(RenderState & renderState,Layer * layer)339 void LayerRenderer::flushLayer(RenderState& renderState, Layer* layer) {
340 #ifdef GL_EXT_discard_framebuffer
341     if (!layer) return;
342 
343     GLuint fbo = layer->getFbo();
344     if (fbo) {
345         // If possible, discard any enqueud operations on deferred
346         // rendering architectures
347         if (Extensions::getInstance().hasDiscardFramebuffer()) {
348             GLuint previousFbo = renderState.getFramebuffer();
349             if (fbo != previousFbo) {
350                 renderState.bindFramebuffer(fbo);
351             }
352 
353             const GLenum attachments[] = { GL_COLOR_ATTACHMENT0 };
354             glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments);
355 
356             if (fbo != previousFbo) {
357                 renderState.bindFramebuffer(previousFbo);
358             }
359         }
360     }
361 #endif
362 }
363 
copyLayer(RenderState & renderState,Layer * layer,SkBitmap * bitmap)364 bool LayerRenderer::copyLayer(RenderState& renderState, Layer* layer, SkBitmap* bitmap) {
365     Caches& caches = Caches::getInstance();
366     if (layer && bitmap->width() <= caches.maxTextureSize &&
367             bitmap->height() <= caches.maxTextureSize) {
368 
369         GLuint fbo = caches.fboCache.get();
370         if (!fbo) {
371             ALOGW("Could not obtain an FBO");
372             return false;
373         }
374 
375         SkAutoLockPixels alp(*bitmap);
376 
377         GLuint texture;
378         GLuint previousFbo;
379         GLsizei previousViewportWidth;
380         GLsizei previousViewportHeight;
381 
382         GLenum format;
383         GLenum type;
384 
385         GLenum error = GL_NO_ERROR;
386         bool status = false;
387 
388         switch (bitmap->colorType()) {
389             case kAlpha_8_SkColorType:
390                 format = GL_ALPHA;
391                 type = GL_UNSIGNED_BYTE;
392                 break;
393             case kRGB_565_SkColorType:
394                 format = GL_RGB;
395                 type = GL_UNSIGNED_SHORT_5_6_5;
396                 break;
397             case kARGB_4444_SkColorType:
398                 format = GL_RGBA;
399                 type = GL_UNSIGNED_SHORT_4_4_4_4;
400                 break;
401             case kN32_SkColorType:
402             default:
403                 format = GL_RGBA;
404                 type = GL_UNSIGNED_BYTE;
405                 break;
406         }
407 
408         float alpha = layer->getAlpha();
409         SkXfermode::Mode mode = layer->getMode();
410         GLuint previousLayerFbo = layer->getFbo();
411 
412         layer->setAlpha(255, SkXfermode::kSrc_Mode);
413         layer->setFbo(fbo);
414 
415         previousFbo = renderState.getFramebuffer();
416         renderState.getViewport(&previousViewportWidth, &previousViewportHeight);
417         renderState.bindFramebuffer(fbo);
418 
419         glGenTextures(1, &texture);
420         if ((error = glGetError()) != GL_NO_ERROR) goto error;
421 
422         caches.activeTexture(0);
423         caches.bindTexture(texture);
424 
425         glPixelStorei(GL_PACK_ALIGNMENT, bitmap->bytesPerPixel());
426 
427         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
428         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
429 
430         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
431         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
432 
433         glTexImage2D(GL_TEXTURE_2D, 0, format, bitmap->width(), bitmap->height(),
434                 0, format, type, NULL);
435         if ((error = glGetError()) != GL_NO_ERROR) goto error;
436 
437         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
438                 GL_TEXTURE_2D, texture, 0);
439         if ((error = glGetError()) != GL_NO_ERROR) goto error;
440 
441         {
442             LayerRenderer renderer(renderState, layer);
443             renderer.setViewport(bitmap->width(), bitmap->height());
444             renderer.OpenGLRenderer::prepareDirty(0.0f, 0.0f,
445                     bitmap->width(), bitmap->height(), !layer->isBlend());
446 
447             caches.disableScissor();
448             renderer.translate(0.0f, bitmap->height());
449             renderer.scale(1.0f, -1.0f);
450 
451             mat4 texTransform(layer->getTexTransform());
452 
453             mat4 invert;
454             invert.translate(0.0f, 1.0f);
455             invert.scale(1.0f, -1.0f, 1.0f);
456             layer->getTexTransform().multiply(invert);
457 
458             if ((error = glGetError()) != GL_NO_ERROR) goto error;
459 
460             {
461                 Rect bounds;
462                 bounds.set(0.0f, 0.0f, bitmap->width(), bitmap->height());
463                 renderer.drawTextureLayer(layer, bounds);
464 
465                 glReadPixels(0, 0, bitmap->width(), bitmap->height(), format,
466                         type, bitmap->getPixels());
467 
468                 if ((error = glGetError()) != GL_NO_ERROR) goto error;
469             }
470 
471             layer->getTexTransform().load(texTransform);
472             status = true;
473         }
474 
475 error:
476 #if DEBUG_OPENGL
477         if (error != GL_NO_ERROR) {
478             ALOGD("GL error while copying layer into bitmap = 0x%x", error);
479         }
480 #endif
481 
482         renderState.bindFramebuffer(previousFbo);
483         layer->setAlpha(alpha, mode);
484         layer->setFbo(previousLayerFbo);
485         caches.deleteTexture(texture);
486         caches.fboCache.put(fbo);
487         renderState.setViewport(previousViewportWidth, previousViewportHeight);
488 
489         return status;
490     }
491     return false;
492 }
493 
494 }; // namespace uirenderer
495 }; // namespace android
496