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