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