OpenGLRenderer.cpp revision b025b9c8b4efefadb01937db61a1f8ee7d2452bf
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "OpenGLRenderer" 18 19#include <stdlib.h> 20#include <stdint.h> 21#include <sys/types.h> 22 23#include <SkCanvas.h> 24#include <SkTypeface.h> 25 26#include <utils/Log.h> 27 28#include "OpenGLRenderer.h" 29 30namespace android { 31namespace uirenderer { 32 33/////////////////////////////////////////////////////////////////////////////// 34// Defines 35/////////////////////////////////////////////////////////////////////////////// 36 37#define REQUIRED_TEXTURE_UNITS_COUNT 3 38 39// Generates simple and textured vertices 40#define FV(x, y, u, v) { { x, y }, { u, v } } 41 42/////////////////////////////////////////////////////////////////////////////// 43// Globals 44/////////////////////////////////////////////////////////////////////////////// 45 46// This array is never used directly but used as a memcpy source in the 47// OpenGLRenderer constructor 48static const TextureVertex gMeshVertices[] = { 49 FV(0.0f, 0.0f, 0.0f, 0.0f), 50 FV(1.0f, 0.0f, 1.0f, 0.0f), 51 FV(0.0f, 1.0f, 0.0f, 1.0f), 52 FV(1.0f, 1.0f, 1.0f, 1.0f) 53}; 54static const GLsizei gMeshStride = sizeof(TextureVertex); 55static const GLsizei gMeshCount = 4; 56 57/** 58 * Structure mapping Skia xfermodes to OpenGL blending factors. 59 */ 60struct Blender { 61 SkXfermode::Mode mode; 62 GLenum src; 63 GLenum dst; 64}; // struct Blender 65 66// In this array, the index of each Blender equals the value of the first 67// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode] 68static const Blender gBlends[] = { 69 { SkXfermode::kClear_Mode, GL_ZERO, GL_ZERO }, 70 { SkXfermode::kSrc_Mode, GL_ONE, GL_ZERO }, 71 { SkXfermode::kDst_Mode, GL_ZERO, GL_ONE }, 72 { SkXfermode::kSrcOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, 73 { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE }, 74 { SkXfermode::kSrcIn_Mode, GL_DST_ALPHA, GL_ZERO }, 75 { SkXfermode::kDstIn_Mode, GL_ZERO, GL_SRC_ALPHA }, 76 { SkXfermode::kSrcOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, 77 { SkXfermode::kDstOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, 78 { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, 79 { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, 80 { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA } 81}; 82 83// This array contains the swapped version of each SkXfermode. For instance 84// this array's SrcOver blending mode is actually DstOver. You can refer to 85// createLayer() for more information on the purpose of this array. 86static const Blender gBlendsSwap[] = { 87 { SkXfermode::kClear_Mode, GL_ZERO, GL_ZERO }, 88 { SkXfermode::kSrc_Mode, GL_ZERO, GL_ONE }, 89 { SkXfermode::kDst_Mode, GL_ONE, GL_ZERO }, 90 { SkXfermode::kSrcOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE }, 91 { SkXfermode::kDstOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, 92 { SkXfermode::kSrcIn_Mode, GL_ZERO, GL_SRC_ALPHA }, 93 { SkXfermode::kDstIn_Mode, GL_DST_ALPHA, GL_ZERO }, 94 { SkXfermode::kSrcOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, 95 { SkXfermode::kDstOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, 96 { SkXfermode::kSrcATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, 97 { SkXfermode::kDstATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, 98 { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA } 99}; 100 101static const GLenum gTextureUnits[] = { 102 GL_TEXTURE0, 103 GL_TEXTURE1, 104 GL_TEXTURE2 105}; 106 107/////////////////////////////////////////////////////////////////////////////// 108// Constructors/destructor 109/////////////////////////////////////////////////////////////////////////////// 110 111OpenGLRenderer::OpenGLRenderer(): mCaches(Caches::getInstance()) { 112 LOGD("Create OpenGLRenderer"); 113 114 mShader = NULL; 115 mColorFilter = NULL; 116 mHasShadow = false; 117 118 memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices)); 119 120 mFirstSnapshot = new Snapshot; 121 122 GLint maxTextureUnits; 123 glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); 124 if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) { 125 LOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT); 126 } 127 128 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); 129} 130 131OpenGLRenderer::~OpenGLRenderer() { 132 LOGD("Destroy OpenGLRenderer"); 133} 134 135/////////////////////////////////////////////////////////////////////////////// 136// Setup 137/////////////////////////////////////////////////////////////////////////////// 138 139void OpenGLRenderer::setViewport(int width, int height) { 140 glViewport(0, 0, width, height); 141 mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1); 142 143 mWidth = width; 144 mHeight = height; 145} 146 147void OpenGLRenderer::prepare() { 148 mSnapshot = new Snapshot(mFirstSnapshot, 149 SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); 150 mSaveCount = 1; 151 152 glViewport(0, 0, mWidth, mHeight); 153 154 glDisable(GL_DITHER); 155 glDisable(GL_SCISSOR_TEST); 156 157 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 158 glClear(GL_COLOR_BUFFER_BIT); 159 160 glEnable(GL_SCISSOR_TEST); 161 glScissor(0, 0, mWidth, mHeight); 162 163 mSnapshot->setClip(0.0f, 0.0f, mWidth, mHeight); 164} 165 166void OpenGLRenderer::finish() { 167#if DEBUG_OPENGL 168 GLenum status = GL_NO_ERROR; 169 while ((status = glGetError()) != GL_NO_ERROR) { 170 LOGD("GL error from OpenGLRenderer: 0x%x", status); 171 } 172#endif 173} 174 175void OpenGLRenderer::acquireContext() { 176 if (mCaches.currentProgram) { 177 if (mCaches.currentProgram->isInUse()) { 178 mCaches.currentProgram->remove(); 179 mCaches.currentProgram = NULL; 180 } 181 } 182} 183 184void OpenGLRenderer::releaseContext() { 185 glViewport(0, 0, mWidth, mHeight); 186 187 glEnable(GL_SCISSOR_TEST); 188 setScissorFromClip(); 189 190 glDisable(GL_DITHER); 191 192 glBindFramebuffer(GL_FRAMEBUFFER, 0); 193 194 if (mCaches.blend) { 195 glEnable(GL_BLEND); 196 glBlendFunc(mCaches.lastSrcMode, mCaches.lastDstMode); 197 glBlendEquation(GL_FUNC_ADD); 198 } else { 199 glDisable(GL_BLEND); 200 } 201} 202 203/////////////////////////////////////////////////////////////////////////////// 204// State management 205/////////////////////////////////////////////////////////////////////////////// 206 207int OpenGLRenderer::getSaveCount() const { 208 return mSaveCount; 209} 210 211int OpenGLRenderer::save(int flags) { 212 return saveSnapshot(flags); 213} 214 215void OpenGLRenderer::restore() { 216 if (mSaveCount > 1) { 217 restoreSnapshot(); 218 } 219} 220 221void OpenGLRenderer::restoreToCount(int saveCount) { 222 if (saveCount < 1) saveCount = 1; 223 224 while (mSaveCount > saveCount) { 225 restoreSnapshot(); 226 } 227} 228 229int OpenGLRenderer::saveSnapshot(int flags) { 230 mSnapshot = new Snapshot(mSnapshot, flags); 231 return mSaveCount++; 232} 233 234bool OpenGLRenderer::restoreSnapshot() { 235 bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet; 236 bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer; 237 238 sp<Snapshot> current = mSnapshot; 239 sp<Snapshot> previous = mSnapshot->previous; 240 241 mSaveCount--; 242 mSnapshot = previous; 243 244 if (restoreLayer) { 245 composeLayer(current, previous); 246 } 247 248 if (restoreClip) { 249 setScissorFromClip(); 250 } 251 252 return restoreClip; 253} 254 255/////////////////////////////////////////////////////////////////////////////// 256// Layers 257/////////////////////////////////////////////////////////////////////////////// 258 259int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom, 260 const SkPaint* p, int flags) { 261 int count = saveSnapshot(flags); 262 263 int alpha = 255; 264 SkXfermode::Mode mode; 265 266 if (p) { 267 alpha = p->getAlpha(); 268 if (!mExtensions.hasFramebufferFetch()) { 269 const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode); 270 if (!isMode) { 271 // Assume SRC_OVER 272 mode = SkXfermode::kSrcOver_Mode; 273 } 274 } else { 275 mode = getXfermode(p->getXfermode()); 276 } 277 } else { 278 mode = SkXfermode::kSrcOver_Mode; 279 } 280 281 createLayer(mSnapshot, left, top, right, bottom, alpha, mode, flags); 282 283 return count; 284} 285 286int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom, 287 int alpha, int flags) { 288 if (alpha == 0xff) { 289 return saveLayer(left, top, right, bottom, NULL, flags); 290 } else { 291 SkPaint paint; 292 paint.setAlpha(alpha); 293 return saveLayer(left, top, right, bottom, &paint, flags); 294 } 295} 296 297/** 298 * Layers are viewed by Skia are slightly different than layers in image editing 299 * programs (for instance.) When a layer is created, previously created layers 300 * and the frame buffer still receive every drawing command. For instance, if a 301 * layer is created and a shape intersecting the bounds of the layers and the 302 * framebuffer is draw, the shape will be drawn on both (unless the layer was 303 * created with the SkCanvas::kClipToLayer_SaveFlag flag.) 304 * 305 * A way to implement layers is to create an FBO for each layer, backed by an RGBA 306 * texture. Unfortunately, this is inefficient as it requires every primitive to 307 * be drawn n + 1 times, where n is the number of active layers. In practice this 308 * means, for every primitive: 309 * - Switch active frame buffer 310 * - Change viewport, clip and projection matrix 311 * - Issue the drawing 312 * 313 * Switching rendering target n + 1 times per drawn primitive is extremely costly. 314 * To avoid this, layers are implemented in a different way here. 315 * 316 * This implementation relies on the frame buffer being at least RGBA 8888. When 317 * a layer is created, only a texture is created, not an FBO. The content of the 318 * frame buffer contained within the layer's bounds is copied into this texture 319 * using glCopyTexImage2D(). The layer's region is then cleared(1) in the frame 320 * buffer and drawing continues as normal. This technique therefore treats the 321 * frame buffer as a scratch buffer for the layers. 322 * 323 * To compose the layers back onto the frame buffer, each layer texture 324 * (containing the original frame buffer data) is drawn as a simple quad over 325 * the frame buffer. The trick is that the quad is set as the composition 326 * destination in the blending equation, and the frame buffer becomes the source 327 * of the composition. 328 * 329 * Drawing layers with an alpha value requires an extra step before composition. 330 * An empty quad is drawn over the layer's region in the frame buffer. This quad 331 * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the 332 * quad is used to multiply the colors in the frame buffer. This is achieved by 333 * changing the GL blend functions for the GL_FUNC_ADD blend equation to 334 * GL_ZERO, GL_SRC_ALPHA. 335 * 336 * Because glCopyTexImage2D() can be slow, an alternative implementation might 337 * be use to draw a single clipped layer. The implementation described above 338 * is correct in every case. 339 * 340 * (1) The frame buffer is actually not cleared right away. To allow the GPU 341 * to potentially optimize series of calls to glCopyTexImage2D, the frame 342 * buffer is left untouched until the first drawing operation. Only when 343 * something actually gets drawn are the layers regions cleared. 344 */ 345bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, 346 float right, float bottom, int alpha, SkXfermode::Mode mode,int flags) { 347 LAYER_LOGD("Requesting layer %fx%f", right - left, bottom - top); 348 LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize()); 349 350 // Window coordinates of the layer 351 Rect bounds(left, top, right, bottom); 352 mSnapshot->transform->mapRect(bounds); 353 354 // Layers only make sense if they are in the framebuffer's bounds 355 bounds.intersect(*mSnapshot->clipRect); 356 if (bounds.isEmpty() || bounds.getWidth() > mMaxTextureSize || 357 bounds.getHeight() > mMaxTextureSize) { 358 return false; 359 } 360 361 LayerSize size(bounds.getWidth(), bounds.getHeight()); 362 Layer* layer = mCaches.layerCache.get(size); 363 if (!layer) { 364 return false; 365 } 366 367 layer->mode = mode; 368 layer->alpha = alpha; 369 layer->layer.set(bounds); 370 371 // Save the layer in the snapshot 372 snapshot->flags |= Snapshot::kFlagIsLayer; 373 snapshot->layer = layer; 374 375 // Copy the framebuffer into the layer 376 glBindTexture(GL_TEXTURE_2D, layer->texture); 377 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left, mHeight - bounds.bottom, 378 bounds.getWidth(), bounds.getHeight(), 0); 379 380 if (flags & SkCanvas::kClipToLayer_SaveFlag) { 381 if (mSnapshot->clipTransformed(bounds)) setScissorFromClip(); 382 } 383 384 // Enqueue the buffer coordinates to clear the corresponding region later 385 mLayers.push(new Rect(bounds)); 386 387 return true; 388} 389 390/** 391 * Read the documentation of createLayer() before doing anything in this method. 392 */ 393void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { 394 if (!current->layer) { 395 LOGE("Attempting to compose a layer that does not exist"); 396 return; 397 } 398 399 // Restore the clip from the previous snapshot 400 const Rect& clip = *previous->clipRect; 401 glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight()); 402 403 Layer* layer = current->layer; 404 const Rect& rect = layer->layer; 405 406 if (layer->alpha < 255) { 407 drawColorRect(rect.left, rect.top, rect.right, rect.bottom, 408 layer->alpha << 24, SkXfermode::kDstIn_Mode, true); 409 } 410 411 // Layers are already drawn with a top-left origin, don't flip the texture 412 resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f); 413 414 drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture, 415 1.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0], 416 &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, true, true); 417 418 resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); 419 420 LayerSize size(rect.getWidth(), rect.getHeight()); 421 // Failing to add the layer to the cache should happen only if the 422 // layer is too large 423 if (!mCaches.layerCache.put(size, layer)) { 424 LAYER_LOGD("Deleting layer"); 425 426 glDeleteTextures(1, &layer->texture); 427 428 delete layer; 429 } 430} 431 432void OpenGLRenderer::clearLayerRegions() { 433 if (mLayers.size() == 0) return; 434 435 for (uint32_t i = 0; i < mLayers.size(); i++) { 436 Rect* bounds = mLayers.itemAt(i); 437 438 // Clear the framebuffer where the layer will draw 439 glScissor(bounds->left, mHeight - bounds->bottom, 440 bounds->getWidth(), bounds->getHeight()); 441 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 442 glClear(GL_COLOR_BUFFER_BIT); 443 444 delete bounds; 445 } 446 mLayers.clear(); 447 448 // Restore the clip 449 setScissorFromClip(); 450} 451 452/////////////////////////////////////////////////////////////////////////////// 453// Transforms 454/////////////////////////////////////////////////////////////////////////////// 455 456void OpenGLRenderer::translate(float dx, float dy) { 457 mSnapshot->transform->translate(dx, dy, 0.0f); 458} 459 460void OpenGLRenderer::rotate(float degrees) { 461 mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f); 462} 463 464void OpenGLRenderer::scale(float sx, float sy) { 465 mSnapshot->transform->scale(sx, sy, 1.0f); 466} 467 468void OpenGLRenderer::setMatrix(SkMatrix* matrix) { 469 mSnapshot->transform->load(*matrix); 470} 471 472void OpenGLRenderer::getMatrix(SkMatrix* matrix) { 473 mSnapshot->transform->copyTo(*matrix); 474} 475 476void OpenGLRenderer::concatMatrix(SkMatrix* matrix) { 477 mat4 m(*matrix); 478 mSnapshot->transform->multiply(m); 479} 480 481/////////////////////////////////////////////////////////////////////////////// 482// Clipping 483/////////////////////////////////////////////////////////////////////////////// 484 485void OpenGLRenderer::setScissorFromClip() { 486 const Rect& clip = *mSnapshot->clipRect; 487 glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight()); 488} 489 490const Rect& OpenGLRenderer::getClipBounds() { 491 return mSnapshot->getLocalClip(); 492} 493 494bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) { 495 Rect r(left, top, right, bottom); 496 mSnapshot->transform->mapRect(r); 497 return !mSnapshot->clipRect->intersects(r); 498} 499 500bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { 501 bool clipped = mSnapshot->clip(left, top, right, bottom, op); 502 if (clipped) { 503 setScissorFromClip(); 504 } 505 return !mSnapshot->clipRect->isEmpty(); 506} 507 508/////////////////////////////////////////////////////////////////////////////// 509// Drawing 510/////////////////////////////////////////////////////////////////////////////// 511 512void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint) { 513 const float right = left + bitmap->width(); 514 const float bottom = top + bitmap->height(); 515 516 if (quickReject(left, top, right, bottom)) { 517 return; 518 } 519 520 glActiveTexture(GL_TEXTURE0); 521 const Texture* texture = mCaches.textureCache.get(bitmap); 522 if (!texture) return; 523 const AutoTexture autoCleanup(texture); 524 525 drawTextureRect(left, top, right, bottom, texture, paint); 526} 527 528void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint) { 529 Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height()); 530 const mat4 transform(*matrix); 531 transform.mapRect(r); 532 533 if (quickReject(r.left, r.top, r.right, r.bottom)) { 534 return; 535 } 536 537 glActiveTexture(GL_TEXTURE0); 538 const Texture* texture = mCaches.textureCache.get(bitmap); 539 if (!texture) return; 540 const AutoTexture autoCleanup(texture); 541 542 drawTextureRect(r.left, r.top, r.right, r.bottom, texture, paint); 543} 544 545void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, 546 float srcLeft, float srcTop, float srcRight, float srcBottom, 547 float dstLeft, float dstTop, float dstRight, float dstBottom, 548 const SkPaint* paint) { 549 if (quickReject(dstLeft, dstTop, dstRight, dstBottom)) { 550 return; 551 } 552 553 glActiveTexture(GL_TEXTURE0); 554 const Texture* texture = mCaches.textureCache.get(bitmap); 555 if (!texture) return; 556 const AutoTexture autoCleanup(texture); 557 558 const float width = texture->width; 559 const float height = texture->height; 560 561 const float u1 = srcLeft / width; 562 const float v1 = srcTop / height; 563 const float u2 = srcRight / width; 564 const float v2 = srcBottom / height; 565 566 resetDrawTextureTexCoords(u1, v1, u2, v2); 567 568 drawTextureRect(dstLeft, dstTop, dstRight, dstBottom, texture, paint); 569 570 resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); 571} 572 573void OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch, 574 float left, float top, float right, float bottom, const SkPaint* paint) { 575 if (quickReject(left, top, right, bottom)) { 576 return; 577 } 578 579 glActiveTexture(GL_TEXTURE0); 580 const Texture* texture = mCaches.textureCache.get(bitmap); 581 if (!texture) return; 582 const AutoTexture autoCleanup(texture); 583 584 int alpha; 585 SkXfermode::Mode mode; 586 getAlphaAndMode(paint, &alpha, &mode); 587 588 Patch* mesh = mCaches.patchCache.get(patch); 589 mesh->updateVertices(bitmap, left, top, right, bottom, 590 &patch->xDivs[0], &patch->yDivs[0], patch->numXDivs, patch->numYDivs); 591 592 // Specify right and bottom as +1.0f from left/top to prevent scaling since the 593 // patch mesh already defines the final size 594 drawTextureMesh(left, top, left + 1.0f, top + 1.0f, texture->id, alpha / 255.0f, 595 mode, texture->blend, &mesh->vertices[0].position[0], 596 &mesh->vertices[0].texture[0], GL_TRIANGLES, mesh->verticesCount); 597} 598 599void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { 600 const Rect& clip = *mSnapshot->clipRect; 601 drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true); 602} 603 604void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, const SkPaint* p) { 605 if (quickReject(left, top, right, bottom)) { 606 return; 607 } 608 609 SkXfermode::Mode mode; 610 if (!mExtensions.hasFramebufferFetch()) { 611 const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode); 612 if (!isMode) { 613 // Assume SRC_OVER 614 mode = SkXfermode::kSrcOver_Mode; 615 } 616 } else { 617 mode = getXfermode(p->getXfermode()); 618 } 619 620 // Skia draws using the color's alpha channel if < 255 621 // Otherwise, it uses the paint's alpha 622 int color = p->getColor(); 623 if (((color >> 24) & 0xff) == 255) { 624 color |= p->getAlpha() << 24; 625 } 626 627 drawColorRect(left, top, right, bottom, color, mode); 628} 629 630void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, 631 float x, float y, SkPaint* paint) { 632 if (text == NULL || count == 0 || (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) { 633 return; 634 } 635 paint->setAntiAlias(true); 636 637 float length = -1.0f; 638 switch (paint->getTextAlign()) { 639 case SkPaint::kCenter_Align: 640 length = paint->measureText(text, bytesCount); 641 x -= length / 2.0f; 642 break; 643 case SkPaint::kRight_Align: 644 length = paint->measureText(text, bytesCount); 645 x -= length; 646 break; 647 default: 648 break; 649 } 650 651 int alpha; 652 SkXfermode::Mode mode; 653 getAlphaAndMode(paint, &alpha, &mode); 654 655 uint32_t color = paint->getColor(); 656 const GLfloat a = alpha / 255.0f; 657 const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f; 658 const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f; 659 const GLfloat b = a * ((color ) & 0xFF) / 255.0f; 660 661 FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint); 662 fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()), 663 paint->getTextSize()); 664 if (mHasShadow) { 665 glActiveTexture(gTextureUnits[0]); 666 mCaches.dropShadowCache.setFontRenderer(fontRenderer); 667 const ShadowTexture* shadow = mCaches.dropShadowCache.get(paint, text, bytesCount, 668 count, mShadowRadius); 669 const AutoTexture autoCleanup(shadow); 670 671 setupShadow(shadow, x, y, mode, a); 672 673 // Draw the mesh 674 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); 675 glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); 676 } 677 678 GLuint textureUnit = 0; 679 glActiveTexture(gTextureUnits[textureUnit]); 680 681 setupTextureAlpha8(fontRenderer.getTexture(), 0, 0, textureUnit, x, y, r, g, b, a, 682 mode, false, true); 683 684 const Rect& clip = mSnapshot->getLocalClip(); 685 clearLayerRegions(); 686 fontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y); 687 688 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 689 glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); 690 691 drawTextDecorations(text, bytesCount, length, x, y, paint); 692} 693 694void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) { 695 GLuint textureUnit = 0; 696 glActiveTexture(gTextureUnits[textureUnit]); 697 698 const PathTexture* texture = mCaches.pathCache.get(path, paint); 699 if (!texture) return; 700 const AutoTexture autoCleanup(texture); 701 702 const float x = texture->left - texture->offset; 703 const float y = texture->top - texture->offset; 704 705 if (quickReject(x, y, x + texture->width, y + texture->height)) { 706 return; 707 } 708 709 int alpha; 710 SkXfermode::Mode mode; 711 getAlphaAndMode(paint, &alpha, &mode); 712 713 uint32_t color = paint->getColor(); 714 const GLfloat a = alpha / 255.0f; 715 const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f; 716 const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f; 717 const GLfloat b = a * ((color ) & 0xFF) / 255.0f; 718 719 setupTextureAlpha8(texture, textureUnit, x, y, r, g, b, a, mode, true, true); 720 721 clearLayerRegions(); 722 723 // Draw the mesh 724 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); 725 glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); 726} 727 728/////////////////////////////////////////////////////////////////////////////// 729// Shaders 730/////////////////////////////////////////////////////////////////////////////// 731 732void OpenGLRenderer::resetShader() { 733 mShader = NULL; 734} 735 736void OpenGLRenderer::setupShader(SkiaShader* shader) { 737 mShader = shader; 738 if (mShader) { 739 mShader->set(&mCaches.textureCache, &mCaches.gradientCache); 740 } 741} 742 743/////////////////////////////////////////////////////////////////////////////// 744// Color filters 745/////////////////////////////////////////////////////////////////////////////// 746 747void OpenGLRenderer::resetColorFilter() { 748 mColorFilter = NULL; 749} 750 751void OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) { 752 mColorFilter = filter; 753} 754 755/////////////////////////////////////////////////////////////////////////////// 756// Drop shadow 757/////////////////////////////////////////////////////////////////////////////// 758 759void OpenGLRenderer::resetShadow() { 760 mHasShadow = false; 761} 762 763void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) { 764 mHasShadow = true; 765 mShadowRadius = radius; 766 mShadowDx = dx; 767 mShadowDy = dy; 768 mShadowColor = color; 769} 770 771/////////////////////////////////////////////////////////////////////////////// 772// Drawing implementation 773/////////////////////////////////////////////////////////////////////////////// 774 775void OpenGLRenderer::setupShadow(const ShadowTexture* texture, float x, float y, 776 SkXfermode::Mode mode, float alpha) { 777 const float sx = x - texture->left + mShadowDx; 778 const float sy = y - texture->top + mShadowDy; 779 780 const int shadowAlpha = ((mShadowColor >> 24) & 0xFF); 781 const GLfloat a = shadowAlpha < 255 ? shadowAlpha / 255.0f : alpha; 782 const GLfloat r = a * ((mShadowColor >> 16) & 0xFF) / 255.0f; 783 const GLfloat g = a * ((mShadowColor >> 8) & 0xFF) / 255.0f; 784 const GLfloat b = a * ((mShadowColor ) & 0xFF) / 255.0f; 785 786 GLuint textureUnit = 0; 787 setupTextureAlpha8(texture, textureUnit, sx, sy, r, g, b, a, mode, true, false); 788} 789 790void OpenGLRenderer::setupTextureAlpha8(const Texture* texture, GLuint& textureUnit, 791 float x, float y, float r, float g, float b, float a, SkXfermode::Mode mode, 792 bool transforms, bool applyFilters) { 793 setupTextureAlpha8(texture->id, texture->width, texture->height, textureUnit, 794 x, y, r, g, b, a, mode, transforms, applyFilters); 795} 796 797void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height, 798 GLuint& textureUnit, float x, float y, float r, float g, float b, float a, 799 SkXfermode::Mode mode, bool transforms, bool applyFilters) { 800 // Describe the required shaders 801 ProgramDescription description; 802 description.hasTexture = true; 803 description.hasAlpha8Texture = true; 804 805 if (applyFilters) { 806 if (mShader) { 807 mShader->describe(description, mExtensions); 808 } 809 if (mColorFilter) { 810 mColorFilter->describe(description, mExtensions); 811 } 812 } 813 814 // Setup the blending mode 815 chooseBlending(true, mode, description); 816 817 // Build and use the appropriate shader 818 useProgram(mCaches.programCache.get(description)); 819 820 bindTexture(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, textureUnit); 821 glUniform1i(mCaches.currentProgram->getUniform("sampler"), textureUnit); 822 823 int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords"); 824 glEnableVertexAttribArray(texCoordsSlot); 825 826 // Setup attributes 827 glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, 828 gMeshStride, &mMeshVertices[0].position[0]); 829 glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, 830 gMeshStride, &mMeshVertices[0].texture[0]); 831 832 // Setup uniforms 833 if (transforms) { 834 mModelView.loadTranslate(x, y, 0.0f); 835 mModelView.scale(width, height, 1.0f); 836 } else { 837 mModelView.loadIdentity(); 838 } 839 mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); 840 glUniform4f(mCaches.currentProgram->color, r, g, b, a); 841 842 textureUnit++; 843 if (applyFilters) { 844 // Setup attributes and uniforms required by the shaders 845 if (mShader) { 846 mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit); 847 } 848 if (mColorFilter) { 849 mColorFilter->setupProgram(mCaches.currentProgram); 850 } 851 } 852} 853 854// Same values used by Skia 855#define kStdStrikeThru_Offset (-6.0f / 21.0f) 856#define kStdUnderline_Offset (1.0f / 9.0f) 857#define kStdUnderline_Thickness (1.0f / 18.0f) 858 859void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float length, 860 float x, float y, SkPaint* paint) { 861 // Handle underline and strike-through 862 uint32_t flags = paint->getFlags(); 863 if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) { 864 float underlineWidth = length; 865 // If length is > 0.0f, we already measured the text for the text alignment 866 if (length <= 0.0f) { 867 underlineWidth = paint->measureText(text, bytesCount); 868 } 869 870 float offsetX = 0; 871 switch (paint->getTextAlign()) { 872 case SkPaint::kCenter_Align: 873 offsetX = underlineWidth * 0.5f; 874 break; 875 case SkPaint::kRight_Align: 876 offsetX = underlineWidth; 877 break; 878 default: 879 break; 880 } 881 882 if (underlineWidth > 0.0f) { 883 float textSize = paint->getTextSize(); 884 float height = textSize * kStdUnderline_Thickness; 885 886 float left = x - offsetX; 887 float top = 0.0f; 888 float right = left + underlineWidth; 889 float bottom = 0.0f; 890 891 if (flags & SkPaint::kUnderlineText_Flag) { 892 top = y + textSize * kStdUnderline_Offset; 893 bottom = top + height; 894 drawRect(left, top, right, bottom, paint); 895 } 896 897 if (flags & SkPaint::kStrikeThruText_Flag) { 898 top = y + textSize * kStdStrikeThru_Offset; 899 bottom = top + height; 900 drawRect(left, top, right, bottom, paint); 901 } 902 } 903 } 904} 905 906void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, 907 int color, SkXfermode::Mode mode, bool ignoreTransform) { 908 clearLayerRegions(); 909 910 // If a shader is set, preserve only the alpha 911 if (mShader) { 912 color |= 0x00ffffff; 913 } 914 915 // Render using pre-multiplied alpha 916 const int alpha = (color >> 24) & 0xFF; 917 const GLfloat a = alpha / 255.0f; 918 const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f; 919 const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f; 920 const GLfloat b = a * ((color ) & 0xFF) / 255.0f; 921 922 GLuint textureUnit = 0; 923 924 // Describe the required shaders 925 ProgramDescription description; 926 if (mShader) { 927 mShader->describe(description, mExtensions); 928 } 929 if (mColorFilter) { 930 mColorFilter->describe(description, mExtensions); 931 } 932 933 // Setup the blending mode 934 chooseBlending(alpha < 255 || (mShader && mShader->blend()), mode, description); 935 936 // Build and use the appropriate shader 937 useProgram(mCaches.programCache.get(description)); 938 939 // Setup attributes 940 glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, 941 gMeshStride, &mMeshVertices[0].position[0]); 942 943 // Setup uniforms 944 mModelView.loadTranslate(left, top, 0.0f); 945 mModelView.scale(right - left, bottom - top, 1.0f); 946 if (!ignoreTransform) { 947 mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); 948 } else { 949 mat4 identity; 950 mCaches.currentProgram->set(mOrthoMatrix, mModelView, identity); 951 } 952 glUniform4f(mCaches.currentProgram->color, r, g, b, a); 953 954 // Setup attributes and uniforms required by the shaders 955 if (mShader) { 956 mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit); 957 } 958 if (mColorFilter) { 959 mColorFilter->setupProgram(mCaches.currentProgram); 960 } 961 962 // Draw the mesh 963 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); 964} 965 966void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, 967 const Texture* texture, const SkPaint* paint) { 968 int alpha; 969 SkXfermode::Mode mode; 970 getAlphaAndMode(paint, &alpha, &mode); 971 972 drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode, 973 texture->blend, &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], 974 GL_TRIANGLE_STRIP, gMeshCount); 975} 976 977void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, 978 GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) { 979 drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend, 980 &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], 981 GL_TRIANGLE_STRIP, gMeshCount); 982} 983 984void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom, 985 GLuint texture, float alpha, SkXfermode::Mode mode, bool blend, 986 GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount, 987 bool swapSrcDst, bool ignoreTransform) { 988 clearLayerRegions(); 989 990 ProgramDescription description; 991 description.hasTexture = true; 992 if (mColorFilter) { 993 mColorFilter->describe(description, mExtensions); 994 } 995 996 mModelView.loadTranslate(left, top, 0.0f); 997 mModelView.scale(right - left, bottom - top, 1.0f); 998 999 chooseBlending(blend || alpha < 1.0f, mode, description, swapSrcDst); 1000 1001 useProgram(mCaches.programCache.get(description)); 1002 if (!ignoreTransform) { 1003 mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); 1004 } else { 1005 mat4 m; 1006 mCaches.currentProgram->set(mOrthoMatrix, mModelView, m); 1007 } 1008 1009 // Texture 1010 bindTexture(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0); 1011 glUniform1i(mCaches.currentProgram->getUniform("sampler"), 0); 1012 1013 // Always premultiplied 1014 glUniform4f(mCaches.currentProgram->color, alpha, alpha, alpha, alpha); 1015 1016 // Mesh 1017 int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords"); 1018 glEnableVertexAttribArray(texCoordsSlot); 1019 glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, 1020 gMeshStride, vertices); 1021 glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords); 1022 1023 // Color filter 1024 if (mColorFilter) { 1025 mColorFilter->setupProgram(mCaches.currentProgram); 1026 } 1027 1028 glDrawArrays(drawMode, 0, elementsCount); 1029 glDisableVertexAttribArray(texCoordsSlot); 1030} 1031 1032void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, 1033 ProgramDescription& description, bool swapSrcDst) { 1034 blend = blend || mode != SkXfermode::kSrcOver_Mode; 1035 if (blend) { 1036 if (mode < SkXfermode::kPlus_Mode) { 1037 if (!mCaches.blend) { 1038 glEnable(GL_BLEND); 1039 } 1040 1041 GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src; 1042 GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst; 1043 1044 if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) { 1045 glBlendFunc(sourceMode, destMode); 1046 mCaches.lastSrcMode = sourceMode; 1047 mCaches.lastDstMode = destMode; 1048 } 1049 } else { 1050 // These blend modes are not supported by OpenGL directly and have 1051 // to be implemented using shaders. Since the shader will perform 1052 // the blending, turn blending off here 1053 if (mExtensions.hasFramebufferFetch()) { 1054 description.framebufferMode = mode; 1055 description.swapSrcDst = swapSrcDst; 1056 } 1057 1058 if (mCaches.blend) { 1059 glDisable(GL_BLEND); 1060 } 1061 blend = false; 1062 } 1063 } else if (mCaches.blend) { 1064 glDisable(GL_BLEND); 1065 } 1066 mCaches.blend = blend; 1067} 1068 1069bool OpenGLRenderer::useProgram(Program* program) { 1070 if (!program->isInUse()) { 1071 if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove(); 1072 program->use(); 1073 mCaches.currentProgram = program; 1074 return false; 1075 } 1076 return true; 1077} 1078 1079void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) { 1080 TextureVertex* v = &mMeshVertices[0]; 1081 TextureVertex::setUV(v++, u1, v1); 1082 TextureVertex::setUV(v++, u2, v1); 1083 TextureVertex::setUV(v++, u1, v2); 1084 TextureVertex::setUV(v++, u2, v2); 1085} 1086 1087void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) { 1088 if (paint) { 1089 if (!mExtensions.hasFramebufferFetch()) { 1090 const bool isMode = SkXfermode::IsMode(paint->getXfermode(), mode); 1091 if (!isMode) { 1092 // Assume SRC_OVER 1093 *mode = SkXfermode::kSrcOver_Mode; 1094 } 1095 } else { 1096 *mode = getXfermode(paint->getXfermode()); 1097 } 1098 1099 // Skia draws using the color's alpha channel if < 255 1100 // Otherwise, it uses the paint's alpha 1101 int color = paint->getColor(); 1102 *alpha = (color >> 24) & 0xFF; 1103 if (*alpha == 255) { 1104 *alpha = paint->getAlpha(); 1105 } 1106 } else { 1107 *mode = SkXfermode::kSrcOver_Mode; 1108 *alpha = 255; 1109 } 1110} 1111 1112SkXfermode::Mode OpenGLRenderer::getXfermode(SkXfermode* mode) { 1113 if (mode == NULL) { 1114 return SkXfermode::kSrcOver_Mode; 1115 } 1116 return mode->fMode; 1117} 1118 1119void OpenGLRenderer::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit) { 1120 glActiveTexture(gTextureUnits[textureUnit]); 1121 glBindTexture(GL_TEXTURE_2D, texture); 1122 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS); 1123 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT); 1124} 1125 1126}; // namespace uirenderer 1127}; // namespace android 1128