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(uint64_t & var)87 static inline void *getPtrOfVar(uint64_t &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 uint64_t initValue = 0xcdcdcdcd;
106
107 std::vector<uint64_t> 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<uint64_t> & outputs)121 bool validateOutput(std::vector<uint64_t> &outputs)
122 {
123 // The shader will write a 1 in the output if the clock did not increase
124 return (outputs.size() == uint64_t(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)
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 = {{"EXTENSIONS", extensions.str()},
206 {"SOURCE", source.str()}};
207
208 m_shaderSpec.globalDeclarations = tcu::StringTemplate("${EXTENSIONS}").specialize(specializations);
209 m_shaderSpec.source = tcu::StringTemplate("${SOURCE} ").specialize(specializations);
210
211 m_shaderSpec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT_VEC2, glu::PRECISION_HIGHP)));
212 }
213
214 private:
215 ShaderClockCase(const ShaderClockCase &);
216 ShaderClockCase &operator=(const ShaderClockCase &);
217
218 testType m_operation;
219 ShaderSpec m_shaderSpec;
220 glu::ShaderType m_shaderType;
221 };
222
addShaderClockTests(tcu::TestCaseGroup * testGroup)223 void addShaderClockTests(tcu::TestCaseGroup *testGroup)
224 {
225 static glu::ShaderType stages[] = {glu::SHADERTYPE_VERTEX, glu::SHADERTYPE_FRAGMENT, glu::SHADERTYPE_COMPUTE};
226
227 static testType operations[] = {{SUBGROUP, BIT_64, "clockARB"},
228 {SUBGROUP, BIT_32, "clock2x32ARB"},
229 {DEVICE, BIT_64, "clockRealtimeEXT"},
230 {DEVICE, BIT_32, "clockRealtime2x32EXT"}};
231
232 tcu::TestContext &testCtx = testGroup->getTestContext();
233
234 for (size_t i = 0; i != DE_LENGTH_OF_ARRAY(stages); ++i)
235 {
236 const char *stageName = (stages[i] == glu::SHADERTYPE_VERTEX) ? ("vertex") :
237 (stages[i] == glu::SHADERTYPE_FRAGMENT) ? ("fragment") :
238 (stages[i] == glu::SHADERTYPE_COMPUTE) ? ("compute") :
239 (DE_NULL);
240
241 const std::string setName = std::string() + stageName;
242 de::MovePtr<tcu::TestCaseGroup> stageGroupTest(new tcu::TestCaseGroup(testCtx, setName.c_str()));
243
244 for (size_t j = 0; j != DE_LENGTH_OF_ARRAY(operations); ++j)
245 {
246 stageGroupTest->addChild(new ShaderClockCase(testCtx, operations[j], stages[i]));
247 }
248
249 testGroup->addChild(stageGroupTest.release());
250 }
251 }
252
253 } // namespace
254
createShaderClockTests(tcu::TestContext & testCtx)255 tcu::TestCaseGroup *createShaderClockTests(tcu::TestContext &testCtx)
256 {
257 return createTestGroup(testCtx, "shader_clock", addShaderClockTests);
258 }
259
260 } // namespace shaderexecutor
261 } // namespace vkt
262