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,const ShaderSpec & shaderSpec,glu::ShaderType shaderType)97 ShaderClockTestInstance(Context& context, const ShaderSpec& shaderSpec, glu::ShaderType shaderType)
98 : TestInstance(context)
99 , m_executor(createExecutor(m_context, shaderType, shaderSpec))
100 {
101 }
102
iterate(void)103 virtual tcu::TestStatus iterate(void)
104 {
105 const deUint64 initValue = 0xcdcdcdcd;
106
107 std::vector<deUint64> outputs (NUM_ELEMENTS, initValue);
108 std::vector<void*> outputPtr (NUM_ELEMENTS, nullptr);
109
110 std::transform(std::begin(outputs), std::end(outputs), std::begin(outputPtr), getPtrOfVar);
111
112 m_executor->execute(NUM_ELEMENTS, nullptr, outputPtr.data());
113
114 if (validateOutput(outputs))
115 return tcu::TestStatus::pass("Pass");
116 else
117 return tcu::TestStatus::fail("Result comparison failed");
118 }
119
120 private:
validateOutput(std::vector<deUint64> & outputs)121 bool validateOutput(std::vector<deUint64>& outputs)
122 {
123 // The shader will write a 1 in the output if the clock did not increase
124 return (outputs.size() == deUint64(std::count(std::begin(outputs), std::end(outputs), 0)));
125 }
126
127 de::UniquePtr<ShaderExecutor> m_executor;
128 };
129
130 class ShaderClockCase : public TestCase
131 {
132 public:
ShaderClockCase(tcu::TestContext & testCtx,testType operation,glu::ShaderType shaderType)133 ShaderClockCase(tcu::TestContext& testCtx, testType operation, glu::ShaderType shaderType)
134 : TestCase(testCtx, operation.testName, operation.testName)
135 , m_operation(operation)
136 , m_shaderSpec()
137 , m_shaderType(shaderType)
138 {
139 initShaderSpec();
140 }
141
createInstance(Context & ctx) const142 TestInstance* createInstance (Context& ctx) const override
143 {
144 return new ShaderClockTestInstance(ctx, m_shaderSpec, m_shaderType);
145 }
146
initPrograms(vk::SourceCollections & programCollection) const147 void initPrograms (vk::SourceCollections& programCollection) const override
148 {
149 generateSources(m_shaderType, m_shaderSpec, programCollection);
150 }
151
checkSupport(Context & context) const152 void checkSupport (Context& context) const override
153 {
154 context.requireDeviceFunctionality("VK_KHR_shader_clock");
155
156 if (m_operation.testBitType == BIT_64)
157 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_INT64);
158
159 const auto& shaderClockFeatures = context.getShaderClockFeatures();
160 const auto realTimeTest = (m_operation.testClockType == DEVICE);
161
162 if (realTimeTest && !shaderClockFeatures.shaderDeviceClock)
163 TCU_THROW(NotSupportedError, "Shader device clock is not supported");
164
165 if (!realTimeTest && !shaderClockFeatures.shaderSubgroupClock)
166 TCU_THROW(NotSupportedError, "Shader subgroup clock is not supported");
167 }
168
169 private:
initShaderSpec()170 void initShaderSpec()
171 {
172 std::stringstream extensions;
173 std::stringstream source;
174
175 if (m_operation.testBitType == BIT_64)
176 {
177 extensions << "#extension GL_ARB_gpu_shader_int64 : require \n";
178
179 source << "uint64_t time1 = " << m_operation.testName << "(); \n";
180 source << "uint64_t time2 = " << m_operation.testName << "(); \n";
181 source << "out0 = uvec2(0, 0); \n";
182 source << "if (time1 > time2) { \n";
183 source << " out0.x = 1; \n";
184 source << "} \n";
185 }
186 else
187 {
188 source << "uvec2 time1 = " << m_operation.testName << "(); \n";
189 source << "uvec2 time2 = " << m_operation.testName << "(); \n";
190 source << "out0 = uvec2(0, 0); \n";
191 source << "if (time1.y > time2.y || (time1.y == time2.y && time1.x > time2.x)){ \n";
192 source << " out0.x = 1; \n";
193 source << "} \n";
194 }
195
196 if (m_operation.testClockType == DEVICE)
197 {
198 extensions << "#extension GL_EXT_shader_realtime_clock : require \n";
199 }
200 else
201 {
202 extensions << "#extension GL_ARB_shader_clock : enable \n";
203 }
204
205 std::map<std::string, std::string> specializations = {
206 { "EXTENSIONS", extensions.str() },
207 { "SOURCE", source.str() }
208 };
209
210 m_shaderSpec.globalDeclarations = tcu::StringTemplate("${EXTENSIONS}").specialize(specializations);
211 m_shaderSpec.source = tcu::StringTemplate("${SOURCE} ").specialize(specializations);
212
213 m_shaderSpec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT_VEC2, glu::PRECISION_HIGHP)));
214 }
215
216 private:
217 ShaderClockCase (const ShaderClockCase&);
218 ShaderClockCase& operator= (const ShaderClockCase&);
219
220 testType m_operation;
221 ShaderSpec m_shaderSpec;
222 glu::ShaderType m_shaderType;
223 };
224
addShaderClockTests(tcu::TestCaseGroup * testGroup)225 void addShaderClockTests (tcu::TestCaseGroup* testGroup)
226 {
227 static glu::ShaderType stages[] =
228 {
229 glu::SHADERTYPE_VERTEX,
230 glu::SHADERTYPE_FRAGMENT,
231 glu::SHADERTYPE_COMPUTE
232 };
233
234 static testType operations[] =
235 {
236 {SUBGROUP, BIT_64, "clockARB"},
237 {SUBGROUP, BIT_32, "clock2x32ARB" },
238 {DEVICE, BIT_64, "clockRealtimeEXT"},
239 {DEVICE, BIT_32, "clockRealtime2x32EXT"}
240 };
241
242 tcu::TestContext& testCtx = testGroup->getTestContext();
243
244 for (size_t i = 0; i != DE_LENGTH_OF_ARRAY(stages); ++i)
245 {
246 const char* stageName = (stages[i] == glu::SHADERTYPE_VERTEX) ? ("vertex")
247 : (stages[i] == glu::SHADERTYPE_FRAGMENT) ? ("fragment")
248 : (stages[i] == glu::SHADERTYPE_COMPUTE) ? ("compute")
249 : (DE_NULL);
250
251 const std::string setName = std::string() + stageName;
252 de::MovePtr<tcu::TestCaseGroup> stageGroupTest(new tcu::TestCaseGroup(testCtx, setName.c_str(), "Shader Clock Tests"));
253
254 for (size_t j = 0; j != DE_LENGTH_OF_ARRAY(operations); ++j)
255 {
256 stageGroupTest->addChild(new ShaderClockCase(testCtx, operations[j], stages[i]));
257 }
258
259 testGroup->addChild(stageGroupTest.release());
260 }
261 }
262
263 } // anonymous
264
createShaderClockTests(tcu::TestContext & testCtx)265 tcu::TestCaseGroup* createShaderClockTests(tcu::TestContext& testCtx)
266 {
267 return createTestGroup(testCtx, "shader_clock", "Shader Clock Tests", addShaderClockTests);
268 }
269
270 } // shaderexecutor
271 } // vkt
272