1 /* 2 * Copyright 2017 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 "SkTypes.h" 9 10 #if SK_SUPPORT_GPU 11 12 #include "GrBackendSurface.h" 13 #include "GrGpu.h" 14 #include "SkCanvas.h" 15 #include "SkDeferredDisplayListRecorder.h" 16 #include "SkGpuDevice.h" 17 #include "SkSurface.h" 18 #include "SkSurface_Gpu.h" 19 #include "SkSurfaceCharacterization.h" 20 #include "SkSurfaceProps.h" 21 #include "Test.h" 22 23 class SurfaceParameters { 24 public: 25 static const int kNumParams = 8; 26 static const int kSampleCount = 5; 27 28 SurfaceParameters() 29 : fWidth(64) 30 , fHeight(64) 31 , fOrigin(kTopLeft_GrSurfaceOrigin) 32 , fColorType(kRGBA_8888_SkColorType) 33 , fColorSpace(SkColorSpace::MakeSRGB()) 34 , fSampleCount(1) 35 , fSurfaceProps(0x0, kUnknown_SkPixelGeometry) {} 36 37 int sampleCount() const { return fSampleCount; } 38 39 // Modify the SurfaceParameters in just one way 40 void modify(int i) { 41 switch (i) { 42 case 0: 43 fWidth = 63; 44 break; 45 case 1: 46 fHeight = 63; 47 break; 48 case 2: 49 fOrigin = kBottomLeft_GrSurfaceOrigin; 50 break; 51 case 3: 52 fColorType = kRGBA_F16_SkColorType; 53 break; 54 case 4: 55 fColorSpace = SkColorSpace::MakeSRGBLinear(); 56 break; 57 case kSampleCount: 58 fSampleCount = 4; 59 break; 60 case 6: 61 fSurfaceProps = SkSurfaceProps(0x0, kRGB_H_SkPixelGeometry); 62 break; 63 case 7: 64 fSurfaceProps = SkSurfaceProps(SkSurfaceProps::kUseDeviceIndependentFonts_Flag, 65 kUnknown_SkPixelGeometry); 66 break; 67 } 68 } 69 70 // Create the surface with the current set of parameters 71 sk_sp<SkSurface> make(GrContext* context) const { 72 // Note that Ganesh doesn't make use of the SkImageInfo's alphaType 73 SkImageInfo ii = SkImageInfo::Make(fWidth, fHeight, fColorType, 74 kPremul_SkAlphaType, fColorSpace); 75 76 return SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, ii, fSampleCount, 77 fOrigin, &fSurfaceProps); 78 } 79 80 private: 81 int fWidth; 82 int fHeight; 83 GrSurfaceOrigin fOrigin; 84 SkColorType fColorType; 85 sk_sp<SkColorSpace> fColorSpace; 86 int fSampleCount; 87 SkSurfaceProps fSurfaceProps; 88 }; 89 90 // This tests SkSurfaceCharacterization/SkSurface compatibility 91 DEF_GPUTEST_FOR_ALL_CONTEXTS(SkSurfaceCharacterization, reporter, ctxInfo) { 92 GrContext* context = ctxInfo.grContext(); 93 94 // Create a bitmap that we can readback into 95 SkImageInfo imageInfo = SkImageInfo::Make(64, 64, kRGBA_8888_SkColorType, 96 kPremul_SkAlphaType); 97 SkBitmap bitmap; 98 bitmap.allocPixels(imageInfo); 99 100 std::unique_ptr<SkDeferredDisplayList> ddl; 101 102 // First, create a DDL using the stock SkSurface parameters 103 { 104 SurfaceParameters params; 105 106 sk_sp<SkSurface> s = params.make(context); 107 if (!s) { 108 return; 109 } 110 111 SkSurfaceCharacterization c; 112 SkAssertResult(s->characterize(&c)); 113 114 SkDeferredDisplayListRecorder r(c); 115 SkCanvas* canvas = r.getCanvas(); 116 if (!canvas) { 117 return; 118 } 119 120 canvas->drawRect(SkRect::MakeXYWH(10, 10, 10, 10), SkPaint()); 121 ddl = r.detach(); 122 123 REPORTER_ASSERT(reporter, s->draw(ddl.get())); 124 s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0); 125 } 126 127 // Then, alter each parameter in turn and check that the DDL & surface are incompatible 128 for (int i = 0; i < SurfaceParameters::kNumParams; ++i) { 129 SurfaceParameters params; 130 params.modify(i); 131 132 sk_sp<SkSurface> s = params.make(context); 133 if (!s) { 134 continue; 135 } 136 137 if (SurfaceParameters::kSampleCount == i) { 138 SkSurface_Gpu* gpuSurf = static_cast<SkSurface_Gpu*>(s.get()); 139 140 int supportedSampleCount = context->caps()->getSampleCount( 141 params.sampleCount(), 142 gpuSurf->getDevice()->accessRenderTargetContext()->asRenderTargetProxy()->config()); 143 if (1 == supportedSampleCount) { 144 // If changing the sample count won't result in a different 145 // surface characterization, skip this step 146 continue; 147 } 148 } 149 150 REPORTER_ASSERT(reporter, !s->draw(ddl.get())); 151 } 152 153 // Next test the compatibility of resource cache parameters 154 { 155 const SurfaceParameters params; 156 sk_sp<SkSurface> s = params.make(context); 157 158 int maxResourceCount; 159 size_t maxResourceBytes; 160 context->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes); 161 162 context->setResourceCacheLimits(maxResourceCount/2, maxResourceBytes); 163 REPORTER_ASSERT(reporter, !s->draw(ddl.get())); 164 165 context->setResourceCacheLimits(maxResourceCount, maxResourceBytes/2); 166 REPORTER_ASSERT(reporter, !s->draw(ddl.get())); 167 168 // DDL TODO: once proxies/ops can be de-instantiated we can re-enable these tests. 169 // For now, DDLs are drawn once. 170 #if 0 171 // resource limits >= those at characterization time are accepted 172 context->setResourceCacheLimits(2*maxResourceCount, maxResourceBytes); 173 REPORTER_ASSERT(reporter, s->draw(ddl.get())); 174 s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0); 175 176 context->setResourceCacheLimits(maxResourceCount, 2*maxResourceBytes); 177 REPORTER_ASSERT(reporter, s->draw(ddl.get())); 178 s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0); 179 180 context->setResourceCacheLimits(maxResourceCount, maxResourceBytes); 181 REPORTER_ASSERT(reporter, s->draw(ddl.get())); 182 s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0); 183 #endif 184 } 185 186 // Make sure non-GPU-backed surfaces fail characterization 187 { 188 SkImageInfo ii = SkImageInfo::MakeN32(64, 64, kOpaque_SkAlphaType); 189 190 sk_sp<SkSurface> rasterSurface = SkSurface::MakeRaster(ii); 191 SkSurfaceCharacterization c; 192 REPORTER_ASSERT(reporter, !rasterSurface->characterize(&c)); 193 } 194 } 195 196 static constexpr int kSize = 8; 197 198 struct TextureReleaseChecker { 199 TextureReleaseChecker() : fReleaseCount(0) {} 200 int fReleaseCount; 201 static void Release(void* self) { 202 static_cast<TextureReleaseChecker*>(self)->fReleaseCount++; 203 } 204 }; 205 206 enum class DDLStage { kMakeImage, kDrawImage, kDetach, kDrawDDL }; 207 208 // This tests the ability to create and use wrapped textures in a DDL world 209 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLWrapBackendTest, reporter, ctxInfo) { 210 GrContext* context = ctxInfo.grContext(); 211 GrGpu* gpu = context->contextPriv().getGpu(); 212 for (auto lastStage : { DDLStage::kMakeImage, DDLStage::kDrawImage, 213 DDLStage::kDetach, DDLStage::kDrawDDL } ) { 214 for (auto earlyImageReset : { false , true } ) { 215 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture( 216 nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig, false, GrMipMapped::kNo); 217 if (!backendTex.isValid()) { 218 continue; 219 } 220 221 SurfaceParameters params; 222 223 sk_sp<SkSurface> s = params.make(context); 224 if (!s) { 225 gpu->deleteTestingOnlyBackendTexture(&backendTex); 226 continue; 227 } 228 229 SkSurfaceCharacterization c; 230 SkAssertResult(s->characterize(&c)); 231 232 std::unique_ptr<SkDeferredDisplayListRecorder> recorder( 233 new SkDeferredDisplayListRecorder(c)); 234 235 SkCanvas* canvas = recorder->getCanvas(); 236 if (!canvas) { 237 gpu->deleteTestingOnlyBackendTexture(&backendTex); 238 continue; 239 } 240 241 GrContext* deferredContext = canvas->getGrContext(); 242 if (!deferredContext) { 243 gpu->deleteTestingOnlyBackendTexture(&backendTex); 244 continue; 245 } 246 247 sk_sp<SkImage> image = SkImage::MakeFromAdoptedTexture(deferredContext, backendTex, 248 kTopLeft_GrSurfaceOrigin, 249 kRGBA_8888_SkColorType, 250 kPremul_SkAlphaType, nullptr); 251 // Adopted Textures are not supported in DDL 252 REPORTER_ASSERT(reporter, !image); 253 254 TextureReleaseChecker releaseChecker; 255 image = SkImage::MakeFromTexture(deferredContext, backendTex, 256 kTopLeft_GrSurfaceOrigin, 257 kRGBA_8888_SkColorType, 258 kPremul_SkAlphaType, nullptr, 259 TextureReleaseChecker::Release, &releaseChecker); 260 261 REPORTER_ASSERT(reporter, image); 262 if (!image) { 263 gpu->deleteTestingOnlyBackendTexture(&backendTex); 264 continue; 265 } 266 267 if (DDLStage::kMakeImage == lastStage) { 268 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 269 image.reset(); 270 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount); 271 recorder.reset(); 272 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount); 273 gpu->deleteTestingOnlyBackendTexture(&backendTex); 274 continue; 275 } 276 277 canvas->drawImage(image.get(), 0, 0); 278 279 if (earlyImageReset) { 280 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 281 image.reset(); 282 // Ref should still be held by DDL recorder since we did the draw 283 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 284 } 285 286 if (DDLStage::kDrawImage == lastStage) { 287 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 288 recorder.reset(); 289 if (earlyImageReset) { 290 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount); 291 } else { 292 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 293 image.reset(); 294 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount); 295 } 296 gpu->deleteTestingOnlyBackendTexture(&backendTex); 297 continue; 298 } 299 300 std::unique_ptr<SkDeferredDisplayList> ddl = recorder->detach(); 301 if (DDLStage::kDetach == lastStage) { 302 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 303 recorder.reset(); 304 #ifndef SK_RASTER_RECORDER_IMPLEMENTATION 305 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 306 #endif 307 ddl.reset(); 308 if (earlyImageReset) { 309 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount); 310 } else { 311 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 312 image.reset(); 313 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount); 314 } 315 gpu->deleteTestingOnlyBackendTexture(&backendTex); 316 continue; 317 } 318 319 REPORTER_ASSERT(reporter, s->draw(ddl.get())); 320 321 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 322 recorder.reset(); 323 #ifndef SK_RASTER_RECORDER_IMPLEMENTATION 324 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 325 #endif 326 ddl.reset(); 327 #ifndef SK_RASTER_RECORDER_IMPLEMENTATION 328 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 329 #endif 330 331 // Force all draws to flush and sync by calling a read pixels 332 SkImageInfo imageInfo = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType, 333 kPremul_SkAlphaType); 334 SkBitmap bitmap; 335 bitmap.allocPixels(imageInfo); 336 s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0); 337 338 if (earlyImageReset) { 339 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount); 340 } else { 341 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 342 image.reset(); 343 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount); 344 } 345 346 gpu->deleteTestingOnlyBackendTexture(&backendTex); 347 } 348 } 349 } 350 351 352 #endif 353