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 {
85 }
86
operator ++(void)87 Iterator &operator++(void)
88 {
89 ++m_impl;
90 return *this;
91 }
operator *(void) const92 const Program &operator*(void) const
93 {
94 return getProgram();
95 }
96
getName(void) const97 const std::string &getName(void) const
98 {
99 return m_impl->first;
100 }
getProgram(void) const101 const Program &getProgram(void) const
102 {
103 return *m_impl->second;
104 }
105
operator ==(const Iterator & other) const106 bool operator==(const Iterator &other) const
107 {
108 return m_impl == other.m_impl;
109 }
operator !=(const Iterator & other) const110 bool operator!=(const Iterator &other) const
111 {
112 return m_impl != other.m_impl;
113 }
114
115 private:
116 IteratorImpl m_impl;
117 };
118
begin(void) const119 Iterator begin(void) const
120 {
121 return Iterator(m_programs.begin());
122 }
end(void) const123 Iterator end(void) const
124 {
125 return Iterator(m_programs.end());
126 }
127
empty(void) const128 bool empty(void) const
129 {
130 return m_programs.empty();
131 }
132
133 private:
134 typedef std::map<std::string, Program *> ProgramMap;
135
136 ProgramMap m_programs;
137 };
138
139 template <typename Program>
ProgramCollection(void)140 ProgramCollection<Program>::ProgramCollection(void)
141 {
142 }
143
144 template <typename Program>
~ProgramCollection(void)145 ProgramCollection<Program>::~ProgramCollection(void)
146 {
147 clear();
148 }
149
150 template <typename Program>
clear(void)151 void ProgramCollection<Program>::clear(void)
152 {
153 for (typename ProgramMap::const_iterator i = m_programs.begin(); i != m_programs.end(); ++i)
154 delete i->second;
155 m_programs.clear();
156 }
157
158 template <typename Program>
add(const std::string & name)159 Program &ProgramCollection<Program>::add(const std::string &name)
160 {
161 DE_ASSERT(!contains(name));
162 de::MovePtr<Program> prog = de::newMovePtr<Program>();
163 m_programs[name] = prog.get();
164 prog.release();
165 return *m_programs[name];
166 }
167
168 template <typename Program>
add(const std::string & name,de::MovePtr<Program> & program)169 void ProgramCollection<Program>::add(const std::string &name, de::MovePtr<Program> &program)
170 {
171 DE_ASSERT(!contains(name));
172 m_programs[name] = program.get();
173 program.release();
174 }
175
176 template <typename Program>
contains(const std::string & name) const177 bool ProgramCollection<Program>::contains(const std::string &name) const
178 {
179 return de::contains(m_programs, name);
180 }
181
182 template <typename Program>
get(const std::string & name) const183 const Program &ProgramCollection<Program>::get(const std::string &name) const
184 {
185 DE_ASSERT(contains(name));
186 return *m_programs.find(name)->second;
187 }
188
189 struct GlslSource
190 {
191 std::vector<std::string> sources[glu::SHADERTYPE_LAST];
192
operator <<glc::GlslSource193 GlslSource &operator<<(const glu::ShaderSource &shaderSource)
194 {
195 sources[shaderSource.shaderType].push_back(shaderSource.source);
196 return *this;
197 }
198 };
199
200 typedef ProgramCollection<GlslSource> SourceCollections;
201
202 class Context
203 {
204 public:
Context(deqp::Context & deqpCtx)205 Context(deqp::Context &deqpCtx)
206 : m_deqpCtx(deqpCtx)
207 , m_sourceCollection()
208 , m_glslVersion(glu::getContextTypeGLSLVersion(m_deqpCtx.getRenderContext().getType()))
209 , m_shaderType(SHADER_TYPE_GLSL)
210 {
211 }
~Context(void)212 ~Context(void)
213 {
214 }
getDeqpContext(void) const215 deqp::Context &getDeqpContext(void) const
216 {
217 return m_deqpCtx;
218 }
getSourceCollection(void)219 SourceCollections &getSourceCollection(void)
220 {
221 return m_sourceCollection;
222 }
getGLSLVersion(void)223 glu::GLSLVersion getGLSLVersion(void)
224 {
225 return m_glslVersion;
226 }
getShaderType(void)227 ShaderType getShaderType(void)
228 {
229 return m_shaderType;
230 }
setShaderType(ShaderType type)231 void setShaderType(ShaderType type)
232 {
233 m_shaderType = type;
234 }
235
236 protected:
237 deqp::Context &m_deqpCtx;
238 SourceCollections m_sourceCollection;
239 glu::GLSLVersion m_glslVersion;
240 ShaderType m_shaderType;
241 };
242
243 namespace subgroups
244 {
245
246 template <typename Arg0>
247 class SubgroupFactory : public deqp::TestCase
248 {
249 public:
250 //void initPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
251 typedef void (*InitFunction)(SourceCollections &programCollection, Arg0 arg0);
252 //void supportedCheck (Context& context, CaseDefinition caseDef)
253 typedef void (*SupportFunction)(Context &context, Arg0 arg0);
254 //tcu::TestStatus test(Context& context, const CaseDefinition caseDef)
255 typedef tcu::TestStatus (*TestFunction)(Context &context, const Arg0 arg0);
256
257 /* 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)258 SubgroupFactory(deqp::Context &context, tcu::TestNodeType type, const std::string &name, const std::string &desc,
259 SupportFunction suppFunc, InitFunction initFunc, TestFunction testFunc, Arg0 arg0)
260 : TestCase(context, type, name.c_str(), desc.c_str())
261 , m_supportedFunc(suppFunc)
262 , m_initFunc(initFunc)
263 , m_testFunc(testFunc)
264 , m_arg0(arg0)
265 , m_glcContext(m_context)
266 {
267 }
268
init()269 void init()
270 {
271 m_supportedFunc(m_glcContext, m_arg0);
272
273 m_initFunc(m_glcContext.getSourceCollection(), m_arg0);
274 }
275
deinit()276 void deinit()
277 {
278 // nothing to do
279 }
280
iterate()281 tcu::TestNode::IterateResult iterate()
282 {
283 DE_ASSERT(m_testFunc);
284 tcu::TestLog &log = m_testCtx.getLog();
285
286 try
287 {
288 // do SPIRV version of tests if supported
289 log << tcu::TestLog::Message << "SPIRV pass beginning..." << tcu::TestLog::EndMessage;
290 spirvUtils::checkGlSpirvSupported(m_glcContext.getDeqpContext());
291
292 m_glcContext.setShaderType(SHADER_TYPE_SPIRV);
293
294 const tcu::TestStatus result = m_testFunc(m_glcContext, m_arg0);
295 if (result.isComplete())
296 {
297 DE_ASSERT(m_testCtx.getTestResult() == QP_TEST_RESULT_LAST);
298 if (result.getCode() == QP_TEST_RESULT_PASS)
299 {
300 log << tcu::TestLog::Message << "SPIRV pass completed successfully (" << result.getDescription()
301 << ")." << tcu::TestLog::EndMessage;
302 }
303 else
304 {
305 // test failed - log result and stop
306 m_testCtx.setTestResult(result.getCode(), result.getDescription().c_str());
307 return tcu::TestNode::STOP;
308 }
309 }
310 }
311 catch (tcu::NotSupportedError &e)
312 {
313 log << tcu::TestLog::Message << "SPIRV pass skipped (" << e.getMessage() << ")."
314 << tcu::TestLog::EndMessage;
315 }
316
317 // do GLSL version of the tests
318 log << tcu::TestLog::Message << "GLSL pass beginning..." << tcu::TestLog::EndMessage;
319 m_glcContext.setShaderType(SHADER_TYPE_GLSL);
320 const tcu::TestStatus result = m_testFunc(m_glcContext, m_arg0);
321
322 if (result.isComplete())
323 {
324 DE_ASSERT(m_testCtx.getTestResult() == QP_TEST_RESULT_LAST);
325 log << tcu::TestLog::Message << "GLSL pass completed successfully (" << result.getDescription() << ")."
326 << tcu::TestLog::EndMessage;
327 m_testCtx.setTestResult(result.getCode(), result.getDescription().c_str());
328 return tcu::TestNode::STOP;
329 }
330
331 return tcu::TestNode::CONTINUE;
332 }
333
addFunctionCaseWithPrograms(deqp::TestCaseGroup * group,const std::string & name,const std::string & desc,SupportFunction suppFunc,InitFunction initFunc,TestFunction testFunc,Arg0 arg0)334 static void addFunctionCaseWithPrograms(deqp::TestCaseGroup *group, const std::string &name,
335 const std::string &desc, SupportFunction suppFunc, InitFunction initFunc,
336 TestFunction testFunc, Arg0 arg0)
337 {
338 group->addChild(new SubgroupFactory(group->getContext(), tcu::NODETYPE_SELF_VALIDATE, name, desc, suppFunc,
339 initFunc, testFunc, arg0));
340 }
341
342 private:
343 SupportFunction m_supportedFunc;
344 InitFunction m_initFunc;
345 TestFunction m_testFunc;
346 Arg0 m_arg0;
347
348 Context m_glcContext;
349 };
350
351 typedef enum ShaderStageFlags
352 {
353 SHADER_STAGE_VERTEX_BIT = GL_VERTEX_SHADER_BIT,
354 SHADER_STAGE_FRAGMENT_BIT = GL_FRAGMENT_SHADER_BIT,
355 SHADER_STAGE_GEOMETRY_BIT = GL_GEOMETRY_SHADER_BIT,
356 SHADER_STAGE_TESS_CONTROL_BIT = GL_TESS_CONTROL_SHADER_BIT,
357 SHADER_STAGE_TESS_EVALUATION_BIT = GL_TESS_EVALUATION_SHADER_BIT,
358 SHADER_STAGE_COMPUTE_BIT = GL_COMPUTE_SHADER_BIT,
359 SHADER_STAGE_ALL_GRAPHICS = (SHADER_STAGE_VERTEX_BIT | SHADER_STAGE_FRAGMENT_BIT | SHADER_STAGE_GEOMETRY_BIT |
360 SHADER_STAGE_TESS_CONTROL_BIT | SHADER_STAGE_TESS_EVALUATION_BIT),
361 SHADER_STAGE_ALL_VALID = (SHADER_STAGE_ALL_GRAPHICS | SHADER_STAGE_COMPUTE_BIT),
362 } ShaderStageFlags;
363
364 typedef enum SubgroupFeatureFlags
365 {
366 SUBGROUP_FEATURE_BASIC_BIT = GL_SUBGROUP_FEATURE_BASIC_BIT_KHR,
367 SUBGROUP_FEATURE_VOTE_BIT = GL_SUBGROUP_FEATURE_VOTE_BIT_KHR,
368 SUBGROUP_FEATURE_ARITHMETIC_BIT = GL_SUBGROUP_FEATURE_ARITHMETIC_BIT_KHR,
369 SUBGROUP_FEATURE_BALLOT_BIT = GL_SUBGROUP_FEATURE_BALLOT_BIT_KHR,
370 SUBGROUP_FEATURE_SHUFFLE_BIT = GL_SUBGROUP_FEATURE_SHUFFLE_BIT_KHR,
371 SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = GL_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT_KHR,
372 SUBGROUP_FEATURE_CLUSTERED_BIT = GL_SUBGROUP_FEATURE_CLUSTERED_BIT_KHR,
373 SUBGROUP_FEATURE_QUAD_BIT = GL_SUBGROUP_FEATURE_QUAD_BIT_KHR,
374 SUBGROUP_FEATURE_PARTITIONED_BIT_NV = GL_SUBGROUP_FEATURE_PARTITIONED_BIT_NV,
375 SUBGROUP_FEATURE_ALL_VALID =
376 (SUBGROUP_FEATURE_BASIC_BIT | SUBGROUP_FEATURE_VOTE_BIT | SUBGROUP_FEATURE_ARITHMETIC_BIT |
377 SUBGROUP_FEATURE_BALLOT_BIT | SUBGROUP_FEATURE_SHUFFLE_BIT | SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT |
378 SUBGROUP_FEATURE_CLUSTERED_BIT | SUBGROUP_FEATURE_QUAD_BIT | SUBGROUP_FEATURE_PARTITIONED_BIT_NV),
379 } SubgroupFeatureFlags;
380
381 typedef enum Format
382 {
383 FORMAT_UNDEFINED = 0,
384 FORMAT_R32_SINT = GL_R32I,
385 FORMAT_R32_UINT = GL_R32UI,
386 FORMAT_R32G32_SINT = GL_RG32I,
387 FORMAT_R32G32_UINT = GL_RG32UI,
388 FORMAT_R32G32B32_SINT = GL_RGB32I,
389 FORMAT_R32G32B32_UINT = GL_RGB32UI,
390 FORMAT_R32G32B32A32_SINT = GL_RGBA32I,
391 FORMAT_R32G32B32A32_UINT = GL_RGBA32UI,
392 FORMAT_R32_SFLOAT = GL_R32F,
393 FORMAT_R32G32_SFLOAT = GL_RG32F,
394 FORMAT_R32G32B32_SFLOAT = GL_RGB32F,
395 FORMAT_R32G32B32A32_SFLOAT = GL_RGBA32F,
396 FORMAT_R64_SFLOAT = 0x6000,
397 FORMAT_R64G64_SFLOAT,
398 FORMAT_R64G64B64_SFLOAT,
399 FORMAT_R64G64B64A64_SFLOAT,
400 FORMAT_R32_BOOL = 0x6100,
401 FORMAT_R32G32_BOOL,
402 FORMAT_R32G32B32_BOOL,
403 FORMAT_R32G32B32A32_BOOL,
404 } Format;
405
406 typedef enum DescriptorType
407 {
408 DESCRIPTOR_TYPE_UNIFORM_BUFFER = GL_UNIFORM_BUFFER,
409 DESCRIPTOR_TYPE_STORAGE_BUFFER = GL_SHADER_STORAGE_BUFFER,
410 DESCRIPTOR_TYPE_STORAGE_IMAGE = GL_TEXTURE_2D,
411 } DescriptorType;
412
413 // A struct to represent input data to a shader
414 struct SSBOData
415 {
SSBODataglc::subgroups::SSBOData416 SSBOData()
417 : initializeType(InitializeNone)
418 , layout(LayoutStd140)
419 , format(FORMAT_UNDEFINED)
420 , numElements(0)
421 , isImage(false)
422 , binding(0u)
423 , stages((ShaderStageFlags)0u)
424 {
425 }
426
427 enum InputDataInitializeType
428 {
429 InitializeNone = 0,
430 InitializeNonZero,
431 InitializeZero,
432 } initializeType;
433
434 enum InputDataLayoutType
435 {
436 LayoutStd140 = 0,
437 LayoutStd430,
438 LayoutPacked,
439 } layout;
440
441 Format format;
442 uint64_t numElements;
443 bool isImage;
444 uint32_t binding;
445 ShaderStageFlags stages;
446 };
447
448 std::string getSharedMemoryBallotHelper();
449
450 uint32_t getSubgroupSize(Context &context);
451
452 uint32_t maxSupportedSubgroupSize();
453
454 std::string getShaderStageName(ShaderStageFlags stage);
455
456 std::string getSubgroupFeatureName(SubgroupFeatureFlags bit);
457
458 void addNoSubgroupShader(SourceCollections &programCollection);
459
460 std::string getVertShaderForStage(ShaderStageFlags stage);
461
462 bool isSubgroupSupported(Context &context);
463
464 bool areSubgroupOperationsSupportedForStage(Context &context, ShaderStageFlags stage);
465
466 bool areSubgroupOperationsRequiredForStage(ShaderStageFlags stage);
467
468 bool isSubgroupFeatureSupportedForDevice(Context &context, SubgroupFeatureFlags bit);
469
470 bool isFragmentSSBOSupportedForDevice(Context &context);
471
472 bool isVertexSSBOSupportedForDevice(Context &context);
473
474 bool isImageSupportedForStageOnDevice(Context &context, const ShaderStageFlags stage);
475
476 bool isDoubleSupportedForDevice(Context &context);
477
478 bool isDoubleFormat(Format format);
479
480 std::string getFormatNameForGLSL(Format format);
481
482 void addGeometryShadersFromTemplate(const std::string &glslTemplate, SourceCollections &collection);
483
484 void setVertexShaderFrameBuffer(SourceCollections &programCollection);
485
486 void setFragmentShaderFrameBuffer(SourceCollections &programCollection);
487
488 void setFragmentShaderFrameBuffer(SourceCollections &programCollection);
489
490 void setTesCtrlShaderFrameBuffer(SourceCollections &programCollection);
491
492 void setTesEvalShaderFrameBuffer(SourceCollections &programCollection);
493
494 bool check(std::vector<const void *> datas, uint32_t width, uint32_t ref);
495
496 bool checkCompute(std::vector<const void *> datas, const uint32_t numWorkgroups[3], const uint32_t localSize[3],
497 uint32_t ref);
498
499 tcu::TestStatus makeTessellationEvaluationFrameBufferTest(
500 Context &context, Format format, SSBOData *extraData, uint32_t extraDataCount,
501 bool (*checkResult)(std::vector<const void *> datas, uint32_t width, uint32_t subgroupSize),
502 const ShaderStageFlags shaderStage = SHADER_STAGE_ALL_GRAPHICS);
503
504 tcu::TestStatus makeGeometryFrameBufferTest(Context &context, Format format, SSBOData *extraData,
505 uint32_t extraDataCount,
506 bool (*checkResult)(std::vector<const void *> datas, uint32_t width,
507 uint32_t subgroupSize));
508
509 tcu::TestStatus allStages(Context &context, Format format, SSBOData *extraData, uint32_t extraDataCount,
510 bool (*checkResult)(std::vector<const void *> datas, uint32_t width, uint32_t subgroupSize),
511 const ShaderStageFlags shaderStage);
512
513 tcu::TestStatus makeVertexFrameBufferTest(Context &context, Format format, SSBOData *extraData, uint32_t extraDataCount,
514 bool (*checkResult)(std::vector<const void *> datas, uint32_t width,
515 uint32_t subgroupSize));
516
517 tcu::TestStatus makeFragmentFrameBufferTest(Context &context, Format format, SSBOData *extraData,
518 uint32_t extraDataCount,
519 bool (*checkResult)(std::vector<const void *> datas, uint32_t width,
520 uint32_t height, uint32_t subgroupSize));
521
522 tcu::TestStatus makeComputeTest(Context &context, Format format, SSBOData *inputs, uint32_t inputsCount,
523 bool (*checkResult)(std::vector<const void *> datas, const uint32_t numWorkgroups[3],
524 const uint32_t localSize[3], uint32_t subgroupSize));
525 } // namespace subgroups
526 } // namespace glc
527
528 #endif // _GLCSUBGROUPSTESTSUTILS_HPP
529