1/*
2 * Copyright 2017 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/SkBitmap.h"
9#include "include/core/SkCanvas.h"
10#include "include/core/SkColor.h"
11#include "include/core/SkColorSpace.h"
12#include "include/core/SkDeferredDisplayList.h"
13#include "include/core/SkDeferredDisplayListRecorder.h"
14#include "include/core/SkImage.h"
15#include "include/core/SkImageInfo.h"
16#include "include/core/SkPaint.h"
17#include "include/core/SkPromiseImageTexture.h"
18#include "include/core/SkRect.h"
19#include "include/core/SkRefCnt.h"
20#include "include/core/SkSurface.h"
21#include "include/core/SkSurfaceCharacterization.h"
22#include "include/core/SkSurfaceProps.h"
23#include "include/core/SkTypes.h"
24#include "include/gpu/GrBackendSurface.h"
25#include "include/gpu/GrContextThreadSafeProxy.h"
26#include "include/gpu/GrDirectContext.h"
27#include "include/gpu/GrRecordingContext.h"
28#include "include/gpu/GrTypes.h"
29#include "include/gpu/gl/GrGLTypes.h"
30#include "include/private/GrTypesPriv.h"
31#include "src/core/SkDeferredDisplayListPriv.h"
32#include "src/gpu/GrCaps.h"
33#include "src/gpu/GrDirectContextPriv.h"
34#include "src/gpu/GrGpu.h"
35#include "src/gpu/GrRecordingContextPriv.h"
36#include "src/gpu/GrRenderTargetProxy.h"
37#include "src/gpu/GrTextureProxy.h"
38#include "src/gpu/gl/GrGLDefines.h"
39#include "src/image/SkImage_GpuBase.h"
40#include "src/image/SkSurface_Gpu.h"
41#include "tests/Test.h"
42#include "tests/TestUtils.h"
43#include "tools/gpu/BackendSurfaceFactory.h"
44#include "tools/gpu/GrContextFactory.h"
45#include "tools/gpu/ManagedBackendTexture.h"
46#include "tools/gpu/ProxyUtils.h"
47
48#include <initializer_list>
49#include <memory>
50#include <utility>
51
52#ifdef SK_VULKAN
53#include "src/gpu/vk/GrVkCaps.h"
54#include "src/gpu/vk/GrVkSecondaryCBDrawContext.h"
55#endif
56
57class SurfaceParameters {
58public:
59    static const int kNumParams      = 13;
60    static const int kFBO0Count      = 9;
61    static const int kVkSCBCount     = 12;
62
63    SurfaceParameters(GrRecordingContext* rContext)
64            : fBackend(rContext->backend())
65            , fCanBeProtected(false)
66            , fWidth(64)
67            , fHeight(64)
68            , fOrigin(kTopLeft_GrSurfaceOrigin)
69            , fColorType(kRGBA_8888_SkColorType)
70            , fColorSpace(SkColorSpace::MakeSRGB())
71            , fSampleCount(1)
72            , fSurfaceProps(0x0, kUnknown_SkPixelGeometry)
73            , fShouldCreateMipMaps(true)
74            , fUsesGLFBO0(false)
75            , fIsTextureable(true)
76            , fIsProtected(GrProtected::kNo)
77            , fVkRTSupportsInputAttachment(false)
78            , fForVulkanSecondaryCommandBuffer(false) {
79#ifdef SK_VULKAN
80        if (rContext->backend() == GrBackendApi::kVulkan) {
81            auto vkCaps = static_cast<const GrVkCaps*>(rContext->priv().caps());
82            fCanBeProtected = vkCaps->supportsProtectedMemory();
83            if (fCanBeProtected) {
84                fIsProtected = GrProtected::kYes;
85            }
86        }
87#endif
88        if (!rContext->priv().caps()->mipmapSupport()) {
89            fShouldCreateMipMaps = false;
90        }
91    }
92
93    int sampleCount() const { return fSampleCount; }
94
95    void setColorType(SkColorType ct) { fColorType = ct; }
96    SkColorType colorType() const { return fColorType; }
97    void setColorSpace(sk_sp<SkColorSpace> cs) { fColorSpace = std::move(cs); }
98    void disableTextureability() {
99        fIsTextureable = false;
100        fShouldCreateMipMaps = false;
101    }
102    void setShouldCreateMipMaps(bool shouldCreateMipMaps) {
103        fShouldCreateMipMaps = shouldCreateMipMaps;
104    }
105    void setVkRTInputAttachmentSupport(bool inputSupport) {
106        fVkRTSupportsInputAttachment = inputSupport;
107    }
108    void setForVulkanSecondaryCommandBuffer(bool forVkSCB) {
109        fForVulkanSecondaryCommandBuffer = forVkSCB;
110    }
111
112    // Modify the SurfaceParameters in just one way. Returns false if the requested modification had
113    // no effect.
114    bool modify(int i) {
115        bool changed = false;
116        auto set = [&changed](auto& var, auto value) {
117            if (var != value) {
118                changed = true;
119            }
120            var = value;
121        };
122        switch (i) {
123        case 0:
124            set(fWidth, 63);
125            break;
126        case 1:
127            set(fHeight, 63);
128            break;
129        case 2:
130            set(fOrigin, kBottomLeft_GrSurfaceOrigin);
131            break;
132        case 3:
133            set(fColorType, kRGBA_F16_SkColorType);
134            break;
135        case 4:
136            // This just needs to be a colorSpace different from that returned by MakeSRGB().
137            // In this case we just change the gamut.
138            set(fColorSpace, SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
139                                                   SkNamedGamut::kAdobeRGB));
140            break;
141        case 5:
142            set(fSampleCount, 4);
143            break;
144        case 6:
145            set(fSurfaceProps, SkSurfaceProps(0x0, kRGB_H_SkPixelGeometry));
146            break;
147        case 7:
148            set(fSurfaceProps, SkSurfaceProps(SkSurfaceProps::kUseDeviceIndependentFonts_Flag,
149                                              kUnknown_SkPixelGeometry));
150            break;
151        case 8:
152            set(fShouldCreateMipMaps, false);
153            break;
154        case 9:
155            if (GrBackendApi::kOpenGL == fBackend) {
156                set(fUsesGLFBO0, true);
157                set(fShouldCreateMipMaps, false);  // needs to changed in tandem w/ textureability
158                set(fIsTextureable, false);
159            }
160            break;
161        case 10:
162            set(fShouldCreateMipMaps, false);  // needs to changed in tandem w/ textureability
163            set(fIsTextureable, false);
164            break;
165        case 11:
166            if (fCanBeProtected) {
167                set(fIsProtected, GrProtected(!static_cast<bool>(fIsProtected)));
168            }
169            break;
170        case 12:
171            if (GrBackendApi::kVulkan == fBackend) {
172                set(fForVulkanSecondaryCommandBuffer, true);
173                set(fUsesGLFBO0, false);
174                set(fShouldCreateMipMaps, false);  // needs to changed in tandem w/ textureability
175                set(fIsTextureable, false);
176                set(fVkRTSupportsInputAttachment, false);
177            }
178            break;
179        }
180        return changed;
181    }
182
183    SkSurfaceCharacterization createCharacterization(GrDirectContext* dContext) const {
184        size_t maxResourceBytes = dContext->getResourceCacheLimit();
185
186        if (!dContext->colorTypeSupportedAsSurface(fColorType)) {
187            return SkSurfaceCharacterization();
188        }
189
190        // Note that Ganesh doesn't make use of the SkImageInfo's alphaType
191        SkImageInfo ii = SkImageInfo::Make(fWidth, fHeight, fColorType,
192                                           kPremul_SkAlphaType, fColorSpace);
193
194        GrBackendFormat backendFormat = dContext->defaultBackendFormat(fColorType,
195                                                                       GrRenderable::kYes);
196        if (!backendFormat.isValid()) {
197            return SkSurfaceCharacterization();
198        }
199
200        SkSurfaceCharacterization c = dContext->threadSafeProxy()->createCharacterization(
201                                                maxResourceBytes, ii, backendFormat, fSampleCount,
202                                                fOrigin, fSurfaceProps, fShouldCreateMipMaps,
203                                                fUsesGLFBO0, fIsTextureable, fIsProtected,
204                                                fVkRTSupportsInputAttachment,
205                                                fForVulkanSecondaryCommandBuffer);
206        return c;
207    }
208
209    // Create a DDL whose characterization captures the current settings
210    sk_sp<SkDeferredDisplayList> createDDL(GrDirectContext* dContext) const {
211        SkSurfaceCharacterization c = this->createCharacterization(dContext);
212        SkAssertResult(c.isValid());
213
214        SkDeferredDisplayListRecorder r(c);
215        SkCanvas* canvas = r.getCanvas();
216        if (!canvas) {
217            return nullptr;
218        }
219
220        canvas->drawRect(SkRect::MakeXYWH(10, 10, 10, 10), SkPaint());
221        return r.detach();
222    }
223
224    // Create the surface with the current set of parameters
225    sk_sp<SkSurface> make(GrDirectContext* dContext) const {
226        const SkSurfaceCharacterization c = this->createCharacterization(dContext);
227
228#ifdef SK_GL
229        if (fUsesGLFBO0) {
230            if (GrBackendApi::kOpenGL != dContext->backend()) {
231                return nullptr;
232            }
233
234            GrGLFramebufferInfo fboInfo;
235            fboInfo.fFBOID = 0;
236            fboInfo.fFormat = GR_GL_RGBA8;
237            static constexpr int kStencilBits = 8;
238            GrBackendRenderTarget backendRT(fWidth, fHeight, 1, kStencilBits, fboInfo);
239
240            if (!backendRT.isValid()) {
241                return nullptr;
242            }
243
244            sk_sp<SkSurface> result = SkSurface::MakeFromBackendRenderTarget(dContext, backendRT,
245                                                                             fOrigin, fColorType,
246                                                                             fColorSpace,
247                                                                             &fSurfaceProps);
248            SkASSERT(result->isCompatible(c));
249            return result;
250        }
251#endif
252
253        // We can't make SkSurfaces for vulkan secondary command buffers.
254        if (fForVulkanSecondaryCommandBuffer) {
255            return nullptr;
256        }
257
258        sk_sp<SkSurface> surface;
259        if (fIsTextureable) {
260            surface = sk_gpu_test::MakeBackendTextureSurface(dContext,
261                                                             {fWidth, fHeight},
262                                                             fOrigin,
263                                                             fSampleCount,
264                                                             fColorType,
265                                                             fColorSpace,
266                                                             GrMipmapped(fShouldCreateMipMaps),
267                                                             fIsProtected,
268                                                             &fSurfaceProps);
269        } else {
270            // Create a surface w/ the current parameters but make it non-textureable
271            SkASSERT(!fShouldCreateMipMaps);
272            surface = sk_gpu_test::MakeBackendRenderTargetSurface(dContext,
273                                                                  {fWidth, fHeight},
274                                                                  fOrigin,
275                                                                  fSampleCount,
276                                                                  fColorType,
277                                                                  fColorSpace,
278                                                                  fIsProtected,
279                                                                  &fSurfaceProps);
280        }
281
282        if (!surface) {
283            SkASSERT(!c.isValid());
284            return nullptr;
285        }
286
287        GrBackendTexture texture =
288                surface->getBackendTexture(SkSurface::kFlushRead_BackendHandleAccess);
289        if (texture.isValid()) {
290            SkASSERT(c.isCompatible(texture));
291        }
292        SkASSERT(c.isValid());
293        SkASSERT(surface->isCompatible(c));
294        return surface;
295    }
296
297#ifdef SK_VULKAN
298    sk_sp<GrVkSecondaryCBDrawContext> makeVkSCB(GrDirectContext* dContext) {
299        const SkSurfaceCharacterization c = this->createCharacterization(dContext);
300        SkImageInfo imageInfo = SkImageInfo::Make({fWidth, fHeight},
301                                                  {fColorType, kPremul_SkAlphaType, fColorSpace});
302        GrVkDrawableInfo vkInfo;
303        // putting in a bunch of placeholder values here
304        vkInfo.fSecondaryCommandBuffer = (VkCommandBuffer)1;
305        vkInfo.fColorAttachmentIndex = 0;
306        vkInfo.fCompatibleRenderPass = (VkRenderPass)1;
307        vkInfo.fFormat = VK_FORMAT_R8G8B8A8_UNORM;
308        vkInfo.fDrawBounds = nullptr;
309        vkInfo.fImage = (VkImage)1;
310
311        return GrVkSecondaryCBDrawContext::Make(dContext, imageInfo, vkInfo, &fSurfaceProps);
312    }
313#endif
314
315private:
316    GrBackendApi        fBackend;
317    bool                fCanBeProtected;
318
319    int                 fWidth;
320    int                 fHeight;
321    GrSurfaceOrigin     fOrigin;
322    SkColorType         fColorType;
323    sk_sp<SkColorSpace> fColorSpace;
324    int                 fSampleCount;
325    SkSurfaceProps      fSurfaceProps;
326    bool                fShouldCreateMipMaps;
327    bool                fUsesGLFBO0;
328    bool                fIsTextureable;
329    GrProtected         fIsProtected;
330    bool                fVkRTSupportsInputAttachment;
331    bool                fForVulkanSecondaryCommandBuffer;
332};
333
334// Test out operator== && operator!=
335DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLOperatorEqTest, reporter, ctxInfo) {
336    auto context = ctxInfo.directContext();
337
338    for (int i = -1; i < SurfaceParameters::kNumParams; ++i) {
339        SurfaceParameters params1(context);
340        bool didModify1 = i >= 0 && params1.modify(i);
341
342        SkSurfaceCharacterization char1 = params1.createCharacterization(context);
343        if (!char1.isValid()) {
344            continue;  // can happen on some platforms (ChromeOS)
345        }
346
347        for (int j = -1; j < SurfaceParameters::kNumParams; ++j) {
348            SurfaceParameters params2(context);
349            bool didModify2 = j >= 0 && params2.modify(j);
350
351            SkSurfaceCharacterization char2 = params2.createCharacterization(context);
352            if (!char2.isValid()) {
353                continue;  // can happen on some platforms (ChromeOS)
354            }
355
356            if (i == j || (!didModify1 && !didModify2)) {
357                REPORTER_ASSERT(reporter, char1 == char2);
358            } else {
359                REPORTER_ASSERT(reporter, char1 != char2);
360            }
361        }
362    }
363
364    {
365        SurfaceParameters params(context);
366
367        SkSurfaceCharacterization valid = params.createCharacterization(context);
368        SkASSERT(valid.isValid());
369
370        SkSurfaceCharacterization inval1, inval2;
371        SkASSERT(!inval1.isValid() && !inval2.isValid());
372
373        REPORTER_ASSERT(reporter, inval1 != inval2);
374        REPORTER_ASSERT(reporter, valid != inval1);
375        REPORTER_ASSERT(reporter, inval1 != valid);
376    }
377}
378
379////////////////////////////////////////////////////////////////////////////////
380// This tests SkSurfaceCharacterization/SkSurface compatibility
381void DDLSurfaceCharacterizationTestImpl(GrDirectContext* dContext, skiatest::Reporter* reporter) {
382    // Create a bitmap that we can readback into
383    SkImageInfo imageInfo = SkImageInfo::Make(64, 64, kRGBA_8888_SkColorType,
384                                              kPremul_SkAlphaType);
385    SkBitmap bitmap;
386    bitmap.allocPixels(imageInfo);
387
388    sk_sp<SkDeferredDisplayList> ddl;
389
390    // First, create a DDL using the stock SkSurface parameters
391    {
392        SurfaceParameters params(dContext);
393        if (dContext->backend() == GrBackendApi::kVulkan) {
394            params.setVkRTInputAttachmentSupport(true);
395        }
396        ddl = params.createDDL(dContext);
397        SkAssertResult(ddl);
398
399        // The DDL should draw into an SkSurface created with the same parameters
400        sk_sp<SkSurface> s = params.make(dContext);
401        if (!s) {
402            return;
403        }
404
405        REPORTER_ASSERT(reporter, s->draw(ddl));
406        s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
407
408        dContext->flush();
409    }
410
411    // Then, alter each parameter in turn and check that the DDL & surface are incompatible
412    for (int i = 0; i < SurfaceParameters::kNumParams; ++i) {
413        SurfaceParameters params(dContext);
414        if (!params.modify(i)) {
415            continue;
416        }
417
418        sk_sp<SkSurface> s = params.make(dContext);
419        if (!s) {
420            continue;
421        }
422
423        REPORTER_ASSERT(reporter, !s->draw(ddl),
424                        "DDLSurfaceCharacterizationTest failed on parameter: %d\n", i);
425        dContext->flush();
426    }
427
428    // Next test the compatibility of resource cache parameters
429    {
430        const SurfaceParameters params(dContext);
431
432        sk_sp<SkSurface> s = params.make(dContext);
433
434        size_t maxResourceBytes = dContext->getResourceCacheLimit();
435
436        dContext->setResourceCacheLimit(maxResourceBytes/2);
437        REPORTER_ASSERT(reporter, !s->draw(ddl));
438
439        // DDL TODO: once proxies/ops can be de-instantiated we can re-enable these tests.
440        // For now, DDLs are drawn once.
441#if 0
442        // resource limits >= those at characterization time are accepted
443        context->setResourceCacheLimits(2*maxResourceCount, maxResourceBytes);
444        REPORTER_ASSERT(reporter, s->draw(ddl));
445        s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
446
447        context->setResourceCacheLimits(maxResourceCount, 2*maxResourceBytes);
448        REPORTER_ASSERT(reporter, s->draw(ddl));
449        s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
450
451        context->setResourceCacheLimits(maxResourceCount, maxResourceBytes);
452        REPORTER_ASSERT(reporter, s->draw(ddl));
453        s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
454#endif
455
456        dContext->flush();
457    }
458
459    // Test that the textureability of the DDL characterization can block a DDL draw
460    {
461        SurfaceParameters params(dContext);
462        params.disableTextureability();
463
464        sk_sp<SkSurface> s = params.make(dContext);
465        if (s) {
466            REPORTER_ASSERT(reporter, !s->draw(ddl)); // bc the DDL was made w/ textureability
467
468            dContext->flush();
469        }
470    }
471
472    // Make sure non-GPU-backed surfaces fail characterization
473    {
474        SkImageInfo ii = SkImageInfo::MakeN32(64, 64, kOpaque_SkAlphaType);
475
476        sk_sp<SkSurface> rasterSurface = SkSurface::MakeRaster(ii);
477        SkSurfaceCharacterization c;
478        REPORTER_ASSERT(reporter, !rasterSurface->characterize(&c));
479    }
480
481    // Exercise the createResized method
482    {
483        SurfaceParameters params(dContext);
484
485        sk_sp<SkSurface> s = params.make(dContext);
486        if (!s) {
487            return;
488        }
489
490        SkSurfaceCharacterization char0;
491        SkAssertResult(s->characterize(&char0));
492
493        // Too small
494        SkSurfaceCharacterization char1 = char0.createResized(-1, -1);
495        REPORTER_ASSERT(reporter, !char1.isValid());
496
497        // Too large
498        SkSurfaceCharacterization char2 = char0.createResized(1000000, 32);
499        REPORTER_ASSERT(reporter, !char2.isValid());
500
501        // Just right
502        SkSurfaceCharacterization char3 = char0.createResized(32, 32);
503        REPORTER_ASSERT(reporter, char3.isValid());
504        REPORTER_ASSERT(reporter, 32 == char3.width());
505        REPORTER_ASSERT(reporter, 32 == char3.height());
506    }
507
508    // Exercise the createColorSpace method
509    {
510        SurfaceParameters params(dContext);
511
512        sk_sp<SkSurface> s = params.make(dContext);
513        if (!s) {
514            return;
515        }
516
517        SkSurfaceCharacterization char0;
518        SkAssertResult(s->characterize(&char0));
519
520        // The default params create an sRGB color space
521        REPORTER_ASSERT(reporter, char0.colorSpace()->isSRGB());
522        REPORTER_ASSERT(reporter, !char0.colorSpace()->gammaIsLinear());
523
524        {
525            sk_sp<SkColorSpace> newCS = SkColorSpace::MakeSRGBLinear();
526
527            SkSurfaceCharacterization char1 = char0.createColorSpace(std::move(newCS));
528            REPORTER_ASSERT(reporter, char1.isValid());
529            REPORTER_ASSERT(reporter, !char1.colorSpace()->isSRGB());
530            REPORTER_ASSERT(reporter, char1.colorSpace()->gammaIsLinear());
531        }
532
533        {
534            SkSurfaceCharacterization char2 = char0.createColorSpace(nullptr);
535            REPORTER_ASSERT(reporter, char2.isValid());
536            REPORTER_ASSERT(reporter, !char2.colorSpace());
537        }
538
539        {
540            sk_sp<SkColorSpace> newCS = SkColorSpace::MakeSRGBLinear();
541
542            SkSurfaceCharacterization invalid;
543            REPORTER_ASSERT(reporter, !invalid.isValid());
544            SkSurfaceCharacterization stillInvalid = invalid.createColorSpace(std::move(newCS));
545            REPORTER_ASSERT(reporter, !stillInvalid.isValid());
546        }
547    }
548
549    // Exercise the createBackendFormat method
550    {
551        SurfaceParameters params(dContext);
552
553        sk_sp<SkSurface> s = params.make(dContext);
554        if (!s) {
555            return;
556        }
557
558        SkSurfaceCharacterization char0;
559        SkAssertResult(s->characterize(&char0));
560
561        // The default params create a renderable RGBA8 surface
562        auto originalBackendFormat = dContext->defaultBackendFormat(kRGBA_8888_SkColorType,
563                                                                    GrRenderable::kYes);
564        REPORTER_ASSERT(reporter, originalBackendFormat.isValid());
565        REPORTER_ASSERT(reporter, char0.backendFormat() == originalBackendFormat);
566
567        auto newBackendFormat = dContext->defaultBackendFormat(kRGB_565_SkColorType,
568                                                               GrRenderable::kYes);
569
570        if (newBackendFormat.isValid()) {
571            SkSurfaceCharacterization char1 = char0.createBackendFormat(kRGB_565_SkColorType,
572                                                                        newBackendFormat);
573            REPORTER_ASSERT(reporter, char1.isValid());
574            REPORTER_ASSERT(reporter, char1.backendFormat() == newBackendFormat);
575
576            SkSurfaceCharacterization invalid;
577            REPORTER_ASSERT(reporter, !invalid.isValid());
578            auto stillInvalid = invalid.createBackendFormat(kRGB_565_SkColorType,
579                                                            newBackendFormat);
580            REPORTER_ASSERT(reporter, !stillInvalid.isValid());
581        }
582    }
583
584    // Exercise the createFBO0 method
585    if (dContext->backend() == GrBackendApi::kOpenGL) {
586        SurfaceParameters params(dContext);
587        // If the original characterization is textureable then we will fail trying to make an
588        // FBO0 characterization
589        params.disableTextureability();
590
591        sk_sp<SkSurface> s = params.make(dContext);
592        if (!s) {
593            return;
594        }
595
596        SkSurfaceCharacterization char0;
597        SkAssertResult(s->characterize(&char0));
598
599        // The default params create a non-FBO0 surface
600        REPORTER_ASSERT(reporter, !char0.usesGLFBO0());
601
602        {
603            SkSurfaceCharacterization char1 = char0.createFBO0(true);
604            REPORTER_ASSERT(reporter, char1.isValid());
605            REPORTER_ASSERT(reporter, char1.usesGLFBO0());
606        }
607
608        {
609            SkSurfaceCharacterization invalid;
610            REPORTER_ASSERT(reporter, !invalid.isValid());
611            SkSurfaceCharacterization stillInvalid = invalid.createFBO0(true);
612            REPORTER_ASSERT(reporter, !stillInvalid.isValid());
613        }
614    }
615}
616
617#ifdef SK_GL
618
619// Test out the surface compatibility checks regarding FBO0-ness. This test constructs
620// two parallel arrays of characterizations and surfaces in the order:
621//    FBO0 w/ MSAA, FBO0 w/o MSAA, not-FBO0 w/ MSAA, not-FBO0 w/o MSAA
622// and then tries all sixteen combinations to check the expected compatibility.
623// Note: this is a GL-only test
624DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(CharacterizationFBO0nessTest, reporter, ctxInfo) {
625    auto context = ctxInfo.directContext();
626    const GrCaps* caps = context->priv().caps();
627    sk_sp<GrContextThreadSafeProxy> proxy = context->threadSafeProxy();
628    const size_t resourceCacheLimit = context->getResourceCacheLimit();
629
630    GrBackendFormat format = GrBackendFormat::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_2D);
631
632    int availableSamples = caps->getRenderTargetSampleCount(4, format);
633    if (availableSamples <= 1) {
634        // This context doesn't support MSAA for RGBA8
635        return;
636    }
637
638    SkImageInfo ii = SkImageInfo::Make({ 128, 128 }, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
639
640    static constexpr int kStencilBits = 8;
641    static constexpr bool kNotMipMapped = false;
642    static constexpr bool kNotTextureable = false;
643    const SkSurfaceProps surfaceProps(0x0, kRGB_H_SkPixelGeometry);
644
645    // Rows are characterizations and columns are surfaces
646    static const bool kExpectedCompatibility[4][4] = {
647                    //  FBO0 & MSAA, FBO0 & not-MSAA, not-FBO0 & MSAA, not-FBO0 & not-MSAA
648/* FBO0 & MSAA     */ { true,        false,           false,           false },
649/* FBO0 & not-MSAA */ { false,       true,            false,           true  },
650/* not-FBO0 & MSAA */ { false,       false,           true,            false },
651/* not-FBO0 & not- */ { false,       false,           false,           true  }
652    };
653
654    SkSurfaceCharacterization characterizations[4];
655    sk_sp<SkSurface> surfaces[4];
656
657    int index = 0;
658    for (bool isFBO0 : { true, false }) {
659        for (int numSamples : { availableSamples, 1 }) {
660            characterizations[index] = proxy->createCharacterization(resourceCacheLimit,
661                                                                     ii, format, numSamples,
662                                                                     kTopLeft_GrSurfaceOrigin,
663                                                                     surfaceProps, kNotMipMapped,
664                                                                     isFBO0, kNotTextureable);
665            SkASSERT(characterizations[index].sampleCount() == numSamples);
666            SkASSERT(characterizations[index].usesGLFBO0() == isFBO0);
667
668            GrGLFramebufferInfo fboInfo{ isFBO0 ? 0 : (GrGLuint) 1, GR_GL_RGBA8 };
669            GrBackendRenderTarget backendRT(128, 128, numSamples, kStencilBits, fboInfo);
670            SkAssertResult(backendRT.isValid());
671
672            surfaces[index] = SkSurface::MakeFromBackendRenderTarget(context, backendRT,
673                                                                     kTopLeft_GrSurfaceOrigin,
674                                                                     kRGBA_8888_SkColorType,
675                                                                     nullptr, &surfaceProps);
676            ++index;
677        }
678    }
679
680    for (int c = 0; c < 4; ++c) {
681        for (int s = 0; s < 4; ++s) {
682            REPORTER_ASSERT(reporter,
683                            kExpectedCompatibility[c][s] ==
684                                                 surfaces[s]->isCompatible(characterizations[c]));
685        }
686    }
687}
688#endif
689
690#ifdef SK_VULKAN
691DEF_GPUTEST_FOR_VULKAN_CONTEXT(CharacterizationVkSCBnessTest, reporter, ctxInfo) {
692    auto dContext = ctxInfo.directContext();
693
694    SurfaceParameters params(dContext);
695    params.modify(SurfaceParameters::kVkSCBCount);
696    SkSurfaceCharacterization characterization = params.createCharacterization(dContext);
697    REPORTER_ASSERT(reporter, characterization.isValid());
698
699    sk_sp<SkDeferredDisplayList> ddl = params.createDDL(dContext);
700    REPORTER_ASSERT(reporter, ddl.get());
701
702    sk_sp<GrVkSecondaryCBDrawContext> scbDrawContext = params.makeVkSCB(dContext);
703    REPORTER_ASSERT(reporter, scbDrawContext->isCompatible(characterization));
704
705    scbDrawContext->releaseResources();
706}
707#endif
708
709DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLSurfaceCharacterizationTest, reporter, ctxInfo) {
710    auto context = ctxInfo.directContext();
711
712    DDLSurfaceCharacterizationTestImpl(context, reporter);
713}
714
715// Test that a DDL created w/o textureability can be replayed into both a textureable and
716// non-textureable destination. Note that DDLSurfaceCharacterizationTest tests that a
717// textureable DDL cannot be played into a non-textureable destination but can be replayed
718// into a textureable destination.
719DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLNonTextureabilityTest, reporter, ctxInfo) {
720    auto context = ctxInfo.directContext();
721
722    // Create a bitmap that we can readback into
723    SkImageInfo imageInfo = SkImageInfo::Make(64, 64, kRGBA_8888_SkColorType,
724                                              kPremul_SkAlphaType);
725    SkBitmap bitmap;
726    bitmap.allocPixels(imageInfo);
727
728    for (bool textureability : { true, false }) {
729        sk_sp<SkDeferredDisplayList> ddl;
730
731        // First, create a DDL w/o textureability (and thus no mipmaps). TODO: once we have
732        // reusable DDLs, move this outside of the loop.
733        {
734            SurfaceParameters params(context);
735            params.disableTextureability();
736            if (context->backend() == GrBackendApi::kVulkan) {
737                params.setVkRTInputAttachmentSupport(true);
738            }
739
740            ddl = params.createDDL(context);
741            SkAssertResult(ddl);
742        }
743
744        // Then verify it can draw into either flavor of destination
745        SurfaceParameters params(context);
746        if (!textureability) {
747            params.disableTextureability();
748        }
749        if (context->backend() == GrBackendApi::kVulkan) {
750            params.setVkRTInputAttachmentSupport(true);
751        }
752
753        sk_sp<SkSurface> s = params.make(context);
754        if (!s) {
755            continue;
756        }
757
758        REPORTER_ASSERT(reporter, s->draw(ddl));
759        s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
760
761        context->flush();
762    }
763
764}
765
766static void test_make_render_target(skiatest::Reporter* reporter,
767                                    GrDirectContext* dContext,
768                                    const SurfaceParameters& params) {
769    {
770        const SkSurfaceCharacterization c = params.createCharacterization(dContext);
771
772        if (!c.isValid()) {
773            sk_sp<SkSurface> tmp = params.make(dContext);
774            // If we couldn't characterize the surface we shouldn't be able to create it either
775            REPORTER_ASSERT(reporter, !tmp);
776            return;
777        }
778    }
779
780    const SkSurfaceCharacterization c = params.createCharacterization(dContext);
781    {
782        sk_sp<SkSurface> s = params.make(dContext);
783        REPORTER_ASSERT(reporter, s);
784        if (!s) {
785            REPORTER_ASSERT(reporter, !c.isValid());
786            return;
787        }
788
789        REPORTER_ASSERT(reporter, c.isValid());
790        GrBackendTexture backend = s->getBackendTexture(SkSurface::kFlushRead_BackendHandleAccess);
791        if (backend.isValid()) {
792            REPORTER_ASSERT(reporter, c.isCompatible(backend));
793        }
794        REPORTER_ASSERT(reporter, s->isCompatible(c));
795        // Note that we're leaving 'backend' live here
796    }
797
798    // Make an SkSurface from scratch
799    {
800        sk_sp<SkSurface> s = SkSurface::MakeRenderTarget(dContext, c, SkBudgeted::kYes);
801        REPORTER_ASSERT(reporter, s);
802        REPORTER_ASSERT(reporter, s->isCompatible(c));
803    }
804}
805
806////////////////////////////////////////////////////////////////////////////////
807// This tests the SkSurface::MakeRenderTarget variants that take an SkSurfaceCharacterization.
808// In particular, the SkSurface, backendTexture and SkSurfaceCharacterization
809// should always be compatible.
810void DDLMakeRenderTargetTestImpl(GrDirectContext* dContext, skiatest::Reporter* reporter) {
811    for (int i = -1; i < SurfaceParameters::kNumParams; ++i) {
812        if (i == SurfaceParameters::kFBO0Count || i == SurfaceParameters::kVkSCBCount) {
813            // MakeRenderTarget doesn't support FBO0 or vulkan secondary command buffers
814            continue;
815        }
816
817        SurfaceParameters params(dContext);
818        if (i >= 0 && !params.modify(i)) {
819            continue;
820        }
821
822        test_make_render_target(reporter, dContext, params);
823    }
824}
825
826DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLMakeRenderTargetTest, reporter, ctxInfo) {
827    auto context = ctxInfo.directContext();
828
829    DDLMakeRenderTargetTestImpl(context, reporter);
830}
831
832////////////////////////////////////////////////////////////////////////////////
833static constexpr int kSize = 8;
834
835struct TextureReleaseChecker {
836    TextureReleaseChecker() : fReleaseCount(0) {}
837    int fReleaseCount;
838    static void Release(void* self) {
839        static_cast<TextureReleaseChecker*>(self)->fReleaseCount++;
840    }
841};
842
843enum class DDLStage { kMakeImage, kDrawImage, kDetach, kDrawDDL };
844
845// This tests the ability to create and use wrapped textures in a DDL world
846DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLWrapBackendTest, reporter, ctxInfo) {
847    auto dContext = ctxInfo.directContext();
848
849    auto mbet = sk_gpu_test::ManagedBackendTexture::MakeWithoutData(dContext,
850                                                                    kSize,
851                                                                    kSize,
852                                                                    kRGBA_8888_SkColorType,
853                                                                    GrMipmapped::kNo,
854                                                                    GrRenderable::kNo,
855                                                                    GrProtected::kNo);
856    if (!mbet) {
857        return;
858    }
859
860    SurfaceParameters params(dContext);
861
862    sk_sp<SkSurface> s = params.make(dContext);
863    if (!s) {
864        return;
865    }
866
867    SkSurfaceCharacterization c;
868    SkAssertResult(s->characterize(&c));
869
870    SkDeferredDisplayListRecorder recorder(c);
871
872    SkCanvas* canvas = recorder.getCanvas();
873    SkASSERT(canvas);
874
875    auto rContext = canvas->recordingContext();
876    if (!rContext) {
877        return;
878    }
879
880    // Wrapped Backend Textures are not supported in DDL
881    TextureReleaseChecker releaseChecker;
882    sk_sp<SkImage> image = SkImage::MakeFromTexture(
883            rContext,
884            mbet->texture(),
885            kTopLeft_GrSurfaceOrigin,
886            kRGBA_8888_SkColorType,
887            kPremul_SkAlphaType,
888            nullptr,
889            sk_gpu_test::ManagedBackendTexture::ReleaseProc,
890            mbet->releaseContext(TextureReleaseChecker::Release, &releaseChecker));
891    REPORTER_ASSERT(reporter, !image);
892}
893
894////////////////////////////////////////////////////////////////////////////////
895// Test out the behavior of an invalid DDLRecorder
896DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLInvalidRecorder, reporter, ctxInfo) {
897    auto dContext = ctxInfo.directContext();
898
899    {
900        SkImageInfo ii = SkImageInfo::MakeN32Premul(32, 32);
901        sk_sp<SkSurface> s = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, ii);
902
903        SkSurfaceCharacterization characterization;
904        SkAssertResult(s->characterize(&characterization));
905
906        // never calling getCanvas means the backing surface is never allocated
907        SkDeferredDisplayListRecorder recorder(characterization);
908    }
909
910    {
911        SkSurfaceCharacterization invalid;
912
913        SkDeferredDisplayListRecorder recorder(invalid);
914
915        const SkSurfaceCharacterization c = recorder.characterization();
916        REPORTER_ASSERT(reporter, !c.isValid());
917        REPORTER_ASSERT(reporter, !recorder.getCanvas());
918        REPORTER_ASSERT(reporter, !recorder.detach());
919    }
920}
921
922DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLCreateCharacterizationFailures, reporter, ctxInfo) {
923    auto dContext = ctxInfo.directContext();
924    size_t maxResourceBytes = dContext->getResourceCacheLimit();
925    auto proxy = dContext->threadSafeProxy().get();
926
927    auto check_create_fails =
928            [proxy, reporter, maxResourceBytes](const GrBackendFormat& backendFormat,
929                                                int width, int height,
930                                                SkColorType ct, bool willUseGLFBO0,
931                                                bool isTextureable,
932                                                GrProtected prot,
933                                                bool vkRTSupportsInputAttachment,
934                                                bool forVulkanSecondaryCommandBuffer) {
935        const SkSurfaceProps surfaceProps(0x0, kRGB_H_SkPixelGeometry);
936
937        SkImageInfo ii = SkImageInfo::Make(width, height, ct,
938                                           kPremul_SkAlphaType, nullptr);
939
940        SkSurfaceCharacterization c = proxy->createCharacterization(
941                                                maxResourceBytes, ii, backendFormat, 1,
942                                                kBottomLeft_GrSurfaceOrigin, surfaceProps, false,
943                                                willUseGLFBO0, isTextureable, prot,
944                                                vkRTSupportsInputAttachment,
945                                                forVulkanSecondaryCommandBuffer);
946        REPORTER_ASSERT(reporter, !c.isValid());
947    };
948
949    GrBackendFormat goodBackendFormat = dContext->defaultBackendFormat(kRGBA_8888_SkColorType,
950                                                                       GrRenderable::kYes);
951    SkASSERT(goodBackendFormat.isValid());
952
953    GrBackendFormat badBackendFormat;
954    SkASSERT(!badBackendFormat.isValid());
955
956    SkColorType kGoodCT = kRGBA_8888_SkColorType;
957    SkColorType kBadCT = kUnknown_SkColorType;
958
959    static const bool kIsTextureable = true;
960    static const bool kIsNotTextureable = false;
961
962    static const bool kGoodUseFBO0 = false;
963    static const bool kBadUseFBO0 = true;
964
965    static const bool kGoodVkInputAttachment = false;
966    static const bool kBadVkInputAttachment = true;
967
968    static const bool kGoodForVkSCB = false;
969    static const bool kBadForVkSCB = true;
970
971    int goodWidth = 64;
972    int goodHeight = 64;
973    int badWidths[] = { 0, 1048576 };
974    int badHeights[] = { 0, 1048576 };
975
976
977    // In each of the check_create_fails calls there is one bad parameter that should cause the
978    // creation of the characterization to fail.
979    check_create_fails(goodBackendFormat, goodWidth, badHeights[0], kGoodCT, kGoodUseFBO0,
980                       kIsTextureable, GrProtected::kNo, kGoodVkInputAttachment, kGoodForVkSCB);
981    check_create_fails(goodBackendFormat, goodWidth, badHeights[1], kGoodCT, kGoodUseFBO0,
982                       kIsTextureable, GrProtected::kNo, kGoodVkInputAttachment, kGoodForVkSCB);
983    check_create_fails(goodBackendFormat, badWidths[0], goodHeight, kGoodCT, kGoodUseFBO0,
984                       kIsTextureable, GrProtected::kNo, kGoodVkInputAttachment, kGoodForVkSCB);
985    check_create_fails(goodBackendFormat, badWidths[1], goodHeight, kGoodCT, kGoodUseFBO0,
986                       kIsTextureable, GrProtected::kNo, kGoodVkInputAttachment, kGoodForVkSCB);
987    check_create_fails(badBackendFormat, goodWidth, goodHeight, kGoodCT, kGoodUseFBO0,
988                       kIsTextureable, GrProtected::kNo, kGoodVkInputAttachment, kGoodForVkSCB);
989    check_create_fails(goodBackendFormat, goodWidth, goodHeight, kBadCT, kGoodUseFBO0,
990                       kIsTextureable, GrProtected::kNo, kGoodVkInputAttachment, kGoodForVkSCB);
991    // This fails because we always try to make a characterization that is textureable and we can't
992    // have UseFBO0 be true and textureable.
993    check_create_fails(goodBackendFormat, goodWidth, goodHeight, kGoodCT, kBadUseFBO0,
994                       kIsTextureable, GrProtected::kNo, kGoodVkInputAttachment, kGoodForVkSCB);
995    if (dContext->backend() == GrBackendApi::kVulkan) {
996        // The bad parameter in this case is the GrProtected::kYes since none of our test contexts
997        // are made protected we can't have a protected surface.
998        check_create_fails(goodBackendFormat, goodWidth, goodHeight, kGoodCT, kGoodUseFBO0,
999                           kIsTextureable, GrProtected::kYes, kGoodVkInputAttachment,
1000                           kGoodForVkSCB);
1001        // The following fails because forVulkanSecondaryCommandBuffer is true and
1002        // isTextureable is true. This is not a legal combination.
1003        check_create_fails(goodBackendFormat, goodWidth, goodHeight, kGoodCT, kGoodUseFBO0,
1004                           kIsTextureable, GrProtected::kNo, kGoodVkInputAttachment, kBadForVkSCB);
1005        // The following fails because forVulkanSecondaryCommandBuffer is true and
1006        // vkRTSupportsInputAttachment is true. This is not a legal combination.
1007        check_create_fails(goodBackendFormat, goodWidth, goodHeight, kGoodCT, kGoodUseFBO0,
1008                           kIsNotTextureable, GrProtected::kNo, kBadVkInputAttachment,
1009                           kBadForVkSCB);
1010        // The following fails because forVulkanSecondaryCommandBuffer is true and
1011        // willUseGLFBO0 is true. This is not a legal combination.
1012        check_create_fails(goodBackendFormat, goodWidth, goodHeight, kGoodCT, kBadUseFBO0,
1013                           kIsNotTextureable, GrProtected::kNo, kGoodVkInputAttachment,
1014                           kBadForVkSCB);
1015    } else {
1016        // The following set vulkan only flags on non vulkan backends.
1017        check_create_fails(goodBackendFormat, goodWidth, goodHeight, kGoodCT, kGoodUseFBO0,
1018                           kIsTextureable, GrProtected::kNo, kBadVkInputAttachment, kGoodForVkSCB);
1019        check_create_fails(goodBackendFormat, goodWidth, goodHeight, kGoodCT, kGoodUseFBO0,
1020                           kIsNotTextureable, GrProtected::kNo, kGoodVkInputAttachment,
1021                           kBadForVkSCB);
1022    }
1023}
1024
1025////////////////////////////////////////////////////////////////////////////////
1026// Test that flushing a DDL via SkSurface::flush works
1027
1028struct FulfillInfo {
1029    sk_sp<SkPromiseImageTexture> fTex;
1030    bool fFulfilled = false;
1031    bool fReleased  = false;
1032};
1033
1034static sk_sp<SkPromiseImageTexture> tracking_fulfill_proc(void* context) {
1035    FulfillInfo* info = (FulfillInfo*) context;
1036    info->fFulfilled = true;
1037    return info->fTex;
1038}
1039
1040static void tracking_release_proc(void* context) {
1041    FulfillInfo* info = (FulfillInfo*) context;
1042    info->fReleased = true;
1043}
1044
1045DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLSkSurfaceFlush, reporter, ctxInfo) {
1046    auto context = ctxInfo.directContext();
1047
1048    SkImageInfo ii = SkImageInfo::Make(32, 32, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
1049    sk_sp<SkSurface> s = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, ii);
1050
1051    SkSurfaceCharacterization characterization;
1052    SkAssertResult(s->characterize(&characterization));
1053
1054    auto mbet = sk_gpu_test::ManagedBackendTexture::MakeFromInfo(context, ii);
1055    if (!mbet) {
1056        ERRORF(reporter, "Could not make texture.");
1057        return;
1058    }
1059
1060    FulfillInfo fulfillInfo;
1061    fulfillInfo.fTex = SkPromiseImageTexture::Make(mbet->texture());
1062
1063    sk_sp<SkDeferredDisplayList> ddl;
1064
1065    {
1066        SkDeferredDisplayListRecorder recorder(characterization);
1067
1068        GrBackendFormat format = context->defaultBackendFormat(kRGBA_8888_SkColorType,
1069                                                               GrRenderable::kNo);
1070        SkASSERT(format.isValid());
1071
1072        SkCanvas* canvas = recorder.getCanvas();
1073
1074        sk_sp<SkImage> promiseImage = SkImage::MakePromiseTexture(
1075                                                      canvas->recordingContext()->threadSafeProxy(),
1076                                                      format,
1077                                                      SkISize::Make(32, 32),
1078                                                      GrMipmapped::kNo,
1079                                                      kTopLeft_GrSurfaceOrigin,
1080                                                      kRGBA_8888_SkColorType,
1081                                                      kPremul_SkAlphaType,
1082                                                      nullptr,
1083                                                      tracking_fulfill_proc,
1084                                                      tracking_release_proc,
1085                                                      &fulfillInfo);
1086
1087        canvas->clear(SK_ColorRED);
1088        canvas->drawImage(promiseImage, 0, 0);
1089        ddl = recorder.detach();
1090    }
1091
1092    context->flushAndSubmit();
1093
1094    s->draw(ddl);
1095
1096    GrFlushInfo flushInfo;
1097    s->flush(SkSurface::BackendSurfaceAccess::kPresent, flushInfo);
1098    context->submit();
1099
1100    REPORTER_ASSERT(reporter, fulfillInfo.fFulfilled);
1101
1102    // In order to receive the done callback with the low-level APIs we need to re-flush
1103    s->flush();
1104    context->submit(true);
1105
1106    REPORTER_ASSERT(reporter, fulfillInfo.fReleased);
1107
1108    REPORTER_ASSERT(reporter, fulfillInfo.fTex->unique());
1109    fulfillInfo.fTex.reset();
1110}
1111
1112////////////////////////////////////////////////////////////////////////////////
1113// Ensure that reusing a single DDLRecorder to create multiple DDLs works cleanly
1114DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLMultipleDDLs, reporter, ctxInfo) {
1115    auto context = ctxInfo.directContext();
1116
1117    SkImageInfo ii = SkImageInfo::MakeN32Premul(32, 32);
1118    sk_sp<SkSurface> s = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, ii);
1119
1120    SkBitmap bitmap;
1121    bitmap.allocPixels(ii);
1122
1123    SkSurfaceCharacterization characterization;
1124    SkAssertResult(s->characterize(&characterization));
1125
1126    SkDeferredDisplayListRecorder recorder(characterization);
1127
1128    SkCanvas* canvas1 = recorder.getCanvas();
1129
1130    canvas1->clear(SK_ColorRED);
1131
1132    canvas1->save();
1133    canvas1->clipRect(SkRect::MakeXYWH(8, 8, 16, 16));
1134
1135    sk_sp<SkDeferredDisplayList> ddl1 = recorder.detach();
1136
1137    SkCanvas* canvas2 = recorder.getCanvas();
1138
1139    SkPaint p;
1140    p.setColor(SK_ColorGREEN);
1141    canvas2->drawRect(SkRect::MakeWH(32, 32), p);
1142
1143    sk_sp<SkDeferredDisplayList> ddl2 = recorder.detach();
1144
1145    REPORTER_ASSERT(reporter, ddl1->priv().lazyProxyData());
1146    REPORTER_ASSERT(reporter, ddl2->priv().lazyProxyData());
1147
1148    // The lazy proxy data being different ensures that the SkSurface, SkCanvas and backing-
1149    // lazy proxy are all different between the two DDLs
1150    REPORTER_ASSERT(reporter, ddl1->priv().lazyProxyData() != ddl2->priv().lazyProxyData());
1151
1152    s->draw(ddl1);
1153    s->draw(ddl2);
1154
1155    // Make sure the clipRect from DDL1 didn't percolate into DDL2
1156    s->readPixels(ii, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
1157    for (int y = 0; y < 32; ++y) {
1158        for (int x = 0; x < 32; ++x) {
1159            REPORTER_ASSERT(reporter, bitmap.getColor(x, y) == SK_ColorGREEN);
1160            if (bitmap.getColor(x, y) != SK_ColorGREEN) {
1161                return; // we only really need to report the error once
1162            }
1163        }
1164    }
1165}
1166
1167#ifdef SK_GL
1168
1169static sk_sp<SkPromiseImageTexture> noop_fulfill_proc(void*) {
1170    SkASSERT(0);
1171    return nullptr;
1172}
1173
1174////////////////////////////////////////////////////////////////////////////////
1175// Check that the texture-specific flags (i.e., for external & rectangle textures) work
1176// for promise images. As such, this is a GL-only test.
1177DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(DDLTextureFlagsTest, reporter, ctxInfo) {
1178    auto context = ctxInfo.directContext();
1179
1180    SkImageInfo ii = SkImageInfo::MakeN32Premul(32, 32);
1181    sk_sp<SkSurface> s = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, ii);
1182
1183    SkSurfaceCharacterization characterization;
1184    SkAssertResult(s->characterize(&characterization));
1185
1186    SkDeferredDisplayListRecorder recorder(characterization);
1187
1188    for (GrGLenum target : { GR_GL_TEXTURE_EXTERNAL, GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_2D } ) {
1189        for (auto mipMapped : { GrMipmapped::kNo, GrMipmapped::kYes }) {
1190            GrBackendFormat format = GrBackendFormat::MakeGL(GR_GL_RGBA8, target);
1191
1192            sk_sp<SkImage> image = SkImage::MakePromiseTexture(
1193                    recorder.getCanvas()->recordingContext()->threadSafeProxy(),
1194                    format,
1195                    SkISize::Make(32, 32),
1196                    mipMapped,
1197                    kTopLeft_GrSurfaceOrigin,
1198                    kRGBA_8888_SkColorType,
1199                    kPremul_SkAlphaType,
1200                    /*color space*/nullptr,
1201                    noop_fulfill_proc,
1202                    /*release proc*/ nullptr,
1203                    /*context*/nullptr);
1204            if (GR_GL_TEXTURE_2D != target && mipMapped == GrMipmapped::kYes) {
1205                REPORTER_ASSERT(reporter, !image);
1206                continue;
1207            }
1208            REPORTER_ASSERT(reporter, image);
1209
1210            GrTextureProxy* backingProxy = sk_gpu_test::GetTextureImageProxy(image.get(), context);
1211
1212            REPORTER_ASSERT(reporter, backingProxy->mipmapped() == mipMapped);
1213            if (GR_GL_TEXTURE_2D == target) {
1214                REPORTER_ASSERT(reporter, !backingProxy->hasRestrictedSampling());
1215            } else {
1216                REPORTER_ASSERT(reporter, backingProxy->hasRestrictedSampling());
1217            }
1218        }
1219    }
1220}
1221#endif  // SK_GL
1222
1223////////////////////////////////////////////////////////////////////////////////
1224// Test colorType and pixelConfig compatibility.
1225DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(DDLCompatibilityTest, reporter, ctxInfo) {
1226    auto context = ctxInfo.directContext();
1227
1228    for (int ct = 0; ct <= kLastEnum_SkColorType; ++ct) {
1229        SkColorType colorType = static_cast<SkColorType>(ct);
1230
1231        SurfaceParameters params(context);
1232        params.setColorType(colorType);
1233        params.setColorSpace(nullptr);
1234
1235        test_make_render_target(reporter, context, params);
1236    }
1237
1238}
1239