• 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/SkDeferredDisplayListRecorder.h"
13 #include "include/core/SkImage.h"
14 #include "include/core/SkImageInfo.h"
15 #include "include/core/SkPaint.h"
16 #include "include/core/SkPromiseImageTexture.h"
17 #include "include/core/SkRect.h"
18 #include "include/core/SkRefCnt.h"
19 #include "include/core/SkSurface.h"
20 #include "include/core/SkSurfaceCharacterization.h"
21 #include "include/core/SkSurfaceProps.h"
22 #include "include/core/SkTypes.h"
23 #include "include/gpu/GrBackendSurface.h"
24 #include "include/gpu/GrContext.h"
25 #include "include/gpu/GrContextThreadSafeProxy.h"
26 #include "include/gpu/GrTypes.h"
27 #include "include/gpu/gl/GrGLTypes.h"
28 #include "include/private/GrTypesPriv.h"
29 #include "include/private/SkDeferredDisplayList.h"
30 #include "src/core/SkDeferredDisplayListPriv.h"
31 #include "src/gpu/GrCaps.h"
32 #include "src/gpu/GrContextPriv.h"
33 #include "src/gpu/GrGpu.h"
34 #include "src/gpu/GrRenderTargetContext.h"
35 #include "src/gpu/GrRenderTargetProxy.h"
36 #include "src/gpu/GrTextureProxy.h"
37 #include "src/gpu/SkGpuDevice.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/GrContextFactory.h"
44 
45 #include <initializer_list>
46 #include <memory>
47 #include <utility>
48 
49 #ifdef SK_VULKAN
50 #include "src/gpu/vk/GrVkCaps.h"
51 #endif
52 
53 class SurfaceParameters {
54 public:
55     static const int kNumParams      = 12;
56     static const int kSampleCount    = 5;
57     static const int kMipMipCount    = 8;
58     static const int kFBO0Count      = 9;
59     static const int kProtectedCount = 11;
60 
SurfaceParameters(GrContext * context)61     SurfaceParameters(GrContext* context)
62             : fBackend(context->backend())
63             , fWidth(64)
64             , fHeight(64)
65             , fOrigin(kTopLeft_GrSurfaceOrigin)
66             , fColorType(kRGBA_8888_SkColorType)
67             , fColorSpace(SkColorSpace::MakeSRGB())
68             , fSampleCount(1)
69             , fSurfaceProps(0x0, kUnknown_SkPixelGeometry)
70             , fShouldCreateMipMaps(true)
71             , fUsesGLFBO0(false)
72             , fIsTextureable(true)
73             , fIsProtected(GrProtected::kNo) {
74 #ifdef SK_VULKAN
75         if (GrBackendApi::kVulkan == context->backend()) {
76             const GrVkCaps* vkCaps = (const GrVkCaps*) context->priv().caps();
77 
78             fIsProtected = GrProtected(vkCaps->supportsProtectedMemory());
79         }
80 #endif
81     }
82 
sampleCount() const83     int sampleCount() const { return fSampleCount; }
84 
setColorType(SkColorType ct)85     void setColorType(SkColorType ct) { fColorType = ct; }
colorType() const86     SkColorType colorType() const { return fColorType; }
setColorSpace(sk_sp<SkColorSpace> cs)87     void setColorSpace(sk_sp<SkColorSpace> cs) { fColorSpace = std::move(cs); }
setTextureable(bool isTextureable)88     void setTextureable(bool isTextureable) { fIsTextureable = isTextureable; }
setShouldCreateMipMaps(bool shouldCreateMipMaps)89     void setShouldCreateMipMaps(bool shouldCreateMipMaps) {
90         fShouldCreateMipMaps = shouldCreateMipMaps;
91     }
92 
93     // Modify the SurfaceParameters in just one way
modify(int i)94     void modify(int i) {
95         switch (i) {
96         case 0:
97             fWidth = 63;
98             break;
99         case 1:
100             fHeight = 63;
101             break;
102         case 2:
103             fOrigin = kBottomLeft_GrSurfaceOrigin;
104             break;
105         case 3:
106             fColorType = kRGBA_F16_SkColorType;
107             break;
108         case 4:
109             // This just needs to be a colorSpace different from that returned by MakeSRGB().
110             // In this case we just change the gamut.
111             fColorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB);
112             break;
113         case kSampleCount:
114             fSampleCount = 4;
115             break;
116         case 6:
117             fSurfaceProps = SkSurfaceProps(0x0, kRGB_H_SkPixelGeometry);
118             break;
119         case 7:
120             fSurfaceProps = SkSurfaceProps(SkSurfaceProps::kUseDeviceIndependentFonts_Flag,
121                                            kUnknown_SkPixelGeometry);
122             break;
123         case 8:
124             fShouldCreateMipMaps = false;
125             break;
126         case 9:
127             if (GrBackendApi::kOpenGL == fBackend) {
128                 fUsesGLFBO0 = true;
129                 fShouldCreateMipMaps = false; // needs to changed in tandem w/ textureability
130                 fIsTextureable = false;
131             }
132             break;
133         case 10:
134             fShouldCreateMipMaps = false; // needs to changed in tandem w/ textureability
135             fIsTextureable = false;
136             break;
137         case 11:
138             fIsProtected = GrProtected::kYes == fIsProtected ? GrProtected::kNo
139                                                              : GrProtected::kYes;
140             break;
141         }
142     }
143 
createCharacterization(GrContext * context) const144     SkSurfaceCharacterization createCharacterization(GrContext* context) const {
145         int maxResourceCount;
146         size_t maxResourceBytes;
147         context->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes);
148 
149         // Note that Ganesh doesn't make use of the SkImageInfo's alphaType
150         SkImageInfo ii = SkImageInfo::Make(fWidth, fHeight, fColorType,
151                                            kPremul_SkAlphaType, fColorSpace);
152 
153         GrBackendFormat backendFormat = context->defaultBackendFormat(fColorType,
154                                                                       GrRenderable::kYes);
155         if (!backendFormat.isValid()) {
156             return SkSurfaceCharacterization();
157         }
158 
159         SkSurfaceCharacterization c = context->threadSafeProxy()->createCharacterization(
160                                                 maxResourceBytes, ii, backendFormat, fSampleCount,
161                                                 fOrigin, fSurfaceProps, fShouldCreateMipMaps,
162                                                 fUsesGLFBO0, fIsTextureable, fIsProtected);
163         return c;
164     }
165 
166     // Create a DDL whose characterization captures the current settings
createDDL(GrContext * context) const167     std::unique_ptr<SkDeferredDisplayList> createDDL(GrContext* context) const {
168         SkSurfaceCharacterization c = this->createCharacterization(context);
169         SkAssertResult(c.isValid());
170 
171         SkDeferredDisplayListRecorder r(c);
172         SkCanvas* canvas = r.getCanvas();
173         if (!canvas) {
174             return nullptr;
175         }
176 
177         canvas->drawRect(SkRect::MakeXYWH(10, 10, 10, 10), SkPaint());
178         return r.detach();
179     }
180 
181     // Create the surface with the current set of parameters
make(GrContext * context,GrBackendTexture * backend) const182     sk_sp<SkSurface> make(GrContext* context, GrBackendTexture* backend) const {
183         const SkSurfaceCharacterization c = this->createCharacterization(context);
184 
185         GrMipMapped mipmapped = !fIsTextureable
186                                         ? GrMipMapped::kNo
187                                         : GrMipMapped(fShouldCreateMipMaps);
188 
189         if (fUsesGLFBO0) {
190             if (GrBackendApi::kOpenGL != context->backend()) {
191                 return nullptr;
192             }
193 
194             GrGLFramebufferInfo fboInfo;
195             fboInfo.fFBOID = 0;
196             fboInfo.fFormat = GR_GL_RGBA8;
197             static constexpr int kStencilBits = 8;
198             GrBackendRenderTarget backendRT(fWidth, fHeight, 1, kStencilBits, fboInfo);
199 
200             if (!backendRT.isValid()) {
201                 return nullptr;
202             }
203 
204             sk_sp<SkSurface> result = SkSurface::MakeFromBackendRenderTarget(context, backendRT,
205                                                                              fOrigin, fColorType,
206                                                                              fColorSpace,
207                                                                              &fSurfaceProps);
208             SkASSERT(result->isCompatible(c));
209             return result;
210         }
211 
212         *backend = context->createBackendTexture(fWidth, fHeight, fColorType,
213                                                  SkColors::kTransparent,
214                                                  mipmapped, GrRenderable::kYes, fIsProtected);
215         if (!backend->isValid()) {
216             return nullptr;
217         }
218 
219         // Even if a characterization couldn't be constructed we want to soldier on to make
220         // sure that surface creation will/would've also failed
221         SkASSERT(!c.isValid() || c.isCompatible(*backend));
222 
223         sk_sp<SkSurface> surface;
224         if (!fIsTextureable) {
225             // Create a surface w/ the current parameters but make it non-textureable
226             surface = SkSurface::MakeFromBackendTextureAsRenderTarget(
227                                             context, *backend, fOrigin, fSampleCount, fColorType,
228                                             fColorSpace, &fSurfaceProps);
229         } else {
230             surface = SkSurface::MakeFromBackendTexture(
231                                             context, *backend, fOrigin, fSampleCount, fColorType,
232                                             fColorSpace, &fSurfaceProps);
233         }
234 
235         if (!surface) {
236             SkASSERT(!c.isValid());
237             this->cleanUpBackEnd(context, *backend);
238             return nullptr;
239         }
240 
241         SkASSERT(c.isValid());
242         SkASSERT(surface->isCompatible(c));
243         return surface;
244     }
245 
cleanUpBackEnd(GrContext * context,const GrBackendTexture & backend) const246     void cleanUpBackEnd(GrContext* context, const GrBackendTexture& backend) const {
247         context->deleteBackendTexture(backend);
248     }
249 
250 private:
251     GrBackendApi        fBackend;
252     int                 fWidth;
253     int                 fHeight;
254     GrSurfaceOrigin     fOrigin;
255     SkColorType         fColorType;
256     sk_sp<SkColorSpace> fColorSpace;
257     int                 fSampleCount;
258     SkSurfaceProps      fSurfaceProps;
259     bool                fShouldCreateMipMaps;
260     bool                fUsesGLFBO0;
261     bool                fIsTextureable;
262     GrProtected         fIsProtected;
263 };
264 
265 // Test out operator== && operator!=
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLOperatorEqTest,reporter,ctxInfo)266 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLOperatorEqTest, reporter, ctxInfo) {
267     GrContext* context = ctxInfo.grContext();
268 
269     for (int i = 0; i < SurfaceParameters::kNumParams; ++i) {
270         SurfaceParameters params1(context);
271         params1.modify(i);
272 
273         SkSurfaceCharacterization char1 = params1.createCharacterization(context);
274         if (!char1.isValid()) {
275             continue;  // can happen on some platforms (ChromeOS)
276         }
277 
278         for (int j = 0; j < SurfaceParameters::kNumParams; ++j) {
279             SurfaceParameters params2(context);
280             params2.modify(j);
281 
282             SkSurfaceCharacterization char2 = params2.createCharacterization(context);
283             if (!char2.isValid()) {
284                 continue;  // can happen on some platforms (ChromeOS)
285             }
286 
287             if (i == j) {
288                 REPORTER_ASSERT(reporter, char1 == char2);
289             } else {
290                 REPORTER_ASSERT(reporter, char1 != char2);
291             }
292 
293         }
294     }
295 
296     {
297         SurfaceParameters params(context);
298 
299         SkSurfaceCharacterization valid = params.createCharacterization(context);
300         SkASSERT(valid.isValid());
301 
302         SkSurfaceCharacterization inval1, inval2;
303         SkASSERT(!inval1.isValid() && !inval2.isValid());
304 
305         REPORTER_ASSERT(reporter, inval1 != inval2);
306         REPORTER_ASSERT(reporter, valid != inval1);
307         REPORTER_ASSERT(reporter, inval1 != valid);
308     }
309 }
310 
311 ////////////////////////////////////////////////////////////////////////////////
312 // This tests SkSurfaceCharacterization/SkSurface compatibility
DDLSurfaceCharacterizationTestImpl(GrContext * context,skiatest::Reporter * reporter)313 void DDLSurfaceCharacterizationTestImpl(GrContext* context, skiatest::Reporter* reporter) {
314     GrGpu* gpu = context->priv().getGpu();
315     const GrCaps* caps = context->priv().caps();
316 
317     // Create a bitmap that we can readback into
318     SkImageInfo imageInfo = SkImageInfo::Make(64, 64, kRGBA_8888_SkColorType,
319                                               kPremul_SkAlphaType);
320     SkBitmap bitmap;
321     bitmap.allocPixels(imageInfo);
322 
323     std::unique_ptr<SkDeferredDisplayList> ddl;
324 
325     // First, create a DDL using the stock SkSurface parameters
326     {
327         SurfaceParameters params(context);
328 
329         ddl = params.createDDL(context);
330         SkAssertResult(ddl);
331 
332         // The DDL should draw into an SkSurface created with the same parameters
333         GrBackendTexture backend;
334         sk_sp<SkSurface> s = params.make(context, &backend);
335         if (!s) {
336             return;
337         }
338 
339         REPORTER_ASSERT(reporter, s->draw(ddl.get()));
340         s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
341         context->flush();
342         gpu->testingOnly_flushGpuAndSync();
343         s = nullptr;
344         params.cleanUpBackEnd(context, backend);
345     }
346 
347     // Then, alter each parameter in turn and check that the DDL & surface are incompatible
348     for (int i = 0; i < SurfaceParameters::kNumParams; ++i) {
349         SurfaceParameters params(context);
350         params.modify(i);
351 
352         if (SurfaceParameters::kProtectedCount == i) {
353             if (context->backend() != GrBackendApi::kVulkan) {
354                 // Only the Vulkan backend respects the protected parameter
355                 continue;
356             }
357 #ifdef SK_VULKAN
358             const GrVkCaps* vkCaps = (const GrVkCaps*) context->priv().caps();
359 
360             // And, even then, only when it is a protected context
361             if (!vkCaps->supportsProtectedMemory()) {
362                 continue;
363             }
364 #endif
365         }
366 
367         GrBackendTexture backend;
368         sk_sp<SkSurface> s = params.make(context, &backend);
369         if (!s) {
370             continue;
371         }
372 
373         if (SurfaceParameters::kSampleCount == i) {
374             int supportedSampleCount = caps->getRenderTargetSampleCount(
375                     params.sampleCount(), backend.getBackendFormat());
376             if (1 == supportedSampleCount) {
377                 // If changing the sample count won't result in a different
378                 // surface characterization, skip this step
379                 s = nullptr;
380                 params.cleanUpBackEnd(context, backend);
381                 continue;
382             }
383         }
384 
385         if (SurfaceParameters::kMipMipCount == i && !caps->mipMapSupport()) {
386             // If changing the mipmap setting won't result in a different surface characterization,
387             // skip this step
388             s = nullptr;
389             params.cleanUpBackEnd(context, backend);
390             continue;
391         }
392 
393         if (SurfaceParameters::kFBO0Count == i && context->backend() != GrBackendApi::kOpenGL) {
394             // FBO0 only affects the surface characterization when using OpenGL
395             s = nullptr;
396             params.cleanUpBackEnd(context, backend);
397             continue;
398         }
399 
400         REPORTER_ASSERT(reporter, !s->draw(ddl.get()),
401                         "DDLSurfaceCharacterizationTest failed on parameter: %d\n", i);
402 
403         context->flush();
404         gpu->testingOnly_flushGpuAndSync();
405         s = nullptr;
406         params.cleanUpBackEnd(context, backend);
407     }
408 
409     // Next test the compatibility of resource cache parameters
410     {
411         const SurfaceParameters params(context);
412         GrBackendTexture backend;
413 
414         sk_sp<SkSurface> s = params.make(context, &backend);
415 
416         int maxResourceCount;
417         size_t maxResourceBytes;
418         context->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes);
419 
420         context->setResourceCacheLimits(maxResourceCount, maxResourceBytes/2);
421         REPORTER_ASSERT(reporter, !s->draw(ddl.get()));
422 
423         // DDL TODO: once proxies/ops can be de-instantiated we can re-enable these tests.
424         // For now, DDLs are drawn once.
425 #if 0
426         // resource limits >= those at characterization time are accepted
427         context->setResourceCacheLimits(2*maxResourceCount, maxResourceBytes);
428         REPORTER_ASSERT(reporter, s->draw(ddl.get()));
429         s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
430 
431         context->setResourceCacheLimits(maxResourceCount, 2*maxResourceBytes);
432         REPORTER_ASSERT(reporter, s->draw(ddl.get()));
433         s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
434 
435         context->setResourceCacheLimits(maxResourceCount, maxResourceBytes);
436         REPORTER_ASSERT(reporter, s->draw(ddl.get()));
437         s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
438 #endif
439 
440         context->flush();
441         gpu->testingOnly_flushGpuAndSync();
442         s = nullptr;
443         params.cleanUpBackEnd(context, backend);
444     }
445 
446     // Test that the textureability of the DDL characterization can block a DDL draw
447     {
448         GrBackendTexture backend;
449         SurfaceParameters params(context);
450         params.setShouldCreateMipMaps(false);
451         params.setTextureable(false);
452 
453         sk_sp<SkSurface> s = params.make(context, &backend);
454         if (s) {
455             REPORTER_ASSERT(reporter, !s->draw(ddl.get())); // bc the DDL was made w/ textureability
456 
457             context->flush();
458             gpu->testingOnly_flushGpuAndSync();
459             s = nullptr;
460             params.cleanUpBackEnd(context, backend);
461         }
462     }
463 
464     // Make sure non-GPU-backed surfaces fail characterization
465     {
466         SkImageInfo ii = SkImageInfo::MakeN32(64, 64, kOpaque_SkAlphaType);
467 
468         sk_sp<SkSurface> rasterSurface = SkSurface::MakeRaster(ii);
469         SkSurfaceCharacterization c;
470         REPORTER_ASSERT(reporter, !rasterSurface->characterize(&c));
471     }
472 
473     // Exercise the createResized method
474     {
475         SurfaceParameters params(context);
476         GrBackendTexture backend;
477 
478         sk_sp<SkSurface> s = params.make(context, &backend);
479         if (!s) {
480             return;
481         }
482 
483         SkSurfaceCharacterization char0;
484         SkAssertResult(s->characterize(&char0));
485 
486         // Too small
487         SkSurfaceCharacterization char1 = char0.createResized(-1, -1);
488         REPORTER_ASSERT(reporter, !char1.isValid());
489 
490         // Too large
491         SkSurfaceCharacterization char2 = char0.createResized(1000000, 32);
492         REPORTER_ASSERT(reporter, !char2.isValid());
493 
494         // Just right
495         SkSurfaceCharacterization char3 = char0.createResized(32, 32);
496         REPORTER_ASSERT(reporter, char3.isValid());
497         REPORTER_ASSERT(reporter, 32 == char3.width());
498         REPORTER_ASSERT(reporter, 32 == char3.height());
499 
500         s = nullptr;
501         params.cleanUpBackEnd(context, backend);
502     }
503 }
504 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLSurfaceCharacterizationTest,reporter,ctxInfo)505 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLSurfaceCharacterizationTest, reporter, ctxInfo) {
506     GrContext* context = ctxInfo.grContext();
507 
508     DDLSurfaceCharacterizationTestImpl(context, reporter);
509 }
510 
511 // Test that a DDL created w/o textureability can be replayed into both a textureable and
512 // non-textureable destination. Note that DDLSurfaceCharacterizationTest tests that a
513 // textureable DDL cannot be played into a non-textureable destination but can be replayed
514 // into a textureable destination.
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLNonTextureabilityTest,reporter,ctxInfo)515 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLNonTextureabilityTest, reporter, ctxInfo) {
516     GrContext* context = ctxInfo.grContext();
517     GrGpu* gpu = context->priv().getGpu();
518 
519     // Create a bitmap that we can readback into
520     SkImageInfo imageInfo = SkImageInfo::Make(64, 64, kRGBA_8888_SkColorType,
521                                               kPremul_SkAlphaType);
522     SkBitmap bitmap;
523     bitmap.allocPixels(imageInfo);
524 
525     for (bool textureability : { true, false }) {
526         std::unique_ptr<SkDeferredDisplayList> ddl;
527 
528         // First, create a DDL w/o textureability (and thus no mipmaps). TODO: once we have
529         // reusable DDLs, move this outside of the loop.
530         {
531             SurfaceParameters params(context);
532             params.setShouldCreateMipMaps(false);
533             params.setTextureable(false);
534 
535             ddl = params.createDDL(context);
536             SkAssertResult(ddl);
537         }
538 
539         // Then verify it can draw into either flavor of destination
540         SurfaceParameters params(context);
541         params.setShouldCreateMipMaps(textureability);
542         params.setTextureable(textureability);
543 
544         GrBackendTexture backend;
545         sk_sp<SkSurface> s = params.make(context, &backend);
546         if (!s) {
547             continue;
548         }
549 
550         REPORTER_ASSERT(reporter, s->draw(ddl.get()));
551         s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
552         context->flush();
553         gpu->testingOnly_flushGpuAndSync();
554         s = nullptr;
555         params.cleanUpBackEnd(context, backend);
556     }
557 
558 }
559 
test_make_render_target(skiatest::Reporter * reporter,GrContext * context,const SurfaceParameters & params)560 static void test_make_render_target(skiatest::Reporter* reporter,
561                                     GrContext* context,
562                                     const SurfaceParameters& params) {
563     {
564         const SkSurfaceCharacterization c = params.createCharacterization(context);
565 
566         if (!c.isValid()) {
567             GrBackendTexture backend;
568             sk_sp<SkSurface> tmp = params.make(context, &backend);
569 
570             // If we couldn't characterize the surface we shouldn't be able to create it either
571             REPORTER_ASSERT(reporter, !tmp);
572             if (tmp) {
573                 tmp = nullptr;
574                 params.cleanUpBackEnd(context, backend);
575             }
576             return;
577         }
578     }
579 
580     const SkSurfaceCharacterization c = params.createCharacterization(context);
581     GrBackendTexture backend;
582 
583     {
584         sk_sp<SkSurface> s = params.make(context, &backend);
585         REPORTER_ASSERT(reporter, s);
586         if (!s) {
587             REPORTER_ASSERT(reporter, !c.isValid());
588             params.cleanUpBackEnd(context, backend);
589             return;
590         }
591 
592         REPORTER_ASSERT(reporter, c.isValid());
593         REPORTER_ASSERT(reporter, c.isCompatible(backend));
594         REPORTER_ASSERT(reporter, s->isCompatible(c));
595         // Note that we're leaving 'backend' live here
596     }
597 
598     // Make an SkSurface from scratch
599     {
600         sk_sp<SkSurface> s = SkSurface::MakeRenderTarget(context, c, SkBudgeted::kYes);
601         REPORTER_ASSERT(reporter, s);
602         REPORTER_ASSERT(reporter, s->isCompatible(c));
603     }
604 
605     // Make an SkSurface that wraps the existing backend texture
606     {
607         sk_sp<SkSurface> s = SkSurface::MakeFromBackendTexture(context, c, backend);
608         REPORTER_ASSERT(reporter, s);
609         REPORTER_ASSERT(reporter, s->isCompatible(c));
610     }
611 
612     params.cleanUpBackEnd(context, backend);
613 }
614 
615 ////////////////////////////////////////////////////////////////////////////////
616 // This tests the SkSurface::MakeRenderTarget variants that take an SkSurfaceCharacterization.
617 // In particular, the SkSurface, backendTexture and SkSurfaceCharacterization
618 // should always be compatible.
DDLMakeRenderTargetTestImpl(GrContext * context,skiatest::Reporter * reporter)619 void DDLMakeRenderTargetTestImpl(GrContext* context, skiatest::Reporter* reporter) {
620     for (int i = 0; i < SurfaceParameters::kNumParams; ++i) {
621 
622         if (SurfaceParameters::kFBO0Count == i) {
623             // MakeRenderTarget doesn't support FBO0
624             continue;
625         }
626 
627         if (SurfaceParameters::kProtectedCount == i) {
628             if (context->backend() != GrBackendApi::kVulkan) {
629                 // Only the Vulkan backend respects the protected parameter
630                 continue;
631             }
632 #ifdef SK_VULKAN
633             const GrVkCaps* vkCaps = (const GrVkCaps*) context->priv().caps();
634 
635             // And, even then, only when it is a protected context
636             if (!vkCaps->supportsProtectedMemory()) {
637                 continue;
638             }
639 #endif
640         }
641 
642 
643         SurfaceParameters params(context);
644         params.modify(i);
645 
646         if (!context->priv().caps()->mipMapSupport()) {
647             params.setShouldCreateMipMaps(false);
648         }
649 
650         test_make_render_target(reporter, context, params);
651     }
652 }
653 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLMakeRenderTargetTest,reporter,ctxInfo)654 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLMakeRenderTargetTest, reporter, ctxInfo) {
655     GrContext* context = ctxInfo.grContext();
656 
657     DDLMakeRenderTargetTestImpl(context, reporter);
658 }
659 
660 ////////////////////////////////////////////////////////////////////////////////
661 static constexpr int kSize = 8;
662 
663 struct TextureReleaseChecker {
TextureReleaseCheckerTextureReleaseChecker664     TextureReleaseChecker() : fReleaseCount(0) {}
665     int fReleaseCount;
ReleaseTextureReleaseChecker666     static void Release(void* self) {
667         static_cast<TextureReleaseChecker*>(self)->fReleaseCount++;
668     }
669 };
670 
671 enum class DDLStage { kMakeImage, kDrawImage, kDetach, kDrawDDL };
672 
673 // This tests the ability to create and use wrapped textures in a DDL world
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLWrapBackendTest,reporter,ctxInfo)674 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLWrapBackendTest, reporter, ctxInfo) {
675     GrContext* context = ctxInfo.grContext();
676 
677     GrBackendTexture backendTex = context->createBackendTexture(
678             kSize, kSize, kRGBA_8888_SkColorType,
679             SkColors::kTransparent, GrMipMapped::kNo, GrRenderable::kNo, GrProtected::kNo);
680     if (!backendTex.isValid()) {
681         return;
682     }
683 
684     SurfaceParameters params(context);
685     GrBackendTexture backend;
686 
687     sk_sp<SkSurface> s = params.make(context, &backend);
688     if (!s) {
689         context->deleteBackendTexture(backendTex);
690         return;
691     }
692 
693     SkSurfaceCharacterization c;
694     SkAssertResult(s->characterize(&c));
695 
696     std::unique_ptr<SkDeferredDisplayListRecorder> recorder(new SkDeferredDisplayListRecorder(c));
697 
698     SkCanvas* canvas = recorder->getCanvas();
699     if (!canvas) {
700         s = nullptr;
701         params.cleanUpBackEnd(context, backend);
702         context->deleteBackendTexture(backendTex);
703         return;
704     }
705 
706     GrContext* deferredContext = canvas->getGrContext();
707     if (!deferredContext) {
708         s = nullptr;
709         params.cleanUpBackEnd(context, backend);
710         context->deleteBackendTexture(backendTex);
711         return;
712     }
713 
714     // Wrapped Backend Textures are not supported in DDL
715     sk_sp<SkImage> image =
716             SkImage::MakeFromAdoptedTexture(deferredContext, backendTex, kTopLeft_GrSurfaceOrigin,
717                                             kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr);
718     REPORTER_ASSERT(reporter, !image);
719 
720     TextureReleaseChecker releaseChecker;
721     image = SkImage::MakeFromTexture(deferredContext, backendTex, kTopLeft_GrSurfaceOrigin,
722                                      kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr,
723                                      TextureReleaseChecker::Release, &releaseChecker);
724     REPORTER_ASSERT(reporter, !image);
725 
726     context->deleteBackendTexture(backendTex);
727 
728     s = nullptr;
729     params.cleanUpBackEnd(context, backend);
730 }
731 
dummy_fulfill_proc(void *)732 static sk_sp<SkPromiseImageTexture> dummy_fulfill_proc(void*) {
733     SkASSERT(0);
734     return nullptr;
735 }
dummy_release_proc(void *)736 static void dummy_release_proc(void*) { SkASSERT(0); }
dummy_done_proc(void *)737 static void dummy_done_proc(void*) {}
738 
739 ////////////////////////////////////////////////////////////////////////////////
740 // Test out the behavior of an invalid DDLRecorder
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLInvalidRecorder,reporter,ctxInfo)741 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLInvalidRecorder, reporter, ctxInfo) {
742     GrContext* context = ctxInfo.grContext();
743 
744     {
745         SkImageInfo ii = SkImageInfo::MakeN32Premul(32, 32);
746         sk_sp<SkSurface> s = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, ii);
747 
748         SkSurfaceCharacterization characterization;
749         SkAssertResult(s->characterize(&characterization));
750 
751         // never calling getCanvas means the backing surface is never allocated
752         SkDeferredDisplayListRecorder recorder(characterization);
753     }
754 
755     {
756         SkSurfaceCharacterization invalid;
757 
758         SkDeferredDisplayListRecorder recorder(invalid);
759 
760         const SkSurfaceCharacterization c = recorder.characterization();
761         REPORTER_ASSERT(reporter, !c.isValid());
762         REPORTER_ASSERT(reporter, !recorder.getCanvas());
763         REPORTER_ASSERT(reporter, !recorder.detach());
764 
765         GrBackendFormat format = context->defaultBackendFormat(kRGBA_8888_SkColorType,
766                                                                GrRenderable::kNo);
767         SkASSERT(format.isValid());
768 
769         sk_sp<SkImage> image = recorder.makePromiseTexture(
770                 format, 32, 32, GrMipMapped::kNo,
771                 kTopLeft_GrSurfaceOrigin,
772                 kRGBA_8888_SkColorType,
773                 kPremul_SkAlphaType, nullptr,
774                 dummy_fulfill_proc,
775                 dummy_release_proc,
776                 dummy_done_proc,
777                 nullptr,
778                 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew);
779         REPORTER_ASSERT(reporter, !image);
780     }
781 
782 }
783 
784 ////////////////////////////////////////////////////////////////////////////////
785 // Ensure that flushing while DDL recording doesn't cause a crash
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLFlushWhileRecording,reporter,ctxInfo)786 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLFlushWhileRecording, reporter, ctxInfo) {
787     GrContext* context = ctxInfo.grContext();
788 
789     SkImageInfo ii = SkImageInfo::MakeN32Premul(32, 32);
790     sk_sp<SkSurface> s = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, ii);
791 
792     SkSurfaceCharacterization characterization;
793     SkAssertResult(s->characterize(&characterization));
794 
795     SkDeferredDisplayListRecorder recorder(characterization);
796     SkCanvas* canvas = recorder.getCanvas();
797 
798     canvas->getGrContext()->flush();
799 }
800 
801 ////////////////////////////////////////////////////////////////////////////////
802 // Test that flushing a DDL via SkSurface::flush works
803 
804 struct FulfillInfo {
805     sk_sp<SkPromiseImageTexture> fTex;
806     bool fFulfilled = false;
807     bool fReleased  = false;
808     bool fDone      = false;
809 };
810 
tracking_fulfill_proc(void * context)811 static sk_sp<SkPromiseImageTexture> tracking_fulfill_proc(void* context) {
812     FulfillInfo* info = (FulfillInfo*) context;
813     info->fFulfilled = true;
814     return info->fTex;
815 }
816 
tracking_release_proc(void * context)817 static void tracking_release_proc(void* context) {
818     FulfillInfo* info = (FulfillInfo*) context;
819     info->fReleased = true;
820 }
821 
tracking_done_proc(void * context)822 static void tracking_done_proc(void* context) {
823     FulfillInfo* info = (FulfillInfo*) context;
824     info->fDone = true;
825 }
826 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLSkSurfaceFlush,reporter,ctxInfo)827 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLSkSurfaceFlush, reporter, ctxInfo) {
828     GrContext* context = ctxInfo.grContext();
829 
830     SkImageInfo ii = SkImageInfo::Make(32, 32, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
831     sk_sp<SkSurface> s = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, ii);
832 
833     SkSurfaceCharacterization characterization;
834     SkAssertResult(s->characterize(&characterization));
835 
836     GrBackendTexture backendTexture;
837 
838     if (!create_backend_texture(context, &backendTexture, ii, SkColors::kCyan,
839                                 GrMipMapped::kNo, GrRenderable::kNo)) {
840         REPORTER_ASSERT(reporter, false);
841         return;
842     }
843 
844     FulfillInfo fulfillInfo;
845     fulfillInfo.fTex = SkPromiseImageTexture::Make(backendTexture);
846 
847     std::unique_ptr<SkDeferredDisplayList> ddl;
848 
849     {
850         SkDeferredDisplayListRecorder recorder(characterization);
851 
852         GrBackendFormat format = context->defaultBackendFormat(kRGBA_8888_SkColorType,
853                                                                GrRenderable::kNo);
854         SkASSERT(format.isValid());
855 
856         sk_sp<SkImage> promiseImage = recorder.makePromiseTexture(
857                 format, 32, 32, GrMipMapped::kNo,
858                 kTopLeft_GrSurfaceOrigin,
859                 kRGBA_8888_SkColorType,
860                 kPremul_SkAlphaType, nullptr,
861                 tracking_fulfill_proc,
862                 tracking_release_proc,
863                 tracking_done_proc,
864                 &fulfillInfo,
865                 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew);
866 
867         SkCanvas* canvas = recorder.getCanvas();
868 
869         canvas->clear(SK_ColorRED);
870         canvas->drawImage(promiseImage, 0, 0);
871         ddl = recorder.detach();
872     }
873 
874     context->flush();
875 
876     s->draw(ddl.get());
877 
878     GrFlushInfo flushInfo;
879     s->flush(SkSurface::BackendSurfaceAccess::kPresent, flushInfo);
880 
881     REPORTER_ASSERT(reporter, fulfillInfo.fFulfilled);
882     REPORTER_ASSERT(reporter, fulfillInfo.fReleased);
883 
884     if (GrBackendApi::kVulkan == context->backend() ||
885         GrBackendApi::kMetal  == context->backend()) {
886         // In order to receive the done callback with Vulkan we need to perform the equivalent
887         // of a glFinish
888         GrFlushInfo flushInfoSyncCpu;
889         flushInfoSyncCpu.fFlags = kSyncCpu_GrFlushFlag;
890         s->flush(SkSurface::BackendSurfaceAccess::kPresent, flushInfoSyncCpu);
891     }
892 
893     REPORTER_ASSERT(reporter, fulfillInfo.fDone);
894 
895     REPORTER_ASSERT(reporter, fulfillInfo.fTex->unique());
896     fulfillInfo.fTex.reset();
897 
898     delete_backend_texture(context, backendTexture);
899 }
900 
901 ////////////////////////////////////////////////////////////////////////////////
902 // Ensure that reusing a single DDLRecorder to create multiple DDLs works cleanly
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLMultipleDDLs,reporter,ctxInfo)903 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLMultipleDDLs, reporter, ctxInfo) {
904     GrContext* context = ctxInfo.grContext();
905 
906     SkImageInfo ii = SkImageInfo::MakeN32Premul(32, 32);
907     sk_sp<SkSurface> s = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, ii);
908 
909     SkBitmap bitmap;
910     bitmap.allocPixels(ii);
911 
912     SkSurfaceCharacterization characterization;
913     SkAssertResult(s->characterize(&characterization));
914 
915     SkDeferredDisplayListRecorder recorder(characterization);
916 
917     SkCanvas* canvas1 = recorder.getCanvas();
918 
919     canvas1->clear(SK_ColorRED);
920 
921     canvas1->save();
922     canvas1->clipRect(SkRect::MakeXYWH(8, 8, 16, 16));
923 
924     std::unique_ptr<SkDeferredDisplayList> ddl1 = recorder.detach();
925 
926     SkCanvas* canvas2 = recorder.getCanvas();
927 
928     SkPaint p;
929     p.setColor(SK_ColorGREEN);
930     canvas2->drawRect(SkRect::MakeWH(32, 32), p);
931 
932     std::unique_ptr<SkDeferredDisplayList> ddl2 = recorder.detach();
933 
934     REPORTER_ASSERT(reporter, ddl1->priv().lazyProxyData());
935     REPORTER_ASSERT(reporter, ddl2->priv().lazyProxyData());
936 
937     // The lazy proxy data being different ensures that the SkSurface, SkCanvas and backing-
938     // lazy proxy are all different between the two DDLs
939     REPORTER_ASSERT(reporter, ddl1->priv().lazyProxyData() != ddl2->priv().lazyProxyData());
940 
941     s->draw(ddl1.get());
942     s->draw(ddl2.get());
943 
944     // Make sure the clipRect from DDL1 didn't percolate into DDL2
945     s->readPixels(ii, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
946     for (int y = 0; y < 32; ++y) {
947         for (int x = 0; x < 32; ++x) {
948             REPORTER_ASSERT(reporter, bitmap.getColor(x, y) == SK_ColorGREEN);
949             if (bitmap.getColor(x, y) != SK_ColorGREEN) {
950                 return; // we only really need to report the error once
951             }
952         }
953     }
954 }
955 
956 ////////////////////////////////////////////////////////////////////////////////
957 // Check that the texture-specific flags (i.e., for external & rectangle textures) work
958 // for promise images. As such, this is a GL-only test.
DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(DDLTextureFlagsTest,reporter,ctxInfo)959 DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(DDLTextureFlagsTest, reporter, ctxInfo) {
960     GrContext* context = ctxInfo.grContext();
961 
962     SkImageInfo ii = SkImageInfo::MakeN32Premul(32, 32);
963     sk_sp<SkSurface> s = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, ii);
964 
965     SkSurfaceCharacterization characterization;
966     SkAssertResult(s->characterize(&characterization));
967 
968     SkDeferredDisplayListRecorder recorder(characterization);
969 
970     for (GrGLenum target : { GR_GL_TEXTURE_EXTERNAL, GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_2D } ) {
971         for (auto mipMapped : { GrMipMapped::kNo, GrMipMapped::kYes }) {
972             GrBackendFormat format = GrBackendFormat::MakeGL(GR_GL_RGBA8, target);
973 
974             sk_sp<SkImage> image = recorder.makePromiseTexture(
975                     format, 32, 32, mipMapped,
976                     kTopLeft_GrSurfaceOrigin,
977                     kRGBA_8888_SkColorType,
978                     kPremul_SkAlphaType, nullptr,
979                     dummy_fulfill_proc,
980                     dummy_release_proc,
981                     dummy_done_proc,
982                     nullptr,
983                     SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew);
984             if (GR_GL_TEXTURE_2D != target && mipMapped == GrMipMapped::kYes) {
985                 REPORTER_ASSERT(reporter, !image);
986                 continue;
987             }
988             REPORTER_ASSERT(reporter, image);
989 
990             GrTextureProxy* backingProxy = ((SkImage_GpuBase*) image.get())->peekProxy();
991 
992             REPORTER_ASSERT(reporter, backingProxy->mipMapped() == mipMapped);
993             if (GR_GL_TEXTURE_2D == target) {
994                 REPORTER_ASSERT(reporter, !backingProxy->hasRestrictedSampling());
995             } else {
996                 REPORTER_ASSERT(reporter, backingProxy->hasRestrictedSampling());
997             }
998         }
999     }
1000 }
1001 
1002 ////////////////////////////////////////////////////////////////////////////////
1003 // Test colorType and pixelConfig compatibility.
DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(DDLCompatibilityTest,reporter,ctxInfo)1004 DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(DDLCompatibilityTest, reporter, ctxInfo) {
1005     GrContext* context = ctxInfo.grContext();
1006 
1007     for (int ct = 0; ct <= kLastEnum_SkColorType; ++ct) {
1008         SkColorType colorType = static_cast<SkColorType>(ct);
1009 
1010         SurfaceParameters params(context);
1011         params.setColorType(colorType);
1012         params.setColorSpace(nullptr);
1013 
1014         if (!context->priv().caps()->mipMapSupport()) {
1015             params.setShouldCreateMipMaps(false);
1016         }
1017 
1018         test_make_render_target(reporter, context, params);
1019     }
1020 
1021 }
1022