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