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