blob: 7b6679c72cd5338479ec03f66f92c2d495985acf [file] [log] [blame]
/*-------------------------------------------------------------------------
* OpenGL Conformance Test Suite
* -----------------------------
*
* Copyright (c) 2017 The Khronos Group Inc.
*
* 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
*/ /*-------------------------------------------------------------------*/
/**
*/ /*!
* \file gl4cGlSpirvTests.cpp
* \brief Conformance tests for the GL_ARB_gl_spirv functionality.
*/ /*-------------------------------------------------------------------*/
#include "gl4cGlSpirvTests.hpp"
#include "deArrayUtil.hpp"
#include "deSingleton.h"
#include "deStringUtil.hpp"
#include "gluContextInfo.hpp"
#include "gluDefs.hpp"
#include "gluShaderProgram.hpp"
#include "gluStrUtil.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include "tcuRenderTarget.hpp"
#include "tcuResource.hpp"
#include "tcuTestLog.hpp"
#if defined DEQP_HAVE_GLSLANG
#include "SPIRV/GlslangToSpv.h"
#include "SPIRV/disassemble.h"
#include "SPIRV/doc.h"
#include "glslang/MachineIndependent/localintermediate.h"
#include "glslang/Public/ShaderLang.h"
#endif // DEQP_HAVE_GLSLANG
#if defined DEQP_HAVE_SPIRV_TOOLS
#include "spirv-tools/libspirv.hpp"
#include "spirv-tools/optimizer.hpp"
#endif // DEQP_HAVE_SPIRV_TOOLS
using namespace glu;
using namespace glw;
namespace gl4cts
{
namespace glslangUtils
{
#if defined DEQP_HAVE_GLSLANG
EShLanguage getGlslangStage(glu::ShaderType type)
{
static const EShLanguage stageMap[] = {
EShLangVertex, EShLangFragment, EShLangGeometry, EShLangTessControl, EShLangTessEvaluation, EShLangCompute,
};
return de::getSizedArrayElement<glu::SHADERTYPE_LAST>(stageMap, type);
}
static volatile deSingletonState s_glslangInitState = DE_SINGLETON_STATE_NOT_INITIALIZED;
void initGlslang(void*)
{
// Main compiler
glslang::InitializeProcess();
// SPIR-V disassembly
spv::Parameterize();
}
void prepareGlslang(void)
{
deInitSingleton(&s_glslangInitState, initGlslang, DE_NULL);
}
void getDefaultLimits(TLimits* limits)
{
limits->nonInductiveForLoops = true;
limits->whileLoops = true;
limits->doWhileLoops = true;
limits->generalUniformIndexing = true;
limits->generalAttributeMatrixVectorIndexing = true;
limits->generalVaryingIndexing = true;
limits->generalSamplerIndexing = true;
limits->generalVariableIndexing = true;
limits->generalConstantMatrixVectorIndexing = true;
}
void getDefaultBuiltInResources(TBuiltInResource* builtin)
{
getDefaultLimits(&builtin->limits);
builtin->maxLights = 32;
builtin->maxClipPlanes = 6;
builtin->maxTextureUnits = 32;
builtin->maxTextureCoords = 32;
builtin->maxVertexAttribs = 64;
builtin->maxVertexUniformComponents = 4096;
builtin->maxVaryingFloats = 64;
builtin->maxVertexTextureImageUnits = 32;
builtin->maxCombinedTextureImageUnits = 80;
builtin->maxTextureImageUnits = 32;
builtin->maxFragmentUniformComponents = 4096;
builtin->maxDrawBuffers = 32;
builtin->maxVertexUniformVectors = 128;
builtin->maxVaryingVectors = 8;
builtin->maxFragmentUniformVectors = 16;
builtin->maxVertexOutputVectors = 16;
builtin->maxFragmentInputVectors = 15;
builtin->minProgramTexelOffset = -8;
builtin->maxProgramTexelOffset = 7;
builtin->maxClipDistances = 8;
builtin->maxComputeWorkGroupCountX = 65535;
builtin->maxComputeWorkGroupCountY = 65535;
builtin->maxComputeWorkGroupCountZ = 65535;
builtin->maxComputeWorkGroupSizeX = 1024;
builtin->maxComputeWorkGroupSizeY = 1024;
builtin->maxComputeWorkGroupSizeZ = 64;
builtin->maxComputeUniformComponents = 1024;
builtin->maxComputeTextureImageUnits = 16;
builtin->maxComputeImageUniforms = 8;
builtin->maxComputeAtomicCounters = 8;
builtin->maxComputeAtomicCounterBuffers = 1;
builtin->maxVaryingComponents = 60;
builtin->maxVertexOutputComponents = 64;
builtin->maxGeometryInputComponents = 64;
builtin->maxGeometryOutputComponents = 128;
builtin->maxFragmentInputComponents = 128;
builtin->maxImageUnits = 8;
builtin->maxCombinedImageUnitsAndFragmentOutputs = 8;
builtin->maxCombinedShaderOutputResources = 8;
builtin->maxImageSamples = 0;
builtin->maxVertexImageUniforms = 0;
builtin->maxTessControlImageUniforms = 0;
builtin->maxTessEvaluationImageUniforms = 0;
builtin->maxGeometryImageUniforms = 0;
builtin->maxFragmentImageUniforms = 8;
builtin->maxCombinedImageUniforms = 8;
builtin->maxGeometryTextureImageUnits = 16;
builtin->maxGeometryOutputVertices = 256;
builtin->maxGeometryTotalOutputComponents = 1024;
builtin->maxGeometryUniformComponents = 1024;
builtin->maxGeometryVaryingComponents = 64;
builtin->maxTessControlInputComponents = 128;
builtin->maxTessControlOutputComponents = 128;
builtin->maxTessControlTextureImageUnits = 16;
builtin->maxTessControlUniformComponents = 1024;
builtin->maxTessControlTotalOutputComponents = 4096;
builtin->maxTessEvaluationInputComponents = 128;
builtin->maxTessEvaluationOutputComponents = 128;
builtin->maxTessEvaluationTextureImageUnits = 16;
builtin->maxTessEvaluationUniformComponents = 1024;
builtin->maxTessPatchComponents = 120;
builtin->maxPatchVertices = 32;
builtin->maxTessGenLevel = 64;
builtin->maxViewports = 16;
builtin->maxVertexAtomicCounters = 0;
builtin->maxTessControlAtomicCounters = 0;
builtin->maxTessEvaluationAtomicCounters = 0;
builtin->maxGeometryAtomicCounters = 0;
builtin->maxFragmentAtomicCounters = 8;
builtin->maxCombinedAtomicCounters = 8;
builtin->maxAtomicCounterBindings = 1;
builtin->maxVertexAtomicCounterBuffers = 0;
builtin->maxTessControlAtomicCounterBuffers = 0;
builtin->maxTessEvaluationAtomicCounterBuffers = 0;
builtin->maxGeometryAtomicCounterBuffers = 0;
builtin->maxFragmentAtomicCounterBuffers = 1;
builtin->maxCombinedAtomicCounterBuffers = 1;
builtin->maxAtomicCounterBufferSize = 16384;
builtin->maxTransformFeedbackBuffers = 4;
builtin->maxTransformFeedbackInterleavedComponents = 64;
builtin->maxCullDistances = 8;
builtin->maxCombinedClipAndCullDistances = 8;
builtin->maxSamples = 4;
};
bool compileGlslToSpirV(tcu::TestLog& log, std::string source, glu::ShaderType type, ShaderBinaryDataType* dst)
{
TBuiltInResource builtinRes;
prepareGlslang();
getDefaultBuiltInResources(&builtinRes);
const EShLanguage shaderStage = getGlslangStage(type);
glslang::TShader shader(shaderStage);
glslang::TProgram program;
const char* src[] = { source.c_str() };
shader.setStrings(src, 1);
program.addShader(&shader);
const int compileRes = shader.parse(&builtinRes, 100, false, EShMsgSpvRules);
if (compileRes != 0)
{
const int linkRes = program.link(EShMsgSpvRules);
if (linkRes != 0)
{
const glslang::TIntermediate* const intermediate = program.getIntermediate(shaderStage);
glslang::GlslangToSpv(*intermediate, *dst);
return true;
}
else
{
log << tcu::TestLog::Message << "Program linking error:\n"
<< program.getInfoLog() << "\n"
<< "Source:\n"
<< source << "\n"
<< tcu::TestLog::EndMessage;
}
}
else
{
log << tcu::TestLog::Message << "Shader compilation error:\n"
<< shader.getInfoLog() << "\n"
<< "Source:\n"
<< source << "\n"
<< tcu::TestLog::EndMessage;
}
return false;
}
#else // DEQP_HAVE_GLSLANG
bool compileGlslToSpirV(tcu::TestLog& log, std::string source, glu::ShaderType type, ShaderBinaryDataType* dst)
{
DE_UNREF(log);
DE_UNREF(source);
DE_UNREF(type);
DE_UNREF(dst);
TCU_THROW(InternalError, "Glslang not available.");
return false;
}
#endif // DEQP_HAVE_GLSLANG
#if defined DEQP_HAVE_SPIRV_TOOLS
void spirvAssemble(ShaderBinaryDataType& dst, const std::string& src)
{
spvtools::SpirvTools core(SPV_ENV_OPENGL_4_5);
auto print_msg_to_stderr = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) {
std::cerr << "error: " << m << std::endl;
};
core.SetMessageConsumer(print_msg_to_stderr);
if (!core.Assemble(src, &dst))
TCU_THROW(InternalError, "Failed to assemble Spir-V source.");
if (!core.Validate(dst))
TCU_THROW(InternalError, "Failed to validate Spir-V module.");
}
void spirvDisassemble(std::string& dst, const ShaderBinaryDataType& src)
{
spvtools::SpirvTools core(SPV_ENV_OPENGL_4_5);
auto print_msg_to_stderr = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) {
std::cerr << "error: " << m << std::endl;
};
core.SetMessageConsumer(print_msg_to_stderr);
if (!core.Disassemble(src, &dst))
TCU_THROW(InternalError, "Failed to disassemble Spir-V module.");
}
#else //DEQP_HAVE_SPIRV_TOOLS
void spirvAssemble(ShaderBinaryDataType& dst, const std::string& src)
{
DE_UNREF(dst);
DE_UNREF(src);
TCU_THROW(InternalError, "Spirv-tools not available.");
}
void spirvDisassemble(std::string& dst, ShaderBinaryDataType& src)
{
DE_UNREF(dst);
DE_UNREF(src);
TCU_THROW(InternalError, "Glslang not available.");
}
#endif // DEQP_HAVE_SPIRV_TOOLS
ShaderBinary makeSpirV(tcu::TestLog& log, ShaderSource source)
{
ShaderBinary binary;
if (!glslangUtils::compileGlslToSpirV(log, source.source, source.shaderType, &binary.binary))
TCU_THROW(InternalError, "Failed to convert GLSL to Spir-V");
binary << source.shaderType << "main";
return binary;
}
/** Verifying if GLSL to SpirV mapping was performed correctly
*
* @param glslSource GLSL shader template
* @param spirVSource SpirV disassembled source
* @param mappings Glsl to SpirV mappings vector
* @param anyOf any occurence indicator
*
* @return true if GLSL code occurs as many times as all of SpirV code for each mapping if anyOf is false
* or true if SpirV code occurs at least once if GLSL code found, false otherwise.
**/
bool verifyMappings(std::string glslSource, std::string spirVSource, SpirVMapping& mappings, bool anyOf)
{
std::vector<std::string> spirVSourceLines = de::splitString(spirVSource, '\n');
// Iterate through all glsl functions
for (SpirVMapping::iterator it = mappings.begin(); it != mappings.end(); it++)
{
int glslCodeCount = 0;
int spirVCodeCount = 0;
// To avoid finding functions with similar names (ie. "cos", "acos", "cosh")
// add characteristic characters that delimits finding results
std::string glslCode = it->first;
// Count GLSL code occurrences in GLSL source
size_t codePosition = glslSource.find(glslCode);
while (codePosition != std::string::npos)
{
glslCodeCount++;
codePosition = glslSource.find(glslCode, codePosition + 1);
}
if (glslCodeCount > 0)
{
// Count all SpirV code variants occurrences in SpirV source
for (int s = 0; s < it->second.size(); ++s)
{
std::vector<std::string> spirVCodes = de::splitString(it->second[s], ' ');
for (int v = 0; v < spirVSourceLines.size(); ++v)
{
std::vector<std::string> spirVLineCodes = de::splitString(spirVSourceLines[v], ' ');
bool matchAll = true;
for (int j = 0; j < spirVCodes.size(); ++j)
{
bool match = false;
for (int i = 0; i < spirVLineCodes.size(); ++i)
{
if (spirVLineCodes[i] == spirVCodes[j])
match = true;
}
matchAll = matchAll && match;
}
if (matchAll)
spirVCodeCount++;
}
}
// Check if both counts match
if (anyOf && (glslCodeCount > 0 && spirVCodeCount == 0))
return false;
else if (!anyOf && glslCodeCount != spirVCodeCount)
return false;
}
}
return true;
}
} // namespace glslangUtils
namespace commonUtils
{
void writeSpirV(const char* filename, ShaderBinary binary)
{
FILE* file = fopen(filename, "wb");
if (file)
{
// As one binary could be associated with many shader objects it should be stored either a type of each shader
// This will be extended in the future
deUint8 count = (deUint8)binary.shaderTypes.size();
fwrite((void*)&count, 1, 1, file);
for (int i = 0; i < binary.shaderTypes.size(); ++i)
{
fwrite((void*)&binary.shaderTypes[i], 1, sizeof(ShaderType), file);
if (count > 1)
{
deUint8 strLen = (deUint8)binary.shaderEntryPoints[i].size();
fwrite((void*)&strLen, 1, 1, file);
fwrite((void*)binary.shaderEntryPoints[i].data(), 1, strLen, file);
}
}
fwrite((void*)binary.binary.data(), 1, binary.binary.size() * 4, file);
fclose(file);
}
}
ShaderBinary readSpirV(tcu::Resource* resource)
{
ShaderBinary binary;
if (!resource)
return binary;
// As one binary could be associated with many shader objects it should be stored either a type of each shader
deUint8 count;
resource->read(&count, 1);
binary.shaderTypes.resize(count);
binary.shaderEntryPoints.resize(count);
for (int i = 0; i < binary.shaderTypes.size(); ++i)
{
resource->read((deUint8*)&binary.shaderTypes[i], sizeof(ShaderType));
if (count > 1)
{
deUint8 strLen;
resource->read(&strLen, 1);
binary.shaderEntryPoints[i].resize(strLen);
resource->read((deUint8*)binary.shaderEntryPoints[i].data(), strLen);
}
else
binary.shaderEntryPoints[i] = "main";
}
binary.binary.resize((resource->getSize() - resource->getPosition()) / sizeof(deUint32));
resource->read((deUint8*)binary.binary.data(), binary.binary.size() * sizeof(deUint32));
return binary;
}
/** Replace all occurance of <token> with <text> in <string>
*
* @param token Token string
* @param text String th at will be used as replacement for <token>
* @param string String to work on
**/
void replaceToken(const GLchar* token, const GLchar* text, std::string& string)
{
const size_t text_length = strlen(text);
const size_t token_length = strlen(token);
size_t token_position;
while ((token_position = string.find(token, 0)) != std::string::npos)
{
string.replace(token_position, token_length, text, text_length);
}
}
bool compareUintColors(const GLuint inColor, const GLuint refColor, const int epsilon)
{
int r1 = (inColor & 0xFF);
int g1 = ((inColor >> 8) & 0xFF);
int b1 = ((inColor >> 16) & 0xFF);
int a1 = ((inColor >> 24) & 0xFF);
int r2 = (refColor & 0xFF);
int g2 = ((refColor >> 8) & 0xFF);
int b2 = ((refColor >> 16) & 0xFF);
int a2 = ((refColor >> 24) & 0xFF);
if (r1 >= r2 - epsilon && r1 <= r2 + epsilon && g1 >= g2 - epsilon && g1 <= g2 + epsilon && b1 >= b2 - epsilon &&
b1 <= b2 + epsilon)
{
return true;
}
return false;
}
} // namespace commonUtils
/** Constructor.
*
* @param context Rendering context
* @param name Test name
* @param description Test description
*/
SpirvModulesPositiveTest::SpirvModulesPositiveTest(deqp::Context& context)
: TestCase(context, "spirv_modules_positive_test",
"Test verifies if using SPIR-V modules for each shader stage works as expected")
{
/* Left blank intentionally */
}
/** Stub init method */
void SpirvModulesPositiveTest::init()
{
if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gl_spirv"))
TCU_THROW(NotSupportedError, "GL_ARB_gl_spirv is not supported");
m_vertex = "#version 450\n"
"\n"
"layout (location = 0) in vec3 position;\n"
"\n"
"layout (location = 1) out vec4 vColor;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(position, 1.0);\n"
" vColor = vec4(0.0, 0.0, 0.0, 1.0);\n"
"}\n";
m_tesselationCtrl = "#version 450\n"
"\n"
"layout (vertices = 3) out;\n"
"\n"
"layout (location = 1) in vec4 vColor[];\n"
"layout (location = 2) out vec4 tcColor[];\n"
"\n"
"void main()\n"
"{\n"
" tcColor[gl_InvocationID] = vColor[gl_InvocationID];\n"
" tcColor[gl_InvocationID].r = 1.0;\n"
"\n"
" if (gl_InvocationID == 0) {\n"
" gl_TessLevelOuter[0] = 1.0;\n"
" gl_TessLevelOuter[1] = 1.0;\n"
" gl_TessLevelOuter[2] = 1.0;\n"
" gl_TessLevelInner[0] = 1.0;\n"
" }\n"
"\n"
" gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
"}\n";
m_tesselationEval = "#version 450\n"
"\n"
"layout (triangles) in;\n"
"\n"
"layout (location = 2) in vec4 tcColor[];\n"
"layout (location = 3) out vec4 teColor;\n"
"\n"
"void main()\n"
"{\n"
" teColor = tcColor[0];\n"
" teColor.g = 1.0;\n"
"\n"
" gl_Position = gl_TessCoord.x * gl_in[0].gl_Position +\n"
" gl_TessCoord.y * gl_in[1].gl_Position +\n"
" gl_TessCoord.z * gl_in[2].gl_Position;\n"
"}\n";
m_geometry = "#version 450\n"
"\n"
"layout (triangles) in;\n"
"layout (triangle_strip, max_vertices = 3) out;\n"
"\n"
"layout (location = 3) in vec4 teColor[];\n"
"layout (location = 4) out vec4 gColor;\n"
"\n"
"void main()\n"
"{\n"
" gColor = teColor[0];\n"
" gColor.b = 1.0;\n"
"\n"
" for (int i = 0; i < 3; ++i) {\n"
" gl_Position = gl_in[i].gl_Position;\n"
" EmitVertex();\n"
" }\n"
" EndPrimitive();\n"
"}\n";
m_fragment = "#version 450\n"
"\n"
"layout (location = 4) in vec4 gColor;\n"
"layout (location = 0) out vec4 fColor;\n"
"\n"
"void main()\n"
"{\n"
" fColor = gColor;\n"
"}\n";
const Functions& gl = m_context.getRenderContext().getFunctions();
gl.genTextures(1, &m_texture);
GLU_EXPECT_NO_ERROR(gl.getError(), "genTextures");
gl.bindTexture(GL_TEXTURE_2D, m_texture);
GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture");
gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 32, 32);
GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage2D");
gl.genFramebuffers(1, &m_fbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "genFramenuffers");
gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer");
gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture2D");
gl.viewport(0, 0, 32, 32);
GLU_EXPECT_NO_ERROR(gl.getError(), "viewport");
}
/** Stub de-init method */
void SpirvModulesPositiveTest::deinit()
{
const Functions& gl = m_context.getRenderContext().getFunctions();
if (m_fbo)
{
gl.deleteFramebuffers(1, &m_fbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "deleteFramebuffers");
}
if (m_texture)
{
gl.deleteTextures(1, &m_texture);
GLU_EXPECT_NO_ERROR(gl.getError(), "deleteTextures");
}
}
/** Executes test iteration.
*
* @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
*/
tcu::TestNode::IterateResult SpirvModulesPositiveTest::iterate()
{
const Functions& gl = m_context.getRenderContext().getFunctions();
const GLfloat vertices[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f };
GLuint vao;
gl.genVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays");
gl.bindVertexArray(vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray");
GLuint vbo;
gl.genBuffers(1, &vbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers");
gl.bindBuffer(GL_ARRAY_BUFFER, vbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer");
gl.bufferData(GL_ARRAY_BUFFER, 9 * sizeof(GLfloat), (GLvoid*)vertices, GL_DYNAMIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData");
enum Iterates
{
ITERATE_GLSL,
ITERATE_SPIRV,
ITERATE_LAST
};
deUint32 outputs[ITERATE_LAST];
for (int it = ITERATE_GLSL; it < ITERATE_LAST; ++it)
{
ShaderProgram* program = DE_NULL;
if (it == ITERATE_GLSL)
{
ProgramSources sources;
sources << VertexSource(m_vertex);
sources << TessellationControlSource(m_tesselationCtrl);
sources << TessellationEvaluationSource(m_tesselationEval);
sources << GeometrySource(m_geometry);
sources << FragmentSource(m_fragment);
program = new ShaderProgram(gl, sources);
}
else if (it == ITERATE_SPIRV)
{
#if defined DEQP_HAVE_GLSLANG
ProgramBinaries binaries;
binaries << glslangUtils::makeSpirV(m_context.getTestContext().getLog(), VertexSource(m_vertex));
binaries << glslangUtils::makeSpirV(m_context.getTestContext().getLog(),
TessellationControlSource(m_tesselationCtrl));
binaries << glslangUtils::makeSpirV(m_context.getTestContext().getLog(),
TessellationEvaluationSource(m_tesselationEval));
binaries << glslangUtils::makeSpirV(m_context.getTestContext().getLog(), GeometrySource(m_geometry));
binaries << glslangUtils::makeSpirV(m_context.getTestContext().getLog(), FragmentSource(m_fragment));
program = new ShaderProgram(gl, binaries);
#else // DEQP_HAVE_GLSLANG
tcu::Archive& archive = m_testCtx.getArchive();
ProgramBinaries binaries;
binaries << commonUtils::readSpirV(archive.getResource("spirv/modules_positive/vertex.nspv"));
binaries << commonUtils::readSpirV(archive.getResource("spirv/modules_positive/tess_control.nspv"));
binaries << commonUtils::readSpirV(archive.getResource("spirv/modules_positive/tess_evaluation.nspv"));
binaries << commonUtils::readSpirV(archive.getResource("spirv/modules_positive/geometry.nspv"));
binaries << commonUtils::readSpirV(archive.getResource("spirv/modules_positive/fragment.nspv"));
program = new ShaderProgram(gl, binaries);
#endif // DEQP_HAVE_GLSLANG
}
if (!program->isOk())
{
m_testCtx.getLog() << tcu::TestLog::Message << "Shader build failed.\n"
<< "Vertex: " << program->getShaderInfo(SHADERTYPE_VERTEX).infoLog << "\n"
<< m_vertex << "\n"
<< "TesselationCtrl: " << program->getShaderInfo(SHADERTYPE_TESSELLATION_CONTROL).infoLog
<< "\n"
<< m_tesselationCtrl << "\n"
<< "TesselationEval: "
<< program->getShaderInfo(SHADERTYPE_TESSELLATION_EVALUATION).infoLog << "\n"
<< m_tesselationEval << "\n"
<< "Geometry: " << program->getShaderInfo(SHADERTYPE_GEOMETRY).infoLog << "\n"
<< m_geometry << "\n"
<< "Fragment: " << program->getShaderInfo(SHADERTYPE_FRAGMENT).infoLog << "\n"
<< m_fragment << "\n"
<< "Program: " << program->getProgramInfo().infoLog << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
gl.useProgram(program->getProgram());
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram");
gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor");
gl.clear(GL_COLOR_BUFFER_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "glClear");
gl.enableVertexAttribArray(0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray");
gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, DE_NULL);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer");
gl.patchParameteri(GL_PATCH_VERTICES, 3);
gl.drawArrays(GL_PATCHES, 0, 3);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArray");
gl.disableVertexAttribArray(0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDisableVertexAttribArray");
gl.readPixels(16, 16, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)&outputs[it]);
GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels");
if (program)
delete program;
}
if (vbo)
{
gl.deleteBuffers(1, &vbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers");
}
if (vao)
{
gl.deleteVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteVertexArrays");
}
if ((outputs[ITERATE_GLSL] & outputs[ITERATE_SPIRV]) != 0xFFFFFFFF)
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
m_testCtx.getLog() << tcu::TestLog::Message << "Wrong output color read from framebuffer.\n"
<< "GLSL: " << outputs[ITERATE_GLSL] << ", SPIR-V: " << outputs[ITERATE_SPIRV]
<< "Expected: " << (deUint32)0xFFFFFFFF << tcu::TestLog::EndMessage;
return STOP;
}
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
return STOP;
}
/** Constructor.
*
* @param context Rendering context
* @param name Test name
* @param description Test description
*/
SpirvShaderBinaryMultipleShaderObjectsTest::SpirvShaderBinaryMultipleShaderObjectsTest(deqp::Context& context)
: TestCase(context, "spirv_modules_shader_binary_multiple_shader_objects_test",
"Test verifies if one binary module can be associated with multiple shader objects.")
{
/* Left blank intentionally */
}
/** Stub init method */
void SpirvShaderBinaryMultipleShaderObjectsTest::init()
{
m_spirv = "OpCapability Shader\n"
"%1 = OpExtInstImport \"GLSL.std.450\"\n"
"OpMemoryModel Logical GLSL450\n"
"OpEntryPoint Vertex %mainv \"mainv\" %_ %position %gl_VertexID %gl_InstanceID\n"
"OpEntryPoint Fragment %mainf \"mainf\" %fColor\n"
"OpSource GLSL 450\n"
"OpName %mainv \"mainv\"\n"
"OpName %mainf \"mainf\"\n"
"OpName %gl_PerVertex \"gl_PerVertex\"\n"
"OpMemberName %gl_PerVertex 0 \"gl_Position\"\n"
"OpMemberName %gl_PerVertex 1 \"gl_PointSize\"\n"
"OpMemberName %gl_PerVertex 2 \"gl_ClipDistance\"\n"
"OpMemberName %gl_PerVertex 3 \"gl_CullDistance\"\n"
"OpName %_ \"\"\n"
"OpName %position \"position\"\n"
"OpName %gl_VertexID \"gl_VertexID\"\n"
"OpName %gl_InstanceID \"gl_InstanceID\"\n"
"OpMemberDecorate %gl_PerVertex 0 BuiltIn Position\n"
"OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize\n"
"OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance\n"
"OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance\n"
"OpDecorate %gl_PerVertex Block\n"
"OpDecorate %position Location 0\n"
"OpDecorate %gl_VertexID BuiltIn VertexId\n"
"OpDecorate %gl_InstanceID BuiltIn InstanceId\n"
"OpDecorate %fColor Location 0\n"
"%void = OpTypeVoid\n"
"%3 = OpTypeFunction %void\n"
"%float = OpTypeFloat 32\n"
"%v4float = OpTypeVector %float 4\n"
"%uint = OpTypeInt 32 0\n"
"%uint_1 = OpConstant %uint 1\n"
"%_arr_float_uint_1 = OpTypeArray %float %uint_1\n"
"%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1\n"
"%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex\n"
"%_ = OpVariable %_ptr_Output_gl_PerVertex Output\n"
"%int = OpTypeInt 32 1\n"
"%int_0 = OpConstant %int 0\n"
"%v3float = OpTypeVector %float 3\n"
"%_ptr_Input_v3float = OpTypePointer Input %v3float\n"
"%position = OpVariable %_ptr_Input_v3float Input\n"
"%float_1 = OpConstant %float 1\n"
"%_ptr_Output_v4float = OpTypePointer Output %v4float\n"
"%_ptr_Input_int = OpTypePointer Input %int\n"
"%gl_VertexID = OpVariable %_ptr_Input_int Input\n"
"%gl_InstanceID = OpVariable %_ptr_Input_int Input\n"
"%fColor = OpVariable %_ptr_Output_v4float Output\n"
"%fVec4_1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1\n"
"\n"
"%mainv = OpFunction %void None %3\n"
"%5 = OpLabel\n"
"%19 = OpLoad %v3float %position\n"
"%21 = OpCompositeExtract %float %19 0\n"
"%22 = OpCompositeExtract %float %19 1\n"
"%23 = OpCompositeExtract %float %19 2\n"
"%24 = OpCompositeConstruct %v4float %21 %22 %23 %float_1\n"
"%26 = OpAccessChain %_ptr_Output_v4float %_ %int_0\n"
"OpStore %26 %24\n"
"OpReturn\n"
"OpFunctionEnd\n"
"\n"
"%mainf = OpFunction %void None %3\n"
"%32 = OpLabel\n"
"OpStore %fColor %fVec4_1\n"
"OpReturn\n"
"OpFunctionEnd\n";
}
/** Stub init method */
void SpirvShaderBinaryMultipleShaderObjectsTest::deinit()
{
}
/** Executes test iteration.
*
* @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
*/
tcu::TestNode::IterateResult SpirvShaderBinaryMultipleShaderObjectsTest::iterate()
{
const Functions& gl = m_context.getRenderContext().getFunctions();
const GLfloat vertices[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f };
GLuint texture;
GLuint fbo;
gl.genTextures(1, &texture);
GLU_EXPECT_NO_ERROR(gl.getError(), "genTextures");
gl.bindTexture(GL_TEXTURE_2D, texture);
GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture");
gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 32, 32);
GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage2D");
gl.genFramebuffers(1, &fbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "genFramenuffers");
gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer");
gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture2D");
GLuint vao;
gl.genVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays");
gl.bindVertexArray(vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray");
GLuint vbo;
gl.genBuffers(1, &vbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers");
gl.bindBuffer(GL_ARRAY_BUFFER, vbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer");
gl.bufferData(GL_ARRAY_BUFFER, 9 * sizeof(GLfloat), (GLvoid*)vertices, GL_DYNAMIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData");
#if DEQP_HAVE_SPIRV_TOOLS
ShaderBinary binary;
binary << SHADERTYPE_VERTEX << "mainv";
binary << SHADERTYPE_FRAGMENT << "mainf";
glslangUtils::spirvAssemble(binary.binary, m_spirv);
#else // DEQP_HAVE_SPIRV_TOOLS
tcu::Archive& archive = m_testCtx.getArchive();
ShaderBinary binary = commonUtils::readSpirV(
archive.getResource("spirv/spirv_modules_shader_binary_multiple_shader_objects/binary.nspv"));
#endif // DEQP_HAVE_SPIRV_TOOLS
ProgramBinaries binaries;
binaries << binary;
ShaderProgram program(gl, binaries);
if (!program.isOk())
{
m_testCtx.getLog() << tcu::TestLog::Message << "Shader build failed.\n"
<< "Vertex: " << program.getShaderInfo(SHADERTYPE_VERTEX).infoLog << "\n"
<< "Fragment: " << program.getShaderInfo(SHADERTYPE_FRAGMENT).infoLog << "\n"
<< "Program: " << program.getProgramInfo().infoLog << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
gl.viewport(0, 0, 32, 32);
GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport");
gl.useProgram(program.getProgram());
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram");
gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor");
gl.clear(GL_COLOR_BUFFER_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "glClear");
gl.enableVertexAttribArray(0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray");
gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, DE_NULL);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer");
gl.drawArrays(GL_TRIANGLE_STRIP, 0, 3);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArray");
gl.disableVertexAttribArray(0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDisableVertexAttribArray");
GLuint insidePixel;
GLuint outsidePixel;
gl.readPixels(16, 16, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)&insidePixel);
GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels");
gl.readPixels(2, 30, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)&outsidePixel);
GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels");
if (vbo)
{
gl.deleteBuffers(1, &vbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers");
}
if (vao)
{
gl.deleteVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteVertexArrays");
}
if (fbo)
{
gl.deleteFramebuffers(1, &fbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteFramebuffers");
}
if (texture)
{
gl.deleteTextures(1, &texture);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures");
}
if (insidePixel == 0xFFFFFFFF && outsidePixel == 0xFF000000)
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
else
{
m_testCtx.getLog() << tcu::TestLog::Message << "Wrong pixels color read.\n"
<< "Expected (inside/outside): " << 0xFFFFFFFF << "/" << 0xFF000000 << "\n"
<< "Read: " << insidePixel << "/" << outsidePixel << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
return STOP;
}
/** Constructor.
*
* @param context Rendering context
* @param name Test name
* @param description Test description
*/
SpirvModulesStateQueriesTest::SpirvModulesStateQueriesTest(deqp::Context& context)
: TestCase(context, "spirv_modules_state_queries_test",
"Test verifies if state queries for new features added by ARB_gl_spirv works as expected.")
{
/* Left blank intentionally */
}
/** Stub init method */
void SpirvModulesStateQueriesTest::init()
{
if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gl_spirv"))
TCU_THROW(NotSupportedError, "GL_ARB_gl_spirv is not supported");
m_vertex = "#version 450\n"
"\n"
"layout (location = 0) in vec4 position;\n"
"layout (location = 20) uniform vec4 extPosition;\n"
"layout (binding = 5) uniform ComponentsBlock\n"
"{\n"
" vec4 c1;\n"
" vec2 c2;\n"
"} components;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = position + extPosition + components.c1 + vec4(components.c2, 0.0, 0.0);\n"
"}\n";
}
/** Stub de-init method */
void SpirvModulesStateQueriesTest::deinit()
{
}
/** Executes test iteration.
*
* @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
*/
tcu::TestNode::IterateResult SpirvModulesStateQueriesTest::iterate()
{
const Functions& gl = m_context.getRenderContext().getFunctions();
ProgramBinaries binaries;
ShaderBinary vertexBinary;
#if defined DEQP_HAVE_GLSLANG && DEQP_HAVE_SPIRV_TOOLS
{
vertexBinary = glslangUtils::makeSpirV(m_context.getTestContext().getLog(), VertexSource(m_vertex));
// Disassemble Spir-V module
std::string output;
glslangUtils::spirvDisassemble(output, vertexBinary.binary);
// Remove name reflection for defined variables
std::vector<std::string> lines = de::splitString(output, '\n');
std::string input;
for (int i = 0; i < lines.size(); ++i)
{
if (lines[i].find("OpName %position") != std::string::npos)
continue;
if (lines[i].find("OpName %extPosition") != std::string::npos)
continue;
if (lines[i].find("OpName %ComponentsBlock") != std::string::npos)
continue;
if (lines[i].find("OpName %components") != std::string::npos)
continue;
input.append(lines[i] + "\n");
}
// Assemble Spir-V module
vertexBinary.binary.clear();
glslangUtils::spirvAssemble(vertexBinary.binary, input);
}
#else // DEQP_HAVE_GLSLANG && DEQP_HAVE_SPIRV_TOOLS
tcu::Archive& archive = m_testCtx.getArchive();
vertexBinary = commonUtils::readSpirV(archive.getResource("spirv/modules_state_queries/vertex.nspv"));
#endif // DEQP_HAVE_GLSLANG && DEQP_HAVE_SPIRV_TOOLS
binaries << vertexBinary;
ShaderProgram program(gl, binaries);
Shader* shader = program.getShader(SHADERTYPE_VERTEX);
// 1) Check compile status
if (!program.getShaderInfo(SHADERTYPE_VERTEX).compileOk)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Check compile status failed.\n"
<< "Vertex: " << program.getShaderInfo(SHADERTYPE_VERTEX).infoLog << "\n"
<< m_vertex << "\n"
<< "Program: " << program.getProgramInfo().infoLog << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
// 2) Check if SPIR_V_BINARY_ARB state is TRUE
GLint shaderState;
gl.getShaderiv(shader->getShader(), GL_SPIR_V_BINARY_ARB, &shaderState);
GLU_EXPECT_NO_ERROR(gl.getError(), "getShaderiv");
if (shaderState != GL_TRUE)
{
m_testCtx.getLog() << tcu::TestLog::Message << "SPIR_V_BINARY_ARB state set to FALSE. Expected TRUE."
<< tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
// 3) Check if queries for ACTIVE_ATTRIBUTE_MAX_LENGTH, ACTIVE_UNIFORM_MAX_LENGTH,
// ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH return value equal to 1, and
// TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH value equals to 0
GLint programState[4];
GLint expectedValues[4] = {1, 1, 0, 1};
gl.getProgramiv(program.getProgram(), GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &programState[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramiv");
gl.getProgramiv(program.getProgram(), GL_ACTIVE_UNIFORM_MAX_LENGTH, &programState[1]);
GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramiv");
// We expect 0 for GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH because the current program
// doesn't activate transform feedback so there isn't any active varying.
gl.getProgramiv(program.getProgram(), GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &programState[2]);
GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramiv");
gl.getProgramiv(program.getProgram(), GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &programState[3]);
GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramiv");
bool programStateResult = true;
for (int i = 0; i < 4; ++i)
{
if (programState[i] != expectedValues[i])
{
m_testCtx.getLog() << tcu::TestLog::Message << "Check max name length [" << i << "] failed. "
<< "Expected: " << expectedValues[i] <<", Queried: "
<< programState[i] << "\n"
<< tcu::TestLog::EndMessage;
programStateResult = false;
}
}
if (!programStateResult)
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
// 4) Check if ShaderSource command usage on Spir-V binary shader will change SPIR_V_BINARY_ARB state to FALSE
const char* source = m_vertex.c_str();
const int length = m_vertex.length();
gl.shaderSource(shader->getShader(), 1, &source, &length);
GLU_EXPECT_NO_ERROR(gl.getError(), "shaderSource");
gl.getShaderiv(shader->getShader(), GL_SPIR_V_BINARY_ARB, &shaderState);
GLU_EXPECT_NO_ERROR(gl.getError(), "getShaderiv");
if (shaderState != GL_FALSE)
{
m_testCtx.getLog() << tcu::TestLog::Message << "SPIR_V_BINARY_ARB state set to TRUE. Expected FALSE."
<< tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
return STOP;
}
/** Constructor.
*
* @param context Rendering context
* @param name Test name
* @param description Test description
*/
SpirvModulesErrorVerificationTest::SpirvModulesErrorVerificationTest(deqp::Context& context)
: TestCase(context, "spirv_modules_error_verification_test",
"Test verifies if new features added by ARB_gl_spirv generate error messages as expected.")
{
/* Left blank intentionally */
}
/** Stub init method */
void SpirvModulesErrorVerificationTest::init()
{
if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gl_spirv"))
TCU_THROW(NotSupportedError, "GL_ARB_gl_spirv is not supported");
const Functions& gl = m_context.getRenderContext().getFunctions();
m_vertex = "#version 450\n"
"\n"
"layout (location = 0) in vec4 position;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = position;\n"
"}\n";
m_glslShaderId = gl.createShader(GL_VERTEX_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "createShader");
m_spirvShaderId = gl.createShader(GL_VERTEX_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "createShader");
m_programId = gl.createProgram();
GLU_EXPECT_NO_ERROR(gl.getError(), "createProgram");
gl.genTextures(1, &m_textureId);
GLU_EXPECT_NO_ERROR(gl.getError(), "genTextures");
}
/** Stub de-init method */
void SpirvModulesErrorVerificationTest::deinit()
{
const Functions& gl = m_context.getRenderContext().getFunctions();
gl.deleteTextures(1, &m_textureId);
GLU_EXPECT_NO_ERROR(gl.getError(), "deleteTextures");
gl.deleteProgram(m_programId);
GLU_EXPECT_NO_ERROR(gl.getError(), "deleteProgram");
gl.deleteShader(m_glslShaderId);
GLU_EXPECT_NO_ERROR(gl.getError(), "deleteShader");
gl.deleteShader(m_spirvShaderId);
GLU_EXPECT_NO_ERROR(gl.getError(), "deleteShader");
}
/** Executes test iteration.
*
* @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
*/
tcu::TestNode::IterateResult SpirvModulesErrorVerificationTest::iterate()
{
const Functions& gl = m_context.getRenderContext().getFunctions();
const char* shaderSrc = m_vertex.c_str();
const int shaderLen = m_vertex.length();
ShaderBinary vertexBinary;
#if defined DEQP_HAVE_GLSLANG
vertexBinary = glslangUtils::makeSpirV(m_context.getTestContext().getLog(), VertexSource(m_vertex));
#else // DEQP_HAVE_GLSLANG
tcu::Archive& archive = m_testCtx.getArchive();
vertexBinary = commonUtils::readSpirV(archive.getResource("spirv/modules_error_verification/vertex.nspv"));
#endif // DEQP_HAVE_GLSLANG
gl.shaderSource(m_glslShaderId, 1, &shaderSrc, &shaderLen);
GLU_EXPECT_NO_ERROR(gl.getError(), "shaderSource");
gl.shaderBinary(1, &m_spirvShaderId, GL_SHADER_BINARY_FORMAT_SPIR_V_ARB, (GLvoid*)vertexBinary.binary.data(),
vertexBinary.binary.size() * sizeof(deUint32));
GLU_EXPECT_NO_ERROR(gl.getError(), "shaderBinary");
gl.attachShader(m_programId, m_spirvShaderId);
GLU_EXPECT_NO_ERROR(gl.getError(), "attachShader");
GLint err;
// 1) Verify if CompileShader function used on shader with SPIR_V_BINARY_ARB state
// will result in generating INVALID_OPERATION error.
gl.compileShader(m_spirvShaderId);
err = gl.getError();
if (err != GL_INVALID_OPERATION)
{
m_testCtx.getLog()
<< tcu::TestLog::Message
<< "Unexpected error code generated by CompileShader [1]. Expected INVALID_OPERATION, generated: "
<< glu::getErrorName(err) << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
// 2) Verify if SpecializeShader function generate INVALID_VALUE error when
// <shader> is not the name of either a program or shader object.
gl.specializeShader(0xFFFF, "main", 0, DE_NULL, DE_NULL);
err = gl.getError();
if (err != GL_INVALID_VALUE)
{
m_testCtx.getLog()
<< tcu::TestLog::Message
<< "Unexpected error code generated by SpecializeShader [2]. Expected INVALID_VALUE, generated: "
<< glu::getErrorName(err) << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
// 3) Verify if SpecializeShader function generate INVALID_OPERATION error when
// <shader> is the name of a program object.
gl.specializeShader(m_programId, "main", 0, DE_NULL, DE_NULL);
err = gl.getError();
if (err != GL_INVALID_OPERATION)
{
m_testCtx.getLog()
<< tcu::TestLog::Message
<< "Unexpected error code generated by SpecializeShader [3]. Expected INVALID_OPERATION, generated: "
<< glu::getErrorName(err) << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
// 4) Verify if SpecializeShader function generate INVALID_OPERATION error when
// SPIR_V_BINARY_ARB state for <shader> is not TRUE.
gl.specializeShader(m_glslShaderId, "main", 0, DE_NULL, DE_NULL);
err = gl.getError();
if (err != GL_INVALID_OPERATION)
{
m_testCtx.getLog()
<< tcu::TestLog::Message
<< "Unexpected error code generated by SpecializeShader [4]. Expected INVALID_OPERATION, generated: "
<< glu::getErrorName(err) << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
// 5) Verify if SpecializeShader function generate INVALID_VALUE when <pEntryPoint>
// does not name a valid entry point for <shader>.
gl.specializeShader(m_spirvShaderId, "entry", 0, DE_NULL, DE_NULL);
err = gl.getError();
if (err != GL_INVALID_VALUE)
{
m_testCtx.getLog()
<< tcu::TestLog::Message
<< "Unexpected error code generated by SpecializeShader [5]. Expected INVALID_VALUE, generated: "
<< glu::getErrorName(err) << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
// 6) Verify if SpecializeShader function generate INVALID_VALUE when any element
// of <pConstantIndex> refers to a specialization constant that does not exist
// in the shader module contained in <shader>.
const GLuint specID = 10;
const GLuint specValue = 10;
gl.specializeShader(m_spirvShaderId, "main", 1, &specID, &specValue);
err = gl.getError();
if (err != GL_INVALID_VALUE)
{
m_testCtx.getLog()
<< tcu::TestLog::Message
<< "Unexpected error code generated by SpecializeShader [6]. Expected INVALID_VALUE, generated: "
<< glu::getErrorName(err) << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
// 7) Verify if LinkProgram fail when one or more of the shader objects attached to
// <program> are not specialized.
gl.linkProgram(m_programId);
err = gl.getError();
if (err == GL_NO_ERROR)
{
GLint linkStatus;
gl.getProgramiv(m_programId, GL_LINK_STATUS, &linkStatus);
GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramiv");
if (linkStatus != 0)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Unexpected result of LinkProgram [7]."
<< tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
}
// 8) Verify if SpecializeShader function generate INVALID_OPERATION error if the
// shader has already been specialized.
gl.specializeShader(m_spirvShaderId, "main", 0, DE_NULL, DE_NULL);
GLU_EXPECT_NO_ERROR(gl.getError(), "specializeShader");
gl.specializeShader(m_spirvShaderId, "main", 0, DE_NULL, DE_NULL);
err = gl.getError();
if (err != GL_INVALID_OPERATION)
{
m_testCtx.getLog()
<< tcu::TestLog::Message
<< "Unexpected error code generated by SpecializeShader [8]. Expected INVALID_OPERATION, generated: "
<< glu::getErrorName(err) << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
// 9) Verify if LinkProgram fail when not all of shaders attached to <program> have
// the same value for the SPIR_V_BINARY_ARB state.
gl.compileShader(m_glslShaderId);
GLU_EXPECT_NO_ERROR(gl.getError(), "compileShader");
gl.attachShader(m_programId, m_glslShaderId);
GLU_EXPECT_NO_ERROR(gl.getError(), "attachShader");
gl.linkProgram(m_programId);
err = gl.getError();
if (err == GL_NO_ERROR)
{
GLint linkStatus;
gl.getProgramiv(m_programId, GL_LINK_STATUS, &linkStatus);
GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramiv");
if (linkStatus != 0)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Unexpected result of LinkProgram [9]."
<< tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
}
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
return STOP;
}
/** Constructor.
*
* @param context Rendering context
* @param name Test name
* @param description Test description
*/
SpirvGlslToSpirVEnableTest::SpirvGlslToSpirVEnableTest(deqp::Context& context)
: TestCase(context, "spirv_glsl_to_spirv_enable_test", "Test verifies if glsl supports Spir-V features.")
{
/* Left blank intentionally */
}
/** Stub init method */
void SpirvGlslToSpirVEnableTest::init()
{
if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gl_spirv"))
TCU_THROW(NotSupportedError, "GL_ARB_gl_spirv is not supported");
m_vertex = "#version 450\n"
"\n"
"#ifdef GL_SPIRV\n"
" layout (location = 0) in vec4 enabled;\n"
"#else\n"
" layout (location = 0) in vec4 notEnabled;\n"
"#endif // GL_SPIRV\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);\n"
"}\n";
}
/** Stub de-init method */
void SpirvGlslToSpirVEnableTest::deinit()
{
}
/** Executes test iteration.
*
* @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
*/
tcu::TestNode::IterateResult SpirvGlslToSpirVEnableTest::iterate()
{
#if defined DEQP_HAVE_GLSLANG && DEQP_HAVE_SPIRV_TOOLS
{
const Functions& gl = m_context.getRenderContext().getFunctions();
ProgramBinaries binaries;
ShaderBinary vertexBinary =
glslangUtils::makeSpirV(m_context.getTestContext().getLog(), VertexSource(m_vertex));
binaries << vertexBinary;
ShaderProgram spirvProgram(gl, binaries);
std::string spirvSource;
glslangUtils::spirvDisassemble(spirvSource, vertexBinary.binary);
if (spirvSource.find("OpName %enabled") == std::string::npos)
{
m_testCtx.getLog() << tcu::TestLog::Message << "GL_SPIRV not defined. Spir-V source:\n"
<< spirvSource.c_str() << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
if (!spirvProgram.isOk())
{
m_testCtx.getLog() << tcu::TestLog::Message << "Shader compilation failed. Source:\n"
<< spirvSource.c_str() << "InfoLog:\n"
<< spirvProgram.getShaderInfo(SHADERTYPE_VERTEX).infoLog << "\n"
<< tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
#else // DEQP_HAVE_GLSLANG && DEQP_HAVE_SPIRV_TOOLS
TCU_THROW(InternalError, "Either glslang or spirv-tools not available.");
#endif // DEQP_HAVE_GLSLANG && DEQP_HAVE_SPIRV_TOOLS
return STOP;
}
enum EShaderTemplate
{
COMPUTE_TEMPLATE,
TESSCTRL_TEMPLATE,
GEOMETRY_TEMPLATE,
FRAGMENT_TEMPLATE
};
struct FunctionMapping
{
EShaderTemplate shaderTemplate;
std::string glslFunc;
std::string glslArgs;
std::string spirVFunc;
FunctionMapping() : shaderTemplate(COMPUTE_TEMPLATE), glslFunc(""), glslArgs(""), spirVFunc("")
{
}
FunctionMapping(EShaderTemplate shaderTemplate_, std::string glslFunc_, std::string glslArgs_,
std::string spirVFunc_)
: shaderTemplate(shaderTemplate_), glslFunc(glslFunc_), glslArgs(glslArgs_), spirVFunc(spirVFunc_)
{
}
};
/** Constructor.
*
* @param context Rendering context
* @param name Test name
* @param description Test description
*/
SpirvGlslToSpirVBuiltInFunctionsTest::SpirvGlslToSpirVBuiltInFunctionsTest(deqp::Context& context)
: TestCase(context, "spirv_glsl_to_spirv_builtin_functions_test",
"Test verifies if GLSL built-in functions are supported by Spir-V.")
{
/* Left blank intentionally */
}
/** Stub init method */
void SpirvGlslToSpirVBuiltInFunctionsTest::init()
{
if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gl_spirv"))
TCU_THROW(NotSupportedError, "GL_ARB_gl_spirv is not supported");
initMappings();
m_commonVertex = "#version 450\n"
"\n"
"layout (location = 0) in vec3 position;\n"
"layout (location = 1) out vec2 texCoord;\n"
"\n"
"void main()\n"
"{\n"
" texCoord = vec2(0.0, 0.0);\n"
" gl_Position = vec4(position, 1.0);\n"
"}\n";
m_commonTessEval = "#version 450\n"
"\n"
"layout (triangles) in;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = gl_TessCoord.x * gl_in[0].gl_Position +\n"
" gl_TessCoord.y * gl_in[1].gl_Position +\n"
" gl_TessCoord.z * gl_in[2].gl_Position;\n"
"}\n";
m_sources.clear();
// Angle Trigonometry
m_sources.push_back(ComputeSource("#version 450\n"
"\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"void main()\n"
"{\n"
" float tmp0 = 0.5;\n"
" float value;\n"
" value = radians(tmp0) +\n"
" degrees(tmp0) +\n"
" sin(tmp0) +\n"
" cos(tmp0) +\n"
" tan(tmp0) +\n"
" asin(tmp0) +\n"
" acos(tmp0) +\n"
" atan(tmp0) +\n"
" atan(tmp0) +\n"
" sinh(tmp0) +\n"
" cosh(tmp0) +\n"
" tanh(tmp0) +\n"
" asinh(tmp0) +\n"
" acosh(tmp0) +\n"
" atanh(tmp0);\n"
"}\n"));
// To avoid duplicated mappings create additional shaders for specific functions
const std::string strAnlgeVariants = "#version 450\n"
"\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"void main()\n"
"{\n"
" float tmp0 = 0.5;\n"
" float value = <ATANGENT>;\n"
"}\n";
std::string strATan = strAnlgeVariants;
std::string strATan2 = strAnlgeVariants;
commonUtils::replaceToken("<ATANGENT>", "atan(tmp0, tmp0)", strATan);
commonUtils::replaceToken("<ATANGENT>", "atan(tmp0)", strATan2);
m_sources.push_back(ComputeSource(strATan));
m_sources.push_back(ComputeSource(strATan2));
// Exponential
m_sources.push_back(ComputeSource("#version 450\n"
"\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"void main()\n"
"{\n"
" float tmp0;\n"
" float tmp1;\n"
" float value;\n"
" value = pow(tmp1, tmp0) +\n"
" exp(tmp0) +\n"
" log(tmp1) +\n"
" exp2(tmp0) +\n"
" log2(tmp1) +\n"
" sqrt(tmp1) +\n"
" inversesqrt(tmp1);\n"
"}\n"));
// Common (without bit operations)
m_sources.push_back(ComputeSource("#version 450\n"
"\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"void main()\n"
"{\n"
" float value;\n"
" float outval;\n"
" float fpval = 0.5;\n"
" float fnval = -0.5;\n"
" int ival = 0x43800000;\n"
" uint uival= 0xC3800000;\n"
" value = abs(fnval) +\n"
" sign(fpval) +\n"
" floor(fpval) +\n"
" trunc(fpval) +\n"
" round(fpval) +\n"
" roundEven(fpval) +\n"
" ceil(fpval) +\n"
" fract(fpval) +\n"
" mod(fpval, 2.0) +\n"
" modf(fpval, outval) +\n"
" min(fpval, 0.2) +\n"
" max(fpval, 0.2) +\n"
" clamp(fpval, 0.8, 2.0) +\n"
" mix(fnval, fpval, 0.5) +\n"
" step(1.0, fpval) +\n"
" smoothstep(0.0, 1.0, fpval) +\n"
" float( isnan(fpval)) +\n"
" float( isinf(fpval)) +\n"
" fma(fpval, 1.0, fnval) +\n"
" frexp(4.0, ival) +\n"
" ldexp(4.0, ival);\n"
"}\n"));
// To avoid duplicated mappings create additional shaders for specific functions
const std::string strBitsOpsVariants = "#version 450\n"
"\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"void main()\n"
"{\n"
" float value;\n"
" int ival = 0x43800000;\n"
" uint uval = 0x43800000;\n"
" value = <BITS_TO_FLOAT>;\n"
"}\n";
std::string strIntBits = strBitsOpsVariants;
std::string strUIntBits = strBitsOpsVariants;
commonUtils::replaceToken("<BITS_TO_FLOAT>", "intBitsToFloat(ival)", strIntBits);
commonUtils::replaceToken("<BITS_TO_FLOAT>", "uintBitsToFloat(uval)", strUIntBits);
m_sources.push_back(ComputeSource(strIntBits));
m_sources.push_back(ComputeSource(strUIntBits));
// Float Pack Unpack
m_sources.push_back(ComputeSource("#version 450\n"
"\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"void main()\n"
"{\n"
" vec2 v2val = vec2(0.1, 0.2);\n"
" vec4 v4val = vec4(0.1, 0.2, 0.3, 0.4);\n"
" uint uival1 = packUnorm2x16(v2val);\n"
" uint uival2 = packSnorm2x16(v2val);\n"
" uint uival3 = packUnorm4x8(v4val);\n"
" uint uival4 = packSnorm4x8(v4val);\n"
" v2val = unpackUnorm2x16(uival1);\n"
" v2val = unpackSnorm2x16(uival2);\n"
" v4val = unpackUnorm4x8(uival3);\n"
" v4val = unpackSnorm4x8(uival4);\n"
" uvec2 uv2val = uvec2(10, 20);\n"
" double dval = packDouble2x32(uv2val);\n"
" uv2val = unpackDouble2x32(dval);\n"
" uint uival5 = packHalf2x16(v2val);\n"
" v2val = unpackHalf2x16(uival5);\n"
"}\n"));
// Geometric
m_sources.push_back(ComputeSource("#version 450\n"
"\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"void main()\n"
"{\n"
" vec3 v3val1 = vec3(0.1, 0.5, 1.0);\n"
" vec3 v3val2 = vec3(0.5, 0.3, 0.9);\n"
" vec3 v3val3 = vec3(1.0, 0.0, 0.0);\n"
" float fval = length(v3val1) +\n"
" distance(v3val1, v3val2) +\n"
" dot(v3val1, v3val2);\n"
" vec3 crossp = cross(v3val1, v3val2);\n"
" vec3 norm = normalize(crossp);\n"
" vec3 facef = faceforward(v3val1, v3val2, v3val3);\n"
" vec3 refl = reflect(v3val1, v3val2);\n"
" float eta = 0.1;\n"
" vec3 refr = refract(v3val1, v3val2, eta);"
"}\n"));
// Matrix
m_sources.push_back(ComputeSource("#version 450\n"
"\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"void main()\n"
"{\n"
" mat2 m2val1 = mat2(\n"
" 0.1, 0.5,\n"
" 0.2, 0.4\n"
" );\n"
" mat2 m2val2 = mat2(\n"
" 0.8, 0.2,\n"
" 0.9, 0.1\n"
" );\n"
" vec2 v2val1 = vec2(0.3, 0.4);\n"
" vec2 v2val2 = vec2(0.5, 0.6);\n"
"\n"
" mat2 m2comp = matrixCompMult(m2val1, m2val2);\n"
" mat2 m2outerp = outerProduct(v2val1, v2val2);\n"
" mat2 m2trans = transpose(m2val1);\n"
" float fdet = determinant(m2val2);\n"
" mat2 m2inv = inverse(m2trans);\n"
"}\n"));
// Vector Relational
m_sources.push_back(ComputeSource("#version 450\n"
"\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"void main()\n"
"{\n"
" vec2 v2val1 = vec2(0.5, 0.2);\n"
" vec2 v2val2 = vec2(0.1, 0.8);\n"
" bvec2 bv2val1 = lessThan(v2val1, v2val2);\n"
" bvec2 bv2val2 = lessThanEqual(v2val1, v2val2);\n"
" bvec2 bv2val3 = greaterThan(v2val1, v2val2);\n"
" bvec2 bv2val4 = greaterThanEqual(v2val1, v2val2);\n"
" bvec2 bv2val5 = equal(v2val1, v2val2);\n"
" bvec2 bv2val6 = notEqual(v2val1, v2val2);\n"
" bool bval1 = any(bv2val1);\n"
" bool bval2 = all(bv2val1);\n"
" bvec2 bv2val7 = not(bv2val1);\n"
"}\n"));
// Integer
m_sources.push_back(ComputeSource("#version 450\n"
"\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"void main()\n"
"{\n"
" int ival = 0;\n"
" uint uival = 200;\n"
" uint uivalRet1;\n"
" uint uivalRet2;\n"
" uivalRet2 = uaddCarry(uival, 0xFFFFFFFF, uivalRet1);\n"
" uivalRet2 = usubBorrow(uival, 0xFFFFFFFF, uivalRet1);\n"
" umulExtended(uival, 0xFFFFFFFF, uivalRet1, uivalRet2);\n"
" uivalRet1 = bitfieldExtract(uival, 3, 8);\n"
" uivalRet1 = bitfieldInsert(uival, 0xFFFFFFFF, 3, 8);\n"
" uivalRet1 = bitfieldReverse(uival);\n"
" ival = bitCount(uival);\n"
" ival = findLSB(uival);\n"
" ival = findMSB(uival);\n"
"}\n"));
// Texture
m_sources.push_back(
FragmentSource("#version 450\n"
"\n"
"layout (location = 0) out vec4 fragColor;\n"
"\n"
"layout (location = 1) uniform sampler2D tex2D;\n"
"layout (location = 2) uniform sampler2DMS tex2DMS;\n"
"\n"
"void main()\n"
"{\n"
" ivec2 iv2size = textureSize(tex2D, 0);\n"
" vec2 v2lod = textureQueryLod(tex2D, vec2(0.0));\n"
" int ilev = textureQueryLevels(tex2D);\n"
" int isamp = textureSamples(tex2DMS);\n"
" vec4 v4pix = textureLod(tex2D, vec2(0.0), 0.0) +\n"
" textureOffset(tex2D, vec2(0.0), ivec2(2)) +\n"
" texelFetch(tex2D, ivec2(2), 0) +\n"
" texelFetchOffset(tex2D, ivec2(2), 0, ivec2(2)) +\n"
" textureProjOffset(tex2D, vec3(0.0), ivec2(2)) +\n"
" textureLodOffset(tex2D, vec2(0.0), 0.0, ivec2(2)) +\n"
" textureProjLod(tex2D, vec3(0.0), 0.0) +\n"
" textureProjLodOffset(tex2D, vec3(0.0), 0.0, ivec2(2)) +\n"
" textureGrad(tex2D, vec2(0.0), vec2(0.2), vec2(0.5)) +\n"
" textureGradOffset(tex2D, vec2(0.0), vec2(0.2), vec2(0.5), ivec2(2)) +\n"
" textureProjGrad(tex2D, vec3(0.0), vec2(0.2), vec2(0.5)) +\n"
" textureProjGradOffset(tex2D, vec3(0.0), vec2(0.2), vec2(0.5), ivec2(2)) +\n"
" textureGatherOffset(tex2D, vec2(0.0), ivec2(2), 0);\n"
" fragColor = vec4(0.0);\n"
"}\n"));
// To avoid duplicated mappings create additional shaders for specific functions
const std::string strTextureVariants = "#version 450\n"
"\n"
"layout (location = 0) out vec4 fragColor;\n"
"\n"
"layout (location = 1) uniform sampler2D tex2D;\n"
"\n"
"void main()\n"
"{\n"
" fragColor = <TEXTURE>;\n"
"}\n";
std::string strTexture = strTextureVariants;
std::string strTextureProj = strTextureVariants;
std::string strTextureGather = strTextureVariants;
commonUtils::replaceToken("<TEXTURE>", "texture(tex2D, vec2(0.0))", strTexture);
commonUtils::replaceToken("<TEXTURE>", "textureProj(tex2D, vec3(0.0))", strTextureProj);
commonUtils::replaceToken("<TEXTURE>", "textureGather(tex2D, vec2(0.0), 0)", strTextureGather);
m_sources.push_back(FragmentSource(strTexture));
m_sources.push_back(FragmentSource(strTextureProj));
m_sources.push_back(FragmentSource(strTextureGather));
// Atomic Counter
m_sources.push_back(ComputeSource("#version 450\n"
"\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"layout (binding = 0) uniform atomic_uint auival;\n"
"\n"
"void main()\n"
"{\n"
" uint uival = atomicCounterIncrement(auival) +\n"
" atomicCounterDecrement(auival) +\n"
" atomicCounter(auival);\n"
"}\n"));
// Atomic Memory
m_sources.push_back(ComputeSource("#version 450\n"
"\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"shared uint uishared;\n"
"\n"
"void main()\n"
"{\n"
" uint uival2 = 5;\n"
" uint uivalRet = atomicAdd(uishared, uival2) +\n"
" atomicMin(uishared, uival2) +\n"
" atomicMax(uishared, uival2) +\n"
" atomicAnd(uishared, uival2) +\n"
" atomicOr(uishared, uival2) +\n"
" atomicXor(uishared, uival2) +\n"
" atomicExchange(uishared, uival2) +\n"
" atomicCompSwap(uishared, uishared, uival2);\n"
"}\n"));
// Image
m_sources.push_back(ComputeSource("#version 450\n"
"\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"layout (location = 1, rgba8ui) uniform readonly uimage2D rimg2D;\n"
"layout (location = 2, rgba8ui) uniform readonly uimage2DMS rimg2DMS;\n"
"layout (location = 3, rgba8ui) uniform writeonly uimage2D wimg2D;\n"
"layout (location = 4, r32ui) uniform uimage2D aimg2D;\n"
"\n"
"void main()\n"
"{\n"
" ivec2 size = imageSize(rimg2D);\n"
" int samp = imageSamples(rimg2DMS);\n"
" uvec4 v4pix = imageLoad(rimg2D, ivec2(0));\n"
" imageStore(wimg2D, ivec2(0), uvec4(255));\n"
" uint uivalRet = imageAtomicAdd(aimg2D, ivec2(0), 1) +\n"
" imageAtomicMin(aimg2D, ivec2(0), 1) +\n"
" imageAtomicMax(aimg2D, ivec2(0), 1) +\n"
" imageAtomicAnd(aimg2D, ivec2(0), 1) +\n"
" imageAtomicOr(aimg2D, ivec2(0), 1) +\n"
" imageAtomicXor(aimg2D, ivec2(0), 1) +\n"
" imageAtomicExchange(aimg2D, ivec2(0), 1) +\n"
" imageAtomicCompSwap(aimg2D, ivec2(0), 1, 2);\n"
"}\n"));
// Fragment Processing
m_sources.push_back(FragmentSource("#version 450\n"
"\n"
"layout (location = 0) out vec4 fragColor;\n"
"layout (location = 1) in vec2 texCoord;\n"
"\n"
"void main()\n"
"{\n"
" vec2 p = vec2(0.0);\n"
" vec2 dx = dFdx(p);\n"
" vec2 dy = dFdy(p);\n"
" dx = dFdxFine(p);\n"
" dy = dFdyFine(p);\n"
" dx = dFdxCoarse(p);\n"
" dy = dFdyCoarse(p);\n"
" vec2 fw = fwidth(p);\n"
" fw = fwidthFine(p);\n"
" fw = fwidthCoarse(p);\n"
" vec2 interp = interpolateAtCentroid(texCoord) +\n"
" interpolateAtSample(texCoord, 0) +\n"
" interpolateAtOffset(texCoord, vec2(0.0));\n"
" fragColor = vec4(1.0);\n"
"}\n"));
// To avoid duplicated mappings create additional shaders for specific functions
const std::string strEmitVariants = "#version 450\n"
"\n"
"layout (points) in;\n"
"layout (points, max_vertices = 3) out;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(0.0);\n"
" <EMIT>;\n"
" <END>;\n"
"}\n";
std::string strEmit = strEmitVariants;
std::string strEmitStream = strEmitVariants;
commonUtils::replaceToken("<EMIT>", "EmitVertex()", strEmit);
commonUtils::replaceToken("<EMIT>", "EmitStreamVertex(0)", strEmitStream);
commonUtils::replaceToken("<END>", "EndPrimitive()", strEmit);
commonUtils::replaceToken("<END>", "EndStreamPrimitive(0)", strEmitStream);
m_sources.push_back(GeometrySource(strEmit));
m_sources.push_back(GeometrySource(strEmitStream));
// Shader Invocation Control
m_sources.push_back(
TessellationControlSource("#version 450\n"
"\n"
"layout (vertices = 3) out;\n"
"\n"
"void main()\n"
"{\n"
" barrier();\n"
"\n"
" gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
"}\n"));
// Shared Memory Control
// To avoid duplicated mappings create additional shaders for specific functions
const std::string strMemoryBarrierSource = "#version 450\n"
"\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"void main()\n"
"{\n"
" <MEMORY_BARRIER>;\n"
"}\n";
std::string strMemoryBarrier = strMemoryBarrierSource;
std::string strMemoryBarrierAtomicCounter = strMemoryBarrierSource;
std::string strMemoryBarrierBuffer = strMemoryBarrierSource;
std::string strMemoryBarrierShared = strMemoryBarrierSource;
std::string strMemoryBarrierImage = strMemoryBarrierSource;
std::string strGroupMemoryBarrier = strMemoryBarrierSource;
commonUtils::replaceToken("<MEMORY_BARRIER>", "memoryBarrier()", strMemoryBarrier);
commonUtils::replaceToken("<MEMORY_BARRIER>", "memoryBarrierAtomicCounter()", strMemoryBarrierAtomicCounter);
commonUtils::replaceToken("<MEMORY_BARRIER>", "memoryBarrierBuffer()", strMemoryBarrierBuffer);
commonUtils::replaceToken("<MEMORY_BARRIER>", "memoryBarrierShared()", strMemoryBarrierShared);
commonUtils::replaceToken("<MEMORY_BARRIER>", "memoryBarrierImage()", strMemoryBarrierImage);
commonUtils::replaceToken("<MEMORY_BARRIER>", "groupMemoryBarrier()", strGroupMemoryBarrier);
m_sources.push_back(ComputeSource(strMemoryBarrier));
m_sources.push_back(ComputeSource(strMemoryBarrierAtomicCounter));
m_sources.push_back(ComputeSource(strMemoryBarrierBuffer));
m_sources.push_back(ComputeSource(strMemoryBarrierShared));
m_sources.push_back(ComputeSource(strMemoryBarrierImage));
m_sources.push_back(ComputeSource(strGroupMemoryBarrier));
}
/** Stub de-init method */
void SpirvGlslToSpirVBuiltInFunctionsTest::deinit()
{
}
/** Executes test iteration.
*
* @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
*/
tcu::TestNode::IterateResult SpirvGlslToSpirVBuiltInFunctionsTest::iterate()
{
const Functions& gl = m_context.getRenderContext().getFunctions();
for (int i = 0; i < m_sources.size(); ++i)
{
ShaderSource shaderSource = m_sources[i];
ProgramSources sources;
ProgramBinaries binaries;
if (shaderSource.shaderType != glu::SHADERTYPE_COMPUTE)
{
ShaderSource vertexSource(glu::SHADERTYPE_VERTEX, m_commonVertex);
sources << vertexSource;
ShaderBinary vertexBinary;
#if defined DEQP_HAVE_GLSLANG
vertexBinary = glslangUtils::makeSpirV(m_context.getTestContext().getLog(), vertexSource);
#else // DEQP_HAVE_GLSLANG
tcu::Archive& archive = m_testCtx.getArchive();
vertexBinary =
commonUtils::readSpirV(archive.getResource("spirv/glsl_to_spirv_builtin_functions/common_vertex.nspv"));
#endif //DEQP_HAVE_GLSLANG
binaries << vertexBinary;
}
sources << shaderSource;
ShaderBinary shaderBinary;
std::string spirvSource;
#if defined DEQP_HAVE_GLSLANG
shaderBinary = glslangUtils::makeSpirV(m_context.getTestContext().getLog(), shaderSource);
#else // DEQP_HAVE_GLSLANG
{
std::stringstream ss;
ss << "spirv/glsl_to_spirv_builtin_functions/binary_" << i << ".nspv";
tcu::Archive& archive = m_testCtx.getArchive();
shaderBinary = commonUtils::readSpirV(archive.getResource(ss.str().c_str()));
}
#endif // DEQP_HAVE_GLSLANG
#if defined DEQP_HAVE_SPIRV_TOOLS
{
glslangUtils::spirvDisassemble(spirvSource, shaderBinary.binary);
if (!glslangUtils::verifyMappings(shaderSource.source, spirvSource, m_mappings, false))
{
m_testCtx.getLog() << tcu::TestLog::Message << "Mappings for shader failed.\n"
<< "GLSL source:\n"
<< shaderSource.source.c_str() << "\n"
<< "SpirV source:\n"
<< spirvSource.c_str() << tcu::TestLog::EndMessage;
TCU_THROW(InternalError, "Mappings for shader failed.");
}
}
#else // DEQP_HAVE_SPIRV_TOOLS
spirvSource = "Could not disassemble Spir-V module. SPIRV-TOOLS not available.";
#endif // DEQP_HAVE_SPIRV_TOOLS
binaries << shaderBinary;
if (shaderSource.shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL)
{
ShaderSource tessEvalSource(glu::SHADERTYPE_TESSELLATION_EVALUATION, m_commonTessEval);
sources << tessEvalSource;
ShaderBinary tessEvalBinary;
#if defined DEQP_HAVE_GLSLANG
tessEvalBinary = glslangUtils::makeSpirV(m_context.getTestContext().getLog(), tessEvalSource);
#else // DEQP_HAVE_GLSLANG
tcu::Archive& archive = m_testCtx.getArchive();
tessEvalBinary = commonUtils::readSpirV(
archive.getResource("spirv/glsl_to_spirv_builtin_functions/common_tesseval.nspv"));
#endif // DEQP_HAVE_GLSLANG
binaries << tessEvalBinary;
}
ShaderProgram glslProgram(gl, sources);
if (!glslProgram.isOk())
{
m_testCtx.getLog() << tcu::TestLog::Message << "GLSL shader compilation failed. Source:\n"
<< shaderSource.source.c_str() << "InfoLog:\n"
<< glslProgram.getShaderInfo(shaderSource.shaderType).infoLog << "\n"
<< tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
ShaderProgram spirvProgram(gl, binaries);
if (!spirvProgram.isOk())
{
m_testCtx.getLog() << tcu::TestLog::Message << "SpirV shader compilation failed. Source:\n"
<< spirvSource.c_str() << "InfoLog:\n"
<< spirvProgram.getShaderInfo(shaderSource.shaderType).infoLog << "\n"
<< tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
}
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
return STOP;
}
/** Mappings init method */
void SpirvGlslToSpirVBuiltInFunctionsTest::initMappings()
{
m_mappings.clear();
m_mappings["radians"].push_back("OpExtInst Radians");
m_mappings["degrees"].push_back("OpExtInst Degrees");
m_mappings["sin"].push_back("OpExtInst Sin");
m_mappings["cos"].push_back("OpExtInst Cos");
m_mappings["tan"].push_back("OpExtInst Tan");
m_mappings["asin"].push_back("OpExtInst Asin");
m_mappings["acos"].push_back("OpExtInst Acos");
m_mappings["atan"].push_back("OpExtInst Atan2");
m_mappings["atan"].push_back("OpExtInst Atan");
m_mappings["sinh"].push_back("OpExtInst Sinh");
m_mappings["cosh"].push_back("OpExtInst Cosh");
m_mappings["tanh"].push_back("OpExtInst Tanh");
m_mappings["asinh"].push_back("OpExtInst Asinh");
m_mappings["acosh"].push_back("OpExtInst Acosh");
m_mappings["atanh"].push_back("OpExtInst Atanh");
m_mappings["pow"].push_back("OpExtInst Pow");
m_mappings["exp"].push_back("OpExtInst Exp");
m_mappings["log"].push_back("OpExtInst Log");
m_mappings["exp2"].push_back("OpExtInst Exp2");
m_mappings["log2"].push_back("OpExtInst Log2");
m_mappings["sqrt"].push_back("OpExtInst Sqrt");
m_mappings["inversesqrt"].push_back("OpExtInst InverseSqrt");
m_mappings["abs"].push_back("OpExtInst FAbs");
m_mappings["sign"].push_back("OpExtInst FSign");
m_mappings["floor"].push_back("OpExtInst Floor");
m_mappings["trunc"].push_back("OpExtInst Trunc");
m_mappings["round"].push_back("OpExtInst Round");
m_mappings["roundEven"].push_back("OpExtInst RoundEven");
m_mappings["ceil"].push_back("OpExtInst Ceil");
m_mappings["fract"].push_back("OpExtInst Fract");
m_mappings["mod"].push_back("OpFMod");
m_mappings["modf"].push_back("OpExtInst Modf");
m_mappings["min"].push_back("OpExtInst FMin");
m_mappings["max"].push_back("OpExtInst FMax");
m_mappings["clamp"].push_back("OpExtInst FClamp");
m_mappings["mix"].push_back("OpExtInst FMix");
m_mappings["step"].push_back("OpExtInst Step");
m_mappings["smoothstep"].push_back("OpExtInst SmoothStep");
m_mappings["intBitsToFloat"].push_back("OpBitcast");
m_mappings["uintBitsToFloat"].push_back("OpBitcast");
m_mappings["isnan"].push_back("OpIsNan");
m_mappings["isinf"].push_back("OpIsInf");
m_mappings["fma"].push_back("OpExtInst Fma");
m_mappings["frexp"].push_back("OpExtInst FrexpStruct");
m_mappings["ldexp"].push_back("OpExtInst Ldexp");
m_mappings["packUnorm2x16"].push_back("OpExtInst PackUnorm2x16");
m_mappings["packSnorm2x16"].push_back("OpExtInst PackSnorm2x16");
m_mappings["packUnorm4x8"].push_back("OpExtInst PackUnorm4x8");
m_mappings["packSnorm4x8"].push_back("OpExtInst PackSnorm4x8");
m_mappings["unpackUnorm2x16"].push_back("OpExtInst UnpackUnorm2x16");
m_mappings["unpackSnorm2x16"].push_back("OpExtInst UnpackSnorm2x16");
m_mappings["unpackUnorm4x8"].push_back("OpExtInst UnpackUnorm4x8");
m_mappings["unpackSnorm4x8"].push_back("OpExtInst UnpackSnorm4x8");
m_mappings["packDouble2x32"].push_back("OpExtInst PackDouble2x32");
m_mappings["unpackDouble2x32"].push_back("OpExtInst UnpackDouble2x32");
m_mappings["packHalf2x16"].push_back("OpExtInst PackHalf2x16");
m_mappings["unpackHalf2x16"].push_back("OpExtInst UnpackHalf2x16");
m_mappings["length"].push_back("OpExtInst Length");
m_mappings["distance"].push_back("OpExtInst Distance");
m_mappings["dot"].push_back("OpDot");
m_mappings["cross"].push_back("OpExtInst Cross");
m_mappings["normalize"].push_back("OpExtInst Normalize");
m_mappings["faceforward"].push_back("OpExtInst FaceForward");
m_mappings["reflect"].push_back("OpExtInst Reflect");
m_mappings["refract"].push_back("OpExtInst Refract");
// This one could not be mapped as Spir-V equivalent need more steps
// m_mappings["matrixCompMult"].push_back("");
m_mappings["outerProduct"].push_back("OpOuterProduct");
m_mappings["transpose"].push_back("OpTranspose");
m_mappings["determinant"].push_back("OpExtInst Determinant");
m_mappings["inverse"].push_back("OpExtInst MatrixInverse");
m_mappings["lessThan"].push_back("OpFOrdLessThan");
m_mappings["lessThanEqual"].push_back("OpFOrdLessThanEqual");
m_mappings["greaterThan"].push_back("OpFOrdGreaterThan");
m_mappings["greaterThanEqual"].push_back("OpFOrdGreaterThanEqual");
m_mappings["equal"].push_back("OpFOrdEqual");
m_mappings["notEqual"].push_back("OpFOrdNotEqual");
m_mappings["any"].push_back("OpAny");
m_mappings["all"].push_back("OpAll");
m_mappings["not"].push_back("OpLogicalNot");
m_mappings["uaddCarry"].push_back("OpIAddCarry");
m_mappings["usubBorrow"].push_back("OpISubBorrow");
m_mappings["umulExtended"].push_back("OpUMulExtended");
m_mappings["bitfieldExtract"].push_back("OpBitFieldUExtract");
m_mappings["bitfieldInsert"].push_back("OpBitFieldInsert");
m_mappings["bitfieldReverse"].push_back("OpBitReverse");
m_mappings["bitCount"].push_back("OpBitCount");
m_mappings["findLSB"].push_back("OpExtInst FindILsb");
m_mappings["findMSB"].push_back("OpExtInst FindUMsb");
m_mappings["textureSize"].push_back("OpImageQuerySizeLod");
m_mappings["textureQueryLod"].push_back("OpImageQueryLod");
m_mappings["textureQueryLevels"].push_back("OpImageQueryLevels");
m_mappings["textureSamples"].push_back("OpImageQuerySamples");
m_mappings["texture"].push_back("OpImageSampleImplicitLod");
m_mappings["textureProj"].push_back("OpImageSampleProjImplicitLod");
m_mappings["textureLod"].push_back("OpImageSampleExplicitLod Lod");
m_mappings["textureOffset"].push_back("OpImageSampleImplicitLod ConstOffset");
m_mappings["texelFetch"].push_back("OpImageFetch Lod");
m_mappings["texelFetchOffset"].push_back("OpImageFetch Lod|ConstOffset");
m_mappings["textureProjOffset"].push_back("OpImageSampleProjImplicitLod ConstOffset");
m_mappings["textureLodOffset"].push_back("OpImageSampleExplicitLod Lod|ConstOffset");
m_mappings["textureProjLod"].push_back("OpImageSampleProjExplicitLod Lod");
m_mappings["textureProjLodOffset"].push_back("OpImageSampleProjExplicitLod Lod|ConstOffset");
m_mappings["textureGrad"].push_back("OpImageSampleExplicitLod Grad");
m_mappings["textureGradOffset"].push_back("OpImageSampleExplicitLod Grad|ConstOffset");
m_mappings["textureProjGrad"].push_back("OpImageSampleProjExplicitLod Grad");
m_mappings["textureProjGradOffset"].push_back("OpImageSampleProjExplicitLod Grad|ConstOffset");
m_mappings["textureGather"].push_back("OpImageGather");
m_mappings["textureGatherOffset"].push_back("OpImageGather ConstOffset");
m_mappings["atomicCounterIncrement"].push_back("OpAtomicIIncrement");
m_mappings["atomicCounterDecrement"].push_back("OpAtomicIDecrement");
m_mappings["atomicCounter"].push_back("OpAtomicLoad");
m_mappings["atomicAdd"].push_back("OpAtomicIAdd");
m_mappings["atomicMin"].push_back("OpAtomicUMin");
m_mappings["atomicMax"].push_back("OpAtomicUMax");
m_mappings["atomicAnd"].push_back("OpAtomicAnd");
m_mappings["atomicOr"].push_back("OpAtomicOr");
m_mappings["atomicXor"].push_back("OpAtomicXor");
m_mappings["atomicExchange"].push_back("OpAtomicExchange");
m_mappings["atomicCompSwap"].push_back("OpAtomicCompareExchange");
m_mappings["imageSize"].push_back("OpImageQuerySize");
m_mappings["imageSamples"].push_back("OpImageQuerySamples");
m_mappings["imageLoad"].push_back("OpImageRead");
m_mappings["imageStore"].push_back("OpImageWrite");
m_mappings["imageAtomicAdd"].push_back("OpAtomicIAdd");
m_mappings["imageAtomicMin"].push_back("OpAtomicUMin");
m_mappings["imageAtomicMax"].push_back("OpAtomicUMax");
m_mappings["imageAtomicAnd"].push_back("OpAtomicAnd");
m_mappings["imageAtomicOr"].push_back("OpAtomicOr");
m_mappings["imageAtomicXor"].push_back("OpAtomicXor");
m_mappings["imageAtomicExchange"].push_back("OpAtomicExchange");
m_mappings["imageAtomicCompSwap"].push_back("OpAtomicCompareExchange");
m_mappings["dFdx"].push_back("OpDPdx");
m_mappings["dFdy"].push_back("OpDPdy");
m_mappings["dFdxFine"].push_back("OpDPdxFine");
m_mappings["dFdyFine"].push_back("OpDPdyFine");
m_mappings["dFdxCoarse"].push_back("OpDPdxCoarse");
m_mappings["dFdyCoarse"].push_back("OpDPdyCoarse");
m_mappings["fwidth"].push_back("OpFwidth");
m_mappings["fwidthFine"].push_back("OpFwidthFine");
m_mappings["fwidthCoarse"].push_back("OpFwidthCoarse");
m_mappings["interpolateAtCentroid"].push_back("OpExtInst InterpolateAtCentroid");
m_mappings["interpolateAtSample"].push_back("OpExtInst InterpolateAtSample");
m_mappings["interpolateAtOffset"].push_back("OpExtInst InterpolateAtOffset");
m_mappings["EmitStreamVertex"].push_back("OpEmitStreamVertex");
m_mappings["EndStreamPrimitive"].push_back("OpEndStreamPrimitive");
m_mappings["EmitVertex"].push_back("OpEmitVertex");
m_mappings["EndPrimitive"].push_back("OpEndPrimitive");
m_mappings["barrier"].push_back("OpControlBarrier");
m_mappings["memoryBarrier"].push_back("OpMemoryBarrier");
m_mappings["memoryBarrierAtomicCounter"].push_back("OpMemoryBarrier");
m_mappings["memoryBarrierBuffer"].push_back("OpMemoryBarrier");
m_mappings["memoryBarrierShared"].push_back("OpMemoryBarrier");
m_mappings["memoryBarrierImage"].push_back("OpMemoryBarrier");
m_mappings["groupMemoryBarrier"].push_back("OpMemoryBarrier");
// Add a space prefix and parenthesis sufix to avoid searching for similar names
SpirVMapping tempMappings;
SpirVMapping::iterator it;
for (it = m_mappings.begin(); it != m_mappings.end(); ++it)
{
tempMappings[std::string(" ") + it->first + "("] = it->second;
}
m_mappings = tempMappings;
}
/** Constructor.
*
* @param context Rendering context
* @param name Test name
* @param description Test description
*/
SpirvGlslToSpirVSpecializationConstantsTest::SpirvGlslToSpirVSpecializationConstantsTest(deqp::Context& context)
: TestCase(context, "spirv_glsl_to_spirv_specialization_constants_test",
"Test verifies if constant specialization feature works as expected.")
{
/* Left blank intentionally */
}
/** Stub init method */
void SpirvGlslToSpirVSpecializationConstantsTest::init()
{
if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gl_spirv"))
TCU_THROW(NotSupportedError, "GL_ARB_gl_spirv is not supported");
const Functions& gl = m_context.getRenderContext().getFunctions();
m_vertex = "#version 450\n"
"\n"
"layout (location = 0) in vec3 position;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(position, 1.0);\n"
"}\n";
m_fragment = "#version 450\n"
"\n"
"layout (constant_id = 10) const int red = 255;\n"
"\n"
"layout (location = 0) out vec4 fragColor;\n"
"\n"
"void main()\n"
"{\n"
" fragColor = vec4(float(red) / 255, 0.0, 1.0, 1.0);\n"
"}\n";
gl.genTextures(1, &m_texture);
GLU_EXPECT_NO_ERROR(gl.getError(), "genTextures");
gl.bindTexture(GL_TEXTURE_2D, m_texture);
GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture");
gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 32, 32);
GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage2D");
gl.genFramebuffers(1, &m_fbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "genFramenuffers");
gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer");
gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture2D");
gl.viewport(0, 0, 32, 32);
GLU_EXPECT_NO_ERROR(gl.getError(), "viewport");
}
/** Stub de-init method */
void SpirvGlslToSpirVSpecializationConstantsTest::deinit()
{
const Functions& gl = m_context.getRenderContext().getFunctions();
if (m_fbo)
{
gl.deleteFramebuffers(1, &m_fbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "deleteFramebuffers");
}
if (m_texture)
{
gl.deleteTextures(1, &m_texture);
GLU_EXPECT_NO_ERROR(gl.getError(), "deleteTextures");
}
}
/** Executes test iteration.
*
* @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
*/
tcu::TestNode::IterateResult SpirvGlslToSpirVSpecializationConstantsTest::iterate()
{
const Functions& gl = m_context.getRenderContext().getFunctions();
const GLfloat vertices[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f };
GLuint vao;
gl.genVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays");
gl.bindVertexArray(vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray");
GLuint vbo;
gl.genBuffers(1, &vbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers");
gl.bindBuffer(GL_ARRAY_BUFFER, vbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer");
gl.bufferData(GL_ARRAY_BUFFER, 9 * sizeof(GLfloat), (GLvoid*)vertices, GL_DYNAMIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData");
ShaderBinary vertexBinary;
ShaderBinary fragmentBinary;
#if defined DEQP_HAVE_GLSLANG
{
vertexBinary = glslangUtils::makeSpirV(m_context.getTestContext().getLog(), VertexSource(m_vertex));
fragmentBinary = glslangUtils::makeSpirV(m_context.getTestContext().getLog(), FragmentSource(m_fragment));
}
#else // DEQP_HAVE_GLSLANG
{
tcu::Archive& archive = m_testCtx.getArchive();
vertexBinary =
commonUtils::readSpirV(archive.getResource("spirv/glsl_to_spirv_specialization_constants/vertex.nspv"));
fragmentBinary =
commonUtils::readSpirV(archive.getResource("spirv/glsl_to_spirv_specialization_constants/fragment.nspv"));
}
#endif // DEQP_HAVE_GLSLANG
fragmentBinary << SpecializationData(10, 128);
ProgramBinaries binaries;
binaries << vertexBinary;
binaries << fragmentBinary;
ShaderProgram spirvProgram(gl, binaries);
if (!spirvProgram.isOk())
{
m_testCtx.getLog() << tcu::TestLog::Message << "Shader compilation failed.\n"
<< "Vertex:\n"
<< m_vertex.c_str() << "Fragment:\n"
<< m_fragment.c_str() << "InfoLog:\n"
<< spirvProgram.getShaderInfo(SHADERTYPE_VERTEX).infoLog << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
gl.useProgram(spirvProgram.getProgram());
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram");
gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor");
gl.clear(GL_COLOR_BUFFER_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "glClear");
gl.enableVertexAttribArray(0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray");
gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, DE_NULL);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer");
gl.drawArrays(GL_TRIANGLES, 0, 3);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArray");
gl.disableVertexAttribArray(0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDisableVertexAttribArray");
GLuint output;
gl.readPixels(16, 16, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)&output);
GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels");
if (output != 0xFFFF0080)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "Color value read from framebuffer is wrong. Expected: " << 0xFFFF0080
<< ", Read: " << output << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
return STOP;
}
/** Constructor.
*
* @param context Rendering context
* @param name Test name
* @param description Test description
*/
SpirvValidationBuiltInVariableDecorationsTest::SpirvValidationBuiltInVariableDecorationsTest(deqp::Context& context)
: TestCase(context, "spirv_validation_builtin_variable_decorations_test",
"Test verifies if Spir-V built in variable decorations works as expected.")
{
/* Left blank intentionally */
}
/** Stub init method */
void SpirvValidationBuiltInVariableDecorationsTest::init()
{
if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gl_spirv"))
TCU_THROW(NotSupportedError, "GL_ARB_gl_spirv is not supported");
m_compute = "#version 450\n"
"\n"
"layout (local_size_x = 1, local_size_y = 2, local_size_z = 1) in;\n"
"\n"
"layout (location = 0, rgba8ui) uniform uimage2D img0;\n"
"layout (location = 1, rgba8ui) uniform uimage2D img1;\n"
"layout (location = 2, rgba8ui) uniform uimage2D img2;\n"
"layout (location = 3, rgba8ui) uniform uimage2D img3;\n"
"layout (location = 4, rgba8ui) uniform uimage2D img4;\n"
"\n"
"void main()\n"
"{\n"
" ivec3 point = ivec3(gl_GlobalInvocationID);\n"
" uvec3 color0 = uvec3(gl_NumWorkGroups);\n"
" uvec3 color1 = uvec3(gl_WorkGroupSize);\n"
" uvec3 color2 = uvec3(gl_WorkGroupID);\n"
" uvec3 color3 = uvec3(gl_LocalInvocationID);\n"
" uvec3 color4 = uvec3(gl_LocalInvocationIndex);\n"
" imageStore(img0, point.xy, uvec4(color0, 0xFF));\n"
" imageStore(img1, point.xy, uvec4(color1, 0xFF));\n"
" imageStore(img2, point.xy, uvec4(color2, 0xFF));\n"
" imageStore(img3, point.xy, uvec4(color3, 0xFF));\n"
" imageStore(img4, point.xy, uvec4(color4, 0xFF));\n"
" memoryBarrier();\n"
"}\n";
m_vertex = "#version 450\n"
"\n"
"layout (location = 0) in vec3 position;\n"
"\n"
"layout (location = 1) out vec4 vColor;\n"
"\n"
"void main()\n"
"{\n"
" gl_PointSize = 10.0f;\n"
" gl_Position = vec4(position.x, position.y + 0.3 * gl_InstanceID, position.z, 1.0);\n"
" gl_ClipDistance[0] = <CLIP_DISTANCE>;\n"
" gl_CullDistance[0] = <CULL_DISTANCE>;\n"
" vColor = <VERTEX_COLOR>;\n"
"}\n";
m_tesselationCtrl = "#version 450\n"
"\n"
"layout (vertices = 3) out;\n"
"\n"
"layout (location = 1) in vec4 vColor[];\n"
"layout (location = 2) out vec4 tcColor[];\n"
"\n"
"void main()\n"
"{\n"
" tcColor[gl_InvocationID] = vColor[gl_InvocationID];\n"
" tcColor[gl_InvocationID].r = float(gl_PatchVerticesIn) / 3;\n"
"\n"
" if (gl_InvocationID == 0) {\n"
" gl_TessLevelOuter[0] = 1.0;\n"
" gl_TessLevelOuter[1] = 1.0;\n"
" gl_TessLevelOuter[2] = 1.0;\n"
" gl_TessLevelInner[0] = 1.0;\n"
" }\n"
"\n"
" gl_out[gl_InvocationID].gl_ClipDistance[0] = gl_in[gl_InvocationID].gl_ClipDistance[0];\n"
" gl_out[gl_InvocationID].gl_CullDistance[0] = gl_in[gl_InvocationID].gl_CullDistance[0];\n"
" gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
"}\n";
m_tesselationEval = "#version 450\n"
"\n"
"layout (triangles) in;\n"
"\n"
"layout (location = 2) in vec4 tcColor[];\n"
"layout (location = 3) out vec4 teColor;\n"
"\n"
"void main()\n"
"{\n"
" teColor = tcColor[0];\n"
"\n"
" gl_ClipDistance[0] = gl_in[0].gl_ClipDistance[0];\n"
" gl_CullDistance[0] = gl_in[0].gl_CullDistance[0];\n"
" gl_Position = gl_TessCoord.x * gl_in[0].gl_Position +\n"
" gl_TessCoord.y * gl_in[1].gl_Position +\n"
" gl_TessCoord.z * gl_in[2].gl_Position;\n"
"}\n";
m_geometry = "#version 450\n"
"\n"
"layout (triangles) in;\n"
"layout (triangle_strip, max_vertices = 3) out;\n"
"\n"
"layout (location = 3) in vec4 teColor[];\n"
"layout (location = 4) out vec4 gColor;\n"
"\n"
"void main()\n"
"{\n"
" gColor = teColor[0];\n"
" gColor.b = float(gl_PrimitiveIDIn);\n"
"\n"
" gl_Layer = 1;\n"
" gl_ViewportIndex = 1;\n"
"\n"
" for (int i = 0; i < 3; ++i) {\n"
" gl_ClipDistance[0] = gl_in[i].gl_ClipDistance[0];\n"
" gl_CullDistance[0] = gl_in[i].gl_CullDistance[0];\n"
" gl_Position = gl_in[i].gl_Position;\n"
" EmitVertex();\n"
" }\n"
" EndPrimitive();\n"
"}\n";
m_fragment = "#version 450\n"
"\n"
"layout (location = <INPUT_LOCATION>) in vec4 <INPUT_NAME>;\n"
"layout (location = 0) out vec4 fColor;\n"
"\n"
"void main()\n"
"{\n"
" vec4 color = <INPUT_NAME>;\n"
" <ADDITIONAL_CODE>\n"
" fColor = color;\n"
"}\n";
ValidationStruct validationCompute(&SpirvValidationBuiltInVariableDecorationsTest::validComputeFunc);
validationCompute.shaders.push_back(ComputeSource(m_compute));
m_validations.push_back(validationCompute);
std::string clipNegativeVertex = m_vertex;
std::string clipNegativeFragment = m_fragment;
commonUtils::replaceToken("<CLIP_DISTANCE>", "-1.0", clipNegativeVertex);
commonUtils::replaceToken("<CULL_DISTANCE>", "1.0", clipNegativeVertex);
commonUtils::replaceToken("<VERTEX_COLOR>", "vec4(1.0, 1.0, 1.0, 1.0)", clipNegativeVertex);
commonUtils::replaceToken("<INPUT_LOCATION>", "1", clipNegativeFragment);
commonUtils::replaceToken("<INPUT_NAME>", "vColor", clipNegativeFragment);
commonUtils::replaceToken("<ADDITIONAL_CODE>", "", clipNegativeFragment);
ValidationStruct validationClipNegative(&SpirvValidationBuiltInVariableDecorationsTest::validPerVertexFragFunc);
validationClipNegative.shaders.push_back(VertexSource(clipNegativeVertex));
validationClipNegative.shaders.push_back(FragmentSource(clipNegativeFragment));
validationClipNegative.outputs.push_back(ValidationOutputStruct(32, 32, 0xFF000000));
m_validations.push_back(validationClipNegative);
std::string perVertexFragVertex = m_vertex;
std::string perVertexFragFragment = m_fragment;
std::string fragCode = "vec4 coord = gl_FragCoord;\n"
"color = vec4(0.0, coord.s / 64, coord.t / 64, 1.0);\n";
commonUtils::replaceToken("<CLIP_DISTANCE>", "1.0", perVertexFragVertex);
commonUtils::replaceToken("<CULL_DISTANCE>", "1.0", perVertexFragVertex);
commonUtils::replaceToken("<VERTEX_COLOR>", "vec4(1.0, 1.0, 1.0, 1.0)", perVertexFragVertex);
commonUtils::replaceToken("<INPUT_LOCATION>", "1", perVertexFragFragment);
commonUtils::replaceToken("<INPUT_NAME>", "vColor", perVertexFragFragment);
commonUtils::replaceToken("<ADDITIONAL_CODE>", fragCode.c_str(), perVertexFragFragment);
ValidationStruct validationFrag(&SpirvValidationBuiltInVariableDecorationsTest::validPerVertexFragFunc);
validationFrag.shaders.push_back(VertexSource(perVertexFragVertex));
validationFrag.shaders.push_back(FragmentSource(perVertexFragFragment));
validationFrag.outputs.push_back(ValidationOutputStruct(32, 32, 0xFF7F7F00));
m_validations.push_back(validationFrag);
std::string perVertexPointVertex = m_vertex;
std::string perVertexPointFragment = m_fragment;
std::string pointCode = "vec2 coord = gl_PointCoord;\n"
"color.b = coord.s * coord.t;\n";
commonUtils::replaceToken("<CLIP_DISTANCE>", "1.0", perVertexPointVertex);
commonUtils::replaceToken("<CULL_DISTANCE>", "1.0", perVertexPointVertex);
commonUtils::replaceToken("<VERTEX_COLOR>", "vec4(float(gl_VertexID) / 3, 0.0, 0.0, 1.0)", perVertexPointVertex);
commonUtils::replaceToken("<INPUT_LOCATION>", "1", perVertexPointFragment);
commonUtils::replaceToken("<INPUT_NAME>", "vColor", perVertexPointFragment);
commonUtils::replaceToken("<ADDITIONAL_CODE>", pointCode.c_str(), perVertexPointFragment);
ValidationStruct validationPoint(&SpirvValidationBuiltInVariableDecorationsTest::validPerVertexPointFunc);
validationPoint.shaders.push_back(VertexSource(perVertexPointVertex));
validationPoint.shaders.push_back(FragmentSource(perVertexPointFragment));
validationPoint.outputs.push_back(ValidationOutputStruct(64, 64, 0xFF3F0055));
validationPoint.outputs.push_back(ValidationOutputStruct(45, 45, 0xFF3F0000));
validationPoint.outputs.push_back(ValidationOutputStruct(83, 83, 0xFF3F00AA));
m_validations.push_back(validationPoint);
std::string tessGeomVertex = m_vertex;
std::string tessGeomFragment = m_fragment;
commonUtils::replaceToken("<CLIP_DISTANCE>", "1.0", tessGeomVertex);
commonUtils::replaceToken("<CULL_DISTANCE>", "1.0", tessGeomVertex);
commonUtils::replaceToken("<VERTEX_COLOR>", "vec4(1.0, 1.0, 1.0, 1.0)", tessGeomVertex);
commonUtils::replaceToken("<INPUT_LOCATION>", "4", tessGeomFragment);
commonUtils::replaceToken("<INPUT_NAME>", "gColor", tessGeomFragment);
commonUtils::replaceToken("<ADDITIONAL_CODE>", "", tessGeomFragment);
ValidationStruct validationTessGeom(&SpirvValidationBuiltInVariableDecorationsTest::validTesselationGeometryFunc);
validationTessGeom.shaders.push_back(VertexSource(tessGeomVertex));
validationTessGeom.shaders.push_back(TessellationControlSource(m_tesselationCtrl));
validationTessGeom.shaders.push_back(TessellationEvaluationSource(m_tesselationEval));
validationTessGeom.shaders.push_back(GeometrySource(m_geometry));
validationTessGeom.shaders.push_back(FragmentSource(tessGeomFragment));
validationTessGeom.outputs.push_back(ValidationOutputStruct(48, 32, 1, 0xFF00FFFF));
m_validations.push_back(validationTessGeom);
std::string multisampleVertex = m_vertex;
std::string multisampleFragment = m_fragment;
std::string samplingCode = "if (gl_SampleID == 0)\n"
"{\n"
" vec2 sampPos = gl_SamplePosition;\n"
" color = vec4(1.0, sampPos.x, sampPos.y, 1.0);\n"
"}\n"
"else\n"
"{\n"
" color = vec4(0.0, 1.0, 0.0, 1.0);\n"
"}\n"
"gl_SampleMask[0] = 0x02;";
commonUtils::replaceToken("<CLIP_DISTANCE>", "1.0", multisampleVertex);
commonUtils::replaceToken("<CULL_DISTANCE>", "1.0", multisampleVertex);
commonUtils::replaceToken("<VERTEX_COLOR>", "vec4(1.0, 1.0, 1.0, 1.0)", multisampleVertex);
commonUtils::replaceToken("<INPUT_LOCATION>", "1", multisampleFragment);
commonUtils::replaceToken("<INPUT_NAME>", "vColor", multisampleFragment);
commonUtils::replaceToken("<ADDITIONAL_CODE>", samplingCode.c_str(), multisampleFragment);
ValidationStruct validationMultisample(&SpirvValidationBuiltInVariableDecorationsTest::validMultiSamplingFunc);
validationMultisample.shaders.push_back(VertexSource(multisampleVertex));
validationMultisample.shaders.push_back(FragmentSource(multisampleFragment));
validationMultisample.outputs.push_back(ValidationOutputStruct(16, 16, 0xFF00BC00));
m_validations.push_back(validationMultisample);
m_mappings["gl_NumWorkGroups"].push_back("BuiltIn NumWorkgroups");
m_mappings["gl_WorkGroupSize"].push_back("BuiltIn WorkgroupSize");
m_mappings["gl_WorkGroupID"].push_back("BuiltIn WorkgroupId");
m_mappings["gl_LocalInvocationID"].push_back("BuiltIn LocalInvocationId");
m_mappings["gl_GlobalInvocationID"].push_back("BuiltIn GlobalInvocationId");
m_mappings["gl_LocalInvocationIndex"].push_back("BuiltIn LocalInvocationIndex");
m_mappings["gl_VertexID"].push_back("BuiltIn VertexId");
m_mappings["gl_InstanceID"].push_back("BuiltIn InstanceId");
m_mappings["gl_Position"].push_back("BuiltIn Position");
m_mappings["gl_PointSize"].push_back("BuiltIn PointSize");
m_mappings["gl_ClipDistance"].push_back("BuiltIn ClipDistance");
m_mappings["gl_CullDistance"].push_back("BuiltIn CullDistance");
m_mappings["gl_PrimitiveIDIn"].push_back("BuiltIn PrimitiveId");
m_mappings["gl_InvocationID"].push_back("BuiltIn InvocationId");
m_mappings["gl_Layer"].push_back("BuiltIn Layer");
m_mappings["gl_ViewportIndex"].push_back("BuiltIn ViewportIndex");
m_mappings["gl_PatchVerticesIn"].push_back("BuiltIn PatchVertices");
m_mappings["gl_TessLevelOuter"].push_back("BuiltIn TessLevelOuter");
m_mappings["gl_TessLevelInner"].push_back("BuiltIn TessLevelInner");
m_mappings["gl_TessCoord"].push_back("BuiltIn TessCoord");
m_mappings["gl_FragCoord"].push_back("BuiltIn FragCoord");
m_mappings["gl_FrontFacing"].push_back("BuiltIn FrontFacing");
m_mappings["gl_PointCoord"].push_back("BuiltIn PointCoord");
m_mappings["gl_SampleId"].push_back("BuiltIn SampleId");
m_mappings["gl_SamplePosition"].push_back("BuiltIn SamplePosition");
m_mappings["gl_SampleMask"].push_back("BuiltIn SampleMask");
}
/** Stub de-init method */
void SpirvValidationBuiltInVariableDecorationsTest::deinit()
{
}
/** Executes test iteration.
*
* @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
*/
tcu::TestNode::IterateResult SpirvValidationBuiltInVariableDecorationsTest::iterate()
{
const Functions& gl = m_context.getRenderContext().getFunctions();
GLuint vao;
gl.genVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays");
gl.bindVertexArray(vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray");
GLuint vbo;
gl.genBuffers(1, &vbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers");
gl.bindBuffer(GL_ARRAY_BUFFER, vbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer");
enum Iterates
{
ITERATE_GLSL,
ITERATE_SPIRV,
ITERATE_LAST
};
bool result = true;
for (int v = 0; v < m_validations.size(); ++v)
{
for (int it = ITERATE_GLSL; it < ITERATE_LAST; ++it)
{
ShaderProgram* program = DE_NULL;
if (it == ITERATE_GLSL)
{
ProgramSources sources;
for (int s = 0; s < m_validations[v].shaders.size(); ++s)
sources << m_validations[v].shaders[s];
program = new ShaderProgram(gl, sources);
}
else if (it == ITERATE_SPIRV)
{
std::vector<ShaderBinary> binariesVec;
#if defined DEQP_HAVE_GLSLANG
ProgramBinaries binaries;
for (int s = 0; s < m_validations[v].shaders.size(); ++s)
{
ShaderBinary shaderBinary =
glslangUtils::makeSpirV(m_context.getTestContext().getLog(), m_validations[v].shaders[s]);
binariesVec.push_back(shaderBinary);
binaries << shaderBinary;
}
#else // DEQP_HAVE_GLSLANG
tcu::Archive& archive = m_testCtx.getArchive();
ProgramBinaries binaries;
for (int s = 0; s < m_validations[v].shaders.size(); ++s)
{
std::stringstream ss;
ss << "spirv/spirv_validation_builtin_variable_decorations/shader_" << v << "_" << s << ".nspv";
ShaderBinary shaderBinary = commonUtils::readSpirV(archive.getResource(ss.str().c_str()));
binariesVec.push_back(shaderBinary);
binaries << shaderBinary;
}
#endif // DEQP_HAVE_GLSLANG
program = new ShaderProgram(gl, binaries);
#if defined DEQP_HAVE_SPIRV_TOOLS
std::string spirvSource;
for (int s = 0; s < m_validations[v].shaders.size(); ++s)
{
ShaderSource shaderSource = m_validations[v].shaders[s];
glslangUtils::spirvDisassemble(spirvSource, binariesVec[s].binary);
if (!glslangUtils::verifyMappings(shaderSource.source, spirvSource, m_mappings, true))
{
m_testCtx.getLog() << tcu::TestLog::Message << "Mappings for shader failed.\n"
<< "GLSL source:\n"
<< shaderSource.source.c_str() << "\n"
<< "SpirV source:\n"
<< spirvSource.c_str() << tcu::TestLog::EndMessage;
TCU_THROW(InternalError, "Mappings for shader failed.");
}
}
#endif // DEQP_HAVE_SPIRV_TOOLS
}
if (!program->isOk())
{
std::stringstream message;
message << "Shader build failed.\n";
if (program->hasShader(SHADERTYPE_COMPUTE))
message << "ComputeInfo: " << program->getShaderInfo(SHADERTYPE_COMPUTE).infoLog << "\n"
<< "ComputeSource: " << program->getShader(SHADERTYPE_COMPUTE)->getSource() << "\n";
if (program->hasShader(SHADERTYPE_VERTEX))
message << "VertexInfo: " << program->getShaderInfo(SHADERTYPE_VERTEX).infoLog << "\n"
<< "VertexSource: " << program->getShader(SHADERTYPE_VERTEX)->getSource() << "\n";
if (program->hasShader(SHADERTYPE_TESSELLATION_CONTROL))
message << "TesselationCtrlInfo: "
<< program->getShaderInfo(SHADERTYPE_TESSELLATION_CONTROL).infoLog << "\n"
<< "TesselationCtrlSource: "
<< program->getShader(SHADERTYPE_TESSELLATION_CONTROL)->getSource() << "\n";
if (program->hasShader(SHADERTYPE_TESSELLATION_EVALUATION))
message << "TesselationEvalInfo: "
<< program->getShaderInfo(SHADERTYPE_TESSELLATION_EVALUATION).infoLog << "\n"
<< "TesselationEvalSource: "
<< program->getShader(SHADERTYPE_TESSELLATION_EVALUATION)->getSource() << "\n";
if (program->hasShader(SHADERTYPE_GEOMETRY))
message << "GeometryInfo: " << program->getShaderInfo(SHADERTYPE_GEOMETRY).infoLog << "\n"
<< "GeometrySource: " << program->getShader(SHADERTYPE_GEOMETRY)->getSource() << "\n";
if (program->hasShader(SHADERTYPE_FRAGMENT))
message << "FragmentInfo: " << program->getShaderInfo(SHADERTYPE_FRAGMENT).infoLog << "\n"
<< "FragmentSource: " << program->getShader(SHADERTYPE_FRAGMENT)->getSource() << "\n";
message << "ProgramInfo: " << program->getProgramInfo().infoLog;
m_testCtx.getLog() << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
gl.useProgram(program->getProgram());
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram");
ValidationFuncPtr funcPtr = m_validations[v].validationFuncPtr;
result = (this->*funcPtr)(m_validations[v].outputs);
if (program)
delete program;
if (!result)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Validation " << v << " failed!"
<< tcu::TestLog::EndMessage;
break;
}
}
}
if (vbo)
{
gl.deleteBuffers(1, &vbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers");
}
if (vao)
{
gl.deleteVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteVertexArrays");
}
if (result)
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
else
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
bool SpirvValidationBuiltInVariableDecorationsTest::validComputeFunc(ValidationOutputVec& outputs)
{
const Functions& gl = m_context.getRenderContext().getFunctions();
GLuint textures[5];
gl.genTextures(5, textures);
GLU_EXPECT_NO_ERROR(gl.getError(), "genTextures");
for (int i = 0; i < 5; ++i)
{
gl.bindTexture(GL_TEXTURE_2D, textures[i]);
GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture");
gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8UI, 4, 4);
GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage2D");
}
gl.bindImageTexture(0, textures[0], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8UI);
GLU_EXPECT_NO_ERROR(gl.getError<