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