• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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