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
37 using sk_gpu_test::ManagedBackendTexture;
38
39 // Test wrapping of GrBackendObjects in SkSurfaces and SkImages (non-static since used in Mtl test)
test_wrapping(GrDirectContext * dContext,skiatest::Reporter * reporter,std::function<sk_sp<ManagedBackendTexture> (GrDirectContext *,GrMipmapped,GrRenderable)> create,GrColorType grColorType,GrMipmapped mipMapped,GrRenderable renderable)40 void 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
isBGRA8(const GrBackendFormat & format)123 static 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
isRGB(const GrBackendFormat & format)172 static 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
check_solid_pixmap(skiatest::Reporter * reporter,const SkColor4f & expected,const SkPixmap & actual,GrColorType ct,const char * label1,const char * label2)201 static 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.
get_expected_color(SkColor4f orig,GrColorType ct)222 static 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
235 static void check_mipmaps(GrDirectContext*,
236 const GrBackendTexture&,
237 GrColorType,
238 const SkColor4f expectedColors[6],
239 skiatest::Reporter*,
240 const char* label);
241
check_base_readbacks(GrDirectContext * dContext,const GrBackendTexture & backendTex,GrColorType colorType,GrRenderable renderableTexture,const SkColor4f & color,skiatest::Reporter * reporter,const char * label)242 static 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)
test_color_init(GrDirectContext * dContext,skiatest::Reporter * reporter,std::function<sk_sp<ManagedBackendTexture> (GrDirectContext *,const SkColor4f &,GrMipmapped,GrRenderable)> create,GrColorType colorType,const SkColor4f & color,GrMipmapped mipmapped,GrRenderable renderable)308 void 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.
check_mipmaps(GrDirectContext * dContext,const GrBackendTexture & backendTex,GrColorType colorType,const SkColor4f expectedColors[6],skiatest::Reporter * reporter,const char * label)356 static 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
make_pixmaps(SkColorType skColorType,GrMipmapped mipmapped,const SkColor4f colors[6],SkPixmap pixmaps[6],std::unique_ptr<char[]> * mem)433 static 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
test_pixmap_init(GrDirectContext * dContext,skiatest::Reporter * reporter,std::function<sk_sp<ManagedBackendTexture> (GrDirectContext *,const SkPixmap srcData[],int numLevels,GrSurfaceOrigin,GrRenderable)> create,SkColorType skColorType,GrSurfaceOrigin origin,GrMipmapped mipmapped,GrRenderable renderable)465 static 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
545 enum class VkLayout {
546 kUndefined,
547 kReadOnlyOptimal,
548 };
549
check_vk_tiling(const GrBackendTexture & backendTex)550 void 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 ///////////////////////////////////////////////////////////////////////////////
color_type_backend_allocation_test(const sk_gpu_test::ContextInfo & ctxInfo,skiatest::Reporter * reporter)560 void 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
DEF_GPUTEST(ColorTypeBackendAllocationTest,reporter,options)720 DEF_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
DEF_GPUTEST_FOR_ALL_GL_CONTEXTS(GLBackendAllocationTest,reporter,ctxInfo)748 DEF_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
DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkBackendAllocationTest,reporter,ctxInfo)902 DEF_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