1 #include "SkGL.h" 2 #include "SkColorPriv.h" 3 #include "SkGeometry.h" 4 #include "SkPaint.h" 5 #include "SkPath.h" 6 #include "SkTemplates.h" 7 #include "SkXfermode.h" 8 9 //#define TRACE_TEXTURE_CREATION 10 11 /////////////////////////////////////////////////////////////////////////////// 12 13 #ifdef SK_GL_HAS_COLOR4UB 14 static inline void gl_pmcolor(U8CPU r, U8CPU g, U8CPU b, U8CPU a) { 15 glColor4ub(r, g, b, a); 16 } 17 18 void SkGL::SetAlpha(U8CPU alpha) { 19 glColor4ub(alpha, alpha, alpha, alpha); 20 } 21 #else 22 static inline SkFixed byte2fixed(U8CPU value) { 23 return (value + (value >> 7)) << 8; 24 } 25 26 static inline void gl_pmcolor(U8CPU r, U8CPU g, U8CPU b, U8CPU a) { 27 glColor4x(byte2fixed(r), byte2fixed(g), byte2fixed(b), byte2fixed(a)); 28 } 29 30 void SkGL::SetAlpha(U8CPU alpha) { 31 SkFixed fa = byte2fixed(alpha); 32 glColor4x(fa, fa, fa, fa); 33 } 34 #endif 35 36 void SkGL::SetColor(SkColor c) { 37 SkPMColor pm = SkPreMultiplyColor(c); 38 gl_pmcolor(SkGetPackedR32(pm), 39 SkGetPackedG32(pm), 40 SkGetPackedB32(pm), 41 SkGetPackedA32(pm)); 42 } 43 44 static const GLenum gXfermodeCoeff2Blend[] = { 45 GL_ZERO, 46 GL_ONE, 47 GL_SRC_COLOR, 48 GL_ONE_MINUS_SRC_COLOR, 49 GL_DST_COLOR, 50 GL_ONE_MINUS_DST_COLOR, 51 GL_SRC_ALPHA, 52 GL_ONE_MINUS_SRC_ALPHA, 53 GL_DST_ALPHA, 54 GL_ONE_MINUS_DST_ALPHA, 55 }; 56 57 void SkGL::SetPaint(const SkPaint& paint, bool isPremul, bool justAlpha) { 58 if (justAlpha) { 59 SkGL::SetAlpha(paint.getAlpha()); 60 } else { 61 SkGL::SetColor(paint.getColor()); 62 } 63 64 GLenum sm = GL_ONE; 65 GLenum dm = GL_ONE_MINUS_SRC_ALPHA; 66 67 SkXfermode* mode = paint.getXfermode(); 68 SkXfermode::Coeff sc, dc; 69 if (mode && mode->asCoeff(&sc, &dc)) { 70 sm = gXfermodeCoeff2Blend[sc]; 71 dm = gXfermodeCoeff2Blend[dc]; 72 } 73 74 // hack for text, which is not-premul (afaik) 75 if (!isPremul) { 76 if (GL_ONE == sm) { 77 sm = GL_SRC_ALPHA; 78 } 79 } 80 81 glEnable(GL_BLEND); 82 glBlendFunc(sm, dm); 83 84 if (paint.isDither()) { 85 glEnable(GL_DITHER); 86 } else { 87 glDisable(GL_DITHER); 88 } 89 } 90 91 /////////////////////////////////////////////////////////////////////////////// 92 93 void SkGL::DumpError(const char caller[]) { 94 GLenum err = glGetError(); 95 if (err) { 96 SkDebugf("---- glGetError(%s) %d\n", caller, err); 97 } 98 } 99 100 void SkGL::SetRGBA(uint8_t rgba[], const SkColor src[], int count) { 101 for (int i = 0; i < count; i++) { 102 SkPMColor c = SkPreMultiplyColor(*src++); 103 *rgba++ = SkGetPackedR32(c); 104 *rgba++ = SkGetPackedG32(c); 105 *rgba++ = SkGetPackedB32(c); 106 *rgba++ = SkGetPackedA32(c); 107 } 108 } 109 110 /////////////////////////////////////////////////////////////////////////////// 111 112 void SkGL::Scissor(const SkIRect& r, int viewportHeight) { 113 glScissor(r.fLeft, viewportHeight - r.fBottom, r.width(), r.height()); 114 } 115 116 /////////////////////////////////////////////////////////////////////////////// 117 118 void SkGL::Ortho(float left, float right, float bottom, float top, 119 float near, float far) { 120 121 float mat[16]; 122 123 sk_bzero(mat, sizeof(mat)); 124 125 mat[0] = 2 / (right - left); 126 mat[5] = 2 / (top - bottom); 127 mat[10] = 2 / (near - far); 128 mat[15] = 1; 129 130 mat[12] = (right + left) / (left - right); 131 mat[13] = (top + bottom) / (bottom - top); 132 mat[14] = (far + near) / (near - far); 133 134 glMultMatrixf(mat); 135 } 136 137 /////////////////////////////////////////////////////////////////////////////// 138 139 static bool canBeTexture(const SkBitmap& bm, GLenum* format, GLenum* type) { 140 switch (bm.config()) { 141 case SkBitmap::kARGB_8888_Config: 142 *format = GL_RGBA; 143 *type = GL_UNSIGNED_BYTE; 144 break; 145 case SkBitmap::kRGB_565_Config: 146 *format = GL_RGB; 147 *type = GL_UNSIGNED_SHORT_5_6_5; 148 break; 149 case SkBitmap::kARGB_4444_Config: 150 *format = GL_RGBA; 151 *type = GL_UNSIGNED_SHORT_4_4_4_4; 152 break; 153 case SkBitmap::kIndex8_Config: 154 #ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D 155 *format = GL_PALETTE8_RGBA8_OES; 156 *type = GL_UNSIGNED_BYTE; // unused I think 157 #else 158 // we promote index to argb32 159 *format = GL_RGBA; 160 *type = GL_UNSIGNED_BYTE; 161 #endif 162 break; 163 case SkBitmap::kA8_Config: 164 *format = GL_ALPHA; 165 *type = GL_UNSIGNED_BYTE; 166 break; 167 default: 168 return false; 169 } 170 return true; 171 } 172 173 #define SK_GL_SIZE_OF_PALETTE (256 * sizeof(SkPMColor)) 174 175 size_t SkGL::ComputeTextureMemorySize(const SkBitmap& bitmap) { 176 int shift = 0; 177 size_t adder = 0; 178 switch (bitmap.config()) { 179 case SkBitmap::kARGB_8888_Config: 180 case SkBitmap::kRGB_565_Config: 181 case SkBitmap::kARGB_4444_Config: 182 case SkBitmap::kA8_Config: 183 // we're good as is 184 break; 185 case SkBitmap::kIndex8_Config: 186 #ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D 187 // account for the colortable 188 adder = SK_GL_SIZE_OF_PALETTE; 189 #else 190 // we promote index to argb32 191 shift = 2; 192 #endif 193 break; 194 default: 195 return 0; 196 } 197 return (bitmap.getSize() << shift) + adder; 198 } 199 200 #ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D 201 /* Fill out buffer with the compressed format GL expects from a colortable 202 based bitmap. [palette (colortable) + indices]. 203 204 At the moment I always take the 8bit version, since that's what my data 205 is. I could detect that the colortable.count is <= 16, and then repack the 206 indices as nibbles to save RAM, but it would take more time (i.e. a lot 207 slower than memcpy), so I'm skipping that for now. 208 209 GL wants a full 256 palette entry, even though my ctable is only as big 210 as the colortable.count says it is. I presume it is OK to leave any 211 trailing entries uninitialized, since none of my indices should exceed 212 ctable->count(). 213 */ 214 static void build_compressed_data(void* buffer, const SkBitmap& bitmap) { 215 SkASSERT(SkBitmap::kIndex8_Config == bitmap.config()); 216 217 SkColorTable* ctable = bitmap.getColorTable(); 218 uint8_t* dst = (uint8_t*)buffer; 219 220 memcpy(dst, ctable->lockColors(), ctable->count() * sizeof(SkPMColor)); 221 ctable->unlockColors(false); 222 223 // always skip a full 256 number of entries, even if we memcpy'd fewer 224 dst += SK_GL_SIZE_OF_PALETTE; 225 memcpy(dst, bitmap.getPixels(), bitmap.getSize()); 226 } 227 #endif 228 229 /* Return true if the bitmap cannot be supported in its current config as a 230 texture, and it needs to be promoted to ARGB32. 231 */ 232 static bool needToPromoteTo32bit(const SkBitmap& bitmap) { 233 if (bitmap.config() == SkBitmap::kIndex8_Config) { 234 #ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D 235 const int w = bitmap.width(); 236 const int h = bitmap.height(); 237 if (SkNextPow2(w) == w && SkNextPow2(h) == h) { 238 // we can handle Indx8 if we're a POW2 239 return false; 240 } 241 #endif 242 return true; // must promote to ARGB32 243 } 244 return false; 245 } 246 247 GLuint SkGL::BindNewTexture(const SkBitmap& origBitmap, SkPoint* max) { 248 SkBitmap tmpBitmap; 249 const SkBitmap* bitmap = &origBitmap; 250 251 if (needToPromoteTo32bit(origBitmap)) { 252 origBitmap.copyTo(&tmpBitmap, SkBitmap::kARGB_8888_Config); 253 // now bitmap points to our temp, which has been promoted to 32bits 254 bitmap = &tmpBitmap; 255 } 256 257 GLenum format, type; 258 if (!canBeTexture(*bitmap, &format, &type)) { 259 return 0; 260 } 261 262 SkAutoLockPixels alp(*bitmap); 263 if (!bitmap->readyToDraw()) { 264 return 0; 265 } 266 267 GLuint textureName; 268 glGenTextures(1, &textureName); 269 270 glBindTexture(GL_TEXTURE_2D, textureName); 271 272 // express rowbytes as a number of pixels for ow 273 int ow = bitmap->rowBytesAsPixels(); 274 int oh = bitmap->height(); 275 int nw = SkNextPow2(ow); 276 int nh = SkNextPow2(oh); 277 278 glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel()); 279 280 // check if we need to scale to create power-of-2 dimensions 281 #ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D 282 if (SkBitmap::kIndex8_Config == bitmap->config()) { 283 size_t imagesize = bitmap->getSize() + SK_GL_SIZE_OF_PALETTE; 284 SkAutoMalloc storage(imagesize); 285 286 build_compressed_data(storage.get(), *bitmap); 287 // we only support POW2 here (GLES 1.0 restriction) 288 SkASSERT(ow == nw); 289 SkASSERT(oh == nh); 290 glCompressedTexImage2D(GL_TEXTURE_2D, 0, format, ow, oh, 0, 291 imagesize, storage.get()); 292 } else // fall through to non-compressed logic 293 #endif 294 { 295 if (ow != nw || oh != nh) { 296 glTexImage2D(GL_TEXTURE_2D, 0, format, nw, nh, 0, 297 format, type, NULL); 298 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ow, oh, 299 format, type, bitmap->getPixels()); 300 } else { 301 // easy case, the bitmap is already pow2 302 glTexImage2D(GL_TEXTURE_2D, 0, format, ow, oh, 0, 303 format, type, bitmap->getPixels()); 304 } 305 } 306 307 #ifdef TRACE_TEXTURE_CREATION 308 SkDebugf("--- new texture [%d] size=(%d %d) bpp=%d\n", textureName, ow, oh, 309 bitmap->bytesPerPixel()); 310 #endif 311 312 if (max) { 313 max->fX = SkFixedToScalar(bitmap->width() << (16 - SkNextLog2(nw))); 314 max->fY = SkFixedToScalar(oh << (16 - SkNextLog2(nh))); 315 } 316 return textureName; 317 } 318 319 static const GLenum gTileMode2GLWrap[] = { 320 GL_CLAMP_TO_EDGE, 321 GL_REPEAT, 322 #if GL_VERSION_ES_CM_1_0 323 GL_REPEAT // GLES doesn't support MIRROR 324 #else 325 GL_MIRRORED_REPEAT 326 #endif 327 }; 328 329 void SkGL::SetTexParams(bool doFilter, 330 SkShader::TileMode tx, SkShader::TileMode ty) { 331 SkASSERT((unsigned)tx < SK_ARRAY_COUNT(gTileMode2GLWrap)); 332 SkASSERT((unsigned)ty < SK_ARRAY_COUNT(gTileMode2GLWrap)); 333 334 GLenum filter = doFilter ? GL_LINEAR : GL_NEAREST; 335 336 SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); 337 SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); 338 SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gTileMode2GLWrap[tx]); 339 SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gTileMode2GLWrap[ty]); 340 } 341 342 void SkGL::SetTexParamsClamp(bool doFilter) { 343 GLenum filter = doFilter ? GL_LINEAR : GL_NEAREST; 344 345 SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); 346 SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); 347 SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 348 SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 349 } 350 351 /////////////////////////////////////////////////////////////////////////////// 352 353 void SkGL::DrawVertices(int count, GLenum mode, 354 const SkGLVertex* SK_RESTRICT vertex, 355 const SkGLVertex* SK_RESTRICT texCoords, 356 const uint8_t* SK_RESTRICT colorArray, 357 const uint16_t* SK_RESTRICT indexArray, 358 SkGLClipIter* iter) { 359 SkASSERT(NULL != vertex); 360 361 if (NULL != texCoords) { 362 glEnable(GL_TEXTURE_2D); 363 glEnableClientState(GL_TEXTURE_COORD_ARRAY); 364 glTexCoordPointer(2, SK_GLType, 0, texCoords); 365 } else { 366 glDisable(GL_TEXTURE_2D); 367 glDisableClientState(GL_TEXTURE_COORD_ARRAY); 368 } 369 370 if (NULL != colorArray) { 371 glEnableClientState(GL_COLOR_ARRAY); 372 glColorPointer(4, GL_UNSIGNED_BYTE, 0, colorArray); 373 glShadeModel(GL_SMOOTH); 374 } else { 375 glDisableClientState(GL_COLOR_ARRAY); 376 glShadeModel(GL_FLAT); 377 } 378 379 glVertexPointer(2, SK_GLType, 0, vertex); 380 381 if (NULL != indexArray) { 382 if (iter) { 383 while (!iter->done()) { 384 iter->scissor(); 385 glDrawElements(mode, count, GL_UNSIGNED_SHORT, indexArray); 386 iter->next(); 387 } 388 } else { 389 glDrawElements(mode, count, GL_UNSIGNED_SHORT, indexArray); 390 } 391 } else { 392 if (iter) { 393 while (!iter->done()) { 394 iter->scissor(); 395 glDrawArrays(mode, 0, count); 396 iter->next(); 397 } 398 } else { 399 glDrawArrays(mode, 0, count); 400 } 401 } 402 } 403 404 void SkGL::PrepareForFillPath(SkPaint* paint) { 405 if (paint->getStrokeWidth() <= 0) { 406 paint->setStrokeWidth(SK_Scalar1); 407 } 408 } 409 410 void SkGL::FillPath(const SkPath& path, const SkPaint& paint, bool useTex, 411 SkGLClipIter* iter) { 412 SkPaint p(paint); 413 SkPath fillPath; 414 415 SkGL::PrepareForFillPath(&p); 416 p.getFillPath(path, &fillPath); 417 SkGL::DrawPath(fillPath, useTex, iter); 418 } 419 420 // should return max of all contours, rather than the sum (to save temp RAM) 421 static int worst_case_edge_count(const SkPath& path) { 422 int edgeCount = 0; 423 424 SkPath::Iter iter(path, true); 425 SkPath::Verb verb; 426 427 while ((verb = iter.next(NULL)) != SkPath::kDone_Verb) { 428 switch (verb) { 429 case SkPath::kLine_Verb: 430 edgeCount += 1; 431 break; 432 case SkPath::kQuad_Verb: 433 edgeCount += 8; 434 break; 435 case SkPath::kCubic_Verb: 436 edgeCount += 16; 437 break; 438 default: 439 break; 440 } 441 } 442 return edgeCount; 443 } 444 445 void SkGL::DrawPath(const SkPath& path, bool useTex, SkGLClipIter* clipIter) { 446 const SkRect& bounds = path.getBounds(); 447 if (bounds.isEmpty()) { 448 return; 449 } 450 451 int maxPts = worst_case_edge_count(path); 452 // add 1 for center of fan, and 1 for closing edge 453 SkAutoSTMalloc<32, SkGLVertex> storage(maxPts + 2); 454 SkGLVertex* base = storage.get(); 455 SkGLVertex* vert = base; 456 SkGLVertex* texs = useTex ? base : NULL; 457 458 SkPath::Iter pathIter(path, true); 459 SkPoint pts[4]; 460 461 bool needEnd = false; 462 463 for (;;) { 464 switch (pathIter.next(pts)) { 465 case SkPath::kMove_Verb: 466 if (needEnd) { 467 SkGL::DrawVertices(vert - base, GL_TRIANGLE_FAN, 468 base, texs, NULL, NULL, clipIter); 469 clipIter->safeRewind(); 470 vert = base; 471 } 472 needEnd = true; 473 // center of the FAN 474 vert->setScalars(bounds.centerX(), bounds.centerY()); 475 vert++; 476 // add first edge point 477 vert->setPoint(pts[0]); 478 vert++; 479 break; 480 case SkPath::kLine_Verb: 481 vert->setPoint(pts[1]); 482 vert++; 483 break; 484 case SkPath::kQuad_Verb: { 485 const int n = 8; 486 const SkScalar dt = SK_Scalar1 / n; 487 SkScalar t = dt; 488 for (int i = 1; i < n; i++) { 489 SkPoint loc; 490 SkEvalQuadAt(pts, t, &loc, NULL); 491 t += dt; 492 vert->setPoint(loc); 493 vert++; 494 } 495 vert->setPoint(pts[2]); 496 vert++; 497 break; 498 } 499 case SkPath::kCubic_Verb: { 500 const int n = 16; 501 const SkScalar dt = SK_Scalar1 / n; 502 SkScalar t = dt; 503 for (int i = 1; i < n; i++) { 504 SkPoint loc; 505 SkEvalCubicAt(pts, t, &loc, NULL, NULL); 506 t += dt; 507 vert->setPoint(loc); 508 vert++; 509 } 510 vert->setPoint(pts[3]); 511 vert++; 512 break; 513 } 514 case SkPath::kClose_Verb: 515 break; 516 case SkPath::kDone_Verb: 517 goto FINISHED; 518 } 519 } 520 FINISHED: 521 if (needEnd) { 522 SkGL::DrawVertices(vert - base, GL_TRIANGLE_FAN, base, texs, 523 NULL, NULL, clipIter); 524 } 525 } 526 527