OpenGLRenderer.cpp revision f158198ccc3a1f53bfebaa6b8f4426e80e1867ea
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 <SkPathMeasure.h> 25#include <SkTypeface.h> 26 27#include <utils/Log.h> 28#include <utils/StopWatch.h> 29 30#include <private/hwui/DrawGlInfo.h> 31 32#include <ui/Rect.h> 33 34#include "OpenGLRenderer.h" 35#include "DisplayListRenderer.h" 36#include "PathRenderer.h" 37#include "Properties.h" 38#include "Vector.h" 39 40namespace android { 41namespace uirenderer { 42 43/////////////////////////////////////////////////////////////////////////////// 44// Defines 45/////////////////////////////////////////////////////////////////////////////// 46 47#define RAD_TO_DEG (180.0f / 3.14159265f) 48#define MIN_ANGLE 0.001f 49 50#define ALPHA_THRESHOLD 0 51 52#define FILTER(paint) (!paint || paint->isFilterBitmap() ? GL_LINEAR : GL_NEAREST) 53 54/////////////////////////////////////////////////////////////////////////////// 55// Globals 56/////////////////////////////////////////////////////////////////////////////// 57 58/** 59 * Structure mapping Skia xfermodes to OpenGL blending factors. 60 */ 61struct Blender { 62 SkXfermode::Mode mode; 63 GLenum src; 64 GLenum dst; 65}; // struct Blender 66 67// In this array, the index of each Blender equals the value of the first 68// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode] 69static const Blender gBlends[] = { 70 { SkXfermode::kClear_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, 71 { SkXfermode::kSrc_Mode, GL_ONE, GL_ZERO }, 72 { SkXfermode::kDst_Mode, GL_ZERO, GL_ONE }, 73 { SkXfermode::kSrcOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, 74 { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE }, 75 { SkXfermode::kSrcIn_Mode, GL_DST_ALPHA, GL_ZERO }, 76 { SkXfermode::kDstIn_Mode, GL_ZERO, GL_SRC_ALPHA }, 77 { SkXfermode::kSrcOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, 78 { SkXfermode::kDstOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, 79 { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, 80 { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, 81 { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, 82 { SkXfermode::kPlus_Mode, GL_ONE, GL_ONE }, 83 { SkXfermode::kMultiply_Mode, GL_ZERO, GL_SRC_COLOR }, 84 { SkXfermode::kScreen_Mode, GL_ONE, GL_ONE_MINUS_SRC_COLOR } 85}; 86 87// This array contains the swapped version of each SkXfermode. For instance 88// this array's SrcOver blending mode is actually DstOver. You can refer to 89// createLayer() for more information on the purpose of this array. 90static const Blender gBlendsSwap[] = { 91 { SkXfermode::kClear_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, 92 { SkXfermode::kSrc_Mode, GL_ZERO, GL_ONE }, 93 { SkXfermode::kDst_Mode, GL_ONE, GL_ZERO }, 94 { SkXfermode::kSrcOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE }, 95 { SkXfermode::kDstOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, 96 { SkXfermode::kSrcIn_Mode, GL_ZERO, GL_SRC_ALPHA }, 97 { SkXfermode::kDstIn_Mode, GL_DST_ALPHA, GL_ZERO }, 98 { SkXfermode::kSrcOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, 99 { SkXfermode::kDstOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, 100 { SkXfermode::kSrcATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, 101 { SkXfermode::kDstATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, 102 { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, 103 { SkXfermode::kPlus_Mode, GL_ONE, GL_ONE }, 104 { SkXfermode::kMultiply_Mode, GL_DST_COLOR, GL_ZERO }, 105 { SkXfermode::kScreen_Mode, GL_ONE_MINUS_DST_COLOR, GL_ONE } 106}; 107 108/////////////////////////////////////////////////////////////////////////////// 109// Constructors/destructor 110/////////////////////////////////////////////////////////////////////////////// 111 112OpenGLRenderer::OpenGLRenderer(): mCaches(Caches::getInstance()) { 113 mShader = NULL; 114 mColorFilter = NULL; 115 mHasShadow = false; 116 mHasDrawFilter = false; 117 118 memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices)); 119 120 mFirstSnapshot = new Snapshot; 121 122 mScissorOptimizationDisabled = false; 123} 124 125OpenGLRenderer::~OpenGLRenderer() { 126 // The context has already been destroyed at this point, do not call 127 // GL APIs. All GL state should be kept in Caches.h 128} 129 130void OpenGLRenderer::initProperties() { 131 char property[PROPERTY_VALUE_MAX]; 132 if (property_get(PROPERTY_DISABLE_SCISSOR_OPTIMIZATION, property, "false")) { 133 mScissorOptimizationDisabled = !strcasecmp(property, "true"); 134 INIT_LOGD(" Scissor optimization %s", 135 mScissorOptimizationDisabled ? "disabled" : "enabled"); 136 } else { 137 INIT_LOGD(" Scissor optimization enabled"); 138 } 139} 140 141/////////////////////////////////////////////////////////////////////////////// 142// Setup 143/////////////////////////////////////////////////////////////////////////////// 144 145bool OpenGLRenderer::isDeferred() { 146 return false; 147} 148 149void OpenGLRenderer::setViewport(int width, int height) { 150 initViewport(width, height); 151 152 glDisable(GL_DITHER); 153 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 154 155 glEnableVertexAttribArray(Program::kBindingPosition); 156} 157 158void OpenGLRenderer::initViewport(int width, int height) { 159 mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1); 160 161 mWidth = width; 162 mHeight = height; 163 164 mFirstSnapshot->height = height; 165 mFirstSnapshot->viewport.set(0, 0, width, height); 166} 167 168status_t OpenGLRenderer::prepare(bool opaque) { 169 return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque); 170} 171 172status_t OpenGLRenderer::prepareDirty(float left, float top, 173 float right, float bottom, bool opaque) { 174 mCaches.clearGarbage(); 175 176 mSnapshot = new Snapshot(mFirstSnapshot, 177 SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); 178 mSnapshot->fbo = getTargetFbo(); 179 mSaveCount = 1; 180 181 mSnapshot->setClip(left, top, right, bottom); 182 mDirtyClip = true; 183 184 updateLayers(); 185 186 discardFramebuffer(left, top, right, bottom); 187 188 syncState(); 189 190 // Functors break the tiling extension in pretty spectacular ways 191 // This ensures we don't use tiling when a functor is going to be 192 // invoked during the frame 193 mSuppressTiling = mCaches.hasRegisteredFunctors(); 194 195 mTilingSnapshot = mSnapshot; 196 startTiling(mTilingSnapshot, true); 197 198 debugOverdraw(true, true); 199 200 return clear(left, top, right, bottom, opaque); 201} 202 203void OpenGLRenderer::discardFramebuffer(float left, float top, float right, float bottom) { 204 // If we know that we are going to redraw the entire framebuffer, 205 // perform a discard to let the driver know we don't need to preserve 206 // the back buffer for this frame. 207 if (mCaches.extensions.hasDiscardFramebuffer() && 208 left <= 0.0f && top <= 0.0f && right >= mWidth && bottom >= mHeight) { 209 const bool isFbo = getTargetFbo() == 0; 210 const GLenum attachments[] = { 211 isFbo ? (const GLenum) GL_COLOR_EXT : (const GLenum) GL_COLOR_ATTACHMENT0, 212 isFbo ? (const GLenum) GL_STENCIL_EXT : (const GLenum) GL_STENCIL_ATTACHMENT }; 213 glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments); 214 } 215} 216 217status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) { 218 if (!opaque) { 219 mCaches.enableScissor(); 220 mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top); 221 glClear(GL_COLOR_BUFFER_BIT); 222 return DrawGlInfo::kStatusDrew; 223 } 224 225 mCaches.resetScissor(); 226 return DrawGlInfo::kStatusDone; 227} 228 229void OpenGLRenderer::syncState() { 230 glViewport(0, 0, mWidth, mHeight); 231 232 if (mCaches.blend) { 233 glEnable(GL_BLEND); 234 } else { 235 glDisable(GL_BLEND); 236 } 237} 238 239void OpenGLRenderer::startTiling(const sp<Snapshot>& s, bool opaque) { 240 if (!mSuppressTiling) { 241 Rect* clip = mTilingSnapshot->clipRect; 242 if (s->flags & Snapshot::kFlagFboTarget) { 243 clip = &s->layer->clipRect; 244 } 245 246 startTiling(*clip, s->height, opaque); 247 } 248} 249 250void OpenGLRenderer::startTiling(const Rect& clip, int windowHeight, bool opaque) { 251 if (!mSuppressTiling) { 252 mCaches.startTiling(clip.left, windowHeight - clip.bottom, 253 clip.right - clip.left, clip.bottom - clip.top, opaque); 254 } 255} 256 257void OpenGLRenderer::endTiling() { 258 if (!mSuppressTiling) mCaches.endTiling(); 259} 260 261void OpenGLRenderer::finish() { 262 renderOverdraw(); 263 endTiling(); 264 265 if (!suppressErrorChecks()) { 266#if DEBUG_OPENGL 267 GLenum status = GL_NO_ERROR; 268 while ((status = glGetError()) != GL_NO_ERROR) { 269 ALOGD("GL error from OpenGLRenderer: 0x%x", status); 270 switch (status) { 271 case GL_INVALID_ENUM: 272 ALOGE(" GL_INVALID_ENUM"); 273 break; 274 case GL_INVALID_VALUE: 275 ALOGE(" GL_INVALID_VALUE"); 276 break; 277 case GL_INVALID_OPERATION: 278 ALOGE(" GL_INVALID_OPERATION"); 279 break; 280 case GL_OUT_OF_MEMORY: 281 ALOGE(" Out of memory!"); 282 break; 283 } 284 } 285#endif 286 287#if DEBUG_MEMORY_USAGE 288 mCaches.dumpMemoryUsage(); 289#else 290 if (mCaches.getDebugLevel() & kDebugMemory) { 291 mCaches.dumpMemoryUsage(); 292 } 293#endif 294 } 295} 296 297void OpenGLRenderer::interrupt() { 298 if (mCaches.currentProgram) { 299 if (mCaches.currentProgram->isInUse()) { 300 mCaches.currentProgram->remove(); 301 mCaches.currentProgram = NULL; 302 } 303 } 304 mCaches.unbindMeshBuffer(); 305 mCaches.unbindIndicesBuffer(); 306 mCaches.resetVertexPointers(); 307 mCaches.disbaleTexCoordsVertexArray(); 308 debugOverdraw(false, false); 309} 310 311void OpenGLRenderer::resume() { 312 sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot; 313 glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight()); 314 glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo); 315 debugOverdraw(true, false); 316 317 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 318 319 mCaches.scissorEnabled = glIsEnabled(GL_SCISSOR_TEST); 320 mCaches.enableScissor(); 321 mCaches.resetScissor(); 322 dirtyClip(); 323 324 mCaches.activeTexture(0); 325 326 mCaches.blend = true; 327 glEnable(GL_BLEND); 328 glBlendFunc(mCaches.lastSrcMode, mCaches.lastDstMode); 329 glBlendEquation(GL_FUNC_ADD); 330} 331 332void OpenGLRenderer::resumeAfterLayer() { 333 sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot; 334 glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight()); 335 glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo); 336 debugOverdraw(true, false); 337 338 mCaches.resetScissor(); 339 dirtyClip(); 340} 341 342void OpenGLRenderer::detachFunctor(Functor* functor) { 343 mFunctors.remove(functor); 344} 345 346void OpenGLRenderer::attachFunctor(Functor* functor) { 347 mFunctors.add(functor); 348} 349 350status_t OpenGLRenderer::invokeFunctors(Rect& dirty) { 351 status_t result = DrawGlInfo::kStatusDone; 352 size_t count = mFunctors.size(); 353 354 if (count > 0) { 355 interrupt(); 356 SortedVector<Functor*> functors(mFunctors); 357 mFunctors.clear(); 358 359 DrawGlInfo info; 360 info.clipLeft = 0; 361 info.clipTop = 0; 362 info.clipRight = 0; 363 info.clipBottom = 0; 364 info.isLayer = false; 365 info.width = 0; 366 info.height = 0; 367 memset(info.transform, 0, sizeof(float) * 16); 368 369 for (size_t i = 0; i < count; i++) { 370 Functor* f = functors.itemAt(i); 371 result |= (*f)(DrawGlInfo::kModeProcess, &info); 372 373 if (result & DrawGlInfo::kStatusDraw) { 374 Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom); 375 dirty.unionWith(localDirty); 376 } 377 378 if (result & DrawGlInfo::kStatusInvoke) { 379 mFunctors.add(f); 380 } 381 } 382 resume(); 383 } 384 385 return result; 386} 387 388status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) { 389 interrupt(); 390 detachFunctor(functor); 391 392 mCaches.enableScissor(); 393 if (mDirtyClip) { 394 setScissorFromClip(); 395 } 396 397 Rect clip(*mSnapshot->clipRect); 398 clip.snapToPixelBoundaries(); 399 400 // Since we don't know what the functor will draw, let's dirty 401 // tne entire clip region 402 if (hasLayer()) { 403 dirtyLayerUnchecked(clip, getRegion()); 404 } 405 406 DrawGlInfo info; 407 info.clipLeft = clip.left; 408 info.clipTop = clip.top; 409 info.clipRight = clip.right; 410 info.clipBottom = clip.bottom; 411 info.isLayer = hasLayer(); 412 info.width = getSnapshot()->viewport.getWidth(); 413 info.height = getSnapshot()->height; 414 getSnapshot()->transform->copyTo(&info.transform[0]); 415 416 status_t result = (*functor)(DrawGlInfo::kModeDraw, &info) | DrawGlInfo::kStatusDrew; 417 418 if (result != DrawGlInfo::kStatusDone) { 419 Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom); 420 dirty.unionWith(localDirty); 421 422 if (result & DrawGlInfo::kStatusInvoke) { 423 mFunctors.add(functor); 424 } 425 } 426 427 resume(); 428 return result; 429} 430 431/////////////////////////////////////////////////////////////////////////////// 432// Debug 433/////////////////////////////////////////////////////////////////////////////// 434 435void OpenGLRenderer::startMark(const char* name) const { 436 mCaches.startMark(0, name); 437} 438 439void OpenGLRenderer::endMark() const { 440 mCaches.endMark(); 441} 442 443void OpenGLRenderer::debugOverdraw(bool enable, bool clear) { 444 if (mCaches.debugOverdraw && getTargetFbo() == 0) { 445 if (clear) { 446 mCaches.disableScissor(); 447 mCaches.stencil.clear(); 448 } 449 if (enable) { 450 mCaches.stencil.enableDebugWrite(); 451 } else { 452 mCaches.stencil.disable(); 453 } 454 } 455} 456 457void OpenGLRenderer::renderOverdraw() { 458 if (mCaches.debugOverdraw && getTargetFbo() == 0) { 459 const Rect* clip = mTilingSnapshot->clipRect; 460 461 mCaches.enableScissor(); 462 mCaches.setScissor(clip->left, mTilingSnapshot->height - clip->bottom, 463 clip->right - clip->left, clip->bottom - clip->top); 464 465 mCaches.stencil.enableDebugTest(2); 466 drawColor(0x2f0000ff, SkXfermode::kSrcOver_Mode); 467 mCaches.stencil.enableDebugTest(3); 468 drawColor(0x2f00ff00, SkXfermode::kSrcOver_Mode); 469 mCaches.stencil.enableDebugTest(4); 470 drawColor(0x3fff0000, SkXfermode::kSrcOver_Mode); 471 mCaches.stencil.enableDebugTest(4, true); 472 drawColor(0x7fff0000, SkXfermode::kSrcOver_Mode); 473 mCaches.stencil.disable(); 474 } 475} 476 477/////////////////////////////////////////////////////////////////////////////// 478// Layers 479/////////////////////////////////////////////////////////////////////////////// 480 481bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) { 482 if (layer->deferredUpdateScheduled && layer->renderer && layer->displayList) { 483 OpenGLRenderer* renderer = layer->renderer; 484 Rect& dirty = layer->dirtyRect; 485 486 if (inFrame) { 487 endTiling(); 488 debugOverdraw(false, false); 489 } 490 491 renderer->setViewport(layer->layer.getWidth(), layer->layer.getHeight()); 492 renderer->prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, !layer->isBlend()); 493 renderer->drawDisplayList(layer->displayList, dirty, DisplayList::kReplayFlag_ClipChildren); 494 renderer->finish(); 495 496 if (inFrame) { 497 resumeAfterLayer(); 498 startTiling(mSnapshot); 499 } 500 501 dirty.setEmpty(); 502 layer->deferredUpdateScheduled = false; 503 layer->renderer = NULL; 504 layer->displayList = NULL; 505 layer->debugDrawUpdate = mCaches.debugLayersUpdates; 506 507 return true; 508 } 509 510 return false; 511} 512 513void OpenGLRenderer::updateLayers() { 514 int count = mLayerUpdates.size(); 515 if (count > 0) { 516 startMark("Layer Updates"); 517 518 // Note: it is very important to update the layers in reverse order 519 for (int i = count - 1; i >= 0; i--) { 520 Layer* layer = mLayerUpdates.itemAt(i); 521 updateLayer(layer, false); 522 mCaches.resourceCache.decrementRefcount(layer); 523 } 524 mLayerUpdates.clear(); 525 526 glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo()); 527 endMark(); 528 } 529} 530 531void OpenGLRenderer::pushLayerUpdate(Layer* layer) { 532 if (layer) { 533 mLayerUpdates.push_back(layer); 534 mCaches.resourceCache.incrementRefcount(layer); 535 } 536} 537 538void OpenGLRenderer::clearLayerUpdates() { 539 size_t count = mLayerUpdates.size(); 540 if (count > 0) { 541 mCaches.resourceCache.lock(); 542 for (size_t i = 0; i < count; i++) { 543 mCaches.resourceCache.decrementRefcountLocked(mLayerUpdates.itemAt(i)); 544 } 545 mCaches.resourceCache.unlock(); 546 mLayerUpdates.clear(); 547 } 548} 549 550/////////////////////////////////////////////////////////////////////////////// 551// State management 552/////////////////////////////////////////////////////////////////////////////// 553 554int OpenGLRenderer::getSaveCount() const { 555 return mSaveCount; 556} 557 558int OpenGLRenderer::save(int flags) { 559 return saveSnapshot(flags); 560} 561 562void OpenGLRenderer::restore() { 563 if (mSaveCount > 1) { 564 restoreSnapshot(); 565 } 566} 567 568void OpenGLRenderer::restoreToCount(int saveCount) { 569 if (saveCount < 1) saveCount = 1; 570 571 while (mSaveCount > saveCount) { 572 restoreSnapshot(); 573 } 574} 575 576int OpenGLRenderer::saveSnapshot(int flags) { 577 mSnapshot = new Snapshot(mSnapshot, flags); 578 return mSaveCount++; 579} 580 581bool OpenGLRenderer::restoreSnapshot() { 582 bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet; 583 bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer; 584 bool restoreOrtho = mSnapshot->flags & Snapshot::kFlagDirtyOrtho; 585 586 sp<Snapshot> current = mSnapshot; 587 sp<Snapshot> previous = mSnapshot->previous; 588 589 if (restoreOrtho) { 590 Rect& r = previous->viewport; 591 glViewport(r.left, r.top, r.right, r.bottom); 592 mOrthoMatrix.load(current->orthoMatrix); 593 } 594 595 mSaveCount--; 596 mSnapshot = previous; 597 598 if (restoreClip) { 599 dirtyClip(); 600 } 601 602 if (restoreLayer) { 603 composeLayer(current, previous); 604 } 605 606 return restoreClip; 607} 608 609/////////////////////////////////////////////////////////////////////////////// 610// Layers 611/////////////////////////////////////////////////////////////////////////////// 612 613int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom, 614 SkPaint* p, int flags) { 615 const GLuint previousFbo = mSnapshot->fbo; 616 const int count = saveSnapshot(flags); 617 618 if (!mSnapshot->isIgnored()) { 619 int alpha = 255; 620 SkXfermode::Mode mode; 621 622 if (p) { 623 alpha = p->getAlpha(); 624 mode = getXfermode(p->getXfermode()); 625 } else { 626 mode = SkXfermode::kSrcOver_Mode; 627 } 628 629 createLayer(left, top, right, bottom, alpha, mode, flags, previousFbo); 630 } 631 632 return count; 633} 634 635int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom, 636 int alpha, int flags) { 637 if (alpha >= 255) { 638 return saveLayer(left, top, right, bottom, NULL, flags); 639 } else { 640 SkPaint paint; 641 paint.setAlpha(alpha); 642 return saveLayer(left, top, right, bottom, &paint, flags); 643 } 644} 645 646/** 647 * Layers are viewed by Skia are slightly different than layers in image editing 648 * programs (for instance.) When a layer is created, previously created layers 649 * and the frame buffer still receive every drawing command. For instance, if a 650 * layer is created and a shape intersecting the bounds of the layers and the 651 * framebuffer is draw, the shape will be drawn on both (unless the layer was 652 * created with the SkCanvas::kClipToLayer_SaveFlag flag.) 653 * 654 * A way to implement layers is to create an FBO for each layer, backed by an RGBA 655 * texture. Unfortunately, this is inefficient as it requires every primitive to 656 * be drawn n + 1 times, where n is the number of active layers. In practice this 657 * means, for every primitive: 658 * - Switch active frame buffer 659 * - Change viewport, clip and projection matrix 660 * - Issue the drawing 661 * 662 * Switching rendering target n + 1 times per drawn primitive is extremely costly. 663 * To avoid this, layers are implemented in a different way here, at least in the 664 * general case. FBOs are used, as an optimization, when the "clip to layer" flag 665 * is set. When this flag is set we can redirect all drawing operations into a 666 * single FBO. 667 * 668 * This implementation relies on the frame buffer being at least RGBA 8888. When 669 * a layer is created, only a texture is created, not an FBO. The content of the 670 * frame buffer contained within the layer's bounds is copied into this texture 671 * using glCopyTexImage2D(). The layer's region is then cleared(1) in the frame 672 * buffer and drawing continues as normal. This technique therefore treats the 673 * frame buffer as a scratch buffer for the layers. 674 * 675 * To compose the layers back onto the frame buffer, each layer texture 676 * (containing the original frame buffer data) is drawn as a simple quad over 677 * the frame buffer. The trick is that the quad is set as the composition 678 * destination in the blending equation, and the frame buffer becomes the source 679 * of the composition. 680 * 681 * Drawing layers with an alpha value requires an extra step before composition. 682 * An empty quad is drawn over the layer's region in the frame buffer. This quad 683 * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the 684 * quad is used to multiply the colors in the frame buffer. This is achieved by 685 * changing the GL blend functions for the GL_FUNC_ADD blend equation to 686 * GL_ZERO, GL_SRC_ALPHA. 687 * 688 * Because glCopyTexImage2D() can be slow, an alternative implementation might 689 * be use to draw a single clipped layer. The implementation described above 690 * is correct in every case. 691 * 692 * (1) The frame buffer is actually not cleared right away. To allow the GPU 693 * to potentially optimize series of calls to glCopyTexImage2D, the frame 694 * buffer is left untouched until the first drawing operation. Only when 695 * something actually gets drawn are the layers regions cleared. 696 */ 697bool OpenGLRenderer::createLayer(float left, float top, float right, float bottom, 698 int alpha, SkXfermode::Mode mode, int flags, GLuint previousFbo) { 699 LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top); 700 LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize()); 701 702 const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag; 703 704 // Window coordinates of the layer 705 Rect clip; 706 Rect bounds(left, top, right, bottom); 707 Rect untransformedBounds(bounds); 708 mSnapshot->transform->mapRect(bounds); 709 710 // Layers only make sense if they are in the framebuffer's bounds 711 if (bounds.intersect(*mSnapshot->clipRect)) { 712 // We cannot work with sub-pixels in this case 713 bounds.snapToPixelBoundaries(); 714 715 // When the layer is not an FBO, we may use glCopyTexImage so we 716 // need to make sure the layer does not extend outside the bounds 717 // of the framebuffer 718 if (!bounds.intersect(mSnapshot->previous->viewport)) { 719 bounds.setEmpty(); 720 } else if (fboLayer) { 721 clip.set(bounds); 722 mat4 inverse; 723 inverse.loadInverse(*mSnapshot->transform); 724 inverse.mapRect(clip); 725 clip.snapToPixelBoundaries(); 726 if (clip.intersect(untransformedBounds)) { 727 clip.translate(-left, -top); 728 bounds.set(untransformedBounds); 729 } else { 730 clip.setEmpty(); 731 } 732 } 733 } else { 734 bounds.setEmpty(); 735 } 736 737 if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize || 738 bounds.getHeight() > mCaches.maxTextureSize || 739 (fboLayer && clip.isEmpty())) { 740 mSnapshot->empty = fboLayer; 741 } else { 742 mSnapshot->invisible = mSnapshot->invisible || (alpha <= ALPHA_THRESHOLD && fboLayer); 743 } 744 745 // Bail out if we won't draw in this snapshot 746 if (mSnapshot->invisible || mSnapshot->empty) { 747 return false; 748 } 749 750 mCaches.activeTexture(0); 751 Layer* layer = mCaches.layerCache.get(bounds.getWidth(), bounds.getHeight()); 752 if (!layer) { 753 return false; 754 } 755 756 layer->setAlpha(alpha, mode); 757 layer->layer.set(bounds); 758 layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()), 759 bounds.getWidth() / float(layer->getWidth()), 0.0f); 760 layer->setColorFilter(mColorFilter); 761 layer->setBlend(true); 762 layer->setDirty(false); 763 764 // Save the layer in the snapshot 765 mSnapshot->flags |= Snapshot::kFlagIsLayer; 766 mSnapshot->layer = layer; 767 768 if (fboLayer) { 769 return createFboLayer(layer, bounds, clip, previousFbo); 770 } else { 771 // Copy the framebuffer into the layer 772 layer->bindTexture(); 773 if (!bounds.isEmpty()) { 774 if (layer->isEmpty()) { 775 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 776 bounds.left, mSnapshot->height - bounds.bottom, 777 layer->getWidth(), layer->getHeight(), 0); 778 layer->setEmpty(false); 779 } else { 780 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left, 781 mSnapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight()); 782 } 783 784 // Enqueue the buffer coordinates to clear the corresponding region later 785 mLayers.push(new Rect(bounds)); 786 } 787 } 788 789 return true; 790} 791 792bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip, GLuint previousFbo) { 793 layer->clipRect.set(clip); 794 layer->setFbo(mCaches.fboCache.get()); 795 796 mSnapshot->region = &mSnapshot->layer->region; 797 mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer | 798 Snapshot::kFlagDirtyOrtho; 799 mSnapshot->fbo = layer->getFbo(); 800 mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f); 801 mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom); 802 mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight()); 803 mSnapshot->height = bounds.getHeight(); 804 mSnapshot->orthoMatrix.load(mOrthoMatrix); 805 806 endTiling(); 807 debugOverdraw(false, false); 808 // Bind texture to FBO 809 glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo()); 810 layer->bindTexture(); 811 812 // Initialize the texture if needed 813 if (layer->isEmpty()) { 814 layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE); 815 layer->setEmpty(false); 816 } 817 818 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 819 layer->getTexture(), 0); 820 821 startTiling(mSnapshot, !layer->isBlend()); 822 823 // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering 824 mCaches.enableScissor(); 825 mCaches.setScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f, 826 clip.getWidth() + 2.0f, clip.getHeight() + 2.0f); 827 glClear(GL_COLOR_BUFFER_BIT); 828 829 dirtyClip(); 830 831 // Change the ortho projection 832 glViewport(0, 0, bounds.getWidth(), bounds.getHeight()); 833 mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f); 834 835 return true; 836} 837 838/** 839 * Read the documentation of createLayer() before doing anything in this method. 840 */ 841void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { 842 if (!current->layer) { 843 ALOGE("Attempting to compose a layer that does not exist"); 844 return; 845 } 846 847 Layer* layer = current->layer; 848 const Rect& rect = layer->layer; 849 const bool fboLayer = current->flags & Snapshot::kFlagIsFboLayer; 850 851 if (fboLayer) { 852 endTiling(); 853 854 // Detach the texture from the FBO 855 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); 856 857 layer->removeFbo(false); 858 859 // Unbind current FBO and restore previous one 860 glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo); 861 debugOverdraw(true, false); 862 863 startTiling(previous); 864 } 865 866 if (!fboLayer && layer->getAlpha() < 255) { 867 drawColorRect(rect.left, rect.top, rect.right, rect.bottom, 868 layer->getAlpha() << 24, SkXfermode::kDstIn_Mode, true); 869 // Required below, composeLayerRect() will divide by 255 870 layer->setAlpha(255); 871 } 872 873 mCaches.unbindMeshBuffer(); 874 875 mCaches.activeTexture(0); 876 877 // When the layer is stored in an FBO, we can save a bit of fillrate by 878 // drawing only the dirty region 879 if (fboLayer) { 880 dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *previous->transform); 881 if (layer->getColorFilter()) { 882 setupColorFilter(layer->getColorFilter()); 883 } 884 composeLayerRegion(layer, rect); 885 if (layer->getColorFilter()) { 886 resetColorFilter(); 887 } 888 } else if (!rect.isEmpty()) { 889 dirtyLayer(rect.left, rect.top, rect.right, rect.bottom); 890 composeLayerRect(layer, rect, true); 891 } 892 893 dirtyClip(); 894 895 // Failing to add the layer to the cache should happen only if the layer is too large 896 if (!mCaches.layerCache.put(layer)) { 897 LAYER_LOGD("Deleting layer"); 898 Caches::getInstance().resourceCache.decrementRefcount(layer); 899 } 900} 901 902void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) { 903 float alpha = layer->getAlpha() / 255.0f; 904 905 setupDraw(); 906 if (layer->getRenderTarget() == GL_TEXTURE_2D) { 907 setupDrawWithTexture(); 908 } else { 909 setupDrawWithExternalTexture(); 910 } 911 setupDrawTextureTransform(); 912 setupDrawColor(alpha, alpha, alpha, alpha); 913 setupDrawColorFilter(); 914 setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode()); 915 setupDrawProgram(); 916 setupDrawPureColorUniforms(); 917 setupDrawColorFilterUniforms(); 918 if (layer->getRenderTarget() == GL_TEXTURE_2D) { 919 setupDrawTexture(layer->getTexture()); 920 } else { 921 setupDrawExternalTexture(layer->getTexture()); 922 } 923 if (mSnapshot->transform->isPureTranslate() && 924 layer->getWidth() == (uint32_t) rect.getWidth() && 925 layer->getHeight() == (uint32_t) rect.getHeight()) { 926 const float x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f); 927 const float y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f); 928 929 layer->setFilter(GL_NEAREST); 930 setupDrawModelView(x, y, x + rect.getWidth(), y + rect.getHeight(), true); 931 } else { 932 layer->setFilter(GL_LINEAR); 933 setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom); 934 } 935 setupDrawTextureTransformUniforms(layer->getTexTransform()); 936 setupDrawMesh(&mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]); 937 938 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); 939 940 finishDrawTexture(); 941} 942 943void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) { 944 if (!layer->isTextureLayer()) { 945 const Rect& texCoords = layer->texCoords; 946 resetDrawTextureTexCoords(texCoords.left, texCoords.top, 947 texCoords.right, texCoords.bottom); 948 949 float x = rect.left; 950 float y = rect.top; 951 bool simpleTransform = mSnapshot->transform->isPureTranslate() && 952 layer->getWidth() == (uint32_t) rect.getWidth() && 953 layer->getHeight() == (uint32_t) rect.getHeight(); 954 955 if (simpleTransform) { 956 // When we're swapping, the layer is already in screen coordinates 957 if (!swap) { 958 x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f); 959 y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f); 960 } 961 962 layer->setFilter(GL_NEAREST, true); 963 } else { 964 layer->setFilter(GL_LINEAR, true); 965 } 966 967 drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(), 968 layer->getTexture(), layer->getAlpha() / 255.0f, 969 layer->getMode(), layer->isBlend(), 970 &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], 971 GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform); 972 973 resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); 974 } else { 975 resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f); 976 drawTextureLayer(layer, rect); 977 resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); 978 } 979} 980 981void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { 982 if (layer->region.isRect()) { 983 layer->setRegionAsRect(); 984 985 composeLayerRect(layer, layer->regionRect); 986 987 layer->region.clear(); 988 return; 989 } 990 991 // TODO: See LayerRenderer.cpp::generateMesh() for important 992 // information about this implementation 993 if (CC_LIKELY(!layer->region.isEmpty())) { 994 size_t count; 995 const android::Rect* rects = layer->region.getArray(&count); 996 997 const float alpha = layer->getAlpha() / 255.0f; 998 const float texX = 1.0f / float(layer->getWidth()); 999 const float texY = 1.0f / float(layer->getHeight()); 1000 const float height = rect.getHeight(); 1001 1002 setupDraw(); 1003 1004 // We must get (and therefore bind) the region mesh buffer 1005 // after we setup drawing in case we need to mess with the 1006 // stencil buffer in setupDraw() 1007 TextureVertex* mesh = mCaches.getRegionMesh(); 1008 GLsizei numQuads = 0; 1009 1010 setupDrawWithTexture(); 1011 setupDrawColor(alpha, alpha, alpha, alpha); 1012 setupDrawColorFilter(); 1013 setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode(), false); 1014 setupDrawProgram(); 1015 setupDrawDirtyRegionsDisabled(); 1016 setupDrawPureColorUniforms(); 1017 setupDrawColorFilterUniforms(); 1018 setupDrawTexture(layer->getTexture()); 1019 if (mSnapshot->transform->isPureTranslate()) { 1020 const float x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f); 1021 const float y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f); 1022 1023 layer->setFilter(GL_NEAREST); 1024 setupDrawModelViewTranslate(x, y, x + rect.getWidth(), y + rect.getHeight(), true); 1025 } else { 1026 layer->setFilter(GL_LINEAR); 1027 setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom); 1028 } 1029 setupDrawMeshIndices(&mesh[0].position[0], &mesh[0].texture[0]); 1030 1031 for (size_t i = 0; i < count; i++) { 1032 const android::Rect* r = &rects[i]; 1033 1034 const float u1 = r->left * texX; 1035 const float v1 = (height - r->top) * texY; 1036 const float u2 = r->right * texX; 1037 const float v2 = (height - r->bottom) * texY; 1038 1039 // TODO: Reject quads outside of the clip 1040 TextureVertex::set(mesh++, r->left, r->top, u1, v1); 1041 TextureVertex::set(mesh++, r->right, r->top, u2, v1); 1042 TextureVertex::set(mesh++, r->left, r->bottom, u1, v2); 1043 TextureVertex::set(mesh++, r->right, r->bottom, u2, v2); 1044 1045 numQuads++; 1046 1047 if (numQuads >= REGION_MESH_QUAD_COUNT) { 1048 glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL); 1049 numQuads = 0; 1050 mesh = mCaches.getRegionMesh(); 1051 } 1052 } 1053 1054 if (numQuads > 0) { 1055 glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL); 1056 } 1057 1058 finishDrawTexture(); 1059 1060#if DEBUG_LAYERS_AS_REGIONS 1061 drawRegionRects(layer->region); 1062#endif 1063 1064 layer->region.clear(); 1065 } 1066} 1067 1068void OpenGLRenderer::drawRegionRects(const Region& region) { 1069#if DEBUG_LAYERS_AS_REGIONS 1070 size_t count; 1071 const android::Rect* rects = region.getArray(&count); 1072 1073 uint32_t colors[] = { 1074 0x7fff0000, 0x7f00ff00, 1075 0x7f0000ff, 0x7fff00ff, 1076 }; 1077 1078 int offset = 0; 1079 int32_t top = rects[0].top; 1080 1081 for (size_t i = 0; i < count; i++) { 1082 if (top != rects[i].top) { 1083 offset ^= 0x2; 1084 top = rects[i].top; 1085 } 1086 1087 Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom); 1088 drawColorRect(r.left, r.top, r.right, r.bottom, colors[offset + (i & 0x1)], 1089 SkXfermode::kSrcOver_Mode); 1090 } 1091#endif 1092} 1093 1094void OpenGLRenderer::drawRegionRects(const SkRegion& region, int color, 1095 SkXfermode::Mode mode, bool dirty) { 1096 int count = 0; 1097 Vector<float> rects; 1098 1099 SkRegion::Iterator it(region); 1100 while (!it.done()) { 1101 const SkIRect& r = it.rect(); 1102 rects.push(r.fLeft); 1103 rects.push(r.fTop); 1104 rects.push(r.fRight); 1105 rects.push(r.fBottom); 1106 count += 4; 1107 it.next(); 1108 } 1109 1110 drawColorRects(rects.array(), count, color, mode, true, dirty); 1111} 1112 1113void OpenGLRenderer::dirtyLayer(const float left, const float top, 1114 const float right, const float bottom, const mat4 transform) { 1115 if (hasLayer()) { 1116 Rect bounds(left, top, right, bottom); 1117 transform.mapRect(bounds); 1118 dirtyLayerUnchecked(bounds, getRegion()); 1119 } 1120} 1121 1122void OpenGLRenderer::dirtyLayer(const float left, const float top, 1123 const float right, const float bottom) { 1124 if (hasLayer()) { 1125 Rect bounds(left, top, right, bottom); 1126 dirtyLayerUnchecked(bounds, getRegion()); 1127 } 1128} 1129 1130void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) { 1131 if (bounds.intersect(*mSnapshot->clipRect)) { 1132 bounds.snapToPixelBoundaries(); 1133 android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom); 1134 if (!dirty.isEmpty()) { 1135 region->orSelf(dirty); 1136 } 1137 } 1138} 1139 1140void OpenGLRenderer::clearLayerRegions() { 1141 const size_t count = mLayers.size(); 1142 if (count == 0) return; 1143 1144 if (!mSnapshot->isIgnored()) { 1145 // Doing several glScissor/glClear here can negatively impact 1146 // GPUs with a tiler architecture, instead we draw quads with 1147 // the Clear blending mode 1148 1149 // The list contains bounds that have already been clipped 1150 // against their initial clip rect, and the current clip 1151 // is likely different so we need to disable clipping here 1152 bool scissorChanged = mCaches.disableScissor(); 1153 1154 Vertex mesh[count * 6]; 1155 Vertex* vertex = mesh; 1156 1157 for (uint32_t i = 0; i < count; i++) { 1158 Rect* bounds = mLayers.itemAt(i); 1159 1160 Vertex::set(vertex++, bounds->left, bounds->bottom); 1161 Vertex::set(vertex++, bounds->left, bounds->top); 1162 Vertex::set(vertex++, bounds->right, bounds->top); 1163 Vertex::set(vertex++, bounds->left, bounds->bottom); 1164 Vertex::set(vertex++, bounds->right, bounds->top); 1165 Vertex::set(vertex++, bounds->right, bounds->bottom); 1166 1167 delete bounds; 1168 } 1169 1170 setupDraw(false); 1171 setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f); 1172 setupDrawBlending(true, SkXfermode::kClear_Mode); 1173 setupDrawProgram(); 1174 setupDrawPureColorUniforms(); 1175 setupDrawModelViewTranslate(0.0f, 0.0f, 0.0f, 0.0f, true); 1176 setupDrawVertices(&mesh[0].position[0]); 1177 1178 glDrawArrays(GL_TRIANGLES, 0, count * 6); 1179 1180 if (scissorChanged) mCaches.enableScissor(); 1181 } else { 1182 for (uint32_t i = 0; i < count; i++) { 1183 delete mLayers.itemAt(i); 1184 } 1185 } 1186 1187 mLayers.clear(); 1188} 1189 1190/////////////////////////////////////////////////////////////////////////////// 1191// Transforms 1192/////////////////////////////////////////////////////////////////////////////// 1193 1194void OpenGLRenderer::translate(float dx, float dy) { 1195 mSnapshot->transform->translate(dx, dy, 0.0f); 1196} 1197 1198void OpenGLRenderer::rotate(float degrees) { 1199 mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f); 1200} 1201 1202void OpenGLRenderer::scale(float sx, float sy) { 1203 mSnapshot->transform->scale(sx, sy, 1.0f); 1204} 1205 1206void OpenGLRenderer::skew(float sx, float sy) { 1207 mSnapshot->transform->skew(sx, sy); 1208} 1209 1210void OpenGLRenderer::setMatrix(SkMatrix* matrix) { 1211 if (matrix) { 1212 mSnapshot->transform->load(*matrix); 1213 } else { 1214 mSnapshot->transform->loadIdentity(); 1215 } 1216} 1217 1218void OpenGLRenderer::getMatrix(SkMatrix* matrix) { 1219 mSnapshot->transform->copyTo(*matrix); 1220} 1221 1222void OpenGLRenderer::concatMatrix(SkMatrix* matrix) { 1223 SkMatrix transform; 1224 mSnapshot->transform->copyTo(transform); 1225 transform.preConcat(*matrix); 1226 mSnapshot->transform->load(transform); 1227} 1228 1229/////////////////////////////////////////////////////////////////////////////// 1230// Clipping 1231/////////////////////////////////////////////////////////////////////////////// 1232 1233void OpenGLRenderer::setScissorFromClip() { 1234 Rect clip(*mSnapshot->clipRect); 1235 clip.snapToPixelBoundaries(); 1236 1237 if (mCaches.setScissor(clip.left, mSnapshot->height - clip.bottom, 1238 clip.getWidth(), clip.getHeight())) { 1239 mDirtyClip = false; 1240 } 1241} 1242 1243void OpenGLRenderer::ensureStencilBuffer() { 1244 // Thanks to the mismatch between EGL and OpenGL ES FBO we 1245 // cannot attach a stencil buffer to fbo0 dynamically. Let's 1246 // just hope we have one when hasLayer() returns false. 1247 if (hasLayer()) { 1248 attachStencilBufferToLayer(mSnapshot->layer); 1249 } 1250} 1251 1252void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) { 1253 // The layer's FBO is already bound when we reach this stage 1254 if (!layer->getStencilRenderBuffer()) { 1255 // GL_QCOM_tiled_rendering doesn't like it if a renderbuffer 1256 // is attached after we initiated tiling. We must turn it off, 1257 // attach the new render buffer then turn tiling back on 1258 endTiling(); 1259 1260 // TODO: See Layer::removeFbo(). The stencil renderbuffer should be cached 1261 GLuint buffer; 1262 glGenRenderbuffers(1, &buffer); 1263 1264 layer->setStencilRenderBuffer(buffer); 1265 layer->bindStencilRenderBuffer(); 1266 layer->allocateStencilRenderBuffer(); 1267 1268 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, buffer); 1269 1270 startTiling(layer->clipRect, layer->layer.getHeight(), !layer->isBlend()); 1271 } 1272} 1273 1274void OpenGLRenderer::setStencilFromClip() { 1275 if (!mCaches.debugOverdraw) { 1276 if (!mSnapshot->clipRegion->isEmpty()) { 1277 // NOTE: The order here is important, we must set dirtyClip to false 1278 // before any draw call to avoid calling back into this method 1279 mDirtyClip = false; 1280 1281 ensureStencilBuffer(); 1282 1283 mCaches.stencil.enableWrite(); 1284 1285 // Clear the stencil but first make sure we restrict drawing 1286 // to the region's bounds 1287 bool resetScissor = mCaches.enableScissor(); 1288 if (resetScissor) { 1289 // The scissor was not set so we now need to update it 1290 setScissorFromClip(); 1291 } 1292 mCaches.stencil.clear(); 1293 if (resetScissor) mCaches.disableScissor(); 1294 1295 // NOTE: We could use the region contour path to generate a smaller mesh 1296 // Since we are using the stencil we could use the red book path 1297 // drawing technique. It might increase bandwidth usage though. 1298 1299 // The last parameter is important: we are not drawing in the color buffer 1300 // so we don't want to dirty the current layer, if any 1301 drawRegionRects(*mSnapshot->clipRegion, 0xff000000, SkXfermode::kSrc_Mode, false); 1302 1303 mCaches.stencil.enableTest(); 1304 } else { 1305 mCaches.stencil.disable(); 1306 } 1307 } 1308} 1309 1310const Rect& OpenGLRenderer::getClipBounds() { 1311 return mSnapshot->getLocalClip(); 1312} 1313 1314bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom) { 1315 if (mSnapshot->isIgnored()) { 1316 return true; 1317 } 1318 1319 Rect r(left, top, right, bottom); 1320 mSnapshot->transform->mapRect(r); 1321 r.snapToPixelBoundaries(); 1322 1323 Rect clipRect(*mSnapshot->clipRect); 1324 clipRect.snapToPixelBoundaries(); 1325 1326 return !clipRect.intersects(r); 1327} 1328 1329bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom, 1330 Rect& transformed, Rect& clip) { 1331 if (mSnapshot->isIgnored()) { 1332 return true; 1333 } 1334 1335 transformed.set(left, top, right, bottom); 1336 mSnapshot->transform->mapRect(transformed); 1337 transformed.snapToPixelBoundaries(); 1338 1339 clip.set(*mSnapshot->clipRect); 1340 clip.snapToPixelBoundaries(); 1341 1342 return !clip.intersects(transformed); 1343} 1344 1345bool OpenGLRenderer::quickRejectPreStroke(float left, float top, float right, float bottom, 1346 SkPaint* paint) { 1347 if (paint->getStyle() != SkPaint::kFill_Style) { 1348 float outset = paint->getStrokeWidth() * 0.5f; 1349 return quickReject(left - outset, top - outset, right + outset, bottom + outset); 1350 } else { 1351 return quickReject(left, top, right, bottom); 1352 } 1353} 1354 1355bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) { 1356 if (mSnapshot->isIgnored() || bottom <= top || right <= left) { 1357 return true; 1358 } 1359 1360 Rect r(left, top, right, bottom); 1361 mSnapshot->transform->mapRect(r); 1362 r.snapToPixelBoundaries(); 1363 1364 Rect clipRect(*mSnapshot->clipRect); 1365 clipRect.snapToPixelBoundaries(); 1366 1367 bool rejected = !clipRect.intersects(r); 1368 if (!isDeferred() && !rejected) { 1369 mCaches.setScissorEnabled(mScissorOptimizationDisabled || !clipRect.contains(r)); 1370 } 1371 1372 return rejected; 1373} 1374 1375void OpenGLRenderer::debugClip() { 1376#if DEBUG_CLIP_REGIONS 1377 if (!isDeferred() && !mSnapshot->clipRegion->isEmpty()) { 1378 drawRegionRects(*mSnapshot->clipRegion, 0x7f00ff00, SkXfermode::kSrcOver_Mode); 1379 } 1380#endif 1381} 1382 1383bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { 1384 if (CC_LIKELY(mSnapshot->transform->rectToRect())) { 1385 bool clipped = mSnapshot->clip(left, top, right, bottom, op); 1386 if (clipped) { 1387 dirtyClip(); 1388 } 1389 return !mSnapshot->clipRect->isEmpty(); 1390 } 1391 1392 SkPath path; 1393 path.addRect(left, top, right, bottom); 1394 1395 return clipPath(&path, op); 1396} 1397 1398bool OpenGLRenderer::clipPath(SkPath* path, SkRegion::Op op) { 1399 SkMatrix transform; 1400 mSnapshot->transform->copyTo(transform); 1401 1402 SkPath transformed; 1403 path->transform(transform, &transformed); 1404 1405 SkRegion clip; 1406 if (!mSnapshot->clipRegion->isEmpty()) { 1407 clip.setRegion(*mSnapshot->clipRegion); 1408 } else { 1409 Rect* bounds = mSnapshot->clipRect; 1410 clip.setRect(bounds->left, bounds->top, bounds->right, bounds->bottom); 1411 } 1412 1413 SkRegion region; 1414 region.setPath(transformed, clip); 1415 1416 bool clipped = mSnapshot->clipRegionTransformed(region, op); 1417 if (clipped) { 1418 dirtyClip(); 1419 } 1420 return !mSnapshot->clipRect->isEmpty(); 1421} 1422 1423bool OpenGLRenderer::clipRegion(SkRegion* region, SkRegion::Op op) { 1424 bool clipped = mSnapshot->clipRegionTransformed(*region, op); 1425 if (clipped) { 1426 dirtyClip(); 1427 } 1428 return !mSnapshot->clipRect->isEmpty(); 1429} 1430 1431Rect* OpenGLRenderer::getClipRect() { 1432 return mSnapshot->clipRect; 1433} 1434 1435/////////////////////////////////////////////////////////////////////////////// 1436// Drawing commands 1437/////////////////////////////////////////////////////////////////////////////// 1438 1439void OpenGLRenderer::setupDraw(bool clear) { 1440 // TODO: It would be best if we could do this before quickReject() 1441 // changes the scissor test state 1442 if (clear) clearLayerRegions(); 1443 // Make sure setScissor & setStencil happen at the beginning of 1444 // this method 1445 if (mDirtyClip) { 1446 setScissorFromClip(); 1447 setStencilFromClip(); 1448 } 1449 mDescription.reset(); 1450 mSetShaderColor = false; 1451 mColorSet = false; 1452 mColorA = mColorR = mColorG = mColorB = 0.0f; 1453 mTextureUnit = 0; 1454 mTrackDirtyRegions = true; 1455} 1456 1457void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) { 1458 mDescription.hasTexture = true; 1459 mDescription.hasAlpha8Texture = isAlpha8; 1460} 1461 1462void OpenGLRenderer::setupDrawWithExternalTexture() { 1463 mDescription.hasExternalTexture = true; 1464} 1465 1466void OpenGLRenderer::setupDrawNoTexture() { 1467 mCaches.disbaleTexCoordsVertexArray(); 1468} 1469 1470void OpenGLRenderer::setupDrawAA() { 1471 mDescription.isAA = true; 1472} 1473 1474void OpenGLRenderer::setupDrawVertexShape() { 1475 mDescription.isVertexShape = true; 1476} 1477 1478void OpenGLRenderer::setupDrawPoint(float pointSize) { 1479 mDescription.isPoint = true; 1480 mDescription.pointSize = pointSize; 1481} 1482 1483void OpenGLRenderer::setupDrawColor(int color, int alpha) { 1484 mColorA = alpha / 255.0f; 1485 mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f; 1486 mColorG = mColorA * ((color >> 8) & 0xFF) / 255.0f; 1487 mColorB = mColorA * ((color ) & 0xFF) / 255.0f; 1488 mColorSet = true; 1489 mSetShaderColor = mDescription.setColor(mColorR, mColorG, mColorB, mColorA); 1490} 1491 1492void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) { 1493 mColorA = alpha / 255.0f; 1494 mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f; 1495 mColorG = mColorA * ((color >> 8) & 0xFF) / 255.0f; 1496 mColorB = mColorA * ((color ) & 0xFF) / 255.0f; 1497 mColorSet = true; 1498 mSetShaderColor = mDescription.setAlpha8Color(mColorR, mColorG, mColorB, mColorA); 1499} 1500 1501void OpenGLRenderer::setupDrawTextGamma(const SkPaint* paint) { 1502 mCaches.fontRenderer->describe(mDescription, paint); 1503} 1504 1505void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) { 1506 mColorA = a; 1507 mColorR = r; 1508 mColorG = g; 1509 mColorB = b; 1510 mColorSet = true; 1511 mSetShaderColor = mDescription.setColor(r, g, b, a); 1512} 1513 1514void OpenGLRenderer::setupDrawShader() { 1515 if (mShader) { 1516 mShader->describe(mDescription, mCaches.extensions); 1517 } 1518} 1519 1520void OpenGLRenderer::setupDrawColorFilter() { 1521 if (mColorFilter) { 1522 mColorFilter->describe(mDescription, mCaches.extensions); 1523 } 1524} 1525 1526void OpenGLRenderer::accountForClear(SkXfermode::Mode mode) { 1527 if (mColorSet && mode == SkXfermode::kClear_Mode) { 1528 mColorA = 1.0f; 1529 mColorR = mColorG = mColorB = 0.0f; 1530 mSetShaderColor = mDescription.modulate = true; 1531 } 1532} 1533 1534void OpenGLRenderer::setupDrawBlending(SkXfermode::Mode mode, bool swapSrcDst) { 1535 // When the blending mode is kClear_Mode, we need to use a modulate color 1536 // argb=1,0,0,0 1537 accountForClear(mode); 1538 chooseBlending((mColorSet && mColorA < 1.0f) || (mShader && mShader->blend()), mode, 1539 mDescription, swapSrcDst); 1540} 1541 1542void OpenGLRenderer::setupDrawBlending(bool blend, SkXfermode::Mode mode, bool swapSrcDst) { 1543 // When the blending mode is kClear_Mode, we need to use a modulate color 1544 // argb=1,0,0,0 1545 accountForClear(mode); 1546 chooseBlending(blend || (mColorSet && mColorA < 1.0f) || (mShader && mShader->blend()) || 1547 (mColorFilter && mColorFilter->blend()), mode, mDescription, swapSrcDst); 1548} 1549 1550void OpenGLRenderer::setupDrawProgram() { 1551 useProgram(mCaches.programCache.get(mDescription)); 1552} 1553 1554void OpenGLRenderer::setupDrawDirtyRegionsDisabled() { 1555 mTrackDirtyRegions = false; 1556} 1557 1558void OpenGLRenderer::setupDrawModelViewTranslate(float left, float top, float right, float bottom, 1559 bool ignoreTransform) { 1560 mModelView.loadTranslate(left, top, 0.0f); 1561 if (!ignoreTransform) { 1562 mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); 1563 if (mTrackDirtyRegions) dirtyLayer(left, top, right, bottom, *mSnapshot->transform); 1564 } else { 1565 mCaches.currentProgram->set(mOrthoMatrix, mModelView, mIdentity); 1566 if (mTrackDirtyRegions) dirtyLayer(left, top, right, bottom); 1567 } 1568} 1569 1570void OpenGLRenderer::setupDrawModelViewIdentity(bool offset) { 1571 mCaches.currentProgram->set(mOrthoMatrix, mIdentity, *mSnapshot->transform, offset); 1572} 1573 1574void OpenGLRenderer::setupDrawModelView(float left, float top, float right, float bottom, 1575 bool ignoreTransform, bool ignoreModelView) { 1576 if (!ignoreModelView) { 1577 mModelView.loadTranslate(left, top, 0.0f); 1578 mModelView.scale(right - left, bottom - top, 1.0f); 1579 } else { 1580 mModelView.loadIdentity(); 1581 } 1582 bool dirty = right - left > 0.0f && bottom - top > 0.0f; 1583 if (!ignoreTransform) { 1584 mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); 1585 if (mTrackDirtyRegions && dirty) { 1586 dirtyLayer(left, top, right, bottom, *mSnapshot->transform); 1587 } 1588 } else { 1589 mCaches.currentProgram->set(mOrthoMatrix, mModelView, mIdentity); 1590 if (mTrackDirtyRegions && dirty) dirtyLayer(left, top, right, bottom); 1591 } 1592} 1593 1594void OpenGLRenderer::setupDrawPointUniforms() { 1595 int slot = mCaches.currentProgram->getUniform("pointSize"); 1596 glUniform1f(slot, mDescription.pointSize); 1597} 1598 1599void OpenGLRenderer::setupDrawColorUniforms() { 1600 if ((mColorSet && !mShader) || (mShader && mSetShaderColor)) { 1601 mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA); 1602 } 1603} 1604 1605void OpenGLRenderer::setupDrawPureColorUniforms() { 1606 if (mSetShaderColor) { 1607 mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA); 1608 } 1609} 1610 1611void OpenGLRenderer::setupDrawShaderUniforms(bool ignoreTransform) { 1612 if (mShader) { 1613 if (ignoreTransform) { 1614 mModelView.loadInverse(*mSnapshot->transform); 1615 } 1616 mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &mTextureUnit); 1617 } 1618} 1619 1620void OpenGLRenderer::setupDrawShaderIdentityUniforms() { 1621 if (mShader) { 1622 mShader->setupProgram(mCaches.currentProgram, mIdentity, *mSnapshot, &mTextureUnit); 1623 } 1624} 1625 1626void OpenGLRenderer::setupDrawColorFilterUniforms() { 1627 if (mColorFilter) { 1628 mColorFilter->setupProgram(mCaches.currentProgram); 1629 } 1630} 1631 1632void OpenGLRenderer::setupDrawTextGammaUniforms() { 1633 mCaches.fontRenderer->setupProgram(mDescription, mCaches.currentProgram); 1634} 1635 1636void OpenGLRenderer::setupDrawSimpleMesh() { 1637 bool force = mCaches.bindMeshBuffer(); 1638 mCaches.bindPositionVertexPointer(force, 0); 1639 mCaches.unbindIndicesBuffer(); 1640} 1641 1642void OpenGLRenderer::setupDrawTexture(GLuint texture) { 1643 bindTexture(texture); 1644 mTextureUnit++; 1645 mCaches.enableTexCoordsVertexArray(); 1646} 1647 1648void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) { 1649 bindExternalTexture(texture); 1650 mTextureUnit++; 1651 mCaches.enableTexCoordsVertexArray(); 1652} 1653 1654void OpenGLRenderer::setupDrawTextureTransform() { 1655 mDescription.hasTextureTransform = true; 1656} 1657 1658void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) { 1659 glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1, 1660 GL_FALSE, &transform.data[0]); 1661} 1662 1663void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLuint vbo) { 1664 bool force = false; 1665 if (!vertices) { 1666 force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo); 1667 } else { 1668 force = mCaches.unbindMeshBuffer(); 1669 } 1670 1671 mCaches.bindPositionVertexPointer(force, vertices); 1672 if (mCaches.currentProgram->texCoords >= 0) { 1673 mCaches.bindTexCoordsVertexPointer(force, texCoords); 1674 } 1675 1676 mCaches.unbindIndicesBuffer(); 1677} 1678 1679void OpenGLRenderer::setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords) { 1680 bool force = mCaches.unbindMeshBuffer(); 1681 mCaches.bindPositionVertexPointer(force, vertices); 1682 if (mCaches.currentProgram->texCoords >= 0) { 1683 mCaches.bindTexCoordsVertexPointer(force, texCoords); 1684 } 1685} 1686 1687void OpenGLRenderer::setupDrawVertices(GLvoid* vertices) { 1688 bool force = mCaches.unbindMeshBuffer(); 1689 mCaches.bindPositionVertexPointer(force, vertices, gVertexStride); 1690 mCaches.unbindIndicesBuffer(); 1691} 1692 1693/** 1694 * Sets up the shader to draw an AA line. We draw AA lines with quads, where there is an 1695 * outer boundary that fades out to 0. The variables set in the shader define the proportion of 1696 * the width and length of the primitive occupied by the AA region. The vtxWidth and vtxLength 1697 * attributes (one per vertex) are values from zero to one that tells the fragment 1698 * shader where the fragment is in relation to the line width/length overall; these values are 1699 * then used to compute the proper color, based on whether the fragment lies in the fading AA 1700 * region of the line. 1701 * Note that we only pass down the width values in this setup function. The length coordinates 1702 * are set up for each individual segment. 1703 */ 1704void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* widthCoords, 1705 GLvoid* lengthCoords, float boundaryWidthProportion, int& widthSlot, int& lengthSlot) { 1706 bool force = mCaches.unbindMeshBuffer(); 1707 mCaches.bindPositionVertexPointer(force, vertices, gAAVertexStride); 1708 mCaches.resetTexCoordsVertexPointer(); 1709 mCaches.unbindIndicesBuffer(); 1710 1711 widthSlot = mCaches.currentProgram->getAttrib("vtxWidth"); 1712 glEnableVertexAttribArray(widthSlot); 1713 glVertexAttribPointer(widthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, widthCoords); 1714 1715 lengthSlot = mCaches.currentProgram->getAttrib("vtxLength"); 1716 glEnableVertexAttribArray(lengthSlot); 1717 glVertexAttribPointer(lengthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, lengthCoords); 1718 1719 int boundaryWidthSlot = mCaches.currentProgram->getUniform("boundaryWidth"); 1720 glUniform1f(boundaryWidthSlot, boundaryWidthProportion); 1721} 1722 1723void OpenGLRenderer::finishDrawAALine(const int widthSlot, const int lengthSlot) { 1724 glDisableVertexAttribArray(widthSlot); 1725 glDisableVertexAttribArray(lengthSlot); 1726} 1727 1728void OpenGLRenderer::finishDrawTexture() { 1729} 1730 1731/////////////////////////////////////////////////////////////////////////////// 1732// Drawing 1733/////////////////////////////////////////////////////////////////////////////// 1734 1735status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, 1736 Rect& dirty, int32_t flags, uint32_t level) { 1737 1738 // All the usual checks and setup operations (quickReject, setupDraw, etc.) 1739 // will be performed by the display list itself 1740 if (displayList && displayList->isRenderable()) { 1741 return displayList->replay(*this, dirty, flags, level); 1742 } 1743 1744 return DrawGlInfo::kStatusDone; 1745} 1746 1747void OpenGLRenderer::outputDisplayList(DisplayList* displayList, uint32_t level) { 1748 if (displayList) { 1749 displayList->output(level); 1750 } 1751} 1752 1753void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint) { 1754 int alpha; 1755 SkXfermode::Mode mode; 1756 getAlphaAndMode(paint, &alpha, &mode); 1757 1758 int color = paint != NULL ? paint->getColor() : 0; 1759 1760 float x = left; 1761 float y = top; 1762 1763 texture->setWrap(GL_CLAMP_TO_EDGE, true); 1764 1765 bool ignoreTransform = false; 1766 if (mSnapshot->transform->isPureTranslate()) { 1767 x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f); 1768 y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f); 1769 ignoreTransform = true; 1770 1771 texture->setFilter(GL_NEAREST, true); 1772 } else { 1773 texture->setFilter(FILTER(paint), true); 1774 } 1775 1776 drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id, 1777 paint != NULL, color, alpha, mode, (GLvoid*) NULL, 1778 (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform); 1779} 1780 1781status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) { 1782 const float right = left + bitmap->width(); 1783 const float bottom = top + bitmap->height(); 1784 1785 if (quickReject(left, top, right, bottom)) { 1786 return DrawGlInfo::kStatusDone; 1787 } 1788 1789 mCaches.activeTexture(0); 1790 Texture* texture = mCaches.textureCache.get(bitmap); 1791 if (!texture) return DrawGlInfo::kStatusDone; 1792 const AutoTexture autoCleanup(texture); 1793 1794 if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) { 1795 drawAlphaBitmap(texture, left, top, paint); 1796 } else { 1797 drawTextureRect(left, top, right, bottom, texture, paint); 1798 } 1799 1800 return DrawGlInfo::kStatusDrew; 1801} 1802 1803status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) { 1804 Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height()); 1805 const mat4 transform(*matrix); 1806 transform.mapRect(r); 1807 1808 if (quickReject(r.left, r.top, r.right, r.bottom)) { 1809 return DrawGlInfo::kStatusDone; 1810 } 1811 1812 mCaches.activeTexture(0); 1813 Texture* texture = mCaches.textureCache.get(bitmap); 1814 if (!texture) return DrawGlInfo::kStatusDone; 1815 const AutoTexture autoCleanup(texture); 1816 1817 // This could be done in a cheaper way, all we need is pass the matrix 1818 // to the vertex shader. The save/restore is a bit overkill. 1819 save(SkCanvas::kMatrix_SaveFlag); 1820 concatMatrix(matrix); 1821 if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) { 1822 drawAlphaBitmap(texture, 0.0f, 0.0f, paint); 1823 } else { 1824 drawTextureRect(0.0f, 0.0f, bitmap->width(), bitmap->height(), texture, paint); 1825 } 1826 restore(); 1827 1828 return DrawGlInfo::kStatusDrew; 1829} 1830 1831status_t OpenGLRenderer::drawBitmapData(SkBitmap* bitmap, float left, float top, SkPaint* paint) { 1832 const float right = left + bitmap->width(); 1833 const float bottom = top + bitmap->height(); 1834 1835 if (quickReject(left, top, right, bottom)) { 1836 return DrawGlInfo::kStatusDone; 1837 } 1838 1839 mCaches.activeTexture(0); 1840 Texture* texture = mCaches.textureCache.getTransient(bitmap); 1841 const AutoTexture autoCleanup(texture); 1842 1843 if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) { 1844 drawAlphaBitmap(texture, left, top, paint); 1845 } else { 1846 drawTextureRect(left, top, right, bottom, texture, paint); 1847 } 1848 1849 return DrawGlInfo::kStatusDrew; 1850} 1851 1852status_t OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight, 1853 float* vertices, int* colors, SkPaint* paint) { 1854 if (!vertices || mSnapshot->isIgnored()) { 1855 return DrawGlInfo::kStatusDone; 1856 } 1857 1858 float left = FLT_MAX; 1859 float top = FLT_MAX; 1860 float right = FLT_MIN; 1861 float bottom = FLT_MIN; 1862 1863 const uint32_t count = meshWidth * meshHeight * 6; 1864 1865 // TODO: Support the colors array 1866 TextureVertex mesh[count]; 1867 TextureVertex* vertex = mesh; 1868 1869 for (int32_t y = 0; y < meshHeight; y++) { 1870 for (int32_t x = 0; x < meshWidth; x++) { 1871 uint32_t i = (y * (meshWidth + 1) + x) * 2; 1872 1873 float u1 = float(x) / meshWidth; 1874 float u2 = float(x + 1) / meshWidth; 1875 float v1 = float(y) / meshHeight; 1876 float v2 = float(y + 1) / meshHeight; 1877 1878 int ax = i + (meshWidth + 1) * 2; 1879 int ay = ax + 1; 1880 int bx = i; 1881 int by = bx + 1; 1882 int cx = i + 2; 1883 int cy = cx + 1; 1884 int dx = i + (meshWidth + 1) * 2 + 2; 1885 int dy = dx + 1; 1886 1887 TextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2); 1888 TextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1); 1889 TextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1); 1890 1891 TextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2); 1892 TextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1); 1893 TextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2); 1894 1895 left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx]))); 1896 top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy]))); 1897 right = fmaxf(right, fmaxf(vertices[ax], fmaxf(vertices[bx], vertices[cx]))); 1898 bottom = fmaxf(bottom, fmaxf(vertices[ay], fmaxf(vertices[by], vertices[cy]))); 1899 } 1900 } 1901 1902 if (quickReject(left, top, right, bottom)) { 1903 return DrawGlInfo::kStatusDone; 1904 } 1905 1906 mCaches.activeTexture(0); 1907 Texture* texture = mCaches.textureCache.get(bitmap); 1908 if (!texture) return DrawGlInfo::kStatusDone; 1909 const AutoTexture autoCleanup(texture); 1910 1911 texture->setWrap(GL_CLAMP_TO_EDGE, true); 1912 texture->setFilter(FILTER(paint), true); 1913 1914 int alpha; 1915 SkXfermode::Mode mode; 1916 getAlphaAndMode(paint, &alpha, &mode); 1917 1918 if (hasLayer()) { 1919 dirtyLayer(left, top, right, bottom, *mSnapshot->transform); 1920 } 1921 1922 drawTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, alpha / 255.0f, 1923 mode, texture->blend, &mesh[0].position[0], &mesh[0].texture[0], 1924 GL_TRIANGLES, count, false, false, 0, false, false); 1925 1926 return DrawGlInfo::kStatusDrew; 1927} 1928 1929status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, 1930 float srcLeft, float srcTop, float srcRight, float srcBottom, 1931 float dstLeft, float dstTop, float dstRight, float dstBottom, 1932 SkPaint* paint) { 1933 if (quickReject(dstLeft, dstTop, dstRight, dstBottom)) { 1934 return DrawGlInfo::kStatusDone; 1935 } 1936 1937 mCaches.activeTexture(0); 1938 Texture* texture = mCaches.textureCache.get(bitmap); 1939 if (!texture) return DrawGlInfo::kStatusDone; 1940 const AutoTexture autoCleanup(texture); 1941 1942 const float width = texture->width; 1943 const float height = texture->height; 1944 1945 const float u1 = fmax(0.0f, srcLeft / width); 1946 const float v1 = fmax(0.0f, srcTop / height); 1947 const float u2 = fmin(1.0f, srcRight / width); 1948 const float v2 = fmin(1.0f, srcBottom / height); 1949 1950 mCaches.unbindMeshBuffer(); 1951 resetDrawTextureTexCoords(u1, v1, u2, v2); 1952 1953 int alpha; 1954 SkXfermode::Mode mode; 1955 getAlphaAndMode(paint, &alpha, &mode); 1956 1957 texture->setWrap(GL_CLAMP_TO_EDGE, true); 1958 1959 float scaleX = (dstRight - dstLeft) / (srcRight - srcLeft); 1960 float scaleY = (dstBottom - dstTop) / (srcBottom - srcTop); 1961 1962 bool scaled = scaleX != 1.0f || scaleY != 1.0f; 1963 // Apply a scale transform on the canvas only when a shader is in use 1964 // Skia handles the ratio between the dst and src rects as a scale factor 1965 // when a shader is set 1966 bool useScaleTransform = mShader && scaled; 1967 bool ignoreTransform = false; 1968 1969 if (CC_LIKELY(mSnapshot->transform->isPureTranslate() && !useScaleTransform)) { 1970 float x = (int) floorf(dstLeft + mSnapshot->transform->getTranslateX() + 0.5f); 1971 float y = (int) floorf(dstTop + mSnapshot->transform->getTranslateY() + 0.5f); 1972 1973 dstRight = x + (dstRight - dstLeft); 1974 dstBottom = y + (dstBottom - dstTop); 1975 1976 dstLeft = x; 1977 dstTop = y; 1978 1979 texture->setFilter(scaled ? FILTER(paint) : GL_NEAREST, true); 1980 ignoreTransform = true; 1981 } else { 1982 texture->setFilter(FILTER(paint), true); 1983 } 1984 1985 if (CC_UNLIKELY(useScaleTransform)) { 1986 save(SkCanvas::kMatrix_SaveFlag); 1987 translate(dstLeft, dstTop); 1988 scale(scaleX, scaleY); 1989 1990 dstLeft = 0.0f; 1991 dstTop = 0.0f; 1992 1993 dstRight = srcRight - srcLeft; 1994 dstBottom = srcBottom - srcTop; 1995 } 1996 1997 if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) { 1998 int color = paint ? paint->getColor() : 0; 1999 drawAlpha8TextureMesh(dstLeft, dstTop, dstRight, dstBottom, 2000 texture->id, paint != NULL, color, alpha, mode, 2001 &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], 2002 GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform); 2003 } else { 2004 drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom, 2005 texture->id, alpha / 255.0f, mode, texture->blend, 2006 &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], 2007 GL_TRIANGLE_STRIP, gMeshCount, false, ignoreTransform); 2008 } 2009 2010 if (CC_UNLIKELY(useScaleTransform)) { 2011 restore(); 2012 } 2013 2014 resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); 2015 2016 return DrawGlInfo::kStatusDrew; 2017} 2018 2019status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, 2020 const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, 2021 float left, float top, float right, float bottom, SkPaint* paint) { 2022 int alpha; 2023 SkXfermode::Mode mode; 2024 getAlphaAndModeDirect(paint, &alpha, &mode); 2025 2026 return drawPatch(bitmap, xDivs, yDivs, colors, width, height, numColors, 2027 left, top, right, bottom, alpha, mode); 2028} 2029 2030status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, 2031 const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, 2032 float left, float top, float right, float bottom, int alpha, SkXfermode::Mode mode) { 2033 if (quickReject(left, top, right, bottom)) { 2034 return DrawGlInfo::kStatusDone; 2035 } 2036 2037 alpha *= mSnapshot->alpha; 2038 2039 mCaches.activeTexture(0); 2040 Texture* texture = mCaches.textureCache.get(bitmap); 2041 if (!texture) return DrawGlInfo::kStatusDone; 2042 const AutoTexture autoCleanup(texture); 2043 texture->setWrap(GL_CLAMP_TO_EDGE, true); 2044 texture->setFilter(GL_LINEAR, true); 2045 2046 const Patch* mesh = mCaches.patchCache.get(bitmap->width(), bitmap->height(), 2047 right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors); 2048 2049 if (CC_LIKELY(mesh && mesh->verticesCount > 0)) { 2050 const bool pureTranslate = mSnapshot->transform->isPureTranslate(); 2051 // Mark the current layer dirty where we are going to draw the patch 2052 if (hasLayer() && mesh->hasEmptyQuads) { 2053 const float offsetX = left + mSnapshot->transform->getTranslateX(); 2054 const float offsetY = top + mSnapshot->transform->getTranslateY(); 2055 const size_t count = mesh->quads.size(); 2056 for (size_t i = 0; i < count; i++) { 2057 const Rect& bounds = mesh->quads.itemAt(i); 2058 if (CC_LIKELY(pureTranslate)) { 2059 const float x = (int) floorf(bounds.left + offsetX + 0.5f); 2060 const float y = (int) floorf(bounds.top + offsetY + 0.5f); 2061 dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight()); 2062 } else { 2063 dirtyLayer(left + bounds.left, top + bounds.top, 2064 left + bounds.right, top + bounds.bottom, *mSnapshot->transform); 2065 } 2066 } 2067 } 2068 2069 if (CC_LIKELY(pureTranslate)) { 2070 const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f); 2071 const float y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f); 2072 2073 drawTextureMesh(x, y, x + right - left, y + bottom - top, texture->id, alpha / 255.0f, 2074 mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset, 2075 GL_TRIANGLES, mesh->verticesCount, false, true, mesh->meshBuffer, 2076 true, !mesh->hasEmptyQuads); 2077 } else { 2078 drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, 2079 mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset, 2080 GL_TRIANGLES, mesh->verticesCount, false, false, mesh->meshBuffer, 2081 true, !mesh->hasEmptyQuads); 2082 } 2083 } 2084 2085 return DrawGlInfo::kStatusDrew; 2086} 2087 2088/** 2089 * Renders a convex path via tessellation. For AA paths, this function uses a similar approach to 2090 * that of AA lines in the drawLines() function. We expand the convex path by a half pixel in 2091 * screen space in all directions. However, instead of using a fragment shader to compute the 2092 * translucency of the color from its position, we simply use a varying parameter to define how far 2093 * a given pixel is from the edge. For non-AA paths, the expansion and alpha varying are not used. 2094 * 2095 * Doesn't yet support joins, caps, or path effects. 2096 */ 2097void OpenGLRenderer::drawConvexPath(const SkPath& path, SkPaint* paint) { 2098 int color = paint->getColor(); 2099 SkXfermode::Mode mode = getXfermode(paint->getXfermode()); 2100 bool isAA = paint->isAntiAlias(); 2101 2102 VertexBuffer vertexBuffer; 2103 // TODO: try clipping large paths to viewport 2104 PathRenderer::convexPathVertices(path, paint, mSnapshot->transform, vertexBuffer); 2105 2106 if (!vertexBuffer.getSize()) { 2107 // no vertices to draw 2108 return; 2109 } 2110 2111 setupDraw(); 2112 setupDrawNoTexture(); 2113 if (isAA) setupDrawAA(); 2114 setupDrawVertexShape(); 2115 setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha); 2116 setupDrawColorFilter(); 2117 setupDrawShader(); 2118 setupDrawBlending(isAA, mode); 2119 setupDrawProgram(); 2120 setupDrawModelViewIdentity(); 2121 setupDrawColorUniforms(); 2122 setupDrawColorFilterUniforms(); 2123 setupDrawShaderIdentityUniforms(); 2124 2125 void* vertices = vertexBuffer.getBuffer(); 2126 bool force = mCaches.unbindMeshBuffer(); 2127 mCaches.bindPositionVertexPointer(true, vertices, isAA ? gAlphaVertexStride : gVertexStride); 2128 mCaches.resetTexCoordsVertexPointer(); 2129 mCaches.unbindIndicesBuffer(); 2130 2131 int alphaSlot = -1; 2132 if (isAA) { 2133 void* alphaCoords = ((GLbyte*) vertices) + gVertexAlphaOffset; 2134 alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha"); 2135 2136 // TODO: avoid enable/disable in back to back uses of the alpha attribute 2137 glEnableVertexAttribArray(alphaSlot); 2138 glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords); 2139 } 2140 2141 SkRect bounds = PathRenderer::computePathBounds(path, paint); 2142 dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, *mSnapshot->transform); 2143 2144 glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getSize()); 2145 2146 if (isAA) { 2147 glDisableVertexAttribArray(alphaSlot); 2148 } 2149} 2150 2151/** 2152 * We draw lines as quads (tristrips). Using GL_LINES can be difficult because the rasterization 2153 * rules for those lines produces some unexpected results, and may vary between hardware devices. 2154 * The basics of lines-as-quads is easy; we simply find the normal to the line and position the 2155 * corners of the quads on either side of each line endpoint, separated by the strokeWidth 2156 * of the line. Hairlines are more involved because we need to account for transform scaling 2157 * to end up with a one-pixel-wide line in screen space.. 2158 * Anti-aliased lines add another factor to the approach. We use a specialized fragment shader 2159 * in combination with values that we calculate and pass down in this method. The basic approach 2160 * is that the quad we create contains both the core line area plus a bounding area in which 2161 * the translucent/AA pixels are drawn. The values we calculate tell the shader what 2162 * proportion of the width and the length of a given segment is represented by the boundary 2163 * region. The quad ends up being exactly .5 pixel larger in all directions than the non-AA quad. 2164 * The bounding region is actually 1 pixel wide on all sides (half pixel on the outside, half pixel 2165 * on the inside). This ends up giving the result we want, with pixels that are completely 2166 * 'inside' the line area being filled opaquely and the other pixels being filled according to 2167 * how far into the boundary region they are, which is determined by shader interpolation. 2168 */ 2169status_t OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { 2170 if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone; 2171 2172 const bool isAA = paint->isAntiAlias(); 2173 // We use half the stroke width here because we're going to position the quad 2174 // corner vertices half of the width away from the line endpoints 2175 float halfStrokeWidth = paint->getStrokeWidth() * 0.5f; 2176 // A stroke width of 0 has a special meaning in Skia: 2177 // it draws a line 1 px wide regardless of current transform 2178 bool isHairLine = paint->getStrokeWidth() == 0.0f; 2179 2180 float inverseScaleX = 1.0f; 2181 float inverseScaleY = 1.0f; 2182 bool scaled = false; 2183 2184 int alpha; 2185 SkXfermode::Mode mode; 2186 2187 int generatedVerticesCount = 0; 2188 int verticesCount = count; 2189 if (count > 4) { 2190 // Polyline: account for extra vertices needed for continuous tri-strip 2191 verticesCount += (count - 4); 2192 } 2193 2194 if (isHairLine || isAA) { 2195 // The quad that we use for AA and hairlines needs to account for scaling. For hairlines 2196 // the line on the screen should always be one pixel wide regardless of scale. For 2197 // AA lines, we only want one pixel of translucent boundary around the quad. 2198 if (CC_UNLIKELY(!mSnapshot->transform->isPureTranslate())) { 2199 Matrix4 *mat = mSnapshot->transform; 2200 float m00 = mat->data[Matrix4::kScaleX]; 2201 float m01 = mat->data[Matrix4::kSkewY]; 2202 float m10 = mat->data[Matrix4::kSkewX]; 2203 float m11 = mat->data[Matrix4::kScaleY]; 2204 2205 float scaleX = sqrtf(m00 * m00 + m01 * m01); 2206 float scaleY = sqrtf(m10 * m10 + m11 * m11); 2207 2208 inverseScaleX = (scaleX != 0) ? (inverseScaleX / scaleX) : 0; 2209 inverseScaleY = (scaleY != 0) ? (inverseScaleY / scaleY) : 0; 2210 2211 if (inverseScaleX != 1.0f || inverseScaleY != 1.0f) { 2212 scaled = true; 2213 } 2214 } 2215 } 2216 2217 getAlphaAndMode(paint, &alpha, &mode); 2218 2219 mCaches.enableScissor(); 2220 2221 setupDraw(); 2222 setupDrawNoTexture(); 2223 if (isAA) { 2224 setupDrawAA(); 2225 } 2226 setupDrawColor(paint->getColor(), alpha); 2227 setupDrawColorFilter(); 2228 setupDrawShader(); 2229 setupDrawBlending(isAA, mode); 2230 setupDrawProgram(); 2231 setupDrawModelViewIdentity(true); 2232 setupDrawColorUniforms(); 2233 setupDrawColorFilterUniforms(); 2234 setupDrawShaderIdentityUniforms(); 2235 2236 if (isHairLine) { 2237 // Set a real stroke width to be used in quad construction 2238 halfStrokeWidth = isAA? 1 : .5; 2239 } else if (isAA && !scaled) { 2240 // Expand boundary to enable AA calculations on the quad border 2241 halfStrokeWidth += .5f; 2242 } 2243 2244 int widthSlot; 2245 int lengthSlot; 2246 2247 Vertex lines[verticesCount]; 2248 Vertex* vertices = &lines[0]; 2249 2250 AAVertex wLines[verticesCount]; 2251 AAVertex* aaVertices = &wLines[0]; 2252 2253 if (CC_UNLIKELY(!isAA)) { 2254 setupDrawVertices(vertices); 2255 } else { 2256 void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset; 2257 void* lengthCoords = ((GLbyte*) aaVertices) + gVertexAALengthOffset; 2258 // innerProportion is the ratio of the inner (non-AA) part of the line to the total 2259 // AA stroke width (the base stroke width expanded by a half pixel on either side). 2260 // This value is used in the fragment shader to determine how to fill fragments. 2261 // We will need to calculate the actual width proportion on each segment for 2262 // scaled non-hairlines, since the boundary proportion may differ per-axis when scaled. 2263 float boundaryWidthProportion = .5 - 1 / (2 * halfStrokeWidth); 2264 setupDrawAALine((void*) aaVertices, widthCoords, lengthCoords, 2265 boundaryWidthProportion, widthSlot, lengthSlot); 2266 } 2267 2268 AAVertex* prevAAVertex = NULL; 2269 Vertex* prevVertex = NULL; 2270 2271 int boundaryLengthSlot = -1; 2272 int boundaryWidthSlot = -1; 2273 2274 for (int i = 0; i < count; i += 4) { 2275 // a = start point, b = end point 2276 vec2 a(points[i], points[i + 1]); 2277 vec2 b(points[i + 2], points[i + 3]); 2278 2279 float length = 0; 2280 float boundaryLengthProportion = 0; 2281 float boundaryWidthProportion = 0; 2282 2283 // Find the normal to the line 2284 vec2 n = (b - a).copyNormalized() * halfStrokeWidth; 2285 float x = n.x; 2286 n.x = -n.y; 2287 n.y = x; 2288 2289 if (isHairLine) { 2290 if (isAA) { 2291 float wideningFactor; 2292 if (fabs(n.x) >= fabs(n.y)) { 2293 wideningFactor = fabs(1.0f / n.x); 2294 } else { 2295 wideningFactor = fabs(1.0f / n.y); 2296 } 2297 n *= wideningFactor; 2298 } 2299 2300 if (scaled) { 2301 n.x *= inverseScaleX; 2302 n.y *= inverseScaleY; 2303 } 2304 } else if (scaled) { 2305 // Extend n by .5 pixel on each side, post-transform 2306 vec2 extendedN = n.copyNormalized(); 2307 extendedN /= 2; 2308 extendedN.x *= inverseScaleX; 2309 extendedN.y *= inverseScaleY; 2310 2311 float extendedNLength = extendedN.length(); 2312 // We need to set this value on the shader prior to drawing 2313 boundaryWidthProportion = .5 - extendedNLength / (halfStrokeWidth + extendedNLength); 2314 n += extendedN; 2315 } 2316 2317 // aa lines expand the endpoint vertices to encompass the AA boundary 2318 if (isAA) { 2319 vec2 abVector = (b - a); 2320 length = abVector.length(); 2321 abVector.normalize(); 2322 2323 if (scaled) { 2324 abVector.x *= inverseScaleX; 2325 abVector.y *= inverseScaleY; 2326 float abLength = abVector.length(); 2327 boundaryLengthProportion = .5 - abLength / (length + abLength); 2328 } else { 2329 boundaryLengthProportion = .5 - .5 / (length + 1); 2330 } 2331 2332 abVector /= 2; 2333 a -= abVector; 2334 b += abVector; 2335 } 2336 2337 // Four corners of the rectangle defining a thick line 2338 vec2 p1 = a - n; 2339 vec2 p2 = a + n; 2340 vec2 p3 = b + n; 2341 vec2 p4 = b - n; 2342 2343 2344 const float left = fmin(p1.x, fmin(p2.x, fmin(p3.x, p4.x))); 2345 const float right = fmax(p1.x, fmax(p2.x, fmax(p3.x, p4.x))); 2346 const float top = fmin(p1.y, fmin(p2.y, fmin(p3.y, p4.y))); 2347 const float bottom = fmax(p1.y, fmax(p2.y, fmax(p3.y, p4.y))); 2348 2349 if (!quickRejectNoScissor(left, top, right, bottom)) { 2350 if (!isAA) { 2351 if (prevVertex != NULL) { 2352 // Issue two repeat vertices to create degenerate triangles to bridge 2353 // between the previous line and the new one. This is necessary because 2354 // we are creating a single triangle_strip which will contain 2355 // potentially discontinuous line segments. 2356 Vertex::set(vertices++, prevVertex->position[0], prevVertex->position[1]); 2357 Vertex::set(vertices++, p1.x, p1.y); 2358 generatedVerticesCount += 2; 2359 } 2360 2361 Vertex::set(vertices++, p1.x, p1.y); 2362 Vertex::set(vertices++, p2.x, p2.y); 2363 Vertex::set(vertices++, p4.x, p4.y); 2364 Vertex::set(vertices++, p3.x, p3.y); 2365 2366 prevVertex = vertices - 1; 2367 generatedVerticesCount += 4; 2368 } else { 2369 if (!isHairLine && scaled) { 2370 // Must set width proportions per-segment for scaled non-hairlines to use the 2371 // correct AA boundary dimensions 2372 if (boundaryWidthSlot < 0) { 2373 boundaryWidthSlot = 2374 mCaches.currentProgram->getUniform("boundaryWidth"); 2375 } 2376 2377 glUniform1f(boundaryWidthSlot, boundaryWidthProportion); 2378 } 2379 2380 if (boundaryLengthSlot < 0) { 2381 boundaryLengthSlot = mCaches.currentProgram->getUniform("boundaryLength"); 2382 } 2383 2384 glUniform1f(boundaryLengthSlot, boundaryLengthProportion); 2385 2386 if (prevAAVertex != NULL) { 2387 // Issue two repeat vertices to create degenerate triangles to bridge 2388 // between the previous line and the new one. This is necessary because 2389 // we are creating a single triangle_strip which will contain 2390 // potentially discontinuous line segments. 2391 AAVertex::set(aaVertices++,prevAAVertex->position[0], 2392 prevAAVertex->position[1], prevAAVertex->width, prevAAVertex->length); 2393 AAVertex::set(aaVertices++, p4.x, p4.y, 1, 1); 2394 generatedVerticesCount += 2; 2395 } 2396 2397 AAVertex::set(aaVertices++, p4.x, p4.y, 1, 1); 2398 AAVertex::set(aaVertices++, p1.x, p1.y, 1, 0); 2399 AAVertex::set(aaVertices++, p3.x, p3.y, 0, 1); 2400 AAVertex::set(aaVertices++, p2.x, p2.y, 0, 0); 2401 2402 prevAAVertex = aaVertices - 1; 2403 generatedVerticesCount += 4; 2404 } 2405 2406 dirtyLayer(a.x == b.x ? left - 1 : left, a.y == b.y ? top - 1 : top, 2407 a.x == b.x ? right: right, a.y == b.y ? bottom: bottom, 2408 *mSnapshot->transform); 2409 } 2410 } 2411 2412 if (generatedVerticesCount > 0) { 2413 glDrawArrays(GL_TRIANGLE_STRIP, 0, generatedVerticesCount); 2414 } 2415 2416 if (isAA) { 2417 finishDrawAALine(widthSlot, lengthSlot); 2418 } 2419 2420 return DrawGlInfo::kStatusDrew; 2421} 2422 2423status_t OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) { 2424 if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone; 2425 2426 // TODO: The paint's cap style defines whether the points are square or circular 2427 // TODO: Handle AA for round points 2428 2429 // A stroke width of 0 has a special meaning in Skia: 2430 // it draws an unscaled 1px point 2431 float strokeWidth = paint->getStrokeWidth(); 2432 const bool isHairLine = paint->getStrokeWidth() == 0.0f; 2433 if (isHairLine) { 2434 // Now that we know it's hairline, we can set the effective width, to be used later 2435 strokeWidth = 1.0f; 2436 } 2437 const float halfWidth = strokeWidth / 2; 2438 int alpha; 2439 SkXfermode::Mode mode; 2440 getAlphaAndMode(paint, &alpha, &mode); 2441 2442 int verticesCount = count >> 1; 2443 int generatedVerticesCount = 0; 2444 2445 TextureVertex pointsData[verticesCount]; 2446 TextureVertex* vertex = &pointsData[0]; 2447 2448 // TODO: We should optimize this method to not generate vertices for points 2449 // that lie outside of the clip. 2450 mCaches.enableScissor(); 2451 2452 setupDraw(); 2453 setupDrawNoTexture(); 2454 setupDrawPoint(strokeWidth); 2455 setupDrawColor(paint->getColor(), alpha); 2456 setupDrawColorFilter(); 2457 setupDrawShader(); 2458 setupDrawBlending(mode); 2459 setupDrawProgram(); 2460 setupDrawModelViewIdentity(true); 2461 setupDrawColorUniforms(); 2462 setupDrawColorFilterUniforms(); 2463 setupDrawPointUniforms(); 2464 setupDrawShaderIdentityUniforms(); 2465 setupDrawMesh(vertex); 2466 2467 for (int i = 0; i < count; i += 2) { 2468 TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f); 2469 generatedVerticesCount++; 2470 2471 float left = points[i] - halfWidth; 2472 float right = points[i] + halfWidth; 2473 float top = points[i + 1] - halfWidth; 2474 float bottom = points [i + 1] + halfWidth; 2475 2476 dirtyLayer(left, top, right, bottom, *mSnapshot->transform); 2477 } 2478 2479 glDrawArrays(GL_POINTS, 0, generatedVerticesCount); 2480 2481 return DrawGlInfo::kStatusDrew; 2482} 2483 2484status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { 2485 // No need to check against the clip, we fill the clip region 2486 if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone; 2487 2488 Rect& clip(*mSnapshot->clipRect); 2489 clip.snapToPixelBoundaries(); 2490 2491 drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true); 2492 2493 return DrawGlInfo::kStatusDrew; 2494} 2495 2496status_t OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture, 2497 SkPaint* paint) { 2498 if (!texture) return DrawGlInfo::kStatusDone; 2499 const AutoTexture autoCleanup(texture); 2500 2501 const float x = left + texture->left - texture->offset; 2502 const float y = top + texture->top - texture->offset; 2503 2504 drawPathTexture(texture, x, y, paint); 2505 2506 return DrawGlInfo::kStatusDrew; 2507} 2508 2509status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom, 2510 float rx, float ry, SkPaint* p) { 2511 if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p)) { 2512 return DrawGlInfo::kStatusDone; 2513 } 2514 2515 if (p->getPathEffect() != 0) { 2516 mCaches.activeTexture(0); 2517 const PathTexture* texture = mCaches.roundRectShapeCache.getRoundRect( 2518 right - left, bottom - top, rx, ry, p); 2519 return drawShape(left, top, texture, p); 2520 } 2521 2522 SkPath path; 2523 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); 2524 if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { 2525 float outset = p->getStrokeWidth() / 2; 2526 rect.outset(outset, outset); 2527 rx += outset; 2528 ry += outset; 2529 } 2530 path.addRoundRect(rect, rx, ry); 2531 drawConvexPath(path, p); 2532 2533 return DrawGlInfo::kStatusDrew; 2534} 2535 2536status_t OpenGLRenderer::drawCircle(float x, float y, float radius, SkPaint* p) { 2537 if (mSnapshot->isIgnored() || quickRejectPreStroke(x - radius, y - radius, 2538 x + radius, y + radius, p)) { 2539 return DrawGlInfo::kStatusDone; 2540 } 2541 if (p->getPathEffect() != 0) { 2542 mCaches.activeTexture(0); 2543 const PathTexture* texture = mCaches.circleShapeCache.getCircle(radius, p); 2544 return drawShape(x - radius, y - radius, texture, p); 2545 } 2546 2547 SkPath path; 2548 if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { 2549 path.addCircle(x, y, radius + p->getStrokeWidth() / 2); 2550 } else { 2551 path.addCircle(x, y, radius); 2552 } 2553 drawConvexPath(path, p); 2554 2555 return DrawGlInfo::kStatusDrew; 2556} 2557 2558status_t OpenGLRenderer::drawOval(float left, float top, float right, float bottom, 2559 SkPaint* p) { 2560 if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p)) { 2561 return DrawGlInfo::kStatusDone; 2562 } 2563 2564 if (p->getPathEffect() != 0) { 2565 mCaches.activeTexture(0); 2566 const PathTexture* texture = mCaches.ovalShapeCache.getOval(right - left, bottom - top, p); 2567 return drawShape(left, top, texture, p); 2568 } 2569 2570 SkPath path; 2571 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); 2572 if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { 2573 rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2); 2574 } 2575 path.addOval(rect); 2576 drawConvexPath(path, p); 2577 2578 return DrawGlInfo::kStatusDrew; 2579} 2580 2581status_t OpenGLRenderer::drawArc(float left, float top, float right, float bottom, 2582 float startAngle, float sweepAngle, bool useCenter, SkPaint* p) { 2583 if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p)) { 2584 return DrawGlInfo::kStatusDone; 2585 } 2586 2587 if (fabs(sweepAngle) >= 360.0f) { 2588 return drawOval(left, top, right, bottom, p); 2589 } 2590 2591 // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180) 2592 if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != 0 || 2593 p->getStrokeCap() != SkPaint::kButt_Cap || useCenter) { 2594 mCaches.activeTexture(0); 2595 const PathTexture* texture = mCaches.arcShapeCache.getArc(right - left, bottom - top, 2596 startAngle, sweepAngle, useCenter, p); 2597 return drawShape(left, top, texture, p); 2598 } 2599 2600 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); 2601 if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { 2602 rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2); 2603 } 2604 2605 SkPath path; 2606 if (useCenter) { 2607 path.moveTo(rect.centerX(), rect.centerY()); 2608 } 2609 path.arcTo(rect, startAngle, sweepAngle, !useCenter); 2610 if (useCenter) { 2611 path.close(); 2612 } 2613 drawConvexPath(path, p); 2614 2615 return DrawGlInfo::kStatusDrew; 2616} 2617 2618// See SkPaintDefaults.h 2619#define SkPaintDefaults_MiterLimit SkIntToScalar(4) 2620 2621status_t OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* p) { 2622 if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p)) { 2623 return DrawGlInfo::kStatusDone; 2624 } 2625 2626 if (p->getStyle() != SkPaint::kFill_Style) { 2627 // only fill style is supported by drawConvexPath, since others have to handle joins 2628 if (p->getPathEffect() != 0 || p->getStrokeJoin() != SkPaint::kMiter_Join || 2629 p->getStrokeMiter() != SkPaintDefaults_MiterLimit) { 2630 mCaches.activeTexture(0); 2631 const PathTexture* texture = 2632 mCaches.rectShapeCache.getRect(right - left, bottom - top, p); 2633 return drawShape(left, top, texture, p); 2634 } 2635 2636 SkPath path; 2637 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); 2638 if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { 2639 rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2); 2640 } 2641 path.addRect(rect); 2642 drawConvexPath(path, p); 2643 2644 return DrawGlInfo::kStatusDrew; 2645 } 2646 2647 if (p->isAntiAlias() && !mSnapshot->transform->isSimple()) { 2648 SkPath path; 2649 path.addRect(left, top, right, bottom); 2650 drawConvexPath(path, p); 2651 } else { 2652 drawColorRect(left, top, right, bottom, p->getColor(), getXfermode(p->getXfermode())); 2653 } 2654 2655 return DrawGlInfo::kStatusDrew; 2656} 2657 2658void OpenGLRenderer::drawTextShadow(SkPaint* paint, const char* text, int bytesCount, int count, 2659 const float* positions, FontRenderer& fontRenderer, int alpha, SkXfermode::Mode mode, 2660 float x, float y) { 2661 mCaches.activeTexture(0); 2662 2663 // NOTE: The drop shadow will not perform gamma correction 2664 // if shader-based correction is enabled 2665 mCaches.dropShadowCache.setFontRenderer(fontRenderer); 2666 const ShadowTexture* shadow = mCaches.dropShadowCache.get( 2667 paint, text, bytesCount, count, mShadowRadius, positions); 2668 const AutoTexture autoCleanup(shadow); 2669 2670 const float sx = x - shadow->left + mShadowDx; 2671 const float sy = y - shadow->top + mShadowDy; 2672 2673 const int shadowAlpha = ((mShadowColor >> 24) & 0xFF) * mSnapshot->alpha; 2674 int shadowColor = mShadowColor; 2675 if (mShader) { 2676 shadowColor = 0xffffffff; 2677 } 2678 2679 setupDraw(); 2680 setupDrawWithTexture(true); 2681 setupDrawAlpha8Color(shadowColor, shadowAlpha < 255 ? shadowAlpha : alpha); 2682 setupDrawColorFilter(); 2683 setupDrawShader(); 2684 setupDrawBlending(true, mode); 2685 setupDrawProgram(); 2686 setupDrawModelView(sx, sy, sx + shadow->width, sy + shadow->height); 2687 setupDrawTexture(shadow->id); 2688 setupDrawPureColorUniforms(); 2689 setupDrawColorFilterUniforms(); 2690 setupDrawShaderUniforms(); 2691 setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset); 2692 2693 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); 2694} 2695 2696status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count, 2697 const float* positions, SkPaint* paint) { 2698 if (text == NULL || count == 0 || mSnapshot->isIgnored() || 2699 (paint->getAlpha() * mSnapshot->alpha == 0 && paint->getXfermode() == NULL)) { 2700 return DrawGlInfo::kStatusDone; 2701 } 2702 2703 // NOTE: Skia does not support perspective transform on drawPosText yet 2704 if (!mSnapshot->transform->isSimple()) { 2705 return DrawGlInfo::kStatusDone; 2706 } 2707 2708 float x = 0.0f; 2709 float y = 0.0f; 2710 const bool pureTranslate = mSnapshot->transform->isPureTranslate(); 2711 if (pureTranslate) { 2712 x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f); 2713 y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f); 2714 } 2715 2716 FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint); 2717 fontRenderer.setFont(paint, *mSnapshot->transform); 2718 2719 int alpha; 2720 SkXfermode::Mode mode; 2721 getAlphaAndMode(paint, &alpha, &mode); 2722 2723 if (CC_UNLIKELY(mHasShadow)) { 2724 drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer, 2725 alpha, mode, 0.0f, 0.0f); 2726 } 2727 2728 // Pick the appropriate texture filtering 2729 bool linearFilter = mSnapshot->transform->changesBounds(); 2730 if (pureTranslate && !linearFilter) { 2731 linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f; 2732 } 2733 2734 mCaches.activeTexture(0); 2735 setupDraw(); 2736 setupDrawTextGamma(paint); 2737 setupDrawDirtyRegionsDisabled(); 2738 setupDrawWithTexture(true); 2739 setupDrawAlpha8Color(paint->getColor(), alpha); 2740 setupDrawColorFilter(); 2741 setupDrawShader(); 2742 setupDrawBlending(true, mode); 2743 setupDrawProgram(); 2744 setupDrawModelView(x, y, x, y, pureTranslate, true); 2745 setupDrawTexture(fontRenderer.getTexture(linearFilter)); 2746 setupDrawPureColorUniforms(); 2747 setupDrawColorFilterUniforms(); 2748 setupDrawShaderUniforms(pureTranslate); 2749 setupDrawTextGammaUniforms(); 2750 2751 const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip(); 2752 Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); 2753 2754 const bool hasActiveLayer = hasLayer(); 2755 2756 if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y, 2757 positions, hasActiveLayer ? &bounds : NULL)) { 2758 if (hasActiveLayer) { 2759 if (!pureTranslate) { 2760 mSnapshot->transform->mapRect(bounds); 2761 } 2762 dirtyLayerUnchecked(bounds, getRegion()); 2763 } 2764 } 2765 2766 return DrawGlInfo::kStatusDrew; 2767} 2768 2769status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, 2770 float x, float y, const float* positions, SkPaint* paint, float length) { 2771 if (text == NULL || count == 0 || mSnapshot->isIgnored() || 2772 (paint->getAlpha() * mSnapshot->alpha == 0 && paint->getXfermode() == NULL)) { 2773 return DrawGlInfo::kStatusDone; 2774 } 2775 2776 if (length < 0.0f) length = paint->measureText(text, bytesCount); 2777 switch (paint->getTextAlign()) { 2778 case SkPaint::kCenter_Align: 2779 x -= length / 2.0f; 2780 break; 2781 case SkPaint::kRight_Align: 2782 x -= length; 2783 break; 2784 default: 2785 break; 2786 } 2787 2788 SkPaint::FontMetrics metrics; 2789 paint->getFontMetrics(&metrics, 0.0f); 2790 if (quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom)) { 2791 return DrawGlInfo::kStatusDone; 2792 } 2793 2794#if DEBUG_GLYPHS 2795 ALOGD("OpenGLRenderer drawText() with FontID=%d", 2796 SkTypeface::UniqueID(paint->getTypeface())); 2797#endif 2798 2799 FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint); 2800 fontRenderer.setFont(paint, *mSnapshot->transform); 2801 2802 const float oldX = x; 2803 const float oldY = y; 2804 const bool pureTranslate = mSnapshot->transform->isPureTranslate(); 2805 if (CC_LIKELY(pureTranslate)) { 2806 x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f); 2807 y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f); 2808 } 2809 2810 int alpha; 2811 SkXfermode::Mode mode; 2812 getAlphaAndMode(paint, &alpha, &mode); 2813 2814 if (CC_UNLIKELY(mHasShadow)) { 2815 drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer, alpha, mode, 2816 oldX, oldY); 2817 } 2818 2819 // Pick the appropriate texture filtering 2820 bool linearFilter = mSnapshot->transform->changesBounds(); 2821 if (pureTranslate && !linearFilter) { 2822 linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f; 2823 } 2824 2825 // The font renderer will always use texture unit 0 2826 mCaches.activeTexture(0); 2827 setupDraw(); 2828 setupDrawTextGamma(paint); 2829 setupDrawDirtyRegionsDisabled(); 2830 setupDrawWithTexture(true); 2831 setupDrawAlpha8Color(paint->getColor(), alpha); 2832 setupDrawColorFilter(); 2833 setupDrawShader(); 2834 setupDrawBlending(true, mode); 2835 setupDrawProgram(); 2836 setupDrawModelView(x, y, x, y, pureTranslate, true); 2837 // See comment above; the font renderer must use texture unit 0 2838 // assert(mTextureUnit == 0) 2839 setupDrawTexture(fontRenderer.getTexture(linearFilter)); 2840 setupDrawPureColorUniforms(); 2841 setupDrawColorFilterUniforms(); 2842 setupDrawShaderUniforms(pureTranslate); 2843 setupDrawTextGammaUniforms(); 2844 2845 const Rect* clip = pureTranslate ? mSnapshot->clipRect : 2846 (mSnapshot->hasPerspectiveTransform() ? NULL : &mSnapshot->getLocalClip()); 2847 Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); 2848 2849 const bool hasActiveLayer = hasLayer(); 2850 2851 bool status; 2852 if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) { 2853 SkPaint paintCopy(*paint); 2854 paintCopy.setTextAlign(SkPaint::kLeft_Align); 2855 status = fontRenderer.renderPosText(&paintCopy, clip, text, 0, bytesCount, count, x, y, 2856 positions, hasActiveLayer ? &bounds : NULL); 2857 } else { 2858 status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y, 2859 positions, hasActiveLayer ? &bounds : NULL); 2860 } 2861 2862 if (status && hasActiveLayer) { 2863 if (!pureTranslate) { 2864 mSnapshot->transform->mapRect(bounds); 2865 } 2866 dirtyLayerUnchecked(bounds, getRegion()); 2867 } 2868 2869 drawTextDecorations(text, bytesCount, length, oldX, oldY, paint); 2870 2871 return DrawGlInfo::kStatusDrew; 2872} 2873 2874status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count, SkPath* path, 2875 float hOffset, float vOffset, SkPaint* paint) { 2876 if (text == NULL || count == 0 || mSnapshot->isIgnored() || 2877 (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) { 2878 return DrawGlInfo::kStatusDone; 2879 } 2880 2881 FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint); 2882 fontRenderer.setFont(paint, *mSnapshot->transform); 2883 2884 int alpha; 2885 SkXfermode::Mode mode; 2886 getAlphaAndMode(paint, &alpha, &mode); 2887 2888 mCaches.activeTexture(0); 2889 setupDraw(); 2890 setupDrawTextGamma(paint); 2891 setupDrawDirtyRegionsDisabled(); 2892 setupDrawWithTexture(true); 2893 setupDrawAlpha8Color(paint->getColor(), alpha); 2894 setupDrawColorFilter(); 2895 setupDrawShader(); 2896 setupDrawBlending(true, mode); 2897 setupDrawProgram(); 2898 setupDrawModelView(0.0f, 0.0f, 0.0f, 0.0f, false, true); 2899 setupDrawTexture(fontRenderer.getTexture(true)); 2900 setupDrawPureColorUniforms(); 2901 setupDrawColorFilterUniforms(); 2902 setupDrawShaderUniforms(false); 2903 setupDrawTextGammaUniforms(); 2904 2905 const Rect* clip = &mSnapshot->getLocalClip(); 2906 Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); 2907 2908 const bool hasActiveLayer = hasLayer(); 2909 2910 if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path, 2911 hOffset, vOffset, hasActiveLayer ? &bounds : NULL)) { 2912 if (hasActiveLayer) { 2913 mSnapshot->transform->mapRect(bounds); 2914 dirtyLayerUnchecked(bounds, getRegion()); 2915 } 2916 } 2917 2918 return DrawGlInfo::kStatusDrew; 2919} 2920 2921status_t OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) { 2922 if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone; 2923 2924 mCaches.activeTexture(0); 2925 2926 const PathTexture* texture = mCaches.pathCache.get(path, paint); 2927 if (!texture) return DrawGlInfo::kStatusDone; 2928 const AutoTexture autoCleanup(texture); 2929 2930 const float x = texture->left - texture->offset; 2931 const float y = texture->top - texture->offset; 2932 2933 drawPathTexture(texture, x, y, paint); 2934 2935 return DrawGlInfo::kStatusDrew; 2936} 2937 2938status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) { 2939 if (!layer) { 2940 return DrawGlInfo::kStatusDone; 2941 } 2942 2943 mat4* transform = NULL; 2944 if (layer->isTextureLayer()) { 2945 transform = &layer->getTransform(); 2946 if (!transform->isIdentity()) { 2947 save(0); 2948 mSnapshot->transform->multiply(*transform); 2949 } 2950 } 2951 2952 Rect transformed; 2953 Rect clip; 2954 const bool rejected = quickRejectNoScissor(x, y, 2955 x + layer->layer.getWidth(), y + layer->layer.getHeight(), transformed, clip); 2956 2957 if (rejected) { 2958 if (transform && !transform->isIdentity()) { 2959 restore(); 2960 } 2961 return DrawGlInfo::kStatusDone; 2962 } 2963 2964 updateLayer(layer, true); 2965 2966 mCaches.setScissorEnabled(mScissorOptimizationDisabled || !clip.contains(transformed)); 2967 mCaches.activeTexture(0); 2968 2969 if (CC_LIKELY(!layer->region.isEmpty())) { 2970 SkiaColorFilter* oldFilter = mColorFilter; 2971 mColorFilter = layer->getColorFilter(); 2972 2973 if (layer->region.isRect()) { 2974 composeLayerRect(layer, layer->regionRect); 2975 } else if (layer->mesh) { 2976 const float a = layer->getAlpha() / 255.0f; 2977 setupDraw(); 2978 setupDrawWithTexture(); 2979 setupDrawColor(a, a, a, a); 2980 setupDrawColorFilter(); 2981 setupDrawBlending(layer->isBlend() || a < 1.0f, layer->getMode(), false); 2982 setupDrawProgram(); 2983 setupDrawPureColorUniforms(); 2984 setupDrawColorFilterUniforms(); 2985 setupDrawTexture(layer->getTexture()); 2986 if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) { 2987 int tx = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f); 2988 int ty = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f); 2989 2990 layer->setFilter(GL_NEAREST); 2991 setupDrawModelViewTranslate(tx, ty, 2992 tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true); 2993 } else { 2994 layer->setFilter(GL_LINEAR); 2995 setupDrawModelViewTranslate(x, y, 2996 x + layer->layer.getWidth(), y + layer->layer.getHeight()); 2997 } 2998 setupDrawMesh(&layer->mesh[0].position[0], &layer->mesh[0].texture[0]); 2999 3000 glDrawElements(GL_TRIANGLES, layer->meshElementCount, 3001 GL_UNSIGNED_SHORT, layer->meshIndices); 3002 3003 finishDrawTexture(); 3004 3005#if DEBUG_LAYERS_AS_REGIONS 3006 drawRegionRects(layer->region); 3007#endif 3008 } 3009 3010 mColorFilter = oldFilter; 3011 3012 if (layer->debugDrawUpdate) { 3013 layer->debugDrawUpdate = false; 3014 drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(), 3015 0x7f00ff00, SkXfermode::kSrcOver_Mode); 3016 } 3017 } 3018 3019 if (transform && !transform->isIdentity()) { 3020 restore(); 3021 } 3022 3023 return DrawGlInfo::kStatusDrew; 3024} 3025 3026/////////////////////////////////////////////////////////////////////////////// 3027// Shaders 3028/////////////////////////////////////////////////////////////////////////////// 3029 3030void OpenGLRenderer::resetShader() { 3031 mShader = NULL; 3032} 3033 3034void OpenGLRenderer::setupShader(SkiaShader* shader) { 3035 mShader = shader; 3036 if (mShader) { 3037 mShader->set(&mCaches.textureCache, &mCaches.gradientCache); 3038 } 3039} 3040 3041/////////////////////////////////////////////////////////////////////////////// 3042// Color filters 3043/////////////////////////////////////////////////////////////////////////////// 3044 3045void OpenGLRenderer::resetColorFilter() { 3046 mColorFilter = NULL; 3047} 3048 3049void OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) { 3050 mColorFilter = filter; 3051} 3052 3053/////////////////////////////////////////////////////////////////////////////// 3054// Drop shadow 3055/////////////////////////////////////////////////////////////////////////////// 3056 3057void OpenGLRenderer::resetShadow() { 3058 mHasShadow = false; 3059} 3060 3061void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) { 3062 mHasShadow = true; 3063 mShadowRadius = radius; 3064 mShadowDx = dx; 3065 mShadowDy = dy; 3066 mShadowColor = color; 3067} 3068 3069/////////////////////////////////////////////////////////////////////////////// 3070// Draw filters 3071/////////////////////////////////////////////////////////////////////////////// 3072 3073void OpenGLRenderer::resetPaintFilter() { 3074 mHasDrawFilter = false; 3075} 3076 3077void OpenGLRenderer::setupPaintFilter(int clearBits, int setBits) { 3078 mHasDrawFilter = true; 3079 mPaintFilterClearBits = clearBits & SkPaint::kAllFlags; 3080 mPaintFilterSetBits = setBits & SkPaint::kAllFlags; 3081} 3082 3083SkPaint* OpenGLRenderer::filterPaint(SkPaint* paint) { 3084 if (CC_LIKELY(!mHasDrawFilter || !paint)) return paint; 3085 3086 uint32_t flags = paint->getFlags(); 3087 3088 mFilteredPaint = *paint; 3089 mFilteredPaint.setFlags((flags & ~mPaintFilterClearBits) | mPaintFilterSetBits); 3090 3091 return &mFilteredPaint; 3092} 3093 3094/////////////////////////////////////////////////////////////////////////////// 3095// Drawing implementation 3096/////////////////////////////////////////////////////////////////////////////// 3097 3098void OpenGLRenderer::drawPathTexture(const PathTexture* texture, 3099 float x, float y, SkPaint* paint) { 3100 if (quickReject(x, y, x + texture->width, y + texture->height)) { 3101 return; 3102 } 3103 3104 int alpha; 3105 SkXfermode::Mode mode; 3106 getAlphaAndMode(paint, &alpha, &mode); 3107 3108 setupDraw(); 3109 setupDrawWithTexture(true); 3110 setupDrawAlpha8Color(paint->getColor(), alpha); 3111 setupDrawColorFilter(); 3112 setupDrawShader(); 3113 setupDrawBlending(true, mode); 3114 setupDrawProgram(); 3115 setupDrawModelView(x, y, x + texture->width, y + texture->height); 3116 setupDrawTexture(texture->id); 3117 setupDrawPureColorUniforms(); 3118 setupDrawColorFilterUniforms(); 3119 setupDrawShaderUniforms(); 3120 setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset); 3121 3122 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); 3123 3124 finishDrawTexture(); 3125} 3126 3127// Same values used by Skia 3128#define kStdStrikeThru_Offset (-6.0f / 21.0f) 3129#define kStdUnderline_Offset (1.0f / 9.0f) 3130#define kStdUnderline_Thickness (1.0f / 18.0f) 3131 3132void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float length, 3133 float x, float y, SkPaint* paint) { 3134 // Handle underline and strike-through 3135 uint32_t flags = paint->getFlags(); 3136 if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) { 3137 SkPaint paintCopy(*paint); 3138 float underlineWidth = length; 3139 // If length is > 0.0f, we already measured the text for the text alignment 3140 if (length <= 0.0f) { 3141 underlineWidth = paintCopy.measureText(text, bytesCount); 3142 } 3143 3144 if (CC_LIKELY(underlineWidth > 0.0f)) { 3145 const float textSize = paintCopy.getTextSize(); 3146 const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f); 3147 3148 const float left = x; 3149 float top = 0.0f; 3150 3151 int linesCount = 0; 3152 if (flags & SkPaint::kUnderlineText_Flag) linesCount++; 3153 if (flags & SkPaint::kStrikeThruText_Flag) linesCount++; 3154 3155 const int pointsCount = 4 * linesCount; 3156 float points[pointsCount]; 3157 int currentPoint = 0; 3158 3159 if (flags & SkPaint::kUnderlineText_Flag) { 3160 top = y + textSize * kStdUnderline_Offset; 3161 points[currentPoint++] = left; 3162 points[currentPoint++] = top; 3163 points[currentPoint++] = left + underlineWidth; 3164 points[currentPoint++] = top; 3165 } 3166 3167 if (flags & SkPaint::kStrikeThruText_Flag) { 3168 top = y + textSize * kStdStrikeThru_Offset; 3169 points[currentPoint++] = left; 3170 points[currentPoint++] = top; 3171 points[currentPoint++] = left + underlineWidth; 3172 points[currentPoint++] = top; 3173 } 3174 3175 paintCopy.setStrokeWidth(strokeWidth); 3176 3177 drawLines(&points[0], pointsCount, &paintCopy); 3178 } 3179 } 3180} 3181 3182status_t OpenGLRenderer::drawRects(const float* rects, int count, SkPaint* paint) { 3183 if (mSnapshot->isIgnored()) { 3184 return DrawGlInfo::kStatusDone; 3185 } 3186 3187 int color = paint->getColor(); 3188 // If a shader is set, preserve only the alpha 3189 if (mShader) { 3190 color |= 0x00ffffff; 3191 } 3192 SkXfermode::Mode mode = getXfermode(paint->getXfermode()); 3193 3194 return drawColorRects(rects, count, color, mode); 3195} 3196 3197status_t OpenGLRenderer::drawColorRects(const float* rects, int count, int color, 3198 SkXfermode::Mode mode, bool ignoreTransform, bool dirty) { 3199 3200 float left = FLT_MAX; 3201 float top = FLT_MAX; 3202 float right = FLT_MIN; 3203 float bottom = FLT_MIN; 3204 3205 int vertexCount = 0; 3206 Vertex mesh[count * 6]; 3207 Vertex* vertex = mesh; 3208 3209 for (int index = 0; index < count; index += 4) { 3210 float l = rects[index + 0]; 3211 float t = rects[index + 1]; 3212 float r = rects[index + 2]; 3213 float b = rects[index + 3]; 3214 3215 if (ignoreTransform || !quickRejectNoScissor(left, top, right, bottom)) { 3216 Vertex::set(vertex++, l, b); 3217 Vertex::set(vertex++, l, t); 3218 Vertex::set(vertex++, r, t); 3219 Vertex::set(vertex++, l, b); 3220 Vertex::set(vertex++, r, t); 3221 Vertex::set(vertex++, r, b); 3222 3223 vertexCount += 6; 3224 3225 left = fminf(left, l); 3226 top = fminf(top, t); 3227 right = fmaxf(right, r); 3228 bottom = fmaxf(bottom, b); 3229 } 3230 } 3231 3232 if (count == 0) return DrawGlInfo::kStatusDone; 3233 3234 setupDraw(); 3235 setupDrawNoTexture(); 3236 setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha); 3237 setupDrawShader(); 3238 setupDrawColorFilter(); 3239 setupDrawBlending(mode); 3240 setupDrawProgram(); 3241 setupDrawDirtyRegionsDisabled(); 3242 setupDrawModelView(0.0f, 0.0f, 1.0f, 1.0f, ignoreTransform, true); 3243 setupDrawColorUniforms(); 3244 setupDrawShaderUniforms(); 3245 setupDrawColorFilterUniforms(); 3246 setupDrawVertices((GLvoid*) &mesh[0].position[0]); 3247 3248 if (dirty && hasLayer()) { 3249 dirtyLayer(left, top, right, bottom, *mSnapshot->transform); 3250 } 3251 3252 glDrawArrays(GL_TRIANGLES, 0, vertexCount); 3253 3254 return DrawGlInfo::kStatusDrew; 3255} 3256 3257void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, 3258 int color, SkXfermode::Mode mode, bool ignoreTransform) { 3259 // If a shader is set, preserve only the alpha 3260 if (mShader) { 3261 color |= 0x00ffffff; 3262 } 3263 3264 setupDraw(); 3265 setupDrawNoTexture(); 3266 setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha); 3267 setupDrawShader(); 3268 setupDrawColorFilter(); 3269 setupDrawBlending(mode); 3270 setupDrawProgram(); 3271 setupDrawModelView(left, top, right, bottom, ignoreTransform); 3272 setupDrawColorUniforms(); 3273 setupDrawShaderUniforms(ignoreTransform); 3274 setupDrawColorFilterUniforms(); 3275 setupDrawSimpleMesh(); 3276 3277 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); 3278} 3279 3280void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, 3281 Texture* texture, SkPaint* paint) { 3282 int alpha; 3283 SkXfermode::Mode mode; 3284 getAlphaAndMode(paint, &alpha, &mode); 3285 3286 texture->setWrap(GL_CLAMP_TO_EDGE, true); 3287 3288 if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) { 3289 const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f); 3290 const float y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f); 3291 3292 texture->setFilter(GL_NEAREST, true); 3293 drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id, 3294 alpha / 255.0f, mode, texture->blend, (GLvoid*) NULL, 3295 (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount, false, true); 3296 } else { 3297 texture->setFilter(FILTER(paint), true); 3298 drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode, 3299 texture->blend, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset, 3300 GL_TRIANGLE_STRIP, gMeshCount); 3301 } 3302} 3303 3304void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, 3305 GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) { 3306 drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend, 3307 (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount); 3308} 3309 3310void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom, 3311 GLuint texture, float alpha, SkXfermode::Mode mode, bool blend, 3312 GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount, 3313 bool swapSrcDst, bool ignoreTransform, GLuint vbo, bool ignoreScale, bool dirty) { 3314 3315 setupDraw(); 3316 setupDrawWithTexture(); 3317 setupDrawColor(alpha, alpha, alpha, alpha); 3318 setupDrawColorFilter(); 3319 setupDrawBlending(blend, mode, swapSrcDst); 3320 setupDrawProgram(); 3321 if (!dirty) setupDrawDirtyRegionsDisabled(); 3322 if (!ignoreScale) { 3323 setupDrawModelView(left, top, right, bottom, ignoreTransform); 3324 } else { 3325 setupDrawModelViewTranslate(left, top, right, bottom, ignoreTransform); 3326 } 3327 setupDrawTexture(texture); 3328 setupDrawPureColorUniforms(); 3329 setupDrawColorFilterUniforms(); 3330 setupDrawMesh(vertices, texCoords, vbo); 3331 3332 glDrawArrays(drawMode, 0, elementsCount); 3333 3334 finishDrawTexture(); 3335} 3336 3337void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom, 3338 GLuint texture, bool hasColor, int color, int alpha, SkXfermode::Mode mode, 3339 GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount, 3340 bool ignoreTransform, bool dirty) { 3341 3342 setupDraw(); 3343 setupDrawWithTexture(true); 3344 if (hasColor) { 3345 setupDrawAlpha8Color(color, alpha); 3346 } 3347 setupDrawColorFilter(); 3348 setupDrawShader(); 3349 setupDrawBlending(true, mode); 3350 setupDrawProgram(); 3351 if (!dirty) setupDrawDirtyRegionsDisabled(); 3352 setupDrawModelView(left, top, right, bottom, ignoreTransform); 3353 setupDrawTexture(texture); 3354 setupDrawPureColorUniforms(); 3355 setupDrawColorFilterUniforms(); 3356 setupDrawShaderUniforms(); 3357 setupDrawMesh(vertices, texCoords); 3358 3359 glDrawArrays(drawMode, 0, elementsCount); 3360 3361 finishDrawTexture(); 3362} 3363 3364void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, 3365 ProgramDescription& description, bool swapSrcDst) { 3366 blend = blend || mode != SkXfermode::kSrcOver_Mode; 3367 3368 if (blend) { 3369 // These blend modes are not supported by OpenGL directly and have 3370 // to be implemented using shaders. Since the shader will perform 3371 // the blending, turn blending off here 3372 // If the blend mode cannot be implemented using shaders, fall 3373 // back to the default SrcOver blend mode instead 3374 if (CC_UNLIKELY(mode > SkXfermode::kScreen_Mode)) { 3375 if (CC_UNLIKELY(mCaches.extensions.hasFramebufferFetch())) { 3376 description.framebufferMode = mode; 3377 description.swapSrcDst = swapSrcDst; 3378 3379 if (mCaches.blend) { 3380 glDisable(GL_BLEND); 3381 mCaches.blend = false; 3382 } 3383 3384 return; 3385 } else { 3386 mode = SkXfermode::kSrcOver_Mode; 3387 } 3388 } 3389 3390 if (!mCaches.blend) { 3391 glEnable(GL_BLEND); 3392 } 3393 3394 GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src; 3395 GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst; 3396 3397 if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) { 3398 glBlendFunc(sourceMode, destMode); 3399 mCaches.lastSrcMode = sourceMode; 3400 mCaches.lastDstMode = destMode; 3401 } 3402 } else if (mCaches.blend) { 3403 glDisable(GL_BLEND); 3404 } 3405 mCaches.blend = blend; 3406} 3407 3408bool OpenGLRenderer::useProgram(Program* program) { 3409 if (!program->isInUse()) { 3410 if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove(); 3411 program->use(); 3412 mCaches.currentProgram = program; 3413 return false; 3414 } 3415 return true; 3416} 3417 3418void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) { 3419 TextureVertex* v = &mMeshVertices[0]; 3420 TextureVertex::setUV(v++, u1, v1); 3421 TextureVertex::setUV(v++, u2, v1); 3422 TextureVertex::setUV(v++, u1, v2); 3423 TextureVertex::setUV(v++, u2, v2); 3424} 3425 3426void OpenGLRenderer::getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) { 3427 getAlphaAndModeDirect(paint, alpha, mode); 3428 *alpha *= mSnapshot->alpha; 3429} 3430 3431}; // namespace uirenderer 3432}; // namespace android 3433