• 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 "SkTypes.h"
9 
10 #if SK_SUPPORT_GPU
11 
12 #include "GrBackendSurface.h"
13 #include "GrGpu.h"
14 #include "SkCanvas.h"
15 #include "SkDeferredDisplayListRecorder.h"
16 #include "SkGpuDevice.h"
17 #include "SkSurface.h"
18 #include "SkSurface_Gpu.h"
19 #include "SkSurfaceCharacterization.h"
20 #include "SkSurfaceProps.h"
21 #include "Test.h"
22 
23 #include "gl/GrGLDefines.h"
24 #ifdef SK_VULKAN
25 #include "vk/GrVkDefines.h"
26 #endif
27 
create_backend_format(GrContext * context,SkColorType colorType)28 static GrBackendFormat create_backend_format(GrContext* context, SkColorType colorType) {
29     const GrCaps* caps = context->caps();
30 
31     switch (context->contextPriv().getBackend()) {
32     case kOpenGL_GrBackend:
33         if (kRGBA_8888_SkColorType == colorType) {
34             GrGLenum format = caps->srgbSupport() ? GR_GL_SRGB8_ALPHA8 : GR_GL_RGBA8;
35             return GrBackendFormat::MakeGL(format, GR_GL_TEXTURE_2D);
36         } else if (kRGBA_F16_SkColorType == colorType) {
37             return GrBackendFormat::MakeGL(GR_GL_RGBA16F, GR_GL_TEXTURE_2D);
38         }
39         break;
40 #ifdef SK_VULKAN
41     case kVulkan_GrBackend:
42         if (kRGBA_8888_SkColorType == colorType) {
43             VkFormat format =  caps->srgbSupport() ? VK_FORMAT_R8G8B8A8_SRGB
44                                                    : VK_FORMAT_R8G8B8A8_UNORM;
45             return GrBackendFormat::MakeVK(format);
46         } else if (kRGBA_F16_SkColorType == colorType) {
47             return GrBackendFormat::MakeVK(VK_FORMAT_R16G16B16A16_SFLOAT);
48         }
49         break;
50 #endif
51     case kMock_GrBackend:
52         if (kRGBA_8888_SkColorType == colorType) {
53             GrPixelConfig config = caps->srgbSupport() ? kSRGBA_8888_GrPixelConfig
54                                                        : kRGBA_8888_GrPixelConfig;
55             return GrBackendFormat::MakeMock(config);
56         } else if (kRGBA_F16_SkColorType == colorType) {
57             return GrBackendFormat::MakeMock(kRGBA_half_GrPixelConfig);
58         }
59         break;
60     default:
61         return GrBackendFormat(); // return an invalid format
62     }
63 
64     return GrBackendFormat(); // return an invalid format
65 }
66 
67 
68 class SurfaceParameters {
69 public:
70     static const int kNumParams = 9;
71     static const int kSampleCount = 5;
72     static const int kMipMipCount = 8;
73 
SurfaceParameters()74     SurfaceParameters()
75             : fWidth(64)
76             , fHeight(64)
77             , fOrigin(kTopLeft_GrSurfaceOrigin)
78             , fColorType(kRGBA_8888_SkColorType)
79             , fColorSpace(SkColorSpace::MakeSRGB())
80             , fSampleCount(1)
81             , fSurfaceProps(0x0, kUnknown_SkPixelGeometry)
82             , fShouldCreateMipMaps(true) {
83     }
84 
sampleCount() const85     int sampleCount() const { return fSampleCount; }
86 
87     // Modify the SurfaceParameters in just one way
modify(int i)88     void modify(int i) {
89         switch (i) {
90         case 0:
91             fWidth = 63;
92             break;
93         case 1:
94             fHeight = 63;
95             break;
96         case 2:
97             fOrigin = kBottomLeft_GrSurfaceOrigin;
98             break;
99         case 3:
100             fColorType = kRGBA_F16_SkColorType;
101             break;
102         case 4:
103             fColorSpace = SkColorSpace::MakeSRGBLinear();
104             break;
105         case kSampleCount:
106             fSampleCount = 4;
107             break;
108         case 6:
109             fSurfaceProps = SkSurfaceProps(0x0, kRGB_H_SkPixelGeometry);
110             break;
111         case 7:
112             fSurfaceProps = SkSurfaceProps(SkSurfaceProps::kUseDeviceIndependentFonts_Flag,
113                                            kUnknown_SkPixelGeometry);
114             break;
115         case 8:
116             fShouldCreateMipMaps = false;
117             break;
118         }
119     }
120 
121     // Create a DDL whose characterization captures the current settings
createDDL(GrContext * context) const122     std::unique_ptr<SkDeferredDisplayList> createDDL(GrContext* context) const {
123         sk_sp<SkSurface> s = this->make(context);
124         if (!s) {
125             return nullptr;
126         }
127 
128         int maxResourceCount;
129         size_t maxResourceBytes;
130         context->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes);
131 
132         // Note that Ganesh doesn't make use of the SkImageInfo's alphaType
133         SkImageInfo ii = SkImageInfo::Make(fWidth, fHeight, fColorType,
134                                            kPremul_SkAlphaType, fColorSpace);
135 
136         GrBackendFormat backendFormat = create_backend_format(context, fColorType);
137 
138         SkSurfaceCharacterization c = context->threadSafeProxy()->createCharacterization(
139                                                 maxResourceBytes, ii, backendFormat, fSampleCount,
140                                                 fOrigin, fSurfaceProps, fShouldCreateMipMaps);
141         SkAssertResult(c.isValid());
142 
143         SkDeferredDisplayListRecorder r(c);
144         SkCanvas* canvas = r.getCanvas();
145         if (!canvas) {
146             return nullptr;
147         }
148 
149         canvas->drawRect(SkRect::MakeXYWH(10, 10, 10, 10), SkPaint());
150         return r.detach();
151     }
152 
153     // Create the surface with the current set of parameters
make(GrContext * context) const154     sk_sp<SkSurface> make(GrContext* context) const {
155         // Note that Ganesh doesn't make use of the SkImageInfo's alphaType
156         SkImageInfo ii = SkImageInfo::Make(fWidth, fHeight, fColorType,
157                                            kPremul_SkAlphaType, fColorSpace);
158 
159         return SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, ii, fSampleCount,
160                                            fOrigin, &fSurfaceProps, fShouldCreateMipMaps);
161     }
162 
163     // Create a surface w/ the current parameters but make it non-textureable
makeNonTextureable(GrContext * context,GrBackendTexture * backend) const164     sk_sp<SkSurface> makeNonTextureable(GrContext* context, GrBackendTexture* backend) const {
165         GrGpu* gpu = context->contextPriv().getGpu();
166 
167         GrPixelConfig config = SkImageInfo2GrPixelConfig(fColorType, nullptr, *context->caps());
168         SkASSERT(kUnknown_GrPixelConfig != config);
169 
170         *backend = gpu->createTestingOnlyBackendTexture(nullptr, fWidth, fHeight,
171                                                         config, true, GrMipMapped::kNo);
172 
173         if (!backend->isValid() || !gpu->isTestingOnlyBackendTexture(*backend)) {
174             return nullptr;
175         }
176 
177         sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTextureAsRenderTarget(
178             context, *backend, fOrigin, fSampleCount, fColorType, nullptr, nullptr);
179 
180         if (!surface) {
181             gpu->deleteTestingOnlyBackendTexture(backend);
182             return nullptr;
183         }
184 
185         return surface;
186     }
187 
cleanUpBackEnd(GrContext * context,GrBackendTexture * backend) const188     void cleanUpBackEnd(GrContext* context, GrBackendTexture* backend) const {
189         GrGpu* gpu = context->contextPriv().getGpu();
190 
191         gpu->deleteTestingOnlyBackendTexture(backend);
192     }
193 
194 private:
195     int                 fWidth;
196     int                 fHeight;
197     GrSurfaceOrigin     fOrigin;
198     SkColorType         fColorType;
199     sk_sp<SkColorSpace> fColorSpace;
200     int                 fSampleCount;
201     SkSurfaceProps      fSurfaceProps;
202     bool                fShouldCreateMipMaps;
203 };
204 
205 // This tests SkSurfaceCharacterization/SkSurface compatibility
DEF_GPUTEST_FOR_ALL_CONTEXTS(DDLSurfaceCharacterizationTest,reporter,ctxInfo)206 DEF_GPUTEST_FOR_ALL_CONTEXTS(DDLSurfaceCharacterizationTest, reporter, ctxInfo) {
207     GrContext* context = ctxInfo.grContext();
208 
209     // Create a bitmap that we can readback into
210     SkImageInfo imageInfo = SkImageInfo::Make(64, 64, kRGBA_8888_SkColorType,
211                                               kPremul_SkAlphaType);
212     SkBitmap bitmap;
213     bitmap.allocPixels(imageInfo);
214 
215     std::unique_ptr<SkDeferredDisplayList> ddl;
216 
217     // First, create a DDL using the stock SkSurface parameters
218     {
219         SurfaceParameters params;
220 
221         ddl = params.createDDL(context);
222         SkAssertResult(ddl);
223 
224         // The DDL should draw into an SkSurface created with the same parameters
225         sk_sp<SkSurface> s = params.make(context);
226         if (!s) {
227             return;
228         }
229 
230         REPORTER_ASSERT(reporter, s->draw(ddl.get()));
231         s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
232     }
233 
234     // Then, alter each parameter in turn and check that the DDL & surface are incompatible
235     for (int i = 0; i < SurfaceParameters::kNumParams; ++i) {
236         SurfaceParameters params;
237         params.modify(i);
238 
239         sk_sp<SkSurface> s = params.make(context);
240         if (!s) {
241             continue;
242         }
243 
244         if (SurfaceParameters::kSampleCount == i) {
245             SkSurface_Gpu* gpuSurf = static_cast<SkSurface_Gpu*>(s.get());
246 
247             int supportedSampleCount = context->caps()->getRenderTargetSampleCount(
248                 params.sampleCount(),
249                 gpuSurf->getDevice()->accessRenderTargetContext()->asRenderTargetProxy()->config());
250             if (1 == supportedSampleCount) {
251                 // If changing the sample count won't result in a different
252                 // surface characterization, skip this step
253                 continue;
254             }
255         }
256 
257         if (SurfaceParameters::kMipMipCount == i && !context->caps()->mipMapSupport()) {
258             continue;
259         }
260 
261         REPORTER_ASSERT(reporter, !s->draw(ddl.get()),
262                         "DDLSurfaceCharacterizationTest failed on parameter: %d\n", i);
263     }
264 
265     // Next test the compatibility of resource cache parameters
266     {
267         const SurfaceParameters params;
268         sk_sp<SkSurface> s = params.make(context);
269 
270         int maxResourceCount;
271         size_t maxResourceBytes;
272         context->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes);
273 
274         context->setResourceCacheLimits(maxResourceCount, maxResourceBytes/2);
275         REPORTER_ASSERT(reporter, !s->draw(ddl.get()));
276 
277         // DDL TODO: once proxies/ops can be de-instantiated we can re-enable these tests.
278         // For now, DDLs are drawn once.
279 #if 0
280         // resource limits >= those at characterization time are accepted
281         context->setResourceCacheLimits(2*maxResourceCount, maxResourceBytes);
282         REPORTER_ASSERT(reporter, s->draw(ddl.get()));
283         s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
284 
285         context->setResourceCacheLimits(maxResourceCount, 2*maxResourceBytes);
286         REPORTER_ASSERT(reporter, s->draw(ddl.get()));
287         s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
288 
289         context->setResourceCacheLimits(maxResourceCount, maxResourceBytes);
290         REPORTER_ASSERT(reporter, s->draw(ddl.get()));
291         s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
292 #endif
293     }
294 
295     // Test that the textureability of the DDL characterization can block a DDL draw
296     {
297         GrBackendTexture backend;
298         const SurfaceParameters params;
299         sk_sp<SkSurface> s = params.makeNonTextureable(context, &backend);
300         if (s) {
301             REPORTER_ASSERT(reporter, !s->draw(ddl.get()));
302 
303             s = nullptr;
304             params.cleanUpBackEnd(context, &backend);
305         }
306     }
307 
308     // Make sure non-GPU-backed surfaces fail characterization
309     {
310         SkImageInfo ii = SkImageInfo::MakeN32(64, 64, kOpaque_SkAlphaType);
311 
312         sk_sp<SkSurface> rasterSurface = SkSurface::MakeRaster(ii);
313         SkSurfaceCharacterization c;
314         REPORTER_ASSERT(reporter, !rasterSurface->characterize(&c));
315     }
316 }
317 
318 static constexpr int kSize = 8;
319 
320 struct TextureReleaseChecker {
TextureReleaseCheckerTextureReleaseChecker321     TextureReleaseChecker() : fReleaseCount(0) {}
322     int fReleaseCount;
ReleaseTextureReleaseChecker323     static void Release(void* self) {
324         static_cast<TextureReleaseChecker*>(self)->fReleaseCount++;
325     }
326 };
327 
328 enum class DDLStage { kMakeImage, kDrawImage, kDetach, kDrawDDL };
329 
330 // This tests the ability to create and use wrapped textures in a DDL world
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLWrapBackendTest,reporter,ctxInfo)331 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLWrapBackendTest, reporter, ctxInfo) {
332     GrContext* context = ctxInfo.grContext();
333     GrGpu* gpu = context->contextPriv().getGpu();
334     for (auto lastStage : { DDLStage::kMakeImage, DDLStage::kDrawImage,
335                             DDLStage::kDetach, DDLStage::kDrawDDL } ) {
336         for (auto earlyImageReset : { false , true } ) {
337             GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
338                     nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig, false, GrMipMapped::kNo);
339             if (!backendTex.isValid()) {
340                 continue;
341             }
342 
343             SurfaceParameters params;
344 
345             sk_sp<SkSurface> s = params.make(context);
346             if (!s) {
347                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
348                 continue;
349             }
350 
351             SkSurfaceCharacterization c;
352             SkAssertResult(s->characterize(&c));
353 
354             std::unique_ptr<SkDeferredDisplayListRecorder> recorder(
355                     new SkDeferredDisplayListRecorder(c));
356 
357             SkCanvas* canvas = recorder->getCanvas();
358             if (!canvas) {
359                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
360                 continue;
361             }
362 
363             GrContext* deferredContext = canvas->getGrContext();
364             if (!deferredContext) {
365                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
366                 continue;
367             }
368 
369             sk_sp<SkImage> image = SkImage::MakeFromAdoptedTexture(deferredContext, backendTex,
370                                                                    kTopLeft_GrSurfaceOrigin,
371                                                                    kRGBA_8888_SkColorType,
372                                                                    kPremul_SkAlphaType, nullptr);
373             // Adopted Textures are not supported in DDL
374             REPORTER_ASSERT(reporter, !image);
375 
376             TextureReleaseChecker releaseChecker;
377             image = SkImage::MakeFromTexture(deferredContext, backendTex,
378                                              kTopLeft_GrSurfaceOrigin,
379                                              kRGBA_8888_SkColorType,
380                                              kPremul_SkAlphaType, nullptr,
381                                              TextureReleaseChecker::Release, &releaseChecker);
382 
383             REPORTER_ASSERT(reporter, image);
384             if (!image) {
385                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
386                 continue;
387             }
388 
389             if (DDLStage::kMakeImage == lastStage) {
390                 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
391                 image.reset();
392                 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
393                 recorder.reset();
394                 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
395                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
396                 continue;
397             }
398 
399             canvas->drawImage(image.get(), 0, 0);
400 
401             if (earlyImageReset) {
402                 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
403                 image.reset();
404                 // Ref should still be held by DDL recorder since we did the draw
405                 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
406             }
407 
408             if (DDLStage::kDrawImage == lastStage) {
409                 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
410                 recorder.reset();
411                 if (earlyImageReset) {
412                     REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
413                 } else {
414                     REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
415                     image.reset();
416                     REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
417                 }
418                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
419                 continue;
420             }
421 
422             std::unique_ptr<SkDeferredDisplayList> ddl = recorder->detach();
423             if (DDLStage::kDetach == lastStage) {
424                 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
425                 recorder.reset();
426 #ifndef SK_RASTER_RECORDER_IMPLEMENTATION
427                 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
428 #endif
429                 ddl.reset();
430                 if (earlyImageReset) {
431                     REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
432                 } else {
433                     REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
434                     image.reset();
435                     REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
436                 }
437                 gpu->deleteTestingOnlyBackendTexture(&backendTex);
438                 continue;
439             }
440 
441             REPORTER_ASSERT(reporter, s->draw(ddl.get()));
442 
443             REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
444             recorder.reset();
445 #ifndef SK_RASTER_RECORDER_IMPLEMENTATION
446             REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
447 #endif
448             ddl.reset();
449 #ifndef SK_RASTER_RECORDER_IMPLEMENTATION
450             REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
451 #endif
452 
453             // Force all draws to flush and sync by calling a read pixels
454             SkImageInfo imageInfo = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
455                                                       kPremul_SkAlphaType);
456             SkBitmap bitmap;
457             bitmap.allocPixels(imageInfo);
458             s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
459 
460             if (earlyImageReset) {
461                 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
462             } else {
463                 REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
464                 image.reset();
465                 REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
466             }
467 
468             gpu->deleteTestingOnlyBackendTexture(&backendTex);
469         }
470     }
471 }
472 
473 
474 #endif
475