yuvtorgbeffect.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  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. // This test only works with the GPU backend.
  8. #include "gm/gm.h"
  9. #include "include/core/SkBitmap.h"
  10. #include "include/core/SkBlendMode.h"
  11. #include "include/core/SkColor.h"
  12. #include "include/core/SkImage.h"
  13. #include "include/core/SkImageInfo.h"
  14. #include "include/core/SkMatrix.h"
  15. #include "include/core/SkRect.h"
  16. #include "include/core/SkRefCnt.h"
  17. #include "include/core/SkScalar.h"
  18. #include "include/core/SkSize.h"
  19. #include "include/core/SkString.h"
  20. #include "include/core/SkTypes.h"
  21. #include "include/core/SkYUVAIndex.h"
  22. #include "include/gpu/GrContext.h"
  23. #include "include/gpu/GrSamplerState.h"
  24. #include "include/private/GrTypesPriv.h"
  25. #include "src/gpu/GrClip.h"
  26. #include "src/gpu/GrContextPriv.h"
  27. #include "src/gpu/GrFragmentProcessor.h"
  28. #include "src/gpu/GrPaint.h"
  29. #include "src/gpu/GrProxyProvider.h"
  30. #include "src/gpu/GrRenderTargetContext.h"
  31. #include "src/gpu/GrRenderTargetContextPriv.h"
  32. #include "src/gpu/GrTextureProxy.h"
  33. #include "src/gpu/effects/GrPorterDuffXferProcessor.h"
  34. #include "src/gpu/effects/GrYUVtoRGBEffect.h"
  35. #include "src/gpu/ops/GrDrawOp.h"
  36. #include "src/gpu/ops/GrFillRectOp.h"
  37. #include <memory>
  38. #include <utility>
  39. class SkCanvas;
  40. #define YSIZE 8
  41. #define USIZE 4
  42. #define VSIZE 4
  43. namespace skiagm {
  44. /**
  45. * This GM directly exercises GrYUVtoRGBEffect.
  46. */
  47. class YUVtoRGBEffect : public GpuGM {
  48. public:
  49. YUVtoRGBEffect() {
  50. this->setBGColor(0xFFFFFFFF);
  51. }
  52. protected:
  53. SkString onShortName() override {
  54. return SkString("yuv_to_rgb_effect");
  55. }
  56. SkISize onISize() override {
  57. int numRows = kLastEnum_SkYUVColorSpace + 1;
  58. return SkISize::Make(238, kDrawPad + numRows * kColorSpaceOffset);
  59. }
  60. void onOnceBeforeDraw() override {
  61. SkBitmap bmp[3];
  62. SkImageInfo yinfo = SkImageInfo::MakeA8(YSIZE, YSIZE);
  63. bmp[0].allocPixels(yinfo);
  64. SkImageInfo uinfo = SkImageInfo::MakeA8(USIZE, USIZE);
  65. bmp[1].allocPixels(uinfo);
  66. SkImageInfo vinfo = SkImageInfo::MakeA8(VSIZE, VSIZE);
  67. bmp[2].allocPixels(vinfo);
  68. unsigned char* pixels[3];
  69. for (int i = 0; i < 3; ++i) {
  70. pixels[i] = (unsigned char*)bmp[i].getPixels();
  71. }
  72. int color[] = {0, 85, 170};
  73. const int limit[] = {255, 0, 255};
  74. const int invl[] = {0, 255, 0};
  75. const int inc[] = {1, -1, 1};
  76. for (int i = 0; i < 3; ++i) {
  77. const size_t nbBytes = bmp[i].rowBytes() * bmp[i].height();
  78. for (size_t j = 0; j < nbBytes; ++j) {
  79. pixels[i][j] = (unsigned char)color[i];
  80. color[i] = (color[i] == limit[i]) ? invl[i] : color[i] + inc[i];
  81. }
  82. }
  83. for (int i = 0; i < 3; ++i) {
  84. fImage[i] = SkImage::MakeFromBitmap(bmp[i]);
  85. }
  86. }
  87. DrawResult onDraw(GrContext* context, GrRenderTargetContext* renderTargetContext,
  88. SkCanvas* canvas, SkString* errorMsg) override {
  89. GrProxyProvider* proxyProvider = context->priv().proxyProvider();
  90. sk_sp<GrTextureProxy> proxies[3];
  91. for (int i = 0; i < 3; ++i) {
  92. proxies[i] = proxyProvider->createTextureProxy(fImage[i], GrRenderable::kNo, 1,
  93. SkBudgeted::kYes, SkBackingFit::kExact);
  94. if (!proxies[i]) {
  95. *errorMsg = "Failed to create proxy";
  96. return DrawResult::kFail;
  97. }
  98. }
  99. for (int space = kJPEG_SkYUVColorSpace; space <= kLastEnum_SkYUVColorSpace; ++space) {
  100. SkRect renderRect = SkRect::MakeWH(SkIntToScalar(fImage[0]->width()),
  101. SkIntToScalar(fImage[0]->height()));
  102. renderRect.outset(kDrawPad, kDrawPad);
  103. SkScalar y = kDrawPad + kTestPad + space * kColorSpaceOffset;
  104. SkScalar x = kDrawPad + kTestPad;
  105. const int indices[6][3] = {{0, 1, 2}, {0, 2, 1}, {1, 0, 2},
  106. {1, 2, 0}, {2, 0, 1}, {2, 1, 0}};
  107. for (int i = 0; i < 6; ++i) {
  108. SkYUVAIndex yuvaIndices[4] = {
  109. { indices[i][0], SkColorChannel::kR },
  110. { indices[i][1], SkColorChannel::kR },
  111. { indices[i][2], SkColorChannel::kR },
  112. { -1, SkColorChannel::kA }
  113. };
  114. std::unique_ptr<GrFragmentProcessor> fp(
  115. GrYUVtoRGBEffect::Make(proxies, yuvaIndices,
  116. static_cast<SkYUVColorSpace>(space),
  117. GrSamplerState::Filter::kNearest));
  118. if (fp) {
  119. GrPaint grPaint;
  120. grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
  121. grPaint.addColorFragmentProcessor(std::move(fp));
  122. SkMatrix viewMatrix;
  123. viewMatrix.setTranslate(x, y);
  124. renderTargetContext->priv().testingOnly_addDrawOp(
  125. GrFillRectOp::MakeNonAARect(context, std::move(grPaint),
  126. viewMatrix, renderRect));
  127. }
  128. x += renderRect.width() + kTestPad;
  129. }
  130. }
  131. return DrawResult::kOk;
  132. }
  133. private:
  134. sk_sp<SkImage> fImage[3];
  135. static constexpr SkScalar kDrawPad = 10.f;
  136. static constexpr SkScalar kTestPad = 10.f;
  137. static constexpr SkScalar kColorSpaceOffset = 36.f;
  138. typedef GM INHERITED;
  139. };
  140. DEF_GM(return new YUVtoRGBEffect;)
  141. //////////////////////////////////////////////////////////////////////////////
  142. class YUVNV12toRGBEffect : public GpuGM {
  143. public:
  144. YUVNV12toRGBEffect() {
  145. this->setBGColor(0xFFFFFFFF);
  146. }
  147. protected:
  148. SkString onShortName() override {
  149. return SkString("yuv_nv12_to_rgb_effect");
  150. }
  151. SkISize onISize() override {
  152. int numRows = kLastEnum_SkYUVColorSpace + 1;
  153. return SkISize::Make(48, kDrawPad + numRows * kColorSpaceOffset);
  154. }
  155. void onOnceBeforeDraw() override {
  156. SkBitmap bmp[2];
  157. SkImageInfo yinfo = SkImageInfo::MakeA8(YSIZE, YSIZE);
  158. bmp[0].allocPixels(yinfo);
  159. SkImageInfo uvinfo = SkImageInfo::MakeN32Premul(USIZE, USIZE);
  160. bmp[1].allocPixels(uvinfo);
  161. int color[] = {0, 85, 170};
  162. const int limit[] = {255, 0, 255};
  163. const int invl[] = {0, 255, 0};
  164. const int inc[] = {1, -1, 1};
  165. {
  166. unsigned char* pixels = (unsigned char*)bmp[0].getPixels();
  167. const size_t nbBytes = bmp[0].rowBytes() * bmp[0].height();
  168. for (size_t j = 0; j < nbBytes; ++j) {
  169. pixels[j] = (unsigned char)color[0];
  170. color[0] = (color[0] == limit[0]) ? invl[0] : color[0] + inc[0];
  171. }
  172. }
  173. {
  174. for (int y = 0; y < bmp[1].height(); ++y) {
  175. uint32_t* pixels = bmp[1].getAddr32(0, y);
  176. for (int j = 0; j < bmp[1].width(); ++j) {
  177. pixels[j] = SkColorSetARGB(0, color[1], color[2], 0);
  178. color[1] = (color[1] == limit[1]) ? invl[1] : color[1] + inc[1];
  179. color[2] = (color[2] == limit[2]) ? invl[2] : color[2] + inc[2];
  180. }
  181. }
  182. }
  183. for (int i = 0; i < 2; ++i) {
  184. fImage[i] = SkImage::MakeFromBitmap(bmp[i]);
  185. }
  186. }
  187. DrawResult onDraw(GrContext* context, GrRenderTargetContext* renderTargetContext,
  188. SkCanvas* canvas, SkString* errorMsg) override {
  189. GrProxyProvider* proxyProvider = context->priv().proxyProvider();
  190. sk_sp<GrTextureProxy> proxies[2];
  191. for (int i = 0; i < 2; ++i) {
  192. proxies[i] = proxyProvider->createTextureProxy(fImage[i], GrRenderable::kNo, 1,
  193. SkBudgeted::kYes, SkBackingFit::kExact);
  194. if (!proxies[i]) {
  195. *errorMsg = "Failed to create proxy";
  196. return DrawResult::kFail;
  197. }
  198. }
  199. SkYUVAIndex yuvaIndices[4] = {
  200. { 0, SkColorChannel::kR },
  201. { 1, SkColorChannel::kR },
  202. { 1, SkColorChannel::kG },
  203. { -1, SkColorChannel::kA }
  204. };
  205. for (int space = kJPEG_SkYUVColorSpace; space <= kLastEnum_SkYUVColorSpace; ++space) {
  206. SkRect renderRect = SkRect::MakeWH(SkIntToScalar(fImage[0]->width()),
  207. SkIntToScalar(fImage[0]->height()));
  208. renderRect.outset(kDrawPad, kDrawPad);
  209. SkScalar y = kDrawPad + kTestPad + space * kColorSpaceOffset;
  210. SkScalar x = kDrawPad + kTestPad;
  211. GrPaint grPaint;
  212. grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
  213. auto fp = GrYUVtoRGBEffect::Make(proxies, yuvaIndices,
  214. static_cast<SkYUVColorSpace>(space),
  215. GrSamplerState::Filter::kNearest);
  216. if (fp) {
  217. SkMatrix viewMatrix;
  218. viewMatrix.setTranslate(x, y);
  219. grPaint.addColorFragmentProcessor(std::move(fp));
  220. std::unique_ptr<GrDrawOp> op(GrFillRectOp::MakeNonAARect(
  221. context, std::move(grPaint), viewMatrix, renderRect));
  222. renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
  223. }
  224. }
  225. return DrawResult::kOk;
  226. }
  227. private:
  228. sk_sp<SkImage> fImage[2];
  229. static constexpr SkScalar kDrawPad = 10.f;
  230. static constexpr SkScalar kTestPad = 10.f;
  231. static constexpr SkScalar kColorSpaceOffset = 36.f;
  232. typedef GM INHERITED;
  233. };
  234. DEF_GM(return new YUVNV12toRGBEffect;)
  235. //////////////////////////////////////////////////////////////////////////////
  236. // This GM tests domain clamping on YUV multiplanar images where the U and V
  237. // planes have different resolution from Y. See skbug:8959
  238. class YUVtoRGBDomainEffect : public GpuGM {
  239. public:
  240. YUVtoRGBDomainEffect() {
  241. this->setBGColor(0xFFFFFFFF);
  242. }
  243. protected:
  244. SkString onShortName() override {
  245. return SkString("yuv_to_rgb_domain_effect");
  246. }
  247. SkISize onISize() override {
  248. return SkISize::Make((YSIZE + kTestPad) * 3 + kDrawPad, (YSIZE + kTestPad) * 2 + kDrawPad);
  249. }
  250. void onOnceBeforeDraw() override {
  251. SkBitmap bmp[3];
  252. SkImageInfo yinfo = SkImageInfo::MakeA8(YSIZE, YSIZE);
  253. bmp[0].allocPixels(yinfo);
  254. SkImageInfo uinfo = SkImageInfo::MakeA8(USIZE, USIZE);
  255. bmp[1].allocPixels(uinfo);
  256. SkImageInfo vinfo = SkImageInfo::MakeA8(VSIZE, VSIZE);
  257. bmp[2].allocPixels(vinfo);
  258. int innerColor[] = {149, 43, 21};
  259. int outerColor[] = {128, 128, 128};
  260. for (int i = 0; i < 3; ++i) {
  261. bmp[i].eraseColor(SkColorSetARGB(outerColor[i], 0, 0, 0));
  262. SkIRect innerRect = i == 0 ? SkIRect::MakeLTRB(2, 2, 6, 6) : SkIRect::MakeLTRB(1, 1, 3, 3);
  263. bmp[i].erase(SkColorSetARGB(innerColor[i], 0, 0, 0), innerRect);
  264. fImage[i] = SkImage::MakeFromBitmap(bmp[i]);
  265. }
  266. }
  267. DrawResult onDraw(GrContext* context, GrRenderTargetContext* renderTargetContext,
  268. SkCanvas* canvas, SkString* errorMsg) override {
  269. GrProxyProvider* proxyProvider = context->priv().proxyProvider();
  270. sk_sp<GrTextureProxy> proxies[3];
  271. for (int i = 0; i < 3; ++i) {
  272. proxies[i] = proxyProvider->createTextureProxy(fImage[i], GrRenderable::kNo, 1,
  273. SkBudgeted::kYes, SkBackingFit::kExact);
  274. if (!proxies[i]) {
  275. *errorMsg = "Failed to create proxy";
  276. return DrawResult::kFail;
  277. }
  278. }
  279. // Draw a 2x2 grid of the YUV images.
  280. // Rows = kNearest, kBilerp, Cols = No clamp, clamp
  281. static const GrSamplerState::Filter kFilters[] = {
  282. GrSamplerState::Filter::kNearest, GrSamplerState::Filter::kBilerp };
  283. static const SkRect kGreenRect = SkRect::MakeLTRB(2.f, 2.f, 6.f, 6.f);
  284. SkYUVAIndex yuvaIndices[4] = {
  285. { SkYUVAIndex::kY_Index, SkColorChannel::kR },
  286. { SkYUVAIndex::kU_Index, SkColorChannel::kR },
  287. { SkYUVAIndex::kV_Index, SkColorChannel::kR },
  288. { -1, SkColorChannel::kA }
  289. };
  290. SkRect rect = SkRect::MakeWH(YSIZE, YSIZE);
  291. SkScalar y = kDrawPad + kTestPad;
  292. for (uint32_t i = 0; i < SK_ARRAY_COUNT(kFilters); ++i) {
  293. SkScalar x = kDrawPad + kTestPad;
  294. for (uint32_t j = 0; j < 2; ++j) {
  295. SkMatrix ctm = SkMatrix::MakeTrans(x, y);
  296. ctm.postScale(10.f, 10.f);
  297. SkRect domain = kGreenRect;
  298. if (kFilters[i] == GrSamplerState::Filter::kNearest) {
  299. // Make a very small inset for nearest-neighbor filtering so that 0.5px
  300. // centers don't round out beyond the green pixels.
  301. domain.inset(0.01f, 0.01f);
  302. }
  303. const SkRect* domainPtr = j > 0 ? &domain : nullptr;
  304. std::unique_ptr<GrFragmentProcessor> fp(GrYUVtoRGBEffect::Make(proxies, yuvaIndices,
  305. kJPEG_SkYUVColorSpace, kFilters[i], SkMatrix::I(), domainPtr));
  306. if (fp) {
  307. GrPaint grPaint;
  308. grPaint.addColorFragmentProcessor(std::move(fp));
  309. renderTargetContext->drawRect(
  310. GrNoClip(), std::move(grPaint), GrAA::kYes, ctm, rect);
  311. }
  312. x += rect.width() + kTestPad;
  313. }
  314. y += rect.height() + kTestPad;
  315. }
  316. return DrawResult::kOk;
  317. }
  318. private:
  319. sk_sp<SkImage> fImage[3];
  320. static constexpr SkScalar kDrawPad = 10.f;
  321. static constexpr SkScalar kTestPad = 10.f;
  322. typedef GM INHERITED;
  323. };
  324. DEF_GM(return new YUVtoRGBDomainEffect;)
  325. }