OpenGLRenderer.cpp revision da8532c6f48b4c10b5e2ccb9e08690341efa1616
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 83static const GLenum gTextureUnits[] = { 84 GL_TEXTURE0, 85 GL_TEXTURE1, 86 GL_TEXTURE2 87}; 88 89/////////////////////////////////////////////////////////////////////////////// 90// Constructors/destructor 91/////////////////////////////////////////////////////////////////////////////// 92 93OpenGLRenderer::OpenGLRenderer(): mCaches(Caches::getInstance()) { 94 LOGD("Create OpenGLRenderer"); 95 96 mShader = NULL; 97 mColorFilter = NULL; 98 mHasShadow = false; 99 100 memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices)); 101 102 mFirstSnapshot = new Snapshot; 103 104 GLint maxTextureUnits; 105 glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); 106 if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) { 107 LOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT); 108 } 109} 110 111OpenGLRenderer::~OpenGLRenderer() { 112 LOGD("Destroy OpenGLRenderer"); 113} 114 115/////////////////////////////////////////////////////////////////////////////// 116// Setup 117/////////////////////////////////////////////////////////////////////////////// 118 119void OpenGLRenderer::setViewport(int width, int height) { 120 glViewport(0, 0, width, height); 121 mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1); 122 123 mWidth = width; 124 mHeight = height; 125 mFirstSnapshot->height = height; 126 mFirstSnapshot->viewport.set(0, 0, width, height); 127} 128 129void OpenGLRenderer::prepare() { 130 mSnapshot = new Snapshot(mFirstSnapshot); 131 mSaveCount = 1; 132 133 glViewport(0, 0, mWidth, mHeight); 134 135 glDisable(GL_SCISSOR_TEST); 136 137 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 138 glClear(GL_COLOR_BUFFER_BIT); 139 140 glEnable(GL_SCISSOR_TEST); 141 glScissor(0, 0, mWidth, mHeight); 142 143 mSnapshot->setClip(0.0f, 0.0f, mWidth, mHeight); 144} 145 146void OpenGLRenderer::acquireContext() { 147 if (mCaches.currentProgram) { 148 if (mCaches.currentProgram->isInUse()) { 149 mCaches.currentProgram->remove(); 150 mCaches.currentProgram = NULL; 151 } 152 } 153} 154 155void OpenGLRenderer::releaseContext() { 156 glViewport(0, 0, mSnapshot->viewport.getWidth(), mSnapshot->viewport.getHeight()); 157 158 glEnable(GL_SCISSOR_TEST); 159 setScissorFromClip(); 160 161 if (mCaches.blend) { 162 glEnable(GL_BLEND); 163 glBlendFunc(mCaches.lastSrcMode, mCaches.lastDstMode); 164 } else { 165 glDisable(GL_BLEND); 166 } 167} 168 169/////////////////////////////////////////////////////////////////////////////// 170// State management 171/////////////////////////////////////////////////////////////////////////////// 172 173int OpenGLRenderer::getSaveCount() const { 174 return mSaveCount; 175} 176 177int OpenGLRenderer::save(int flags) { 178 return saveSnapshot(); 179} 180 181void OpenGLRenderer::restore() { 182 if (mSaveCount > 1) { 183 restoreSnapshot(); 184 } 185} 186 187void OpenGLRenderer::restoreToCount(int saveCount) { 188 if (saveCount < 1) saveCount = 1; 189 190 while (mSaveCount > saveCount) { 191 restoreSnapshot(); 192 } 193} 194 195int OpenGLRenderer::saveSnapshot() { 196 mSnapshot = new Snapshot(mSnapshot); 197 return mSaveCount++; 198} 199 200bool OpenGLRenderer::restoreSnapshot() { 201 bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet; 202 bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer; 203 bool restoreOrtho = mSnapshot->flags & Snapshot::kFlagDirtyOrtho; 204 205 sp<Snapshot> current = mSnapshot; 206 sp<Snapshot> previous = mSnapshot->previous; 207 208 if (restoreOrtho) { 209 Rect& r = previous->viewport; 210 glViewport(r.left, r.top, r.right, r.bottom); 211 mOrthoMatrix.load(current->orthoMatrix); 212 } 213 214 mSaveCount--; 215 mSnapshot = previous; 216 217 if (restoreLayer) { 218 composeLayer(current, previous); 219 } 220 221 if (restoreClip) { 222 setScissorFromClip(); 223 } 224 225 return restoreClip; 226} 227 228/////////////////////////////////////////////////////////////////////////////// 229// Layers 230/////////////////////////////////////////////////////////////////////////////// 231 232int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom, 233 const SkPaint* p, int flags) { 234 int count = saveSnapshot(); 235 236 int alpha = 255; 237 SkXfermode::Mode mode; 238 239 if (p) { 240 alpha = p->getAlpha(); 241 const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode); 242 if (!isMode) { 243 // Assume SRC_OVER 244 mode = SkXfermode::kSrcOver_Mode; 245 } 246 } else { 247 mode = SkXfermode::kSrcOver_Mode; 248 } 249 250 if (alpha > 0 && !mSnapshot->invisible) { 251 createLayer(mSnapshot, left, top, right, bottom, alpha, mode, flags); 252 } else { 253 mSnapshot->invisible = true; 254 } 255 256 return count; 257} 258 259int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom, 260 int alpha, int flags) { 261 int count = saveSnapshot(); 262 if (alpha > 0 && !mSnapshot->invisible) { 263 createLayer(mSnapshot, left, top, right, bottom, alpha, SkXfermode::kSrcOver_Mode, flags); 264 } else { 265 mSnapshot->invisible = true; 266 } 267 return count; 268} 269 270bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, 271 float right, float bottom, int alpha, SkXfermode::Mode mode,int flags) { 272 LAYER_LOGD("Requesting layer %fx%f", right - left, bottom - top); 273 LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize()); 274 275 GLuint previousFbo = snapshot->previous.get() ? snapshot->previous->fbo : 0; 276 LayerSize size(right - left, bottom - top); 277 278 Layer* layer = mCaches.layerCache.get(size, previousFbo); 279 if (!layer) { 280 return false; 281 } 282 283 glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo); 284 285 // Clear the FBO 286 glDisable(GL_SCISSOR_TEST); 287 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 288 glClear(GL_COLOR_BUFFER_BIT); 289 glEnable(GL_SCISSOR_TEST); 290 291 layer->mode = mode; 292 layer->alpha = alpha / 255.0f; 293 layer->layer.set(left, top, right, bottom); 294 295 // Save the layer in the snapshot 296 snapshot->flags |= Snapshot::kFlagIsLayer; 297 snapshot->layer = layer; 298 snapshot->fbo = layer->fbo; 299 snapshot->transform.loadTranslate(-left, -top, 0.0f); 300 snapshot->setClip(0.0f, 0.0f, right - left, bottom - top); 301 snapshot->viewport.set(0.0f, 0.0f, right - left, bottom - top); 302 snapshot->height = bottom - top; 303 snapshot->flags |= Snapshot::kFlagDirtyOrtho; 304 snapshot->orthoMatrix.load(mOrthoMatrix); 305 306 setScissorFromClip(); 307 308 // Change the ortho projection 309 glViewport(0, 0, right - left, bottom - top); 310 mOrthoMatrix.loadOrtho(0.0f, right - left, bottom - top, 0.0f, -1.0f, 1.0f); 311 312 return true; 313} 314 315void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { 316 if (!current->layer) { 317 LOGE("Attempting to compose a layer that does not exist"); 318 return; 319 } 320 321 // Unbind current FBO and restore previous one 322 // Most of the time, previous->fbo will be 0 to bind the default buffer 323 glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo); 324 325 // Restore the clip from the previous snapshot 326 const Rect& clip = previous->clipRect; 327 glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight()); 328 329 Layer* layer = current->layer; 330 const Rect& rect = layer->layer; 331 332 // FBOs are already drawn with a top-left origin, don't flip the texture 333 resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f); 334 335 drawTextureRect(rect.left, rect.top, rect.right, rect.bottom, 336 layer->texture, layer->alpha, layer->mode, layer->blend); 337 338 resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); 339 340 LayerSize size(rect.getWidth(), rect.getHeight()); 341 // Failing to add the layer to the cache should happen only if the 342 // layer is too large 343 if (!mCaches.layerCache.put(size, layer)) { 344 LAYER_LOGD("Deleting layer"); 345 346 glDeleteFramebuffers(1, &layer->fbo); 347 glDeleteTextures(1, &layer->texture); 348 349 delete layer; 350 } 351} 352 353/////////////////////////////////////////////////////////////////////////////// 354// Transforms 355/////////////////////////////////////////////////////////////////////////////// 356 357void OpenGLRenderer::translate(float dx, float dy) { 358 mSnapshot->transform.translate(dx, dy, 0.0f); 359} 360 361void OpenGLRenderer::rotate(float degrees) { 362 mSnapshot->transform.rotate(degrees, 0.0f, 0.0f, 1.0f); 363} 364 365void OpenGLRenderer::scale(float sx, float sy) { 366 mSnapshot->transform.scale(sx, sy, 1.0f); 367} 368 369void OpenGLRenderer::setMatrix(SkMatrix* matrix) { 370 mSnapshot->transform.load(*matrix); 371} 372 373void OpenGLRenderer::getMatrix(SkMatrix* matrix) { 374 mSnapshot->transform.copyTo(*matrix); 375} 376 377void OpenGLRenderer::concatMatrix(SkMatrix* matrix) { 378 mat4 m(*matrix); 379 mSnapshot->transform.multiply(m); 380} 381 382/////////////////////////////////////////////////////////////////////////////// 383// Clipping 384/////////////////////////////////////////////////////////////////////////////// 385 386void OpenGLRenderer::setScissorFromClip() { 387 const Rect& clip = mSnapshot->clipRect; 388 glScissor(clip.left, mSnapshot->height - clip.bottom, clip.getWidth(), clip.getHeight()); 389} 390 391const Rect& OpenGLRenderer::getClipBounds() { 392 return mSnapshot->getLocalClip(); 393} 394 395bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) { 396 if (mSnapshot->invisible) return true; 397 398 Rect r(left, top, right, bottom); 399 mSnapshot->transform.mapRect(r); 400 return !mSnapshot->clipRect.intersects(r); 401} 402 403bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { 404 bool clipped = mSnapshot->clip(left, top, right, bottom, op); 405 if (clipped) { 406 setScissorFromClip(); 407 } 408 return !mSnapshot->clipRect.isEmpty(); 409} 410 411/////////////////////////////////////////////////////////////////////////////// 412// Drawing 413/////////////////////////////////////////////////////////////////////////////// 414 415void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint) { 416 const float right = left + bitmap->width(); 417 const float bottom = top + bitmap->height(); 418 419 if (quickReject(left, top, right, bottom)) { 420 return; 421 } 422 423 glActiveTexture(GL_TEXTURE0); 424 const Texture* texture = mCaches.textureCache.get(bitmap); 425 if (!texture) return; 426 const AutoTexture autoCleanup(texture); 427 428 drawTextureRect(left, top, right, bottom, texture, paint); 429} 430 431void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint) { 432 Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height()); 433 const mat4 transform(*matrix); 434 transform.mapRect(r); 435 436 if (quickReject(r.left, r.top, r.right, r.bottom)) { 437 return; 438 } 439 440 glActiveTexture(GL_TEXTURE0); 441 const Texture* texture = mCaches.textureCache.get(bitmap); 442 if (!texture) return; 443 const AutoTexture autoCleanup(texture); 444 445 drawTextureRect(r.left, r.top, r.right, r.bottom, texture, paint); 446} 447 448void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, 449 float srcLeft, float srcTop, float srcRight, float srcBottom, 450 float dstLeft, float dstTop, float dstRight, float dstBottom, 451 const SkPaint* paint) { 452 if (quickReject(dstLeft, dstTop, dstRight, dstBottom)) { 453 return; 454 } 455 456 glActiveTexture(GL_TEXTURE0); 457 const Texture* texture = mCaches.textureCache.get(bitmap); 458 if (!texture) return; 459 const AutoTexture autoCleanup(texture); 460 461 const float width = texture->width; 462 const float height = texture->height; 463 464 const float u1 = srcLeft / width; 465 const float v1 = srcTop / height; 466 const float u2 = srcRight / width; 467 const float v2 = srcBottom / height; 468 469 resetDrawTextureTexCoords(u1, v1, u2, v2); 470 471 drawTextureRect(dstLeft, dstTop, dstRight, dstBottom, texture, paint); 472 473 resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); 474} 475 476void OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch, 477 float left, float top, float right, float bottom, const SkPaint* paint) { 478 if (quickReject(left, top, right, bottom)) { 479 return; 480 } 481 482 glActiveTexture(GL_TEXTURE0); 483 const Texture* texture = mCaches.textureCache.get(bitmap); 484 if (!texture) return; 485 const AutoTexture autoCleanup(texture); 486 487 int alpha; 488 SkXfermode::Mode mode; 489 getAlphaAndMode(paint, &alpha, &mode); 490 491 Patch* mesh = mCaches.patchCache.get(patch); 492 mesh->updateVertices(bitmap, left, top, right, bottom, 493 &patch->xDivs[0], &patch->yDivs[0], patch->numXDivs, patch->numYDivs); 494 495 // Specify right and bottom as +1.0f from left/top to prevent scaling since the 496 // patch mesh already defines the final size 497 drawTextureMesh(left, top, left + 1.0f, top + 1.0f, texture->id, alpha / 255.0f, 498 mode, texture->blend, &mesh->vertices[0].position[0], 499 &mesh->vertices[0].texture[0], mesh->indices, mesh->indicesCount); 500} 501 502void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { 503 if (mSnapshot->invisible) return; 504 const Rect& clip = mSnapshot->clipRect; 505 drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true); 506} 507 508void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, const SkPaint* p) { 509 if (quickReject(left, top, right, bottom)) { 510 return; 511 } 512 513 SkXfermode::Mode mode; 514 515 const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode); 516 if (!isMode) { 517 // Assume SRC_OVER 518 mode = SkXfermode::kSrcOver_Mode; 519 } 520 521 // Skia draws using the color's alpha channel if < 255 522 // Otherwise, it uses the paint's alpha 523 int color = p->getColor(); 524 if (((color >> 24) & 0xff) == 255) { 525 color |= p->getAlpha() << 24; 526 } 527 528 drawColorRect(left, top, right, bottom, color, mode); 529} 530 531void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, 532 float x, float y, SkPaint* paint) { 533 if (mSnapshot->invisible || text == NULL || count == 0 || 534 (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) { 535 return; 536 } 537 538 float scaleX = paint->getTextScaleX(); 539 bool applyScaleX = scaleX < 0.9999f || scaleX > 1.0001f; 540 if (applyScaleX) { 541 save(0); 542 translate(x - (x * scaleX), 0.0f); 543 scale(scaleX, 1.0f); 544 } 545 546 float length = -1.0f; 547 switch (paint->getTextAlign()) { 548 case SkPaint::kCenter_Align: 549 length = paint->measureText(text, bytesCount); 550 x -= length / 2.0f; 551 break; 552 case SkPaint::kRight_Align: 553 length = paint->measureText(text, bytesCount); 554 x -= length; 555 break; 556 default: 557 break; 558 } 559 560 int alpha; 561 SkXfermode::Mode mode; 562 getAlphaAndMode(paint, &alpha, &mode); 563 564 uint32_t color = paint->getColor(); 565 const GLfloat a = alpha / 255.0f; 566 const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f; 567 const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f; 568 const GLfloat b = a * ((color ) & 0xFF) / 255.0f; 569 570 FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint); 571 fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()), 572 paint->getTextSize()); 573 if (mHasShadow) { 574 glActiveTexture(gTextureUnits[0]); 575 mCaches.dropShadowCache.setFontRenderer(fontRenderer); 576 const ShadowTexture* shadow = mCaches.dropShadowCache.get(paint, text, bytesCount, 577 count, mShadowRadius); 578 const AutoTexture autoCleanup(shadow); 579 580 setupShadow(shadow, x, y, mode, a); 581 582 // Draw the mesh 583 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); 584 glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); 585 } 586 587 GLuint textureUnit = 0; 588 glActiveTexture(gTextureUnits[textureUnit]); 589 590 setupTextureAlpha8(fontRenderer.getTexture(), 0, 0, textureUnit, x, y, r, g, b, a, 591 mode, false, true); 592 593 const Rect& clip = mSnapshot->getLocalClip(); 594 fontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y); 595 596 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 597 glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); 598 599 drawTextDecorations(text, bytesCount, length, x, y, paint); 600 601 if (applyScaleX) { 602 restore(); 603 } 604} 605 606void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) { 607 if (mSnapshot->invisible) return; 608 609 GLuint textureUnit = 0; 610 glActiveTexture(gTextureUnits[textureUnit]); 611 612 const PathTexture* texture = mCaches.pathCache.get(path, paint); 613 if (!texture) return; 614 const AutoTexture autoCleanup(texture); 615 616 const float x = texture->left - texture->offset; 617 const float y = texture->top - texture->offset; 618 619 if (quickReject(x, y, x + texture->width, y + texture->height)) { 620 return; 621 } 622 623 int alpha; 624 SkXfermode::Mode mode; 625 getAlphaAndMode(paint, &alpha, &mode); 626 627 uint32_t color = paint->getColor(); 628 const GLfloat a = alpha / 255.0f; 629 const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f; 630 const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f; 631 const GLfloat b = a * ((color ) & 0xFF) / 255.0f; 632 633 setupTextureAlpha8(texture, textureUnit, x, y, r, g, b, a, mode, true, true); 634 635 // Draw the mesh 636 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); 637 glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); 638} 639 640/////////////////////////////////////////////////////////////////////////////// 641// Shaders 642/////////////////////////////////////////////////////////////////////////////// 643 644void OpenGLRenderer::resetShader() { 645 mShader = NULL; 646} 647 648void OpenGLRenderer::setupShader(SkiaShader* shader) { 649 mShader = shader; 650 if (mShader) { 651 mShader->set(&mCaches.textureCache, &mCaches.gradientCache); 652 } 653} 654 655/////////////////////////////////////////////////////////////////////////////// 656// Color filters 657/////////////////////////////////////////////////////////////////////////////// 658 659void OpenGLRenderer::resetColorFilter() { 660 mColorFilter = NULL; 661} 662 663void OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) { 664 mColorFilter = filter; 665} 666 667/////////////////////////////////////////////////////////////////////////////// 668// Drop shadow 669/////////////////////////////////////////////////////////////////////////////// 670 671void OpenGLRenderer::resetShadow() { 672 mHasShadow = false; 673} 674 675void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) { 676 mHasShadow = true; 677 mShadowRadius = radius; 678 mShadowDx = dx; 679 mShadowDy = dy; 680 mShadowColor = color; 681} 682 683/////////////////////////////////////////////////////////////////////////////// 684// Drawing implementation 685/////////////////////////////////////////////////////////////////////////////// 686 687void OpenGLRenderer::setupShadow(const ShadowTexture* texture, float x, float y, 688 SkXfermode::Mode mode, float alpha) { 689 const float sx = x - texture->left + mShadowDx; 690 const float sy = y - texture->top + mShadowDy; 691 692 const int shadowAlpha = ((mShadowColor >> 24) & 0xFF); 693 const GLfloat a = shadowAlpha < 255 ? shadowAlpha / 255.0f : alpha; 694 const GLfloat r = a * ((mShadowColor >> 16) & 0xFF) / 255.0f; 695 const GLfloat g = a * ((mShadowColor >> 8) & 0xFF) / 255.0f; 696 const GLfloat b = a * ((mShadowColor ) & 0xFF) / 255.0f; 697 698 GLuint textureUnit = 0; 699 setupTextureAlpha8(texture, textureUnit, sx, sy, r, g, b, a, mode, true, false); 700} 701 702void OpenGLRenderer::setupTextureAlpha8(const Texture* texture, GLuint& textureUnit, 703 float x, float y, float r, float g, float b, float a, SkXfermode::Mode mode, 704 bool transforms, bool applyFilters) { 705 setupTextureAlpha8(texture->id, texture->width, texture->height, textureUnit, 706 x, y, r, g, b, a, mode, transforms, applyFilters); 707} 708 709void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height, 710 GLuint& textureUnit, float x, float y, float r, float g, float b, float a, 711 SkXfermode::Mode mode, bool transforms, bool applyFilters) { 712 // Describe the required shaders 713 ProgramDescription description; 714 description.hasTexture = true; 715 description.hasAlpha8Texture = true; 716 717 if (applyFilters) { 718 if (mShader) { 719 mShader->describe(description, mExtensions); 720 } 721 if (mColorFilter) { 722 mColorFilter->describe(description, mExtensions); 723 } 724 } 725 726 // Build and use the appropriate shader 727 useProgram(mCaches.programCache.get(description)); 728 729 // Setup the blending mode 730 chooseBlending(true, mode); 731 bindTexture(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, textureUnit); 732 glUniform1i(mCaches.currentProgram->getUniform("sampler"), textureUnit); 733 734 int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords"); 735 glEnableVertexAttribArray(texCoordsSlot); 736 737 // Setup attributes 738 glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, 739 gMeshStride, &mMeshVertices[0].position[0]); 740 glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, 741 gMeshStride, &mMeshVertices[0].texture[0]); 742 743 // Setup uniforms 744 if (transforms) { 745 mModelView.loadTranslate(x, y, 0.0f); 746 mModelView.scale(width, height, 1.0f); 747 } else { 748 mModelView.loadIdentity(); 749 } 750 mCaches.currentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); 751 glUniform4f(mCaches.currentProgram->color, r, g, b, a); 752 753 textureUnit++; 754 if (applyFilters) { 755 // Setup attributes and uniforms required by the shaders 756 if (mShader) { 757 mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit); 758 } 759 if (mColorFilter) { 760 mColorFilter->setupProgram(mCaches.currentProgram); 761 } 762 } 763} 764 765#define kStdStrikeThru_Offset (-6.0f / 21.0f) 766#define kStdUnderline_Offset (1.0f / 9.0f) 767#define kStdUnderline_Thickness (1.0f / 18.0f) 768 769void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float length, 770 float x, float y, SkPaint* paint) { 771 // Handle underline and strike-through 772 uint32_t flags = paint->getFlags(); 773 if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) { 774 float underlineWidth = length; 775 // If length is > 0.0f, we already measured the text for the text alignment 776 if (length <= 0.0f) { 777 underlineWidth = paint->measureText(text, bytesCount); 778 } 779 780 float offsetX = 0; 781 switch (paint->getTextAlign()) { 782 case SkPaint::kCenter_Align: 783 offsetX = underlineWidth * 0.5f; 784 break; 785 case SkPaint::kRight_Align: 786 offsetX = underlineWidth; 787 break; 788 default: 789 break; 790 } 791 792 if (underlineWidth > 0.0f) { 793 float textSize = paint->getTextSize(); 794 float height = textSize * kStdUnderline_Thickness; 795 796 float left = x - offsetX; 797 float top = 0.0f; 798 float right = left + underlineWidth; 799 float bottom = 0.0f; 800 801 if (flags & SkPaint::kUnderlineText_Flag) { 802 top = y + textSize * kStdUnderline_Offset; 803 bottom = top + height; 804 drawRect(left, top, right, bottom, paint); 805 } 806 807 if (flags & SkPaint::kStrikeThruText_Flag) { 808 top = y + textSize * kStdStrikeThru_Offset; 809 bottom = top + height; 810 drawRect(left, top, right, bottom, paint); 811 } 812 } 813 } 814} 815 816void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, 817 int color, SkXfermode::Mode mode, bool ignoreTransform) { 818 // If a shader is set, preserve only the alpha 819 if (mShader) { 820 color |= 0x00ffffff; 821 } 822 823 // Render using pre-multiplied alpha 824 const int alpha = (color >> 24) & 0xFF; 825 const GLfloat a = alpha / 255.0f; 826 const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f; 827 const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f; 828 const GLfloat b = a * ((color ) & 0xFF) / 255.0f; 829 830 GLuint textureUnit = 0; 831 832 // Setup the blending mode 833 chooseBlending(alpha < 255 || (mShader && mShader->blend()), mode); 834 835 // Describe the required shaders 836 ProgramDescription description; 837 if (mShader) { 838 mShader->describe(description, mExtensions); 839 } 840 if (mColorFilter) { 841 mColorFilter->describe(description, mExtensions); 842 } 843 844 // Build and use the appropriate shader 845 useProgram(mCaches.programCache.get(description)); 846 847 // Setup attributes 848 glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, 849 gMeshStride, &mMeshVertices[0].position[0]); 850 851 // Setup uniforms 852 mModelView.loadTranslate(left, top, 0.0f); 853 mModelView.scale(right - left, bottom - top, 1.0f); 854 if (!ignoreTransform) { 855 mCaches.currentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); 856 } else { 857 mat4 identity; 858 mCaches.currentProgram->set(mOrthoMatrix, mModelView, identity); 859 } 860 glUniform4f(mCaches.currentProgram->color, r, g, b, a); 861 862 // Setup attributes and uniforms required by the shaders 863 if (mShader) { 864 mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit); 865 } 866 if (mColorFilter) { 867 mColorFilter->setupProgram(mCaches.currentProgram); 868 } 869 870 // Draw the mesh 871 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); 872} 873 874void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, 875 const Texture* texture, const SkPaint* paint) { 876 int alpha; 877 SkXfermode::Mode mode; 878 getAlphaAndMode(paint, &alpha, &mode); 879 880 drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode, texture->blend, 881 &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], NULL); 882} 883 884void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, 885 GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) { 886 drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend, 887 &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], NULL); 888} 889 890void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom, 891 GLuint texture, float alpha, SkXfermode::Mode mode, bool blend, 892 GLvoid* vertices, GLvoid* texCoords, GLvoid* indices, GLsizei elementsCount) { 893 ProgramDescription description; 894 description.hasTexture = true; 895 if (mColorFilter) { 896 mColorFilter->describe(description, mExtensions); 897 } 898 899 mModelView.loadTranslate(left, top, 0.0f); 900 mModelView.scale(right - left, bottom - top, 1.0f); 901 902 useProgram(mCaches.programCache.get(description)); 903 mCaches.currentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform); 904 905 chooseBlending(blend || alpha < 1.0f, mode); 906 907 // Texture 908 bindTexture(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0); 909 glUniform1i(mCaches.currentProgram->getUniform("sampler"), 0); 910 911 // Always premultiplied 912 glUniform4f(mCaches.currentProgram->color, alpha, alpha, alpha, alpha); 913 914 // Mesh 915 int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords"); 916 glEnableVertexAttribArray(texCoordsSlot); 917 glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, 918 gMeshStride, vertices); 919 glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords); 920 921 // Color filter 922 if (mColorFilter) { 923 mColorFilter->setupProgram(mCaches.currentProgram); 924 } 925 926 if (!indices) { 927 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); 928 } else { 929 glDrawElements(GL_TRIANGLES, elementsCount, GL_UNSIGNED_SHORT, indices); 930 } 931 glDisableVertexAttribArray(texCoordsSlot); 932} 933 934void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, bool isPremultiplied) { 935 blend = blend || mode != SkXfermode::kSrcOver_Mode; 936 if (blend) { 937 if (!mCaches.blend) { 938 glEnable(GL_BLEND); 939 } 940 941 GLenum sourceMode = gBlends[mode].src; 942 GLenum destMode = gBlends[mode].dst; 943 if (!isPremultiplied && sourceMode == GL_ONE) { 944 sourceMode = GL_SRC_ALPHA; 945 } 946 947 if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) { 948 glBlendFunc(sourceMode, destMode); 949 mCaches.lastSrcMode = sourceMode; 950 mCaches.lastDstMode = destMode; 951 } 952 } else if (mCaches.blend) { 953 glDisable(GL_BLEND); 954 } 955 mCaches.blend = blend; 956} 957 958bool OpenGLRenderer::useProgram(Program* program) { 959 if (!program->isInUse()) { 960 if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove(); 961 program->use(); 962 mCaches.currentProgram = program; 963 return false; 964 } 965 return true; 966} 967 968void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) { 969 TextureVertex* v = &mMeshVertices[0]; 970 TextureVertex::setUV(v++, u1, v1); 971 TextureVertex::setUV(v++, u2, v1); 972 TextureVertex::setUV(v++, u1, v2); 973 TextureVertex::setUV(v++, u2, v2); 974} 975 976void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) { 977 if (paint) { 978 const bool isMode = SkXfermode::IsMode(paint->getXfermode(), mode); 979 if (!isMode) { 980 // Assume SRC_OVER 981 *mode = SkXfermode::kSrcOver_Mode; 982 } 983 984 // Skia draws using the color's alpha channel if < 255 985 // Otherwise, it uses the paint's alpha 986 int color = paint->getColor(); 987 *alpha = (color >> 24) & 0xFF; 988 if (*alpha == 255) { 989 *alpha = paint->getAlpha(); 990 } 991 } else { 992 *mode = SkXfermode::kSrcOver_Mode; 993 *alpha = 255; 994 } 995} 996 997void OpenGLRenderer::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit) { 998 glActiveTexture(gTextureUnits[textureUnit]); 999 glBindTexture(GL_TEXTURE_2D, texture); 1000 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS); 1001 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT); 1002} 1003 1004}; // namespace uirenderer 1005}; // namespace android 1006