blob: 19d1d04c9fd4f17b3fe0a1297b48afa59cf30576 [file] [log] [blame]
#ifndef _GLCSUBGROUPSTESTSUTILS_HPP
#define _GLCSUBGROUPSTESTSUTILS_HPP
/*------------------------------------------------------------------------
* OpenGL Conformance Tests
* ------------------------
*
* Copyright (c) 2017-2019 The Khronos Group Inc.
* Copyright (c) 2017 Codeplay Software Ltd.
* Copyright (c) 2019 NVIDIA Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/ /*!
* \file
* \brief Subgroups tests utility classes
*/ /*--------------------------------------------------------------------*/
#include "deDefs.hpp"
#include "deSTLUtil.hpp"
#include "deStringUtil.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include "glwDefs.hpp"
#include "tcuDefs.hpp"
#include "tcuTestCase.hpp"
#include "glcTestCase.hpp"
#include "glcSpirvUtils.hpp"
#include "tcuFormatUtil.hpp"
#include "tcuTestLog.hpp"
#include "tcuVectorUtil.hpp"
#include "gluShaderUtil.hpp"
#include "gluContextInfo.hpp"
#include "deSharedPtr.hpp"
#include "deUniquePtr.hpp"
#include <string>
namespace glc
{
enum ShaderType
{
SHADER_TYPE_GLSL = 0,
SHADER_TYPE_SPIRV,
SHADER_TYPE_LAST
};
template<typename Program>
class ProgramCollection
{
public:
ProgramCollection (void);
~ProgramCollection (void);
void clear (void);
Program& add (const std::string& name);
void add (const std::string& name, de::MovePtr<Program>& program);
bool contains (const std::string& name) const;
const Program& get (const std::string& name) const;
class Iterator
{
private:
typedef typename std::map<std::string, Program*>::const_iterator IteratorImpl;
public:
explicit Iterator (const IteratorImpl& i) : m_impl(i) {}
Iterator& operator++ (void) { ++m_impl; return *this; }
const Program& operator* (void) const { return getProgram(); }
const std::string& getName (void) const { return m_impl->first; }
const Program& getProgram (void) const { return *m_impl->second; }
bool operator== (const Iterator& other) const { return m_impl == other.m_impl; }
bool operator!= (const Iterator& other) const { return m_impl != other.m_impl; }
private:
IteratorImpl m_impl;
};
Iterator begin (void) const { return Iterator(m_programs.begin()); }
Iterator end (void) const { return Iterator(m_programs.end()); }
bool empty (void) const { return m_programs.empty(); }
private:
typedef std::map<std::string, Program*> ProgramMap;
ProgramMap m_programs;
};
template<typename Program>
ProgramCollection<Program>::ProgramCollection (void)
{
}
template<typename Program>
ProgramCollection<Program>::~ProgramCollection (void)
{
clear();
}
template<typename Program>
void ProgramCollection<Program>::clear (void)
{
for (typename ProgramMap::const_iterator i = m_programs.begin(); i != m_programs.end(); ++i)
delete i->second;
m_programs.clear();
}
template<typename Program>
Program& ProgramCollection<Program>::add (const std::string& name)
{
DE_ASSERT(!contains(name));
de::MovePtr<Program> prog = de::newMovePtr<Program>();
m_programs[name] = prog.get();
prog.release();
return *m_programs[name];
}
template<typename Program>
void ProgramCollection<Program>::add (const std::string& name, de::MovePtr<Program>& program)
{
DE_ASSERT(!contains(name));
m_programs[name] = program.get();
program.release();
}
template<typename Program>
bool ProgramCollection<Program>::contains (const std::string& name) const
{
return de::contains(m_programs, name);
}
template<typename Program>
const Program& ProgramCollection<Program>::get (const std::string& name) const
{
DE_ASSERT(contains(name));
return *m_programs.find(name)->second;
}
struct GlslSource
{
std::vector<std::string> sources[glu::SHADERTYPE_LAST];
GlslSource& operator<< (const glu::ShaderSource& shaderSource)
{
sources[shaderSource.shaderType].push_back(shaderSource.source);
return *this;
}
};
typedef ProgramCollection<GlslSource> SourceCollections;
class Context
{
public:
Context (deqp::Context& deqpCtx)
: m_deqpCtx(deqpCtx)
, m_sourceCollection()
, m_glslVersion(glu::getContextTypeGLSLVersion(m_deqpCtx.getRenderContext().getType()))
, m_shaderType(SHADER_TYPE_GLSL)
{}
~Context (void) {}
deqp::Context& getDeqpContext (void) const { return m_deqpCtx; }
SourceCollections& getSourceCollection (void) { return m_sourceCollection; }
glu::GLSLVersion getGLSLVersion (void) { return m_glslVersion; }
ShaderType getShaderType (void) { return m_shaderType; }
void setShaderType (ShaderType type) { m_shaderType = type; }
protected:
deqp::Context& m_deqpCtx;
SourceCollections m_sourceCollection;
glu::GLSLVersion m_glslVersion;
ShaderType m_shaderType;
};
namespace subgroups
{
template<typename Arg0>
class SubgroupFactory : public deqp::TestCase
{
public:
//void initPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
typedef void (*InitFunction)(SourceCollections& programCollection, Arg0 arg0);
//void supportedCheck (Context& context, CaseDefinition caseDef)
typedef void (*SupportFunction)(Context& context, Arg0 arg0);
//tcu::TestStatus test(Context& context, const CaseDefinition caseDef)
typedef tcu::TestStatus (*TestFunction)(Context& context, const Arg0 arg0);
/* 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)
: TestCase(context, type, name.c_str(), desc.c_str())
, m_supportedFunc(suppFunc)
, m_initFunc(initFunc)
, m_testFunc(testFunc)
, m_arg0(arg0)
, m_glcContext(m_context)
{}
void init()
{
m_supportedFunc(m_glcContext, m_arg0);
m_initFunc(m_glcContext.getSourceCollection(), m_arg0);
}
void deinit()
{
// nothing to do
}
tcu::TestNode::IterateResult iterate()
{
DE_ASSERT(m_testFunc);
tcu::TestLog& log = m_testCtx.getLog();
try {
// do SPIRV version of tests if supported
log << tcu::TestLog::Message << "SPIRV pass beginning..." << tcu::TestLog::EndMessage;
spirvUtils::checkGlSpirvSupported(m_glcContext.getDeqpContext());
m_glcContext.setShaderType(SHADER_TYPE_SPIRV);
const tcu::TestStatus result = m_testFunc(m_glcContext, m_arg0);
if (result.isComplete())
{
DE_ASSERT(m_testCtx.getTestResult() == QP_TEST_RESULT_LAST);
if (result.getCode() == QP_TEST_RESULT_PASS)
{
log << tcu::TestLog::Message << "SPIRV pass completed successfully ("
<< result.getDescription() << ")." << tcu::TestLog::EndMessage;
} else {
// test failed - log result and stop
m_testCtx.setTestResult(result.getCode(), result.getDescription().c_str());
return tcu::TestNode::STOP;
}
}
} catch(tcu::NotSupportedError& e)
{
log << tcu::TestLog::Message << "SPIRV pass skipped ("
<< e.getMessage() << ")." << tcu::TestLog::EndMessage;
}
// do GLSL version of the tests
log << tcu::TestLog::Message << "GLSL pass beginning..." << tcu::TestLog::EndMessage;
m_glcContext.setShaderType(SHADER_TYPE_GLSL);
const tcu::TestStatus result = m_testFunc(m_glcContext, m_arg0);
if (result.isComplete())
{
DE_ASSERT(m_testCtx.getTestResult() == QP_TEST_RESULT_LAST);
log << tcu::TestLog::Message << "GLSL pass completed successfully ("
<< result.getDescription() << ")." << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(result.getCode(), result.getDescription().c_str());
return tcu::TestNode::STOP;
}
return tcu::TestNode::CONTINUE;
}
static void addFunctionCaseWithPrograms (deqp::TestCaseGroup* group,
const std::string& name,
const std::string& desc,
SupportFunction suppFunc,
InitFunction initFunc,
TestFunction testFunc,
Arg0 arg0)
{
group->addChild(new SubgroupFactory(group->getContext(), tcu::NODETYPE_SELF_VALIDATE, name, desc, suppFunc, initFunc, testFunc, arg0));
}
private:
SupportFunction m_supportedFunc;
InitFunction m_initFunc;
TestFunction m_testFunc;
Arg0 m_arg0;
Context m_glcContext;
};
typedef enum ShaderStageFlags
{
SHADER_STAGE_VERTEX_BIT = GL_VERTEX_SHADER_BIT,
SHADER_STAGE_FRAGMENT_BIT = GL_FRAGMENT_SHADER_BIT,
SHADER_STAGE_GEOMETRY_BIT = GL_GEOMETRY_SHADER_BIT,
SHADER_STAGE_TESS_CONTROL_BIT = GL_TESS_CONTROL_SHADER_BIT,
SHADER_STAGE_TESS_EVALUATION_BIT = GL_TESS_EVALUATION_SHADER_BIT,
SHADER_STAGE_COMPUTE_BIT = GL_COMPUTE_SHADER_BIT,
SHADER_STAGE_ALL_GRAPHICS = (SHADER_STAGE_VERTEX_BIT | SHADER_STAGE_FRAGMENT_BIT | SHADER_STAGE_GEOMETRY_BIT |
SHADER_STAGE_TESS_CONTROL_BIT | SHADER_STAGE_TESS_EVALUATION_BIT ),
SHADER_STAGE_ALL_VALID = (SHADER_STAGE_ALL_GRAPHICS | SHADER_STAGE_COMPUTE_BIT),
} ShaderStageFlags;
typedef enum SubgroupFeatureFlags
{
SUBGROUP_FEATURE_BASIC_BIT = GL_SUBGROUP_FEATURE_BASIC_BIT_KHR,
SUBGROUP_FEATURE_VOTE_BIT = GL_SUBGROUP_FEATURE_VOTE_BIT_KHR,
SUBGROUP_FEATURE_ARITHMETIC_BIT = GL_SUBGROUP_FEATURE_ARITHMETIC_BIT_KHR,
SUBGROUP_FEATURE_BALLOT_BIT = GL_SUBGROUP_FEATURE_BALLOT_BIT_KHR,
SUBGROUP_FEATURE_SHUFFLE_BIT = GL_SUBGROUP_FEATURE_SHUFFLE_BIT_KHR,
SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = GL_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT_KHR,
SUBGROUP_FEATURE_CLUSTERED_BIT = GL_SUBGROUP_FEATURE_CLUSTERED_BIT_KHR,
SUBGROUP_FEATURE_QUAD_BIT = GL_SUBGROUP_FEATURE_QUAD_BIT_KHR,
SUBGROUP_FEATURE_PARTITIONED_BIT_NV = GL_SUBGROUP_FEATURE_PARTITIONED_BIT_NV,
SUBGROUP_FEATURE_ALL_VALID = (SUBGROUP_FEATURE_BASIC_BIT | SUBGROUP_FEATURE_VOTE_BIT | SUBGROUP_FEATURE_ARITHMETIC_BIT |
SUBGROUP_FEATURE_BALLOT_BIT | SUBGROUP_FEATURE_SHUFFLE_BIT | SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT |
SUBGROUP_FEATURE_CLUSTERED_BIT | SUBGROUP_FEATURE_QUAD_BIT | SUBGROUP_FEATURE_PARTITIONED_BIT_NV),
} SubgroupFeatureFlags;
typedef enum Format
{
FORMAT_UNDEFINED = 0,
FORMAT_R32_SINT = GL_R32I,
FORMAT_R32_UINT = GL_R32UI,
FORMAT_R32G32_SINT = GL_RG32I,
FORMAT_R32G32_UINT = GL_RG32UI,
FORMAT_R32G32B32_SINT = GL_RGB32I,
FORMAT_R32G32B32_UINT = GL_RGB32UI,
FORMAT_R32G32B32A32_SINT = GL_RGBA32I,
FORMAT_R32G32B32A32_UINT = GL_RGBA32UI,
FORMAT_R32_SFLOAT = GL_R32F,
FORMAT_R32G32_SFLOAT = GL_RG32F,
FORMAT_R32G32B32_SFLOAT = GL_RGB32F,
FORMAT_R32G32B32A32_SFLOAT = GL_RGBA32F,
FORMAT_R64_SFLOAT = 0x6000,
FORMAT_R64G64_SFLOAT,
FORMAT_R64G64B64_SFLOAT,
FORMAT_R64G64B64A64_SFLOAT,
FORMAT_R32_BOOL = 0x6100,
FORMAT_R32G32_BOOL,
FORMAT_R32G32B32_BOOL,
FORMAT_R32G32B32A32_BOOL,
} Format;
typedef enum DescriptorType
{
DESCRIPTOR_TYPE_UNIFORM_BUFFER = GL_UNIFORM_BUFFER,
DESCRIPTOR_TYPE_STORAGE_BUFFER = GL_SHADER_STORAGE_BUFFER,
DESCRIPTOR_TYPE_STORAGE_IMAGE = GL_TEXTURE_2D,
} DescriptorType;
// A struct to represent input data to a shader
struct SSBOData
{
SSBOData() :
initializeType (InitializeNone),
layout (LayoutStd140),
format (FORMAT_UNDEFINED),
numElements (0),
isImage (false),
binding (0u),
stages ((ShaderStageFlags)0u)
{}
enum InputDataInitializeType
{
InitializeNone = 0,
InitializeNonZero,
InitializeZero,
} initializeType;
enum InputDataLayoutType
{
LayoutStd140 = 0,
LayoutStd430,
LayoutPacked,
} layout;
Format format;
deUint64 numElements;
bool isImage;
deUint32 binding;
ShaderStageFlags stages;
};
std::string getSharedMemoryBallotHelper();
deUint32 getSubgroupSize(Context& context);
deUint32 maxSupportedSubgroupSize();
std::string getShaderStageName(ShaderStageFlags stage);
std::string getSubgroupFeatureName(SubgroupFeatureFlags bit);
void addNoSubgroupShader (SourceCollections& programCollection);
std::string getVertShaderForStage(ShaderStageFlags stage);
bool isSubgroupSupported(Context& context);
bool areSubgroupOperationsSupportedForStage(
Context& context, ShaderStageFlags stage);
bool areSubgroupOperationsRequiredForStage(ShaderStageFlags stage);
bool isSubgroupFeatureSupportedForDevice(Context& context, SubgroupFeatureFlags bit);
bool isFragmentSSBOSupportedForDevice(Context& context);
bool isVertexSSBOSupportedForDevice(Context& context);
bool isImageSupportedForStageOnDevice(Context& context, const ShaderStageFlags stage);
bool isDoubleSupportedForDevice(Context& context);
bool isDoubleFormat(Format format);
std::string getFormatNameForGLSL(Format format);
void addGeometryShadersFromTemplate (const std::string& glslTemplate, SourceCollections& collection);
void setVertexShaderFrameBuffer (SourceCollections& programCollection);
void setFragmentShaderFrameBuffer (SourceCollections& programCollection);
void setFragmentShaderFrameBuffer (SourceCollections& programCollection);
void setTesCtrlShaderFrameBuffer (SourceCollections& programCollection);
void setTesEvalShaderFrameBuffer (SourceCollections& programCollection);
bool check(std::vector<const void*> datas,
deUint32 width, deUint32 ref);
bool checkCompute(std::vector<const void*> datas,
const deUint32 numWorkgroups[3], const deUint32 localSize[3],
deUint32 ref);
tcu::TestStatus makeTessellationEvaluationFrameBufferTest(Context& context, Format format,
SSBOData* extraData, deUint32 extraDataCount,
bool (*checkResult)(std::vector<const void*> datas, deUint32 width, deUint32 subgroupSize),
const ShaderStageFlags shaderStage = SHADER_STAGE_ALL_GRAPHICS);
tcu::TestStatus makeGeometryFrameBufferTest(Context& context, Format format, SSBOData* extraData,
deUint32 extraDataCount,
bool (*checkResult)(std::vector<const void*> datas, deUint32 width, deUint32 subgroupSize));
tcu::TestStatus allStages(Context& context, Format format,
SSBOData* extraData, deUint32 extraDataCount,
bool (*checkResult)(std::vector<const void*> datas, deUint32 width, deUint32 subgroupSize),
const ShaderStageFlags shaderStage);
tcu::TestStatus makeVertexFrameBufferTest(Context& context, Format format,
SSBOData* extraData, deUint32 extraDataCount,
bool (*checkResult)(std::vector<const void*> datas, deUint32 width, deUint32 subgroupSize));
tcu::TestStatus makeFragmentFrameBufferTest(Context& context, Format format,
SSBOData* extraData, deUint32 extraDataCount,
bool (*checkResult)(std::vector<const void*> datas, deUint32 width,
deUint32 height, deUint32 subgroupSize));
tcu::TestStatus makeComputeTest(
Context& context, Format format, SSBOData* inputs,
deUint32 inputsCount,
bool (*checkResult)(std::vector<const void*> datas,
const deUint32 numWorkgroups[3], const deUint32 localSize[3],
deUint32 subgroupSize));
} // subgroups
} // glc
#endif // _GLCSUBGROUPSTESTSUTILS_HPP