• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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