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