• 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 
19 #include <ui/Rect.h>
20 
21 #include <private/hwui/DrawGlInfo.h>
22 
23 #include "LayerCache.h"
24 #include "LayerRenderer.h"
25 #include "Matrix.h"
26 #include "Properties.h"
27 #include "Rect.h"
28 
29 namespace android {
30 namespace uirenderer {
31 
32 ///////////////////////////////////////////////////////////////////////////////
33 // Rendering
34 ///////////////////////////////////////////////////////////////////////////////
35 
LayerRenderer(Layer * layer)36 LayerRenderer::LayerRenderer(Layer* layer): mLayer(layer) {
37 }
38 
~LayerRenderer()39 LayerRenderer::~LayerRenderer() {
40 }
41 
setViewport(int width,int height)42 void LayerRenderer::setViewport(int width, int height) {
43     initViewport(width, height);
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     glBindFramebuffer(GL_FRAMEBUFFER, 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 GLint 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 (getSnapshot()->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             delete[] mLayer->meshIndices;
134 
135             mLayer->mesh = NULL;
136             mLayer->meshIndices = NULL;
137             mLayer->meshElementCount = 0;
138         }
139 
140         mLayer->setRegionAsRect();
141         return;
142     }
143 
144     // avoid T-junctions as they cause artifacts in between the resultant
145     // geometry when complex transforms occur.
146     // TODO: generate the safeRegion only if necessary based on drawing transform (see
147     // OpenGLRenderer::composeLayerRegion())
148     Region safeRegion = Region::createTJunctionFreeRegion(mLayer->region);
149 
150     size_t count;
151     const android::Rect* rects = safeRegion.getArray(&count);
152 
153     GLsizei elementCount = count * 6;
154 
155     if (mLayer->mesh && mLayer->meshElementCount < elementCount) {
156         delete[] mLayer->mesh;
157         delete[] mLayer->meshIndices;
158 
159         mLayer->mesh = NULL;
160         mLayer->meshIndices = NULL;
161     }
162 
163     bool rebuildIndices = false;
164     if (!mLayer->mesh) {
165         mLayer->mesh = new TextureVertex[count * 4];
166         mLayer->meshIndices = new uint16_t[elementCount];
167         rebuildIndices = true;
168     }
169     mLayer->meshElementCount = elementCount;
170 
171     const float texX = 1.0f / float(mLayer->getWidth());
172     const float texY = 1.0f / float(mLayer->getHeight());
173     const float height = mLayer->layer.getHeight();
174 
175     TextureVertex* mesh = mLayer->mesh;
176     uint16_t* indices = mLayer->meshIndices;
177 
178     for (size_t i = 0; i < count; i++) {
179         const android::Rect* r = &rects[i];
180 
181         const float u1 = r->left * texX;
182         const float v1 = (height - r->top) * texY;
183         const float u2 = r->right * texX;
184         const float v2 = (height - r->bottom) * texY;
185 
186         TextureVertex::set(mesh++, r->left, r->top, u1, v1);
187         TextureVertex::set(mesh++, r->right, r->top, u2, v1);
188         TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
189         TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
190 
191         if (rebuildIndices) {
192             uint16_t quad = i * 4;
193             int index = i * 6;
194             indices[index    ] = quad;       // top-left
195             indices[index + 1] = quad + 1;   // top-right
196             indices[index + 2] = quad + 2;   // bottom-left
197             indices[index + 3] = quad + 2;   // bottom-left
198             indices[index + 4] = quad + 1;   // top-right
199             indices[index + 5] = quad + 3;   // bottom-right
200         }
201     }
202 }
203 
204 ///////////////////////////////////////////////////////////////////////////////
205 // Layers management
206 ///////////////////////////////////////////////////////////////////////////////
207 
createLayer(uint32_t width,uint32_t height,bool isOpaque)208 Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque) {
209     LAYER_RENDERER_LOGD("Requesting new render layer %dx%d", width, height);
210 
211     Caches& caches = Caches::getInstance();
212     GLuint fbo = caches.fboCache.get();
213     if (!fbo) {
214         ALOGW("Could not obtain an FBO");
215         return NULL;
216     }
217 
218     caches.activeTexture(0);
219     Layer* layer = caches.layerCache.get(width, height);
220     if (!layer) {
221         ALOGW("Could not obtain a layer");
222         return NULL;
223     }
224 
225     // We first obtain a layer before comparing against the max texture size
226     // because layers are not allocated at the exact desired size. They are
227     // always created slighly larger to improve recycling
228     const uint32_t maxTextureSize = caches.maxTextureSize;
229     if (layer->getWidth() > maxTextureSize || layer->getHeight() > maxTextureSize) {
230         ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)",
231                 width, height, maxTextureSize, maxTextureSize);
232 
233         // Creating a new layer always increment its refcount by 1, this allows
234         // us to destroy the layer object if one was created for us
235         Caches::getInstance().resourceCache.decrementRefcount(layer);
236 
237         return NULL;
238     }
239 
240     layer->setFbo(fbo);
241     layer->layer.set(0.0f, 0.0f, width, height);
242     layer->texCoords.set(0.0f, height / float(layer->getHeight()),
243             width / float(layer->getWidth()), 0.0f);
244     layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
245     layer->setBlend(!isOpaque);
246     layer->setColorFilter(NULL);
247     layer->setDirty(true);
248     layer->region.clear();
249 
250     GLuint previousFbo;
251     glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
252 
253     glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo());
254     layer->bindTexture();
255 
256     // Initialize the texture if needed
257     if (layer->isEmpty()) {
258         layer->setEmpty(false);
259         layer->allocateTexture();
260 
261         // This should only happen if we run out of memory
262         if (glGetError() != GL_NO_ERROR) {
263             ALOGE("Could not allocate texture for layer (fbo=%d %dx%d)", fbo, width, height);
264             glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
265             caches.resourceCache.decrementRefcount(layer);
266             return NULL;
267         }
268     }
269 
270     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
271             layer->getTexture(), 0);
272 
273     glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
274 
275     return layer;
276 }
277 
resizeLayer(Layer * layer,uint32_t width,uint32_t height)278 bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) {
279     if (layer) {
280         LAYER_RENDERER_LOGD("Resizing layer fbo = %d to %dx%d", layer->getFbo(), width, height);
281 
282         if (layer->resize(width, height)) {
283             layer->layer.set(0.0f, 0.0f, width, height);
284             layer->texCoords.set(0.0f, height / float(layer->getHeight()),
285                     width / float(layer->getWidth()), 0.0f);
286         } else {
287             return false;
288         }
289     }
290 
291     return true;
292 }
293 
createTextureLayer(bool isOpaque)294 Layer* LayerRenderer::createTextureLayer(bool isOpaque) {
295     LAYER_RENDERER_LOGD("Creating new texture layer");
296 
297     Layer* layer = new Layer(0, 0);
298     layer->setCacheable(false);
299     layer->setTextureLayer(true);
300     layer->setBlend(!isOpaque);
301     layer->setEmpty(true);
302     layer->setFbo(0);
303     layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
304     layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f);
305     layer->texCoords.set(0.0f, 1.0f, 1.0f, 0.0f);
306     layer->region.clear();
307     layer->setRenderTarget(GL_NONE); // see ::updateTextureLayer()
308 
309     Caches::getInstance().activeTexture(0);
310     layer->generateTexture();
311 
312     return layer;
313 }
314 
updateTextureLayer(Layer * layer,uint32_t width,uint32_t height,bool isOpaque,GLenum renderTarget,float * transform)315 void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
316         bool isOpaque, GLenum renderTarget, float* transform) {
317     if (layer) {
318         layer->setBlend(!isOpaque);
319         layer->setSize(width, height);
320         layer->layer.set(0.0f, 0.0f, width, height);
321         layer->region.set(width, height);
322         layer->regionRect.set(0.0f, 0.0f, width, height);
323         layer->getTexTransform().load(transform);
324 
325         if (renderTarget != layer->getRenderTarget()) {
326             layer->setRenderTarget(renderTarget);
327             layer->bindTexture();
328             layer->setFilter(GL_NEAREST, false, true);
329             layer->setWrap(GL_CLAMP_TO_EDGE, false, true);
330         }
331     }
332 }
333 
destroyLayer(Layer * layer)334 void LayerRenderer::destroyLayer(Layer* layer) {
335     if (layer) {
336         LAYER_RENDERER_LOGD("Recycling layer, %dx%d fbo = %d",
337                 layer->getWidth(), layer->getHeight(), layer->getFbo());
338 
339         if (!Caches::getInstance().layerCache.put(layer)) {
340             LAYER_RENDERER_LOGD("  Destroyed!");
341             Caches::getInstance().resourceCache.decrementRefcount(layer);
342         } else {
343             LAYER_RENDERER_LOGD("  Cached!");
344 #if DEBUG_LAYER_RENDERER
345             Caches::getInstance().layerCache.dump();
346 #endif
347             layer->removeFbo();
348             layer->region.clear();
349         }
350     }
351 }
352 
destroyLayerDeferred(Layer * layer)353 void LayerRenderer::destroyLayerDeferred(Layer* layer) {
354     if (layer) {
355         LAYER_RENDERER_LOGD("Deferring layer destruction, fbo = %d", layer->getFbo());
356 
357         Caches::getInstance().deleteLayerDeferred(layer);
358     }
359 }
360 
flushLayer(Layer * layer)361 void LayerRenderer::flushLayer(Layer* layer) {
362 #ifdef GL_EXT_discard_framebuffer
363     GLuint fbo = layer->getFbo();
364     if (layer && fbo) {
365         // If possible, discard any enqueud operations on deferred
366         // rendering architectures
367         if (Extensions::getInstance().hasDiscardFramebuffer()) {
368             GLuint previousFbo;
369             glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
370             if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, fbo);
371 
372             const GLenum attachments[] = { GL_COLOR_ATTACHMENT0 };
373             glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments);
374 
375             if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
376         }
377     }
378 #endif
379 }
380 
copyLayer(Layer * layer,SkBitmap * bitmap)381 bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) {
382     Caches& caches = Caches::getInstance();
383     if (layer && bitmap->width() <= caches.maxTextureSize &&
384             bitmap->height() <= caches.maxTextureSize) {
385 
386         GLuint fbo = caches.fboCache.get();
387         if (!fbo) {
388             ALOGW("Could not obtain an FBO");
389             return false;
390         }
391 
392         SkAutoLockPixels alp(*bitmap);
393 
394         GLuint texture;
395         GLuint previousFbo;
396         GLuint previousViewport[4];
397 
398         GLenum format;
399         GLenum type;
400 
401         GLenum error = GL_NO_ERROR;
402         bool status = false;
403 
404         switch (bitmap->config()) {
405             case SkBitmap::kA8_Config:
406                 format = GL_ALPHA;
407                 type = GL_UNSIGNED_BYTE;
408                 break;
409             case SkBitmap::kRGB_565_Config:
410                 format = GL_RGB;
411                 type = GL_UNSIGNED_SHORT_5_6_5;
412                 break;
413             case SkBitmap::kARGB_4444_Config:
414                 format = GL_RGBA;
415                 type = GL_UNSIGNED_SHORT_4_4_4_4;
416                 break;
417             case SkBitmap::kARGB_8888_Config:
418             default:
419                 format = GL_RGBA;
420                 type = GL_UNSIGNED_BYTE;
421                 break;
422         }
423 
424         float alpha = layer->getAlpha();
425         SkXfermode::Mode mode = layer->getMode();
426         GLuint previousLayerFbo = layer->getFbo();
427 
428         layer->setAlpha(255, SkXfermode::kSrc_Mode);
429         layer->setFbo(fbo);
430 
431         glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
432         glGetIntegerv(GL_VIEWPORT, (GLint*) &previousViewport);
433         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
434 
435         glGenTextures(1, &texture);
436         if ((error = glGetError()) != GL_NO_ERROR) goto error;
437 
438         caches.activeTexture(0);
439         glBindTexture(GL_TEXTURE_2D, texture);
440 
441         glPixelStorei(GL_PACK_ALIGNMENT, bitmap->bytesPerPixel());
442 
443         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
444         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
445 
446         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
447         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
448 
449         glTexImage2D(GL_TEXTURE_2D, 0, format, bitmap->width(), bitmap->height(),
450                 0, format, type, NULL);
451         if ((error = glGetError()) != GL_NO_ERROR) goto error;
452 
453         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
454                 GL_TEXTURE_2D, texture, 0);
455         if ((error = glGetError()) != GL_NO_ERROR) goto error;
456 
457         {
458             LayerRenderer renderer(layer);
459             renderer.setViewport(bitmap->width(), bitmap->height());
460             renderer.OpenGLRenderer::prepareDirty(0.0f, 0.0f,
461                     bitmap->width(), bitmap->height(), !layer->isBlend());
462 
463             caches.disableScissor();
464             renderer.translate(0.0f, bitmap->height());
465             renderer.scale(1.0f, -1.0f);
466 
467             mat4 texTransform(layer->getTexTransform());
468 
469             mat4 invert;
470             invert.translate(0.0f, 1.0f, 0.0f);
471             invert.scale(1.0f, -1.0f, 1.0f);
472             layer->getTexTransform().multiply(invert);
473 
474             if ((error = glGetError()) != GL_NO_ERROR) goto error;
475 
476             {
477                 Rect bounds;
478                 bounds.set(0.0f, 0.0f, bitmap->width(), bitmap->height());
479                 renderer.drawTextureLayer(layer, bounds);
480 
481                 glReadPixels(0, 0, bitmap->width(), bitmap->height(), format,
482                         type, bitmap->getPixels());
483 
484                 if ((error = glGetError()) != GL_NO_ERROR) goto error;
485             }
486 
487             layer->getTexTransform().load(texTransform);
488             status = true;
489         }
490 
491 error:
492 #if DEBUG_OPENGL
493         if (error != GL_NO_ERROR) {
494             ALOGD("GL error while copying layer into bitmap = 0x%x", error);
495         }
496 #endif
497 
498         glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
499         layer->setAlpha(alpha, mode);
500         layer->setFbo(previousLayerFbo);
501         glDeleteTextures(1, &texture);
502         caches.fboCache.put(fbo);
503         glViewport(previousViewport[0], previousViewport[1],
504                 previousViewport[2], previousViewport[3]);
505 
506         return status;
507     }
508     return false;
509 }
510 
511 }; // namespace uirenderer
512 }; // namespace android
513