xref: /aosp_15_r20/external/skia/tests/VkBackendSurfaceTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2018 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 // This is a GPU-backend specific test. It relies on static initializers to work
9 
10 #include "include/core/SkTypes.h"
11 
12 #if defined(SK_VULKAN)
13 #include "include/core/SkAlphaType.h"
14 #include "include/core/SkColorSpace.h"
15 #include "include/core/SkColorType.h"
16 #include "include/core/SkImage.h"
17 #include "include/core/SkRefCnt.h"
18 #include "include/gpu/GpuTypes.h"
19 #include "include/gpu/ganesh/GrBackendSurface.h"
20 #include "include/gpu/ganesh/GrDirectContext.h"
21 #include "include/gpu/ganesh/GrTypes.h"
22 #include "include/gpu/ganesh/SkImageGanesh.h"
23 #include "include/gpu/ganesh/vk/GrVkBackendSurface.h"
24 #include "include/gpu/ganesh/vk/GrVkTypes.h"
25 #include "include/private/gpu/ganesh/GrTypesPriv.h"
26 #include "src/gpu/ganesh/GrDirectContextPriv.h"
27 #include "src/gpu/ganesh/GrSurface.h"
28 #include "src/gpu/ganesh/GrSurfaceProxy.h"
29 #include "src/gpu/ganesh/GrTextureProxy.h"
30 #include "src/gpu/ganesh/image/GrImageUtils.h"
31 #include "src/gpu/ganesh/vk/GrVkCaps.h"
32 #include "src/gpu/ganesh/vk/GrVkImage.h"
33 #include "src/gpu/ganesh/vk/GrVkTexture.h"
34 #include "tests/CtsEnforcement.h"
35 #include "tests/Test.h"
36 #include "tools/gpu/ManagedBackendTexture.h"
37 #include "tools/gpu/ProxyUtils.h"
38 
39 #include <vulkan/vulkan_core.h>
40 
41 class GrTexture;
42 struct GrContextOptions;
43 
DEF_GANESH_TEST_FOR_VULKAN_CONTEXT(VkDRMModifierTest,reporter,ctxInfo,CtsEnforcement::kNever)44 DEF_GANESH_TEST_FOR_VULKAN_CONTEXT(VkDRMModifierTest, reporter, ctxInfo, CtsEnforcement::kNever) {
45     using namespace skgpu;
46 
47     auto dContext = ctxInfo.directContext();
48 
49     const GrVkCaps* vkCaps = static_cast<const GrVkCaps*>(dContext->priv().caps());
50     if (!vkCaps->supportsDRMFormatModifiers()) {
51         return;
52     }
53 
54     Protected isProtected = Protected(vkCaps->supportsProtectedContent());
55 
56     // First make a normal backend texture with DRM
57     auto mbet = sk_gpu_test::ManagedBackendTexture::MakeWithoutData(
58             dContext, 1, 1, kRGBA_8888_SkColorType, Mipmapped::kNo, GrRenderable::kNo, isProtected);
59     if (!mbet) {
60         ERRORF(reporter, "Could not create backend texture.");
61         return;
62     }
63 
64     GrVkImageInfo info;
65     REPORTER_ASSERT(reporter, GrBackendTextures::GetVkImageInfo(mbet->texture(), &info));
66 
67     // Next we will use the same VkImageInfo but lie to say tiling is a DRM modifier. This should
68     // cause us to think the resource is eternal/read only internally. Though since we don't
69     // explicitly pass in the tiling to anything, this shouldn't cause us to do anything illegal.
70     info.fImageTiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
71 
72     GrBackendTexture drmBETex = GrBackendTextures::MakeVk(1, 1, info);
73     GrBackendFormat drmFormat = GrBackendFormats::MakeVk(info.fFormat, true);
74     REPORTER_ASSERT(reporter, drmFormat == drmBETex.getBackendFormat());
75     REPORTER_ASSERT(reporter, drmBETex.textureType() == GrTextureType::kExternal);
76 
77     // Now wrap the texture in an SkImage and make sure we have the required read only properties
78     sk_sp<SkImage> drmImage = SkImages::BorrowTextureFrom(dContext,
79                                                           drmBETex,
80                                                           kTopLeft_GrSurfaceOrigin,
81                                                           kRGBA_8888_SkColorType,
82                                                           kPremul_SkAlphaType,
83                                                           nullptr);
84     REPORTER_ASSERT(reporter, drmImage);
85 
86     GrBackendTexture actual;
87     bool ok = SkImages::GetBackendTextureFromImage(drmImage, &actual, false);
88     REPORTER_ASSERT(reporter, ok);
89     REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(actual, drmBETex));
90 
91     auto [view, _] = skgpu::ganesh::AsView(dContext, drmImage, Mipmapped::kNo);
92     REPORTER_ASSERT(reporter, view);
93     const GrSurfaceProxy* proxy = view.proxy();
94     REPORTER_ASSERT(reporter, proxy);
95 
96     REPORTER_ASSERT(reporter, proxy->readOnly());
97 
98     const GrSurface* surf = proxy->peekSurface();
99     REPORTER_ASSERT(reporter, surf);
100     REPORTER_ASSERT(reporter, surf->readOnly());
101 
102     drmImage.reset();
103 }
104 
DEF_GANESH_TEST_FOR_VULKAN_CONTEXT(VkImageLayoutTest,reporter,ctxInfo,CtsEnforcement::kNever)105 DEF_GANESH_TEST_FOR_VULKAN_CONTEXT(VkImageLayoutTest, reporter, ctxInfo, CtsEnforcement::kNever) {
106     using namespace skgpu;
107 
108     auto dContext = ctxInfo.directContext();
109 
110     Protected isProtected = Protected(dContext->priv().caps()->supportsProtectedContent());
111 
112     auto mbet = sk_gpu_test::ManagedBackendTexture::MakeWithoutData(
113             dContext, 1, 1, kRGBA_8888_SkColorType, Mipmapped::kNo, GrRenderable::kNo, isProtected);
114     if (!mbet) {
115         ERRORF(reporter, "Could not create backend texture.");
116         return;
117     }
118 
119     GrVkImageInfo info;
120     REPORTER_ASSERT(reporter, GrBackendTextures::GetVkImageInfo(mbet->texture(), &info));
121     VkImageLayout initLayout = info.fImageLayout;
122 
123     // Verify that setting that layout via a copy of a backendTexture is reflected in all the
124     // backendTextures.
125     GrBackendTexture backendTex1 = mbet->texture();
126     GrBackendTexture backendTex2 = backendTex1;
127     REPORTER_ASSERT(reporter, GrBackendTextures::GetVkImageInfo(backendTex2, &info));
128     REPORTER_ASSERT(reporter, initLayout == info.fImageLayout);
129 
130     GrBackendTextures::SetVkImageLayout(&backendTex2, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
131 
132     REPORTER_ASSERT(reporter, GrBackendTextures::GetVkImageInfo(backendTex1, &info));
133     REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == info.fImageLayout);
134 
135     REPORTER_ASSERT(reporter, GrBackendTextures::GetVkImageInfo(backendTex2, &info));
136     REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == info.fImageLayout);
137 
138     // Setting back the layout since we didn't actually change it
139     GrBackendTextures::SetVkImageLayout(&backendTex1, initLayout);
140 
141     sk_sp<SkImage> wrappedImage =
142             SkImages::BorrowTextureFrom(dContext,
143                                         backendTex1,
144                                         kTopLeft_GrSurfaceOrigin,
145                                         kRGBA_8888_SkColorType,
146                                         kPremul_SkAlphaType,
147                                         /*color space*/ nullptr,
148                                         sk_gpu_test::ManagedBackendTexture::ReleaseProc,
149                                         mbet->releaseContext());
150     REPORTER_ASSERT(reporter, wrappedImage.get());
151 
152     GrSurfaceProxy* proxy = sk_gpu_test::GetTextureImageProxy(wrappedImage.get(), dContext);
153     REPORTER_ASSERT(reporter, proxy);
154     REPORTER_ASSERT(reporter, proxy->isInstantiated());
155     GrTexture* texture = proxy->peekTexture();
156     REPORTER_ASSERT(reporter, texture);
157 
158     // Verify that modifying the layout via the GrVkTexture is reflected in the GrBackendTexture
159     GrVkImage* vkTexture = static_cast<GrVkTexture*>(texture)->textureImage();
160     REPORTER_ASSERT(reporter, initLayout == vkTexture->currentLayout());
161     vkTexture->updateImageLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
162 
163     REPORTER_ASSERT(reporter, GrBackendTextures::GetVkImageInfo(backendTex1, &info));
164     REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == info.fImageLayout);
165 
166     GrBackendTexture backendTexImage;
167     bool ok = SkImages::GetBackendTextureFromImage(wrappedImage, &backendTexImage, false);
168     REPORTER_ASSERT(reporter, ok);
169     REPORTER_ASSERT(reporter, GrBackendTextures::GetVkImageInfo(backendTexImage, &info));
170     REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == info.fImageLayout);
171 
172     // Verify that modifying the layout via the GrBackendTexutre is reflected in the GrVkTexture
173     GrBackendTextures::SetVkImageLayout(&backendTexImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
174     REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == vkTexture->currentLayout());
175 
176     vkTexture->updateImageLayout(initLayout);
177 
178     REPORTER_ASSERT(reporter, GrBackendTextures::GetVkImageInfo(backendTex1, &info));
179     REPORTER_ASSERT(reporter, initLayout == info.fImageLayout);
180 
181     REPORTER_ASSERT(reporter, GrBackendTextures::GetVkImageInfo(backendTex2, &info));
182     REPORTER_ASSERT(reporter, initLayout == info.fImageLayout);
183 
184     REPORTER_ASSERT(reporter, GrBackendTextures::GetVkImageInfo(backendTexImage, &info));
185     REPORTER_ASSERT(reporter, initLayout == info.fImageLayout);
186 
187     // Check that we can do things like assigning the backend texture to invalid one, assign an
188     // invalid one, assin a backend texture to inself etc. Success here is that we don't hit any of
189     // our ref counting asserts.
190     REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(backendTex1, backendTex2));
191 
192     GrBackendTexture invalidTexture;
193     REPORTER_ASSERT(reporter, !invalidTexture.isValid());
194     REPORTER_ASSERT(reporter, !GrBackendTexture::TestingOnly_Equals(invalidTexture, backendTex2));
195 
196     backendTex2 = invalidTexture;
197     REPORTER_ASSERT(reporter, !backendTex2.isValid());
198     REPORTER_ASSERT(reporter, !GrBackendTexture::TestingOnly_Equals(invalidTexture, backendTex2));
199 
200     invalidTexture = backendTex1;
201     REPORTER_ASSERT(reporter, invalidTexture.isValid());
202     REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(invalidTexture, backendTex1));
203 
204     invalidTexture = static_cast<decltype(invalidTexture)&>(invalidTexture);
205     REPORTER_ASSERT(reporter, invalidTexture.isValid());
206     REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(invalidTexture, invalidTexture));
207 }
208 
209 // This test is disabled because it executes illegal vulkan calls which cause the validations layers
210 // to fail and makes us assert. Once fixed to use a valid vulkan call sequence it should be
211 // renenabled, see skbug.com/8936.
212 #if 0
213 // Test to make sure we transition from the EXTERNAL queue even when no layout transition is needed.
214 DEF_GANESH_TEST_FOR_VULKAN_CONTEXT(VkTransitionExternalQueueTest, reporter, ctxInfo,
215                                    CtsEnforcement::kApiLevel_T) {
216     auto dContext = ctxInfo.directContext();
217     GrGpu* gpu = dContext->priv().getGpu();
218     GrVkGpu* vkGpu = static_cast<GrVkGpu*>(gpu);
219     if (!vkGpu->vkCaps().supportsExternalMemory()) {
220         return;
221     }
222 
223     GrBackendTexture backendTex = dContext->createBackendTexture(
224             1, 1, kRGBA_8888_SkColorType,
225             SkColors::kTransparent, skgpu::Mipmapped::kNo, GrRenderable::kNo);
226     sk_sp<SkImage> image;
227     // Make a backend texture with an external queue family and general layout.
228     GrVkImageInfo vkInfo;
229     if (!GrBackendTextures::GetVkImageInfo(backendTex, &vkInfo)) {
230         return;
231     }
232     vkInfo.fCurrentQueueFamily = VK_QUEUE_FAMILY_EXTERNAL;
233     // Use a read-only layout as these are the ones where we can otherwise skip a transition.
234     vkInfo.fImageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
235 
236     GrBackendTexture vkExtTex(1, 1, vkInfo);
237     REPORTER_ASSERT(reporter, vkExtTex.isValid());
238     image = SkImages::BorrowTextureFrom(dContext, vkExtTex, kTopLeft_GrSurfaceOrigin,
239                                      kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr, nullptr,
240                                      nullptr);
241 
242     if (!image) {
243         return;
244     }
245 
246     GrTexture* texture = image->getTexture();
247     REPORTER_ASSERT(reporter, texture);
248     GrVkTexture* vkTex = static_cast<GrVkTexture*>(texture);
249 
250     // Change our backend texture to the internal queue, with the same layout. This should force a
251     // queue transition even though the layouts match.
252     vkTex->setImageLayout(vkGpu, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0,
253                           VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, false);
254 
255     // Get our image info again and make sure we transitioned queues.
256     GrBackendTexture newBackendTexture = image->getBackendTexture(true);
257     GrVkImageInfo newVkInfo;
258     REPORTER_ASSERT(reporter, GrBackendTextures::GetVkImageInfo(newBackendTexture, &newVkInfo));
259     REPORTER_ASSERT(reporter, newVkInfo.fCurrentQueueFamily == vkGpu->queueIndex());
260 
261     image.reset();
262     dContext->submit(GrSyncCpu::kYes);
263     dContext->deleteBackendTexture(backendTex);
264 }
265 #endif
266 
267 #endif
268