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