You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
879 lines
34 KiB
879 lines
34 KiB
/*-------------------------------------------------------------------------
|
|
* drawElements Quality Program OpenGL ES 3.1 Module
|
|
* -------------------------------------------------
|
|
*
|
|
* Copyright 2017 The Android Open Source Project
|
|
*
|
|
* 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 Negative Compute tests.
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "es31fNegativeComputeTests.hpp"
|
|
#include "gluContextInfo.hpp"
|
|
#include "gluShaderProgram.hpp"
|
|
#include "glwDefs.hpp"
|
|
#include "glwEnums.hpp"
|
|
#include "tcuStringTemplate.hpp"
|
|
|
|
namespace deqp
|
|
{
|
|
|
|
using std::string;
|
|
using std::map;
|
|
|
|
namespace gles31
|
|
{
|
|
namespace Functional
|
|
{
|
|
namespace NegativeTestShared
|
|
{
|
|
namespace
|
|
{
|
|
|
|
using tcu::TestLog;
|
|
using namespace glw;
|
|
|
|
static const char* const vertexShaderSource = "${GLSL_VERSION_STRING}\n"
|
|
"\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" gl_Position = vec4(0.0);\n"
|
|
"}\n";
|
|
|
|
static const char* const fragmentShaderSource = "${GLSL_VERSION_STRING}\n"
|
|
"precision mediump float;\n"
|
|
"layout(location = 0) out mediump vec4 fragColor;\n"
|
|
"\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" fragColor = vec4(1.0);\n"
|
|
"}\n";
|
|
|
|
static const char* const computeShaderSource = "${GLSL_VERSION_STRING}\n"
|
|
"layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
"}\n";
|
|
|
|
static const char* const invalidComputeShaderSource = "${GLSL_VERSION_STRING}\n"
|
|
"layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" highp uint var = -1;\n" // error
|
|
"}\n";
|
|
|
|
int getResourceLimit (NegativeTestContext& ctx, GLenum resource)
|
|
{
|
|
int limit = 0;
|
|
ctx.glGetIntegerv(resource, &limit);
|
|
|
|
return limit;
|
|
}
|
|
|
|
void verifyLinkError (NegativeTestContext& ctx, const glu::ShaderProgram& program)
|
|
{
|
|
bool testFailed = false;
|
|
|
|
tcu::TestLog& log = ctx.getLog();
|
|
log << program;
|
|
|
|
testFailed = program.getProgramInfo().linkOk;
|
|
|
|
if (testFailed)
|
|
{
|
|
const char* const message("Program was not expected to link.");
|
|
log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
|
|
ctx.fail(message);
|
|
}
|
|
}
|
|
|
|
void verifyCompileError (NegativeTestContext& ctx, const glu::ShaderProgram& program, glu::ShaderType shaderType)
|
|
{
|
|
bool testFailed = false;
|
|
|
|
tcu::TestLog& log = ctx.getLog();
|
|
log << program;
|
|
|
|
testFailed = program.getShaderInfo(shaderType).compileOk;
|
|
|
|
if (testFailed)
|
|
{
|
|
const char* const message("Program was not expected to compile.");
|
|
log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
|
|
ctx.fail(message);
|
|
}
|
|
}
|
|
|
|
string generateComputeShader (NegativeTestContext& ctx, const string& shaderDeclarations, const string& shaderBody)
|
|
{
|
|
const bool isES32 = glu::contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
|
|
const char* const shaderVersion = isES32
|
|
? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES)
|
|
: getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
|
|
|
|
std::ostringstream compShaderSource;
|
|
|
|
compShaderSource << shaderVersion << "\n"
|
|
<< "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
|
|
<< shaderDeclarations << "\n"
|
|
<< "void main (void)\n"
|
|
<< "{\n"
|
|
<< shaderBody
|
|
<< "}\n";
|
|
|
|
return compShaderSource.str();
|
|
}
|
|
|
|
string genBuiltInSource (glu::ShaderType shaderType)
|
|
{
|
|
std::ostringstream source;
|
|
source << "${GLSL_VERSION_STRING}\n";
|
|
|
|
switch (shaderType)
|
|
{
|
|
case glu::SHADERTYPE_VERTEX:
|
|
case glu::SHADERTYPE_FRAGMENT:
|
|
break;
|
|
|
|
case glu::SHADERTYPE_COMPUTE:
|
|
source << "layout (local_size_x = 1) in;\n";
|
|
break;
|
|
|
|
case glu::SHADERTYPE_GEOMETRY:
|
|
source << "layout(points) in;\n"
|
|
<< "layout(line_strip, max_vertices = 3) out;\n";
|
|
break;
|
|
|
|
case glu::SHADERTYPE_TESSELLATION_CONTROL:
|
|
source << "${GLSL_TESS_EXTENSION_STRING}\n"
|
|
<< "layout(vertices = 10) out;\n";
|
|
break;
|
|
|
|
case glu::SHADERTYPE_TESSELLATION_EVALUATION:
|
|
source << "${GLSL_TESS_EXTENSION_STRING}\n"
|
|
<< "layout(triangles) in;\n";
|
|
break;
|
|
|
|
default:
|
|
DE_FATAL("Unknown shader type");
|
|
break;
|
|
}
|
|
|
|
source << "\n"
|
|
<< "void main(void)\n"
|
|
<< "{\n"
|
|
<< "${COMPUTE_BUILT_IN_CONSTANTS_STRING}"
|
|
<< "}\n";
|
|
|
|
return source.str();
|
|
}
|
|
|
|
void exceed_uniform_block_limit (NegativeTestContext& ctx)
|
|
{
|
|
std::ostringstream shaderDecl;
|
|
std::ostringstream shaderBody;
|
|
|
|
shaderDecl << "layout(std140, binding = 0) uniform Block\n"
|
|
<< "{\n"
|
|
<< " highp vec4 val;\n"
|
|
<< "} block[" << getResourceLimit(ctx, GL_MAX_COMPUTE_UNIFORM_BLOCKS) + 1 << "];\n";
|
|
|
|
glu::ShaderProgram program(ctx.getRenderContext(), glu::ProgramSources()
|
|
<< glu::ComputeSource(generateComputeShader(ctx, shaderDecl.str(), shaderBody.str())));
|
|
|
|
ctx.beginSection("Link error is generated if a compute shader exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS.");
|
|
verifyLinkError(ctx, program);
|
|
ctx.endSection();
|
|
}
|
|
|
|
void exceed_shader_storage_block_limit (NegativeTestContext& ctx)
|
|
{
|
|
std::ostringstream shaderDecl;
|
|
std::ostringstream shaderBody;
|
|
|
|
shaderDecl << "layout(std140, binding = 0) buffer Block\n"
|
|
<< "{\n"
|
|
<< " highp vec4 val;\n"
|
|
<< "} block[" << getResourceLimit(ctx, GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS) + 1 << "];\n";
|
|
|
|
glu::ShaderProgram program(ctx.getRenderContext(), glu::ProgramSources()
|
|
<< glu::ComputeSource(generateComputeShader(ctx, shaderDecl.str(), shaderBody.str())));
|
|
|
|
ctx.beginSection("Link error is generated if compute shader exceeds GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS.");
|
|
verifyLinkError(ctx, program);
|
|
ctx.endSection();
|
|
}
|
|
|
|
void exceed_texture_image_units_limit (NegativeTestContext& ctx)
|
|
{
|
|
const int limit = getResourceLimit(ctx, GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS) + 1;
|
|
std::ostringstream shaderDecl;
|
|
std::ostringstream shaderBody;
|
|
|
|
shaderDecl << "layout(binding = 0) "
|
|
<< "uniform highp sampler2D u_sampler[" << limit + 1 << "];\n"
|
|
<< "\n"
|
|
<< "layout(binding = 0) buffer Output {\n"
|
|
<< " vec4 values[ " << limit + 1 << " ];\n"
|
|
<< "} sb_out;\n";
|
|
|
|
for (int i = 0; i < limit + 1; ++i)
|
|
shaderBody << " sb_out.values[" << i << "] = texture(u_sampler[" << i << "], vec2(1.0f));\n";
|
|
|
|
glu::ShaderProgram program(ctx.getRenderContext(), glu::ProgramSources()
|
|
<< glu::ComputeSource(generateComputeShader(ctx, shaderDecl.str(), shaderBody.str())));
|
|
|
|
tcu::TestLog& log = ctx.getLog();
|
|
log << tcu::TestLog::Message << "Possible link error is generated if compute shader exceeds GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS." << tcu::TestLog::EndMessage;
|
|
log << program;
|
|
|
|
if (program.getProgramInfo().linkOk)
|
|
{
|
|
log << tcu::TestLog::Message << "Quality Warning: program was not expected to link." << tcu::TestLog::EndMessage;
|
|
ctx.glUseProgram(program.getProgram());
|
|
ctx.expectError(GL_NO_ERROR);
|
|
|
|
ctx.beginSection("GL_INVALID_OPERATION error is generated if the sum of the number of active samplers for each active program exceeds the maximum number of texture image units allowed");
|
|
ctx.glDispatchCompute(1, 1, 1);
|
|
ctx.expectError(GL_INVALID_OPERATION);
|
|
ctx.endSection();
|
|
}
|
|
}
|
|
|
|
void exceed_image_uniforms_limit (NegativeTestContext& ctx)
|
|
{
|
|
const int limit = getResourceLimit(ctx, GL_MAX_COMPUTE_IMAGE_UNIFORMS);
|
|
std::ostringstream shaderDecl;
|
|
std::ostringstream shaderBody;
|
|
|
|
shaderDecl << "layout(rgba8, binding = 0) "
|
|
<< "uniform readonly highp image2D u_image[" << limit + 1 << "];\n"
|
|
<< "\n"
|
|
<< "layout(binding = 0) buffer Output {\n"
|
|
<< " float values[" << limit + 1 << "];\n"
|
|
<< "} sb_out;\n";
|
|
|
|
for (int i = 0; i < limit + 1; ++i)
|
|
shaderBody << " sb_out.values[" << i << "]" << " = imageLoad(u_image[" << i << "], ivec2(gl_GlobalInvocationID.xy)).x;\n";
|
|
|
|
glu::ShaderProgram program(ctx.getRenderContext(), glu::ProgramSources()
|
|
<< glu::ComputeSource(generateComputeShader(ctx, shaderDecl.str(), shaderBody.str())));
|
|
|
|
ctx.beginSection("Link error is generated if compute shader exceeds GL_MAX_COMPUTE_IMAGE_UNIFORMS.");
|
|
verifyLinkError(ctx, program);
|
|
ctx.endSection();
|
|
}
|
|
|
|
void exceed_shared_memory_size_limit (NegativeTestContext& ctx)
|
|
{
|
|
const int limit = getResourceLimit(ctx, GL_MAX_COMPUTE_SHARED_MEMORY_SIZE);
|
|
const long numberOfElements = limit / sizeof(GLuint);
|
|
std::ostringstream shaderDecl;
|
|
std::ostringstream shaderBody;
|
|
|
|
shaderDecl << "shared uint values[" << numberOfElements + 1 << "];\n"
|
|
<< "\n"
|
|
<< "layout(binding = 0) buffer Output {\n"
|
|
<< " uint values;\n"
|
|
<< "} sb_out;\n";
|
|
|
|
shaderBody << " sb_out.values = values[" << numberOfElements << "];\n";
|
|
|
|
glu::ShaderProgram program(ctx.getRenderContext(), glu::ProgramSources()
|
|
<< glu::ComputeSource(generateComputeShader(ctx, shaderDecl.str(), shaderBody.str())));
|
|
|
|
ctx.beginSection("Link error is generated if compute shader exceeds GL_MAX_COMPUTE_SHARED_MEMORY_SIZE.");
|
|
verifyLinkError(ctx, program);
|
|
ctx.endSection();
|
|
}
|
|
|
|
void exceed_uniform_components_limit (NegativeTestContext& ctx)
|
|
{
|
|
const int limit = getResourceLimit(ctx, GL_MAX_COMPUTE_UNIFORM_COMPONENTS);
|
|
std::ostringstream shaderDecl;
|
|
std::ostringstream shaderBody;
|
|
|
|
shaderDecl << "uniform highp uint u_value[" << limit + 1 << "];\n"
|
|
<< "\n"
|
|
<< "layout(binding = 0) buffer Output {\n"
|
|
<< " uint values[2];\n"
|
|
<< "} sb_out;\n";
|
|
|
|
shaderBody << " sb_out.values[0] = u_value[" << limit << "];\n";
|
|
shaderBody << " sb_out.values[1] = u_value[0];\n";
|
|
|
|
glu::ShaderProgram program(ctx.getRenderContext(), glu::ProgramSources()
|
|
<< glu::ComputeSource(generateComputeShader(ctx, shaderDecl.str(), shaderBody.str())));
|
|
|
|
ctx.beginSection("Link error is generated if compute shader exceeds GL_MAX_COMPUTE_UNIFORM_COMPONENTS.");
|
|
verifyLinkError(ctx, program);
|
|
ctx.endSection();
|
|
}
|
|
|
|
void exceed_atomic_counter_buffer_limit (NegativeTestContext& ctx)
|
|
{
|
|
const int limit = getResourceLimit(ctx, GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS);
|
|
std::ostringstream shaderDecl;
|
|
std::ostringstream shaderBody;
|
|
|
|
for (int i = 0; i < limit + 1; ++i)
|
|
{
|
|
shaderDecl << "layout(binding = " << i << ") "
|
|
<< "uniform atomic_uint u_atomic" << i << ";\n";
|
|
|
|
if (i == 0)
|
|
shaderBody << " uint oldVal = atomicCounterIncrement(u_atomic" << i << ");\n";
|
|
else
|
|
shaderBody << " oldVal = atomicCounterIncrement(u_atomic" << i << ");\n";
|
|
}
|
|
|
|
shaderBody << " sb_out.value = oldVal;\n";
|
|
|
|
shaderDecl << "\n"
|
|
<< "layout(binding = 0) buffer Output {\n"
|
|
<< " uint value;\n"
|
|
<< "} sb_out;\n";
|
|
|
|
glu::ShaderProgram program(ctx.getRenderContext(), glu::ProgramSources()
|
|
<< glu::ComputeSource(generateComputeShader(ctx, shaderDecl.str(), shaderBody.str())));
|
|
|
|
ctx.beginSection("Link error is generated if compute shader exceeds GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS.");
|
|
verifyLinkError(ctx, program);
|
|
ctx.endSection();
|
|
}
|
|
|
|
void exceed_atomic_counters_limit (NegativeTestContext& ctx)
|
|
{
|
|
std::ostringstream shaderDecl;
|
|
std::ostringstream shaderBody;
|
|
|
|
shaderDecl << "layout(binding = 0, offset = 0) uniform atomic_uint u_atomic0;\n"
|
|
<< "layout(binding = " << sizeof(GLuint) * getResourceLimit(ctx, GL_MAX_COMPUTE_ATOMIC_COUNTERS) << ", offset = 0) uniform atomic_uint u_atomic1;\n"
|
|
<< "\n"
|
|
<< "layout(binding = 0) buffer Output {\n"
|
|
<< " uint value;\n"
|
|
<< "} sb_out;\n";
|
|
|
|
shaderBody << " uint oldVal = 0u;\n"
|
|
<< " oldVal = atomicCounterIncrement(u_atomic0);\n"
|
|
<< " oldVal = atomicCounterIncrement(u_atomic1);\n"
|
|
<< " sb_out.value = oldVal;\n";
|
|
|
|
glu::ShaderProgram program(ctx.getRenderContext(), glu::ProgramSources()
|
|
<< glu::ComputeSource(generateComputeShader(ctx, shaderDecl.str(), shaderBody.str())));
|
|
|
|
ctx.beginSection("Link error is generated if compute shader exceeds GL_MAX_COMPUTE_ATOMIC_COUNTERS.");
|
|
verifyLinkError(ctx, program);
|
|
ctx.endSection();
|
|
}
|
|
|
|
void program_not_active (NegativeTestContext& ctx)
|
|
{
|
|
const bool isES32 = glu::contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
|
|
map<string, string> args;
|
|
args["GLSL_VERSION_STRING"] = isES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
|
|
|
|
const glu::VertexSource vertSource(tcu::StringTemplate(vertexShaderSource).specialize(args));
|
|
const glu::FragmentSource fragSource(tcu::StringTemplate(fragmentShaderSource).specialize(args));
|
|
|
|
glu::ProgramPipeline pipeline(ctx.getRenderContext());
|
|
|
|
glu::ShaderProgram vertProgram (ctx.getRenderContext(), glu::ProgramSources() << glu::ProgramSeparable(true) << vertSource);
|
|
glu::ShaderProgram fragProgram (ctx.getRenderContext(), glu::ProgramSources() << glu::ProgramSeparable(true) << fragSource);
|
|
|
|
tcu::TestLog& log = ctx.getLog();
|
|
log << vertProgram << fragProgram;
|
|
|
|
if (!vertProgram.isOk() || !fragProgram.isOk())
|
|
TCU_THROW(InternalError, "failed to build program");
|
|
|
|
ctx.glBindProgramPipeline(pipeline.getPipeline());
|
|
ctx.expectError(GL_NO_ERROR);
|
|
|
|
ctx.beginSection("Program not set at all");
|
|
{
|
|
ctx.beginSection("GL_INVALID_OPERATION is generated by glDispatchCompute if there is no active program for the compute shader stage.");
|
|
ctx.glDispatchCompute(1, 1, 1);
|
|
ctx.expectError(GL_INVALID_OPERATION);
|
|
ctx.endSection();
|
|
|
|
ctx.beginSection("GL_INVALID_OPERATION is generated by glDispatchComputeIndirect if there is no active program for the compute shader stage.");
|
|
GLintptr indirect = 0;
|
|
ctx.glDispatchComputeIndirect(indirect);
|
|
ctx.expectError(GL_INVALID_OPERATION);
|
|
ctx.endSection();
|
|
}
|
|
ctx.endSection();
|
|
|
|
ctx.beginSection("Program contains graphic pipeline stages");
|
|
{
|
|
ctx.glUseProgramStages(pipeline.getPipeline(), GL_VERTEX_SHADER_BIT, vertProgram.getProgram());
|
|
ctx.glUseProgramStages(pipeline.getPipeline(), GL_FRAGMENT_SHADER_BIT, fragProgram.getProgram());
|
|
ctx.expectError(GL_NO_ERROR);
|
|
|
|
ctx.beginSection("GL_INVALID_OPERATION is generated by glDispatchCompute if there is no active program for the compute shader stage.");
|
|
ctx.glDispatchCompute(1, 1, 1);
|
|
ctx.expectError(GL_INVALID_OPERATION);
|
|
ctx.endSection();
|
|
|
|
ctx.beginSection("GL_INVALID_OPERATION is generated by glDispatchComputeIndirect if there is no active program for the compute shader stage.");
|
|
GLintptr indirect = 0;
|
|
ctx.glDispatchComputeIndirect(indirect);
|
|
ctx.expectError(GL_INVALID_OPERATION);
|
|
ctx.endSection();
|
|
}
|
|
ctx.endSection();
|
|
|
|
ctx.glBindProgramPipeline(0);
|
|
ctx.expectError(GL_NO_ERROR);
|
|
}
|
|
|
|
void invalid_program_query (NegativeTestContext& ctx)
|
|
{
|
|
const bool isES32 = glu::contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
|
|
map<string, string> args;
|
|
args["GLSL_VERSION_STRING"] = isES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
|
|
|
|
GLint data[3] = { 0, 0, 0 };
|
|
|
|
ctx.beginSection("Compute shader that does not link");
|
|
{
|
|
const glu::ComputeSource compSource(tcu::StringTemplate(invalidComputeShaderSource).specialize(args));
|
|
glu::ShaderProgram invalidComputeProgram (ctx.getRenderContext(), glu::ProgramSources() << compSource);
|
|
|
|
tcu::TestLog& log = ctx.getLog();
|
|
log << invalidComputeProgram;
|
|
|
|
if (invalidComputeProgram.isOk())
|
|
TCU_THROW(InternalError, "program should not of built");
|
|
|
|
ctx.beginSection("GL_INVALID_OPERATION is generated if GL_COMPUTE_WORK_GROUP_SIZE is queried for a program which has not been linked properly.");
|
|
ctx.glGetProgramiv(invalidComputeProgram.getProgram(), GL_COMPUTE_WORK_GROUP_SIZE, &data[0]);
|
|
ctx.expectError(GL_INVALID_OPERATION);
|
|
ctx.endSection();
|
|
|
|
ctx.glUseProgram(0);
|
|
}
|
|
ctx.endSection();
|
|
|
|
ctx.beginSection("Compute shader not present");
|
|
{
|
|
const glu::VertexSource vertSource(tcu::StringTemplate(vertexShaderSource).specialize(args));
|
|
const glu::FragmentSource fragSource(tcu::StringTemplate(fragmentShaderSource).specialize(args));
|
|
glu::ShaderProgram graphicsPipelineProgram (ctx.getRenderContext(), glu::ProgramSources() << vertSource << fragSource);
|
|
|
|
tcu::TestLog& log = ctx.getLog();
|
|
log << graphicsPipelineProgram;
|
|
|
|
if (!graphicsPipelineProgram.isOk())
|
|
TCU_THROW(InternalError, "failed to build program");
|
|
|
|
ctx.beginSection("GL_INVALID_OPERATION is generated if GL_COMPUTE_WORK_GROUP_SIZE is queried for a program which has not been linked properly.");
|
|
ctx.glGetProgramiv(graphicsPipelineProgram.getProgram(), GL_COMPUTE_WORK_GROUP_SIZE, &data[0]);
|
|
ctx.expectError(GL_INVALID_OPERATION);
|
|
ctx.endSection();
|
|
|
|
ctx.glUseProgram(0);
|
|
}
|
|
ctx.endSection();
|
|
}
|
|
|
|
void invalid_dispatch_compute_indirect (NegativeTestContext& ctx)
|
|
{
|
|
const bool isES32 = glu::contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
|
|
map<string, string> args;
|
|
args["GLSL_VERSION_STRING"] = isES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
|
|
|
|
const glu::ComputeSource compSource(tcu::StringTemplate(computeShaderSource).specialize(args));
|
|
glu::ShaderProgram program(ctx.getRenderContext(), glu::ProgramSources() << compSource);
|
|
|
|
tcu::TestLog& log = ctx.getLog();
|
|
log << program;
|
|
|
|
if (!program.isOk())
|
|
TCU_THROW(InternalError, "failed to build program");
|
|
|
|
ctx.glUseProgram(program.getProgram());
|
|
ctx.expectError(GL_NO_ERROR);
|
|
|
|
static const struct
|
|
{
|
|
GLuint numGroupsX;
|
|
GLuint numGroupsY;
|
|
GLuint numGroupsZ;
|
|
} data = {0, 0, 0};
|
|
|
|
{
|
|
GLuint buffer;
|
|
ctx.glGenBuffers(1, &buffer);
|
|
ctx.glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0);
|
|
ctx.expectError(GL_NO_ERROR);
|
|
|
|
ctx.beginSection("GL_INVALID_OPERATION is generated by glDispatchComputeIndirect if zero is bound to GL_DISPATCH_INDIRECT_BUFFER.");
|
|
GLintptr indirect = 0;
|
|
ctx.glDispatchComputeIndirect(indirect);
|
|
ctx.expectError(GL_INVALID_OPERATION);
|
|
ctx.endSection();
|
|
|
|
ctx.glDeleteBuffers(1, &buffer);
|
|
}
|
|
|
|
{
|
|
GLuint buffer;
|
|
ctx.glGenBuffers(1, &buffer);
|
|
ctx.expectError(GL_NO_ERROR);
|
|
|
|
ctx.glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, buffer);
|
|
ctx.expectError(GL_NO_ERROR);
|
|
|
|
ctx.glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
|
|
ctx.expectError(GL_NO_ERROR);
|
|
|
|
ctx.beginSection("GL_INVALID_OPERATION is generated by glDispatchComputeIndirect if data is sourced beyond the end of the buffer object.");
|
|
GLintptr indirect = 1 << 10;
|
|
ctx.glDispatchComputeIndirect(indirect);
|
|
ctx.expectError(GL_INVALID_OPERATION);
|
|
ctx.endSection();
|
|
|
|
ctx.glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0);
|
|
ctx.glDeleteBuffers(1, &buffer);
|
|
}
|
|
|
|
{
|
|
ctx.beginSection("GL_INVALID_VALUE is generated by glDispatchComputeIndirect if the value of indirect is less than zero.");
|
|
GLintptr indirect = -1;
|
|
ctx.glDispatchComputeIndirect(indirect);
|
|
ctx.expectError(GL_INVALID_VALUE);
|
|
ctx.endSection();
|
|
}
|
|
|
|
{
|
|
GLuint buffer;
|
|
ctx.glGenBuffers(1, &buffer);
|
|
ctx.expectError(GL_NO_ERROR);
|
|
|
|
ctx.glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, buffer);
|
|
ctx.expectError(GL_NO_ERROR);
|
|
|
|
ctx.glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
|
|
ctx.expectError(GL_NO_ERROR);
|
|
|
|
ctx.beginSection("GL_INVALID_VALUE is generated by glDispatchComputeIndirect if indirect is not a multiple of the size, in basic machine units, of uint.");
|
|
GLintptr indirect = sizeof(data) + 1;
|
|
ctx.glDispatchComputeIndirect(indirect);
|
|
ctx.expectError(GL_INVALID_VALUE);
|
|
ctx.endSection();
|
|
|
|
ctx.glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0);
|
|
ctx.glDeleteBuffers(1, &buffer);
|
|
}
|
|
}
|
|
|
|
void invalid_maximum_work_group_counts (NegativeTestContext& ctx)
|
|
{
|
|
const bool isES32 = glu::contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
|
|
map<string, string> args;
|
|
args["GLSL_VERSION_STRING"] = isES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
|
|
|
|
const glu::ComputeSource compSource(tcu::StringTemplate(computeShaderSource).specialize(args));
|
|
glu::ShaderProgram program(ctx.getRenderContext(), glu::ProgramSources() << compSource);
|
|
|
|
tcu::TestLog& log = ctx.getLog();
|
|
log << program;
|
|
|
|
if (!program.isOk())
|
|
TCU_THROW(InternalError, "failed to build program");
|
|
|
|
ctx.glUseProgram(program.getProgram());
|
|
ctx.expectError(GL_NO_ERROR);
|
|
|
|
GLint workGroupCountX;
|
|
ctx.glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, (GLuint)0, &workGroupCountX);
|
|
ctx.expectError(GL_NO_ERROR);
|
|
|
|
ctx.beginSection("GL_INVALID_VALUE is generated by glDispatchCompute if <numGroupsX> array is larger than the maximum work group count for the x dimension.");
|
|
ctx.glDispatchCompute(workGroupCountX+1, 1, 1);
|
|
ctx.expectError(GL_INVALID_VALUE);
|
|
ctx.endSection();
|
|
|
|
GLint workGroupCountY;
|
|
ctx.glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, (GLuint)1, &workGroupCountY);
|
|
ctx.expectError(GL_NO_ERROR);
|
|
|
|
ctx.beginSection("GL_INVALID_VALUE is generated by glDispatchCompute if <numGroupsY> array is larger than the maximum work group count for the y dimension.");
|
|
ctx.glDispatchCompute(1, workGroupCountY+1, 1);
|
|
ctx.expectError(GL_INVALID_VALUE);
|
|
ctx.endSection();
|
|
|
|
GLint workGroupCountZ;
|
|
ctx.glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, (GLuint)2, &workGroupCountZ);
|
|
ctx.expectError(GL_NO_ERROR);
|
|
|
|
ctx.beginSection("GL_INVALID_VALUE is generated by glDispatchCompute if <numGroupsZ> array is larger than the maximum work group count for the z dimension.");
|
|
ctx.glDispatchCompute(1, 1, workGroupCountZ+1);
|
|
ctx.expectError(GL_INVALID_VALUE);
|
|
ctx.endSection();
|
|
}
|
|
|
|
void invalid_maximum_work_group_sizes (NegativeTestContext& ctx)
|
|
{
|
|
GLint maxWorkGroupSizeX;
|
|
ctx.glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, (GLuint)0, &maxWorkGroupSizeX);
|
|
ctx.expectError(GL_NO_ERROR);
|
|
|
|
GLint maxWorkGroupSizeY;
|
|
ctx.glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, (GLuint)1, &maxWorkGroupSizeY);
|
|
ctx.expectError(GL_NO_ERROR);
|
|
|
|
GLint maxWorkGroupSizeZ;
|
|
ctx.glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, (GLuint)2, &maxWorkGroupSizeZ);
|
|
ctx.expectError(GL_NO_ERROR);
|
|
|
|
GLint maxWorkGroupInvocations;
|
|
ctx.glGetIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, &maxWorkGroupInvocations);
|
|
ctx.expectError(GL_NO_ERROR);
|
|
|
|
DE_ASSERT(((deInt64) maxWorkGroupSizeX * maxWorkGroupSizeY * maxWorkGroupSizeZ) > maxWorkGroupInvocations );
|
|
|
|
const bool isES32 = glu::contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
|
|
const char* const shaderVersion = isES32
|
|
? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES)
|
|
: getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
|
|
|
|
static const struct
|
|
{
|
|
GLint x;
|
|
GLint y;
|
|
GLint z;
|
|
} localWorkGroupSizeCases[] =
|
|
{
|
|
{ maxWorkGroupSizeX+1, 1, 1 },
|
|
{ 1, maxWorkGroupSizeY+1, 1 },
|
|
{ 1, 1, maxWorkGroupSizeZ+1 },
|
|
{ maxWorkGroupSizeX, maxWorkGroupSizeY, maxWorkGroupSizeZ },
|
|
};
|
|
|
|
for (int testCase = 0; testCase < DE_LENGTH_OF_ARRAY(localWorkGroupSizeCases); ++testCase)
|
|
{
|
|
std::ostringstream compShaderSource;
|
|
|
|
compShaderSource << shaderVersion << "\n"
|
|
<< "layout(local_size_x = " << localWorkGroupSizeCases[testCase].x << ", local_size_y = " << localWorkGroupSizeCases[testCase].y << ", local_size_z = " << localWorkGroupSizeCases[testCase].z << ") in;\n"
|
|
<< "void main (void)\n"
|
|
<< "{\n"
|
|
<< "}\n";
|
|
|
|
const glu::ComputeSource compSource(compShaderSource.str());
|
|
glu::ShaderProgram program(ctx.getRenderContext(), glu::ProgramSources() << compSource);
|
|
|
|
if (testCase == DE_LENGTH_OF_ARRAY(localWorkGroupSizeCases)-1)
|
|
{
|
|
bool testFailed = false;
|
|
ctx.beginSection("A compile time or link error is generated if the maximum number of invocations in a single local work group (product of the three dimensions) is greater than GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS.");
|
|
|
|
ctx.getLog() << program;
|
|
testFailed = (program.getProgramInfo().linkOk) && (program.getShaderInfo(glu::SHADERTYPE_COMPUTE).compileOk);
|
|
|
|
if (testFailed)
|
|
{
|
|
const char* const message("Program was not expected to compile or link.");
|
|
ctx.getLog() << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
|
|
ctx.fail(message);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ctx.beginSection("A compile time error is generated if the fixed local group size of the shader in any dimension is greater than the maximum supported.");
|
|
verifyCompileError(ctx, program, glu::SHADERTYPE_COMPUTE);
|
|
}
|
|
|
|
ctx.endSection();
|
|
}
|
|
}
|
|
|
|
void invalid_layout_qualifiers (NegativeTestContext& ctx)
|
|
{
|
|
const bool isES32 = glu::contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
|
|
const char* const shaderVersion = isES32
|
|
? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES)
|
|
: getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
|
|
|
|
{
|
|
std::ostringstream compShaderSource;
|
|
compShaderSource << shaderVersion << "\n"
|
|
<< "void main (void)\n"
|
|
<< "{\n"
|
|
<< "}\n";
|
|
|
|
const glu::ComputeSource compSource(compShaderSource.str());
|
|
glu::ShaderProgram program(ctx.getRenderContext(), glu::ProgramSources() << compSource);
|
|
|
|
ctx.beginSection("A link error is generated if the compute shader program does not contain an input layout qualifier specifying a fixed local group size.");
|
|
verifyLinkError(ctx, program);
|
|
ctx.endSection();
|
|
}
|
|
|
|
{
|
|
std::ostringstream compShaderSource;
|
|
compShaderSource << shaderVersion << "\n"
|
|
<< "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
|
|
<< "layout(local_size_x = 2, local_size_y = 2, local_size_z = 2) in;\n"
|
|
<< "void main (void)\n"
|
|
<< "{\n"
|
|
<< "}\n";
|
|
|
|
const glu::ComputeSource compSource(compShaderSource.str());
|
|
glu::ShaderProgram program(ctx.getRenderContext(), glu::ProgramSources() << compSource);
|
|
|
|
ctx.beginSection("A compile-time error is generated if a local work group size qualifier is declared more than once in the same shader.");
|
|
verifyCompileError(ctx, program, glu::SHADERTYPE_COMPUTE);
|
|
ctx.endSection();
|
|
}
|
|
|
|
{
|
|
std::ostringstream compShaderSource;
|
|
compShaderSource << shaderVersion << "\n"
|
|
<< "out mediump vec4 fragColor;\n"
|
|
<< "\n"
|
|
<< "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
|
|
<< "void main (void)\n"
|
|
<< "{\n"
|
|
<< "}\n";
|
|
|
|
const glu::ComputeSource compSource(compShaderSource.str());
|
|
glu::ShaderProgram program(ctx.getRenderContext(), glu::ProgramSources() << compSource);
|
|
|
|
ctx.beginSection("A compile-time error is generated if a user defined output variable is declared in a compute shader.");
|
|
verifyCompileError(ctx, program, glu::SHADERTYPE_COMPUTE);
|
|
ctx.endSection();
|
|
}
|
|
|
|
if (glu::isContextTypeES(ctx.getRenderContext().getType())) // for GL4.5 program will compile and link
|
|
{
|
|
std::ostringstream compShaderSource;
|
|
compShaderSource << shaderVersion << "\n"
|
|
<< "uvec3 gl_NumWorkGroups;\n"
|
|
<< "uvec3 gl_WorkGroupSize;\n"
|
|
<< "uvec3 gl_WorkGroupID;\n"
|
|
<< "uvec3 gl_LocalInvocationID;\n"
|
|
<< "uvec3 gl_GlobalInvocationID;\n"
|
|
<< "uvec3 gl_LocalInvocationIndex;\n"
|
|
<< "\n"
|
|
<< "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
|
|
<< "void main (void)\n"
|
|
<< "{\n"
|
|
<< "}\n";
|
|
|
|
const glu::ComputeSource compSource(compShaderSource.str());
|
|
glu::ShaderProgram program(ctx.getRenderContext(), glu::ProgramSources() << compSource);
|
|
|
|
ctx.beginSection("A compile time or link error is generated if compute shader built-in variables are redeclared.");
|
|
bool testFailed = false;
|
|
|
|
tcu::TestLog& log = ctx.getLog();
|
|
log << program;
|
|
|
|
testFailed = (program.getProgramInfo().linkOk) && (program.getShaderInfo(glu::SHADERTYPE_COMPUTE).compileOk);
|
|
|
|
if (testFailed)
|
|
{
|
|
const char* const message("Program was not expected to compile or link.");
|
|
log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
|
|
ctx.fail(message);
|
|
}
|
|
|
|
ctx.endSection();
|
|
}
|
|
}
|
|
|
|
void invalid_write_built_in_constants (NegativeTestContext& ctx)
|
|
{
|
|
if (glu::isContextTypeES(ctx.getRenderContext().getType()))
|
|
{
|
|
if((!ctx.isExtensionSupported("GL_EXT_tessellation_shader") && !ctx.isExtensionSupported("GL_OES_tessellation_shader")) ||
|
|
(!ctx.isExtensionSupported("GL_EXT_geometry_shader") && !ctx.isExtensionSupported("GL_OES_geometry_shader")))
|
|
TCU_THROW(NotSupportedError, "tessellation and geometry shader extensions not supported");
|
|
}
|
|
|
|
const bool isES32 = glu::contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
|
|
map<string, string> args;
|
|
|
|
args["GLSL_VERSION_STRING"] = isES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
|
|
args["GLSL_TESS_EXTENSION_STRING"] = isES32 ? "" : "#extension GL_EXT_tessellation_shader : require";
|
|
args["COMPUTE_BUILT_IN_CONSTANTS_STRING"] = " gl_MaxComputeWorkGroupCount = ivec3(65535, 65535, 65535);\n"
|
|
" gl_MaxComputeWorkGroupCount = ivec3(1024, 1024, 64);\n"
|
|
" gl_MaxComputeWorkGroupSize = ivec3(512);\n"
|
|
" gl_MaxComputeUniformComponents = 512;\n"
|
|
" gl_MaxComputeTextureImageUnits = 16;\n"
|
|
" gl_MaxComputeImageUniforms = 8;\n"
|
|
" gl_MaxComputeAtomicCounters = 8;\n"
|
|
" gl_MaxComputeAtomicCounterBuffers = 1;\n";
|
|
|
|
const glu::VertexSource vertSource (tcu::StringTemplate(genBuiltInSource(glu::SHADERTYPE_VERTEX)).specialize(args));
|
|
const glu::FragmentSource fragSource (tcu::StringTemplate(genBuiltInSource(glu::SHADERTYPE_FRAGMENT)).specialize(args));
|
|
const glu::TessellationControlSource tessCtrlSource (tcu::StringTemplate(genBuiltInSource(glu::SHADERTYPE_TESSELLATION_CONTROL)).specialize(args));
|
|
const glu::TessellationEvaluationSource tessEvalSource (tcu::StringTemplate(genBuiltInSource(glu::SHADERTYPE_TESSELLATION_EVALUATION)).specialize(args));
|
|
const glu::GeometrySource geometrySource (tcu::StringTemplate(genBuiltInSource(glu::SHADERTYPE_GEOMETRY)).specialize(args));
|
|
const glu::ComputeSource computeSource (tcu::StringTemplate(genBuiltInSource(glu::SHADERTYPE_COMPUTE)).specialize(args));
|
|
|
|
glu::ShaderProgram vertProgram (ctx.getRenderContext(), glu::ProgramSources() << glu::ProgramSeparable(true) << vertSource);
|
|
glu::ShaderProgram fragProgram (ctx.getRenderContext(), glu::ProgramSources() << glu::ProgramSeparable(true) << fragSource);
|
|
glu::ShaderProgram tessCtrlProgram (ctx.getRenderContext(), glu::ProgramSources() << glu::ProgramSeparable(true) << tessCtrlSource);
|
|
glu::ShaderProgram tessEvalProgram (ctx.getRenderContext(), glu::ProgramSources() << glu::ProgramSeparable(true) << tessEvalSource);
|
|
glu::ShaderProgram geometryProgram (ctx.getRenderContext(), glu::ProgramSources() << glu::ProgramSeparable(true) << geometrySource);
|
|
glu::ShaderProgram computeProgram (ctx.getRenderContext(), glu::ProgramSources() << glu::ProgramSeparable(true) << computeSource);
|
|
|
|
ctx.beginSection("A compile time is generated if compute built-in constants provided in all shaders are written to.");
|
|
verifyCompileError(ctx, vertProgram, glu::SHADERTYPE_VERTEX);
|
|
verifyCompileError(ctx, fragProgram, glu::SHADERTYPE_FRAGMENT);
|
|
verifyCompileError(ctx, tessCtrlProgram, glu::SHADERTYPE_TESSELLATION_CONTROL);
|
|
verifyCompileError(ctx, tessEvalProgram, glu::SHADERTYPE_TESSELLATION_EVALUATION);
|
|
verifyCompileError(ctx, geometryProgram, glu::SHADERTYPE_GEOMETRY);
|
|
verifyCompileError(ctx, computeProgram, glu::SHADERTYPE_COMPUTE);
|
|
ctx.endSection();
|
|
}
|
|
|
|
} // anonymous
|
|
|
|
std::vector<FunctionContainer> getNegativeComputeTestFunctions (void)
|
|
{
|
|
const FunctionContainer funcs[] =
|
|
{
|
|
{ program_not_active, "program_not_active", "Use dispatch commands with no active program" },
|
|
{ invalid_program_query, "invalid_program_query", "Querying GL_COMPUTE_WORK_GROUP_SIZE with glGetProgramiv() on invalid programs" },
|
|
{ invalid_dispatch_compute_indirect, "invalid_dispatch_compute_indirect", "Invalid glDispatchComputeIndirect usage" },
|
|
{ invalid_maximum_work_group_counts, "invalid_maximum_work_group_counts", "Maximum workgroup counts for dispatch commands" },
|
|
{ invalid_maximum_work_group_sizes, "invalid_maximum_work_group_sizes", "Maximum local workgroup sizes declared in compute shaders" },
|
|
{ invalid_layout_qualifiers, "invalid_layout_qualifiers", "Invalid layout qualifiers in compute shaders" },
|
|
{ invalid_write_built_in_constants, "invalid_write_built_in_constants", "Invalid writes to built-in compute shader constants" },
|
|
{ exceed_uniform_block_limit, "exceed_uniform_block_limit", "Link error when shader exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS" },
|
|
{ exceed_shader_storage_block_limit, "exceed_shader_storage_block_limit", "Link error when shader exceeds GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS" },
|
|
{ exceed_texture_image_units_limit, "exceed_texture_image_units_limit", "Link error when shader exceeds GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS" },
|
|
{ exceed_image_uniforms_limit, "exceed_image_uniforms_limit", "Link error when shader exceeds GL_MAX_COMPUTE_IMAGE_UNIFORMS" },
|
|
{ exceed_shared_memory_size_limit, "exceed_shared_memory_size_limit", "Link error when shader exceeds GL_MAX_COMPUTE_SHARED_MEMORY_SIZE" },
|
|
{ exceed_uniform_components_limit, "exceed_uniform_components_limit", "Link error when shader exceeds GL_MAX_COMPUTE_UNIFORM_COMPONENTS" },
|
|
{ exceed_atomic_counter_buffer_limit, "exceed_atomic_counter_buffer_limit", "Link error when shader exceeds GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS" },
|
|
{ exceed_atomic_counters_limit, "exceed_atomic_counters_limit", "Link error when shader exceeds GL_MAX_COMPUTE_ATOMIC_COUNTERS" },
|
|
};
|
|
|
|
return std::vector<FunctionContainer>(DE_ARRAY_BEGIN(funcs), DE_ARRAY_END(funcs));
|
|
}
|
|
|
|
} // NegativeTestShared
|
|
} // Functional
|
|
} // gles31
|
|
} // deqp
|