SpecialImageTest.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. /*
  2. * Copyright 2016 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. #include "include/core/SkBitmap.h"
  8. #include "include/core/SkCanvas.h"
  9. #include "include/core/SkImage.h"
  10. #include "include/core/SkPixmap.h"
  11. #include "include/core/SkSurface.h"
  12. #include "src/core/SkAutoPixmapStorage.h"
  13. #include "src/core/SkSpecialImage.h"
  14. #include "src/core/SkSpecialSurface.h"
  15. #include "tests/Test.h"
  16. #include "include/gpu/GrBackendSurface.h"
  17. #include "include/gpu/GrContext.h"
  18. #include "src/gpu/GrContextPriv.h"
  19. #include "src/gpu/GrProxyProvider.h"
  20. #include "src/gpu/GrSurfaceProxy.h"
  21. #include "src/gpu/GrTextureProxy.h"
  22. #include "src/gpu/SkGr.h"
  23. // This test creates backing resources exactly sized to [kFullSize x kFullSize].
  24. // It then wraps them in an SkSpecialImage with only the center (red) region being active.
  25. // It then draws the SkSpecialImage to a full sized (all blue) canvas and checks that none
  26. // of the inactive (green) region leaked out.
  27. static const int kSmallerSize = 10;
  28. static const int kPad = 3;
  29. static const int kFullSize = kSmallerSize + 2 * kPad;
  30. // Create a bitmap with red in the center and green around it
  31. static SkBitmap create_bm() {
  32. SkBitmap bm;
  33. bm.allocN32Pixels(kFullSize, kFullSize, true);
  34. SkCanvas temp(bm);
  35. temp.clear(SK_ColorGREEN);
  36. SkPaint p;
  37. p.setColor(SK_ColorRED);
  38. p.setAntiAlias(false);
  39. temp.drawRect(SkRect::MakeXYWH(SkIntToScalar(kPad), SkIntToScalar(kPad),
  40. SkIntToScalar(kSmallerSize), SkIntToScalar(kSmallerSize)),
  41. p);
  42. return bm;
  43. }
  44. // Basic test of the SkSpecialImage public API (e.g., peekTexture, peekPixels & draw)
  45. static void test_image(const sk_sp<SkSpecialImage>& img, skiatest::Reporter* reporter,
  46. GrContext* context, bool isGPUBacked) {
  47. const SkIRect subset = img->subset();
  48. REPORTER_ASSERT(reporter, kPad == subset.left());
  49. REPORTER_ASSERT(reporter, kPad == subset.top());
  50. REPORTER_ASSERT(reporter, kSmallerSize == subset.width());
  51. REPORTER_ASSERT(reporter, kSmallerSize == subset.height());
  52. //--------------
  53. // Test that isTextureBacked reports the correct backing type
  54. REPORTER_ASSERT(reporter, isGPUBacked == img->isTextureBacked());
  55. //--------------
  56. // Test asTextureProxyRef - as long as there is a context this should succeed
  57. if (context) {
  58. sk_sp<GrTextureProxy> proxy(img->asTextureProxyRef(context));
  59. REPORTER_ASSERT(reporter, proxy);
  60. }
  61. //--------------
  62. // Test getROPixels - this should always succeed regardless of backing store
  63. SkBitmap bitmap;
  64. REPORTER_ASSERT(reporter, img->getROPixels(&bitmap));
  65. REPORTER_ASSERT(reporter, kSmallerSize == bitmap.width());
  66. REPORTER_ASSERT(reporter, kSmallerSize == bitmap.height());
  67. //--------------
  68. // Test that draw restricts itself to the subset
  69. SkImageFilter::OutputProperties outProps(kN32_SkColorType, img->getColorSpace());
  70. sk_sp<SkSpecialSurface> surf(img->makeSurface(outProps, SkISize::Make(kFullSize, kFullSize),
  71. kPremul_SkAlphaType));
  72. SkCanvas* canvas = surf->getCanvas();
  73. canvas->clear(SK_ColorBLUE);
  74. img->draw(canvas, SkIntToScalar(kPad), SkIntToScalar(kPad), nullptr);
  75. SkBitmap bm;
  76. bm.allocN32Pixels(kFullSize, kFullSize, false);
  77. bool result = canvas->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), 0, 0);
  78. SkASSERT_RELEASE(result);
  79. // Only the center (red) portion should've been drawn into the canvas
  80. REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kPad-1, kPad-1));
  81. REPORTER_ASSERT(reporter, SK_ColorRED == bm.getColor(kPad, kPad));
  82. REPORTER_ASSERT(reporter, SK_ColorRED == bm.getColor(kSmallerSize+kPad-1,
  83. kSmallerSize+kPad-1));
  84. REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kSmallerSize+kPad,
  85. kSmallerSize+kPad));
  86. //--------------
  87. // Test that asImage & makeTightSurface return appropriately sized objects
  88. // of the correct backing type
  89. SkIRect newSubset = SkIRect::MakeWH(subset.width(), subset.height());
  90. {
  91. sk_sp<SkImage> tightImg(img->asImage(&newSubset));
  92. REPORTER_ASSERT(reporter, tightImg->width() == subset.width());
  93. REPORTER_ASSERT(reporter, tightImg->height() == subset.height());
  94. REPORTER_ASSERT(reporter, isGPUBacked == tightImg->isTextureBacked());
  95. SkPixmap tmpPixmap;
  96. REPORTER_ASSERT(reporter, isGPUBacked != !!tightImg->peekPixels(&tmpPixmap));
  97. }
  98. {
  99. SkImageFilter::OutputProperties outProps(kN32_SkColorType, img->getColorSpace());
  100. sk_sp<SkSurface> tightSurf(img->makeTightSurface(outProps, subset.size()));
  101. REPORTER_ASSERT(reporter, tightSurf->width() == subset.width());
  102. REPORTER_ASSERT(reporter, tightSurf->height() == subset.height());
  103. GrBackendTexture backendTex = tightSurf->getBackendTexture(
  104. SkSurface::kDiscardWrite_BackendHandleAccess);
  105. REPORTER_ASSERT(reporter, isGPUBacked == backendTex.isValid());
  106. SkPixmap tmpPixmap;
  107. REPORTER_ASSERT(reporter, isGPUBacked != !!tightSurf->peekPixels(&tmpPixmap));
  108. }
  109. }
  110. DEF_TEST(SpecialImage_Raster, reporter) {
  111. SkBitmap bm = create_bm();
  112. sk_sp<SkSpecialImage> fullSImage(SkSpecialImage::MakeFromRaster(
  113. SkIRect::MakeWH(kFullSize, kFullSize),
  114. bm));
  115. const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
  116. {
  117. sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeFromRaster(subset, bm));
  118. test_image(subSImg1, reporter, nullptr, false);
  119. }
  120. {
  121. sk_sp<SkSpecialImage> subSImg2(fullSImage->makeSubset(subset));
  122. test_image(subSImg2, reporter, nullptr, false);
  123. }
  124. }
  125. static void test_specialimage_image(skiatest::Reporter* reporter) {
  126. SkBitmap bm = create_bm();
  127. sk_sp<SkImage> fullImage(SkImage::MakeFromBitmap(bm));
  128. sk_sp<SkSpecialImage> fullSImage(SkSpecialImage::MakeFromImage(
  129. nullptr,
  130. SkIRect::MakeWH(kFullSize, kFullSize),
  131. fullImage));
  132. const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
  133. {
  134. sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeFromImage(nullptr, subset, fullImage));
  135. test_image(subSImg1, reporter, nullptr, false);
  136. }
  137. {
  138. sk_sp<SkSpecialImage> subSImg2(fullSImage->makeSubset(subset));
  139. test_image(subSImg2, reporter, nullptr, false);
  140. }
  141. }
  142. DEF_TEST(SpecialImage_Image_Legacy, reporter) {
  143. test_specialimage_image(reporter);
  144. }
  145. static void test_texture_backed(skiatest::Reporter* reporter,
  146. const sk_sp<SkSpecialImage>& orig,
  147. const sk_sp<SkSpecialImage>& gpuBacked) {
  148. REPORTER_ASSERT(reporter, gpuBacked);
  149. REPORTER_ASSERT(reporter, gpuBacked->isTextureBacked());
  150. REPORTER_ASSERT(reporter, gpuBacked->uniqueID() == orig->uniqueID());
  151. REPORTER_ASSERT(reporter, gpuBacked->subset().width() == orig->subset().width() &&
  152. gpuBacked->subset().height() == orig->subset().height());
  153. REPORTER_ASSERT(reporter, gpuBacked->getColorSpace() == orig->getColorSpace());
  154. }
  155. // Test out the SkSpecialImage::makeTextureImage entry point
  156. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_MakeTexture, reporter, ctxInfo) {
  157. GrContext* context = ctxInfo.grContext();
  158. GrProxyProvider* proxyProvider = context->priv().proxyProvider();
  159. SkBitmap bm = create_bm();
  160. const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
  161. {
  162. // raster
  163. sk_sp<SkSpecialImage> rasterImage(SkSpecialImage::MakeFromRaster(
  164. SkIRect::MakeWH(kFullSize,
  165. kFullSize),
  166. bm));
  167. {
  168. sk_sp<SkSpecialImage> fromRaster(rasterImage->makeTextureImage(context));
  169. test_texture_backed(reporter, rasterImage, fromRaster);
  170. }
  171. {
  172. sk_sp<SkSpecialImage> subRasterImage(rasterImage->makeSubset(subset));
  173. sk_sp<SkSpecialImage> fromSubRaster(subRasterImage->makeTextureImage(context));
  174. test_texture_backed(reporter, subRasterImage, fromSubRaster);
  175. }
  176. }
  177. {
  178. // gpu
  179. sk_sp<SkImage> rasterImage = SkImage::MakeFromBitmap(bm);
  180. sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(
  181. rasterImage, GrRenderable::kNo, 1, SkBudgeted::kNo, SkBackingFit::kExact);
  182. if (!proxy) {
  183. return;
  184. }
  185. sk_sp<SkSpecialImage> gpuImage(SkSpecialImage::MakeDeferredFromGpu(
  186. context,
  187. SkIRect::MakeWH(kFullSize, kFullSize),
  188. kNeedNewImageUniqueID_SpecialImage,
  189. std::move(proxy), nullptr));
  190. {
  191. sk_sp<SkSpecialImage> fromGPU(gpuImage->makeTextureImage(context));
  192. test_texture_backed(reporter, gpuImage, fromGPU);
  193. }
  194. {
  195. sk_sp<SkSpecialImage> subGPUImage(gpuImage->makeSubset(subset));
  196. sk_sp<SkSpecialImage> fromSubGPU(subGPUImage->makeTextureImage(context));
  197. test_texture_backed(reporter, subGPUImage, fromSubGPU);
  198. }
  199. }
  200. }
  201. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_Gpu, reporter, ctxInfo) {
  202. GrContext* context = ctxInfo.grContext();
  203. GrProxyProvider* proxyProvider = context->priv().proxyProvider();
  204. SkBitmap bm = create_bm();
  205. sk_sp<SkImage> rasterImage = SkImage::MakeFromBitmap(bm);
  206. sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(
  207. rasterImage, GrRenderable::kNo, 1, SkBudgeted::kNo, SkBackingFit::kExact);
  208. if (!proxy) {
  209. return;
  210. }
  211. sk_sp<SkSpecialImage> fullSImg(SkSpecialImage::MakeDeferredFromGpu(
  212. context,
  213. SkIRect::MakeWH(kFullSize, kFullSize),
  214. kNeedNewImageUniqueID_SpecialImage,
  215. proxy, nullptr));
  216. const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
  217. {
  218. sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeDeferredFromGpu(
  219. context, subset,
  220. kNeedNewImageUniqueID_SpecialImage,
  221. std::move(proxy), nullptr));
  222. test_image(subSImg1, reporter, context, true);
  223. }
  224. {
  225. sk_sp<SkSpecialImage> subSImg2(fullSImg->makeSubset(subset));
  226. test_image(subSImg2, reporter, context, true);
  227. }
  228. }
  229. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_ReadbackAndCachingSubsets_Gpu, reporter, ctxInfo) {
  230. GrContext* context = ctxInfo.grContext();
  231. SkImageInfo ii = SkImageInfo::Make(50, 50, kN32_SkColorType, kPremul_SkAlphaType);
  232. auto surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, ii);
  233. // Fill out our surface:
  234. // Green | Blue
  235. // Red | Green
  236. {
  237. surface->getCanvas()->clear(SK_ColorGREEN);
  238. SkPaint p;
  239. p.setColor(SK_ColorRED);
  240. surface->getCanvas()->drawRect(SkRect::MakeXYWH(0, 25, 25, 25), p);
  241. p.setColor(SK_ColorBLUE);
  242. surface->getCanvas()->drawRect(SkRect::MakeXYWH(25, 0, 25, 25), p);
  243. }
  244. auto image = surface->makeImageSnapshot();
  245. auto redImg = SkSpecialImage::MakeFromImage(context, SkIRect::MakeXYWH(10, 30, 10, 10), image);
  246. auto blueImg = SkSpecialImage::MakeFromImage(context, SkIRect::MakeXYWH(30, 10, 10, 10), image);
  247. // This isn't necessary, but if it ever becomes false, then the cache collision bug that we're
  248. // checking below is irrelevant.
  249. REPORTER_ASSERT(reporter, redImg->uniqueID() == blueImg->uniqueID());
  250. SkBitmap redBM, blueBM;
  251. SkAssertResult(redImg->getROPixels(&redBM));
  252. SkAssertResult(blueImg->getROPixels(&blueBM));
  253. // Each image should read from the correct sub-rect. Past bugs (skbug.com/8448) have included:
  254. // - Always reading back from (0, 0), producing green
  255. // - Incorrectly hitting the cache on the 2nd read-back, causing blueBM to be red
  256. REPORTER_ASSERT(reporter, redBM.getColor(0, 0) == SK_ColorRED,
  257. "0x%08x != 0x%08x", redBM.getColor(0, 0), SK_ColorRED);
  258. REPORTER_ASSERT(reporter, blueBM.getColor(0, 0) == SK_ColorBLUE,
  259. "0x%08x != 0x%08x", blueBM.getColor(0, 0), SK_ColorBLUE);
  260. }