1/* 2 * Copyright 2019 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 "include/core/SkCanvas.h" 9#include "include/core/SkSurface.h" 10#include "include/core/SkSurfaceCharacterization.h" 11#include "include/gpu/GrDirectContext.h" 12#include "src/core/SkAutoPixmapStorage.h" 13#include "src/gpu/GrDirectContextPriv.h" 14#include "src/gpu/GrProxyProvider.h" 15#include "src/gpu/SurfaceFillContext.h" 16#include "src/gpu/effects/GrBlendFragmentProcessor.h" 17#include "src/gpu/effects/GrTextureEffect.h" 18#include "src/image/SkImage_Base.h" 19#include "tests/Test.h" 20#include "tests/TestUtils.h" 21#include "tools/ToolUtils.h" 22#include "tools/gpu/ManagedBackendTexture.h" 23#include "tools/gpu/ProxyUtils.h" 24 25#ifdef SK_GL 26#include "src/gpu/gl/GrGLCaps.h" 27#include "src/gpu/gl/GrGLDefines.h" 28#include "src/gpu/gl/GrGLGpu.h" 29#include "src/gpu/gl/GrGLUtil.h" 30#endif 31 32#ifdef SK_METAL 33#include "include/gpu/mtl/GrMtlTypes.h" 34#include "src/gpu/mtl/GrMtlCppUtil.h" 35#endif 36 37using sk_gpu_test::ManagedBackendTexture; 38 39// Test wrapping of GrBackendObjects in SkSurfaces and SkImages (non-static since used in Mtl test) 40void test_wrapping(GrDirectContext* dContext, 41 skiatest::Reporter* reporter, 42 std::function<sk_sp<ManagedBackendTexture>(GrDirectContext*, 43 GrMipmapped, 44 GrRenderable)> create, 45 GrColorType grColorType, 46 GrMipmapped mipMapped, 47 GrRenderable renderable) { 48 GrResourceCache* cache = dContext->priv().getResourceCache(); 49 50 const int initialCount = cache->getResourceCount(); 51 52 sk_sp<ManagedBackendTexture> mbet = create(dContext, mipMapped, renderable); 53 if (!mbet) { 54 ERRORF(reporter, "Couldn't create backendTexture for grColorType %d renderable %s\n", 55 grColorType, 56 GrRenderable::kYes == renderable ? "yes" : "no"); 57 return; 58 } 59 60 // Skia proper should know nothing about the new backend object 61 REPORTER_ASSERT(reporter, initialCount == cache->getResourceCount()); 62 63 SkColorType skColorType = GrColorTypeToSkColorType(grColorType); 64 65 // Wrapping a backendTexture in an SkImage/SkSurface requires an SkColorType 66 if (skColorType == kUnknown_SkColorType) { 67 return; 68 } 69 70 // As we transition to using attachments instead of GrTextures and GrRenderTargets individual 71 // proxy instansiations may add multiple things to the cache. There would be an entry for the 72 // GrTexture/GrRenderTarget and entries for one or more attachments. 73 int cacheEntriesPerProxy = 1; 74 // We currently only have attachments on the vulkan and metal backends 75 if (dContext->backend() == GrBackend::kVulkan || dContext->backend() == GrBackend::kMetal) { 76 // If we ever make a rt with multisamples this would have an additional 77 // attachment as well. 78 cacheEntriesPerProxy++; 79 } 80 81 if (GrRenderable::kYes == renderable && dContext->colorTypeSupportedAsSurface(skColorType)) { 82 sk_sp<SkSurface> surf = SkSurface::MakeFromBackendTexture(dContext, 83 mbet->texture(), 84 kTopLeft_GrSurfaceOrigin, 85 0, 86 skColorType, 87 nullptr, nullptr); 88 if (!surf) { 89 ERRORF(reporter, "Couldn't make SkSurface from backendTexture for %s\n", 90 ToolUtils::colortype_name(skColorType)); 91 } else { 92 REPORTER_ASSERT(reporter, 93 initialCount + cacheEntriesPerProxy == cache->getResourceCount()); 94 } 95 } 96 97 { 98 sk_sp<SkImage> img = SkImage::MakeFromTexture(dContext, 99 mbet->texture(), 100 kTopLeft_GrSurfaceOrigin, 101 skColorType, 102 kUnpremul_SkAlphaType, 103 nullptr); 104 if (!img) { 105 ERRORF(reporter, "Couldn't make SkImage from backendTexture for %s\n", 106 ToolUtils::colortype_name(skColorType)); 107 } else { 108 GrTextureProxy* proxy = sk_gpu_test::GetTextureImageProxy(img.get(), dContext); 109 REPORTER_ASSERT(reporter, proxy); 110 111 REPORTER_ASSERT(reporter, mipMapped == proxy->proxyMipmapped()); 112 REPORTER_ASSERT(reporter, proxy->isInstantiated()); 113 REPORTER_ASSERT(reporter, mipMapped == proxy->mipmapped()); 114 115 REPORTER_ASSERT(reporter, 116 initialCount + cacheEntriesPerProxy == cache->getResourceCount()); 117 } 118 } 119 120 REPORTER_ASSERT(reporter, initialCount == cache->getResourceCount()); 121} 122 123static bool isBGRA8(const GrBackendFormat& format) { 124 switch (format.backend()) { 125 case GrBackendApi::kOpenGL: 126#ifdef SK_GL 127 return format.asGLFormat() == GrGLFormat::kBGRA8; 128#else 129 return false; 130#endif 131 case GrBackendApi::kVulkan: { 132#ifdef SK_VULKAN 133 VkFormat vkFormat; 134 format.asVkFormat(&vkFormat); 135 return vkFormat == VK_FORMAT_B8G8R8A8_UNORM; 136#else 137 return false; 138#endif 139 } 140 case GrBackendApi::kMetal: 141#ifdef SK_METAL 142 return GrMtlFormatIsBGRA8(format.asMtlFormat()); 143#else 144 return false; 145#endif 146 case GrBackendApi::kDirect3D: 147#ifdef SK_DIRECT3D 148 return false; // TODO 149#else 150 return false; 151#endif 152 case GrBackendApi::kDawn: 153#ifdef SK_DAWN 154 wgpu::TextureFormat dawnFormat; 155 format.asDawnFormat(&dawnFormat); 156 return dawnFormat == wgpu::TextureFormat::BGRA8Unorm; 157#else 158 return false; 159#endif 160 case GrBackendApi::kMock: { 161 SkImage::CompressionType compression = format.asMockCompressionType(); 162 if (compression != SkImage::CompressionType::kNone) { 163 return false; // No compressed formats are BGRA 164 } 165 166 return format.asMockColorType() == GrColorType::kBGRA_8888; 167 } 168 } 169 SkUNREACHABLE; 170} 171 172static bool isRGB(const GrBackendFormat& format) { 173 switch (format.backend()) { 174 case GrBackendApi::kOpenGL: 175#ifdef SK_GL 176 return format.asGLFormat() == GrGLFormat::kRGB8; 177#else 178 return false; 179#endif 180 case GrBackendApi::kVulkan: { 181#ifdef SK_VULKAN 182 VkFormat vkFormat; 183 format.asVkFormat(&vkFormat); 184 return vkFormat == VK_FORMAT_R8G8B8_UNORM; 185#else 186 return false; 187#endif 188 } 189 case GrBackendApi::kMetal: 190 return false; // Metal doesn't even pretend to support this 191 case GrBackendApi::kDirect3D: 192 return false; // Not supported in Direct3D 12 193 case GrBackendApi::kDawn: 194 return false; 195 case GrBackendApi::kMock: 196 return false; // No GrColorType::kRGB_888 197 } 198 SkUNREACHABLE; 199} 200 201static void check_solid_pixmap(skiatest::Reporter* reporter, 202 const SkColor4f& expected, 203 const SkPixmap& actual, 204 GrColorType ct, 205 const char* label1, 206 const char* label2) { 207 // we need 0.001f across the board just for noise 208 // we need 0.01f across the board for 1010102 209 const float tols[4] = { 0.01f, 0.01f, 0.01f, 0.01f }; 210 211 auto error = std::function<ComparePixmapsErrorReporter>( 212 [reporter, ct, label1, label2](int x, int y, const float diffs[4]) { 213 SkASSERT(x >= 0 && y >= 0); 214 ERRORF(reporter, "%s %s %s - mismatch at %d, %d (%f, %f, %f %f)", GrColorTypeToStr(ct), 215 label1, label2, x, y, diffs[0], diffs[1], diffs[2], diffs[3]); 216 }); 217 218 CheckSolidPixels(expected, actual, tols, error); 219} 220 221// Determine what color we expect if we store 'orig' in 'ct' converted back to SkColor4f. 222static SkColor4f get_expected_color(SkColor4f orig, GrColorType ct) { 223 GrImageInfo ii(ct, kUnpremul_SkAlphaType, nullptr, {1, 1}); 224 std::unique_ptr<char[]> data(new char[ii.minRowBytes()]); 225 GrClearImage(ii, data.get(), ii.minRowBytes(), orig.array()); 226 227 // Read back to SkColor4f. 228 SkColor4f result; 229 GrImageInfo resultII(GrColorType::kRGBA_F32, kUnpremul_SkAlphaType, nullptr, {1, 1}); 230 GrConvertPixels(GrPixmap(resultII, &result.fR, sizeof(result)), 231 GrPixmap( ii, data.get(), ii.minRowBytes())); 232 return result; 233} 234 235static void check_mipmaps(GrDirectContext*, 236 const GrBackendTexture&, 237 GrColorType, 238 const SkColor4f expectedColors[6], 239 skiatest::Reporter*, 240 const char* label); 241 242static void check_base_readbacks(GrDirectContext* dContext, 243 const GrBackendTexture& backendTex, 244 GrColorType colorType, 245 GrRenderable renderableTexture, 246 const SkColor4f& color, 247 skiatest::Reporter* reporter, 248 const char* label) { 249 if (isRGB(backendTex.getBackendFormat())) { 250 // readPixels is busted for the RGB backend format (skbug.com/8862) 251 // TODO: add a GrColorType::kRGB_888 to fix the situation 252 return; 253 } 254 255 SkColor4f expectedColor = get_expected_color(color, colorType); 256 257 SkAutoPixmapStorage actual; 258 259 { 260 SkImageInfo readBackII = SkImageInfo::Make(32, 32, 261 kRGBA_8888_SkColorType, 262 kUnpremul_SkAlphaType); 263 264 SkAssertResult(actual.tryAlloc(readBackII)); 265 } 266 for (GrRenderable renderableCtx : {GrRenderable::kNo, GrRenderable::kYes}) { 267 if (renderableCtx == GrRenderable::kYes && renderableTexture == GrRenderable::kNo) { 268 continue; 269 } 270 sk_sp<GrSurfaceProxy> proxy; 271 if (renderableCtx == GrRenderable::kYes) { 272 proxy = dContext->priv().proxyProvider()->wrapRenderableBackendTexture( 273 backendTex, 1, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, nullptr); 274 } else { 275 proxy = dContext->priv().proxyProvider()->wrapBackendTexture( 276 backendTex, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, kRW_GrIOType); 277 } 278 if (!proxy) { 279 ERRORF(reporter, "Could not make proxy from backend texture"); 280 return; 281 } 282 auto swizzle = dContext->priv().caps()->getReadSwizzle(backendTex.getBackendFormat(), 283 colorType); 284 GrSurfaceProxyView readView(proxy, kTopLeft_GrSurfaceOrigin, swizzle); 285 GrColorInfo info(colorType, kUnpremul_SkAlphaType, nullptr); 286 auto surfaceContext = dContext->priv().makeSC(readView, info); 287 if (!surfaceContext) { 288 ERRORF(reporter, "Could not create surface context for colorType: %d\n", colorType); 289 } 290 291 if (!surfaceContext->readPixels(dContext, actual, {0, 0})) { 292 // TODO: we need a better way to tell a priori if readPixels will work for an 293 // arbitrary colorType 294#if 0 295 ERRORF(reporter, "Couldn't readback from SurfaceContext for colorType: %d\n", 296 colorType); 297#endif 298 } else { 299 auto name = SkStringPrintf("%s::readPixels", 300 (renderableCtx == GrRenderable::kYes ? "SurfaceFillContext" 301 : "SurfaceContext")); 302 check_solid_pixmap(reporter, expectedColor, actual, colorType, label, name.c_str()); 303 } 304 } 305} 306 307// Test initialization of GrBackendObjects to a specific color (non-static since used in Mtl test) 308void test_color_init(GrDirectContext* dContext, 309 skiatest::Reporter* reporter, 310 std::function<sk_sp<ManagedBackendTexture>(GrDirectContext*, 311 const SkColor4f&, 312 GrMipmapped, 313 GrRenderable)> create, 314 GrColorType colorType, 315 const SkColor4f& color, 316 GrMipmapped mipmapped, 317 GrRenderable renderable) { 318 sk_sp<ManagedBackendTexture> mbet = create(dContext, color, mipmapped, renderable); 319 if (!mbet) { 320 // errors here should be reported by the test_wrapping test 321 return; 322 } 323 324 auto checkBackendTexture = [&](const SkColor4f& testColor) { 325 if (mipmapped == GrMipmapped::kYes) { 326 SkColor4f expectedColor = get_expected_color(testColor, colorType); 327 SkColor4f expectedColors[6] = {expectedColor, expectedColor, expectedColor, 328 expectedColor, expectedColor, expectedColor}; 329 check_mipmaps(dContext, mbet->texture(), colorType, expectedColors, reporter, 330 "colorinit"); 331 } 332 333 // The last step in this test will dirty the mipmaps so do it last 334 check_base_readbacks(dContext, mbet->texture(), colorType, renderable, testColor, reporter, 335 "colorinit"); 336 }; 337 338 checkBackendTexture(color); 339 340 SkColor4f newColor = {color.fB , color.fR, color.fG, color.fA }; 341 342 SkColorType skColorType = GrColorTypeToSkColorType(colorType); 343 // Our update method only works with SkColorTypes. 344 if (skColorType != kUnknown_SkColorType) { 345 dContext->updateBackendTexture(mbet->texture(), 346 skColorType, 347 newColor, 348 ManagedBackendTexture::ReleaseProc, 349 mbet->releaseContext()); 350 checkBackendTexture(newColor); 351 } 352} 353 354// Draw the backend texture into an RGBA surface fill context, attempting to access all the mipMap 355// levels. 356static void check_mipmaps(GrDirectContext* dContext, 357 const GrBackendTexture& backendTex, 358 GrColorType colorType, 359 const SkColor4f expectedColors[6], 360 skiatest::Reporter* reporter, 361 const char* label) { 362#ifdef SK_GL 363 // skbug.com/9141 (RGBA_F32 mipmaps appear to be broken on some Mali devices) 364 if (GrBackendApi::kOpenGL == dContext->backend()) { 365 GrGLGpu* glGPU = static_cast<GrGLGpu*>(dContext->priv().getGpu()); 366 367 if (colorType == GrColorType::kRGBA_F32 && 368 glGPU->ctxInfo().standard() == kGLES_GrGLStandard) { 369 return; 370 } 371 } 372#endif 373 374 if (isRGB(backendTex.getBackendFormat())) { 375 // readPixels is busted for the RGB backend format (skbug.com/8862) 376 // TODO: add a GrColorType::kRGB_888 to fix the situation 377 return; 378 } 379 380 GrImageInfo info(GrColorType::kRGBA_8888, kUnpremul_SkAlphaType, nullptr, {32, 32}); 381 auto dstFillContext = dContext->priv().makeSFC(info); 382 if (!dstFillContext) { 383 ERRORF(reporter, "Could not make dst fill context."); 384 return; 385 } 386 387 int numMipLevels = 6; 388 389 auto proxy = dContext->priv().proxyProvider()->wrapBackendTexture(backendTex, 390 kBorrow_GrWrapOwnership, 391 GrWrapCacheable::kNo, 392 kRW_GrIOType); 393 if (!proxy) { 394 ERRORF(reporter, "Could not make proxy from backend texture"); 395 return; 396 } 397 auto swizzle = dContext->priv().caps()->getReadSwizzle(backendTex.getBackendFormat(), 398 colorType); 399 GrSurfaceProxyView readView(proxy, kTopLeft_GrSurfaceOrigin, swizzle); 400 401 for (int i = 0, rectSize = 32; i < numMipLevels; ++i, rectSize /= 2) { 402 SkASSERT(rectSize >= 1); 403 dstFillContext->clear(SK_PMColor4fTRANSPARENT); 404 405 SkMatrix texMatrix; 406 texMatrix.setScale(1 << i, 1 << i); 407 static constexpr GrSamplerState kNearestNearest(GrSamplerState::Filter::kNearest, 408 GrSamplerState::MipmapMode::kNearest); 409 auto fp = GrTextureEffect::Make(readView, 410 kUnpremul_SkAlphaType, 411 texMatrix, 412 kNearestNearest, 413 *dstFillContext->caps()); 414 dstFillContext->fillRectWithFP(SkIRect::MakeWH(rectSize, rectSize), std::move(fp)); 415 416 SkImageInfo readbackII = SkImageInfo::Make(rectSize, rectSize, 417 kRGBA_8888_SkColorType, 418 kUnpremul_SkAlphaType); 419 SkAutoPixmapStorage actual; 420 SkAssertResult(actual.tryAlloc(readbackII)); 421 actual.erase(SkColors::kTransparent); 422 423 bool result = dstFillContext->readPixels(dContext, actual, {0, 0}); 424 REPORTER_ASSERT(reporter, result); 425 426 SkString str; 427 str.appendf("mip-level %d", i); 428 429 check_solid_pixmap(reporter, expectedColors[i], actual, colorType, label, str.c_str()); 430 } 431} 432 433static int make_pixmaps(SkColorType skColorType, 434 GrMipmapped mipmapped, 435 const SkColor4f colors[6], 436 SkPixmap pixmaps[6], 437 std::unique_ptr<char[]>* mem) { 438 int levelSize = 32; 439 int numMipLevels = mipmapped == GrMipmapped::kYes ? 6 : 1; 440 size_t size = 0; 441 SkImageInfo ii[6]; 442 size_t rowBytes[6]; 443 for (int level = 0; level < numMipLevels; ++level) { 444 ii[level] = SkImageInfo::Make(levelSize, levelSize, skColorType, kUnpremul_SkAlphaType); 445 rowBytes[level] = ii[level].minRowBytes(); 446 // Make sure we test row bytes that aren't tight. 447 if (!(level % 2)) { 448 rowBytes[level] += (level + 1)*SkColorTypeBytesPerPixel(ii[level].colorType()); 449 } 450 size += rowBytes[level]*ii[level].height(); 451 levelSize /= 2; 452 } 453 mem->reset(new char[size]); 454 char* addr = mem->get(); 455 for (int level = 0; level < numMipLevels; ++level) { 456 pixmaps[level].reset(ii[level], addr, rowBytes[level]); 457 addr += rowBytes[level]*ii[level].height(); 458 pixmaps[level].erase(colors[level]); 459 levelSize /= 2; 460 } 461 return numMipLevels; 462} 463 464// Test initialization of GrBackendObjects using SkPixmaps 465static void test_pixmap_init(GrDirectContext* dContext, 466 skiatest::Reporter* reporter, 467 std::function<sk_sp<ManagedBackendTexture>(GrDirectContext*, 468 const SkPixmap srcData[], 469 int numLevels, 470 GrSurfaceOrigin, 471 GrRenderable)> create, 472 SkColorType skColorType, 473 GrSurfaceOrigin origin, 474 GrMipmapped mipmapped, 475 GrRenderable renderable) { 476 SkPixmap pixmaps[6]; 477 std::unique_ptr<char[]> memForPixmaps; 478 SkColor4f colors[6] = { 479 { 1.0f, 0.0f, 0.0f, 1.0f }, // R 480 { 0.0f, 1.0f, 0.0f, 0.9f }, // G 481 { 0.0f, 0.0f, 1.0f, 0.7f }, // B 482 { 0.0f, 1.0f, 1.0f, 0.5f }, // C 483 { 1.0f, 0.0f, 1.0f, 0.3f }, // M 484 { 1.0f, 1.0f, 0.0f, 0.2f }, // Y 485 }; 486 487 int numMipLevels = make_pixmaps(skColorType, mipmapped, colors, pixmaps, &memForPixmaps); 488 SkASSERT(numMipLevels); 489 490 sk_sp<ManagedBackendTexture> mbet = create(dContext, pixmaps, numMipLevels, origin, renderable); 491 if (!mbet) { 492 // errors here should be reported by the test_wrapping test 493 return; 494 } 495 496 if (skColorType == kBGRA_8888_SkColorType && !isBGRA8(mbet->texture().getBackendFormat())) { 497 // When kBGRA is backed by an RGBA something goes wrong in the swizzling 498 return; 499 } 500 501 auto checkBackendTexture = [&](SkColor4f colors[6]) { 502 GrColorType grColorType = SkColorTypeToGrColorType(skColorType); 503 if (mipmapped == GrMipmapped::kYes) { 504 SkColor4f expectedColors[6] = { 505 get_expected_color(colors[0], grColorType), 506 get_expected_color(colors[1], grColorType), 507 get_expected_color(colors[2], grColorType), 508 get_expected_color(colors[3], grColorType), 509 get_expected_color(colors[4], grColorType), 510 get_expected_color(colors[5], grColorType), 511 }; 512 513 check_mipmaps(dContext, mbet->texture(), grColorType, expectedColors, reporter, 514 "pixmap"); 515 } 516 517 // The last step in this test will dirty the mipmaps so do it last 518 check_base_readbacks(dContext, mbet->texture(), grColorType, renderable, colors[0], 519 reporter, "pixmap"); 520 }; 521 522 checkBackendTexture(colors); 523 524 SkColor4f colorsNew[6] = { 525 {1.0f, 1.0f, 0.0f, 0.2f}, // Y 526 {1.0f, 0.0f, 0.0f, 1.0f}, // R 527 {0.0f, 1.0f, 0.0f, 0.9f}, // G 528 {0.0f, 0.0f, 1.0f, 0.7f}, // B 529 {0.0f, 1.0f, 1.0f, 0.5f}, // C 530 {1.0f, 0.0f, 1.0f, 0.3f}, // M 531 }; 532 make_pixmaps(skColorType, mipmapped, colorsNew, pixmaps, &memForPixmaps); 533 534 // Upload new data and make sure everything still works 535 dContext->updateBackendTexture(mbet->texture(), 536 pixmaps, 537 numMipLevels, 538 origin, 539 ManagedBackendTexture::ReleaseProc, 540 mbet->releaseContext()); 541 542 checkBackendTexture(colorsNew); 543} 544 545enum class VkLayout { 546 kUndefined, 547 kReadOnlyOptimal, 548}; 549 550void check_vk_tiling(const GrBackendTexture& backendTex) { 551#if defined(SK_VULKAN) && defined(SK_DEBUG) 552 GrVkImageInfo vkII; 553 if (backendTex.getVkImageInfo(&vkII)) { 554 SkASSERT(VK_IMAGE_TILING_OPTIMAL == vkII.fImageTiling); 555 } 556#endif 557} 558 559/////////////////////////////////////////////////////////////////////////////// 560void color_type_backend_allocation_test(const sk_gpu_test::ContextInfo& ctxInfo, 561 skiatest::Reporter* reporter) { 562 auto context = ctxInfo.directContext(); 563 const GrCaps* caps = context->priv().caps(); 564 565 constexpr SkColor4f kTransCol { 0, 0.25f, 0.75f, 0.5f }; 566 constexpr SkColor4f kGrayCol { 0.75f, 0.75f, 0.75f, 0.75f }; 567 568 struct { 569 SkColorType fColorType; 570 SkColor4f fColor; 571 } combinations[] = { 572 { kAlpha_8_SkColorType, kTransCol }, 573 { kRGB_565_SkColorType, SkColors::kRed }, 574 { kARGB_4444_SkColorType, SkColors::kGreen }, 575 { kRGBA_8888_SkColorType, SkColors::kBlue }, 576 { kSRGBA_8888_SkColorType, { 0.25f, 0.5f, 0.75f, 1.0f}}, 577 { kRGB_888x_SkColorType, SkColors::kCyan }, 578 // TODO: readback is busted when alpha = 0.5f (perhaps premul vs. unpremul) 579 { kBGRA_8888_SkColorType, { 1, 0, 0, 1.0f } }, 580 // TODO: readback is busted for *10A2 when alpha = 0.5f (perhaps premul vs. unpremul) 581 { kRGBA_1010102_SkColorType, { 0.25f, 0.5f, 0.75f, 1.0f }}, 582 { kBGRA_1010102_SkColorType, { 0.25f, 0.5f, 0.75f, 1.0f }}, 583 // RGB/BGR 101010x have no Ganesh correlate 584 { kRGB_101010x_SkColorType, { 0, 0.5f, 0, 0.5f } }, 585 { kBGR_101010x_SkColorType, { 0, 0.5f, 0, 0.5f } }, 586 { kGray_8_SkColorType, kGrayCol }, 587 { kRGBA_F16Norm_SkColorType, SkColors::kLtGray }, 588 { kRGBA_F16_SkColorType, SkColors::kYellow }, 589 { kRGBA_F32_SkColorType, SkColors::kGray }, 590 { kR8G8_unorm_SkColorType, { .25f, .75f, 0, 1 } }, 591 { kR16G16_unorm_SkColorType, SkColors::kGreen }, 592 { kA16_unorm_SkColorType, kTransCol }, 593 { kA16_float_SkColorType, kTransCol }, 594 { kR16G16_float_SkColorType, { .25f, .75f, 0, 1 } }, 595 { kR16G16B16A16_unorm_SkColorType,{ .25f, .5f, .75f, 1 } }, 596 }; 597 598 static_assert(kLastEnum_SkColorType == SK_ARRAY_COUNT(combinations)); 599 600 for (auto combo : combinations) { 601 SkColorType colorType = combo.fColorType; 602 603 if (GrBackendApi::kMetal == context->backend()) { 604 // skbug.com/9086 (Metal caps may not be handling RGBA32 correctly) 605 if (kRGBA_F32_SkColorType == combo.fColorType) { 606 continue; 607 } 608 } 609 610 for (auto mipmapped : {GrMipmapped::kNo, GrMipmapped::kYes}) { 611 if (GrMipmapped::kYes == mipmapped && !caps->mipmapSupport()) { 612 continue; 613 } 614 615 for (auto renderable : { GrRenderable::kNo, GrRenderable::kYes }) { 616 if (!caps->getDefaultBackendFormat(SkColorTypeToGrColorType(colorType), 617 renderable).isValid()) { 618 continue; 619 } 620 621 if (GrRenderable::kYes == renderable) { 622 if (kRGB_888x_SkColorType == combo.fColorType) { 623 // Ganesh can't perform the blends correctly when rendering this format 624 continue; 625 } 626 } 627 628 { 629 auto uninitCreateMtd = [colorType](GrDirectContext* dContext, 630 GrMipmapped mipmapped, 631 GrRenderable renderable) { 632 auto mbet = ManagedBackendTexture::MakeWithoutData(dContext, 633 32, 32, 634 colorType, 635 mipmapped, 636 renderable, 637 GrProtected::kNo); 638 check_vk_tiling(mbet->texture()); 639#ifdef SK_DEBUG 640 { 641 GrBackendFormat format = dContext->defaultBackendFormat(colorType, 642 renderable); 643 SkASSERT(format == mbet->texture().getBackendFormat()); 644 } 645#endif 646 647 return mbet; 648 }; 649 650 test_wrapping(context, reporter, uninitCreateMtd, 651 SkColorTypeToGrColorType(colorType), mipmapped, renderable); 652 } 653 654 { 655 auto createWithColorMtd = [colorType](GrDirectContext* dContext, 656 const SkColor4f& color, 657 GrMipmapped mipmapped, 658 GrRenderable renderable) { 659 auto mbet = ManagedBackendTexture::MakeWithData(dContext, 660 32, 32, 661 colorType, 662 color, 663 mipmapped, 664 renderable, 665 GrProtected::kNo); 666 check_vk_tiling(mbet->texture()); 667 668#ifdef SK_DEBUG 669 { 670 GrBackendFormat format = dContext->defaultBackendFormat(colorType, 671 renderable); 672 SkASSERT(format == mbet->texture().getBackendFormat()); 673 } 674#endif 675 676 return mbet; 677 }; 678 test_color_init(context, reporter, createWithColorMtd, 679 SkColorTypeToGrColorType(colorType), combo.fColor, mipmapped, 680 renderable); 681 } 682 683 for (auto origin : {kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin}) { 684 auto createWithSrcDataMtd = [](GrDirectContext* dContext, 685 const SkPixmap srcData[], 686 int numLevels, 687 GrSurfaceOrigin origin, 688 GrRenderable renderable) { 689 SkASSERT(srcData && numLevels); 690 auto mbet = ManagedBackendTexture::MakeWithData(dContext, 691 srcData, 692 numLevels, 693 origin, 694 renderable, 695 GrProtected::kNo); 696 check_vk_tiling(mbet->texture()); 697#ifdef SK_DEBUG 698 { 699 auto format = dContext->defaultBackendFormat(srcData[0].colorType(), 700 renderable); 701 SkASSERT(format == mbet->texture().getBackendFormat()); 702 } 703#endif 704 return mbet; 705 }; 706 707 test_pixmap_init(context, 708 reporter, 709 createWithSrcDataMtd, 710 colorType, 711 origin, 712 mipmapped, 713 renderable); 714 } 715 } 716 } 717 } 718} 719 720DEF_GPUTEST(ColorTypeBackendAllocationTest, reporter, options) { 721 for (int t = 0; t < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++t) { 722 auto type = static_cast<sk_gpu_test::GrContextFactory::ContextType>(t); 723 if (!sk_gpu_test::GrContextFactory::IsRenderingContext(type)) { 724 continue; 725 } 726 sk_gpu_test::GrContextFactory factory(options); 727 sk_gpu_test::ContextInfo info = factory.getContextInfo(type); 728 if (!info.directContext()) { 729 continue; 730 } 731 color_type_backend_allocation_test(info, reporter); 732 // The GL backend must support contexts that don't allow GL_UNPACK_ROW_LENGTH. Other 733 // backends are not required to work with this cap disabled. 734 if (info.directContext()->priv().caps()->writePixelsRowBytesSupport() && 735 info.directContext()->backend() == GrBackendApi::kOpenGL) { 736 GrContextOptions overrideOptions = options; 737 overrideOptions.fDisallowWriteAndTransferPixelRowBytes = true; 738 sk_gpu_test::GrContextFactory overrideFactory(overrideOptions); 739 info = overrideFactory.getContextInfo(type); 740 color_type_backend_allocation_test(info, reporter); 741 } 742 } 743} 744 745/////////////////////////////////////////////////////////////////////////////// 746#ifdef SK_GL 747 748DEF_GPUTEST_FOR_ALL_GL_CONTEXTS(GLBackendAllocationTest, reporter, ctxInfo) { 749 sk_gpu_test::GLTestContext* glCtx = ctxInfo.glContext(); 750 GrGLStandard standard = glCtx->gl()->fStandard; 751 auto context = ctxInfo.directContext(); 752 const GrGLCaps* glCaps = static_cast<const GrGLCaps*>(context->priv().caps()); 753 754 constexpr SkColor4f kTransCol { 0, 0.25f, 0.75f, 0.5f }; 755 constexpr SkColor4f kGrayCol { 0.75f, 0.75f, 0.75f, 1.f }; 756 constexpr SkColor4f kTransGrayCol { 0.5f, 0.5f, 0.5f, .8f }; 757 758 struct { 759 GrColorType fColorType; 760 GrGLenum fFormat; 761 SkColor4f fColor; 762 } combinations[] = { 763 { GrColorType::kRGBA_8888, GR_GL_RGBA8, SkColors::kRed }, 764 { GrColorType::kRGBA_8888_SRGB, GR_GL_SRGB8_ALPHA8, SkColors::kRed }, 765 766 { GrColorType::kRGB_888x, GR_GL_RGBA8, SkColors::kYellow }, 767 { GrColorType::kRGB_888x, GR_GL_RGB8, SkColors::kCyan }, 768 769 { GrColorType::kBGRA_8888, GR_GL_RGBA8, SkColors::kBlue }, 770 { GrColorType::kBGRA_8888, GR_GL_BGRA8, SkColors::kBlue }, 771 // TODO: readback is busted when alpha = 0.5f (perhaps premul vs. unpremul) 772 { GrColorType::kRGBA_1010102, GR_GL_RGB10_A2, { 0.25f, 0.5f, 0.75f, 1.f }}, 773 { GrColorType::kBGRA_1010102, GR_GL_RGB10_A2, { 0.25f, 0.5f, 0.75f, 1.f }}, 774 { GrColorType::kBGR_565, GR_GL_RGB565, SkColors::kRed }, 775 { GrColorType::kABGR_4444, GR_GL_RGBA4, SkColors::kGreen }, 776 777 { GrColorType::kAlpha_8, GR_GL_ALPHA8, kTransCol }, 778 { GrColorType::kAlpha_8, GR_GL_R8, kTransCol }, 779 780 { GrColorType::kGray_8, GR_GL_LUMINANCE8, kGrayCol }, 781 { GrColorType::kGray_8, GR_GL_R8, kGrayCol }, 782 783 { GrColorType::kGrayAlpha_88, GR_GL_LUMINANCE8_ALPHA8, kTransGrayCol }, 784 785 { GrColorType::kRGBA_F32, GR_GL_RGBA32F, SkColors::kRed }, 786 787 { GrColorType::kRGBA_F16_Clamped, GR_GL_RGBA16F, SkColors::kLtGray }, 788 { GrColorType::kRGBA_F16, GR_GL_RGBA16F, SkColors::kYellow }, 789 790 { GrColorType::kRG_88, GR_GL_RG8, { 1, 0.5f, 0, 1 } }, 791 { GrColorType::kAlpha_F16, GR_GL_R16F, { 1.0f, 0, 0, 0.5f } }, 792 { GrColorType::kAlpha_F16, GR_GL_LUMINANCE16F, kGrayCol }, 793 794 { GrColorType::kAlpha_16, GR_GL_R16, kTransCol }, 795 { GrColorType::kRG_1616, GR_GL_RG16, SkColors::kYellow }, 796 797 { GrColorType::kRGBA_16161616, GR_GL_RGBA16, SkColors::kLtGray }, 798 { GrColorType::kRG_F16, GR_GL_RG16F, SkColors::kYellow }, 799 }; 800 801 for (auto combo : combinations) { 802 for (GrTextureType textureType : {GrTextureType::k2D, GrTextureType::kRectangle}) { 803 GrGLenum target = textureType == GrTextureType::k2D ? GR_GL_TEXTURE_2D 804 : GR_GL_TEXTURE_RECTANGLE; 805 GrBackendFormat format = GrBackendFormat::MakeGL(combo.fFormat, target); 806 if (!glCaps->isFormatTexturable(format, textureType)) { 807 continue; 808 } 809 810 if (GrColorType::kBGRA_8888 == combo.fColorType || 811 GrColorType::kBGRA_1010102 == combo.fColorType) { 812 // We allow using a GL_RGBA8 or GR_GL_RGB10_A2 texture as BGRA on desktop GL but not 813 // ES 814 if (kGL_GrGLStandard != standard && 815 (GR_GL_RGBA8 == combo.fFormat || GR_GL_RGB10_A2 == combo.fFormat)) { 816 continue; 817 } 818 } 819 820 for (auto mipMapped : {GrMipmapped::kNo, GrMipmapped::kYes}) { 821 if (GrMipmapped::kYes == mipMapped && 822 (!glCaps->mipmapSupport() || target == GR_GL_TEXTURE_RECTANGLE)) { 823 continue; 824 } 825 826 for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) { 827 if (GrRenderable::kYes == renderable) { 828 if (!glCaps->isFormatAsColorTypeRenderable(combo.fColorType, format)) { 829 continue; 830 } 831 } 832 833 { 834 auto uninitCreateMtd = [format](GrDirectContext* dContext, 835 GrMipmapped mipMapped, 836 GrRenderable renderable) { 837 return ManagedBackendTexture::MakeWithoutData(dContext, 838 32, 32, 839 format, 840 mipMapped, 841 renderable, 842 GrProtected::kNo); 843 }; 844 845 test_wrapping(context, reporter, uninitCreateMtd, combo.fColorType, 846 mipMapped, renderable); 847 } 848 849 { 850 // We're creating backend textures without specifying a color type "view" of 851 // them at the public API level. Therefore, Ganesh will not apply any 852 // swizzles before writing the color to the texture. However, our validation 853 // code does rely on interpreting the texture contents via a SkColorType and 854 // therefore swizzles may be applied during the read step. Ideally we'd 855 // update our validation code to use a "raw" read that doesn't impose a 856 // color type but for now we just munge the data we upload to match the 857 // expectation. 858 GrSwizzle swizzle; 859 switch (combo.fColorType) { 860 case GrColorType::kAlpha_8: 861 swizzle = GrSwizzle("aaaa"); 862 break; 863 case GrColorType::kAlpha_16: 864 swizzle = GrSwizzle("aaaa"); 865 break; 866 case GrColorType::kAlpha_F16: 867 swizzle = GrSwizzle("aaaa"); 868 break; 869 default: 870 break; 871 } 872 auto createWithColorMtd = [format, swizzle](GrDirectContext* dContext, 873 const SkColor4f& color, 874 GrMipmapped mipmapped, 875 GrRenderable renderable) { 876 auto swizzledColor = swizzle.applyTo(color); 877 return ManagedBackendTexture::MakeWithData(dContext, 878 32, 32, 879 format, 880 swizzledColor, 881 mipmapped, 882 renderable, 883 GrProtected::kNo); 884 }; 885 test_color_init(context, reporter, createWithColorMtd, combo.fColorType, 886 combo.fColor, mipMapped, renderable); 887 } 888 } 889 } 890 } 891 } 892} 893 894#endif 895 896/////////////////////////////////////////////////////////////////////////////// 897 898#ifdef SK_VULKAN 899 900#include "src/gpu/vk/GrVkCaps.h" 901 902DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkBackendAllocationTest, reporter, ctxInfo) { 903 auto context = ctxInfo.directContext(); 904 const GrVkCaps* vkCaps = static_cast<const GrVkCaps*>(context->priv().caps()); 905 906 constexpr SkColor4f kTransCol { 0, 0.25f, 0.75f, 0.5f }; 907 constexpr SkColor4f kGrayCol { 0.75f, 0.75f, 0.75f, 1 }; 908 909 struct { 910 GrColorType fColorType; 911 VkFormat fFormat; 912 SkColor4f fColor; 913 } combinations[] = { 914 { GrColorType::kRGBA_8888, VK_FORMAT_R8G8B8A8_UNORM, SkColors::kRed }, 915 { GrColorType::kRGBA_8888_SRGB, VK_FORMAT_R8G8B8A8_SRGB, SkColors::kRed }, 916 917 // In this configuration (i.e., an RGB_888x colortype with an RGBA8 backing format), 918 // there is nothing to tell Skia to make the provided color opaque. Clients will need 919 // to provide an opaque initialization color in this case. 920 { GrColorType::kRGB_888x, VK_FORMAT_R8G8B8A8_UNORM, SkColors::kYellow }, 921 { GrColorType::kRGB_888x, VK_FORMAT_R8G8B8_UNORM, SkColors::kCyan }, 922 923 { GrColorType::kBGRA_8888, VK_FORMAT_B8G8R8A8_UNORM, SkColors::kBlue }, 924 925 { GrColorType::kRGBA_1010102, VK_FORMAT_A2B10G10R10_UNORM_PACK32, 926 { 0.25f, 0.5f, 0.75f, 1.0f }}, 927 { GrColorType::kBGRA_1010102, VK_FORMAT_A2R10G10B10_UNORM_PACK32, 928 { 0.25f, 0.5f, 0.75f, 1.0f }}, 929 { GrColorType::kBGR_565, VK_FORMAT_R5G6B5_UNORM_PACK16, SkColors::kRed }, 930 931 { GrColorType::kABGR_4444, VK_FORMAT_R4G4B4A4_UNORM_PACK16, SkColors::kCyan }, 932 { GrColorType::kABGR_4444, VK_FORMAT_B4G4R4A4_UNORM_PACK16, SkColors::kYellow }, 933 934 { GrColorType::kAlpha_8, VK_FORMAT_R8_UNORM, kTransCol }, 935 // In this config (i.e., a Gray8 color type with an R8 backing format), there is nothing 936 // to tell Skia this isn't an Alpha8 color type (so it will initialize the texture with 937 // the alpha channel of the color). Clients should, in general, fill all the channels 938 // of the provided color with the same value in such cases. 939 { GrColorType::kGray_8, VK_FORMAT_R8_UNORM, kGrayCol }, 940 941 { GrColorType::kRGBA_F16_Clamped, VK_FORMAT_R16G16B16A16_SFLOAT, SkColors::kLtGray }, 942 { GrColorType::kRGBA_F16, VK_FORMAT_R16G16B16A16_SFLOAT, SkColors::kYellow }, 943 944 { GrColorType::kRG_88, VK_FORMAT_R8G8_UNORM, { 1, 0.5f, 0, 1 } }, 945 { GrColorType::kAlpha_F16, VK_FORMAT_R16_SFLOAT, { 1.0f, 0, 0, 0.5f }}, 946 947 { GrColorType::kAlpha_16, VK_FORMAT_R16_UNORM, kTransCol }, 948 { GrColorType::kRG_1616, VK_FORMAT_R16G16_UNORM, SkColors::kYellow }, 949 { GrColorType::kRGBA_16161616, VK_FORMAT_R16G16B16A16_UNORM, SkColors::kLtGray }, 950 { GrColorType::kRG_F16, VK_FORMAT_R16G16_SFLOAT, SkColors::kYellow }, 951 }; 952 953 for (auto combo : combinations) { 954 if (!vkCaps->isVkFormatTexturable(combo.fFormat)) { 955 continue; 956 } 957 958 GrBackendFormat format = GrBackendFormat::MakeVk(combo.fFormat); 959 960 for (auto mipMapped : { GrMipmapped::kNo, GrMipmapped::kYes }) { 961 if (GrMipmapped::kYes == mipMapped && !vkCaps->mipmapSupport()) { 962 continue; 963 } 964 965 for (auto renderable : { GrRenderable::kNo, GrRenderable::kYes }) { 966 967 if (GrRenderable::kYes == renderable) { 968 // We must also check whether we allow rendering to the format using the 969 // color type. 970 if (!vkCaps->isFormatAsColorTypeRenderable( 971 combo.fColorType, GrBackendFormat::MakeVk(combo.fFormat), 1)) { 972 continue; 973 } 974 } 975 976 { 977 auto uninitCreateMtd = [format](GrDirectContext* dContext, 978 GrMipmapped mipMapped, 979 GrRenderable renderable) { 980 auto mbet = ManagedBackendTexture::MakeWithoutData(dContext, 981 32, 32, 982 format, 983 mipMapped, 984 renderable, 985 GrProtected::kNo); 986 check_vk_tiling(mbet->texture()); 987 return mbet; 988 }; 989 990 test_wrapping(context, reporter, uninitCreateMtd, combo.fColorType, mipMapped, 991 renderable); 992 } 993 994 { 995 // We're creating backend textures without specifying a color type "view" of 996 // them at the public API level. Therefore, Ganesh will not apply any swizzles 997 // before writing the color to the texture. However, our validation code does 998 // rely on interpreting the texture contents via a SkColorType and therefore 999 // swizzles may be applied during the read step. 1000 // Ideally we'd update our validation code to use a "raw" read that doesn't 1001 // impose a color type but for now we just munge the data we upload to match the 1002 // expectation. 1003 GrSwizzle swizzle; 1004 switch (combo.fColorType) { 1005 case GrColorType::kAlpha_8: 1006 SkASSERT(combo.fFormat == VK_FORMAT_R8_UNORM); 1007 swizzle = GrSwizzle("aaaa"); 1008 break; 1009 case GrColorType::kAlpha_16: 1010 SkASSERT(combo.fFormat == VK_FORMAT_R16_UNORM); 1011 swizzle = GrSwizzle("aaaa"); 1012 break; 1013 case GrColorType::kAlpha_F16: 1014 SkASSERT(combo.fFormat == VK_FORMAT_R16_SFLOAT); 1015 swizzle = GrSwizzle("aaaa"); 1016 break; 1017 case GrColorType::kABGR_4444: 1018 if (combo.fFormat == VK_FORMAT_B4G4R4A4_UNORM_PACK16) { 1019 swizzle = GrSwizzle("bgra"); 1020 } 1021 break; 1022 default: 1023 swizzle = GrSwizzle("rgba"); 1024 break; 1025 } 1026 1027 auto createWithColorMtd = [format, swizzle](GrDirectContext* dContext, 1028 const SkColor4f& color, 1029 GrMipmapped mipMapped, 1030 GrRenderable renderable) { 1031 auto swizzledColor = swizzle.applyTo(color); 1032 auto mbet = ManagedBackendTexture::MakeWithData(dContext, 1033 32, 32, 1034 format, 1035 swizzledColor, 1036 mipMapped, 1037 renderable, 1038 GrProtected::kNo); 1039 check_vk_tiling(mbet->texture()); 1040 return mbet; 1041 }; 1042 test_color_init(context, reporter, createWithColorMtd, combo.fColorType, 1043 combo.fColor, mipMapped, renderable); 1044 } 1045 } 1046 } 1047 } 1048} 1049 1050#endif 1051