xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmFromHlslTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief SPIR-V Assembly Tests for indexing with access chain operations.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktSpvAsmFromHlslTests.hpp"
25 #include "vktTestCaseUtil.hpp"
26 #include "vkPrograms.hpp"
27 #include "vkObjUtil.hpp"
28 #include "vkRefUtil.hpp"
29 #include "vkTypeUtil.hpp"
30 #include "vkQueryUtil.hpp"
31 #include "vkBuilderUtil.hpp"
32 #include "vkBarrierUtil.hpp"
33 #include "vkCmdUtil.hpp"
34 
35 namespace vkt
36 {
37 namespace SpirVAssembly
38 {
39 
40 namespace
41 {
42 
43 using namespace vk;
44 
45 enum TestType
46 {
47     TT_CBUFFER_PACKING = 0,
48 };
49 
50 struct TestConfig
51 {
52     TestType type;
53 };
54 
55 struct Programs
56 {
initvkt::SpirVAssembly::__anon4dbd7b600111::Programs57     void init(vk::SourceCollections &dst, TestConfig config) const
58     {
59         if (config.type == TT_CBUFFER_PACKING)
60         {
61             // HLSL shaders has a packing corner case that GLSL shaders cannot exhibit.
62             // Below shader, foo has an ArrayStride of 16, which leaves bar effectively
63             // 'within' the end of the foo array. This is entirely valid for HLSL and
64             // with the VK_EXT_scalar_block_layout extension.
65             std::string source("cbuffer cbIn\n"
66                                "{\n"
67                                "  int foo[2] : packoffset(c0);\n"
68                                "  int bar    : packoffset(c1.y);\n"
69                                "};\n"
70                                "RWStructuredBuffer<int> result : register(u1);\n"
71                                "[numthreads(1, 1, 1)]\n"
72                                "void main(uint3 dispatchThreadID : SV_DispatchThreadID)\n"
73                                "{\n"
74                                "  result[0] = bar;\n"
75                                "}\n");
76 
77             dst.hlslSources.add("comp") << glu::ComputeSource(source)
78                                         << vk::ShaderBuildOptions(dst.usedVulkanVersion, vk::SPIRV_VERSION_1_0,
79                                                                   vk::ShaderBuildOptions::FLAG_ALLOW_SCALAR_OFFSETS);
80         }
81     }
82 };
83 
84 class HlslTest : public TestInstance
85 {
86 public:
87     HlslTest(Context &context, TestConfig config);
88     virtual ~HlslTest(void) = default;
89 
90     tcu::TestStatus iterate(void);
91 };
92 
HlslTest(Context & context,TestConfig config)93 HlslTest::HlslTest(Context &context, TestConfig config) : TestInstance(context)
94 {
95     DE_UNREF(config);
96 }
97 
iterate(void)98 tcu::TestStatus HlslTest::iterate(void)
99 {
100     const DeviceInterface &vk       = m_context.getDeviceInterface();
101     const VkDevice device           = m_context.getDevice();
102     const VkQueue queue             = m_context.getUniversalQueue();
103     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
104     Allocator &allocator            = m_context.getDefaultAllocator();
105     const int testValue             = 5;
106 
107     // Create an input buffer
108     const VkBufferUsageFlags inBufferUsageFlags = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
109     const VkDeviceSize inBufferSizeBytes        = 32; // 2 element array with 16B stride
110     VkBufferCreateInfo inBufferCreateInfo       = makeBufferCreateInfo(inBufferSizeBytes, inBufferUsageFlags);
111     vk::Move<vk::VkBuffer> inBuffer             = createBuffer(vk, device, &inBufferCreateInfo);
112     de::MovePtr<vk::Allocation> inAllocation =
113         allocator.allocate(getBufferMemoryRequirements(vk, device, *inBuffer), MemoryRequirement::HostVisible);
114     VK_CHECK(vk.bindBufferMemory(device, *inBuffer, inAllocation->getMemory(), inAllocation->getOffset()));
115 
116     // Fill the input structure with data - first attribute is array that has 16B stride,
117     // this means that second attribute has to start at offset 20B (4B + 16B)
118     {
119         int *bufferPtr = static_cast<int *>(inAllocation->getHostPtr());
120         memset(bufferPtr, 0, inBufferSizeBytes);
121         bufferPtr[5] = testValue;
122         flushAlloc(vk, device, *inAllocation);
123     }
124 
125     // Create an output buffer
126     const VkBufferUsageFlags outBufferUsageFlags = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
127     const VkDeviceSize outBufferSizeBytes        = sizeof(int);
128     VkBufferCreateInfo outBufferCreateInfo       = makeBufferCreateInfo(outBufferSizeBytes, outBufferUsageFlags);
129     vk::Move<vk::VkBuffer> outBuffer             = createBuffer(vk, device, &outBufferCreateInfo);
130     de::MovePtr<vk::Allocation> outAllocation =
131         allocator.allocate(getBufferMemoryRequirements(vk, device, *outBuffer), MemoryRequirement::HostVisible);
132     VK_CHECK(vk.bindBufferMemory(device, *outBuffer, outAllocation->getMemory(), outAllocation->getOffset()));
133 
134     // Create descriptor set
135     const VkDescriptorType uniBufDesc  = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
136     const VkDescriptorType storBufDesc = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
137     const Unique<VkDescriptorSetLayout> descriptorSetLayout(
138         DescriptorSetLayoutBuilder()
139             .addSingleBinding(uniBufDesc, VK_SHADER_STAGE_COMPUTE_BIT)
140             .addSingleBinding(storBufDesc, VK_SHADER_STAGE_COMPUTE_BIT)
141             .build(vk, device));
142 
143     const Unique<VkDescriptorPool> descriptorPool(
144         DescriptorPoolBuilder()
145             .addType(uniBufDesc)
146             .addType(storBufDesc)
147             .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
148 
149     const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
150 
151     const VkDescriptorBufferInfo inputBufferDescriptorInfo =
152         makeDescriptorBufferInfo(*inBuffer, 0ull, inBufferSizeBytes);
153     const VkDescriptorBufferInfo outputBufferDescriptorInfo =
154         makeDescriptorBufferInfo(*outBuffer, 0ull, outBufferSizeBytes);
155     DescriptorSetUpdateBuilder()
156         .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), uniBufDesc,
157                      &inputBufferDescriptorInfo)
158         .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), storBufDesc,
159                      &outputBufferDescriptorInfo)
160         .update(vk, device);
161 
162     // Perform the computation
163     const Unique<VkShaderModule> shaderModule(
164         createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0u));
165     const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout));
166 
167     const VkPipelineShaderStageCreateInfo pipelineShaderStageParams = {
168         VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
169         DE_NULL,
170         static_cast<VkPipelineShaderStageCreateFlags>(0u),
171         VK_SHADER_STAGE_COMPUTE_BIT,
172         *shaderModule,
173         "main",
174         DE_NULL,
175     };
176     const VkComputePipelineCreateInfo pipelineCreateInfo = {
177         VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
178         DE_NULL,
179         static_cast<VkPipelineCreateFlags>(0u),
180         pipelineShaderStageParams,
181         *pipelineLayout,
182         DE_NULL,
183         0,
184     };
185     Unique<VkPipeline> pipeline(createComputePipeline(vk, device, DE_NULL, &pipelineCreateInfo));
186     const VkBufferMemoryBarrier hostWriteBarrier = makeBufferMemoryBarrier(
187         VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, *inBuffer, 0ull, inBufferSizeBytes);
188     const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
189         VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *outBuffer, 0ull, outBufferSizeBytes);
190 
191     const Unique<VkCommandPool> cmdPool(makeCommandPool(vk, device, queueFamilyIndex));
192     const Unique<VkCommandBuffer> cmdBuffer(
193         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
194 
195     // Start recording commands
196     beginCommandBuffer(vk, *cmdBuffer);
197 
198     vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
199     vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(),
200                              0u, DE_NULL);
201 
202     vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
203                           (VkDependencyFlags)0, 0, (const VkMemoryBarrier *)DE_NULL, 1, &hostWriteBarrier, 0,
204                           (const VkImageMemoryBarrier *)DE_NULL);
205     vk.cmdDispatch(*cmdBuffer, 1, 1, 1);
206     vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
207                           (VkDependencyFlags)0, 0, (const VkMemoryBarrier *)DE_NULL, 1, &shaderWriteBarrier, 0,
208                           (const VkImageMemoryBarrier *)DE_NULL);
209 
210     endCommandBuffer(vk, *cmdBuffer);
211 
212     // Wait for completion
213     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
214 
215     // Validate the results
216     invalidateAlloc(vk, device, *outAllocation);
217     const int *bufferPtr = static_cast<int *>(outAllocation->getHostPtr());
218     if (*bufferPtr != testValue)
219         return tcu::TestStatus::fail("Fail");
220     return tcu::TestStatus::pass("Pass");
221 }
222 
checkSupport(Context & context)223 void checkSupport(Context &context)
224 {
225     context.requireDeviceFunctionality("VK_EXT_scalar_block_layout");
226 }
227 
228 } // namespace
229 
createHlslComputeGroup(tcu::TestContext & testCtx)230 tcu::TestCaseGroup *createHlslComputeGroup(tcu::TestContext &testCtx)
231 {
232     typedef InstanceFactory1WithSupport<HlslTest, TestConfig, FunctionSupport0, Programs> HlslTestInstance;
233     de::MovePtr<tcu::TestCaseGroup> hlslCasesGroup(new tcu::TestCaseGroup(testCtx, "hlsl_cases"));
234 
235     TestConfig testConfig = {TT_CBUFFER_PACKING};
236     hlslCasesGroup->addChild(new HlslTestInstance(testCtx, "cbuffer_packing", testConfig, checkSupport));
237 
238     return hlslCasesGroup.release();
239 }
240 
241 } // namespace SpirVAssembly
242 } // namespace vkt
243