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 8 #include "SkAutoPixmapStorage.h" 9 #include "SkBitmap.h" 10 #include "SkCanvas.h" 11 #include "SkImage.h" 12 #include "SkPixmap.h" 13 #include "SkSpecialImage.h" 14 #include "SkSpecialSurface.h" 15 #include "SkSurface.h" 16 #include "Test.h" 17 18 #if SK_SUPPORT_GPU 19 #include "GrContext.h" 20 #include "GrContextPriv.h" 21 #include "GrProxyProvider.h" 22 #include "GrSurfaceProxy.h" 23 #include "GrTextureProxy.h" 24 #include "SkGr.h" 25 #endif 26 27 28 // This test creates backing resources exactly sized to [kFullSize x kFullSize]. 29 // It then wraps them in an SkSpecialImage with only the center (red) region being active. 30 // It then draws the SkSpecialImage to a full sized (all blue) canvas and checks that none 31 // of the inactive (green) region leaked out. 32 33 static const int kSmallerSize = 10; 34 static const int kPad = 3; 35 static const int kFullSize = kSmallerSize + 2 * kPad; 36 37 // Create a bitmap with red in the center and green around it 38 static SkBitmap create_bm() { 39 SkBitmap bm; 40 bm.allocN32Pixels(kFullSize, kFullSize, true); 41 42 SkCanvas temp(bm); 43 44 temp.clear(SK_ColorGREEN); 45 SkPaint p; 46 p.setColor(SK_ColorRED); 47 p.setAntiAlias(false); 48 49 temp.drawRect(SkRect::MakeXYWH(SkIntToScalar(kPad), SkIntToScalar(kPad), 50 SkIntToScalar(kSmallerSize), SkIntToScalar(kSmallerSize)), 51 p); 52 53 return bm; 54 } 55 56 // Basic test of the SkSpecialImage public API (e.g., peekTexture, peekPixels & draw) 57 static void test_image(const sk_sp<SkSpecialImage>& img, skiatest::Reporter* reporter, 58 GrContext* context, bool isGPUBacked, 59 int offset, int size) { 60 const SkIRect subset = img->subset(); 61 REPORTER_ASSERT(reporter, offset == subset.left()); 62 REPORTER_ASSERT(reporter, offset == subset.top()); 63 REPORTER_ASSERT(reporter, kSmallerSize == subset.width()); 64 REPORTER_ASSERT(reporter, kSmallerSize == subset.height()); 65 66 //-------------- 67 // Test that isTextureBacked reports the correct backing type 68 REPORTER_ASSERT(reporter, isGPUBacked == img->isTextureBacked()); 69 70 #if SK_SUPPORT_GPU 71 //-------------- 72 // Test asTextureProxyRef - as long as there is a context this should succeed 73 if (context) { 74 sk_sp<GrTextureProxy> proxy(img->asTextureProxyRef(context)); 75 REPORTER_ASSERT(reporter, proxy); 76 } 77 #endif 78 79 //-------------- 80 // Test getROPixels - this should always succeed regardless of backing store 81 SkBitmap bitmap; 82 REPORTER_ASSERT(reporter, img->getROPixels(&bitmap)); 83 if (context) { 84 REPORTER_ASSERT(reporter, kSmallerSize == bitmap.width()); 85 REPORTER_ASSERT(reporter, kSmallerSize == bitmap.height()); 86 } else { 87 REPORTER_ASSERT(reporter, size == bitmap.width()); 88 REPORTER_ASSERT(reporter, size == bitmap.height()); 89 } 90 91 //-------------- 92 // Test that draw restricts itself to the subset 93 SkImageFilter::OutputProperties outProps(img->getColorSpace()); 94 sk_sp<SkSpecialSurface> surf(img->makeSurface(outProps, SkISize::Make(kFullSize, kFullSize), 95 kPremul_SkAlphaType)); 96 97 SkCanvas* canvas = surf->getCanvas(); 98 99 canvas->clear(SK_ColorBLUE); 100 img->draw(canvas, SkIntToScalar(kPad), SkIntToScalar(kPad), nullptr); 101 102 SkBitmap bm; 103 bm.allocN32Pixels(kFullSize, kFullSize, false); 104 105 bool result = canvas->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), 0, 0); 106 SkASSERT_RELEASE(result); 107 108 // Only the center (red) portion should've been drawn into the canvas 109 REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kPad-1, kPad-1)); 110 REPORTER_ASSERT(reporter, SK_ColorRED == bm.getColor(kPad, kPad)); 111 REPORTER_ASSERT(reporter, SK_ColorRED == bm.getColor(kSmallerSize+kPad-1, 112 kSmallerSize+kPad-1)); 113 REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kSmallerSize+kPad, 114 kSmallerSize+kPad)); 115 116 //-------------- 117 // Test that asImage & makeTightSurface return appropriately sized objects 118 // of the correct backing type 119 SkIRect newSubset = SkIRect::MakeWH(subset.width(), subset.height()); 120 { 121 sk_sp<SkImage> tightImg(img->asImage(&newSubset)); 122 123 REPORTER_ASSERT(reporter, tightImg->width() == subset.width()); 124 REPORTER_ASSERT(reporter, tightImg->height() == subset.height()); 125 REPORTER_ASSERT(reporter, isGPUBacked == tightImg->isTextureBacked()); 126 SkPixmap tmpPixmap; 127 REPORTER_ASSERT(reporter, isGPUBacked != !!tightImg->peekPixels(&tmpPixmap)); 128 } 129 { 130 SkImageFilter::OutputProperties outProps(img->getColorSpace()); 131 sk_sp<SkSurface> tightSurf(img->makeTightSurface(outProps, subset.size())); 132 133 REPORTER_ASSERT(reporter, tightSurf->width() == subset.width()); 134 REPORTER_ASSERT(reporter, tightSurf->height() == subset.height()); 135 REPORTER_ASSERT(reporter, isGPUBacked == 136 !!tightSurf->getTextureHandle(SkSurface::kDiscardWrite_BackendHandleAccess)); 137 SkPixmap tmpPixmap; 138 REPORTER_ASSERT(reporter, isGPUBacked != !!tightSurf->peekPixels(&tmpPixmap)); 139 } 140 } 141 142 DEF_TEST(SpecialImage_Raster, reporter) { 143 SkBitmap bm = create_bm(); 144 145 sk_sp<SkSpecialImage> fullSImage(SkSpecialImage::MakeFromRaster( 146 SkIRect::MakeWH(kFullSize, kFullSize), 147 bm)); 148 149 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize); 150 151 { 152 sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeFromRaster(subset, bm)); 153 test_image(subSImg1, reporter, nullptr, false, kPad, kFullSize); 154 } 155 156 { 157 sk_sp<SkSpecialImage> subSImg2(fullSImage->makeSubset(subset)); 158 test_image(subSImg2, reporter, nullptr, false, 0, kSmallerSize); 159 } 160 } 161 162 static void test_specialimage_image(skiatest::Reporter* reporter, SkColorSpace* dstColorSpace) { 163 SkBitmap bm = create_bm(); 164 165 sk_sp<SkImage> fullImage(SkImage::MakeFromBitmap(bm)); 166 167 sk_sp<SkSpecialImage> fullSImage(SkSpecialImage::MakeFromImage( 168 SkIRect::MakeWH(kFullSize, kFullSize), 169 fullImage, dstColorSpace)); 170 171 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize); 172 173 { 174 sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeFromImage(subset, fullImage, 175 dstColorSpace)); 176 test_image(subSImg1, reporter, nullptr, false, kPad, kFullSize); 177 } 178 179 { 180 sk_sp<SkSpecialImage> subSImg2(fullSImage->makeSubset(subset)); 181 test_image(subSImg2, reporter, nullptr, false, 0, kSmallerSize); 182 } 183 } 184 185 DEF_TEST(SpecialImage_Image_Legacy, reporter) { 186 SkColorSpace* legacyColorSpace = nullptr; 187 test_specialimage_image(reporter, legacyColorSpace); 188 } 189 190 DEF_TEST(SpecialImage_Image_ColorSpaceAware, reporter) { 191 sk_sp<SkColorSpace> srgbColorSpace = SkColorSpace::MakeSRGB(); 192 test_specialimage_image(reporter, srgbColorSpace.get()); 193 } 194 195 #if SK_SUPPORT_GPU 196 197 static void test_texture_backed(skiatest::Reporter* reporter, 198 const sk_sp<SkSpecialImage>& orig, 199 const sk_sp<SkSpecialImage>& gpuBacked) { 200 REPORTER_ASSERT(reporter, gpuBacked); 201 REPORTER_ASSERT(reporter, gpuBacked->isTextureBacked()); 202 REPORTER_ASSERT(reporter, gpuBacked->uniqueID() == orig->uniqueID()); 203 REPORTER_ASSERT(reporter, gpuBacked->subset().width() == orig->subset().width() && 204 gpuBacked->subset().height() == orig->subset().height()); 205 REPORTER_ASSERT(reporter, gpuBacked->getColorSpace() == orig->getColorSpace()); 206 } 207 208 // Test out the SkSpecialImage::makeTextureImage entry point 209 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_MakeTexture, reporter, ctxInfo) { 210 GrContext* context = ctxInfo.grContext(); 211 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); 212 SkBitmap bm = create_bm(); 213 214 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize); 215 216 { 217 // raster 218 sk_sp<SkSpecialImage> rasterImage(SkSpecialImage::MakeFromRaster( 219 SkIRect::MakeWH(kFullSize, 220 kFullSize), 221 bm)); 222 223 { 224 sk_sp<SkSpecialImage> fromRaster(rasterImage->makeTextureImage(context)); 225 test_texture_backed(reporter, rasterImage, fromRaster); 226 } 227 228 { 229 sk_sp<SkSpecialImage> subRasterImage(rasterImage->makeSubset(subset)); 230 231 sk_sp<SkSpecialImage> fromSubRaster(subRasterImage->makeTextureImage(context)); 232 test_texture_backed(reporter, subRasterImage, fromSubRaster); 233 } 234 } 235 236 { 237 // gpu 238 const GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bm.info(), *context->caps()); 239 240 sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy( 241 desc, SkBudgeted::kNo, bm.getPixels(), bm.rowBytes()); 242 if (!proxy) { 243 return; 244 } 245 246 sk_sp<SkSpecialImage> gpuImage(SkSpecialImage::MakeDeferredFromGpu( 247 context, 248 SkIRect::MakeWH(kFullSize, kFullSize), 249 kNeedNewImageUniqueID_SpecialImage, 250 std::move(proxy), nullptr)); 251 252 { 253 sk_sp<SkSpecialImage> fromGPU(gpuImage->makeTextureImage(context)); 254 test_texture_backed(reporter, gpuImage, fromGPU); 255 } 256 257 { 258 sk_sp<SkSpecialImage> subGPUImage(gpuImage->makeSubset(subset)); 259 260 sk_sp<SkSpecialImage> fromSubGPU(subGPUImage->makeTextureImage(context)); 261 test_texture_backed(reporter, subGPUImage, fromSubGPU); 262 } 263 } 264 } 265 266 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_Gpu, reporter, ctxInfo) { 267 GrContext* context = ctxInfo.grContext(); 268 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); 269 SkBitmap bm = create_bm(); 270 271 const GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bm.info(), *context->caps()); 272 273 sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy( 274 desc, SkBudgeted::kNo, bm.getPixels(), bm.rowBytes()); 275 if (!proxy) { 276 return; 277 } 278 279 sk_sp<SkSpecialImage> fullSImg(SkSpecialImage::MakeDeferredFromGpu( 280 context, 281 SkIRect::MakeWH(kFullSize, kFullSize), 282 kNeedNewImageUniqueID_SpecialImage, 283 proxy, nullptr)); 284 285 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize); 286 287 { 288 sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeDeferredFromGpu( 289 context, subset, 290 kNeedNewImageUniqueID_SpecialImage, 291 std::move(proxy), nullptr)); 292 test_image(subSImg1, reporter, context, true, kPad, kFullSize); 293 } 294 295 { 296 sk_sp<SkSpecialImage> subSImg2(fullSImg->makeSubset(subset)); 297 test_image(subSImg2, reporter, context, true, kPad, kFullSize); 298 } 299 } 300 301 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_DeferredGpu, reporter, ctxInfo) { 302 GrContext* context = ctxInfo.grContext(); 303 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); 304 SkBitmap bm = create_bm(); 305 306 GrSurfaceDesc desc; 307 desc.fFlags = kNone_GrSurfaceFlags; 308 desc.fOrigin = kTopLeft_GrSurfaceOrigin; 309 desc.fWidth = kFullSize; 310 desc.fHeight = kFullSize; 311 desc.fConfig = kSkia8888_GrPixelConfig; 312 313 sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy( 314 desc, SkBudgeted::kNo, bm.getPixels(), bm.rowBytes()); 315 if (!proxy) { 316 return; 317 } 318 319 sk_sp<SkSpecialImage> fullSImg(SkSpecialImage::MakeDeferredFromGpu( 320 context, 321 SkIRect::MakeWH(kFullSize, kFullSize), 322 kNeedNewImageUniqueID_SpecialImage, 323 proxy, nullptr)); 324 325 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize); 326 327 { 328 sk_sp<SkSpecialImage> subSImg1(SkSpecialImage::MakeDeferredFromGpu( 329 context, subset, 330 kNeedNewImageUniqueID_SpecialImage, 331 std::move(proxy), nullptr)); 332 test_image(subSImg1, reporter, context, true, kPad, kFullSize); 333 } 334 335 { 336 sk_sp<SkSpecialImage> subSImg2(fullSImg->makeSubset(subset)); 337 test_image(subSImg2, reporter, context, true, kPad, kFullSize); 338 } 339 } 340 341 #endif 342