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