1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2018 Advanced Micro Devices, Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Test cases for VK_KHR_shader_clock. Ensure that values are
23           being read from the OpReadClockKHR OpCode.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktShaderClockTests.hpp"
27 #include "vktTestCaseUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
29 #include "vktShaderExecutor.hpp"
30 
31 #include "vkQueryUtil.hpp"
32 
33 #include "tcuStringTemplate.hpp"
34 
35 #include "vktAtomicOperationTests.hpp"
36 #include "vktShaderExecutor.hpp"
37 
38 #include "vkRefUtil.hpp"
39 #include "vkMemUtil.hpp"
40 #include "vkQueryUtil.hpp"
41 #include "vktTestGroupUtil.hpp"
42 
43 #include "tcuTestLog.hpp"
44 #include "tcuStringTemplate.hpp"
45 #include "tcuResultCollector.hpp"
46 
47 #include "deStringUtil.hpp"
48 #include "deSharedPtr.hpp"
49 #include "deRandom.hpp"
50 #include "deArrayUtil.hpp"
51 
52 #include <cassert>
53 #include <string>
54 
55 namespace vkt
56 {
57 namespace shaderexecutor
58 {
59 
60 namespace
61 {
62 
63 enum
64 {
65 	NUM_ELEMENTS = 32
66 };
67 
68 enum clockType
69 {
70 	SUBGROUP = 0,
71 	DEVICE
72 };
73 
74 enum bitType
75 {
76 	BIT_32 = 0,
77 	BIT_64
78 };
79 
80 struct testType
81 {
82 	clockType   testClockType;
83 	bitType     testBitType;
84 	const char* testName;
85 };
86 
getPtrOfVar(deUint64 & var)87 static inline void* getPtrOfVar(deUint64& var)
88 {
89 	return &var;
90 }
91 
92 using namespace vk;
93 
94 class ShaderClockTestInstance : public TestInstance
95 {
96 public:
ShaderClockTestInstance(Context & context,bool realtimeTest,const ShaderSpec & shaderSpec,glu::ShaderType shaderType)97 	ShaderClockTestInstance(Context& context, bool realtimeTest, const ShaderSpec& shaderSpec, glu::ShaderType shaderType)
98 		: TestInstance(context)
99 		, m_realtime_test(realtimeTest)
100 		, m_executor(createExecutor(m_context, shaderType, shaderSpec))
101 	{
102 		checkSupported();
103 	}
104 
iterate(void)105 	virtual tcu::TestStatus iterate(void)
106 	{
107 		const deUint64 initValue = 0xcdcdcdcd;
108 
109 		std::vector<deUint64>	outputs		(NUM_ELEMENTS, initValue);
110 		std::vector<void*>		outputPtr	(NUM_ELEMENTS, nullptr);
111 
112 		std::transform(std::begin(outputs), std::end(outputs), std::begin(outputPtr), getPtrOfVar);
113 
114 		m_executor->execute(NUM_ELEMENTS, nullptr, outputPtr.data());
115 
116 		if (validateOutput(outputs))
117 			return tcu::TestStatus::pass("Pass");
118 		else
119 			return tcu::TestStatus::fail("Result comparison failed");
120 	}
121 
122 private:
checkSupported(void)123 	void checkSupported(void)
124 	{
125 		m_context.requireDeviceFunctionality("VK_KHR_shader_clock");
126 
127 		VkPhysicalDeviceShaderClockFeaturesKHR shaderClockFeatures;
128 		shaderClockFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR;
129 		shaderClockFeatures.pNext = DE_NULL;
130 
131 		VkPhysicalDeviceFeatures2 features;
132 		features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
133 		features.pNext = &shaderClockFeatures;
134 
135 		m_context.getInstanceInterface().getPhysicalDeviceFeatures2(m_context.getPhysicalDevice(), &features);
136 
137 		if (m_realtime_test && !shaderClockFeatures.shaderDeviceClock)
138 			TCU_THROW(NotSupportedError, "Shader device clock is not supported");
139 
140 		if (!m_realtime_test && !shaderClockFeatures.shaderSubgroupClock)
141 			TCU_THROW(NotSupportedError, "Shader subgroup clock is not supported");
142 	}
143 
validateOutput(std::vector<deUint64> & outputs)144 	bool validateOutput(std::vector<deUint64>& outputs)
145 	{
146 		// The shader will write a 1 in the output if the clock did not increase
147 		return (outputs.size() == deUint64(std::count(std::begin(outputs), std::end(outputs), 0)));
148 	}
149 
150 	const bool							m_realtime_test;
151 	de::UniquePtr<ShaderExecutor>		m_executor;
152 };
153 
154 class ShaderClockCase : public TestCase
155 {
156 public:
ShaderClockCase(tcu::TestContext & testCtx,testType operation,glu::ShaderType shaderType)157 	ShaderClockCase(tcu::TestContext& testCtx, testType operation, glu::ShaderType shaderType)
158 		: TestCase(testCtx, operation.testName, operation.testName)
159 		, m_operation(operation)
160 		, m_shaderSpec()
161 		, m_shaderType(shaderType)
162 	{
163 		initShaderSpec();
164 	}
165 
createInstance(Context & ctx) const166 	TestInstance* createInstance(Context& ctx) const
167 	{
168 		return new ShaderClockTestInstance(ctx, (m_operation.testClockType == DEVICE), m_shaderSpec, m_shaderType);
169 	}
170 
initPrograms(vk::SourceCollections & programCollection) const171 	void initPrograms(vk::SourceCollections& programCollection) const
172 	{
173 		generateSources(m_shaderType, m_shaderSpec, programCollection);
174 	}
175 
176 private:
initShaderSpec()177 	void initShaderSpec()
178 	{
179 		std::stringstream extensions;
180 		std::stringstream source;
181 
182 		if (m_operation.testBitType == BIT_64)
183 		{
184 			extensions	<< "#extension GL_ARB_gpu_shader_int64 : require        \n";
185 
186 			source << "uint64_t time1 = " << m_operation.testName << "();   \n";
187 			source << "uint64_t time2 = " << m_operation.testName << "();   \n";
188 			source << "out0  = uvec2(0, 0);                                 \n";
189 			source << "if (time1 > time2) {                                 \n";
190 			source << "    out0.x = 1;                                      \n";
191 			source << "}                                                    \n";
192 		}
193 		else
194 		{
195 			source << "uvec2 time1 = " << m_operation.testName << "();                      \n";
196 			source << "uvec2 time2 = " << m_operation.testName << "();                      \n";
197 			source << "out0  = uvec2(0, 0);                                                 \n";
198 			source << "if (time1.y > time2.y || (time1.y == time2.y && time1.x > time2.x)){ \n";
199 			source << "    out0.x = 1;                                                      \n";
200 			source << "}                                                                    \n";
201 		}
202 
203 		if (m_operation.testClockType == DEVICE)
204 		{
205 			extensions << "#extension GL_EXT_shader_realtime_clock : require	\n";
206 		}
207 		else
208 		{
209 			extensions << "#extension GL_ARB_shader_clock : enable				\n";
210 		}
211 
212 		std::map<std::string, std::string> specializations = {
213 			{	"EXTENSIONS",	extensions.str()    },
214 			{	"SOURCE",		source.str()        }
215 		};
216 
217 		m_shaderSpec.globalDeclarations = tcu::StringTemplate("${EXTENSIONS}").specialize(specializations);
218 		m_shaderSpec.source             = tcu::StringTemplate("${SOURCE}	").specialize(specializations);
219 
220 		m_shaderSpec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT_VEC2, glu::PRECISION_HIGHP)));
221 	}
222 
223 private:
224 	ShaderClockCase				(const ShaderClockCase&);
225 	ShaderClockCase& operator=	(const ShaderClockCase&);
226 
227 	testType							m_operation;
228 	ShaderSpec							m_shaderSpec;
229 	glu::ShaderType						m_shaderType;
230 };
231 
addShaderClockTests(tcu::TestCaseGroup * testGroup)232 void addShaderClockTests (tcu::TestCaseGroup* testGroup)
233 {
234 	static glu::ShaderType stages[] =
235 	{
236 		glu::SHADERTYPE_VERTEX,
237 		glu::SHADERTYPE_FRAGMENT,
238 		glu::SHADERTYPE_COMPUTE
239 	};
240 
241 	static testType operations[] =
242     {
243 		{SUBGROUP, BIT_64, "clockARB"},
244 		{SUBGROUP, BIT_32, "clock2x32ARB" },
245 		{DEVICE,   BIT_64, "clockRealtimeEXT"},
246 		{DEVICE,   BIT_32, "clockRealtime2x32EXT"}
247 	};
248 
249 	tcu::TestContext& testCtx = testGroup->getTestContext();
250 
251 	for (size_t i = 0; i != DE_LENGTH_OF_ARRAY(stages); ++i)
252 	{
253 		const char* stageName = (stages[i] == glu::SHADERTYPE_VERTEX) ? ("vertex")
254 								: (stages[i] == glu::SHADERTYPE_FRAGMENT) ? ("fragment")
255 								: (stages[i] == glu::SHADERTYPE_COMPUTE) ? ("compute")
256 								: (DE_NULL);
257 
258 		const std::string setName = std::string() + stageName;
259 		de::MovePtr<tcu::TestCaseGroup> stageGroupTest(new tcu::TestCaseGroup(testCtx, setName.c_str(), "Shader Clock Tests"));
260 
261 		for (size_t j = 0; j != DE_LENGTH_OF_ARRAY(operations); ++j)
262 		{
263 			stageGroupTest->addChild(new ShaderClockCase(testCtx, operations[j], stages[i]));
264 		}
265 
266 		testGroup->addChild(stageGroupTest.release());
267 	}
268 }
269 
270 } // anonymous
271 
createShaderClockTests(tcu::TestContext & testCtx)272 tcu::TestCaseGroup* createShaderClockTests(tcu::TestContext& testCtx)
273 {
274 	return createTestGroup(testCtx, "shader_clock", "Shader Clock Tests", addShaderClockTests);
275 }
276 
277 } // shaderexecutor
278 } // vkt
279