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