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