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
gl_pmcolor(U8CPU r,U8CPU g,U8CPU b,U8CPU a)14 static inline void gl_pmcolor(U8CPU r, U8CPU g, U8CPU b, U8CPU a) {
15 glColor4ub(r, g, b, a);
16 }
17
SetAlpha(U8CPU alpha)18 void SkGL::SetAlpha(U8CPU alpha) {
19 glColor4ub(alpha, alpha, alpha, alpha);
20 }
21 #else
byte2fixed(U8CPU value)22 static inline SkFixed byte2fixed(U8CPU value) {
23 return (value + (value >> 7)) << 8;
24 }
25
gl_pmcolor(U8CPU r,U8CPU g,U8CPU b,U8CPU a)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
SetAlpha(U8CPU alpha)30 void SkGL::SetAlpha(U8CPU alpha) {
31 SkFixed fa = byte2fixed(alpha);
32 glColor4x(fa, fa, fa, fa);
33 }
34 #endif
35
SetColor(SkColor c)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
SetPaint(const SkPaint & paint,bool isPremul,bool justAlpha)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
DumpError(const char caller[])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
SetRGBA(uint8_t rgba[],const SkColor src[],int count)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
Scissor(const SkIRect & r,int viewportHeight)112 void SkGL::Scissor(const SkIRect& r, int viewportHeight) {
113 glScissor(r.fLeft, viewportHeight - r.fBottom, r.width(), r.height());
114 }
115
116 ///////////////////////////////////////////////////////////////////////////////
117
Ortho(float left,float right,float bottom,float top,float near,float far)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
canBeTexture(const SkBitmap & bm,GLenum * format,GLenum * type)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
ComputeTextureMemorySize(const SkBitmap & bitmap)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 */
build_compressed_data(void * buffer,const SkBitmap & bitmap)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 */
needToPromoteTo32bit(const SkBitmap & bitmap)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
BindNewTexture(const SkBitmap & origBitmap,SkPoint * max)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
SetTexParams(bool doFilter,SkShader::TileMode tx,SkShader::TileMode ty)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
SetTexParamsClamp(bool doFilter)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
DrawVertices(int count,GLenum mode,const SkGLVertex * SK_RESTRICT vertex,const SkGLVertex * SK_RESTRICT texCoords,const uint8_t * SK_RESTRICT colorArray,const uint16_t * SK_RESTRICT indexArray,SkGLClipIter * iter)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
PrepareForFillPath(SkPaint * paint)404 void SkGL::PrepareForFillPath(SkPaint* paint) {
405 if (paint->getStrokeWidth() <= 0) {
406 paint->setStrokeWidth(SK_Scalar1);
407 }
408 }
409
FillPath(const SkPath & path,const SkPaint & paint,bool useTex,SkGLClipIter * iter)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)
worst_case_edge_count(const SkPath & path)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
DrawPath(const SkPath & path,bool useTex,SkGLClipIter * clipIter)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