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