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