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