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