blob: 896a64a5a9d274170ef7b73d86a639b3806ed66b [file] [log] [blame]
Robert Phillips7ffbcf92017-12-04 12:52:46 -05001/*
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
Greg Danielf2336e42018-01-23 16:38:14 -050012#include "GrBackendSurface.h"
13#include "GrGpu.h"
Robert Phillips7ffbcf92017-12-04 12:52:46 -050014#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
Robert Phillipsfc711a22018-02-13 17:03:00 -050023#include "gl/GrGLDefines.h"
24#ifdef SK_VULKAN
25#include "vk/GrVkDefines.h"
26#endif
27
28static 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;
Greg Daniela8d92112018-03-09 12:05:04 -050045 return GrBackendFormat::MakeVk(format);
Robert Phillipsfc711a22018-02-13 17:03:00 -050046 } else if (kRGBA_F16_SkColorType == colorType) {
Greg Daniela8d92112018-03-09 12:05:04 -050047 return GrBackendFormat::MakeVk(VK_FORMAT_R16G16B16A16_SFLOAT);
Robert Phillipsfc711a22018-02-13 17:03:00 -050048 }
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
Robert Phillips7ffbcf92017-12-04 12:52:46 -050068class SurfaceParameters {
69public:
Robert Phillipse8fabb22018-02-04 14:33:21 -050070 static const int kNumParams = 9;
Robert Phillips7ffbcf92017-12-04 12:52:46 -050071 static const int kSampleCount = 5;
Robert Phillipse8fabb22018-02-04 14:33:21 -050072 static const int kMipMipCount = 8;
Robert Phillips7ffbcf92017-12-04 12:52:46 -050073
74 SurfaceParameters()
75 : fWidth(64)
76 , fHeight(64)
77 , fOrigin(kTopLeft_GrSurfaceOrigin)
78 , fColorType(kRGBA_8888_SkColorType)
79 , fColorSpace(SkColorSpace::MakeSRGB())
Brian Salomonbdecacf2018-02-02 20:32:49 -050080 , fSampleCount(1)
Robert Phillipse8fabb22018-02-04 14:33:21 -050081 , fSurfaceProps(0x0, kUnknown_SkPixelGeometry)
82 , fShouldCreateMipMaps(true) {
83 }
Robert Phillips7ffbcf92017-12-04 12:52:46 -050084
85 int sampleCount() const { return fSampleCount; }
86
87 // Modify the SurfaceParameters in just one way
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;
Robert Phillipse8fabb22018-02-04 14:33:21 -0500115 case 8:
116 fShouldCreateMipMaps = false;
117 break;
Robert Phillips7ffbcf92017-12-04 12:52:46 -0500118 }
119 }
120
Robert Phillipse8fabb22018-02-04 14:33:21 -0500121 // Create a DDL whose characterization captures the current settings
122 std::unique_ptr<SkDeferredDisplayList> createDDL(GrContext* context) const {
123 sk_sp<SkSurface> s = this->make(context);
124 if (!s) {
125 return nullptr;
126 }
127
Robert Phillipsfc711a22018-02-13 17:03:00 -0500128 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());
Robert Phillipse8fabb22018-02-04 14:33:21 -0500142
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
Robert Phillips7ffbcf92017-12-04 12:52:46 -0500153 // Create the surface with the current set of parameters
154 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,
Robert Phillipse8fabb22018-02-04 14:33:21 -0500160 fOrigin, &fSurfaceProps, fShouldCreateMipMaps);
161 }
162
163 // Create a surface w/ the current parameters but make it non-textureable
164 sk_sp<SkSurface> makeNonTextureable(GrContext* context, GrBackendTexture* backend) const {
165 GrGpu* gpu = context->contextPriv().getGpu();
166
167 GrPixelConfig config = SkImageInfo2GrPixelConfig(fColorType, nullptr, *context->caps());
Greg Daniel0a7aa142018-02-21 13:02:32 -0500168 SkASSERT(kUnknown_GrPixelConfig != config);
Robert Phillipse8fabb22018-02-04 14:33:21 -0500169
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) {
Brian Salomon26102cb2018-03-09 09:33:19 -0500181 gpu->deleteTestingOnlyBackendTexture(*backend);
Robert Phillipse8fabb22018-02-04 14:33:21 -0500182 return nullptr;
183 }
184
185 return surface;
186 }
187
Brian Salomon26102cb2018-03-09 09:33:19 -0500188 void cleanUpBackEnd(GrContext* context, const GrBackendTexture& backend) const {
Robert Phillipse8fabb22018-02-04 14:33:21 -0500189 GrGpu* gpu = context->contextPriv().getGpu();
190
191 gpu->deleteTestingOnlyBackendTexture(backend);
Robert Phillips7ffbcf92017-12-04 12:52:46 -0500192 }
193
194private:
195 int fWidth;
196 int fHeight;
197 GrSurfaceOrigin fOrigin;
198 SkColorType fColorType;
199 sk_sp<SkColorSpace> fColorSpace;
200 int fSampleCount;
201 SkSurfaceProps fSurfaceProps;
Robert Phillipse8fabb22018-02-04 14:33:21 -0500202 bool fShouldCreateMipMaps;
Robert Phillips7ffbcf92017-12-04 12:52:46 -0500203};
204
205// This tests SkSurfaceCharacterization/SkSurface compatibility
Robert Phillipse8fabb22018-02-04 14:33:21 -0500206DEF_GPUTEST_FOR_ALL_CONTEXTS(DDLSurfaceCharacterizationTest, reporter, ctxInfo) {
Robert Phillips7ffbcf92017-12-04 12:52:46 -0500207 GrContext* context = ctxInfo.grContext();
208
Robert Phillips9e441ee2018-02-01 15:14:55 -0500209 // 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
Robert Phillips7ffbcf92017-12-04 12:52:46 -0500215 std::unique_ptr<SkDeferredDisplayList> ddl;
216
217 // First, create a DDL using the stock SkSurface parameters
218 {
219 SurfaceParameters params;
220
Robert Phillipse8fabb22018-02-04 14:33:21 -0500221 ddl = params.createDDL(context);
Robert Phillipsfc711a22018-02-13 17:03:00 -0500222 SkAssertResult(ddl);
Robert Phillipse8fabb22018-02-04 14:33:21 -0500223
224 // The DDL should draw into an SkSurface created with the same parameters
Robert Phillips7ffbcf92017-12-04 12:52:46 -0500225 sk_sp<SkSurface> s = params.make(context);
226 if (!s) {
227 return;
228 }
229
Robert Phillips7ffbcf92017-12-04 12:52:46 -0500230 REPORTER_ASSERT(reporter, s->draw(ddl.get()));
Robert Phillips9e441ee2018-02-01 15:14:55 -0500231 s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
Robert Phillips7ffbcf92017-12-04 12:52:46 -0500232 }
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
Brian Salomonbdecacf2018-02-02 20:32:49 -0500247 int supportedSampleCount = context->caps()->getRenderTargetSampleCount(
Robert Phillips7ffbcf92017-12-04 12:52:46 -0500248 params.sampleCount(),
249 gpuSurf->getDevice()->accessRenderTargetContext()->asRenderTargetProxy()->config());
Brian Salomonbdecacf2018-02-02 20:32:49 -0500250 if (1 == supportedSampleCount) {
Robert Phillips7ffbcf92017-12-04 12:52:46 -0500251 // If changing the sample count won't result in a different
252 // surface characterization, skip this step
253 continue;
254 }
255 }
256
Robert Phillipse8fabb22018-02-04 14:33:21 -0500257 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);
Robert Phillips7ffbcf92017-12-04 12:52:46 -0500263 }
Robert Phillips8d1e67e2017-12-04 13:48:14 -0500264
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
Robert Phillips8d1e67e2017-12-04 13:48:14 -0500274 context->setResourceCacheLimits(maxResourceCount, maxResourceBytes/2);
275 REPORTER_ASSERT(reporter, !s->draw(ddl.get()));
276
Robert Phillips9e441ee2018-02-01 15:14:55 -0500277 // 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
Robert Phillips8d1e67e2017-12-04 13:48:14 -0500280 // resource limits >= those at characterization time are accepted
281 context->setResourceCacheLimits(2*maxResourceCount, maxResourceBytes);
282 REPORTER_ASSERT(reporter, s->draw(ddl.get()));
Robert Phillips9e441ee2018-02-01 15:14:55 -0500283 s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
Robert Phillips8d1e67e2017-12-04 13:48:14 -0500284
285 context->setResourceCacheLimits(maxResourceCount, 2*maxResourceBytes);
286 REPORTER_ASSERT(reporter, s->draw(ddl.get()));
Robert Phillips9e441ee2018-02-01 15:14:55 -0500287 s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
Robert Phillips8d1e67e2017-12-04 13:48:14 -0500288
289 context->setResourceCacheLimits(maxResourceCount, maxResourceBytes);
290 REPORTER_ASSERT(reporter, s->draw(ddl.get()));
Robert Phillips9e441ee2018-02-01 15:14:55 -0500291 s->readPixels(imageInfo, bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
292#endif
Robert Phillips8d1e67e2017-12-04 13:48:14 -0500293 }
294
Robert Phillipse8fabb22018-02-04 14:33:21 -0500295 // 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;
Brian Salomon26102cb2018-03-09 09:33:19 -0500304 params.cleanUpBackEnd(context, backend);
Robert Phillipse8fabb22018-02-04 14:33:21 -0500305 }
306 }
307
Robert Phillips8d1e67e2017-12-04 13:48:14 -0500308 // 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 }
Robert Phillips94458ee2018-03-06 13:41:51 -0500316
317 // Exercise the createResized method
318 {
319 SurfaceParameters params;
320
321 sk_sp<SkSurface> s = params.make(context);
322 if (!s) {
323 return;
324 }
325
326 SkSurfaceCharacterization char0;
327 SkAssertResult(s->characterize(&char0));
328
329 // Too small
330 SkSurfaceCharacterization char1 = char0.createResized(-1, -1);
331 REPORTER_ASSERT(reporter, !char1.isValid());
332
333 // Too large
334 SkSurfaceCharacterization char2 = char0.createResized(1000000, 32);
335 REPORTER_ASSERT(reporter, !char2.isValid());
336
337 // Just right
338 SkSurfaceCharacterization char3 = char0.createResized(32, 32);
339 REPORTER_ASSERT(reporter, char3.isValid());
340 REPORTER_ASSERT(reporter, 32 == char3.width());
341 REPORTER_ASSERT(reporter, 32 == char3.height());
342 }
Robert Phillips7ffbcf92017-12-04 12:52:46 -0500343}
344
Greg Danielf2336e42018-01-23 16:38:14 -0500345static constexpr int kSize = 8;
346
347struct TextureReleaseChecker {
348 TextureReleaseChecker() : fReleaseCount(0) {}
349 int fReleaseCount;
350 static void Release(void* self) {
351 static_cast<TextureReleaseChecker*>(self)->fReleaseCount++;
352 }
353};
354
355enum class DDLStage { kMakeImage, kDrawImage, kDetach, kDrawDDL };
356
357// This tests the ability to create and use wrapped textures in a DDL world
358DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLWrapBackendTest, reporter, ctxInfo) {
359 GrContext* context = ctxInfo.grContext();
360 GrGpu* gpu = context->contextPriv().getGpu();
Brian Salomonf7778972018-03-08 10:13:17 -0500361 GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
362 nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig, false, GrMipMapped::kNo);
363 if (!backendTex.isValid()) {
364 return;
Greg Danielf2336e42018-01-23 16:38:14 -0500365 }
Brian Salomonf7778972018-03-08 10:13:17 -0500366
367 SurfaceParameters params;
368
369 sk_sp<SkSurface> s = params.make(context);
370 if (!s) {
Brian Salomon26102cb2018-03-09 09:33:19 -0500371 gpu->deleteTestingOnlyBackendTexture(backendTex);
Brian Salomonf7778972018-03-08 10:13:17 -0500372 return;
373 }
374
375 SkSurfaceCharacterization c;
376 SkAssertResult(s->characterize(&c));
377
378 std::unique_ptr<SkDeferredDisplayListRecorder> recorder(new SkDeferredDisplayListRecorder(c));
379
380 SkCanvas* canvas = recorder->getCanvas();
381 if (!canvas) {
Brian Salomon26102cb2018-03-09 09:33:19 -0500382 gpu->deleteTestingOnlyBackendTexture(backendTex);
Brian Salomonf7778972018-03-08 10:13:17 -0500383 return;
384 }
385
386 GrContext* deferredContext = canvas->getGrContext();
387 if (!deferredContext) {
Brian Salomon26102cb2018-03-09 09:33:19 -0500388 gpu->deleteTestingOnlyBackendTexture(backendTex);
Brian Salomonf7778972018-03-08 10:13:17 -0500389 return;
390 }
391
392 // Wrapped Backend Textures are not supported in DDL
393 sk_sp<SkImage> image =
394 SkImage::MakeFromAdoptedTexture(deferredContext, backendTex, kTopLeft_GrSurfaceOrigin,
395 kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr);
396 REPORTER_ASSERT(reporter, !image);
397
398 TextureReleaseChecker releaseChecker;
399 image = SkImage::MakeFromTexture(deferredContext, backendTex, kTopLeft_GrSurfaceOrigin,
400 kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr,
401 TextureReleaseChecker::Release, &releaseChecker);
402 REPORTER_ASSERT(reporter, !image);
403
Brian Salomon26102cb2018-03-09 09:33:19 -0500404 gpu->deleteTestingOnlyBackendTexture(backendTex);
Greg Danielf2336e42018-01-23 16:38:14 -0500405}
406
407
Robert Phillips7ffbcf92017-12-04 12:52:46 -0500408#endif