Merge branch 'jekstrand_renderpass_transfer_bit_fix' into 'master'
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / spirv_assembly / vktSpvAsmComputeShaderCase.cpp
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 Google Inc.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and/or associated documentation files (the
9  * "Materials"), to deal in the Materials without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sublicense, and/or sell copies of the Materials, and to
12  * permit persons to whom the Materials are furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice(s) and this permission notice shall be
16  * included in all copies or substantial portions of the Materials.
17  *
18  * The Materials are Confidential Information as defined by the
19  * Khronos Membership Agreement until designated non-confidential by
20  * Khronos, at which point this condition clause shall be removed.
21  *
22  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
26  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28  * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
29  *
30  *//*!
31  * \file
32  * \brief Test Case Skeleton Based on Compute Shaders
33  *//*--------------------------------------------------------------------*/
34
35 #include "vktSpvAsmComputeShaderCase.hpp"
36
37 #include "deSharedPtr.hpp"
38
39 #include "vkBuilderUtil.hpp"
40 #include "vkMemUtil.hpp"
41 #include "vkRefUtil.hpp"
42 #include "vkQueryUtil.hpp"
43 #include "vkTypeUtil.hpp"
44
45 namespace
46 {
47
48 using namespace vk;
49 using std::vector;
50
51 typedef vkt::SpirVAssembly::AllocationMp                        AllocationMp;
52 typedef vkt::SpirVAssembly::AllocationSp                        AllocationSp;
53
54 typedef Unique<VkBuffer>                                                        BufferHandleUp;
55 typedef de::SharedPtr<BufferHandleUp>                           BufferHandleSp;
56
57 /*--------------------------------------------------------------------*//*!
58  * \brief Create storage buffer, allocate and bind memory for the buffer
59  *
60  * The memory is created as host visible and passed back as a vk::Allocation
61  * instance via outMemory.
62  *//*--------------------------------------------------------------------*/
63 Move<VkBuffer> createBufferAndBindMemory (const DeviceInterface& vkdi, const VkDevice& device, Allocator& allocator, size_t numBytes, AllocationMp* outMemory)
64 {
65         const VkBufferCreateInfo bufferCreateInfo =
66         {
67                 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,   // sType
68                 DE_NULL,                                                                // pNext
69                 0u,                                                                             // flags
70                 numBytes,                                                               // size
71                 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,             // usage
72                 VK_SHARING_MODE_EXCLUSIVE,                              // sharingMode
73                 0u,                                                                             // queueFamilyCount
74                 DE_NULL,                                                                // pQueueFamilyIndices
75         };
76
77         Move<VkBuffer>                          buffer                  (createBuffer(vkdi, device, &bufferCreateInfo));
78         const VkMemoryRequirements      requirements    = getBufferMemoryRequirements(vkdi, device, *buffer);
79         AllocationMp                            bufferMemory    = allocator.allocate(requirements, MemoryRequirement::HostVisible);
80
81         VK_CHECK(vkdi.bindBufferMemory(device, *buffer, bufferMemory->getMemory(), bufferMemory->getOffset()));
82         *outMemory = bufferMemory;
83
84         return buffer;
85 }
86
87 void setMemory (const DeviceInterface& vkdi, const VkDevice& device, Allocation* destAlloc, size_t numBytes, const void* data)
88 {
89         void* const hostPtr = destAlloc->getHostPtr();
90
91         deMemcpy((deUint8*)hostPtr, data, numBytes);
92         flushMappedMemoryRange(vkdi, device, destAlloc->getMemory(), destAlloc->getOffset(), numBytes);
93 }
94
95 void fillMemoryWithValue (const DeviceInterface& vkdi, const VkDevice& device, Allocation* destAlloc, size_t numBytes, deUint8 value)
96 {
97         void* const hostPtr = destAlloc->getHostPtr();
98
99         deMemset((deUint8*)hostPtr, value, numBytes);
100         flushMappedMemoryRange(vkdi, device, destAlloc->getMemory(), destAlloc->getOffset(), numBytes);
101 }
102
103 /*--------------------------------------------------------------------*//*!
104  * \brief Create a descriptor set layout with numBindings descriptors
105  *
106  * All descriptors are created for shader storage buffer objects and
107  * compute pipeline.
108  *//*--------------------------------------------------------------------*/
109 Move<VkDescriptorSetLayout> createDescriptorSetLayout (const DeviceInterface& vkdi, const VkDevice& device, size_t numBindings)
110 {
111         DescriptorSetLayoutBuilder builder;
112
113         for (size_t bindingNdx = 0; bindingNdx < numBindings; ++bindingNdx)
114                 builder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT);
115
116         return builder.build(vkdi, device);
117 }
118
119 /*--------------------------------------------------------------------*//*!
120  * \brief Create a pipeline layout with one descriptor set
121  *//*--------------------------------------------------------------------*/
122 Move<VkPipelineLayout> createPipelineLayout (const DeviceInterface& vkdi, const VkDevice& device, VkDescriptorSetLayout descriptorSetLayout)
123 {
124         const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
125         {
126                 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,  // sType
127                 DE_NULL,                                                                                // pNext
128                 (VkPipelineLayoutCreateFlags)0,
129                 1u,                                                                                             // descriptorSetCount
130                 &descriptorSetLayout,                                                   // pSetLayouts
131                 0u,                                                                                             // pushConstantRangeCount
132                 DE_NULL,                                                                                // pPushConstantRanges
133         };
134
135         return createPipelineLayout(vkdi, device, &pipelineLayoutCreateInfo);
136 }
137
138 /*--------------------------------------------------------------------*//*!
139  * \brief Create a one-time descriptor pool for one descriptor set
140  *
141  * The pool supports numDescriptors storage buffer descriptors.
142  *//*--------------------------------------------------------------------*/
143 inline Move<VkDescriptorPool> createDescriptorPool (const DeviceInterface& vkdi, const VkDevice& device, deUint32 numDescriptors)
144 {
145         return DescriptorPoolBuilder()
146                 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, numDescriptors)
147                 .build(vkdi, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, /* maxSets = */ 1);
148 }
149
150 /*--------------------------------------------------------------------*//*!
151  * \brief Create a descriptor set
152  *
153  * The descriptor set's layout should contain numViews descriptors.
154  * All the descriptors represent buffer views, and they are sequentially
155  * binded to binding point starting from 0.
156  *//*--------------------------------------------------------------------*/
157 Move<VkDescriptorSet> createDescriptorSet (const DeviceInterface& vkdi, const VkDevice& device, VkDescriptorPool pool, VkDescriptorSetLayout layout, size_t numViews, const vector<VkDescriptorBufferInfo>& descriptorInfos)
158 {
159         const VkDescriptorSetAllocateInfo       allocInfo       =
160         {
161                 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
162                 DE_NULL,
163                 pool,
164                 1u,
165                 &layout
166         };
167
168         Move<VkDescriptorSet>                           descriptorSet   = allocateDescriptorSet(vkdi, device, &allocInfo);
169         DescriptorSetUpdateBuilder                      builder;
170
171         for (deUint32 descriptorNdx = 0; descriptorNdx < numViews; ++descriptorNdx)
172                 builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(descriptorNdx), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorInfos[descriptorNdx]);
173         builder.update(vkdi, device);
174
175         return descriptorSet;
176 }
177
178 /*--------------------------------------------------------------------*//*!
179  * \brief Create a compute pipeline based on the given shader
180  *//*--------------------------------------------------------------------*/
181 Move<VkPipeline> createComputePipeline (const DeviceInterface& vkdi, const VkDevice& device, VkPipelineLayout pipelineLayout, VkShaderModule shader, const char* entryPoint, const vector<deUint32>& specConstants)
182 {
183         const deUint32                                                  numSpecConstants                                = (deUint32)specConstants.size();
184         vector<VkSpecializationMapEntry>                entries;
185         VkSpecializationInfo                                    specInfo;
186
187         if (numSpecConstants != 0)
188         {
189                 entries.resize(numSpecConstants);
190
191                 for (deUint32 ndx = 0; ndx < numSpecConstants; ++ndx)
192                 {
193                         entries[ndx].constantID = ndx;
194                         entries[ndx].offset             = ndx * (deUint32)sizeof(deUint32);
195                         entries[ndx].size               = sizeof(deUint32);
196                 }
197
198                 specInfo.mapEntryCount          = numSpecConstants;
199                 specInfo.pMapEntries            = &entries[0];
200                 specInfo.dataSize                       = numSpecConstants * sizeof(deUint32);
201                 specInfo.pData                          = specConstants.data();
202         }
203
204         const VkPipelineShaderStageCreateInfo   pipelineShaderStageCreateInfo   =
205         {
206                 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,    // sType
207                 DE_NULL,                                                                                                // pNext
208                 (VkPipelineShaderStageCreateFlags)0,                                    // flags
209                 VK_SHADER_STAGE_COMPUTE_BIT,                                                    // stage
210                 shader,                                                                                                 // module
211                 entryPoint,                                                                                             // pName
212                 (numSpecConstants == 0) ? DE_NULL : &specInfo,                  // pSpecializationInfo
213         };
214         const VkComputePipelineCreateInfo               pipelineCreateInfo                              =
215         {
216                 VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,                 // sType
217                 DE_NULL,                                                                                                // pNext
218                 (VkPipelineCreateFlags)0,
219                 pipelineShaderStageCreateInfo,                                                  // cs
220                 pipelineLayout,                                                                                 // layout
221                 (VkPipeline)0,                                                                                  // basePipelineHandle
222                 0u,                                                                                                             // basePipelineIndex
223         };
224
225         return createComputePipeline(vkdi, device, (VkPipelineCache)0u, &pipelineCreateInfo);
226 }
227
228 /*--------------------------------------------------------------------*//*!
229  * \brief Create a command pool
230  *
231  * The created command pool is designated for use on the queue type
232  * represented by the given queueFamilyIndex.
233  *//*--------------------------------------------------------------------*/
234 Move<VkCommandPool> createCommandPool (const DeviceInterface& vkdi, VkDevice device, deUint32 queueFamilyIndex)
235 {
236         const VkCommandPoolCreateInfo cmdPoolCreateInfo =
237         {
238                 VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,     // sType
239                 DE_NULL,                                                                        // pNext
240                 0u,                                                                                     // flags
241                 queueFamilyIndex,                                                       // queueFamilyIndex
242         };
243
244         return createCommandPool(vkdi, device, &cmdPoolCreateInfo);
245 }
246
247 } // anonymous
248
249 namespace vkt
250 {
251 namespace SpirVAssembly
252 {
253
254 /*--------------------------------------------------------------------*//*!
255  * \brief Test instance for compute pipeline
256  *
257  * The compute shader is specified in the format of SPIR-V assembly, which
258  * is allowed to access MAX_NUM_INPUT_BUFFERS input storage buffers and
259  * MAX_NUM_OUTPUT_BUFFERS output storage buffers maximally. The shader
260  * source and input/output data are given in a ComputeShaderSpec object.
261  *
262  * This instance runs the given compute shader by feeding the data from input
263  * buffers and compares the data in the output buffers with the expected.
264  *//*--------------------------------------------------------------------*/
265 class SpvAsmComputeShaderInstance : public TestInstance
266 {
267 public:
268                                                                 SpvAsmComputeShaderInstance     (Context& ctx, const ComputeShaderSpec& spec);
269         tcu::TestStatus                         iterate                                         (void);
270
271 private:
272         const ComputeShaderSpec&        m_shaderSpec;
273 };
274
275 // ComputeShaderTestCase implementations
276
277 SpvAsmComputeShaderCase::SpvAsmComputeShaderCase (tcu::TestContext& testCtx, const char* name, const char* description, const ComputeShaderSpec& spec)
278         : TestCase              (testCtx, name, description)
279         , m_shaderSpec  (spec)
280 {
281 }
282
283 void SpvAsmComputeShaderCase::initPrograms (SourceCollections& programCollection) const
284 {
285         programCollection.spirvAsmSources.add("compute") << m_shaderSpec.assembly.c_str();
286 }
287
288 TestInstance* SpvAsmComputeShaderCase::createInstance (Context& ctx) const
289 {
290         return new SpvAsmComputeShaderInstance(ctx, m_shaderSpec);
291 }
292
293 // ComputeShaderTestInstance implementations
294
295 SpvAsmComputeShaderInstance::SpvAsmComputeShaderInstance (Context& ctx, const ComputeShaderSpec& spec)
296         : TestInstance  (ctx)
297         , m_shaderSpec  (spec)
298 {
299 }
300
301 tcu::TestStatus SpvAsmComputeShaderInstance::iterate (void)
302 {
303         const DeviceInterface&                          vkdi                            = m_context.getDeviceInterface();
304         const VkDevice&                                         device                          = m_context.getDevice();
305         Allocator&                                                      allocator                       = m_context.getDefaultAllocator();
306
307         vector<AllocationSp>                            inputAllocs;
308         vector<AllocationSp>                            outputAllocs;
309         vector<BufferHandleSp>                          inputBuffers;
310         vector<BufferHandleSp>                          outputBuffers;
311         vector<VkDescriptorBufferInfo>          descriptorInfos;
312
313         DE_ASSERT(!m_shaderSpec.outputs.empty());
314         const size_t                                            numBuffers                      = m_shaderSpec.inputs.size() + m_shaderSpec.outputs.size();
315
316         // Create buffer object, allocate storage, and create view for all input/output buffers.
317
318         for (size_t inputNdx = 0; inputNdx < m_shaderSpec.inputs.size(); ++inputNdx)
319         {
320                 AllocationMp            alloc;
321                 const BufferSp&         input           = m_shaderSpec.inputs[inputNdx];
322                 const size_t            numBytes        = input->getNumBytes();
323                 BufferHandleUp*         buffer          = new BufferHandleUp(createBufferAndBindMemory(vkdi, device, allocator, numBytes, &alloc));
324
325                 setMemory(vkdi, device, &*alloc, numBytes, input->data());
326                 descriptorInfos.push_back(vk::makeDescriptorBufferInfo(**buffer, 0u, numBytes));
327                 inputBuffers.push_back(BufferHandleSp(buffer));
328                 inputAllocs.push_back(de::SharedPtr<Allocation>(alloc.release()));
329         }
330
331         for (size_t outputNdx = 0; outputNdx < m_shaderSpec.outputs.size(); ++outputNdx)
332         {
333                 AllocationMp            alloc;
334                 const BufferSp&         output          = m_shaderSpec.outputs[outputNdx];
335                 const size_t            numBytes        = output->getNumBytes();
336                 BufferHandleUp*         buffer          = new BufferHandleUp(createBufferAndBindMemory(vkdi, device, allocator, numBytes, &alloc));
337
338                 fillMemoryWithValue(vkdi, device, &*alloc, numBytes, 0xff);
339                 descriptorInfos.push_back(vk::makeDescriptorBufferInfo(**buffer, 0u, numBytes));
340                 outputBuffers.push_back(BufferHandleSp(buffer));
341                 outputAllocs.push_back(de::SharedPtr<Allocation>(alloc.release()));
342         }
343
344         // Create layouts and descriptor set.
345
346         Unique<VkDescriptorSetLayout>           descriptorSetLayout     (createDescriptorSetLayout(vkdi, device, numBuffers));
347         Unique<VkPipelineLayout>                        pipelineLayout          (createPipelineLayout(vkdi, device, *descriptorSetLayout));
348         Unique<VkDescriptorPool>                        descriptorPool          (createDescriptorPool(vkdi, device, (deUint32)numBuffers));
349         Unique<VkDescriptorSet>                         descriptorSet           (createDescriptorSet(vkdi, device, *descriptorPool, *descriptorSetLayout, numBuffers, descriptorInfos));
350
351         // Create compute shader and pipeline.
352
353         const ProgramBinary&                            binary                          = m_context.getBinaryCollection().get("compute");
354         Unique<VkShaderModule>                          module                          (createShaderModule(vkdi, device, binary, (VkShaderModuleCreateFlags)0u));
355
356         Unique<VkPipeline>                                      computePipeline         (createComputePipeline(vkdi, device, *pipelineLayout, *module, m_shaderSpec.entryPoint.c_str(), m_shaderSpec.specConstants));
357
358         // Create command buffer and record commands
359
360         const Unique<VkCommandPool>                     cmdPool                         (createCommandPool(vkdi, device, m_context.getUniversalQueueFamilyIndex()));
361         const VkCommandBufferAllocateInfo       cmdBufferCreateInfo     =
362         {
363                 VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // sType
364                 NULL,                                                                                   // pNext
365                 *cmdPool,                                                                               // cmdPool
366                 VK_COMMAND_BUFFER_LEVEL_PRIMARY,                                // level
367                 1u                                                                                              // count
368         };
369
370         Unique<VkCommandBuffer>                         cmdBuffer                       (allocateCommandBuffer(vkdi, device, &cmdBufferCreateInfo));
371
372         const VkCommandBufferBeginInfo          cmdBufferBeginInfo      =
373         {
374                 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,    // sType
375                 DE_NULL,                                                                                // pNext
376                 VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
377                 (const VkCommandBufferInheritanceInfo*)DE_NULL,
378         };
379
380         const tcu::IVec3&                               numWorkGroups           = m_shaderSpec.numWorkGroups;
381
382         VK_CHECK(vkdi.beginCommandBuffer(*cmdBuffer, &cmdBufferBeginInfo));
383         vkdi.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipeline);
384         vkdi.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0, 1, &descriptorSet.get(), 0, DE_NULL);
385         vkdi.cmdDispatch(*cmdBuffer, numWorkGroups.x(), numWorkGroups.y(), numWorkGroups.z());
386         VK_CHECK(vkdi.endCommandBuffer(*cmdBuffer));
387
388         // Create fence and run.
389
390         const VkFenceCreateInfo                 fenceCreateInfo         =
391         {
392                  VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,           // sType
393                  NULL,                                                                          // pNext
394                  0                                                                                      // flags
395     };
396         const Unique<VkFence>                   cmdCompleteFence        (createFence(vkdi, device, &fenceCreateInfo));
397         const deUint64                                  infiniteTimeout         = ~(deUint64)0u;
398         const VkSubmitInfo                              submitInfo                      =
399         {
400                 VK_STRUCTURE_TYPE_SUBMIT_INFO,
401                 DE_NULL,
402                 0u,
403                 (const VkSemaphore*)DE_NULL,
404                 (const VkPipelineStageFlags*)DE_NULL,
405                 1u,
406                 &cmdBuffer.get(),
407                 0u,
408                 (const VkSemaphore*)DE_NULL,
409         };
410
411         VK_CHECK(vkdi.queueSubmit(m_context.getUniversalQueue(), 1, &submitInfo, *cmdCompleteFence));
412         VK_CHECK(vkdi.waitForFences(device, 1, &cmdCompleteFence.get(), 0u, infiniteTimeout)); // \note: timeout is failure
413
414         // Check output.
415         if (m_shaderSpec.verifyIO)
416         {
417                 if (!(*m_shaderSpec.verifyIO)(m_shaderSpec.inputs, outputAllocs, m_shaderSpec.outputs))
418                         return tcu::TestStatus::fail("Output doesn't match with expected");
419         }
420         else
421         {
422                 for (size_t outputNdx = 0; outputNdx < m_shaderSpec.outputs.size(); ++outputNdx)
423                 {
424                         const BufferSp& expectedOutput = m_shaderSpec.outputs[outputNdx];
425                         if (deMemCmp(expectedOutput->data(), outputAllocs[outputNdx]->getHostPtr(), expectedOutput->getNumBytes()))
426                                 return tcu::TestStatus::fail("Output doesn't match with expected");
427                 }
428         }
429
430         return tcu::TestStatus::pass("Ouput match with expected");
431 }
432
433 } // SpirVAssembly
434 } // vkt