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 #include "gl/GrGLDefines.h" 24 #ifdef SK_VULKAN 25 #include "vk/GrVkDefines.h" 26 #endif 27 28 static GrBackendFormat create_backend_format(GrContext* context, SkColorType colorType) { 29 const GrCaps* caps = context->caps(); 30 31 switch (context->contextPriv().getBackend()) { 32 case kOpenGL_GrBackend: 33 if (kRGBA_8888_SkColorType == colorType) { 34 GrGLenum format = caps->srgbSupport() ? GR_GL_SRGB8_ALPHA8 : GR_GL_RGBA8; 35 return GrBackendFormat::MakeGL(format, GR_GL_TEXTURE_2D); 36 } else if (kRGBA_F16_SkColorType == colorType) { 37 return GrBackendFormat::MakeGL(GR_GL_RGBA16F, GR_GL_TEXTURE_2D); 38 } 39 break; 40 #ifdef SK_VULKAN 41 case kVulkan_GrBackend: 42 if (kRGBA_8888_SkColorType == colorType) { 43 VkFormat format = caps->srgbSupport() ? VK_FORMAT_R8G8B8A8_SRGB 44 : VK_FORMAT_R8G8B8A8_UNORM; 45 return GrBackendFormat::MakeVK(format); 46 } else if (kRGBA_F16_SkColorType == colorType) { 47 return GrBackendFormat::MakeVK(VK_FORMAT_R16G16B16A16_SFLOAT); 48 } 49 break; 50 #endif 51 case kMock_GrBackend: 52 if (kRGBA_8888_SkColorType == colorType) { 53 GrPixelConfig config = caps->srgbSupport() ? kSRGBA_8888_GrPixelConfig 54 : kRGBA_8888_GrPixelConfig; 55 return GrBackendFormat::MakeMock(config); 56 } else if (kRGBA_F16_SkColorType == colorType) { 57 return GrBackendFormat::MakeMock(kRGBA_half_GrPixelConfig); 58 } 59 break; 60 default: 61 return GrBackendFormat(); // return an invalid format 62 } 63 64 return GrBackendFormat(); // return an invalid format 65 } 66 67 68 class SurfaceParameters { 69 public: 70 static const int kNumParams = 9; 71 static const int kSampleCount = 5; 72 static const int kMipMipCount = 8; 73 74 SurfaceParameters() 75 : fWidth(64) 76 , fHeight(64) 77 , fOrigin(kTopLeft_GrSurfaceOrigin) 78 , fColorType(kRGBA_8888_SkColorType) 79 , fColorSpace(SkColorSpace::MakeSRGB()) 80 , fSampleCount(1) 81 , fSurfaceProps(0x0, kUnknown_SkPixelGeometry) 82 , fShouldCreateMipMaps(true) { 83 } 84 85 int sampleCount() const { return fSampleCount; } 86 87 // Modify the SurfaceParameters in just one way 88 void modify(int i) { 89 switch (i) { 90 case 0: 91 fWidth = 63; 92 break; 93 case 1: 94 fHeight = 63; 95 break; 96 case 2: 97 fOrigin = kBottomLeft_GrSurfaceOrigin; 98 break; 99 case 3: 100 fColorType = kRGBA_F16_SkColorType; 101 break; 102 case 4: 103 fColorSpace = SkColorSpace::MakeSRGBLinear(); 104 break; 105 case kSampleCount: 106 fSampleCount = 4; 107 break; 108 case 6: 109 fSurfaceProps = SkSurfaceProps(0x0, kRGB_H_SkPixelGeometry); 110 break; 111 case 7: 112 fSurfaceProps = SkSurfaceProps(SkSurfaceProps::kUseDeviceIndependentFonts_Flag, 113 kUnknown_SkPixelGeometry); 114 break; 115 case 8: 116 fShouldCreateMipMaps = false; 117 break; 118 } 119 } 120 121 // Create a DDL whose characterization captures the current settings 122 std::unique_ptr<SkDeferredDisplayList> createDDL(GrContext* context) const { 123 sk_sp<SkSurface> s = this->make(context); 124 if (!s) { 125 return nullptr; 126 } 127 128 int maxResourceCount; 129 size_t maxResourceBytes; 130 context->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes); 131 132 // Note that Ganesh doesn't make use of the SkImageInfo's alphaType 133 SkImageInfo ii = SkImageInfo::Make(fWidth, fHeight, fColorType, 134 kPremul_SkAlphaType, fColorSpace); 135 136 GrBackendFormat backendFormat = create_backend_format(context, fColorType); 137 138 SkSurfaceCharacterization c = context->threadSafeProxy()->createCharacterization( 139 maxResourceBytes, ii, backendFormat, fSampleCount, 140 fOrigin, fSurfaceProps, fShouldCreateMipMaps); 141 SkAssertResult(c.isValid()); 142 143 SkDeferredDisplayListRecorder r(c); 144 SkCanvas* canvas = r.getCanvas(); 145 if (!canvas) { 146 return nullptr; 147 } 148 149 canvas->drawRect(SkRect::MakeXYWH(10, 10, 10, 10), SkPaint()); 150 return r.detach(); 151 } 152 153 // Create the surface with the current set of parameters 154 sk_sp<SkSurface> make(GrContext* context) const { 155 // Note that Ganesh doesn't make use of the SkImageInfo's alphaType 156 SkImageInfo ii = SkImageInfo::Make(fWidth, fHeight, fColorType, 157 kPremul_SkAlphaType, fColorSpace); 158 159 return SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, ii, fSampleCount, 160 fOrigin, &fSurfaceProps, fShouldCreateMipMaps); 161 } 162 163 // Create a surface w/ the current parameters but make it non-textureable 164 sk_sp<SkSurface> makeNonTextureable(GrContext* context, GrBackendTexture* backend) const { 165 GrGpu* gpu = context->contextPriv().getGpu(); 166 167 GrPixelConfig config = SkImageInfo2GrPixelConfig(fColorType, nullptr, *context->caps()); 168 SkASSERT(kUnknown_GrPixelConfig != config); 169 170 *backend = gpu->createTestingOnlyBackendTexture(nullptr, fWidth, fHeight, 171 config, true, GrMipMapped::kNo); 172 173 if (!backend->isValid() || !gpu->isTestingOnlyBackendTexture(*backend)) { 174 return nullptr; 175 } 176 177 sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTextureAsRenderTarget( 178 context, *backend, fOrigin, fSampleCount, fColorType, nullptr, nullptr); 179 180 if (!surface) { 181 gpu->deleteTestingOnlyBackendTexture(backend); 182 return nullptr; 183 } 184 185 return surface; 186 } 187 188 void cleanUpBackEnd(GrContext* context, GrBackendTexture* backend) const { 189 GrGpu* gpu = context->contextPriv().getGpu(); 190 191 gpu->deleteTestingOnlyBackendTexture(backend); 192 } 193 194 private: 195 int fWidth; 196 int fHeight; 197 GrSurfaceOrigin fOrigin; 198 SkColorType fColorType; 199 sk_sp<SkColorSpace> fColorSpace; 200 int fSampleCount; 201 SkSurfaceProps fSurfaceProps; 202 bool fShouldCreateMipMaps; 203 }; 204 205 // This tests SkSurfaceCharacterization/SkSurface compatibility 206 DEF_GPUTEST_FOR_ALL_CONTEXTS(DDLSurfaceCharacterizationTest, reporter, ctxInfo) { 207 GrContext* context = ctxInfo.grContext(); 208 209 // Create a bitmap that we can readback into 210 SkImageInfo imageInfo = SkImageInfo::Make(64, 64, kRGBA_8888_SkColorType, 211 kPremul_SkAlphaType); 212 SkBitmap bitmap; 213 bitmap.allocPixels(imageInfo); 214 215 std::unique_ptr<SkDeferredDisplayList> ddl; 216 217 // First, create a DDL using the stock SkSurface parameters 218 { 219 SurfaceParameters params; 220 221 ddl = params.createDDL(context); 222 SkAssertResult(ddl); 223 224 // The DDL should draw into an SkSurface created with the same parameters 225 sk_sp<SkSurface> s = params.make(context); 226 if (!s) { 227 return; 228 } 229 230 REPORTER_ASSERT(reporter, s->draw(ddl.get())); 231 s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0); 232 } 233 234 // Then, alter each parameter in turn and check that the DDL & surface are incompatible 235 for (int i = 0; i < SurfaceParameters::kNumParams; ++i) { 236 SurfaceParameters params; 237 params.modify(i); 238 239 sk_sp<SkSurface> s = params.make(context); 240 if (!s) { 241 continue; 242 } 243 244 if (SurfaceParameters::kSampleCount == i) { 245 SkSurface_Gpu* gpuSurf = static_cast<SkSurface_Gpu*>(s.get()); 246 247 int supportedSampleCount = context->caps()->getRenderTargetSampleCount( 248 params.sampleCount(), 249 gpuSurf->getDevice()->accessRenderTargetContext()->asRenderTargetProxy()->config()); 250 if (1 == supportedSampleCount) { 251 // If changing the sample count won't result in a different 252 // surface characterization, skip this step 253 continue; 254 } 255 } 256 257 if (SurfaceParameters::kMipMipCount == i && !context->caps()->mipMapSupport()) { 258 continue; 259 } 260 261 REPORTER_ASSERT(reporter, !s->draw(ddl.get()), 262 "DDLSurfaceCharacterizationTest failed on parameter: %d\n", i); 263 } 264 265 // Next test the compatibility of resource cache parameters 266 { 267 const SurfaceParameters params; 268 sk_sp<SkSurface> s = params.make(context); 269 270 int maxResourceCount; 271 size_t maxResourceBytes; 272 context->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes); 273 274 context->setResourceCacheLimits(maxResourceCount, maxResourceBytes/2); 275 REPORTER_ASSERT(reporter, !s->draw(ddl.get())); 276 277 // DDL TODO: once proxies/ops can be de-instantiated we can re-enable these tests. 278 // For now, DDLs are drawn once. 279 #if 0 280 // resource limits >= those at characterization time are accepted 281 context->setResourceCacheLimits(2*maxResourceCount, maxResourceBytes); 282 REPORTER_ASSERT(reporter, s->draw(ddl.get())); 283 s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0); 284 285 context->setResourceCacheLimits(maxResourceCount, 2*maxResourceBytes); 286 REPORTER_ASSERT(reporter, s->draw(ddl.get())); 287 s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0); 288 289 context->setResourceCacheLimits(maxResourceCount, maxResourceBytes); 290 REPORTER_ASSERT(reporter, s->draw(ddl.get())); 291 s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0); 292 #endif 293 } 294 295 // Test that the textureability of the DDL characterization can block a DDL draw 296 { 297 GrBackendTexture backend; 298 const SurfaceParameters params; 299 sk_sp<SkSurface> s = params.makeNonTextureable(context, &backend); 300 if (s) { 301 REPORTER_ASSERT(reporter, !s->draw(ddl.get())); 302 303 s = nullptr; 304 params.cleanUpBackEnd(context, &backend); 305 } 306 } 307 308 // Make sure non-GPU-backed surfaces fail characterization 309 { 310 SkImageInfo ii = SkImageInfo::MakeN32(64, 64, kOpaque_SkAlphaType); 311 312 sk_sp<SkSurface> rasterSurface = SkSurface::MakeRaster(ii); 313 SkSurfaceCharacterization c; 314 REPORTER_ASSERT(reporter, !rasterSurface->characterize(&c)); 315 } 316 } 317 318 static constexpr int kSize = 8; 319 320 struct TextureReleaseChecker { 321 TextureReleaseChecker() : fReleaseCount(0) {} 322 int fReleaseCount; 323 static void Release(void* self) { 324 static_cast<TextureReleaseChecker*>(self)->fReleaseCount++; 325 } 326 }; 327 328 enum class DDLStage { kMakeImage, kDrawImage, kDetach, kDrawDDL }; 329 330 // This tests the ability to create and use wrapped textures in a DDL world 331 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLWrapBackendTest, reporter, ctxInfo) { 332 GrContext* context = ctxInfo.grContext(); 333 GrGpu* gpu = context->contextPriv().getGpu(); 334 for (auto lastStage : { DDLStage::kMakeImage, DDLStage::kDrawImage, 335 DDLStage::kDetach, DDLStage::kDrawDDL } ) { 336 for (auto earlyImageReset : { false , true } ) { 337 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture( 338 nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig, false, GrMipMapped::kNo); 339 if (!backendTex.isValid()) { 340 continue; 341 } 342 343 SurfaceParameters params; 344 345 sk_sp<SkSurface> s = params.make(context); 346 if (!s) { 347 gpu->deleteTestingOnlyBackendTexture(&backendTex); 348 continue; 349 } 350 351 SkSurfaceCharacterization c; 352 SkAssertResult(s->characterize(&c)); 353 354 std::unique_ptr<SkDeferredDisplayListRecorder> recorder( 355 new SkDeferredDisplayListRecorder(c)); 356 357 SkCanvas* canvas = recorder->getCanvas(); 358 if (!canvas) { 359 gpu->deleteTestingOnlyBackendTexture(&backendTex); 360 continue; 361 } 362 363 GrContext* deferredContext = canvas->getGrContext(); 364 if (!deferredContext) { 365 gpu->deleteTestingOnlyBackendTexture(&backendTex); 366 continue; 367 } 368 369 sk_sp<SkImage> image = SkImage::MakeFromAdoptedTexture(deferredContext, backendTex, 370 kTopLeft_GrSurfaceOrigin, 371 kRGBA_8888_SkColorType, 372 kPremul_SkAlphaType, nullptr); 373 // Adopted Textures are not supported in DDL 374 REPORTER_ASSERT(reporter, !image); 375 376 TextureReleaseChecker releaseChecker; 377 image = SkImage::MakeFromTexture(deferredContext, backendTex, 378 kTopLeft_GrSurfaceOrigin, 379 kRGBA_8888_SkColorType, 380 kPremul_SkAlphaType, nullptr, 381 TextureReleaseChecker::Release, &releaseChecker); 382 383 REPORTER_ASSERT(reporter, image); 384 if (!image) { 385 gpu->deleteTestingOnlyBackendTexture(&backendTex); 386 continue; 387 } 388 389 if (DDLStage::kMakeImage == lastStage) { 390 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 391 image.reset(); 392 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount); 393 recorder.reset(); 394 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount); 395 gpu->deleteTestingOnlyBackendTexture(&backendTex); 396 continue; 397 } 398 399 canvas->drawImage(image.get(), 0, 0); 400 401 if (earlyImageReset) { 402 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 403 image.reset(); 404 // Ref should still be held by DDL recorder since we did the draw 405 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 406 } 407 408 if (DDLStage::kDrawImage == lastStage) { 409 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 410 recorder.reset(); 411 if (earlyImageReset) { 412 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount); 413 } else { 414 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 415 image.reset(); 416 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount); 417 } 418 gpu->deleteTestingOnlyBackendTexture(&backendTex); 419 continue; 420 } 421 422 std::unique_ptr<SkDeferredDisplayList> ddl = recorder->detach(); 423 if (DDLStage::kDetach == lastStage) { 424 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 425 recorder.reset(); 426 #ifndef SK_RASTER_RECORDER_IMPLEMENTATION 427 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 428 #endif 429 ddl.reset(); 430 if (earlyImageReset) { 431 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount); 432 } else { 433 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 434 image.reset(); 435 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount); 436 } 437 gpu->deleteTestingOnlyBackendTexture(&backendTex); 438 continue; 439 } 440 441 REPORTER_ASSERT(reporter, s->draw(ddl.get())); 442 443 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 444 recorder.reset(); 445 #ifndef SK_RASTER_RECORDER_IMPLEMENTATION 446 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 447 #endif 448 ddl.reset(); 449 #ifndef SK_RASTER_RECORDER_IMPLEMENTATION 450 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 451 #endif 452 453 // Force all draws to flush and sync by calling a read pixels 454 SkImageInfo imageInfo = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType, 455 kPremul_SkAlphaType); 456 SkBitmap bitmap; 457 bitmap.allocPixels(imageInfo); 458 s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0); 459 460 if (earlyImageReset) { 461 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount); 462 } else { 463 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount); 464 image.reset(); 465 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount); 466 } 467 468 gpu->deleteTestingOnlyBackendTexture(&backendTex); 469 } 470 } 471 } 472 473 474 #endif 475