1 #ifndef _GLCSUBGROUPSTESTSUTILS_HPP
2 #define _GLCSUBGROUPSTESTSUTILS_HPP
3 /*------------------------------------------------------------------------
4 * OpenGL Conformance Tests
5 * ------------------------
6 *
7 * Copyright (c) 2017-2019 The Khronos Group Inc.
8 * Copyright (c) 2017 Codeplay Software Ltd.
9 * Copyright (c) 2019 NVIDIA Corporation.
10 *
11 * Licensed under the Apache License, Version 2.0 (the "License");
12 * you may not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
14 *
15 * http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
22 *
23 */ /*!
24 * \file
25 * \brief Subgroups tests utility classes
26 */ /*--------------------------------------------------------------------*/
27
28 #include "deDefs.hpp"
29 #include "deSTLUtil.hpp"
30 #include "deStringUtil.hpp"
31 #include "glwEnums.hpp"
32 #include "glwFunctions.hpp"
33 #include "glwDefs.hpp"
34 #include "tcuDefs.hpp"
35 #include "tcuTestCase.hpp"
36 #include "glcTestCase.hpp"
37 #include "glcSpirvUtils.hpp"
38
39 #include "tcuFormatUtil.hpp"
40 #include "tcuTestLog.hpp"
41 #include "tcuVectorUtil.hpp"
42
43 #include "gluShaderUtil.hpp"
44 #include "gluContextInfo.hpp"
45
46 #include "deSharedPtr.hpp"
47 #include "deUniquePtr.hpp"
48
49 #include <string>
50
51 namespace glc
52 {
53
54 enum ShaderType
55 {
56 SHADER_TYPE_GLSL = 0,
57 SHADER_TYPE_SPIRV,
58
59 SHADER_TYPE_LAST
60 };
61
62 template<typename Program>
63 class ProgramCollection
64 {
65 public:
66 ProgramCollection (void);
67 ~ProgramCollection (void);
68
69 void clear (void);
70
71 Program& add (const std::string& name);
72 void add (const std::string& name, de::MovePtr<Program>& program);
73
74 bool contains (const std::string& name) const;
75 const Program& get (const std::string& name) const;
76
77 class Iterator
78 {
79 private:
80 typedef typename std::map<std::string, Program*>::const_iterator IteratorImpl;
81
82 public:
Iterator(const IteratorImpl & i)83 explicit Iterator (const IteratorImpl& i) : m_impl(i) {}
84
operator ++(void)85 Iterator& operator++ (void) { ++m_impl; return *this; }
operator *(void) const86 const Program& operator* (void) const { return getProgram(); }
87
getName(void) const88 const std::string& getName (void) const { return m_impl->first; }
getProgram(void) const89 const Program& getProgram (void) const { return *m_impl->second; }
90
operator ==(const Iterator & other) const91 bool operator== (const Iterator& other) const { return m_impl == other.m_impl; }
operator !=(const Iterator & other) const92 bool operator!= (const Iterator& other) const { return m_impl != other.m_impl; }
93
94 private:
95
96 IteratorImpl m_impl;
97 };
98
begin(void) const99 Iterator begin (void) const { return Iterator(m_programs.begin()); }
end(void) const100 Iterator end (void) const { return Iterator(m_programs.end()); }
101
empty(void) const102 bool empty (void) const { return m_programs.empty(); }
103
104 private:
105 typedef std::map<std::string, Program*> ProgramMap;
106
107 ProgramMap m_programs;
108 };
109
110 template<typename Program>
ProgramCollection(void)111 ProgramCollection<Program>::ProgramCollection (void)
112 {
113 }
114
115 template<typename Program>
~ProgramCollection(void)116 ProgramCollection<Program>::~ProgramCollection (void)
117 {
118 clear();
119 }
120
121 template<typename Program>
clear(void)122 void ProgramCollection<Program>::clear (void)
123 {
124 for (typename ProgramMap::const_iterator i = m_programs.begin(); i != m_programs.end(); ++i)
125 delete i->second;
126 m_programs.clear();
127 }
128
129 template<typename Program>
add(const std::string & name)130 Program& ProgramCollection<Program>::add (const std::string& name)
131 {
132 DE_ASSERT(!contains(name));
133 de::MovePtr<Program> prog = de::newMovePtr<Program>();
134 m_programs[name] = prog.get();
135 prog.release();
136 return *m_programs[name];
137 }
138
139 template<typename Program>
add(const std::string & name,de::MovePtr<Program> & program)140 void ProgramCollection<Program>::add (const std::string& name, de::MovePtr<Program>& program)
141 {
142 DE_ASSERT(!contains(name));
143 m_programs[name] = program.get();
144 program.release();
145 }
146
147 template<typename Program>
contains(const std::string & name) const148 bool ProgramCollection<Program>::contains (const std::string& name) const
149 {
150 return de::contains(m_programs, name);
151 }
152
153 template<typename Program>
get(const std::string & name) const154 const Program& ProgramCollection<Program>::get (const std::string& name) const
155 {
156 DE_ASSERT(contains(name));
157 return *m_programs.find(name)->second;
158 }
159
160 struct GlslSource
161 {
162 std::vector<std::string> sources[glu::SHADERTYPE_LAST];
163
operator <<glc::GlslSource164 GlslSource& operator<< (const glu::ShaderSource& shaderSource)
165 {
166 sources[shaderSource.shaderType].push_back(shaderSource.source);
167 return *this;
168 }
169 };
170
171 typedef ProgramCollection<GlslSource> SourceCollections;
172
173
174 class Context
175 {
176 public:
Context(deqp::Context & deqpCtx)177 Context (deqp::Context& deqpCtx)
178 : m_deqpCtx(deqpCtx)
179 , m_sourceCollection()
180 , m_glslVersion(glu::getContextTypeGLSLVersion(m_deqpCtx.getRenderContext().getType()))
181 , m_shaderType(SHADER_TYPE_GLSL)
182 {}
~Context(void)183 ~Context (void) {}
getDeqpContext(void) const184 deqp::Context& getDeqpContext (void) const { return m_deqpCtx; }
getSourceCollection(void)185 SourceCollections& getSourceCollection (void) { return m_sourceCollection; }
getGLSLVersion(void)186 glu::GLSLVersion getGLSLVersion (void) { return m_glslVersion; }
getShaderType(void)187 ShaderType getShaderType (void) { return m_shaderType; }
setShaderType(ShaderType type)188 void setShaderType (ShaderType type) { m_shaderType = type; }
189
190 protected:
191 deqp::Context& m_deqpCtx;
192 SourceCollections m_sourceCollection;
193 glu::GLSLVersion m_glslVersion;
194 ShaderType m_shaderType;
195 };
196
197 namespace subgroups
198 {
199
200 template<typename Arg0>
201 class SubgroupFactory : public deqp::TestCase
202 {
203 public:
204 //void initPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
205 typedef void (*InitFunction)(SourceCollections& programCollection, Arg0 arg0);
206 //void supportedCheck (Context& context, CaseDefinition caseDef)
207 typedef void (*SupportFunction)(Context& context, Arg0 arg0);
208 //tcu::TestStatus test(Context& context, const CaseDefinition caseDef)
209 typedef tcu::TestStatus (*TestFunction)(Context& context, const Arg0 arg0);
210
211 /* Public methods */
SubgroupFactory(deqp::Context & context,tcu::TestNodeType type,const std::string & name,const std::string & desc,SupportFunction suppFunc,InitFunction initFunc,TestFunction testFunc,Arg0 arg0)212 SubgroupFactory(deqp::Context& context, tcu::TestNodeType type, const std::string& name, const std::string& desc,
213 SupportFunction suppFunc, InitFunction initFunc, TestFunction testFunc, Arg0 arg0)
214 : TestCase(context, type, name.c_str(), desc.c_str())
215 , m_supportedFunc(suppFunc)
216 , m_initFunc(initFunc)
217 , m_testFunc(testFunc)
218 , m_arg0(arg0)
219 , m_glcContext(m_context)
220 {}
221
init()222 void init()
223 {
224 m_supportedFunc(m_glcContext, m_arg0);
225
226 m_initFunc(m_glcContext.getSourceCollection(), m_arg0);
227 }
228
deinit()229 void deinit()
230 {
231 // nothing to do
232 }
233
iterate()234 tcu::TestNode::IterateResult iterate()
235 {
236 DE_ASSERT(m_testFunc);
237 tcu::TestLog& log = m_testCtx.getLog();
238
239 try {
240 // do SPIRV version of tests if supported
241 log << tcu::TestLog::Message << "SPIRV pass beginning..." << tcu::TestLog::EndMessage;
242 spirvUtils::checkGlSpirvSupported(m_glcContext.getDeqpContext());
243
244 m_glcContext.setShaderType(SHADER_TYPE_SPIRV);
245
246 const tcu::TestStatus result = m_testFunc(m_glcContext, m_arg0);
247 if (result.isComplete())
248 {
249 DE_ASSERT(m_testCtx.getTestResult() == QP_TEST_RESULT_LAST);
250 if (result.getCode() == QP_TEST_RESULT_PASS)
251 {
252 log << tcu::TestLog::Message << "SPIRV pass completed successfully ("
253 << result.getDescription() << ")." << tcu::TestLog::EndMessage;
254 } else {
255 // test failed - log result and stop
256 m_testCtx.setTestResult(result.getCode(), result.getDescription().c_str());
257 return tcu::TestNode::STOP;
258 }
259 }
260 } catch(tcu::NotSupportedError& e)
261 {
262 log << tcu::TestLog::Message << "SPIRV pass skipped ("
263 << e.getMessage() << ")." << tcu::TestLog::EndMessage;
264 }
265
266 // do GLSL version of the tests
267 log << tcu::TestLog::Message << "GLSL pass beginning..." << tcu::TestLog::EndMessage;
268 m_glcContext.setShaderType(SHADER_TYPE_GLSL);
269 const tcu::TestStatus result = m_testFunc(m_glcContext, m_arg0);
270
271 if (result.isComplete())
272 {
273 DE_ASSERT(m_testCtx.getTestResult() == QP_TEST_RESULT_LAST);
274 log << tcu::TestLog::Message << "GLSL pass completed successfully ("
275 << result.getDescription() << ")." << tcu::TestLog::EndMessage;
276 m_testCtx.setTestResult(result.getCode(), result.getDescription().c_str());
277 return tcu::TestNode::STOP;
278 }
279
280 return tcu::TestNode::CONTINUE;
281 }
282
addFunctionCaseWithPrograms(deqp::TestCaseGroup * group,const std::string & name,const std::string & desc,SupportFunction suppFunc,InitFunction initFunc,TestFunction testFunc,Arg0 arg0)283 static void addFunctionCaseWithPrograms (deqp::TestCaseGroup* group,
284 const std::string& name,
285 const std::string& desc,
286 SupportFunction suppFunc,
287 InitFunction initFunc,
288 TestFunction testFunc,
289 Arg0 arg0)
290 {
291 group->addChild(new SubgroupFactory(group->getContext(), tcu::NODETYPE_SELF_VALIDATE, name, desc, suppFunc, initFunc, testFunc, arg0));
292 }
293
294 private:
295 SupportFunction m_supportedFunc;
296 InitFunction m_initFunc;
297 TestFunction m_testFunc;
298 Arg0 m_arg0;
299
300 Context m_glcContext;
301 };
302
303
304 typedef enum ShaderStageFlags
305 {
306 SHADER_STAGE_VERTEX_BIT = GL_VERTEX_SHADER_BIT,
307 SHADER_STAGE_FRAGMENT_BIT = GL_FRAGMENT_SHADER_BIT,
308 SHADER_STAGE_GEOMETRY_BIT = GL_GEOMETRY_SHADER_BIT,
309 SHADER_STAGE_TESS_CONTROL_BIT = GL_TESS_CONTROL_SHADER_BIT,
310 SHADER_STAGE_TESS_EVALUATION_BIT = GL_TESS_EVALUATION_SHADER_BIT,
311 SHADER_STAGE_COMPUTE_BIT = GL_COMPUTE_SHADER_BIT,
312 SHADER_STAGE_ALL_GRAPHICS = (SHADER_STAGE_VERTEX_BIT | SHADER_STAGE_FRAGMENT_BIT | SHADER_STAGE_GEOMETRY_BIT |
313 SHADER_STAGE_TESS_CONTROL_BIT | SHADER_STAGE_TESS_EVALUATION_BIT ),
314 SHADER_STAGE_ALL_VALID = (SHADER_STAGE_ALL_GRAPHICS | SHADER_STAGE_COMPUTE_BIT),
315 } ShaderStageFlags;
316
317 typedef enum SubgroupFeatureFlags
318 {
319 SUBGROUP_FEATURE_BASIC_BIT = GL_SUBGROUP_FEATURE_BASIC_BIT_KHR,
320 SUBGROUP_FEATURE_VOTE_BIT = GL_SUBGROUP_FEATURE_VOTE_BIT_KHR,
321 SUBGROUP_FEATURE_ARITHMETIC_BIT = GL_SUBGROUP_FEATURE_ARITHMETIC_BIT_KHR,
322 SUBGROUP_FEATURE_BALLOT_BIT = GL_SUBGROUP_FEATURE_BALLOT_BIT_KHR,
323 SUBGROUP_FEATURE_SHUFFLE_BIT = GL_SUBGROUP_FEATURE_SHUFFLE_BIT_KHR,
324 SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = GL_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT_KHR,
325 SUBGROUP_FEATURE_CLUSTERED_BIT = GL_SUBGROUP_FEATURE_CLUSTERED_BIT_KHR,
326 SUBGROUP_FEATURE_QUAD_BIT = GL_SUBGROUP_FEATURE_QUAD_BIT_KHR,
327 SUBGROUP_FEATURE_PARTITIONED_BIT_NV = GL_SUBGROUP_FEATURE_PARTITIONED_BIT_NV,
328 SUBGROUP_FEATURE_ALL_VALID = (SUBGROUP_FEATURE_BASIC_BIT | SUBGROUP_FEATURE_VOTE_BIT | SUBGROUP_FEATURE_ARITHMETIC_BIT |
329 SUBGROUP_FEATURE_BALLOT_BIT | SUBGROUP_FEATURE_SHUFFLE_BIT | SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT |
330 SUBGROUP_FEATURE_CLUSTERED_BIT | SUBGROUP_FEATURE_QUAD_BIT | SUBGROUP_FEATURE_PARTITIONED_BIT_NV),
331 } SubgroupFeatureFlags;
332
333 typedef enum Format
334 {
335 FORMAT_UNDEFINED = 0,
336 FORMAT_R32_SINT = GL_R32I,
337 FORMAT_R32_UINT = GL_R32UI,
338 FORMAT_R32G32_SINT = GL_RG32I,
339 FORMAT_R32G32_UINT = GL_RG32UI,
340 FORMAT_R32G32B32_SINT = GL_RGB32I,
341 FORMAT_R32G32B32_UINT = GL_RGB32UI,
342 FORMAT_R32G32B32A32_SINT = GL_RGBA32I,
343 FORMAT_R32G32B32A32_UINT = GL_RGBA32UI,
344 FORMAT_R32_SFLOAT = GL_R32F,
345 FORMAT_R32G32_SFLOAT = GL_RG32F,
346 FORMAT_R32G32B32_SFLOAT = GL_RGB32F,
347 FORMAT_R32G32B32A32_SFLOAT = GL_RGBA32F,
348 FORMAT_R64_SFLOAT = 0x6000,
349 FORMAT_R64G64_SFLOAT,
350 FORMAT_R64G64B64_SFLOAT,
351 FORMAT_R64G64B64A64_SFLOAT,
352 FORMAT_R32_BOOL = 0x6100,
353 FORMAT_R32G32_BOOL,
354 FORMAT_R32G32B32_BOOL,
355 FORMAT_R32G32B32A32_BOOL,
356 } Format;
357
358 typedef enum DescriptorType
359 {
360 DESCRIPTOR_TYPE_UNIFORM_BUFFER = GL_UNIFORM_BUFFER,
361 DESCRIPTOR_TYPE_STORAGE_BUFFER = GL_SHADER_STORAGE_BUFFER,
362 DESCRIPTOR_TYPE_STORAGE_IMAGE = GL_TEXTURE_2D,
363 } DescriptorType;
364
365 // A struct to represent input data to a shader
366 struct SSBOData
367 {
SSBODataglc::subgroups::SSBOData368 SSBOData() :
369 initializeType (InitializeNone),
370 layout (LayoutStd140),
371 format (FORMAT_UNDEFINED),
372 numElements (0),
373 isImage (false),
374 binding (0u),
375 stages ((ShaderStageFlags)0u)
376 {}
377
378 enum InputDataInitializeType
379 {
380 InitializeNone = 0,
381 InitializeNonZero,
382 InitializeZero,
383 } initializeType;
384
385 enum InputDataLayoutType
386 {
387 LayoutStd140 = 0,
388 LayoutStd430,
389 LayoutPacked,
390 } layout;
391
392 Format format;
393 deUint64 numElements;
394 bool isImage;
395 deUint32 binding;
396 ShaderStageFlags stages;
397 };
398
399 std::string getSharedMemoryBallotHelper();
400
401 deUint32 getSubgroupSize(Context& context);
402
403 deUint32 maxSupportedSubgroupSize();
404
405 std::string getShaderStageName(ShaderStageFlags stage);
406
407 std::string getSubgroupFeatureName(SubgroupFeatureFlags bit);
408
409 void addNoSubgroupShader (SourceCollections& programCollection);
410
411 std::string getVertShaderForStage(ShaderStageFlags stage);
412
413 bool isSubgroupSupported(Context& context);
414
415 bool areSubgroupOperationsSupportedForStage(
416 Context& context, ShaderStageFlags stage);
417
418 bool areSubgroupOperationsRequiredForStage(ShaderStageFlags stage);
419
420 bool isSubgroupFeatureSupportedForDevice(Context& context, SubgroupFeatureFlags bit);
421
422 bool isFragmentSSBOSupportedForDevice(Context& context);
423
424 bool isVertexSSBOSupportedForDevice(Context& context);
425
426 bool isImageSupportedForStageOnDevice(Context& context, const ShaderStageFlags stage);
427
428 bool isDoubleSupportedForDevice(Context& context);
429
430 bool isDoubleFormat(Format format);
431
432 std::string getFormatNameForGLSL(Format format);
433
434 void addGeometryShadersFromTemplate (const std::string& glslTemplate, SourceCollections& collection);
435
436 void setVertexShaderFrameBuffer (SourceCollections& programCollection);
437
438 void setFragmentShaderFrameBuffer (SourceCollections& programCollection);
439
440 void setFragmentShaderFrameBuffer (SourceCollections& programCollection);
441
442 void setTesCtrlShaderFrameBuffer (SourceCollections& programCollection);
443
444 void setTesEvalShaderFrameBuffer (SourceCollections& programCollection);
445
446 bool check(std::vector<const void*> datas,
447 deUint32 width, deUint32 ref);
448
449 bool checkCompute(std::vector<const void*> datas,
450 const deUint32 numWorkgroups[3], const deUint32 localSize[3],
451 deUint32 ref);
452
453 tcu::TestStatus makeTessellationEvaluationFrameBufferTest(Context& context, Format format,
454 SSBOData* extraData, deUint32 extraDataCount,
455 bool (*checkResult)(std::vector<const void*> datas, deUint32 width, deUint32 subgroupSize),
456 const ShaderStageFlags shaderStage = SHADER_STAGE_ALL_GRAPHICS);
457
458 tcu::TestStatus makeGeometryFrameBufferTest(Context& context, Format format, SSBOData* extraData,
459 deUint32 extraDataCount,
460 bool (*checkResult)(std::vector<const void*> datas, deUint32 width, deUint32 subgroupSize));
461
462 tcu::TestStatus allStages(Context& context, Format format,
463 SSBOData* extraData, deUint32 extraDataCount,
464 bool (*checkResult)(std::vector<const void*> datas, deUint32 width, deUint32 subgroupSize),
465 const ShaderStageFlags shaderStage);
466
467 tcu::TestStatus makeVertexFrameBufferTest(Context& context, Format format,
468 SSBOData* extraData, deUint32 extraDataCount,
469 bool (*checkResult)(std::vector<const void*> datas, deUint32 width, deUint32 subgroupSize));
470
471 tcu::TestStatus makeFragmentFrameBufferTest(Context& context, Format format,
472 SSBOData* extraData, deUint32 extraDataCount,
473 bool (*checkResult)(std::vector<const void*> datas, deUint32 width,
474 deUint32 height, deUint32 subgroupSize));
475
476 tcu::TestStatus makeComputeTest(
477 Context& context, Format format, SSBOData* inputs,
478 deUint32 inputsCount,
479 bool (*checkResult)(std::vector<const void*> datas,
480 const deUint32 numWorkgroups[3], const deUint32 localSize[3],
481 deUint32 subgroupSize));
482 } // subgroups
483 } // glc
484
485 #endif // _GLCSUBGROUPSTESTSUTILS_HPP
486