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