OpenGLRenderer.cpp revision e190aa69756aecfaffabdd4c6d32cb6b3220d842
1/* 2 * Copyright (C) 2010 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 <stdlib.h> 20#include <stdint.h> 21#include <sys/types.h> 22 23#include <SkCanvas.h> 24#include <SkTypeface.h> 25 26#include <utils/Log.h> 27#include <utils/StopWatch.h> 28 29#include <ui/Rect.h> 30 31#include "OpenGLRenderer.h" 32#include "DisplayListRenderer.h" 33 34namespace android { 35namespace uirenderer { 36 37/////////////////////////////////////////////////////////////////////////////// 38// Defines 39/////////////////////////////////////////////////////////////////////////////// 40 41#define RAD_TO_DEG (180.0f / 3.14159265f) 42#define MIN_ANGLE 0.001f 43 44// TODO: This should be set in properties 45#define ALPHA_THRESHOLD (0x7f / PANEL_BIT_DEPTH) 46 47/////////////////////////////////////////////////////////////////////////////// 48// Globals 49/////////////////////////////////////////////////////////////////////////////// 50 51/** 52 * Structure mapping Skia xfermodes to OpenGL blending factors. 53 */ 54struct Blender { 55 SkXfermode::Mode mode; 56 GLenum src; 57 GLenum dst; 58}; // struct Blender 59 60// In this array, the index of each Blender equals the value of the first 61// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode] 62static const Blender gBlends[] = { 63 { SkXfermode::kClear_Mode, GL_ZERO, GL_ZERO }, 64 { SkXfermode::kSrc_Mode, GL_ONE, GL_ZERO }, 65 { SkXfermode::kDst_Mode, GL_ZERO, GL_ONE }, 66 { SkXfermode::kSrcOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, 67 { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE }, 68 { SkXfermode::kSrcIn_Mode, GL_DST_ALPHA, GL_ZERO }, 69 { SkXfermode::kDstIn_Mode, GL_ZERO, GL_SRC_ALPHA }, 70 { SkXfermode::kSrcOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, 71 { SkXfermode::kDstOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, 72 { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, 73 { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, 74 { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA } 75}; 76 77// This array contains the swapped version of each SkXfermode. For instance 78// this array's SrcOver blending mode is actually DstOver. You can refer to 79// createLayer() for more information on the purpose of this array. 80static const Blender gBlendsSwap[] = { 81 { SkXfermode::kClear_Mode, GL_ZERO, GL_ZERO }, 82 { SkXfermode::kSrc_Mode, GL_ZERO, GL_ONE }, 83 { SkXfermode::kDst_Mode, GL_ONE, GL_ZERO }, 84 { SkXfermode::kSrcOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE }, 85 { SkXfermode::kDstOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, 86 { SkXfermode::kSrcIn_Mode, GL_ZERO, GL_SRC_ALPHA }, 87 { SkXfermode::kDstIn_Mode, GL_DST_ALPHA, GL_ZERO }, 88 { SkXfermode::kSrcOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, 89 { SkXfermode::kDstOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, 90 { SkXfermode::kSrcATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, 91 { SkXfermode::kDstATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, 92 { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA } 93}; 94 95static const GLenum gTextureUnits[] = { 96 GL_TEXTURE0, 97 GL_TEXTURE1, 98 GL_TEXTURE2 99}; 100 101/////////////////////////////////////////////////////////////////////////////// 102// Constructors/destructor 103/////////////////////////////////////////////////////////////////////////////// 104 105OpenGLRenderer::OpenGLRenderer(): mCaches(Caches::getInstance()) { 106 mShader = NULL; 107 mColorFilter = NULL; 108 mHasShadow = false; 109 110 memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices)); 111 112 mFirstSnapshot = new Snapshot; 113} 114 115OpenGLRenderer::~OpenGLRenderer() { 116 // The context has already been destroyed at this point, do not call 117 // GL APIs. All GL state should be kept in Caches.h 118} 119 120/////////////////////////////////////////////////////////////////////////////// 121// Setup 122/////////////////////////////////////////////////////////////////////////////// 123 124void OpenGLRenderer::setViewport(int width, int height) { 125 glViewport(0, 0, width, height); 126 mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1); 127 128 mWidth = width; 129 mHeight = height; 130 131 mFirstSnapshot->height = height; 132 mFirstSnapshot->viewport.set(0, 0, width, height); 133 134 mDirtyClip = false; 135} 136 137void OpenGLRenderer::prepare(bool opaque) { 138 mSnapshot = new Snapshot(mFirstSnapshot, 139 SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); 140 mSaveCount = 1; 141 142 glViewport(0, 0, mWidth, mHeight); 143 144 glDisable(GL_DITHER); 145 146 if (!opaque) { 147 glDisable(GL_SCISSOR_TEST); 148 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 149 glClear(GL_COLOR_BUFFER_BIT); 150 } 151 152 glEnable(GL_SCISSOR_TEST); 153 glScissor(0, 0, mWidth, mHeight); 154 mSnapshot->setClip(0.0f, 0.0f, mWidth, mHeight); 155} 156 157void OpenGLRenderer::finish() { 158#if DEBUG_OPENGL 159 GLenum status = GL_NO_ERROR; 160 while ((status = glGetError()) != GL_NO_ERROR) { 161 LOGD("GL error from OpenGLRenderer: 0x%x", status); 162 } 163#endif 164#if DEBUG_MEMORY_USAGE 165 mCaches.dumpMemoryUsage(); 166#else 167 if (mCaches.getDebugLevel() & kDebugMemory) { 168 mCaches.dumpMemoryUsage(); 169 } 170#endif 171} 172 173void OpenGLRenderer::acquireContext() { 174 if (mCaches.currentProgram) { 175 if (mCaches.currentProgram->isInUse()) { 176 mCaches.currentProgram->remove(); 177 mCaches.currentProgram = NULL; 178 } 179 } 180 mCaches.unbindMeshBuffer(); 181} 182 183void OpenGLRenderer::releaseContext() { 184 glViewport(0, 0, mSnapshot->viewport.getWidth(), mSnapshot->viewport.getHeight()); 185 186 glEnable(GL_SCISSOR_TEST); 187 dirtyClip(); 188 189 glDisable(GL_DITHER); 190 191 glBindFramebuffer(GL_FRAMEBUFFER, 0); 192 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 193 194 mCaches.blend = true; 195 glEnable(GL_BLEND); 196 glBlendFunc(mCaches.lastSrcMode, mCaches.lastDstMode); 197 glBlendEquation(GL_FUNC_ADD); 198} 199 200/////////////////////////////////////////////////////////////////////////////// 201// State management 202/////////////////////////////////////////////////////////////////////////////// 203 204int OpenGLRenderer::getSaveCount() const { 205 return mSaveCount; 206} 207 208int OpenGLRenderer::save(int flags) { 209 return saveSnapshot(flags); 210} 211 212void OpenGLRenderer::restore() { 213 if (mSaveCount > 1) { 214 restoreSnapshot(); 215 } 216} 217 218void OpenGLRenderer::restoreToCount(int saveCount) { 219 if (saveCount < 1) saveCount = 1; 220 221 while (mSaveCount > saveCount) { 222 restoreSnapshot(); 223 } 224} 225 226int OpenGLRenderer::saveSnapshot(int flags) { 227 mSnapshot = new Snapshot(mSnapshot, flags); 228 return mSaveCount++; 229} 230 231bool OpenGLRenderer::restoreSnapshot() { 232 bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet; 233 bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer; 234 bool restoreOrtho = mSnapshot->flags & Snapshot::kFlagDirtyOrtho; 235 236 sp<Snapshot> current = mSnapshot; 237 sp<Snapshot> previous = mSnapshot->previous; 238 239 if (restoreOrtho) { 240 Rect& r = previous->viewport; 241 glViewport(r.left, r.top, r.right, r.bottom); 242 mOrthoMatrix.load(current->orthoMatrix); 243 } 244 245 mSaveCount--; 246 mSnapshot = previous; 247 248 if (restoreClip) { 249 dirtyClip(); 250 } 251 252 if (restoreLayer) { 253 composeLayer(current, previous); 254 } 255 256 return restoreClip; 257} 258 259/////////////////////////////////////////////////////////////////////////////// 260// Layers 261/////////////////////////////////////////////////////////////////////////////// 262 263int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom, 264 SkPaint* p, int flags) { 265 const GLuint previousFbo = mSnapshot->fbo; 266 const int count = saveSnapshot(flags); 267 268 if (!mSnapshot->invisible) { 269 int alpha = 255; 270 SkXfermode::Mode mode; 271 272 if (p) { 273 alpha = p->getAlpha(); 274 if (!mCaches.extensions.hasFramebufferFetch()) { 275 const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode); 276 if (!isMode) { 277 // Assume SRC_OVER 278 mode = SkXfermode::kSrcOver_Mode; 279 } 280 } else { 281 mode = getXfermode(p->getXfermode()); 282 } 283 } else { 284 mode = SkXfermode::kSrcOver_Mode; 285 } 286 287 createLayer(mSnapshot, left, top, right, bottom, alpha, mode, flags, previousFbo); 288 } 289 290 return count; 291} 292 293int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom, 294 int alpha, int flags) { 295 if (alpha >= 255 - ALPHA_THRESHOLD) { 296 return saveLayer(left, top, right, bottom, NULL, flags); 297 } else { 298 SkPaint paint; 299 paint.setAlpha(alpha); 300 return saveLayer(left, top, right, bottom, &paint, flags); 301 } 302} 303 304/** 305 * Layers are viewed by Skia are slightly different than layers in image editing 306 * programs (for instance.) When a layer is created, previously created layers 307 * and the frame buffer still receive every drawing command. For instance, if a 308 * layer is created and a shape intersecting the bounds of the layers and the 309 * framebuffer is draw, the shape will be drawn on both (unless the layer was 310 * created with the SkCanvas::kClipToLayer_SaveFlag flag.) 311 * 312 * A way to implement layers is to create an FBO for each layer, backed by an RGBA 313 * texture. Unfortunately, this is inefficient as it requires every primitive to 314 * be drawn n + 1 times, where n is the number of active layers. In practice this 315 * means, for every primitive: 316 * - Switch active frame buffer 317 * - Change viewport, clip and projection matrix 318 * - Issue the drawing 319 * 320 * Switching rendering target n + 1 times per drawn primitive is extremely costly. 321 * To avoid this, layers are implemented in a different way here, at least in the 322 * general case. FBOs are used, as an optimization, when the "clip to layer" flag 323 * is set. When this flag is set we can redirect all drawing operations into a 324 * single FBO. 325 * 326 * This implementation relies on the frame buffer being at least RGBA 8888. When 327 * a layer is created, only a texture is created, not an FBO. The content of the 328 * frame buffer contained within the layer's bounds is copied into this texture 329 * using glCopyTexImage2D(). The layer's region is then cleared(1) in the frame 330 * buffer and drawing continues as normal. This technique therefore treats the 331 * frame buffer as a scratch buffer for the layers. 332 * 333 * To compose the layers back onto the frame buffer, each layer texture 334 * (containing the original frame buffer data) is drawn as a simple quad over 335 * the frame buffer. The trick is that the quad is set as the composition 336 * destination in the blending equation, and the frame buffer becomes the source 337 * of the composition. 338 * 339 * Drawing layers with an alpha value requires an extra step before composition. 340 * An empty quad is drawn over the layer's region in the frame buffer. This quad 341 * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the 342 * quad is used to multiply the colors in the frame buffer. This is achieved by 343 * changing the GL blend functions for the GL_FUNC_ADD blend equation to 344 * GL_ZERO, GL_SRC_ALPHA. 345 * 346 * Because glCopyTexImage2D() can be slow, an alternative implementation might 347 * be use to draw a single clipped layer. The implementation described above 348 * is correct in every case. 349 * 350 * (1) The frame buffer is actually not cleared right away. To allow the GPU 351 * to potentially optimize series of calls to glCopyTexImage2D, the frame 352 * buffer is left untouched until the first drawing operation. Only when 353 * something actually gets drawn are the layers regions cleared. 354 */ 355bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, 356 float right, float bottom, int alpha, SkXfermode::Mode mode, 357 int flags, GLuint previousFbo) { 358 LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top); 359 LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize()); 360 361 const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag; 362 363 // Window coordinates of the layer 364 Rect bounds(left, top, right, bottom); 365 if (fboLayer) { 366 // Clear the previous layer regions before we change the viewport 367 clearLayerRegions(); 368 } else { 369 mSnapshot->transform->mapRect(bounds); 370 371 // Layers only make sense if they are in the framebuffer's bounds 372 bounds.intersect(*snapshot->clipRect); 373 374 // We cannot work with sub-pixels in this case 375 bounds.snapToPixelBoundaries(); 376 377 // When the layer is not an FBO, we may use glCopyTexImage so we 378 // need to make sure the layer does not extend outside the bounds 379 // of the framebuffer 380 bounds.intersect(snapshot->previous->viewport); 381 } 382 383 if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize || 384 bounds.getHeight() > mCaches.maxTextureSize) { 385 snapshot->invisible = true; 386 } else { 387 snapshot->invisible = snapshot->invisible || (alpha <= ALPHA_THRESHOLD && fboLayer); 388 } 389 390 // Bail out if we won't draw in this snapshot 391 if (snapshot->invisible) { 392 return false; 393 } 394 395 glActiveTexture(gTextureUnits[0]); 396 Layer* layer = mCaches.layerCache.get(bounds.getWidth(), bounds.getHeight()); 397 if (!layer) { 398 return false; 399 } 400 401 layer->mode = mode; 402 layer->alpha = alpha; 403 layer->layer.set(bounds); 404 layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->height), 405 bounds.getWidth() / float(layer->width), 0.0f); 406 407 // Save the layer in the snapshot 408 snapshot->flags |= Snapshot::kFlagIsLayer; 409 snapshot->layer = layer; 410 411 if (fboLayer) { 412 return createFboLayer(layer, bounds, snapshot, previousFbo); 413 } else { 414 // Copy the framebuffer into the layer 415 glBindTexture(GL_TEXTURE_2D, layer->texture); 416 417 if (layer->empty) { 418 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left, 419 snapshot->height - bounds.bottom, layer->width, layer->height, 0); 420 layer->empty = false; 421 } else { 422 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left, 423 snapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight()); 424 } 425 426 // Enqueue the buffer coordinates to clear the corresponding region later 427 mLayers.push(new Rect(bounds)); 428 } 429 430 return true; 431} 432 433bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> snapshot, 434 GLuint previousFbo) { 435 layer->fbo = mCaches.fboCache.get(); 436 437#if RENDER_LAYERS_AS_REGIONS 438 snapshot->region = &snapshot->layer->region; 439 snapshot->flags |= Snapshot::kFlagFboTarget; 440#endif 441 442 Rect clip(bounds); 443 snapshot->transform->mapRect(clip); 444 clip.intersect(*snapshot->clipRect); 445 clip.snapToPixelBoundaries(); 446 clip.intersect(snapshot->previous->viewport); 447 448 mat4 inverse; 449 inverse.loadInverse(*mSnapshot->transform); 450 451 inverse.mapRect(clip); 452 clip.snapToPixelBoundaries(); 453 clip.intersect(bounds); 454 clip.translate(-bounds.left, -bounds.top); 455 456 snapshot->flags |= Snapshot::kFlagIsFboLayer; 457 snapshot->fbo = layer->fbo; 458 snapshot->resetTransform(-bounds.left, -bounds.top, 0.0f); 459 //snapshot->resetClip(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight()); 460 snapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom); 461 snapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight()); 462 snapshot->height = bounds.getHeight(); 463 snapshot->flags |= Snapshot::kFlagDirtyOrtho; 464 snapshot->orthoMatrix.load(mOrthoMatrix); 465 466 // Bind texture to FBO 467 glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo); 468 glBindTexture(GL_TEXTURE_2D, layer->texture); 469 470 // Initialize the texture if needed 471 if (layer->empty) { 472 layer->empty = false; 473 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->width, layer->height, 0, 474 GL_RGBA, GL_UNSIGNED_BYTE, NULL); 475 } 476 477 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 478 layer->texture, 0); 479 480#if DEBUG_LAYERS_AS_REGIONS 481 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 482 if (status != GL_FRAMEBUFFER_COMPLETE) { 483 LOGE("Framebuffer incomplete (GL error code 0x%x)", status); 484 485 glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); 486 glDeleteTextures(1, &layer->texture); 487 mCaches.fboCache.put(layer->fbo); 488 489 delete layer; 490 491 return false; 492 } 493#endif 494 495 // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering 496 glScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f, 497 clip.getWidth() + 2.0f, clip.getHeight() + 2.0f); 498 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 499 glClear(GL_COLOR_BUFFER_BIT); 500 501 dirtyClip(); 502 503 // Change the ortho projection 504 glViewport(0, 0, bounds.getWidth(), bounds.getHeight()); 505 mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f); 506 507 return true; 508} 509 510/** 511 * Read the documentation of createLayer() before doing anything in this method. 512 */ 513void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { 514 if (!current->layer) { 515 LOGE("Attempting to compose a layer that does not exist"); 516 return; 517 } 518 519 const bool fboLayer = current->flags & Snapshot::kFlagIsFboLayer; 520 521 if (fboLayer) { 522 // Unbind current FBO and restore previous one 523 glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo); 524 } 525 526 Layer* layer = current->layer; 527 const Rect& rect = layer->layer; 528 529 if (!fboLayer && layer->alpha < 255) { 530 drawColorRect(rect.left, rect.top, rect.right, rect.bottom, 531 layer->alpha << 24, SkXfermode::kDstIn_Mode, true); 532 // Required below, composeLayerRect() will divide by 255 533 layer->alpha = 255; 534 } 535 536 mCaches.unbindMeshBuffer(); 537 538 glActiveTexture(gTextureUnits[0]); 539 540 // When the layer is stored in an FBO, we can save a bit of fillrate by 541 // drawing only the dirty region 542 if (fboLayer) { 543 dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *previous->transform); 544 composeLayerRegion(layer, rect); 545 } else { 546 dirtyLayer(rect.left, rect.top, rect.right, rect.bottom); 547 composeLayerRect(layer, rect, true); 548 } 549 550 if (fboLayer) { 551 // Detach the texture from the FBO 552 glBindFramebuffer(GL_FRAMEBUFFER, current->fbo); 553 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); 554 glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo); 555 556 // Put the FBO name back in the cache, if it doesn't fit, it will be destroyed 557 mCaches.fboCache.put(current->fbo); 558 } 559 560 dirtyClip(); 561 562 // Failing to add the layer to the cache should happen only if the layer is too large 563 if (!mCaches.layerCache.put(layer)) { 564 LAYER_LOGD("Deleting layer"); 565 glDeleteTextures(1, &layer->texture); 566 delete layer; 567 } 568} 569 570void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) { 571 const Rect& texCoords = layer->texCoords; 572 resetDrawTextureTexCoords(texCoords.left, texCoords.top, texCoords.right, texCoords.bottom); 573 574 drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture, 575 layer->alpha / 255.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0], 576 &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, swap, swap); 577 578 resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); 579} 580 581void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { 582#if RENDER_LAYERS_AS_REGIONS 583 if (layer->region.isRect()) { 584 composeLayerRect(layer, rect); 585 layer->region.clear(); 586 return; 587 } 588 589 if (!layer->region.isEmpty()) { 590 size_t count; 591 const android::Rect* rects = layer->region.getArray(&count); 592 593 setupDraw(); 594 595 ProgramDescription description; 596 description.hasTexture = true; 597 598 const float alpha = layer->alpha / 255.0f; 599 const bool setColor = description.setColor(alpha, alpha, alpha, alpha); 600 chooseBlending(layer->blend || layer->alpha < 255, layer->mode, description, false); 601 602 useProgram(mCaches.programCache.get(description)); 603 604 // Texture 605 bindTexture(layer->texture); 606 glUniform1i(mCaches.currentProgram->getUniform("sampler"), 0); 607 608 // Always premultiplied 609 if (setColor) { 610 mCaches.currentProgram->setColor(alpha, alpha, alpha, alpha); 611 } 612 613 // Mesh 614 int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords"); 615 glEnableVertexAttribArray(texCoordsSlot); 616 617 mModelView.loadIdentity(); 618 mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); 619 620 const float texX = 1.0f / float(layer->width); 621 const float texY = 1.0f / float(layer->height); 622 623 TextureVertex* mesh = mCaches.getRegionMesh(); 624 GLsizei numQuads = 0; 625 626 glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, 627 gMeshStride, &mesh[0].position[0]); 628 glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, 629 gMeshStride, &mesh[0].texture[0]); 630 631 for (size_t i = 0; i < count; i++) { 632 const android::Rect* r = &rects[i]; 633 634 const float u1 = r->left * texX; 635 const float v1 = (rect.getHeight() - r->top) * texY; 636 const float u2 = r->right * texX; 637 const float v2 = (rect.getHeight() - r->bottom) * texY; 638 639 // TODO: Reject quads outside of the clip 640 TextureVertex::set(mesh++, r->left, r->top, u1, v1); 641 TextureVertex::set(mesh++, r->right, r->top, u2, v1); 642 TextureVertex::set(mesh++, r->left, r->bottom, u1, v2); 643 TextureVertex::set(mesh++, r->right, r->bottom, u2, v2); 644 645 numQuads++; 646 647 if (numQuads >= REGION_MESH_QUAD_COUNT) { 648 glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL); 649 numQuads = 0; 650 mesh = mCaches.getRegionMesh(); 651 } 652 } 653 654 if (numQuads > 0) { 655 glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL); 656 } 657 658 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 659 glDisableVertexAttribArray(texCoordsSlot); 660 661#if DEBUG_LAYERS_AS_REGIONS 662 uint32_t colors[] = { 663 0x7fff0000, 0x7f00ff00, 664 0x7f0000ff, 0x7fff00ff, 665 }; 666 667 int offset = 0; 668 int32_t top = rects[0].top; 669 int i = 0; 670 671 for (size_t i = 0; i < count; i++) { 672 if (top != rects[i].top) { 673 offset ^= 0x2; 674 top = rects[i].top; 675 } 676 677 Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom); 678 drawColorRect(r.left, r.top, r.right, r.bottom, colors[offset + (i & 0x1)], 679 SkXfermode::kSrcOver_Mode); 680 } 681#endif 682 683 layer->region.clear(); 684 } 685#else 686 composeLayerRect(layer, rect); 687#endif 688} 689 690void OpenGLRenderer::dirtyLayer(const float left, const float top, 691 const float right, const float bottom, const mat4 transform) { 692#if RENDER_LAYERS_AS_REGIONS 693 if ((mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region) { 694 Rect bounds(left, top, right, bottom); 695 transform.mapRect(bounds); 696 bounds.intersect(*mSnapshot->clipRect); 697 bounds.snapToPixelBoundaries(); 698 699 android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom); 700 if (!dirty.isEmpty()) { 701 mSnapshot->region->orSelf(dirty); 702 } 703 } 704#endif 705} 706 707void OpenGLRenderer::dirtyLayer(const float left, const float top, 708 const float right, const float bottom) { 709#if RENDER_LAYERS_AS_REGIONS 710 if ((mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region) { 711 Rect bounds(left, top, right, bottom); 712 bounds.intersect(*mSnapshot->clipRect); 713 bounds.snapToPixelBoundaries(); 714 715 android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom); 716 if (!dirty.isEmpty()) { 717 mSnapshot->region->orSelf(dirty); 718 } 719 } 720#endif 721} 722 723void OpenGLRenderer::setupDraw() { 724 clearLayerRegions(); 725 if (mDirtyClip) { 726 setScissorFromClip(); 727 } 728} 729 730void OpenGLRenderer::clearLayerRegions() { 731 if (mLayers.size() == 0 || mSnapshot->invisible) return; 732 733 Rect clipRect(*mSnapshot->clipRect); 734 clipRect.snapToPixelBoundaries(); 735 736 for (uint32_t i = 0; i < mLayers.size(); i++) { 737 Rect* bounds = mLayers.itemAt(i); 738 if (clipRect.intersects(*bounds)) { 739 // Clear the framebuffer where the layer will draw 740 glScissor(bounds->left, mSnapshot->height - bounds->bottom, 741 bounds->getWidth(), bounds->getHeight()); 742 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 743 glClear(GL_COLOR_BUFFER_BIT); 744 745 // Restore the clip 746 dirtyClip(); 747 } 748 749 delete bounds; 750 } 751 752 mLayers.clear(); 753} 754 755/////////////////////////////////////////////////////////////////////////////// 756// Transforms 757/////////////////////////////////////////////////////////////////////////////// 758 759void OpenGLRenderer::translate(float dx, float dy) { 760 mSnapshot->transform->translate(dx, dy, 0.0f); 761} 762 763void OpenGLRenderer::rotate(float degrees) { 764 mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f); 765} 766 767void OpenGLRenderer::scale(float sx, float sy) { 768 mSnapshot->transform->scale(sx, sy, 1.0f); 769} 770 771void OpenGLRenderer::setMatrix(SkMatrix* matrix) { 772 mSnapshot->transform->load(*matrix); 773} 774 775const float* OpenGLRenderer::getMatrix() const { 776 if (mSnapshot->fbo != 0) { 777 return &mSnapshot->transform->data[0]; 778 } 779 return &mIdentity.data[0]; 780} 781 782void OpenGLRenderer::getMatrix(SkMatrix* matrix) { 783 mSnapshot->transform->copyTo(*matrix); 784} 785 786void OpenGLRenderer::concatMatrix(SkMatrix* matrix) { 787 SkMatrix transform; 788 mSnapshot->transform->copyTo(transform); 789 transform.preConcat(*matrix); 790 mSnapshot->transform->load(transform); 791} 792 793/////////////////////////////////////////////////////////////////////////////// 794// Clipping 795/////////////////////////////////////////////////////////////////////////////// 796 797void OpenGLRenderer::setScissorFromClip() { 798 Rect clip(*mSnapshot->clipRect); 799 clip.snapToPixelBoundaries(); 800 glScissor(clip.left, mSnapshot->height - clip.bottom, clip.getWidth(), clip.getHeight()); 801 mDirtyClip = false; 802} 803 804const Rect& OpenGLRenderer::getClipBounds() { 805 return mSnapshot->getLocalClip(); 806} 807 808bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) { 809 if (mSnapshot->invisible) { 810 return true; 811 } 812 813 Rect r(left, top, right, bottom); 814 mSnapshot->transform->mapRect(r); 815 r.snapToPixelBoundaries(); 816 817 Rect clipRect(*mSnapshot->clipRect); 818 clipRect.snapToPixelBoundaries(); 819 820 return !clipRect.intersects(r); 821} 822 823bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { 824 bool clipped = mSnapshot->clip(left, top, right, bottom, op); 825 if (clipped) { 826 dirtyClip(); 827 } 828 return !mSnapshot->clipRect->isEmpty(); 829} 830 831/////////////////////////////////////////////////////////////////////////////// 832// Drawing 833/////////////////////////////////////////////////////////////////////////////// 834 835void OpenGLRenderer::drawDisplayList(DisplayList* displayList) { 836 // All the usual checks and setup operations (quickReject, setupDraw, etc.) 837 // will be performed by the display list itself 838 if (displayList) { 839 displayList->replay(*this); 840 } 841} 842 843void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) { 844 const float right = left + bitmap->width(); 845 const float bottom = top + bitmap->height(); 846 847 if (quickReject(left, top, right, bottom)) { 848 return; 849 } 850 851 glActiveTexture(GL_TEXTURE0); 852 Texture* texture = mCaches.textureCache.get(bitmap); 853 if (!texture) return; 854 const AutoTexture autoCleanup(texture); 855 856 drawTextureRect(left, top, right, bottom, texture, paint); 857} 858 859void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) { 860 Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height()); 861 const mat4 transform(*matrix); 862 transform.mapRect(r); 863 864 if (quickReject(r.left, r.top, r.right, r.bottom)) { 865 return; 866 } 867 868 glActiveTexture(GL_TEXTURE0); 869 Texture* texture = mCaches.textureCache.get(bitmap); 870 if (!texture) return; 871 const AutoTexture autoCleanup(texture); 872 873 // This could be done in a cheaper way, all we need is pass the matrix 874 // to the vertex shader. The save/restore is a bit overkill. 875 save(SkCanvas::kMatrix_SaveFlag); 876 concatMatrix(matrix); 877 drawTextureRect(0.0f, 0.0f, bitmap->width(), bitmap->height(), texture, paint); 878 restore(); 879} 880 881void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, 882 float srcLeft, float srcTop, float srcRight, float srcBottom, 883 float dstLeft, float dstTop, float dstRight, float dstBottom, 884 SkPaint* paint) { 885 if (quickReject(dstLeft, dstTop, dstRight, dstBottom)) { 886 return; 887 } 888 889 glActiveTexture(gTextureUnits[0]); 890 Texture* texture = mCaches.textureCache.get(bitmap); 891 if (!texture) return; 892 const AutoTexture autoCleanup(texture); 893 setTextureWrapModes(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 894 895 const float width = texture->width; 896 const float height = texture->height; 897 898 const float u1 = srcLeft / width; 899 const float v1 = srcTop / height; 900 const float u2 = srcRight / width; 901 const float v2 = srcBottom / height; 902 903 mCaches.unbindMeshBuffer(); 904 resetDrawTextureTexCoords(u1, v1, u2, v2); 905 906 int alpha; 907 SkXfermode::Mode mode; 908 getAlphaAndMode(paint, &alpha, &mode); 909 910 drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom, texture->id, alpha / 255.0f, 911 mode, texture->blend, &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], 912 GL_TRIANGLE_STRIP, gMeshCount); 913 914 resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); 915} 916 917void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, 918 const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, 919 float left, float top, float right, float bottom, SkPaint* paint) { 920 if (quickReject(left, top, right, bottom)) { 921 return; 922 } 923 924 glActiveTexture(gTextureUnits[0]); 925 Texture* texture = mCaches.textureCache.get(bitmap); 926 if (!texture) return; 927 const AutoTexture autoCleanup(texture); 928 setTextureWrapModes(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 929 930 int alpha; 931 SkXfermode::Mode mode; 932 getAlphaAndMode(paint, &alpha, &mode); 933 934 const Patch* mesh = mCaches.patchCache.get(bitmap->width(), bitmap->height(), 935 right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors); 936 937 if (mesh) { 938 // Mark the current layer dirty where we are going to draw the patch 939 if ((mSnapshot->flags & Snapshot::kFlagFboTarget) && 940 mSnapshot->region && mesh->hasEmptyQuads) { 941 const size_t count = mesh->quads.size(); 942 for (size_t i = 0; i < count; i++) { 943 Rect bounds = mesh->quads.itemAt(i); 944 dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, 945 *mSnapshot->transform); 946 } 947 } 948 949 drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, 950 mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset, 951 GL_TRIANGLES, mesh->verticesCount, false, false, mesh->meshBuffer, 952 true, !mesh->hasEmptyQuads); 953 } 954} 955 956void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { 957 // TODO: Should do quickReject for each line 958 if (mSnapshot->invisible) return; 959 960 setupDraw(); 961 962 int alpha; 963 SkXfermode::Mode mode; 964 getAlphaAndMode(paint, &alpha, &mode); 965 966 uint32_t color = paint->getColor(); 967 const GLfloat a = alpha / 255.0f; 968 const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f; 969 const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f; 970 const GLfloat b = a * ((color ) & 0xFF) / 255.0f; 971 972 const bool isAA = paint->isAntiAlias(); 973 if (isAA) { 974 GLuint textureUnit = 0; 975 glActiveTexture(gTextureUnits[textureUnit]); 976 setupTextureAlpha8(mCaches.line.getTexture(), 0, 0, textureUnit, 0.0f, 0.0f, r, g, b, a, 977 mode, false, true, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset, 978 mCaches.line.getMeshBuffer()); 979 } else { 980 setupColorRect(0.0f, 0.0f, 1.0f, 1.0f, r, g, b, a, mode, false, true); 981 } 982 983 const float strokeWidth = paint->getStrokeWidth(); 984 const GLsizei elementsCount = isAA ? mCaches.line.getElementsCount() : gMeshCount; 985 const GLenum drawMode = isAA ? GL_TRIANGLES : GL_TRIANGLE_STRIP; 986 987 for (int i = 0; i < count; i += 4) { 988 float tx = 0.0f; 989 float ty = 0.0f; 990 991 if (isAA) { 992 mCaches.line.update(points[i], points[i + 1], points[i + 2], points[i + 3], 993 strokeWidth, tx, ty); 994 } else { 995 ty = strokeWidth <= 1.0f ? 0.0f : -strokeWidth * 0.5f; 996 } 997 998 const float dx = points[i + 2] - points[i]; 999 const float dy = points[i + 3] - points[i + 1]; 1000 const float mag = sqrtf(dx * dx + dy * dy); 1001 const float angle = acos(dx / mag); 1002 1003 mModelView.loadTranslate(points[i], points[i + 1], 0.0f); 1004 if (angle > MIN_ANGLE || angle < -MIN_ANGLE) { 1005 mModelView.rotate(angle * RAD_TO_DEG, 0.0f, 0.0f, 1.0f); 1006 } 1007 mModelView.translate(tx, ty, 0.0f); 1008 if (!isAA) { 1009 float length = mCaches.line.getLength(points[i], points[i + 1], 1010 points[i + 2], points[i + 3]); 1011 mModelView.scale(length, strokeWidth, 1.0f); 1012 } 1013 mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); 1014 // TODO: Add bounds to the layer's region 1015 1016 if (mShader) { 1017 mShader->updateTransforms(mCaches.currentProgram, mModelView, *mSnapshot); 1018 } 1019 1020 glDrawArrays(drawMode, 0, elementsCount); 1021 } 1022 1023 if (isAA) { 1024 glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); 1025 } 1026} 1027 1028void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { 1029 // No need to check against the clip, we fill the clip region 1030 if (mSnapshot->invisible) return; 1031 1032 Rect& clip(*mSnapshot->clipRect); 1033 clip.snapToPixelBoundaries(); 1034 drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true); 1035} 1036 1037void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* p) { 1038 if (quickReject(left, top, right, bottom)) { 1039 return; 1040 } 1041 1042 SkXfermode::Mode mode; 1043 if (!mCaches.extensions.hasFramebufferFetch()) { 1044 const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode); 1045 if (!isMode) { 1046 // Assume SRC_OVER 1047 mode = SkXfermode::kSrcOver_Mode; 1048 } 1049 } else { 1050 mode = getXfermode(p->getXfermode()); 1051 } 1052 1053 // Skia draws using the color's alpha channel if < 255 1054 // Otherwise, it uses the paint's alpha 1055 int color = p->getColor(); 1056 if (((color >> 24) & 0xff) == 255) { 1057 color |= p->getAlpha() << 24; 1058 } 1059 1060 drawColorRect(left, top, right, bottom, color, mode); 1061} 1062 1063void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, 1064 float x, float y, SkPaint* paint) { 1065 if (text == NULL || count == 0 || (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) { 1066 return; 1067 } 1068 if (mSnapshot->invisible) return; 1069 1070 paint->setAntiAlias(true); 1071 1072 float length = -1.0f; 1073 switch (paint->getTextAlign()) { 1074 case SkPaint::kCenter_Align: 1075 length = paint->measureText(text, bytesCount); 1076 x -= length / 2.0f; 1077 break; 1078 case SkPaint::kRight_Align: 1079 length = paint->measureText(text, bytesCount); 1080 x -= length; 1081 break; 1082 default: 1083 break; 1084 } 1085 1086 int alpha; 1087 SkXfermode::Mode mode; 1088 getAlphaAndMode(paint, &alpha, &mode); 1089 1090 uint32_t color = paint->getColor(); 1091 const GLfloat a = alpha / 255.0f; 1092 const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f; 1093 const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f; 1094 const GLfloat b = a * ((color ) & 0xFF) / 255.0f; 1095 1096 FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint); 1097 fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()), 1098 paint->getTextSize()); 1099 1100 setupDraw(); 1101 1102 if (mHasShadow) { 1103 glActiveTexture(gTextureUnits[0]); 1104 mCaches.dropShadowCache.setFontRenderer(fontRenderer); 1105 const ShadowTexture* shadow = mCaches.dropShadowCache.get(paint, text, bytesCount, 1106 count, mShadowRadius); 1107 const AutoTexture autoCleanup(shadow); 1108 1109 setupShadow(shadow, x, y, mode, a); 1110 1111 // Draw the mesh 1112 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); 1113 glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); 1114 } 1115 1116 GLuint textureUnit = 0; 1117 glActiveTexture(gTextureUnits[textureUnit]); 1118 1119 // Assume that the modelView matrix does not force scales, rotates, etc. 1120 const bool linearFilter = mSnapshot->transform->changesBounds(); 1121 1122 // Dimensions are set to (0,0), the layer (if any) won't be dirtied 1123 setupTextureAlpha8(fontRenderer.getTexture(linearFilter), 0, 0, textureUnit, 1124 x, y, r, g, b, a, mode, false, true, NULL, NULL); 1125 1126 const Rect& clip = mSnapshot->getLocalClip(); 1127 Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); 1128 1129#if RENDER_LAYERS_AS_REGIONS 1130 bool hasLayer = (mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region; 1131#else 1132 bool hasLayer = false; 1133#endif 1134 1135 mCaches.unbindMeshBuffer(); 1136 if (fontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y, 1137 hasLayer ? &bounds : NULL)) { 1138#if RENDER_LAYERS_AS_REGIONS 1139 if (hasLayer) { 1140 mSnapshot->transform->mapRect(bounds); 1141 bounds.intersect(*mSnapshot->clipRect); 1142 bounds.snapToPixelBoundaries(); 1143 1144 android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom); 1145 mSnapshot->region->orSelf(dirty); 1146 } 1147#endif 1148 } 1149 1150 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 1151 glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); 1152 1153 drawTextDecorations(text, bytesCount, length, x, y, paint); 1154} 1155 1156void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) { 1157 if (mSnapshot->invisible) return; 1158 1159 GLuint textureUnit = 0; 1160 glActiveTexture(gTextureUnits[textureUnit]); 1161 1162 const PathTexture* texture = mCaches.pathCache.get(path, paint); 1163 if (!texture) return; 1164 const AutoTexture autoCleanup(texture); 1165 1166 const float x = texture->left - texture->offset; 1167 const float y = texture->top - texture->offset; 1168 1169 if (quickReject(x, y, x + texture->width, y + texture->height)) { 1170 return; 1171 } 1172 1173 int alpha; 1174 SkXfermode::Mode mode; 1175 getAlphaAndMode(paint, &alpha, &mode); 1176 1177 uint32_t color = paint->getColor(); 1178 const GLfloat a = alpha / 255.0f; 1179 const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f; 1180 const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f; 1181 const GLfloat b = a * ((color ) & 0xFF) / 255.0f; 1182 1183 setupTextureAlpha8(texture, textureUnit, x, y, r, g, b, a, mode, true, true); 1184 1185 setupDraw(); 1186 1187 // Draw the mesh 1188 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); 1189 glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); 1190} 1191 1192/////////////////////////////////////////////////////////////////////////////// 1193// Shaders 1194/////////////////////////////////////////////////////////////////////////////// 1195 1196void OpenGLRenderer::resetShader() { 1197 mShader = NULL; 1198} 1199 1200void OpenGLRenderer::setupShader(SkiaShader* shader) { 1201 mShader = shader; 1202 if (mShader) { 1203 mShader->set(&mCaches.textureCache, &mCaches.gradientCache); 1204 } 1205} 1206 1207/////////////////////////////////////////////////////////////////////////////// 1208// Color filters 1209/////////////////////////////////////////////////////////////////////////////// 1210 1211void OpenGLRenderer::resetColorFilter() { 1212 mColorFilter = NULL; 1213} 1214 1215void OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) { 1216 mColorFilter = filter; 1217} 1218 1219/////////////////////////////////////////////////////////////////////////////// 1220// Drop shadow 1221/////////////////////////////////////////////////////////////////////////////// 1222 1223void OpenGLRenderer::resetShadow() { 1224 mHasShadow = false; 1225} 1226 1227void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) { 1228 mHasShadow = true; 1229 mShadowRadius = radius; 1230 mShadowDx = dx; 1231 mShadowDy = dy; 1232 mShadowColor = color; 1233} 1234 1235/////////////////////////////////////////////////////////////////////////////// 1236// Drawing implementation 1237/////////////////////////////////////////////////////////////////////////////// 1238 1239void OpenGLRenderer::setupShadow(const ShadowTexture* texture, float x, float y, 1240 SkXfermode::Mode mode, float alpha) { 1241 const float sx = x - texture->left + mShadowDx; 1242 const float sy = y - texture->top + mShadowDy; 1243 1244 const int shadowAlpha = ((mShadowColor >> 24) & 0xFF); 1245 const GLfloat a = shadowAlpha < 255 ? shadowAlpha / 255.0f : alpha; 1246 const GLfloat r = a * ((mShadowColor >> 16) & 0xFF) / 255.0f; 1247 const GLfloat g = a * ((mShadowColor >> 8) & 0xFF) / 255.0f; 1248 const GLfloat b = a * ((mShadowColor ) & 0xFF) / 255.0f; 1249 1250 GLuint textureUnit = 0; 1251 setupTextureAlpha8(texture, textureUnit, sx, sy, r, g, b, a, mode, true, false); 1252} 1253 1254void OpenGLRenderer::setupTextureAlpha8(const Texture* texture, GLuint& textureUnit, 1255 float x, float y, float r, float g, float b, float a, SkXfermode::Mode mode, 1256 bool transforms, bool applyFilters) { 1257 setupTextureAlpha8(texture->id, texture->width, texture->height, textureUnit, 1258 x, y, r, g, b, a, mode, transforms, applyFilters, 1259 (GLvoid*) 0, (GLvoid*) gMeshTextureOffset); 1260} 1261 1262void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height, 1263 GLuint& textureUnit, float x, float y, float r, float g, float b, float a, 1264 SkXfermode::Mode mode, bool transforms, bool applyFilters) { 1265 setupTextureAlpha8(texture, width, height, textureUnit, x, y, r, g, b, a, mode, 1266 transforms, applyFilters, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset); 1267} 1268 1269void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height, 1270 GLuint& textureUnit, float x, float y, float r, float g, float b, float a, 1271 SkXfermode::Mode mode, bool transforms, bool applyFilters, 1272 GLvoid* vertices, GLvoid* texCoords, GLuint vbo) { 1273 // Describe the required shaders 1274 ProgramDescription description; 1275 description.hasTexture = true; 1276 description.hasAlpha8Texture = true; 1277 const bool setColor = description.setAlpha8Color(r, g, b, a); 1278 1279 if (applyFilters) { 1280 if (mShader) { 1281 mShader->describe(description, mCaches.extensions); 1282 } 1283 if (mColorFilter) { 1284 mColorFilter->describe(description, mCaches.extensions); 1285 } 1286 } 1287 1288 // Setup the blending mode 1289 chooseBlending(true, mode, description); 1290 1291 // Build and use the appropriate shader 1292 useProgram(mCaches.programCache.get(description)); 1293 1294 bindTexture(texture); 1295 glUniform1i(mCaches.currentProgram->getUniform("sampler"), textureUnit); 1296 1297 int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords"); 1298 glEnableVertexAttribArray(texCoordsSlot); 1299 1300 if (texCoords) { 1301 // Setup attributes 1302 if (!vertices) { 1303 mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo); 1304 } else { 1305 mCaches.unbindMeshBuffer(); 1306 } 1307 glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, 1308 gMeshStride, vertices); 1309 glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords); 1310 } 1311 1312 // Setup uniforms 1313 if (transforms) { 1314 mModelView.loadTranslate(x, y, 0.0f); 1315 mModelView.scale(width, height, 1.0f); 1316 } else { 1317 mModelView.loadIdentity(); 1318 } 1319 1320 mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); 1321 if (width > 0 && height > 0) { 1322 dirtyLayer(x, y, x + width, y + height, *mSnapshot->transform); 1323 } 1324 1325 if (setColor) { 1326 mCaches.currentProgram->setColor(r, g, b, a); 1327 } 1328 1329 textureUnit++; 1330 if (applyFilters) { 1331 // Setup attributes and uniforms required by the shaders 1332 if (mShader) { 1333 mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit); 1334 } 1335 if (mColorFilter) { 1336 mColorFilter->setupProgram(mCaches.currentProgram); 1337 } 1338 } 1339} 1340 1341// Same values used by Skia 1342#define kStdStrikeThru_Offset (-6.0f / 21.0f) 1343#define kStdUnderline_Offset (1.0f / 9.0f) 1344#define kStdUnderline_Thickness (1.0f / 18.0f) 1345 1346void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float length, 1347 float x, float y, SkPaint* paint) { 1348 // Handle underline and strike-through 1349 uint32_t flags = paint->getFlags(); 1350 if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) { 1351 float underlineWidth = length; 1352 // If length is > 0.0f, we already measured the text for the text alignment 1353 if (length <= 0.0f) { 1354 underlineWidth = paint->measureText(text, bytesCount); 1355 } 1356 1357 float offsetX = 0; 1358 switch (paint->getTextAlign()) { 1359 case SkPaint::kCenter_Align: 1360 offsetX = underlineWidth * 0.5f; 1361 break; 1362 case SkPaint::kRight_Align: 1363 offsetX = underlineWidth; 1364 break; 1365 default: 1366 break; 1367 } 1368 1369 if (underlineWidth > 0.0f) { 1370 const float textSize = paint->getTextSize(); 1371 const float strokeWidth = textSize * kStdUnderline_Thickness; 1372 1373 const float left = x - offsetX; 1374 float top = 0.0f; 1375 1376 const int pointsCount = 4 * (flags & SkPaint::kStrikeThruText_Flag ? 2 : 1); 1377 float points[pointsCount]; 1378 int currentPoint = 0; 1379 1380 if (flags & SkPaint::kUnderlineText_Flag) { 1381 top = y + textSize * kStdUnderline_Offset; 1382 points[currentPoint++] = left; 1383 points[currentPoint++] = top; 1384 points[currentPoint++] = left + underlineWidth; 1385 points[currentPoint++] = top; 1386 } 1387 1388 if (flags & SkPaint::kStrikeThruText_Flag) { 1389 top = y + textSize * kStdStrikeThru_Offset; 1390 points[currentPoint++] = left; 1391 points[currentPoint++] = top; 1392 points[currentPoint++] = left + underlineWidth; 1393 points[currentPoint++] = top; 1394 } 1395 1396 SkPaint linesPaint(*paint); 1397 linesPaint.setStrokeWidth(strokeWidth); 1398 1399 drawLines(&points[0], pointsCount, &linesPaint); 1400 } 1401 } 1402} 1403 1404void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, 1405 int color, SkXfermode::Mode mode, bool ignoreTransform) { 1406 setupDraw(); 1407 1408 // If a shader is set, preserve only the alpha 1409 if (mShader) { 1410 color |= 0x00ffffff; 1411 } 1412 1413 // Render using pre-multiplied alpha 1414 const int alpha = (color >> 24) & 0xFF; 1415 const GLfloat a = alpha / 255.0f; 1416 const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f; 1417 const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f; 1418 const GLfloat b = a * ((color ) & 0xFF) / 255.0f; 1419 1420 setupColorRect(left, top, right, bottom, r, g, b, a, mode, ignoreTransform); 1421 1422 // Draw the mesh 1423 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); 1424} 1425 1426void OpenGLRenderer::setupColorRect(float left, float top, float right, float bottom, 1427 float r, float g, float b, float a, SkXfermode::Mode mode, 1428 bool ignoreTransform, bool ignoreMatrix) { 1429 GLuint textureUnit = 0; 1430 1431 // Describe the required shaders 1432 ProgramDescription description; 1433 const bool setColor = description.setColor(r, g, b, a); 1434 1435 if (mShader) { 1436 mShader->describe(description, mCaches.extensions); 1437 } 1438 if (mColorFilter) { 1439 mColorFilter->describe(description, mCaches.extensions); 1440 } 1441 1442 // Setup the blending mode 1443 chooseBlending(a < 1.0f || (mShader && mShader->blend()), mode, description); 1444 1445 // Build and use the appropriate shader 1446 useProgram(mCaches.programCache.get(description)); 1447 1448 // Setup attributes 1449 mCaches.bindMeshBuffer(); 1450 glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, 1451 gMeshStride, 0); 1452 1453 if (!ignoreMatrix) { 1454 // Setup uniforms 1455 mModelView.loadTranslate(left, top, 0.0f); 1456 mModelView.scale(right - left, bottom - top, 1.0f); 1457 if (!ignoreTransform) { 1458 mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); 1459 dirtyLayer(left, top, right, bottom, *mSnapshot->transform); 1460 } else { 1461 mat4 identity; 1462 mCaches.currentProgram->set(mOrthoMatrix, mModelView, identity); 1463 dirtyLayer(left, top, right, bottom); 1464 } 1465 } 1466 mCaches.currentProgram->setColor(r, g, b, a); 1467 1468 // Setup attributes and uniforms required by the shaders 1469 if (mShader) { 1470 if (ignoreMatrix) mModelView.loadIdentity(); 1471 mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit); 1472 } 1473 if (mColorFilter) { 1474 mColorFilter->setupProgram(mCaches.currentProgram); 1475 } 1476} 1477 1478void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, 1479 Texture* texture, SkPaint* paint) { 1480 int alpha; 1481 SkXfermode::Mode mode; 1482 getAlphaAndMode(paint, &alpha, &mode); 1483 1484 setTextureWrapModes(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 1485 1486 drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode, 1487 texture->blend, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset, 1488 GL_TRIANGLE_STRIP, gMeshCount); 1489} 1490 1491void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, 1492 GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) { 1493 drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend, 1494 (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount); 1495} 1496 1497void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom, 1498 GLuint texture, float alpha, SkXfermode::Mode mode, bool blend, 1499 GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount, 1500 bool swapSrcDst, bool ignoreTransform, GLuint vbo, bool ignoreScale, bool dirty) { 1501 setupDraw(); 1502 1503 ProgramDescription description; 1504 description.hasTexture = true; 1505 const bool setColor = description.setColor(alpha, alpha, alpha, alpha); 1506 if (mColorFilter) { 1507 mColorFilter->describe(description, mCaches.extensions); 1508 } 1509 1510 mModelView.loadTranslate(left, top, 0.0f); 1511 if (!ignoreScale) { 1512 mModelView.scale(right - left, bottom - top, 1.0f); 1513 } 1514 1515 chooseBlending(blend || alpha < 1.0f, mode, description, swapSrcDst); 1516 1517 useProgram(mCaches.programCache.get(description)); 1518 if (!ignoreTransform) { 1519 mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); 1520 if (dirty) dirtyLayer(left, top, right, bottom, *mSnapshot->transform); 1521 } else { 1522 mat4 identity; 1523 mCaches.currentProgram->set(mOrthoMatrix, mModelView, identity); 1524 if (dirty) dirtyLayer(left, top, right, bottom); 1525 } 1526 1527 // Texture 1528 bindTexture(texture); 1529 glUniform1i(mCaches.currentProgram->getUniform("sampler"), 0); 1530 1531 // Always premultiplied 1532 if (setColor) { 1533 mCaches.currentProgram->setColor(alpha, alpha, alpha, alpha); 1534 } 1535 1536 // Mesh 1537 int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords"); 1538 glEnableVertexAttribArray(texCoordsSlot); 1539 1540 if (!vertices) { 1541 mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo); 1542 } else { 1543 mCaches.unbindMeshBuffer(); 1544 } 1545 glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, 1546 gMeshStride, vertices); 1547 glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords); 1548 1549 // Color filter 1550 if (mColorFilter) { 1551 mColorFilter->setupProgram(mCaches.currentProgram); 1552 } 1553 1554 glDrawArrays(drawMode, 0, elementsCount); 1555 glDisableVertexAttribArray(texCoordsSlot); 1556} 1557 1558void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, 1559 ProgramDescription& description, bool swapSrcDst) { 1560 blend = blend || mode != SkXfermode::kSrcOver_Mode; 1561 if (blend) { 1562 if (mode < SkXfermode::kPlus_Mode) { 1563 if (!mCaches.blend) { 1564 glEnable(GL_BLEND); 1565 } 1566 1567 GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src; 1568 GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst; 1569 1570 if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) { 1571 glBlendFunc(sourceMode, destMode); 1572 mCaches.lastSrcMode = sourceMode; 1573 mCaches.lastDstMode = destMode; 1574 } 1575 } else { 1576 // These blend modes are not supported by OpenGL directly and have 1577 // to be implemented using shaders. Since the shader will perform 1578 // the blending, turn blending off here 1579 if (mCaches.extensions.hasFramebufferFetch()) { 1580 description.framebufferMode = mode; 1581 description.swapSrcDst = swapSrcDst; 1582 } 1583 1584 if (mCaches.blend) { 1585 glDisable(GL_BLEND); 1586 } 1587 blend = false; 1588 } 1589 } else if (mCaches.blend) { 1590 glDisable(GL_BLEND); 1591 } 1592 mCaches.blend = blend; 1593} 1594 1595bool OpenGLRenderer::useProgram(Program* program) { 1596 if (!program->isInUse()) { 1597 if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove(); 1598 program->use(); 1599 mCaches.currentProgram = program; 1600 return false; 1601 } 1602 return true; 1603} 1604 1605void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) { 1606 TextureVertex* v = &mMeshVertices[0]; 1607 TextureVertex::setUV(v++, u1, v1); 1608 TextureVertex::setUV(v++, u2, v1); 1609 TextureVertex::setUV(v++, u1, v2); 1610 TextureVertex::setUV(v++, u2, v2); 1611} 1612 1613void OpenGLRenderer::getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) { 1614 if (paint) { 1615 if (!mCaches.extensions.hasFramebufferFetch()) { 1616 const bool isMode = SkXfermode::IsMode(paint->getXfermode(), mode); 1617 if (!isMode) { 1618 // Assume SRC_OVER 1619 *mode = SkXfermode::kSrcOver_Mode; 1620 } 1621 } else { 1622 *mode = getXfermode(paint->getXfermode()); 1623 } 1624 1625 // Skia draws using the color's alpha channel if < 255 1626 // Otherwise, it uses the paint's alpha 1627 int color = paint->getColor(); 1628 *alpha = (color >> 24) & 0xFF; 1629 if (*alpha == 255) { 1630 *alpha = paint->getAlpha(); 1631 } 1632 } else { 1633 *mode = SkXfermode::kSrcOver_Mode; 1634 *alpha = 255; 1635 } 1636} 1637 1638SkXfermode::Mode OpenGLRenderer::getXfermode(SkXfermode* mode) { 1639 if (mode == NULL) { 1640 return SkXfermode::kSrcOver_Mode; 1641 } 1642 return mode->fMode; 1643} 1644 1645void OpenGLRenderer::setTextureWrapModes(Texture* texture, GLenum wrapS, GLenum wrapT) { 1646 bool bound = false; 1647 if (wrapS != texture->wrapS) { 1648 glBindTexture(GL_TEXTURE_2D, texture->id); 1649 bound = true; 1650 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS); 1651 texture->wrapS = wrapS; 1652 } 1653 if (wrapT != texture->wrapT) { 1654 if (!bound) { 1655 glBindTexture(GL_TEXTURE_2D, texture->id); 1656 } 1657 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT); 1658 texture->wrapT = wrapT; 1659 } 1660} 1661 1662}; // namespace uirenderer 1663}; // namespace android 1664