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