1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2020 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 Experimental crash postmortem shader timeout tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktPostmortemTests.hpp"
25 #include "vktPostmortemShaderTimeoutTests.hpp"
26 #include "vktTestGroupUtil.hpp"
27 #include "vktTestCase.hpp"
28 #include "vkBarrierUtil.hpp"
29 #include "vkBufferWithMemory.hpp"
30 #include "vkBuilderUtil.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkDefs.hpp"
33 #include "vkObjUtil.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "deUniquePtr.hpp"
36 #include "tcuCommandLine.hpp"
37 #include "vktCustomInstancesDevices.hpp"
38 #include "vktPostmortemUtil.hpp"
39
40 using namespace vk;
41
42 namespace vkt
43 {
44 namespace postmortem
45 {
46 namespace
47 {
48
49 class ShaderTimeoutCase : public vkt::TestCase
50 {
51 public:
ShaderTimeoutCase(tcu::TestContext & testCtx,const std::string & name,deUint32 iterations)52 ShaderTimeoutCase(tcu::TestContext& testCtx, const std::string& name, deUint32 iterations) : TestCase(testCtx, name, "Long-running compute shader"), m_iterations(iterations) {}
53
54 TestInstance* createInstance(Context& context) const override;
55 void initPrograms(vk::SourceCollections& programCollection) const override;
56
57 private:
58 deUint32 m_iterations;
59 };
60
61 class ShaderTimeoutInstance : public PostmortemTestInstance
62 {
63 public:
64 ShaderTimeoutInstance(Context& context, deUint32 iterations);
65
66 tcu::TestStatus iterate(void) override;
67
68 private:
69 deUint32 m_iterations;
70 };
71
ShaderTimeoutInstance(Context & context,deUint32 iterations)72 ShaderTimeoutInstance::ShaderTimeoutInstance(Context& context, deUint32 iterations)
73 : PostmortemTestInstance(context), m_iterations(iterations)
74 {
75
76 }
77
createInstance(Context & context) const78 TestInstance* ShaderTimeoutCase::createInstance(Context& context) const
79 {
80 return new ShaderTimeoutInstance(context, m_iterations);
81 }
82
initPrograms(vk::SourceCollections & programCollection) const83 void ShaderTimeoutCase::initPrograms(vk::SourceCollections& programCollection) const
84 {
85 std::ostringstream src;
86 src << "#version 320 es\n"
87 << "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1)\n"
88 << "layout(binding = 0) uniform Params {\n"
89 << " int x;\n"
90 << " int y;\n"
91 << "} bounds;\n"
92 << "layout(std430, binding = 1) buffer Output {\n"
93 << " uint values[];\n"
94 << "} sb_out;\n"
95 << "\n"
96 << "void main()\n"
97 << "{\n"
98 << " uint localSize = gl_WorkGroupSize.x * gl_WorkGroupSize.y * gl_WorkGroupSize.z;\n"
99 << " uint globalNdx = gl_NumWorkGroups.x * gl_NumWorkGroups.y * gl_WorkGroupID.z + gl_NumWorkGroups.x * gl_WorkGroupID.y + gl_WorkGroupID.x;\n"
100 << " uint globalOffs = localSize * globalNdx;\n"
101 << " uint localOffs = gl_WorkGroupSize.x * gl_WorkGroupSize.y * gl_LocalInvocationID.z + gl_WorkGroupSize.x * gl_LocalInvocationID.y + gl_LocalInvocationID.x;\n"
102 << " uint sum = uint(0);\n"
103 << " for (int y = 0; y < bounds.y; ++y) {\n"
104 << " for (int x = 0; x < bounds.x; ++x) {\n"
105 << " sb_out.values[globalOffs + localOffs] = sb_out.values[globalOffs + localOffs] + uint(1);\n"
106 << " memoryBarrierBuffer();\n"
107 << " barrier();\n"
108 << " }\n"
109 << " }\n"
110 << "}\n";
111
112 programCollection.glslSources.add("comp") << glu::ComputeSource(src.str());
113 }
114
iterate(void)115 tcu::TestStatus ShaderTimeoutInstance::iterate(void)
116 {
117 const VkDevice device = *m_logicalDevice;
118 const DeviceInterface& vk = m_deviceDriver;
119 const VkQueue queue = m_queue;
120 const deUint32 queueFamilyIndex = m_queueFamilyIndex;
121 Allocator& allocator = m_allocator;
122
123 const int workSize = 1024;
124 const VkDeviceSize storageSizeInBytes = sizeof(deUint32) * workSize;
125 const VkDeviceSize uniformSizeInBytes = sizeof(deUint32) * 2;
126
127 // Create storage and uniform buffers
128 BufferWithMemory storageBuffer(vk, device, allocator,
129 makeBufferCreateInfo(storageSizeInBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT),
130 MemoryRequirement::HostVisible);
131 BufferWithMemory uniformBuffer(vk, device, allocator,
132 makeBufferCreateInfo(uniformSizeInBytes, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT),
133 MemoryRequirement::HostVisible);
134
135 // Fill storage buffer with sequentially increasing values
136 {
137 const Allocation& storageBufferAllocation = storageBuffer.getAllocation();
138 deUint32* storageBufferPtr = static_cast<deUint32*>(storageBufferAllocation.getHostPtr());
139 for (int i = 0; i < workSize; ++i)
140 storageBufferPtr[i] = i;
141
142 flushAlloc(vk, device, storageBufferAllocation);
143 }
144
145 // Set uniforms for shader loop bounds to m_iterations
146 {
147 const Allocation& uniformBufferAllocation = uniformBuffer.getAllocation();
148 deUint32* uniformBufferPtr = static_cast<deUint32*>(uniformBufferAllocation.getHostPtr());
149 uniformBufferPtr[0] = m_iterations;
150 uniformBufferPtr[1] = m_iterations;
151
152 flushAlloc(vk, device, uniformBufferAllocation);
153 }
154
155 const Unique<VkDescriptorSetLayout> descriptorSetLayout(
156 DescriptorSetLayoutBuilder()
157 .addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
158 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
159 .build(vk, device));
160
161 const Unique<VkDescriptorPool> descriptorPool(
162 DescriptorPoolBuilder()
163 .addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
164 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
165 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
166
167 const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
168
169 const VkDescriptorBufferInfo uniformDescriptorInfo = makeDescriptorBufferInfo(*uniformBuffer, 0ull, uniformSizeInBytes);
170 const VkDescriptorBufferInfo storageDescriptorInfo = makeDescriptorBufferInfo(*storageBuffer, 0ull, storageSizeInBytes);
171 DescriptorSetUpdateBuilder()
172 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &uniformDescriptorInfo)
173 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &storageDescriptorInfo)
174 .update(vk, device);
175
176 // Create pipelines
177 const Unique<VkShaderModule> shaderModule(createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0u));
178 const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout));
179 const Unique<VkPipeline> pipeline(makeComputePipeline(vk, device, *pipelineLayout, *shaderModule));
180
181 const VkBufferMemoryBarrier hostWriteBarriers[2] =
182 {
183 makeBufferMemoryBarrier(VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, *storageBuffer, 0ull, storageSizeInBytes),
184 makeBufferMemoryBarrier(VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_UNIFORM_READ_BIT, *uniformBuffer, 0ull, uniformSizeInBytes)
185 };
186 const VkBufferMemoryBarrier computeFinishBarrier = makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *storageBuffer, 0ull, storageSizeInBytes);
187
188 // Create command buffer and launch dispatch,
189 const Unique<VkCommandPool> cmdPool(makeCommandPool(vk, device, queueFamilyIndex));
190 const Unique<VkCommandBuffer> cmdBuffer(allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
191
192 beginCommandBuffer(vk, *cmdBuffer);
193 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
194 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
195 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 2u, hostWriteBarriers, 0, (const VkImageMemoryBarrier*)DE_NULL);
196 vk.cmdDispatch(*cmdBuffer, workSize, 1, 1);
197 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*) DE_NULL, 1u, &computeFinishBarrier, 0, (const VkImageMemoryBarrier*) DE_NULL);
198 endCommandBuffer(vk, *cmdBuffer);
199
200 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
201
202 // Verify output
203 const Allocation& storageAllocation = storageBuffer.getAllocation();
204 invalidateAlloc(vk, device, storageAllocation);
205
206 const deUint32* bufferPtr = static_cast<deUint32*>(storageAllocation.getHostPtr());
207 for (int i = 0; i < workSize; ++i)
208 {
209 const deUint32 res = bufferPtr[i];
210 const deUint32 ref = i + m_iterations * m_iterations;
211 if (res != ref)
212 {
213 std::ostringstream msg;
214 msg << "Comparison failed for sb_out.values[" << i << "] ref:" << ref << " res:" << res;
215 return tcu::TestStatus::fail(msg.str());
216 }
217 }
218
219 return tcu::TestStatus::pass("Test succeeded without device loss");
220 }
221
222 }
223
createShaderTimeoutTests(tcu::TestContext & testCtx)224 tcu::TestCaseGroup* createShaderTimeoutTests(tcu::TestContext& testCtx)
225 {
226 de::MovePtr<tcu::TestCaseGroup> timeoutGroup(new tcu::TestCaseGroup(testCtx, "shader_timeout", "Shader timeout tests."));
227 for (int i = 0; i < 16; ++i)
228 {
229 deUint32 iterations = 0x1u << i;
230 std::stringstream name;
231 name << "compute_" << iterations << "x" << iterations;
232 timeoutGroup->addChild(new ShaderTimeoutCase(testCtx, name.str(), iterations));
233 }
234
235 return timeoutGroup.release();
236 }
237
238 } // postmortem
239 } // vkt
240