• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "gm/gm.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkBlendMode.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkColorFilter.h"
14 #include "include/core/SkColorPriv.h"
15 #include "include/core/SkColorSpace.h"
16 #include "include/core/SkFilterQuality.h"
17 #include "include/core/SkFont.h"
18 #include "include/core/SkFontStyle.h"
19 #include "include/core/SkFontTypes.h"
20 #include "include/core/SkImage.h"
21 #include "include/core/SkImageGenerator.h"
22 #include "include/core/SkImageInfo.h"
23 #include "include/core/SkMatrix.h"
24 #include "include/core/SkPaint.h"
25 #include "include/core/SkPath.h"
26 #include "include/core/SkPixmap.h"
27 #include "include/core/SkPoint.h"
28 #include "include/core/SkRect.h"
29 #include "include/core/SkRefCnt.h"
30 #include "include/core/SkScalar.h"
31 #include "include/core/SkSize.h"
32 #include "include/core/SkString.h"
33 #include "include/core/SkTypeface.h"
34 #include "include/core/SkTypes.h"
35 #include "include/core/SkYUVAIndex.h"
36 #include "include/core/SkYUVASizeInfo.h"
37 #include "include/gpu/GrBackendSurface.h"
38 #include "include/gpu/GrConfig.h"
39 #include "include/gpu/GrContext.h"
40 #include "include/gpu/GrTypes.h"
41 #include "include/private/GrTypesPriv.h"
42 #include "include/private/SkTArray.h"
43 #include "include/private/SkTDArray.h"
44 #include "include/private/SkTemplates.h"
45 #include "include/utils/SkTextUtils.h"
46 #include "src/gpu/GrContextPriv.h"
47 #include "src/gpu/GrGpu.h"
48 #include "tools/ToolUtils.h"
49 
50 #include <math.h>
51 #include <string.h>
52 #include <initializer_list>
53 #include <memory>
54 #include <utility>
55 
56 class GrRenderTargetContext;
57 
58 static const int kTileWidthHeight = 128;
59 static const int kLabelWidth = 64;
60 static const int kLabelHeight = 32;
61 static const int kDomainPadding = 8;
62 static const int kPad = 1;
63 
64 enum YUVFormat {
65     // 4:2:0 formats, 24 bpp
66     kP016_YUVFormat, // 16-bit Y plane + 2x2 down sampled interleaved U/V plane (2 textures)
67     // 4:2:0 formats, "15 bpp" (but really 24 bpp)
68     kP010_YUVFormat, // same as kP016 except "10 bpp". Note that it is the same memory layout
69                      // except that the bottom 6 bits are zeroed out (2 textures)
70     // TODO: we're cheating a bit w/ P010 and just treating it as unorm 16. This means its
71     // fully saturated values are 65504 rather than 65535 (that is just .9995 out of 1.0 though).
72 
73     // 4:4:4 formats, 64 bpp
74     kY416_YUVFormat,  // 16-bit AVYU values all interleaved (1 texture)
75 
76     // 4:4:4 formats, 32 bpp
77     kAYUV_YUVFormat,  // 8-bit YUVA values all interleaved (1 texture)
78     kY410_YUVFormat,  // AVYU w/ 10bpp for YUV and 2 for A all interleaved (1 texture)
79 
80     // 4:2:0 formats, 12 bpp
81     kNV12_YUVFormat, // 8-bit Y plane + 2x2 down sampled interleaved U/V planes (2 textures)
82     kNV21_YUVFormat, // same as kNV12 but w/ U/V reversed in the interleaved texture (2 textures)
83 
84     kI420_YUVFormat, // 8-bit Y plane + separate 2x2 down sampled U and V planes (3 textures)
85     kYV12_YUVFormat, // 8-bit Y plane + separate 2x2 down sampled V and U planes (3 textures)
86 
87     kLast_YUVFormat = kYV12_YUVFormat
88 };
89 
format_uses_16_bpp(YUVFormat yuvFormat)90 static bool format_uses_16_bpp(YUVFormat yuvFormat) {
91     return kP016_YUVFormat == yuvFormat ||
92            kP010_YUVFormat == yuvFormat ||
93            kY416_YUVFormat == yuvFormat;
94 }
95 
format_has_builtin_alpha(YUVFormat yuvFormat)96 static bool format_has_builtin_alpha(YUVFormat yuvFormat) {
97     return kY416_YUVFormat == yuvFormat ||
98            kAYUV_YUVFormat == yuvFormat ||
99            kY410_YUVFormat == yuvFormat;
100 }
101 
format_cant_be_represented_with_pixmaps(YUVFormat yuvFormat)102 static bool format_cant_be_represented_with_pixmaps(YUVFormat yuvFormat) {
103     return kP016_YUVFormat == yuvFormat ||      // bc missing SkColorType::kRG_1616 and kR_16
104            kP010_YUVFormat == yuvFormat ||      // bc missing SkColorType::kRG_1616 and kR_16
105            kY416_YUVFormat == yuvFormat ||      // bc missing SkColorType::kRGBA_16161616
106            kNV12_YUVFormat == yuvFormat ||      // bc missing SkColorType::kRG_88
107            kNV21_YUVFormat == yuvFormat;        // bc missing SkColorType::kRG_88
108 }
109 
110 // Helper to setup the SkYUVAIndex array correctly
111 // Skia allows the client to tack an additional alpha plane onto any of the standard opaque
112 // formats (via the addExtraAlpha) flag. In this case it is assumed to be a stand-alone single-
113 // channel plane.
setup_yuv_indices(YUVFormat yuvFormat,bool addExtraAlpha,SkYUVAIndex yuvaIndices[4])114 static void setup_yuv_indices(YUVFormat yuvFormat, bool addExtraAlpha, SkYUVAIndex yuvaIndices[4]) {
115     switch (yuvFormat) {
116         case kP016_YUVFormat: // fall through
117         case kP010_YUVFormat:
118             yuvaIndices[0].fIndex = 0;
119             yuvaIndices[0].fChannel = SkColorChannel::kR; // bc 16bit is stored in R16 format
120             yuvaIndices[1].fIndex = 1;
121             yuvaIndices[1].fChannel = SkColorChannel::kR;
122             yuvaIndices[2].fIndex = 1;
123             yuvaIndices[2].fChannel = SkColorChannel::kG;
124             if (addExtraAlpha) {
125                 yuvaIndices[3].fIndex = 2;
126                 yuvaIndices[3].fChannel = SkColorChannel::kR; // bc 16bit is stored in R16 format
127             } else {
128                 yuvaIndices[3].fIndex = -1; // No alpha channel
129             }
130             break;
131         case kY416_YUVFormat:
132             SkASSERT(!addExtraAlpha); // this format already has an alpha channel
133             yuvaIndices[0].fIndex = 0;
134             yuvaIndices[0].fChannel = SkColorChannel::kG;
135             yuvaIndices[1].fIndex = 0;
136             yuvaIndices[1].fChannel = SkColorChannel::kB;
137             yuvaIndices[2].fIndex = 0;
138             yuvaIndices[2].fChannel = SkColorChannel::kR;
139             yuvaIndices[3].fIndex = 0;
140             yuvaIndices[3].fChannel = SkColorChannel::kA;
141             break;
142         case kAYUV_YUVFormat:
143             SkASSERT(!addExtraAlpha); // this format already has an alpha channel
144             yuvaIndices[0].fIndex = 0;
145             yuvaIndices[0].fChannel = SkColorChannel::kR;
146             yuvaIndices[1].fIndex = 0;
147             yuvaIndices[1].fChannel = SkColorChannel::kG;
148             yuvaIndices[2].fIndex = 0;
149             yuvaIndices[2].fChannel = SkColorChannel::kB;
150             yuvaIndices[3].fIndex = 0;
151             yuvaIndices[3].fChannel = SkColorChannel::kA;
152             break;
153         case kY410_YUVFormat:
154             SkASSERT(!addExtraAlpha); // this format already has an alpha channel
155             yuvaIndices[0].fIndex = 0;
156             yuvaIndices[0].fChannel = SkColorChannel::kG;
157             yuvaIndices[1].fIndex = 0;
158             yuvaIndices[1].fChannel = SkColorChannel::kB;
159             yuvaIndices[2].fIndex = 0;
160             yuvaIndices[2].fChannel = SkColorChannel::kR;
161             yuvaIndices[3].fIndex = 0;
162             yuvaIndices[3].fChannel = SkColorChannel::kA;
163             break;
164         case kNV12_YUVFormat:
165             yuvaIndices[0].fIndex = 0;
166             yuvaIndices[0].fChannel = SkColorChannel::kR;
167             yuvaIndices[1].fIndex = 1;
168             yuvaIndices[1].fChannel = SkColorChannel::kR;
169             yuvaIndices[2].fIndex = 1;
170             yuvaIndices[2].fChannel = SkColorChannel::kG;
171             if (addExtraAlpha) {
172                 yuvaIndices[3].fIndex = 2;
173                 yuvaIndices[3].fChannel = SkColorChannel::kA;
174             } else {
175                 yuvaIndices[3].fIndex = -1; // No alpha channel
176             }
177             break;
178         case kNV21_YUVFormat:
179             yuvaIndices[0].fIndex = 0;
180             yuvaIndices[0].fChannel = SkColorChannel::kR;
181             yuvaIndices[1].fIndex = 1;
182             yuvaIndices[1].fChannel = SkColorChannel::kG;
183             yuvaIndices[2].fIndex = 1;
184             yuvaIndices[2].fChannel = SkColorChannel::kR;
185             if (addExtraAlpha) {
186                 yuvaIndices[3].fIndex = 2;
187                 yuvaIndices[3].fChannel = SkColorChannel::kA;
188             } else {
189                 yuvaIndices[3].fIndex = -1; // No alpha channel
190             }
191             break;
192         case kI420_YUVFormat:
193             yuvaIndices[0].fIndex = 0;
194             yuvaIndices[0].fChannel = SkColorChannel::kR;
195             yuvaIndices[1].fIndex = 1;
196             yuvaIndices[1].fChannel = SkColorChannel::kR;
197             yuvaIndices[2].fIndex = 2;
198             yuvaIndices[2].fChannel = SkColorChannel::kR;
199             if (addExtraAlpha) {
200                 yuvaIndices[3].fIndex = 3;
201                 yuvaIndices[3].fChannel = SkColorChannel::kA;
202             } else {
203                 yuvaIndices[3].fIndex = -1; // No alpha channel
204             }
205             break;
206         case kYV12_YUVFormat:
207             yuvaIndices[0].fIndex = 0;
208             yuvaIndices[0].fChannel = SkColorChannel::kR;
209             yuvaIndices[1].fIndex = 2;
210             yuvaIndices[1].fChannel = SkColorChannel::kR;
211             yuvaIndices[2].fIndex = 1;
212             yuvaIndices[2].fChannel = SkColorChannel::kR;
213             if (addExtraAlpha) {
214                 yuvaIndices[3].fIndex = 3;
215                 yuvaIndices[3].fChannel = SkColorChannel::kA;
216             } else {
217                 yuvaIndices[3].fIndex = -1; // No alpha channel
218             }
219             break;
220     }
221 }
222 
223 // All the planes we need to construct the various YUV formats
224 struct PlaneData {
225    SkBitmap fYFull;
226    SkBitmap fUFull;
227    SkBitmap fVFull;
228    SkBitmap fAFull;
229    SkBitmap fUQuarter; // 2x2 downsampled U channel
230    SkBitmap fVQuarter; // 2x2 downsampled V channel
231 };
232 
233 // Add a portion of a circle to 'path'. The points 'o1' and 'o2' are on the border of the circle
234 // and have tangents 'v1' and 'v2'.
add_arc(SkPath * path,const SkPoint & o1,const SkVector & v1,const SkPoint & o2,const SkVector & v2,SkTDArray<SkRect> * circles,bool takeLongWayRound)235 static void add_arc(SkPath* path,
236                     const SkPoint& o1, const SkVector& v1,
237                     const SkPoint& o2, const SkVector& v2,
238                     SkTDArray<SkRect>* circles, bool takeLongWayRound) {
239 
240     SkVector v3 = { -v1.fY, v1.fX };
241     SkVector v4 = { v2.fY, -v2.fX };
242 
243     SkScalar t = ((o2.fX - o1.fX) * v4.fY - (o2.fY - o1.fY) * v4.fX) / v3.cross(v4);
244     SkPoint center = { o1.fX + t * v3.fX, o1.fY + t * v3.fY };
245 
246     SkRect r = { center.fX - t, center.fY - t, center.fX + t, center.fY + t };
247 
248     if (circles) {
249         circles->push_back(r);
250     }
251 
252     SkVector startV = o1 - center, endV = o2 - center;
253     startV.normalize();
254     endV.normalize();
255 
256     SkScalar startDeg = SkRadiansToDegrees(SkScalarATan2(startV.fY, startV.fX));
257     SkScalar endDeg = SkRadiansToDegrees(SkScalarATan2(endV.fY, endV.fX));
258 
259     startDeg += 360.0f;
260     startDeg = fmodf(startDeg, 360.0f);
261 
262     endDeg += 360.0f;
263     endDeg = fmodf(endDeg, 360.0f);
264 
265     if (endDeg < startDeg) {
266         endDeg += 360.0f;
267     }
268 
269     SkScalar sweepDeg = SkTAbs(endDeg - startDeg);
270     if (!takeLongWayRound) {
271         sweepDeg = sweepDeg - 360;
272     }
273 
274     path->arcTo(r, startDeg, sweepDeg, false);
275 }
276 
create_splat(const SkPoint & o,SkScalar innerRadius,SkScalar outerRadius,SkScalar ratio,int numLobes,SkTDArray<SkRect> * circles)277 static SkPath create_splat(const SkPoint& o, SkScalar innerRadius, SkScalar outerRadius,
278                            SkScalar ratio, int numLobes, SkTDArray<SkRect>* circles) {
279     if (numLobes <= 1) {
280         return SkPath();
281     }
282 
283     SkPath p;
284 
285     int numDivisions = 2 * numLobes;
286     SkScalar fullLobeDegrees = 360.0f / numLobes;
287     SkScalar outDegrees = ratio * fullLobeDegrees / (ratio + 1.0f);
288     SkScalar innerDegrees = fullLobeDegrees / (ratio + 1.0f);
289     SkMatrix outerStep, innerStep;
290     outerStep.setRotate(outDegrees);
291     innerStep.setRotate(innerDegrees);
292     SkVector curV = SkVector::Make(0.0f, 1.0f);
293 
294     if (circles) {
295         circles->push_back(SkRect::MakeLTRB(o.fX - innerRadius, o.fY - innerRadius,
296                                             o.fX + innerRadius, o.fY + innerRadius));
297     }
298 
299     p.moveTo(o.fX + innerRadius * curV.fX, o.fY + innerRadius * curV.fY);
300 
301     for (int i = 0; i < numDivisions; ++i) {
302 
303         SkVector nextV;
304         if (0 == (i % 2)) {
305             nextV = outerStep.mapVector(curV.fX, curV.fY);
306 
307             SkPoint top = SkPoint::Make(o.fX + outerRadius * curV.fX,
308                                         o.fY + outerRadius * curV.fY);
309             SkPoint nextTop = SkPoint::Make(o.fX + outerRadius * nextV.fX,
310                                             o.fY + outerRadius * nextV.fY);
311 
312             p.lineTo(top);
313             add_arc(&p, top, curV, nextTop, nextV, circles, true);
314         } else {
315             nextV = innerStep.mapVector(curV.fX, curV.fY);
316 
317             SkPoint bot = SkPoint::Make(o.fX + innerRadius * curV.fX,
318                                         o.fY + innerRadius * curV.fY);
319             SkPoint nextBot = SkPoint::Make(o.fX + innerRadius * nextV.fX,
320                                             o.fY + innerRadius * nextV.fY);
321 
322             p.lineTo(bot);
323             add_arc(&p, bot, curV, nextBot, nextV, nullptr, false);
324         }
325 
326         curV = nextV;
327     }
328 
329     p.close();
330 
331     return p;
332 }
333 
make_bitmap(SkColorType colorType,const SkPath & path,const SkTDArray<SkRect> & circles,bool opaque,bool padWithRed)334 static SkBitmap make_bitmap(SkColorType colorType, const SkPath& path,
335                             const SkTDArray<SkRect>& circles, bool opaque, bool padWithRed) {
336     const SkColor kGreen  = ToolUtils::color_to_565(SkColorSetARGB(0xFF, 178, 240, 104));
337     const SkColor kBlue   = ToolUtils::color_to_565(SkColorSetARGB(0xFF, 173, 167, 252));
338     const SkColor kYellow = ToolUtils::color_to_565(SkColorSetARGB(0xFF, 255, 221, 117));
339 
340     int widthHeight = kTileWidthHeight + (padWithRed ? 2 * kDomainPadding : 0);
341 
342     SkImageInfo ii = SkImageInfo::Make(widthHeight, widthHeight,
343                                        colorType, kPremul_SkAlphaType);
344 
345     SkBitmap bm;
346     bm.allocPixels(ii);
347 
348     std::unique_ptr<SkCanvas> canvas = SkCanvas::MakeRasterDirect(ii,
349                                                                   bm.getPixels(),
350                                                                   bm.rowBytes());
351     if (padWithRed) {
352         canvas->clear(SK_ColorRED);
353         canvas->translate(kDomainPadding, kDomainPadding);
354         canvas->clipRect(SkRect::MakeWH(kTileWidthHeight, kTileWidthHeight));
355     }
356     canvas->clear(opaque ? kGreen : SK_ColorTRANSPARENT);
357 
358     SkPaint paint;
359     paint.setAntiAlias(false); // serialize-8888 doesn't seem to work well w/ partial transparency
360     paint.setColor(kBlue);
361 
362     canvas->drawPath(path, paint);
363 
364     paint.setColor(opaque ? kYellow : SK_ColorTRANSPARENT);
365     paint.setBlendMode(SkBlendMode::kSrc);
366     for (int i = 0; i < circles.count(); ++i) {
367         SkRect r = circles[i];
368         r.inset(r.width()/4, r.height()/4);
369         canvas->drawOval(r, paint);
370     }
371 
372     return bm;
373 }
374 
convert_rgba_to_yuva_601_shared(SkColor col,uint8_t yuv[4],uint8_t off,uint8_t range)375 static void convert_rgba_to_yuva_601_shared(SkColor col, uint8_t yuv[4],
376                                             uint8_t off, uint8_t range) {
377     static const float Kr = 0.299f;
378     static const float Kb = 0.114f;
379     static const float Kg = 1.0f - Kr - Kb;
380 
381     float r = SkColorGetR(col) / 255.0f;
382     float g = SkColorGetG(col) / 255.0f;
383     float b = SkColorGetB(col) / 255.0f;
384 
385     float Ey = Kr * r + Kg * g + Kb * b;
386     float Ecb = (b - Ey) / 1.402f;
387     float Ecr = (r - Ey) / 1.772;
388     SkASSERT(Ey >= 0.0f && Ey <= 1.0f);
389     SkASSERT(Ecb >= -0.5f && Ecb <= 0.5f);
390     SkASSERT(Ecr >= -0.5f && Ecr <= 0.5f);
391 
392     yuv[0] = SkScalarRoundToInt( range * Ey + off );
393     yuv[1] = SkScalarRoundToInt( 224 * Ecb + 128 );
394     yuv[2] = SkScalarRoundToInt( 224 * Ecr + 128 );
395     yuv[3] = SkColorGetA(col);
396 }
397 
convert_rgba_to_yuva_jpeg(SkColor col,uint8_t yuv[4])398 static void convert_rgba_to_yuva_jpeg(SkColor col, uint8_t yuv[4]) {
399     // full swing from 0..255
400     convert_rgba_to_yuva_601_shared(col, yuv, 0, 255);
401 }
402 
convert_rgba_to_yuva_601(SkColor col,uint8_t yuv[4])403 static void convert_rgba_to_yuva_601(SkColor col, uint8_t yuv[4]) {
404     // partial swing from 16..235
405     convert_rgba_to_yuva_601_shared(col, yuv, 16, 219);
406 
407 }
408 
convert_rgba_to_yuva_709(SkColor col,uint8_t yuv[4])409 static void convert_rgba_to_yuva_709(SkColor col, uint8_t yuv[4]) {
410     static const float Kr = 0.2126f;
411     static const float Kb = 0.0722f;
412     static const float Kg = 1.0f - Kr - Kb;
413 
414     float r = SkColorGetR(col) / 255.0f;
415     float g = SkColorGetG(col) / 255.0f;
416     float b = SkColorGetB(col) / 255.0f;
417 
418     float Ey = Kr * r + Kg * g + Kb * b;
419     float Ecb = (b - Ey) / 1.8556f;
420     float Ecr = (r - Ey) / 1.5748;
421     SkASSERT(Ey >= 0.0f && Ey <= 1.0f);
422     SkASSERT(Ecb >= -0.5f && Ecb <= 0.5f);
423     SkASSERT(Ecr >= -0.5f && Ecr <= 0.5f);
424 
425     yuv[0] = SkScalarRoundToInt( 219 * Ey +  16 );
426     yuv[1] = SkScalarRoundToInt( 224 * Ecb + 128 );
427     yuv[2] = SkScalarRoundToInt( 224 * Ecr + 128 );
428 
429     yuv[3] = SkColorGetA(col);
430 }
431 
432 
convert_yuva_to_rgba_jpeg(uint8_t y,uint8_t u,uint8_t v,uint8_t a)433 static SkPMColor convert_yuva_to_rgba_jpeg(uint8_t y, uint8_t u, uint8_t v, uint8_t a) {
434     uint8_t r = SkScalarPin(SkScalarRoundToInt( 1.0f * y                   +  1.402f    * v  - 0.703749f * 255),
435                             0, 255);
436     uint8_t g = SkScalarPin(SkScalarRoundToInt( 1.0f * y - (0.344136f * u) - (0.714136f * v) + 0.531211f * 255),
437                             0, 255);
438     uint8_t b = SkScalarPin(SkScalarRoundToInt( 1.0f * y +  1.772f    * u                    - 0.889475f * 255),
439                             0, 255);
440 
441     SkPMColor c = SkPremultiplyARGBInline(a, b, g, r);
442     return c;
443 }
444 
convert_yuva_to_rgba_601(uint8_t y,uint8_t u,uint8_t v,uint8_t a)445 static SkPMColor convert_yuva_to_rgba_601(uint8_t y, uint8_t u, uint8_t v, uint8_t a) {
446     uint8_t r = SkScalarPin(SkScalarRoundToInt( 1.164f * y                +  1.596f * v  - 0.87075f * 255), 0, 255);
447     uint8_t g = SkScalarPin(SkScalarRoundToInt( 1.164f * y - (0.391f * u) - (0.813f * v) + 0.52925f * 255), 0, 255);
448     uint8_t b = SkScalarPin(SkScalarRoundToInt( 1.164f * y +  2.018f * u                 - 1.08175f * 255), 0, 255);
449 
450     SkPMColor c = SkPremultiplyARGBInline(a, b, g, r);
451     return c;
452 }
453 
convert_yuva_to_rgba_709(uint8_t y,uint8_t u,uint8_t v,uint8_t a)454 static SkPMColor convert_yuva_to_rgba_709(uint8_t y, uint8_t u, uint8_t v, uint8_t a) {
455     uint8_t r = SkScalarPin(SkScalarRoundToInt( 1.164f * y                + (1.793f * v) - 0.96925f * 255), 0, 255);
456     uint8_t g = SkScalarPin(SkScalarRoundToInt( 1.164f * y - (0.213f * u) - (0.533f * v) + 0.30025f * 255), 0, 255);
457     uint8_t b = SkScalarPin(SkScalarRoundToInt( 1.164f * y + (2.112f * u)                - 1.12875f * 255), 0, 255);
458 
459     SkPMColor c = SkPremultiplyARGBInline(a, b, g, r);
460     return c;
461 }
462 
extract_planes(const SkBitmap & bm,SkYUVColorSpace yuvColorSpace,PlaneData * planes)463 static void extract_planes(const SkBitmap& bm, SkYUVColorSpace yuvColorSpace, PlaneData* planes) {
464     if (kIdentity_SkYUVColorSpace == yuvColorSpace) {
465         // To test the identity color space we use JPEG YUV planes
466         yuvColorSpace = kJPEG_SkYUVColorSpace;
467     }
468 
469     SkASSERT(!(bm.width() % 2));
470     SkASSERT(!(bm.height() % 2));
471     planes->fYFull.allocPixels(SkImageInfo::Make(bm.width(), bm.height(), kGray_8_SkColorType,
472                                kUnpremul_SkAlphaType));
473     planes->fUFull.allocPixels(SkImageInfo::Make(bm.width(), bm.height(), kGray_8_SkColorType,
474                                kUnpremul_SkAlphaType));
475     planes->fVFull.allocPixels(SkImageInfo::Make(bm.width(), bm.height(), kGray_8_SkColorType,
476                                kUnpremul_SkAlphaType));
477     planes->fAFull.allocPixels(SkImageInfo::MakeA8(bm.width(), bm.height()));
478     planes->fUQuarter.allocPixels(SkImageInfo::Make(bm.width()/2, bm.height()/2,
479                                   kGray_8_SkColorType, kUnpremul_SkAlphaType));
480     planes->fVQuarter.allocPixels(SkImageInfo::Make(bm.width()/2, bm.height()/2,
481                                   kGray_8_SkColorType, kUnpremul_SkAlphaType));
482 
483     for (int y = 0; y < bm.height(); ++y) {
484         for (int x = 0; x < bm.width(); ++x) {
485             SkColor col = bm.getColor(x, y);
486 
487             uint8_t yuva[4];
488 
489             if (kJPEG_SkYUVColorSpace == yuvColorSpace) {
490                 convert_rgba_to_yuva_jpeg(col, yuva);
491             } else if (kRec601_SkYUVColorSpace == yuvColorSpace) {
492                 convert_rgba_to_yuva_601(col, yuva);
493             } else {
494                 SkASSERT(kRec709_SkYUVColorSpace == yuvColorSpace);
495                 convert_rgba_to_yuva_709(col, yuva);
496             }
497 
498             *planes->fYFull.getAddr8(x, y) = yuva[0];
499             *planes->fUFull.getAddr8(x, y) = yuva[1];
500             *planes->fVFull.getAddr8(x, y) = yuva[2];
501             *planes->fAFull.getAddr8(x, y) = yuva[3];
502         }
503     }
504 
505     for (int y = 0; y < bm.height()/2; ++y) {
506         for (int x = 0; x < bm.width()/2; ++x) {
507             uint32_t uAccum = 0, vAccum = 0;
508 
509             uAccum += *planes->fUFull.getAddr8(2*x, 2*y);
510             uAccum += *planes->fUFull.getAddr8(2*x+1, 2*y);
511             uAccum += *planes->fUFull.getAddr8(2*x, 2*y+1);
512             uAccum += *planes->fUFull.getAddr8(2*x+1, 2*y+1);
513 
514             *planes->fUQuarter.getAddr8(x, y) = uAccum / 4.0f;
515 
516             vAccum += *planes->fVFull.getAddr8(2*x, 2*y);
517             vAccum += *planes->fVFull.getAddr8(2*x+1, 2*y);
518             vAccum += *planes->fVFull.getAddr8(2*x, 2*y+1);
519             vAccum += *planes->fVFull.getAddr8(2*x+1, 2*y+1);
520 
521             *planes->fVQuarter.getAddr8(x, y) = vAccum / 4.0f;
522         }
523     }
524 }
525 
526 // Create a 2x2 downsampled SkBitmap. It is stored in an RGBA texture. It can optionally be
527 // uv (i.e., for P016, P010 and NV12) or vu (i.e., NV21).
make_quarter_2_channel(const SkBitmap & fullY,const SkBitmap & quarterU,const SkBitmap & quarterV,bool uv)528 static SkBitmap make_quarter_2_channel(const SkBitmap& fullY,
529                                        const SkBitmap& quarterU,
530                                        const SkBitmap& quarterV,
531                                        bool uv) {
532     SkBitmap result;
533 
534     // There isn't a RG color type. Approx w/ RGBA.
535     result.allocPixels(SkImageInfo::Make(fullY.width()/2,
536                                          fullY.height()/2,
537                                          kRGBA_8888_SkColorType,
538                                          kUnpremul_SkAlphaType));
539 
540     for (int y = 0; y < fullY.height()/2; ++y) {
541         for (int x = 0; x < fullY.width()/2; ++x) {
542             uint8_t u8 = *quarterU.getAddr8(x, y);
543             uint8_t v8 = *quarterV.getAddr8(x, y);
544 
545             if (uv) {
546                 // NOT premul!
547                 // U and 0 swapped to match RGBA layout
548                 *result.getAddr32(x, y) = SkColorSetARGB(0xFF, 0, v8, u8);
549             } else {
550                 // NOT premul!
551                 // V and 0 swapped to match RGBA layout
552                 *result.getAddr32(x, y) = SkColorSetARGB(0xFF, 0, u8, v8);
553             }
554         }
555     }
556 
557     return result;
558 }
559 
560 // Recombine the separate planes into some YUV format
create_YUV(const PlaneData & planes,YUVFormat yuvFormat,SkBitmap resultBMs[],SkYUVAIndex yuvaIndices[4],bool opaque)561 static void create_YUV(const PlaneData& planes, YUVFormat yuvFormat,
562                        SkBitmap resultBMs[], SkYUVAIndex yuvaIndices[4], bool opaque) {
563     int nextLayer = 0;
564 
565     switch (yuvFormat) {
566         case kY416_YUVFormat: {
567             // Although this is 16 bpp, store the data in an 8 bpp SkBitmap
568             SkBitmap yuvaFull;
569 
570             yuvaFull.allocPixels(SkImageInfo::Make(planes.fYFull.width(), planes.fYFull.height(),
571                                                    kRGBA_8888_SkColorType, kUnpremul_SkAlphaType));
572 
573             for (int y = 0; y < planes.fYFull.height(); ++y) {
574                 for (int x = 0; x < planes.fYFull.width(); ++x) {
575 
576                     uint8_t Y = *planes.fYFull.getAddr8(x, y);
577                     uint8_t U = *planes.fUFull.getAddr8(x, y);
578                     uint8_t V = *planes.fVFull.getAddr8(x, y);
579                     uint8_t A = *planes.fAFull.getAddr8(x, y);
580 
581                     // NOT premul!
582                     // U and V swapped to match RGBA layout
583                     SkColor c = SkColorSetARGB(A, U, Y, V);
584                     *yuvaFull.getAddr32(x, y) = c;
585                 }
586             }
587 
588             resultBMs[nextLayer++] = yuvaFull;
589 
590             setup_yuv_indices(yuvFormat, false, yuvaIndices);
591             break;
592         }
593         case kAYUV_YUVFormat: {
594             SkBitmap yuvaFull;
595 
596             yuvaFull.allocPixels(SkImageInfo::Make(planes.fYFull.width(), planes.fYFull.height(),
597                                                    kRGBA_8888_SkColorType, kUnpremul_SkAlphaType));
598 
599             for (int y = 0; y < planes.fYFull.height(); ++y) {
600                 for (int x = 0; x < planes.fYFull.width(); ++x) {
601 
602                     uint8_t Y = *planes.fYFull.getAddr8(x, y);
603                     uint8_t U = *planes.fUFull.getAddr8(x, y);
604                     uint8_t V = *planes.fVFull.getAddr8(x, y);
605                     uint8_t A = *planes.fAFull.getAddr8(x, y);
606 
607                     // NOT premul!
608                     // V and Y swapped to match RGBA layout
609                     SkColor c = SkColorSetARGB(A, V, U, Y);
610                     *yuvaFull.getAddr32(x, y) = c;
611                 }
612             }
613 
614             resultBMs[nextLayer++] = yuvaFull;
615 
616             setup_yuv_indices(yuvFormat, false, yuvaIndices);
617             break;
618         }
619         case kY410_YUVFormat: {
620             SkBitmap yuvaFull;
621             uint32_t Y, U, V;
622             uint8_t A;
623 
624             yuvaFull.allocPixels(SkImageInfo::Make(planes.fYFull.width(), planes.fYFull.height(),
625                                                    kRGBA_1010102_SkColorType,
626                                                    kUnpremul_SkAlphaType));
627 
628             for (int y = 0; y < planes.fYFull.height(); ++y) {
629                 for (int x = 0; x < planes.fYFull.width(); ++x) {
630 
631                     Y = SkScalarRoundToInt((*planes.fYFull.getAddr8(x, y) / 255.0f) * 1023.0f);
632                     U = SkScalarRoundToInt((*planes.fUFull.getAddr8(x, y) / 255.0f) * 1023.0f);
633                     V = SkScalarRoundToInt((*planes.fVFull.getAddr8(x, y) / 255.0f) * 1023.0f);
634                     A = SkScalarRoundToInt((*planes.fAFull.getAddr8(x, y) / 255.0f) * 3.0f);
635 
636                     // NOT premul!
637                     // AVYU but w/ V and U swapped to match RGBA layout
638                     *yuvaFull.getAddr32(x, y) = (A << 30) | (U << 20) | (Y << 10) | (V << 0);
639                 }
640             }
641 
642             resultBMs[nextLayer++] = yuvaFull;
643 
644             setup_yuv_indices(yuvFormat, false, yuvaIndices);
645             break;
646         }
647         case kP016_YUVFormat:     // fall through
648         case kP010_YUVFormat:     // fall through
649         case kNV12_YUVFormat: {
650             SkBitmap uvQuarter = make_quarter_2_channel(planes.fYFull,
651                                                         planes.fUQuarter,
652                                                         planes.fVQuarter, true);
653             resultBMs[nextLayer++] = planes.fYFull;
654             resultBMs[nextLayer++] = uvQuarter;
655 
656             setup_yuv_indices(yuvFormat, !opaque, yuvaIndices);
657             break;
658         }
659         case kNV21_YUVFormat: {
660             SkBitmap vuQuarter = make_quarter_2_channel(planes.fYFull,
661                                                         planes.fUQuarter,
662                                                         planes.fVQuarter, false);
663             resultBMs[nextLayer++] = planes.fYFull;
664             resultBMs[nextLayer++] = vuQuarter;
665 
666             setup_yuv_indices(yuvFormat, !opaque, yuvaIndices);
667             break;
668         }
669         case kI420_YUVFormat:
670             resultBMs[nextLayer++] = planes.fYFull;
671             resultBMs[nextLayer++] = planes.fUQuarter;
672             resultBMs[nextLayer++] = planes.fVQuarter;
673 
674             setup_yuv_indices(yuvFormat, !opaque, yuvaIndices);
675             break;
676         case kYV12_YUVFormat:
677             resultBMs[nextLayer++] = planes.fYFull;
678             resultBMs[nextLayer++] = planes.fVQuarter;
679             resultBMs[nextLayer++] = planes.fUQuarter;
680 
681             setup_yuv_indices(yuvFormat, !opaque, yuvaIndices);
682             break;
683     }
684 
685     if (!format_has_builtin_alpha(yuvFormat) && !opaque) {
686         resultBMs[nextLayer] = planes.fAFull;
687     }
688 }
689 
look_up(float x1,float y1,const SkBitmap & bm,SkColorChannel channel)690 static uint8_t look_up(float x1, float y1, const SkBitmap& bm, SkColorChannel channel) {
691     uint8_t result;
692 
693     SkASSERT(x1 > 0 && x1 < 1.0f);
694     SkASSERT(y1 > 0 && y1 < 1.0f);
695     int x = SkScalarFloorToInt(x1 * bm.width());
696     int y = SkScalarFloorToInt(y1 * bm.height());
697 
698     if (kAlpha_8_SkColorType == bm.colorType() || kGray_8_SkColorType == bm.colorType()) {
699         SkASSERT(SkColorChannel::kA == channel || SkColorChannel::kR == channel);
700         result = *bm.getAddr8(x, y);
701     } else if (kRGBA_8888_SkColorType == bm.colorType()) {
702         SkColor c = *bm.getAddr32(x, y);
703 
704         switch (channel) {
705             case SkColorChannel::kR:
706                 result = SkColorGetB(c);
707                 break;
708             case SkColorChannel::kG:
709                 result = SkColorGetG(c);
710                 break;
711             case SkColorChannel::kB:
712                 result = SkColorGetR(c);
713                 break;
714             case SkColorChannel::kA:
715                 result = SkColorGetA(c);
716                 break;
717         }
718     } else {
719         SkASSERT(kRGBA_1010102_SkColorType == bm.colorType());
720 
721         SkColor c = *bm.getAddr32(x, y);
722 
723         switch (channel) {
724             case SkColorChannel::kR:
725                 result = SkScalarRoundToInt(((c >>  0) & 0x3ff) * (255.0f/1023.0f));
726                 break;
727             case SkColorChannel::kG:
728                 result = SkScalarRoundToInt(((c >> 10) & 0x3ff) * (255.0f/1023.0f));
729                 break;
730             case SkColorChannel::kB:
731                 result = SkScalarRoundToInt(((c >> 20) & 0x3ff) * (255.0f/1023.0f));
732                 break;
733             case SkColorChannel::kA:
734                 result = SkScalarRoundToInt(((c >> 30) & 0x3) * (255.0f/3.0f));
735                 break;
736         }
737     }
738 
739     return result;
740 }
741 
742 class YUVGenerator : public SkImageGenerator {
743 public:
YUVGenerator(const SkImageInfo & ii,SkYUVColorSpace yuvColorSpace,SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],SkBitmap bitmaps[SkYUVASizeInfo::kMaxCount])744     YUVGenerator(const SkImageInfo& ii,
745                  SkYUVColorSpace yuvColorSpace,
746                  SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
747                  SkBitmap bitmaps[SkYUVASizeInfo::kMaxCount])
748             : SkImageGenerator(ii)
749             , fYUVColorSpace(yuvColorSpace)
750             , fAllA8(true) {
751         memcpy(fYUVAIndices, yuvaIndices, sizeof(fYUVAIndices));
752 
753         SkAssertResult(SkYUVAIndex::AreValidIndices(fYUVAIndices, &fNumBitmaps));
754         SkASSERT(fNumBitmaps > 0 && fNumBitmaps <= SkYUVASizeInfo::kMaxCount);
755 
756         for (int i = 0; i < fNumBitmaps; ++i) {
757             fYUVBitmaps[i] = bitmaps[i];
758             if (kAlpha_8_SkColorType != fYUVBitmaps[i].colorType()) {
759                 fAllA8 = false;
760             }
761         }
762     }
763 
764 protected:
onGetPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,const Options &)765     bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
766                      const Options&) override {
767 
768         if (kUnknown_SkColorType == fFlattened.colorType()) {
769             fFlattened.allocPixels(info);
770             SkASSERT(kPremul_SkAlphaType == info.alphaType());
771 
772             for (int y = 0; y < info.height(); ++y) {
773                 for (int x = 0; x < info.width(); ++x) {
774 
775                     float x1 = (x + 0.5f) / info.width();
776                     float y1 = (y + 0.5f) / info.height();
777 
778                     uint8_t Y = look_up(x1, y1,
779                                         fYUVBitmaps[fYUVAIndices[0].fIndex],
780                                         fYUVAIndices[0].fChannel);
781 
782                     uint8_t U = look_up(x1, y1,
783                                         fYUVBitmaps[fYUVAIndices[1].fIndex],
784                                         fYUVAIndices[1].fChannel);
785 
786 
787                     uint8_t V = look_up(x1, y1,
788                                         fYUVBitmaps[fYUVAIndices[2].fIndex],
789                                         fYUVAIndices[2].fChannel);
790 
791                     uint8_t A = 255;
792                     if (fYUVAIndices[3].fIndex >= 0) {
793                         A = look_up(x1, y1,
794                                     fYUVBitmaps[fYUVAIndices[3].fIndex],
795                                     fYUVAIndices[3].fChannel);
796                     }
797 
798                     // Making premul here.
799                     switch (fYUVColorSpace) {
800                         case kJPEG_SkYUVColorSpace:
801                             *fFlattened.getAddr32(x, y) = convert_yuva_to_rgba_jpeg(Y, U, V, A);
802                             break;
803                         case kRec601_SkYUVColorSpace:
804                             *fFlattened.getAddr32(x, y) = convert_yuva_to_rgba_601(Y, U, V, A);
805                             break;
806                         case kRec709_SkYUVColorSpace:
807                             *fFlattened.getAddr32(x, y) = convert_yuva_to_rgba_709(Y, U, V, A);
808                             break;
809                         case kIdentity_SkYUVColorSpace:
810                             *fFlattened.getAddr32(x, y) = SkPremultiplyARGBInline(A, V, U, Y);
811                             break;
812                     }
813                 }
814             }
815         }
816 
817         return fFlattened.readPixels(info, pixels, rowBytes, 0, 0);
818     }
819 
onQueryYUVA8(SkYUVASizeInfo * size,SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],SkYUVColorSpace * yuvColorSpace) const820     bool onQueryYUVA8(SkYUVASizeInfo* size,
821                       SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
822                       SkYUVColorSpace* yuvColorSpace) const override {
823 
824         // The onQueryYUVA8/onGetYUVA8Planes can only handle A8 planes
825         if (!fAllA8) {
826             return false;
827         }
828 
829         memcpy(yuvaIndices, fYUVAIndices, sizeof(fYUVAIndices));
830         *yuvColorSpace = fYUVColorSpace;
831 
832         int i = 0;
833         for ( ; i < fNumBitmaps; ++i) {
834             size->fSizes[i].fWidth = fYUVBitmaps[i].width();
835             size->fSizes[i].fHeight = fYUVBitmaps[i].height();
836             size->fWidthBytes[i] = fYUVBitmaps[i].rowBytes();
837         }
838         for ( ; i < SkYUVASizeInfo::kMaxCount; ++i) {
839             size->fSizes[i].fWidth = 0;
840             size->fSizes[i].fHeight = 0;
841             size->fWidthBytes[i] = 0;
842         }
843 
844         return true;
845     }
846 
onGetYUVA8Planes(const SkYUVASizeInfo &,const SkYUVAIndex[SkYUVAIndex::kIndexCount],void * planes[SkYUVASizeInfo::kMaxCount])847     bool onGetYUVA8Planes(const SkYUVASizeInfo&, const SkYUVAIndex[SkYUVAIndex::kIndexCount],
848                           void* planes[SkYUVASizeInfo::kMaxCount]) override {
849         SkASSERT(fAllA8);
850         for (int i = 0; i < fNumBitmaps; ++i) {
851             planes[i] = fYUVBitmaps[i].getPixels();
852         }
853         return true;
854     }
855 
856 private:
857     SkYUVColorSpace fYUVColorSpace;
858     SkYUVAIndex     fYUVAIndices[SkYUVAIndex::kIndexCount];
859     int             fNumBitmaps;
860     SkBitmap        fYUVBitmaps[SkYUVASizeInfo::kMaxCount];
861     SkBitmap        fFlattened;
862     bool            fAllA8;     // are all the SkBitmaps in "fYUVBitmaps" A8?
863 
864 };
865 
make_yuv_gen_image(const SkImageInfo & ii,SkYUVColorSpace yuvColorSpace,SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],SkBitmap bitmaps[])866 static sk_sp<SkImage> make_yuv_gen_image(const SkImageInfo& ii,
867                                          SkYUVColorSpace yuvColorSpace,
868                                          SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
869                                          SkBitmap bitmaps[]) {
870     std::unique_ptr<SkImageGenerator> gen(new YUVGenerator(ii, yuvColorSpace,
871                                                            yuvaIndices, bitmaps));
872 
873     return SkImage::MakeFromGenerator(std::move(gen));
874 }
875 
draw_col_label(SkCanvas * canvas,int x,int yuvColorSpace,bool opaque)876 static void draw_col_label(SkCanvas* canvas, int x, int yuvColorSpace, bool opaque) {
877     static const char* kYUVColorSpaceNames[] = { "JPEG", "601", "709", "Identity" };
878     GR_STATIC_ASSERT(SK_ARRAY_COUNT(kYUVColorSpaceNames) == kLastEnum_SkYUVColorSpace+1);
879 
880     SkPaint paint;
881     SkFont  font(ToolUtils::create_portable_typeface(nullptr, SkFontStyle::Bold()), 16);
882     font.setEdging(SkFont::Edging::kAlias);
883 
884     SkRect textRect;
885     SkString colLabel;
886 
887     colLabel.printf("%s", kYUVColorSpaceNames[yuvColorSpace]);
888     font.measureText(colLabel.c_str(), colLabel.size(), SkTextEncoding::kUTF8, &textRect);
889     int y = textRect.height();
890 
891     SkTextUtils::DrawString(canvas, colLabel.c_str(), x, y, font, paint, SkTextUtils::kCenter_Align);
892 
893     colLabel.printf("%s", opaque ? "Opaque" : "Transparent");
894 
895     font.measureText(colLabel.c_str(), colLabel.size(), SkTextEncoding::kUTF8, &textRect);
896     y += textRect.height();
897 
898     SkTextUtils::DrawString(canvas, colLabel.c_str(), x, y, font, paint, SkTextUtils::kCenter_Align);
899 }
900 
draw_row_label(SkCanvas * canvas,int y,int yuvFormat)901 static void draw_row_label(SkCanvas* canvas, int y, int yuvFormat) {
902     static const char* kYUVFormatNames[] = {
903         "P016", "P010", "Y416", "AYUV", "Y410", "NV12", "NV21", "I420", "YV12"
904     };
905     GR_STATIC_ASSERT(SK_ARRAY_COUNT(kYUVFormatNames) == kLast_YUVFormat+1);
906 
907     SkPaint paint;
908     SkFont  font(ToolUtils::create_portable_typeface(nullptr, SkFontStyle::Bold()), 16);
909     font.setEdging(SkFont::Edging::kAlias);
910 
911     SkRect textRect;
912     SkString rowLabel;
913 
914     rowLabel.printf("%s", kYUVFormatNames[yuvFormat]);
915     font.measureText(rowLabel.c_str(), rowLabel.size(), SkTextEncoding::kUTF8, &textRect);
916     y += kTileWidthHeight/2 + textRect.height()/2;
917 
918     canvas->drawString(rowLabel, 0, y, font, paint);
919 }
920 
make_RG_88(const GrCaps * caps,const SkBitmap & bm,YUVFormat yuvFormat,SkAutoTMalloc<uint8_t> * pixels,GrBackendFormat * format,size_t * rowBytes)921 static void make_RG_88(const GrCaps* caps,
922                        const SkBitmap& bm, YUVFormat yuvFormat,
923                        SkAutoTMalloc<uint8_t>* pixels,
924                        GrBackendFormat* format, size_t* rowBytes) {
925     SkASSERT(kNV12_YUVFormat == yuvFormat || kNV21_YUVFormat == yuvFormat);
926     SkASSERT(kRGBA_8888_SkColorType == bm.colorType());     // uv stored in rg
927 
928     *rowBytes = bm.width() * 2 * sizeof(uint8_t);
929     pixels->reset(*rowBytes * bm.height());
930     uint8_t* currPixel = pixels->get();
931     for (int y = 0; y < bm.height(); ++y) {
932         for (int x = 0; x < bm.width(); ++x) {
933             SkColor color = bm.getColor(x, y);
934             uint8_t u8 = SkColorGetR(color);
935             uint8_t v8 = SkColorGetG(color);
936 
937             currPixel[0] = u8;
938             currPixel[1] = v8;
939             currPixel += 2;
940         }
941     }
942     *format = caps->getDefaultBackendFormat(GrColorType::kRG_88, GrRenderable::kNo);
943 }
944 
make_RG_1616(const GrCaps * caps,const SkBitmap & bm,YUVFormat yuvFormat,SkAutoTMalloc<uint8_t> * pixels,GrBackendFormat * format,size_t * rowBytes)945 static void make_RG_1616(const GrCaps* caps,
946                          const SkBitmap& bm, YUVFormat yuvFormat,
947                          SkAutoTMalloc<uint8_t>* pixels,
948                          GrBackendFormat* format, size_t* rowBytes) {
949     SkASSERT(kP016_YUVFormat == yuvFormat || kP010_YUVFormat == yuvFormat);
950     SkASSERT(kRGBA_8888_SkColorType == bm.colorType());     // uv stored in rg
951 
952     uint16_t u16, v16;
953     *rowBytes = bm.width() * 2 * sizeof(uint16_t);
954     pixels->reset(*rowBytes * bm.height());
955     uint16_t* currPixel = (uint16_t*) pixels->get();
956     for (int y = 0; y < bm.height(); ++y) {
957         for (int x = 0; x < bm.width(); ++x) {
958             SkColor color = bm.getColor(x, y);
959 
960             if (kP016_YUVFormat == yuvFormat) {
961                 u16 = SkScalarRoundToInt((SkColorGetR(color) / 255.0f) * 65535.0f);
962                 v16 = SkScalarRoundToInt((SkColorGetG(color) / 255.0f) * 65535.0f);
963             } else {
964                 u16 = SkScalarRoundToInt((SkColorGetR(color) / 255.0f) * 1023.0f);
965                 v16 = SkScalarRoundToInt((SkColorGetG(color) / 255.0f) * 1023.0f);
966                 u16 <<= 6;
967                 v16 <<= 6;
968             }
969 
970             currPixel[0] = u16;
971             currPixel[1] = v16;
972             currPixel += 2;
973         }
974     }
975 
976     *format = caps->getDefaultBackendFormat(GrColorType::kRG_1616, GrRenderable::kNo);
977 }
978 
make_RGBA_16(const GrCaps * caps,const SkBitmap & bm,YUVFormat yuvFormat,SkAutoTMalloc<uint8_t> * pixels,GrBackendFormat * format,size_t * rowBytes)979 static void make_RGBA_16(const GrCaps* caps,
980                          const SkBitmap& bm,
981                          YUVFormat yuvFormat,
982                          SkAutoTMalloc<uint8_t>* pixels,
983                          GrBackendFormat* format,
984                          size_t* rowBytes) {
985     SkASSERT(kY416_YUVFormat == yuvFormat);
986     SkASSERT(kRGBA_8888_SkColorType == bm.colorType());
987 
988     uint16_t y16, u16, v16, a16;
989     *rowBytes = 4 * sizeof(uint16_t) * bm.width();
990     pixels->reset(*rowBytes * bm.height());
991     uint16_t* currPixel = (uint16_t*) pixels->get();
992     for (int y = 0; y < bm.height(); ++y) {
993         for (int x = 0; x < bm.width(); ++x) {
994             SkColor color = bm.getColor(x, y);
995 
996             y16 = SkScalarRoundToInt((SkColorGetR(color) / 255.0f) * 65535.0f);
997             u16 = SkScalarRoundToInt((SkColorGetG(color) / 255.0f) * 65535.0f);
998             v16 = SkScalarRoundToInt((SkColorGetB(color) / 255.0f) * 65535.0f);
999             a16 = SkScalarRoundToInt((SkColorGetA(color) / 255.0f) * 65535.0f);
1000 
1001             currPixel[0] = y16;
1002             currPixel[1] = u16;
1003             currPixel[2] = v16;
1004             currPixel[3] = a16;
1005             currPixel += 4;
1006         }
1007     }
1008 
1009     *format = caps->getDefaultBackendFormat(GrColorType::kRGBA_16161616, GrRenderable::kNo);
1010     return;
1011 }
1012 
make_R_16(const GrCaps * caps,const SkBitmap & bm,YUVFormat yuvFormat,SkAutoTMalloc<uint8_t> * pixels,GrBackendFormat * format,size_t * rowBytes)1013 static void make_R_16(const GrCaps* caps,
1014                       const SkBitmap& bm,
1015                       YUVFormat yuvFormat,
1016                       SkAutoTMalloc<uint8_t>* pixels,
1017                       GrBackendFormat* format,
1018                       size_t* rowBytes) {
1019     SkASSERT(kP016_YUVFormat == yuvFormat || kP010_YUVFormat == yuvFormat);
1020     SkASSERT(kGray_8_SkColorType == bm.colorType() || kAlpha_8_SkColorType == bm.colorType());
1021 
1022     uint16_t y16;
1023     *rowBytes = sizeof(uint16_t) * bm.width();
1024     pixels->reset(*rowBytes * bm.height());
1025     uint16_t* currPixel = (uint16_t*) pixels->get();
1026     for (int y = 0; y < bm.height(); ++y) {
1027         for (int x = 0; x < bm.width(); ++x) {
1028             uint8_t y8 = *bm.getAddr8(x, y);
1029 
1030             if (kP016_YUVFormat == yuvFormat) {
1031                 y16 = SkScalarRoundToInt((y8 / 255.0f) * 65535.0f);
1032             } else {
1033                 y16 = SkScalarRoundToInt((y8 / 255.0f) * 1023.0f);
1034                 y16 <<= 6;
1035             }
1036 
1037             currPixel[0] = y16;
1038             currPixel += 1;
1039         }
1040     }
1041 
1042     *format = caps->getDefaultBackendFormat(GrColorType::kR_16, GrRenderable::kNo);
1043 }
1044 
create_yuva_texture(GrContext * context,const SkBitmap & bm,SkYUVAIndex yuvaIndices[4],int texIndex,YUVFormat yuvFormat)1045 static GrBackendTexture create_yuva_texture(GrContext* context, const SkBitmap& bm,
1046                                             SkYUVAIndex yuvaIndices[4], int texIndex,
1047                                             YUVFormat yuvFormat) {
1048     SkASSERT(texIndex >= 0 && texIndex <= 3);
1049     int channelCount = 0;
1050     for (int i = 0; i < SkYUVAIndex::kIndexCount; ++i) {
1051         if (yuvaIndices[i].fIndex == texIndex) {
1052             ++channelCount;
1053         }
1054     }
1055 
1056     GrBackendTexture tex;
1057 
1058     if (format_uses_16_bpp(yuvFormat) || 2 == channelCount) {
1059         // Due to the limitations of SkPixmap these cases need to be handled separately
1060         const GrCaps* caps = context->priv().caps();
1061         GrGpu* gpu = context->priv().getGpu();
1062 
1063         SkAutoTMalloc<uint8_t> pixels;
1064         GrBackendFormat format;
1065         size_t rowBytes;
1066 
1067         if (2 == channelCount) {
1068             if (format_uses_16_bpp(yuvFormat)) {
1069                 make_RG_1616(caps, bm, yuvFormat, &pixels, &format, &rowBytes);
1070             } else {
1071                 make_RG_88(caps, bm, yuvFormat, &pixels, &format, &rowBytes);
1072             }
1073         } else {
1074             if (kRGBA_8888_SkColorType == bm.colorType()) {
1075                 make_RGBA_16(caps, bm, yuvFormat, &pixels, &format, &rowBytes);
1076             } else {
1077                 make_R_16(caps, bm, yuvFormat, &pixels, &format, &rowBytes);
1078             }
1079         }
1080 
1081         // TODO: SkColorType needs to be expanded to allow this to be done via the
1082         // GrContext::createBackendTexture API
1083         tex = gpu->createBackendTexture(bm.width(), bm.height(), format,
1084                                         GrMipMapped::kNo, GrRenderable::kNo,
1085                                         pixels, rowBytes, nullptr, GrProtected::kNo);
1086     } else {
1087         tex = context->priv().createBackendTexture(&bm.pixmap(), 1,
1088                                                    GrRenderable::kNo, GrProtected::kNo);
1089     }
1090 
1091     return tex;
1092 }
1093 
yuv_to_rgb_colorfilter()1094 static sk_sp<SkColorFilter> yuv_to_rgb_colorfilter() {
1095     static const float kJPEGConversionMatrix[20] = {
1096         1.0f,  0.0f,       1.402f,    0.0f, -180.0f/255,
1097         1.0f, -0.344136f, -0.714136f, 0.0f,  136.0f/255,
1098         1.0f,  1.772f,     0.0f,      0.0f, -227.6f/255,
1099         0.0f,  0.0f,       0.0f,      1.0f,    0.0f
1100     };
1101 
1102     return SkColorFilters::Matrix(kJPEGConversionMatrix);
1103 }
1104 
1105 namespace skiagm {
1106 
1107 // This GM creates an opaque and transparent bitmap, extracts the planes and then recombines
1108 // them into various YUV formats. It then renders the results in the grid:
1109 //
1110 //                 JPEG                  601                   709                Identity
1111 //        Transparent  Opaque   Transparent  Opaque   Transparent  Opaque   Transparent Opaque
1112 // originals
1113 // P016
1114 // P010
1115 // Y416
1116 // AYUV
1117 // Y410
1118 // NV12
1119 // NV21
1120 // I420
1121 // YV12
1122 class WackyYUVFormatsGM : public GM {
1123 public:
WackyYUVFormatsGM(bool useTargetColorSpace,bool useDomain)1124     WackyYUVFormatsGM(bool useTargetColorSpace, bool useDomain)
1125             : fUseTargetColorSpace(useTargetColorSpace)
1126             , fUseDomain(useDomain) {
1127         this->setBGColor(0xFFCCCCCC);
1128     }
1129 
1130 protected:
1131 
onShortName()1132     SkString onShortName() override {
1133         SkString name("wacky_yuv_formats");
1134         if (fUseTargetColorSpace) {
1135             name += "_cs";
1136         }
1137         if (fUseDomain) {
1138             name += "_domain";
1139         }
1140 
1141         return name;
1142     }
1143 
onISize()1144     SkISize onISize() override {
1145         int numCols = 2 * (kLastEnum_SkYUVColorSpace + 1); // opacity x color-space
1146         int numRows = 1 + (kLast_YUVFormat + 1);  // origin + # yuv formats
1147         int wh = SkScalarCeilToInt(kTileWidthHeight * (fUseDomain ? 1.5f : 1.f));
1148         return SkISize::Make(kLabelWidth  + numCols * (wh + kPad),
1149                              kLabelHeight + numRows * (wh + kPad));
1150     }
1151 
onOnceBeforeDraw()1152     void onOnceBeforeDraw() override {
1153         SkPoint origin = { kTileWidthHeight/2.0f, kTileWidthHeight/2.0f };
1154         float outerRadius = kTileWidthHeight/2.0f - 20.0f;
1155         float innerRadius = 20.0f;
1156 
1157         {
1158             // transparent
1159             SkTDArray<SkRect> circles;
1160             SkPath path = create_splat(origin, innerRadius, outerRadius, 1.0f, 5, &circles);
1161             fOriginalBMs[0] = make_bitmap(kRGBA_8888_SkColorType, path, circles, false, fUseDomain);
1162         }
1163 
1164         {
1165             // opaque
1166             SkTDArray<SkRect> circles;
1167             SkPath path = create_splat(origin, innerRadius, outerRadius, 1.0f, 7, &circles);
1168             fOriginalBMs[1] = make_bitmap(kRGBA_8888_SkColorType, path, circles, true, fUseDomain);
1169         }
1170 
1171         if (fUseTargetColorSpace) {
1172             fTargetColorSpace = SkColorSpace::MakeSRGB()->makeColorSpin();
1173         }
1174     }
1175 
createImages(GrContext * context)1176     void createImages(GrContext* context) {
1177         int counter = 0;
1178         for (bool opaque : { false, true }) {
1179             for (int cs = kJPEG_SkYUVColorSpace; cs <= kLastEnum_SkYUVColorSpace; ++cs) {
1180                 PlaneData planes;
1181                 extract_planes(fOriginalBMs[opaque], (SkYUVColorSpace) cs, &planes);
1182 
1183                 for (int format = kP016_YUVFormat; format <= kLast_YUVFormat; ++format) {
1184                     SkBitmap resultBMs[4];
1185                     SkYUVAIndex yuvaIndices[4];
1186 
1187                     create_YUV(planes, (YUVFormat) format, resultBMs, yuvaIndices, opaque);
1188 
1189                     int numTextures;
1190                     if (!SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures)) {
1191                         continue;
1192                     }
1193 
1194                     if (context) {
1195                         if (context->abandoned()) {
1196                             return;
1197                         }
1198 
1199                         GrBackendTexture yuvaTextures[4];
1200                         SkPixmap yuvaPixmaps[4];
1201 
1202                         for (int i = 0; i < numTextures; ++i) {
1203                             yuvaTextures[i] = create_yuva_texture(context, resultBMs[i],
1204                                                                   yuvaIndices, i,
1205                                                                   (YUVFormat) format);
1206                             if (yuvaTextures[i].isValid()) {
1207                                 fBackendTextures.push_back(yuvaTextures[i]);
1208                             }
1209                             yuvaPixmaps[i] = resultBMs[i].pixmap();
1210                         }
1211 
1212                         int counterMod = counter % 3;
1213                         if (format_cant_be_represented_with_pixmaps((YUVFormat) format) &&
1214                             counterMod == 2) {
1215                             // These formats don't work as pixmaps
1216                             counterMod = 1;
1217                         } else if (fUseDomain && counterMod == 0) {
1218                             // Copies flatten to RGB when they copy the YUVA data, which doesn't
1219                             // know about the intended domain and the domain padding bleeds in
1220                             counterMod = 1;
1221                         }
1222                         switch (counterMod) {
1223                         case 0:
1224                             fImages[opaque][cs][format] = SkImage::MakeFromYUVATexturesCopy(
1225                                 context,
1226                                 (SkYUVColorSpace)cs,
1227                                 yuvaTextures,
1228                                 yuvaIndices,
1229                                 { fOriginalBMs[opaque].width(), fOriginalBMs[opaque].height() },
1230                                 kTopLeft_GrSurfaceOrigin);
1231                             break;
1232                         case 1:
1233                             fImages[opaque][cs][format] = SkImage::MakeFromYUVATextures(
1234                                 context,
1235                                 (SkYUVColorSpace)cs,
1236                                 yuvaTextures,
1237                                 yuvaIndices,
1238                                 { fOriginalBMs[opaque].width(), fOriginalBMs[opaque].height() },
1239                                 kTopLeft_GrSurfaceOrigin);
1240                             break;
1241                         case 2:
1242                         default:
1243                             fImages[opaque][cs][format] = SkImage::MakeFromYUVAPixmaps(
1244                                 context,
1245                                 (SkYUVColorSpace)cs,
1246                                 yuvaPixmaps,
1247                                 yuvaIndices,
1248                                 { fOriginalBMs[opaque].width(), fOriginalBMs[opaque].height() },
1249                                 kTopLeft_GrSurfaceOrigin, true);
1250                             break;
1251                         }
1252                         ++counter;
1253                     } else {
1254                         fImages[opaque][cs][format] = make_yuv_gen_image(
1255                                                                 fOriginalBMs[opaque].info(),
1256                                                                 (SkYUVColorSpace) cs,
1257                                                                 yuvaIndices,
1258                                                                 resultBMs);
1259                     }
1260                 }
1261             }
1262         }
1263     }
1264 
onDraw(SkCanvas * canvas)1265     void onDraw(SkCanvas* canvas) override {
1266         this->createImages(canvas->getGrContext());
1267 
1268         SkRect srcRect = SkRect::MakeWH(fOriginalBMs[0].width(), fOriginalBMs[0].height());
1269         SkRect dstRect = SkRect::MakeXYWH(kLabelWidth, 0.f, srcRect.width(), srcRect.height());
1270 
1271         SkCanvas::SrcRectConstraint constraint = SkCanvas::kFast_SrcRectConstraint;
1272         if (fUseDomain) {
1273             srcRect.inset(kDomainPadding, kDomainPadding);
1274             // Draw a larger rectangle to ensure bilerp filtering would normally read outside the
1275             // srcRect and hit the red pixels, if strict constraint weren't used.
1276             dstRect.fRight = kLabelWidth + 1.5f * srcRect.width();
1277             dstRect.fBottom = 1.5f * srcRect.height();
1278             constraint = SkCanvas::kStrict_SrcRectConstraint;
1279         }
1280 
1281         for (int cs = kJPEG_SkYUVColorSpace; cs <= kLastEnum_SkYUVColorSpace; ++cs) {
1282             SkPaint paint;
1283             paint.setFilterQuality(kLow_SkFilterQuality);
1284             if (kIdentity_SkYUVColorSpace == cs) {
1285                 // The identity color space needs post processing to appear correctly
1286                 paint.setColorFilter(yuv_to_rgb_colorfilter());
1287             }
1288 
1289             for (int opaque : { 0, 1 }) {
1290                 dstRect.offsetTo(dstRect.fLeft, kLabelHeight);
1291 
1292                 draw_col_label(canvas, dstRect.fLeft + dstRect.height() / 2, cs, opaque);
1293 
1294                 canvas->drawBitmapRect(fOriginalBMs[opaque], srcRect, dstRect, nullptr, constraint);
1295                 dstRect.offset(0.f, dstRect.height() + kPad);
1296 
1297                 for (int format = kP016_YUVFormat; format <= kLast_YUVFormat; ++format) {
1298                     draw_row_label(canvas, dstRect.fTop, format);
1299                     if (fUseTargetColorSpace && fImages[opaque][cs][format]) {
1300                         // Making a CS-specific version of a kIdentity_SkYUVColorSpace YUV image
1301                         // doesn't make a whole lot of sense. The colorSpace conversion will
1302                         // operate on the YUV components rather than the RGB components.
1303                         sk_sp<SkImage> csImage =
1304                             fImages[opaque][cs][format]->makeColorSpace(fTargetColorSpace);
1305                         canvas->drawImageRect(csImage, srcRect, dstRect, &paint, constraint);
1306                     } else {
1307                         canvas->drawImageRect(fImages[opaque][cs][format], srcRect, dstRect, &paint,
1308                                               constraint);
1309                     }
1310                     dstRect.offset(0.f, dstRect.height() + kPad);
1311                 }
1312 
1313                 dstRect.offset(dstRect.width() + kPad, 0.f);
1314             }
1315         }
1316         if (auto context = canvas->getGrContext()) {
1317             if (!context->abandoned()) {
1318                 context->flush();
1319                 GrGpu* gpu = context->priv().getGpu();
1320                 SkASSERT(gpu);
1321                 gpu->testingOnly_flushGpuAndSync();
1322                 for (const auto& tex : fBackendTextures) {
1323                     context->deleteBackendTexture(tex);
1324                 }
1325                 fBackendTextures.reset();
1326             }
1327         }
1328         SkASSERT(!fBackendTextures.count());
1329     }
1330 
1331 private:
1332     SkBitmap                   fOriginalBMs[2];
1333     sk_sp<SkImage>             fImages[2][kLastEnum_SkYUVColorSpace + 1][kLast_YUVFormat + 1];
1334     SkTArray<GrBackendTexture> fBackendTextures;
1335     bool                       fUseTargetColorSpace;
1336     bool                       fUseDomain;
1337     sk_sp<SkColorSpace>        fTargetColorSpace;
1338 
1339     typedef GM INHERITED;
1340 };
1341 
1342 //////////////////////////////////////////////////////////////////////////////
1343 
1344 DEF_GM(return new WackyYUVFormatsGM(/* cs */ false, /* domain */ false);)
1345 DEF_GM(return new WackyYUVFormatsGM(/* cs */ true,  /* domain */ false);)
1346 DEF_GM(return new WackyYUVFormatsGM(/* cs */ false, /* domain */ true);)
1347 
1348 class YUVMakeColorSpaceGM : public GpuGM {
1349 public:
YUVMakeColorSpaceGM()1350     YUVMakeColorSpaceGM() {
1351         this->setBGColor(0xFFCCCCCC);
1352     }
1353 
1354 protected:
onShortName()1355     SkString onShortName() override {
1356         return SkString("yuv_make_color_space");
1357     }
1358 
onISize()1359     SkISize onISize() override {
1360         int numCols = 4; // (transparent, opaque) x (untagged, tagged)
1361         int numRows = 5; // original, YUV, subset, readPixels, makeNonTextureImage
1362         return SkISize::Make(numCols * (kTileWidthHeight + kPad) + kPad,
1363                              numRows * (kTileWidthHeight + kPad) + kPad);
1364     }
1365 
onOnceBeforeDraw()1366     void onOnceBeforeDraw() override {
1367         SkPoint origin = { kTileWidthHeight/2.0f, kTileWidthHeight/2.0f };
1368         float outerRadius = kTileWidthHeight/2.0f - 20.0f;
1369         float innerRadius = 20.0f;
1370 
1371         {
1372             // transparent
1373             SkTDArray<SkRect> circles;
1374             SkPath path = create_splat(origin, innerRadius, outerRadius, 1.0f, 5, &circles);
1375             fOriginalBMs[0] = make_bitmap(kN32_SkColorType, path, circles, false, false);
1376         }
1377 
1378         {
1379             // opaque
1380             SkTDArray<SkRect> circles;
1381             SkPath path = create_splat(origin, innerRadius, outerRadius, 1.0f, 7, &circles);
1382             fOriginalBMs[1] = make_bitmap(kN32_SkColorType, path, circles, true, false);
1383         }
1384 
1385         fTargetColorSpace = SkColorSpace::MakeSRGB()->makeColorSpin();
1386     }
1387 
createImages(GrContext * context)1388     void createImages(GrContext* context) {
1389         for (bool opaque : { false, true }) {
1390             PlaneData planes;
1391             extract_planes(fOriginalBMs[opaque], kJPEG_SkYUVColorSpace, &planes);
1392 
1393             SkBitmap resultBMs[4];
1394             SkYUVAIndex yuvaIndices[4];
1395 
1396             create_YUV(planes, kAYUV_YUVFormat, resultBMs, yuvaIndices, opaque);
1397 
1398             int numTextures;
1399             if (!SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures)) {
1400                 continue;
1401             }
1402 
1403             GrBackendTexture yuvaTextures[4];
1404             for (int i = 0; i < numTextures; ++i) {
1405                 yuvaTextures[i] = create_yuva_texture(context, resultBMs[i], yuvaIndices, i,
1406                                                       kAYUV_YUVFormat);
1407                 if (yuvaTextures[i].isValid()) {
1408                     fBackendTextures.push_back(yuvaTextures[i]);
1409                 }
1410             }
1411 
1412             fImages[opaque][0] = SkImage::MakeFromYUVATextures(
1413                     context,
1414                     kJPEG_SkYUVColorSpace,
1415                     yuvaTextures,
1416                     yuvaIndices,
1417                     { fOriginalBMs[opaque].width(), fOriginalBMs[opaque].height() },
1418                     kTopLeft_GrSurfaceOrigin);
1419             fImages[opaque][1] = SkImage::MakeFromYUVATextures(
1420                     context,
1421                     kJPEG_SkYUVColorSpace,
1422                     yuvaTextures,
1423                     yuvaIndices,
1424                     { fOriginalBMs[opaque].width(), fOriginalBMs[opaque].height() },
1425                     kTopLeft_GrSurfaceOrigin,
1426                     SkColorSpace::MakeSRGB());
1427         }
1428     }
1429 
onDraw(GrContext * context,GrRenderTargetContext *,SkCanvas * canvas)1430     void onDraw(GrContext* context, GrRenderTargetContext*, SkCanvas* canvas) override {
1431         this->createImages(context);
1432 
1433         int x = kPad;
1434         for (int tagged : { 0, 1 }) {
1435             for (int opaque : { 0, 1 }) {
1436                 int y = kPad;
1437 
1438                 auto raster = SkImage::MakeFromBitmap(fOriginalBMs[opaque])
1439                     ->makeColorSpace(fTargetColorSpace);
1440                 canvas->drawImage(raster, x, y);
1441                 y += kTileWidthHeight + kPad;
1442 
1443                 auto yuv = fImages[opaque][tagged]->makeColorSpace(fTargetColorSpace);
1444                 SkASSERT(SkColorSpace::Equals(yuv->colorSpace(), fTargetColorSpace.get()));
1445                 canvas->drawImage(yuv, x, y);
1446                 y += kTileWidthHeight + kPad;
1447 
1448                 auto subset = yuv->makeSubset(SkIRect::MakeWH(kTileWidthHeight / 2,
1449                                                               kTileWidthHeight / 2));
1450                 canvas->drawImage(subset, x, y);
1451                 y += kTileWidthHeight + kPad;
1452 
1453                 auto nonTexture = yuv->makeNonTextureImage();
1454                 canvas->drawImage(nonTexture, x, y);
1455                 y += kTileWidthHeight + kPad;
1456 
1457                 SkBitmap readBack;
1458                 readBack.allocPixels(yuv->imageInfo());
1459                 yuv->readPixels(readBack.pixmap(), 0, 0);
1460                 canvas->drawBitmap(readBack, x, y);
1461 
1462                 x += kTileWidthHeight + kPad;
1463             }
1464         }
1465 
1466         context->flush();
1467         GrGpu* gpu = context->priv().getGpu();
1468         SkASSERT(gpu);
1469         gpu->testingOnly_flushGpuAndSync();
1470         for (const auto& tex : fBackendTextures) {
1471             context->deleteBackendTexture(tex);
1472         }
1473         fBackendTextures.reset();
1474     }
1475 
1476 private:
1477     SkBitmap fOriginalBMs[2];
1478     sk_sp<SkImage> fImages[2][2];
1479     SkTArray<GrBackendTexture> fBackendTextures;
1480     sk_sp<SkColorSpace> fTargetColorSpace;
1481 
1482     typedef GM INHERITED;
1483 };
1484 
1485 DEF_GM(return new YUVMakeColorSpaceGM();)
1486 
1487 }
1488 
1489 ///////////////
1490 
1491 #include "include/effects/SkColorMatrix.h"
1492 #include "src/core/SkAutoPixmapStorage.h"
1493 #include "src/core/SkYUVMath.h"
1494 #include "tools/Resources.h"
1495 
draw_into_alpha(const SkImage * img,sk_sp<SkColorFilter> cf,const SkPixmap & dst)1496 static void draw_into_alpha(const SkImage* img, sk_sp<SkColorFilter> cf, const SkPixmap& dst) {
1497     auto canvas = SkCanvas::MakeRasterDirect(dst.info(), dst.writable_addr(), dst.rowBytes());
1498     canvas->scale(1.0f * dst.width() / img->width(), 1.0f * dst.height() / img->height());
1499     SkPaint paint;
1500     paint.setFilterQuality(kLow_SkFilterQuality);
1501     paint.setColorFilter(cf);
1502     paint.setBlendMode(SkBlendMode::kSrc);
1503     canvas->drawImage(img, 0, 0, &paint);
1504 }
1505 
split_into_yuv(const SkImage * img,SkYUVColorSpace cs,const SkPixmap dst[3])1506 static void split_into_yuv(const SkImage* img, SkYUVColorSpace cs, const SkPixmap dst[3]) {
1507     float m[20];
1508     SkColorMatrix_RGB2YUV(cs, m);
1509 
1510     memcpy(m + 15, m + 0, 5 * sizeof(float));   // copy Y into A
1511     draw_into_alpha(img, SkColorFilters::Matrix(m), dst[0]);
1512 
1513     memcpy(m + 15, m + 5, 5 * sizeof(float));   // copy U into A
1514     draw_into_alpha(img, SkColorFilters::Matrix(m), dst[1]);
1515 
1516     memcpy(m + 15, m + 10, 5 * sizeof(float));   // copy V into A
1517     draw_into_alpha(img, SkColorFilters::Matrix(m), dst[2]);
1518 }
1519 
draw_diff(SkCanvas * canvas,SkScalar x,SkScalar y,const SkImage * a,const SkImage * b)1520 static void draw_diff(SkCanvas* canvas, SkScalar x, SkScalar y,
1521                       const SkImage* a, const SkImage* b) {
1522     auto sh = SkShaders::Blend(SkBlendMode::kDifference, a->makeShader(), b->makeShader());
1523     SkPaint paint;
1524     paint.setShader(sh);
1525     canvas->save();
1526     canvas->translate(x, y);
1527     canvas->drawRect(SkRect::MakeWH(a->width(), a->height()), paint);
1528 
1529     SkColorMatrix cm;
1530     cm.setScale(64, 64, 64);
1531     paint.setShader(sh->makeWithColorFilter(SkColorFilters::Matrix(cm)));
1532     canvas->translate(0, a->height());
1533     canvas->drawRect(SkRect::MakeWH(a->width(), a->height()), paint);
1534 
1535     canvas->restore();
1536 }
1537 
1538 // Exercises SkColorMatrix_RGB2YUV for yuv colorspaces, showing the planes, and the
1539 // resulting (recombined) images (gpu only for now).
1540 //
1541 class YUVSplitterGM : public skiagm::GM {
1542     sk_sp<SkImage>      fOrig;
1543     SkAutoPixmapStorage fStorage[3];
1544     SkPixmap            fPM[3];
1545 
1546 public:
YUVSplitterGM()1547     YUVSplitterGM() {}
1548 
1549 protected:
1550 
onShortName()1551     SkString onShortName() override {
1552         return SkString("yuv_splitter");
1553     }
1554 
onISize()1555     SkISize onISize() override {
1556         return SkISize::Make(1024, 768);
1557     }
1558 
onOnceBeforeDraw()1559     void onOnceBeforeDraw() override {
1560         fOrig = GetResourceAsImage("images/mandrill_256.png");
1561 
1562         SkImageInfo info = SkImageInfo::Make(fOrig->width(), fOrig->height(), kAlpha_8_SkColorType,
1563                                              kPremul_SkAlphaType);
1564         fStorage[0].alloc(info);
1565         if (0) {
1566             // if you want to scale U,V down by 1/2
1567             info = info.makeWH(info.width()/2, info.height()/2);
1568         }
1569         fStorage[1].alloc(info);
1570         fStorage[2].alloc(info);
1571         for (int i = 0; i < 3; ++i) {
1572             fPM[i] = fStorage[i];
1573         }
1574     }
1575 
onDraw(SkCanvas * canvas)1576     void onDraw(SkCanvas* canvas) override {
1577         SkYUVAIndex indices[4];
1578         indices[SkYUVAIndex::kY_Index] = {0, SkColorChannel::kR};
1579         indices[SkYUVAIndex::kU_Index] = {1, SkColorChannel::kR};
1580         indices[SkYUVAIndex::kV_Index] = {2, SkColorChannel::kR};
1581         indices[SkYUVAIndex::kA_Index] = {-1, SkColorChannel::kR};
1582 
1583         canvas->translate(fOrig->width(), 0);
1584         canvas->save();
1585         for (auto cs : {kRec709_SkYUVColorSpace, kRec601_SkYUVColorSpace, kJPEG_SkYUVColorSpace}) {
1586             split_into_yuv(fOrig.get(), cs, fPM);
1587             auto img = SkImage::MakeFromYUVAPixmaps(canvas->getGrContext(), cs, fPM, indices,
1588                                                     fPM[0].info().dimensions(),
1589                                                     kTopLeft_GrSurfaceOrigin,
1590                                                     false, false, nullptr);
1591             if (img) {
1592                 canvas->drawImage(img, 0, 0, nullptr);
1593                 draw_diff(canvas, 0, fOrig->height(), fOrig.get(), img.get());
1594             }
1595             canvas->translate(fOrig->width(), 0);
1596         }
1597         canvas->restore();
1598         canvas->translate(-fOrig->width(), 0);
1599 
1600         canvas->drawImage(SkImage::MakeRasterCopy(fPM[0]), 0, 0, nullptr);
1601         canvas->drawImage(SkImage::MakeRasterCopy(fPM[1]), 0, fPM[0].height(), nullptr);
1602         canvas->drawImage(SkImage::MakeRasterCopy(fPM[2]),
1603                           0, fPM[0].height() + fPM[1].height(), nullptr);
1604     }
1605 
1606 private:
1607     typedef GM INHERITED;
1608 };
1609 DEF_GM( return new YUVSplitterGM; )
1610