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: 34 YUVtoRGBEffect() { 35 this->setBGColor(0xFFFFFFFF); 36 } 37 38 protected: 39 SkString onShortName() override { 40 return SkString("yuv_to_rgb_effect"); 41 } 42 43 SkISize onISize() override { 44 int numRows = kLastEnum_SkYUVColorSpace + 1; 45 return SkISize::Make(238, kDrawPad + numRows * kColorSpaceOffset); 46 } 47 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 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: 145 YUVNV12toRGBEffect() { 146 this->setBGColor(0xFFFFFFFF); 147 } 148 149 protected: 150 SkString onShortName() override { 151 return SkString("yuv_nv12_to_rgb_effect"); 152 } 153 154 SkISize onISize() override { 155 int numRows = kLastEnum_SkYUVColorSpace + 1; 156 return SkISize::Make(48, kDrawPad + numRows * kColorSpaceOffset); 157 } 158 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 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