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