1 /*
2  * Copyright 2014 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 // This test only works with the GPU backend.
9 
10 #include "gm.h"
11 
12 #include "GrContext.h"
13 #include "GrContextPriv.h"
14 #include "GrProxyProvider.h"
15 #include "GrRenderTargetContextPriv.h"
16 #include "GrTextureProxy.h"
17 #include "SkBitmap.h"
18 #include "SkGr.h"
19 #include "SkGradientShader.h"
20 #include "effects/GrYUVtoRGBEffect.h"
21 #include "ops/GrDrawOp.h"
22 #include "ops/GrFillRectOp.h"
23 
24 #define YSIZE 8
25 #define USIZE 4
26 #define VSIZE 4
27 
28 namespace skiagm {
29 /**
30  * This GM directly exercises GrYUVtoRGBEffect.
31  */
32 class YUVtoRGBEffect : public GpuGM {
33 public:
YUVtoRGBEffect()34     YUVtoRGBEffect() {
35         this->setBGColor(0xFFFFFFFF);
36     }
37 
38 protected:
onShortName()39     SkString onShortName() override {
40         return SkString("yuv_to_rgb_effect");
41     }
42 
onISize()43     SkISize onISize() override {
44         int numRows = kLastEnum_SkYUVColorSpace + 1;
45         return SkISize::Make(238, kDrawPad + numRows * kColorSpaceOffset);
46     }
47 
onOnceBeforeDraw()48     void onOnceBeforeDraw() override {
49         SkBitmap bmp[3];
50         SkImageInfo yinfo = SkImageInfo::MakeA8(YSIZE, YSIZE);
51         bmp[0].allocPixels(yinfo);
52         SkImageInfo uinfo = SkImageInfo::MakeA8(USIZE, USIZE);
53         bmp[1].allocPixels(uinfo);
54         SkImageInfo vinfo = SkImageInfo::MakeA8(VSIZE, VSIZE);
55         bmp[2].allocPixels(vinfo);
56         unsigned char* pixels[3];
57         for (int i = 0; i < 3; ++i) {
58             pixels[i] = (unsigned char*)bmp[i].getPixels();
59         }
60         int color[] = {0, 85, 170};
61         const int limit[] = {255, 0, 255};
62         const int invl[]  = {0, 255, 0};
63         const int inc[]   = {1, -1, 1};
64         for (int i = 0; i < 3; ++i) {
65             const size_t nbBytes = bmp[i].rowBytes() * bmp[i].height();
66             for (size_t j = 0; j < nbBytes; ++j) {
67                 pixels[i][j] = (unsigned char)color[i];
68                 color[i] = (color[i] == limit[i]) ? invl[i] : color[i] + inc[i];
69             }
70         }
71         for (int i = 0; i < 3; ++i) {
72             fImage[i] = SkImage::MakeFromBitmap(bmp[i]);
73         }
74     }
75 
onDraw(GrContext * context,GrRenderTargetContext * renderTargetContext,SkCanvas * canvas,SkString * errorMsg)76     DrawResult onDraw(GrContext* context, GrRenderTargetContext* renderTargetContext,
77                       SkCanvas* canvas, SkString* errorMsg) override {
78         GrProxyProvider* proxyProvider = context->priv().proxyProvider();
79         sk_sp<GrTextureProxy> proxies[3];
80 
81         for (int i = 0; i < 3; ++i) {
82             proxies[i] = proxyProvider->createTextureProxy(fImage[i], kNone_GrSurfaceFlags, 1,
83                                                            SkBudgeted::kYes, SkBackingFit::kExact);
84             if (!proxies[i]) {
85                 *errorMsg = "Failed to create proxy";
86                 return DrawResult::kFail;
87             }
88         }
89 
90         for (int space = kJPEG_SkYUVColorSpace; space <= kLastEnum_SkYUVColorSpace; ++space) {
91             SkRect renderRect = SkRect::MakeWH(SkIntToScalar(fImage[0]->width()),
92                                                SkIntToScalar(fImage[0]->height()));
93             renderRect.outset(kDrawPad, kDrawPad);
94 
95             SkScalar y = kDrawPad + kTestPad + space * kColorSpaceOffset;
96             SkScalar x = kDrawPad + kTestPad;
97 
98             const int indices[6][3] = {{0, 1, 2}, {0, 2, 1}, {1, 0, 2},
99                                        {1, 2, 0}, {2, 0, 1}, {2, 1, 0}};
100 
101             for (int i = 0; i < 6; ++i) {
102                 SkYUVAIndex yuvaIndices[4] = {
103                     { indices[i][0], SkColorChannel::kR },
104                     { indices[i][1], SkColorChannel::kR },
105                     { indices[i][2], SkColorChannel::kR },
106                     { -1, SkColorChannel::kA }
107                 };
108 
109                 std::unique_ptr<GrFragmentProcessor> fp(
110                         GrYUVtoRGBEffect::Make(proxies, yuvaIndices,
111                                                static_cast<SkYUVColorSpace>(space),
112                                                GrSamplerState::Filter::kNearest));
113                 if (fp) {
114                     GrPaint grPaint;
115                     grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
116                     grPaint.addColorFragmentProcessor(std::move(fp));
117                     SkMatrix viewMatrix;
118                     viewMatrix.setTranslate(x, y);
119                     renderTargetContext->priv().testingOnly_addDrawOp(
120                             GrFillRectOp::Make(context, std::move(grPaint), GrAAType::kNone,
121                                                viewMatrix, renderRect));
122                 }
123                 x += renderRect.width() + kTestPad;
124             }
125         }
126         return DrawResult::kOk;
127      }
128 
129 private:
130     sk_sp<SkImage> fImage[3];
131 
132     static constexpr SkScalar kDrawPad = 10.f;
133     static constexpr SkScalar kTestPad = 10.f;
134     static constexpr SkScalar kColorSpaceOffset = 36.f;
135 
136     typedef GM INHERITED;
137 };
138 
139 DEF_GM(return new YUVtoRGBEffect;)
140 
141 //////////////////////////////////////////////////////////////////////////////
142 
143 class YUVNV12toRGBEffect : public GpuGM {
144 public:
YUVNV12toRGBEffect()145     YUVNV12toRGBEffect() {
146         this->setBGColor(0xFFFFFFFF);
147     }
148 
149 protected:
onShortName()150     SkString onShortName() override {
151         return SkString("yuv_nv12_to_rgb_effect");
152     }
153 
onISize()154     SkISize onISize() override {
155         int numRows = kLastEnum_SkYUVColorSpace + 1;
156         return SkISize::Make(48, kDrawPad + numRows * kColorSpaceOffset);
157     }
158 
onOnceBeforeDraw()159     void onOnceBeforeDraw() override {
160         SkBitmap bmp[2];
161         SkImageInfo yinfo = SkImageInfo::MakeA8(YSIZE, YSIZE);
162         bmp[0].allocPixels(yinfo);
163         SkImageInfo uvinfo = SkImageInfo::MakeN32Premul(USIZE, USIZE);
164         bmp[1].allocPixels(uvinfo);
165         int color[] = {0, 85, 170};
166         const int limit[] = {255, 0, 255};
167         const int invl[] = {0, 255, 0};
168         const int inc[] = {1, -1, 1};
169 
170         {
171             unsigned char* pixels = (unsigned char*)bmp[0].getPixels();
172             const size_t nbBytes = bmp[0].rowBytes() * bmp[0].height();
173             for (size_t j = 0; j < nbBytes; ++j) {
174                 pixels[j] = (unsigned char)color[0];
175                 color[0] = (color[0] == limit[0]) ? invl[0] : color[0] + inc[0];
176             }
177         }
178 
179         {
180             for (int y = 0; y < bmp[1].height(); ++y) {
181                 uint32_t* pixels = bmp[1].getAddr32(0, y);
182                 for (int j = 0; j < bmp[1].width(); ++j) {
183                     pixels[j] = SkColorSetARGB(0, color[1], color[2], 0);
184                     color[1] = (color[1] == limit[1]) ? invl[1] : color[1] + inc[1];
185                     color[2] = (color[2] == limit[2]) ? invl[2] : color[2] + inc[2];
186                 }
187             }
188         }
189 
190         for (int i = 0; i < 2; ++i) {
191             fImage[i] = SkImage::MakeFromBitmap(bmp[i]);
192         }
193     }
194 
onDraw(GrContext * context,GrRenderTargetContext * renderTargetContext,SkCanvas * canvas,SkString * errorMsg)195     DrawResult onDraw(GrContext* context, GrRenderTargetContext* renderTargetContext,
196                       SkCanvas* canvas, SkString* errorMsg) override {
197         GrProxyProvider* proxyProvider = context->priv().proxyProvider();
198         sk_sp<GrTextureProxy> proxies[2];
199 
200         for (int i = 0; i < 2; ++i) {
201             proxies[i] = proxyProvider->createTextureProxy(fImage[i], kNone_GrSurfaceFlags, 1,
202                                                            SkBudgeted::kYes, SkBackingFit::kExact);
203             if (!proxies[i]) {
204                 *errorMsg = "Failed to create proxy";
205                 return DrawResult::kFail;
206             }
207         }
208 
209         SkYUVAIndex yuvaIndices[4] = {
210             {  0, SkColorChannel::kR },
211             {  1, SkColorChannel::kR },
212             {  1, SkColorChannel::kG },
213             { -1, SkColorChannel::kA }
214         };
215 
216         for (int space = kJPEG_SkYUVColorSpace; space <= kLastEnum_SkYUVColorSpace; ++space) {
217             SkRect renderRect = SkRect::MakeWH(SkIntToScalar(fImage[0]->width()),
218                                                SkIntToScalar(fImage[0]->height()));
219             renderRect.outset(kDrawPad, kDrawPad);
220 
221             SkScalar y = kDrawPad + kTestPad + space * kColorSpaceOffset;
222             SkScalar x = kDrawPad + kTestPad;
223 
224             GrPaint grPaint;
225             grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
226             auto fp = GrYUVtoRGBEffect::Make(proxies, yuvaIndices,
227                                              static_cast<SkYUVColorSpace>(space),
228                                              GrSamplerState::Filter::kNearest);
229             if (fp) {
230                 SkMatrix viewMatrix;
231                 viewMatrix.setTranslate(x, y);
232                 grPaint.addColorFragmentProcessor(std::move(fp));
233                 std::unique_ptr<GrDrawOp> op(GrFillRectOp::Make(context, std::move(grPaint),
234                         GrAAType::kNone, viewMatrix, renderRect));
235                 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
236             }
237         }
238         return DrawResult::kOk;
239     }
240 
241 private:
242     sk_sp<SkImage> fImage[2];
243 
244     static constexpr SkScalar kDrawPad = 10.f;
245     static constexpr SkScalar kTestPad = 10.f;
246     static constexpr SkScalar kColorSpaceOffset = 36.f;
247 
248     typedef GM INHERITED;
249 };
250 
251 DEF_GM(return new YUVNV12toRGBEffect;)
252 }
253