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/SkSurface.h"
9 #include "include/core/SkSurfaceCharacterization.h"
10 #include "include/gpu/GrContext.h"
11 #include "src/core/SkAutoPixmapStorage.h"
12 #include "src/gpu/GrContextPriv.h"
13 #include "src/image/SkImage_Base.h"
14 #include "tests/Test.h"
15
16 #ifdef SK_GL
17 #include "src/gpu/gl/GrGLGpu.h"
18 #include "src/gpu/gl/GrGLUtil.h"
19 #endif
20
21 // Test wrapping of GrBackendObjects in SkSurfaces and SkImages
test_wrapping(GrContext * context,skiatest::Reporter * reporter,std::function<GrBackendTexture (GrContext *,GrMipMapped,GrRenderable)> create,GrColorType grColorType,GrMipMapped mipMapped,GrRenderable renderable)22 void test_wrapping(GrContext* context, skiatest::Reporter* reporter,
23 std::function<GrBackendTexture (GrContext*,
24 GrMipMapped,
25 GrRenderable)> create,
26 GrColorType grColorType, GrMipMapped mipMapped, GrRenderable renderable) {
27 GrResourceCache* cache = context->priv().getResourceCache();
28
29 const int initialCount = cache->getResourceCount();
30
31 GrBackendTexture backendTex = create(context, mipMapped, renderable);
32 if (!backendTex.isValid()) {
33 ERRORF(reporter, "Couldn't create backendTexture for grColorType %d renderable %s\n",
34 grColorType,
35 GrRenderable::kYes == renderable ? "yes" : "no");
36 return;
37 }
38
39 // Skia proper should know nothing about the new backend object
40 REPORTER_ASSERT(reporter, initialCount == cache->getResourceCount());
41
42 SkColorType skColorType = GrColorTypeToSkColorType(grColorType);
43
44 // Wrapping a backendTexture in an image requires an SkColorType
45 if (kUnknown_SkColorType == skColorType) {
46 context->deleteBackendTexture(backendTex);
47 return;
48 }
49
50 if (GrRenderable::kYes == renderable) {
51 sk_sp<SkSurface> surf = SkSurface::MakeFromBackendTexture(context,
52 backendTex,
53 kTopLeft_GrSurfaceOrigin,
54 0,
55 skColorType,
56 nullptr, nullptr);
57 if (!surf) {
58 ERRORF(reporter, "Couldn't make surface from backendTexture for colorType %d\n",
59 skColorType);
60 } else {
61 REPORTER_ASSERT(reporter, initialCount+1 == cache->getResourceCount());
62 }
63 }
64
65 {
66 sk_sp<SkImage> img = SkImage::MakeFromTexture(context,
67 backendTex,
68 kTopLeft_GrSurfaceOrigin,
69 skColorType,
70 kPremul_SkAlphaType,
71 nullptr);
72 if (!img) {
73 ERRORF(reporter, "Couldn't make image from backendTexture for skColorType %d\n",
74 skColorType);
75 } else {
76 SkImage_Base* ib = as_IB(img);
77
78 GrTextureProxy* proxy = ib->peekProxy();
79 REPORTER_ASSERT(reporter, proxy);
80
81 REPORTER_ASSERT(reporter, mipMapped == proxy->proxyMipMapped());
82 REPORTER_ASSERT(reporter, proxy->isInstantiated());
83 REPORTER_ASSERT(reporter, mipMapped == proxy->mipMapped());
84
85 REPORTER_ASSERT(reporter, initialCount+1 == cache->getResourceCount());
86 }
87 }
88
89 REPORTER_ASSERT(reporter, initialCount == cache->getResourceCount());
90
91 context->deleteBackendTexture(backendTex);
92 }
93
colors_eq(SkColor colA,SkColor colB,int tol)94 static bool colors_eq(SkColor colA, SkColor colB, int tol) {
95 int maxDiff = 0;
96 for (int i = 0; i < 4; ++i) {
97 int diff = SkTAbs<int>((0xFF & (colA >> i*8)) - (0xFF & (colB >> i*8)));
98 if (maxDiff < diff) {
99 maxDiff = diff;
100 }
101 }
102
103 return maxDiff <= tol;
104 }
105
compare_pixmaps(const SkPixmap & expected,const SkPixmap & actual,SkColorType colorType,skiatest::Reporter * reporter)106 static void compare_pixmaps(const SkPixmap& expected, const SkPixmap& actual,
107 SkColorType colorType, skiatest::Reporter* reporter) {
108 SkASSERT(expected.info() == actual.info());
109 for (int y = 0; y < expected.height(); ++y) {
110 for (int x = 0; x < expected.width(); ++x) {
111
112 SkColor expectedCol = expected.getColor(x, y);
113 SkColor actualCol = actual.getColor(x, y);
114
115 // GPU and raster differ a bit on kGray_8_SkColorType and kRGBA_1010102_SkColorType
116 if (colors_eq(actualCol, expectedCol, 12)) {
117 continue;
118 }
119
120 ERRORF(reporter,
121 "Mismatched pixels at %d %d ct: %d expected: 0x%x actual: 0x%x\n",
122 x, y, colorType, expectedCol, actualCol);
123 return;
124 }
125 }
126 }
127
128 // Test initialization of GrBackendObjects to a specific color
test_color_init(GrContext * context,skiatest::Reporter * reporter,std::function<GrBackendTexture (GrContext *,const SkColor4f &,GrMipMapped,GrRenderable)> create,GrColorType grColorType,const SkColor4f & color,GrMipMapped mipMapped,GrRenderable renderable)129 void test_color_init(GrContext* context, skiatest::Reporter* reporter,
130 std::function<GrBackendTexture (GrContext*,
131 const SkColor4f&,
132 GrMipMapped,
133 GrRenderable)> create,
134 GrColorType grColorType, const SkColor4f& color,
135 GrMipMapped mipMapped, GrRenderable renderable) {
136 GrBackendTexture backendTex = create(context, color, mipMapped, renderable);
137 if (!backendTex.isValid()) {
138 // errors here should be reported by the test_wrapping test
139 return;
140 }
141
142 SkColorType skColorType = GrColorTypeToSkColorType(grColorType);
143
144 // Can't wrap backend textures in images and surfaces w/o an SkColorType
145 if (kUnknown_SkColorType == skColorType) {
146 // TODO: burrow in and scrappily check that data was uploaded!
147 context->deleteBackendTexture(backendTex);
148 return;
149 }
150
151 SkAlphaType at = SkColorTypeIsAlwaysOpaque(skColorType) ? kOpaque_SkAlphaType
152 : kPremul_SkAlphaType;
153
154 SkImageInfo ii = SkImageInfo::Make(32, 32, skColorType, at);
155
156 SkColor4f rasterColor = color;
157 if (kGray_8_SkColorType == skColorType) {
158 // For the GPU backends, gray implies a single channel which is opaque.
159 rasterColor.fR = color.fA;
160 rasterColor.fG = color.fA;
161 rasterColor.fB = color.fA;
162 rasterColor.fA = 1.0f;
163 } else if (kAlpha_8_SkColorType == skColorType) {
164 // For the GPU backends, alpha implies a single alpha channel.
165 rasterColor.fR = 0;
166 rasterColor.fG = 0;
167 rasterColor.fB = 0;
168 rasterColor.fA = color.fA;
169 }
170
171 SkAutoPixmapStorage expected;
172 SkAssertResult(expected.tryAlloc(ii));
173 expected.erase(rasterColor);
174
175 SkAutoPixmapStorage actual;
176 SkAssertResult(actual.tryAlloc(ii));
177 actual.erase(SkColors::kTransparent);
178
179 if (GrRenderable::kYes == renderable) {
180 sk_sp<SkSurface> surf = SkSurface::MakeFromBackendTexture(context,
181 backendTex,
182 kTopLeft_GrSurfaceOrigin,
183 0,
184 skColorType,
185 nullptr, nullptr);
186 if (surf) {
187 bool result = surf->readPixels(actual, 0, 0);
188 REPORTER_ASSERT(reporter, result);
189
190 compare_pixmaps(expected, actual, skColorType, reporter);
191
192 actual.erase(SkColors::kTransparent);
193 }
194 }
195
196 {
197 sk_sp<SkImage> img = SkImage::MakeFromTexture(context,
198 backendTex,
199 kTopLeft_GrSurfaceOrigin,
200 skColorType,
201 at,
202 nullptr);
203 if (img) {
204 // If possible, read back the pixels and check that they're correct
205 {
206 bool result = img->readPixels(actual, 0, 0);
207 if (!result) {
208 // TODO: we need a better way to tell a priori if readPixels will work for an
209 // arbitrary colorType
210 #if 0
211 ERRORF(reporter, "Couldn't readback from SkImage for colorType: %d\n",
212 colorType);
213 #endif
214 } else {
215 compare_pixmaps(expected, actual, skColorType, reporter);
216 }
217 }
218
219 // Draw the wrapped image into an RGBA surface attempting to access all the
220 // mipMap levels.
221 {
222 #ifdef SK_GL
223 // skbug.com/9141 (RGBA_F32 mipmaps appear to be broken on some Mali devices)
224 if (GrBackendApi::kOpenGL == context->backend()) {
225 GrGLGpu* glGPU = static_cast<GrGLGpu*>(context->priv().getGpu());
226
227 if (kRGBA_F32_SkColorType == skColorType && GrMipMapped::kYes == mipMapped &&
228 kGLES_GrGLStandard == glGPU->ctxInfo().standard()) {
229 context->deleteBackendTexture(backendTex);
230 return;
231 }
232 }
233 #endif
234
235 SkImageInfo newII = SkImageInfo::Make(32, 32, kRGBA_8888_SkColorType,
236 kPremul_SkAlphaType);
237
238 SkAutoPixmapStorage actual2;
239 SkAssertResult(actual2.tryAlloc(newII));
240 actual2.erase(SkColors::kTransparent);
241
242 sk_sp<SkSurface> surf = SkSurface::MakeRenderTarget(context,
243 SkBudgeted::kNo,
244 newII, 1,
245 kTopLeft_GrSurfaceOrigin,
246 nullptr);
247 if (!surf) {
248 context->deleteBackendTexture(backendTex);
249 return;
250 }
251
252 SkCanvas* canvas = surf->getCanvas();
253
254 SkPaint p;
255 p.setFilterQuality(kHigh_SkFilterQuality);
256
257 int numMipLevels = (GrMipMapped::kYes == mipMapped) ? 6 : 1;
258
259 for (int i = 0, rectSize = 32; i < numMipLevels; ++i, rectSize /= 2) {
260 SkASSERT(rectSize >= 1);
261
262 SkRect r = SkRect::MakeWH(rectSize, rectSize);
263 canvas->clear(SK_ColorTRANSPARENT);
264 canvas->drawImageRect(img, r, &p);
265
266 bool result = surf->readPixels(actual2, 0, 0);
267 REPORTER_ASSERT(reporter, result);
268
269 SkColor actualColor = actual2.getColor(0, 0);
270
271 if (!colors_eq(actualColor, rasterColor.toSkColor(), 1)) {
272 ERRORF(reporter, "Pixel mismatch colorType %d: level: %d e: 0x%x a: 0x%x\n",
273 skColorType, i, rasterColor.toSkColor(), actualColor);
274 }
275 }
276 }
277 }
278 }
279
280 context->deleteBackendTexture(backendTex);
281 }
282
283 enum class VkLayout {
284 kUndefined,
285 kReadOnlyOptimal,
286 kColorAttachmentOptimal
287 };
288
check_vk_layout(const GrBackendTexture & backendTex,VkLayout layout)289 void check_vk_layout(const GrBackendTexture& backendTex, VkLayout layout) {
290 #if defined(SK_VULKAN) && defined(SK_DEBUG)
291 VkImageLayout expected;
292
293 switch (layout) {
294 case VkLayout::kUndefined:
295 expected = VK_IMAGE_LAYOUT_UNDEFINED;
296 break;
297 case VkLayout::kReadOnlyOptimal:
298 expected = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
299 break;
300 case VkLayout::kColorAttachmentOptimal:
301 expected = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
302 break;
303 default:
304 SkUNREACHABLE;
305 }
306
307 GrVkImageInfo vkII;
308
309 if (backendTex.getVkImageInfo(&vkII)) {
310 SkASSERT(expected == vkII.fImageLayout);
311 SkASSERT(VK_IMAGE_TILING_OPTIMAL == vkII.fImageTiling);
312 }
313 #endif
314 }
315
316 ///////////////////////////////////////////////////////////////////////////////
317 // This test is a bit different from the others in this file. It is mainly checking that, for any
318 // SkSurface we can create in Ganesh, we can also create a backend texture that is compatible with
319 // its characterization and then create a new surface that wraps that backend texture.
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(CharacterizationBackendAllocationTest,reporter,ctxInfo)320 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(CharacterizationBackendAllocationTest, reporter, ctxInfo) {
321 GrContext* context = ctxInfo.grContext();
322
323 for (int ct = 0; ct <= kLastEnum_SkColorType; ++ct) {
324 SkColorType colorType = static_cast<SkColorType>(ct);
325
326 SkImageInfo ii = SkImageInfo::Make(32, 32, colorType, kPremul_SkAlphaType);
327
328 for (auto origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin } ) {
329 for (bool mipMaps : { true, false } ) {
330 for (int sampleCount : {1, 2}) {
331 SkSurfaceCharacterization c;
332
333 // Get a characterization, if possible
334 {
335 sk_sp<SkSurface> s = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo,
336 ii, sampleCount,
337 origin, nullptr, mipMaps);
338 if (!s) {
339 continue;
340 }
341
342 if (!s->characterize(&c)) {
343 continue;
344 }
345
346 REPORTER_ASSERT(reporter, s->isCompatible(c));
347 }
348
349 // Test out uninitialized path
350 {
351 GrBackendTexture backendTex = context->createBackendTexture(c);
352 check_vk_layout(backendTex, VkLayout::kUndefined);
353 REPORTER_ASSERT(reporter, backendTex.isValid());
354 REPORTER_ASSERT(reporter, c.isCompatible(backendTex));
355
356 {
357 GrBackendFormat format = context->defaultBackendFormat(
358 c.imageInfo().colorType(),
359 GrRenderable::kYes);
360 REPORTER_ASSERT(reporter, format == backendTex.getBackendFormat());
361 }
362
363 sk_sp<SkSurface> s2 = SkSurface::MakeFromBackendTexture(context, c,
364 backendTex);
365 REPORTER_ASSERT(reporter, s2);
366 REPORTER_ASSERT(reporter, s2->isCompatible(c));
367
368 s2 = nullptr;
369 context->deleteBackendTexture(backendTex);
370 }
371
372 // Test out color-initialized path
373 {
374 GrBackendTexture backendTex = context->createBackendTexture(c,
375 SkColors::kRed);
376 check_vk_layout(backendTex, VkLayout::kColorAttachmentOptimal);
377 REPORTER_ASSERT(reporter, backendTex.isValid());
378 REPORTER_ASSERT(reporter, c.isCompatible(backendTex));
379
380 {
381 GrBackendFormat format = context->defaultBackendFormat(
382 c.imageInfo().colorType(),
383 GrRenderable::kYes);
384 REPORTER_ASSERT(reporter, format == backendTex.getBackendFormat());
385 }
386
387 sk_sp<SkSurface> s2 = SkSurface::MakeFromBackendTexture(context, c,
388 backendTex);
389 REPORTER_ASSERT(reporter, s2);
390 REPORTER_ASSERT(reporter, s2->isCompatible(c));
391
392 s2 = nullptr;
393 context->deleteBackendTexture(backendTex);
394 }
395 }
396 }
397 }
398 }
399 }
400
401 ///////////////////////////////////////////////////////////////////////////////
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ColorTypeBackendAllocationTest,reporter,ctxInfo)402 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ColorTypeBackendAllocationTest, reporter, ctxInfo) {
403 GrContext* context = ctxInfo.grContext();
404 const GrCaps* caps = context->priv().caps();
405
406 constexpr SkColor4f kTransCol { 0, 0.25f, 0.75f, 0.5f };
407 constexpr SkColor4f kGrayCol { 0.75f, 0.75f, 0.75f, 0.75f };
408
409 struct {
410 SkColorType fColorType;
411 GrPixelConfig fConfig;
412 SkColor4f fColor;
413 } combinations[] = {
414 { kAlpha_8_SkColorType, kAlpha_8_GrPixelConfig, kTransCol },
415 { kRGB_565_SkColorType, kRGB_565_GrPixelConfig, SkColors::kRed },
416 { kARGB_4444_SkColorType, kRGBA_4444_GrPixelConfig, SkColors::kGreen },
417 { kRGBA_8888_SkColorType, kRGBA_8888_GrPixelConfig, SkColors::kBlue },
418 { kRGB_888x_SkColorType, kRGB_888_GrPixelConfig, SkColors::kCyan },
419 // TODO: readback is busted when alpha = 0.5f (perhaps premul vs. unpremul)
420 { kBGRA_8888_SkColorType, kBGRA_8888_GrPixelConfig, { 1, 0, 0, 1.0f } },
421 // TODO: readback is busted when alpha = 0.5f (perhaps premul vs. unpremul)
422 { kRGBA_1010102_SkColorType, kRGBA_1010102_GrPixelConfig, { 0.5f, 0, 0, 1.0f }},
423 // The kRGB_101010x_SkColorType has no Ganesh correlate
424 { kRGB_101010x_SkColorType, kUnknown_GrPixelConfig, { 0, 0.5f, 0, 0.5f }},
425 { kGray_8_SkColorType, kGray_8_GrPixelConfig, kGrayCol },
426 { kRGBA_F16Norm_SkColorType, kRGBA_half_Clamped_GrPixelConfig, SkColors::kLtGray },
427 { kRGBA_F16_SkColorType, kRGBA_half_GrPixelConfig, SkColors::kYellow },
428 { kRGBA_F32_SkColorType, kRGBA_float_GrPixelConfig, SkColors::kGray },
429 };
430
431 GR_STATIC_ASSERT(kLastEnum_SkColorType == SK_ARRAY_COUNT(combinations));
432
433 for (auto combo : combinations) {
434 SkColorType colorType = combo.fColorType;
435
436 if (GrBackendApi::kMetal == context->backend()) {
437 // skbug.com/9086 (Metal caps may not be handling RGBA32 correctly)
438 if (kRGBA_F32_SkColorType == combo.fColorType) {
439 continue;
440 }
441 }
442
443 for (auto mipMapped : { GrMipMapped::kNo, GrMipMapped::kYes }) {
444 if (GrMipMapped::kYes == mipMapped && !caps->mipMapSupport()) {
445 continue;
446 }
447
448 for (auto renderable : { GrRenderable::kNo, GrRenderable::kYes }) {
449 if (!caps->getDefaultBackendFormat(SkColorTypeToGrColorType(colorType),
450 renderable).isValid()) {
451 continue;
452 }
453 if (GrRenderable::kYes == renderable) {
454 if (kRGB_888x_SkColorType == combo.fColorType) {
455 // Ganesh can't perform the blends correctly when rendering this format
456 continue;
457 }
458 }
459
460 {
461 auto uninitCreateMtd = [colorType](GrContext* context,
462 GrMipMapped mipMapped,
463 GrRenderable renderable) {
464 auto result = context->createBackendTexture(32, 32, colorType,
465 mipMapped, renderable,
466 GrProtected::kNo);
467 check_vk_layout(result, VkLayout::kUndefined);
468
469 #ifdef SK_DEBUG
470 {
471 GrBackendFormat format = context->defaultBackendFormat(colorType,
472 renderable);
473 SkASSERT(format == result.getBackendFormat());
474 }
475 #endif
476
477 return result;
478 };
479
480 test_wrapping(context, reporter, uninitCreateMtd,
481 SkColorTypeToGrColorType(colorType), mipMapped, renderable);
482 }
483
484 {
485 // GL has difficulties reading back from these combinations. In particular,
486 // reading back kGray_8 is a mess.
487 if (GrBackendApi::kOpenGL == context->backend()) {
488 if (kAlpha_8_SkColorType == combo.fColorType ||
489 kGray_8_SkColorType == combo.fColorType) {
490 continue;
491 }
492 } else if (GrBackendApi::kMetal == context->backend()) {
493 // Not yet implemented for Metal
494 continue;
495 }
496
497 auto createWithColorMtd = [colorType](GrContext* context,
498 const SkColor4f& color,
499 GrMipMapped mipMapped,
500 GrRenderable renderable) {
501 auto result = context->createBackendTexture(32, 32, colorType, color,
502 mipMapped, renderable,
503 GrProtected::kNo);
504 check_vk_layout(result, GrRenderable::kYes == renderable
505 ? VkLayout::kColorAttachmentOptimal
506 : VkLayout::kReadOnlyOptimal);
507
508 #ifdef SK_DEBUG
509 {
510 GrBackendFormat format = context->defaultBackendFormat(colorType,
511 renderable);
512 SkASSERT(format == result.getBackendFormat());
513 }
514 #endif
515
516 return result;
517 };
518
519 test_color_init(context, reporter, createWithColorMtd,
520 SkColorTypeToGrColorType(colorType),
521 combo.fColor, mipMapped, renderable);
522 }
523 }
524 }
525 }
526
527 }
528
529 ///////////////////////////////////////////////////////////////////////////////
530 #ifdef SK_GL
531
532 #include "src/gpu/gl/GrGLCaps.h"
533 #include "src/gpu/gl/GrGLDefines.h"
534 #include "src/gpu/gl/GrGLUtil.h"
535
DEF_GPUTEST_FOR_ALL_GL_CONTEXTS(GLBackendAllocationTest,reporter,ctxInfo)536 DEF_GPUTEST_FOR_ALL_GL_CONTEXTS(GLBackendAllocationTest, reporter, ctxInfo) {
537 sk_gpu_test::GLTestContext* glCtx = ctxInfo.glContext();
538 GrGLStandard standard = glCtx->gl()->fStandard;
539 GrContext* context = ctxInfo.grContext();
540 const GrGLCaps* glCaps = static_cast<const GrGLCaps*>(context->priv().caps());
541
542 constexpr SkColor4f kTransCol { 0, 0.25f, 0.75f, 0.5f };
543 constexpr SkColor4f kGrayCol { 0.75f, 0.75f, 0.75f, 0.75f };
544
545 struct {
546 GrColorType fColorType;
547 GrGLenum fFormat;
548 SkColor4f fColor;
549 } combinations[] = {
550 { GrColorType::kRGBA_8888, GR_GL_RGBA8, SkColors::kRed },
551 { GrColorType::kRGBA_8888_SRGB, GR_GL_SRGB8_ALPHA8, SkColors::kRed },
552
553 { GrColorType::kRGB_888x, GR_GL_RGBA8, SkColors::kYellow },
554 { GrColorType::kRGB_888x, GR_GL_RGB8, SkColors::kCyan },
555
556 { GrColorType::kBGRA_8888, GR_GL_RGBA8, SkColors::kBlue },
557 { GrColorType::kBGRA_8888, GR_GL_BGRA8, SkColors::kBlue },
558 // TODO: readback is busted when alpha = 0.5f (perhaps premul vs. unpremul)
559 { GrColorType::kRGBA_1010102, GR_GL_RGB10_A2, { 0.5f, 0, 0, 1.0f } },
560 { GrColorType::kBGR_565, GR_GL_RGB565, SkColors::kRed },
561 { GrColorType::kABGR_4444, GR_GL_RGBA4, SkColors::kGreen },
562
563 { GrColorType::kAlpha_8, GR_GL_ALPHA8, kTransCol },
564 { GrColorType::kAlpha_8, GR_GL_R8, kTransCol },
565
566 { GrColorType::kGray_8, GR_GL_LUMINANCE8, kGrayCol },
567 { GrColorType::kGray_8, GR_GL_R8, kGrayCol },
568
569 { GrColorType::kRGBA_F32, GR_GL_RGBA32F, SkColors::kRed },
570
571 { GrColorType::kRGBA_F16_Clamped, GR_GL_RGBA16F, SkColors::kLtGray },
572 { GrColorType::kRGBA_F16, GR_GL_RGBA16F, SkColors::kYellow },
573
574 { GrColorType::kRG_88, GR_GL_RG8, { 0.5f, 0.5f, 0, 0 } },
575 { GrColorType::kAlpha_F16, GR_GL_R16F, { 1.0f, 0, 0, 0.5f } },
576 { GrColorType::kAlpha_F16, GR_GL_LUMINANCE16F, kGrayCol },
577
578 { GrColorType::kR_16, GR_GL_R16, SkColors::kRed },
579 { GrColorType::kRG_1616, GR_GL_RG16, SkColors::kYellow },
580
581 // Experimental (for Y416 and mutant P016/P010)
582 { GrColorType::kRGBA_16161616, GR_GL_RGBA16, SkColors::kLtGray },
583 { GrColorType::kRG_F16, GR_GL_RG16F, SkColors::kYellow },
584
585 { GrColorType::kUnknown, GR_GL_COMPRESSED_RGB8_ETC2, SkColors::kRed },
586 { GrColorType::kUnknown, GR_GL_COMPRESSED_ETC1_RGB8, SkColors::kRed },
587 };
588
589 for (auto combo : combinations) {
590 GrBackendFormat format = GrBackendFormat::MakeGL(combo.fFormat, GR_GL_TEXTURE_2D);
591
592 if (!glCaps->isFormatTexturable(format)) {
593 continue;
594 }
595
596 if (GrColorType::kBGRA_8888 == combo.fColorType) {
597 if (GR_GL_RGBA8 == combo.fFormat && kGL_GrGLStandard != standard) {
598 continue;
599 }
600 if (GR_GL_BGRA8 == combo.fFormat && kGL_GrGLStandard == standard) {
601 continue;
602 }
603 }
604
605 for (auto mipMapped : { GrMipMapped::kNo, GrMipMapped::kYes }) {
606 if (GrMipMapped::kYes == mipMapped && !glCaps->mipMapSupport()) {
607 continue;
608 }
609
610 for (auto renderable : { GrRenderable::kNo, GrRenderable::kYes }) {
611
612 if (GrRenderable::kYes == renderable) {
613 if (!glCaps->isFormatAsColorTypeRenderable(combo.fColorType, format)) {
614 continue;
615 }
616 }
617
618
619 // We current disallow uninitialized compressed textures in the GL backend
620 if (GR_GL_COMPRESSED_RGB8_ETC2 != combo.fFormat &&
621 GR_GL_COMPRESSED_ETC1_RGB8 != combo.fFormat) {
622 auto uninitCreateMtd = [format](GrContext* context,
623 GrMipMapped mipMapped,
624 GrRenderable renderable) {
625 return context->createBackendTexture(32, 32, format,
626 mipMapped, renderable,
627 GrProtected::kNo);
628 };
629
630 test_wrapping(context, reporter, uninitCreateMtd,
631 combo.fColorType, mipMapped, renderable);
632 }
633
634 {
635 // GL has difficulties reading back from these combinations
636 if (GrColorType::kAlpha_8 == combo.fColorType) {
637 continue;
638 }
639 if (GrRenderable::kYes != renderable) {
640 continue;
641 }
642
643 auto createWithColorMtd = [format](GrContext* context,
644 const SkColor4f& color,
645 GrMipMapped mipMapped,
646 GrRenderable renderable) {
647 return context->createBackendTexture(32, 32, format, color,
648 mipMapped, renderable,
649 GrProtected::kNo);
650 };
651
652 test_color_init(context, reporter, createWithColorMtd,
653 combo.fColorType, combo.fColor, mipMapped, renderable);
654 }
655 }
656 }
657 }
658 }
659
660 #endif
661
662 ///////////////////////////////////////////////////////////////////////////////
663
664 #ifdef SK_VULKAN
665
666 #include "src/gpu/vk/GrVkCaps.h"
667
DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkBackendAllocationTest,reporter,ctxInfo)668 DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkBackendAllocationTest, reporter, ctxInfo) {
669 GrContext* context = ctxInfo.grContext();
670 const GrVkCaps* vkCaps = static_cast<const GrVkCaps*>(context->priv().caps());
671
672 constexpr SkColor4f kTransCol { 0, 0.25f, 0.75f, 0.5f };
673 constexpr SkColor4f kGrayCol { 0.75f, 0.75f, 0.75f, 0.75f };
674
675 struct {
676 GrColorType fColorType;
677 VkFormat fFormat;
678 SkColor4f fColor;
679 } combinations[] = {
680 { GrColorType::kRGBA_8888, VK_FORMAT_R8G8B8A8_UNORM, SkColors::kRed },
681 { GrColorType::kRGBA_8888_SRGB, VK_FORMAT_R8G8B8A8_SRGB, SkColors::kRed },
682
683 // In this configuration (i.e., an RGB_888x colortype with an RGBA8 backing format),
684 // there is nothing to tell Skia to make the provided color opaque. Clients will need
685 // to provide an opaque initialization color in this case.
686 { GrColorType::kRGB_888x, VK_FORMAT_R8G8B8A8_UNORM, SkColors::kYellow },
687 { GrColorType::kRGB_888x, VK_FORMAT_R8G8B8_UNORM, SkColors::kCyan },
688
689 { GrColorType::kBGRA_8888, VK_FORMAT_B8G8R8A8_UNORM, SkColors::kBlue },
690
691 { GrColorType::kRGBA_1010102, VK_FORMAT_A2B10G10R10_UNORM_PACK32, { 0.5f, 0, 0, 1.0f }},
692 { GrColorType::kBGR_565, VK_FORMAT_R5G6B5_UNORM_PACK16, SkColors::kRed },
693
694 { GrColorType::kABGR_4444, VK_FORMAT_R4G4B4A4_UNORM_PACK16, SkColors::kCyan },
695 { GrColorType::kABGR_4444, VK_FORMAT_B4G4R4A4_UNORM_PACK16, SkColors::kYellow },
696
697 { GrColorType::kAlpha_8, VK_FORMAT_R8_UNORM, kTransCol },
698 // In this config (i.e., a Gray8 color type with an R8 backing format), there is nothing
699 // to tell Skia this isn't an Alpha8 color type (so it will initialize the texture with
700 // the alpha channel of the color). Clients should, in general, fill all the channels
701 // of the provided color with the same value in such cases.
702 { GrColorType::kGray_8, VK_FORMAT_R8_UNORM, kGrayCol },
703
704 { GrColorType::kRGBA_F32, VK_FORMAT_R32G32B32A32_SFLOAT, SkColors::kRed },
705
706 { GrColorType::kRGBA_F16_Clamped, VK_FORMAT_R16G16B16A16_SFLOAT, SkColors::kLtGray },
707 { GrColorType::kRGBA_F16, VK_FORMAT_R16G16B16A16_SFLOAT, SkColors::kYellow },
708
709 // These backend formats don't have SkColorType equivalents
710 { GrColorType::kRG_88, VK_FORMAT_R8G8_UNORM, { 0.5f, 0.5f, 0, 0 }},
711 { GrColorType::kAlpha_F16, VK_FORMAT_R16_SFLOAT, { 1.0f, 0, 0, 0.5f }},
712
713 { GrColorType::kR_16, VK_FORMAT_R16_UNORM, SkColors::kRed },
714 { GrColorType::kRG_1616, VK_FORMAT_R16G16_UNORM, SkColors::kYellow },
715
716 // Experimental (for Y416 and mutant P016/P010)
717 { GrColorType::kRGBA_16161616, VK_FORMAT_R16G16B16A16_UNORM, SkColors::kLtGray },
718 { GrColorType::kRG_F16, VK_FORMAT_R16G16_SFLOAT, SkColors::kYellow },
719
720 { GrColorType::kUnknown, VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, SkColors::kRed },
721 };
722
723 for (auto combo : combinations) {
724 if (!vkCaps->isVkFormatTexturable(combo.fFormat)) {
725 continue;
726 }
727
728 GrBackendFormat format = GrBackendFormat::MakeVk(combo.fFormat);
729
730 for (auto mipMapped : { GrMipMapped::kNo, GrMipMapped::kYes }) {
731 if (GrMipMapped::kYes == mipMapped && !vkCaps->mipMapSupport()) {
732 continue;
733 }
734
735 for (auto renderable : { GrRenderable::kNo, GrRenderable::kYes }) {
736
737 if (GrRenderable::kYes == renderable) {
738 // We must also check whether we allow rendering to the format using the
739 // color type.
740 if (!vkCaps->isFormatAsColorTypeRenderable(
741 combo.fColorType, GrBackendFormat::MakeVk(combo.fFormat), 1)) {
742 continue;
743 }
744 }
745
746 // We current disallow uninitialized compressed textures in the Vulkan backend
747 if (combo.fFormat != VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK) {
748 auto uninitCreateMtd = [format](GrContext* context,
749 GrMipMapped mipMapped,
750 GrRenderable renderable) {
751 GrBackendTexture beTex = context->createBackendTexture(32, 32, format,
752 mipMapped,
753 renderable,
754 GrProtected::kNo);
755 check_vk_layout(beTex, VkLayout::kUndefined);
756 return beTex;
757 };
758
759 test_wrapping(context, reporter, uninitCreateMtd,
760 combo.fColorType, mipMapped, renderable);
761 }
762
763 {
764 // We're creating backend textures without specifying a color type "view" of
765 // them at the public API level. Therefore, Ganesh will not apply any swizzles
766 // before writing the color to the texture. However, our validation code does
767 // rely on interpreting the texture contents via a SkColorType and therefore
768 // swizzles may be applied during the read step.
769 // Ideally we'd update our validation code to use a "raw" read that doesn't
770 // impose a color type but for now we just munge the data we upload to match the
771 // expectation.
772 GrSwizzle swizzle;
773 switch (combo.fColorType) {
774 case GrColorType::kAlpha_8:
775 SkASSERT(combo.fFormat == VK_FORMAT_R8_UNORM);
776 swizzle = GrSwizzle("aaaa");
777 break;
778 case GrColorType::kABGR_4444:
779 if (combo.fFormat == VK_FORMAT_B4G4R4A4_UNORM_PACK16) {
780 swizzle = GrSwizzle("bgra");
781 }
782 break;
783 default:
784 swizzle = GrSwizzle("rgba");
785 break;
786 }
787 auto createWithColorMtd = [format, swizzle](GrContext* context,
788 const SkColor4f& color,
789 GrMipMapped mipMapped,
790 GrRenderable renderable) {
791 auto swizzledColor = swizzle.applyTo(color);
792 GrBackendTexture beTex = context->createBackendTexture(32, 32, format,
793 swizzledColor,
794 mipMapped,
795 renderable,
796 GrProtected::kNo);
797 check_vk_layout(beTex, GrRenderable::kYes == renderable
798 ? VkLayout::kColorAttachmentOptimal
799 : VkLayout::kReadOnlyOptimal);
800 return beTex;
801 };
802 test_color_init(context, reporter, createWithColorMtd,
803 combo.fColorType, combo.fColor, mipMapped, renderable);
804 }
805 }
806 }
807 }
808 }
809
810 #endif
811