/*------------------------------------------------------------------------- * drawElements Quality Program OpenGL ES 3.1 Module * ------------------------------------------------- * * Copyright 2016 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 Shader Storage Tests *//*--------------------------------------------------------------------*/ #include "es31fNegativeShaderStorageTests.hpp" #include "gluShaderProgram.hpp" #include "glwDefs.hpp" #include "glwEnums.hpp" namespace deqp { namespace gles31 { namespace Functional { namespace NegativeTestShared { namespace { void verifyProgram(NegativeTestContext& ctx, glu::ProgramSources sources) { tcu::TestLog& log = ctx.getLog(); const glu::ShaderProgram program (ctx.getRenderContext(), sources); bool testFailed = false; 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); } } const char* getShaderExtensionDeclaration (glw::GLenum glShaderType) { switch (glShaderType) { case GL_TESS_CONTROL_SHADER: case GL_TESS_EVALUATION_SHADER: return "#extension GL_EXT_tessellation_shader : require\n"; case GL_GEOMETRY_SHADER: return "#extension GL_EXT_geometry_shader : require\n"; default: return ""; } } glu::ShaderType getGLUShaderType (glw::GLenum glShaderType) { switch (glShaderType) { case GL_VERTEX_SHADER: return glu::SHADERTYPE_VERTEX; case GL_FRAGMENT_SHADER: return glu::SHADERTYPE_FRAGMENT; case GL_TESS_CONTROL_SHADER: return glu::SHADERTYPE_TESSELLATION_CONTROL; case GL_TESS_EVALUATION_SHADER: return glu::SHADERTYPE_TESSELLATION_EVALUATION; case GL_GEOMETRY_SHADER: return glu::SHADERTYPE_GEOMETRY; case GL_COMPUTE_SHADER: return glu::SHADERTYPE_COMPUTE; default: DE_FATAL("Unknown shader type"); return glu::SHADERTYPE_LAST; } } glw::GLenum getMaxSSBlockSizeEnum (glw::GLenum glShaderType) { switch (glShaderType) { case GL_VERTEX_SHADER: return GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS; case GL_FRAGMENT_SHADER: return GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS; case GL_TESS_CONTROL_SHADER: return GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS; case GL_TESS_EVALUATION_SHADER: return GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS; case GL_GEOMETRY_SHADER: return GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS; case GL_COMPUTE_SHADER: return GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS; default: DE_FATAL("Unknown shader type"); return -1; } } int getMaxSSBlockSize (NegativeTestContext& ctx, glw::GLenum glShaderType) { int maxSSBlocks = 0; ctx.glGetIntegerv(getMaxSSBlockSizeEnum(glShaderType), &maxSSBlocks); return maxSSBlocks; } std::string genBlockSource (NegativeTestContext& ctx, deInt64 numSSBlocks, glw::GLenum shaderType) { const bool isES32 = contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2)); const glu::GLSLVersion version = isES32 ? glu::GLSL_VERSION_320_ES : glu::GLSL_VERSION_310_ES; std::ostringstream source; source << glu::getGLSLVersionDeclaration(version) << "\n" << ((isES32) ? "" : getShaderExtensionDeclaration(shaderType)); switch (shaderType) { case GL_VERTEX_SHADER: case GL_FRAGMENT_SHADER: break; case GL_COMPUTE_SHADER: source << "layout (local_size_x = 1) in;\n"; break; case GL_GEOMETRY_SHADER: source << "layout(points) in;\n" << "layout(line_strip, max_vertices = 3) out;\n"; break; case GL_TESS_CONTROL_SHADER: source << "layout(vertices = 10) out;\n"; break; case GL_TESS_EVALUATION_SHADER: source << "layout(triangles) in;\n"; break; default: DE_FATAL("Unknown shader type"); break; } source << "\n" << "layout(std430, binding = 0) buffer Block {\n" << " int value;\n" << "} sb_in[" << numSSBlocks << "];\n" << "void main(void) { sb_in[0].value = 1; }\n"; return source.str(); } std::string genCommonSource (NegativeTestContext& ctx, glw::GLenum shaderType) { const bool isES32 = contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2)); const glu::GLSLVersion version = isES32 ? glu::GLSL_VERSION_320_ES : glu::GLSL_VERSION_310_ES; std::ostringstream source; source << glu::getGLSLVersionDeclaration(version) << "\n" << ((isES32) ? "" : getShaderExtensionDeclaration(shaderType)); switch (shaderType) { case GL_TESS_CONTROL_SHADER: source << "layout(vertices = 3) out;\n" << "void main() {}\n"; break; case GL_TESS_EVALUATION_SHADER: source << "layout(triangles, equal_spacing, cw) in;\n" << "void main() {}\n"; break; default: source << "void main() {}\n"; break; } return source.str(); } int genMaxSSBlocksSource (NegativeTestContext& ctx, glw::GLenum glShaderType, glu::ProgramSources& sources) { int maxSSBlocks = getMaxSSBlockSize(ctx, glShaderType); const std::string shaderSrc = genBlockSource(ctx, (maxSSBlocks), glShaderType); sources.sources[getGLUShaderType(glShaderType)].push_back(shaderSrc); return maxSSBlocks; } void block_number_limits (NegativeTestContext& ctx) { const glw::GLenum glShaderTypes[] = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER, GL_TESS_CONTROL_SHADER, GL_TESS_EVALUATION_SHADER, GL_GEOMETRY_SHADER, GL_COMPUTE_SHADER, }; const std::string vertSource = genCommonSource(ctx, GL_VERTEX_SHADER); const std::string fragSource = genCommonSource(ctx, GL_FRAGMENT_SHADER); const std::string tessControlSource = genCommonSource(ctx, GL_TESS_CONTROL_SHADER); const std::string tessEvalSource = genCommonSource(ctx, GL_TESS_EVALUATION_SHADER); for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(glShaderTypes); ndx++) { ctx.beginSection("maxShaderStorageBlocks: Exceed limits"); if (!ctx.isShaderSupported(static_cast<glu::ShaderType>(getGLUShaderType(glShaderTypes[ndx])))) { ctx.endSection(); continue; } int maxSSBlocks = getMaxSSBlockSize(ctx, glShaderTypes[ndx]); std::string source = genBlockSource(ctx, maxSSBlocks+1, glShaderTypes[ndx]); glu::ProgramSources sources; if (maxSSBlocks == 0) { ctx.endSection(); continue; } switch (glShaderTypes[ndx]) { case GL_VERTEX_SHADER: sources << glu::VertexSource(source) << glu::FragmentSource(fragSource); break; case GL_FRAGMENT_SHADER: sources << glu::VertexSource(vertSource) << glu::FragmentSource(source); break; case GL_TESS_CONTROL_SHADER: sources << glu::VertexSource(vertSource) << glu::FragmentSource(fragSource) << glu::TessellationControlSource(source) << glu::TessellationEvaluationSource(tessEvalSource); break; case GL_TESS_EVALUATION_SHADER: sources << glu::VertexSource(vertSource) << glu::FragmentSource(fragSource) << glu::TessellationControlSource(tessControlSource) << glu::TessellationEvaluationSource(source); break; case GL_GEOMETRY_SHADER: sources << glu::VertexSource(vertSource) << glu::FragmentSource(fragSource) << glu::GeometrySource(source); break; case GL_COMPUTE_SHADER: sources << glu::ComputeSource(source); break; default: DE_FATAL("Unknown shader type"); break; } verifyProgram(ctx, sources); ctx.endSection(); } } void max_combined_block_number_limit (NegativeTestContext& ctx) { ctx.beginSection("maxCombinedShaderStorageBlocks: Exceed limits"); glu::ProgramSources sources; int combinedSSBlocks = 0; int maxCombinedSSBlocks = 0; combinedSSBlocks += genMaxSSBlocksSource(ctx, GL_VERTEX_SHADER, sources); combinedSSBlocks += genMaxSSBlocksSource(ctx, GL_FRAGMENT_SHADER, sources); if ((ctx.isShaderSupported(glu::SHADERTYPE_TESSELLATION_CONTROL)) && (ctx.isShaderSupported(glu::SHADERTYPE_TESSELLATION_EVALUATION))) { combinedSSBlocks += genMaxSSBlocksSource(ctx, GL_TESS_CONTROL_SHADER, sources); combinedSSBlocks += genMaxSSBlocksSource(ctx, GL_TESS_EVALUATION_SHADER, sources); } if (ctx.isShaderSupported(glu::SHADERTYPE_GEOMETRY)) combinedSSBlocks += genMaxSSBlocksSource(ctx, GL_GEOMETRY_SHADER, sources); ctx.glGetIntegerv(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, &maxCombinedSSBlocks); ctx.getLog() << tcu::TestLog::Message << "GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS: " << maxCombinedSSBlocks << tcu::TestLog::EndMessage; ctx.getLog() << tcu::TestLog::Message << "Combined shader storage blocks: " << combinedSSBlocks << tcu::TestLog::EndMessage; if (combinedSSBlocks > maxCombinedSSBlocks) verifyProgram(ctx, sources); else ctx.getLog() << tcu::TestLog::Message << "Test skipped: Combined shader storage blocks < GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS: " << tcu::TestLog::EndMessage; ctx.endSection(); } } // anonymous std::vector<FunctionContainer> getNegativeShaderStorageTestFunctions () { const FunctionContainer funcs[] = { { block_number_limits, "block_number_limits", "Invalid shader linkage" }, { max_combined_block_number_limit, "max_combined_block_number_limit", "Invalid shader linkage" }, }; return std::vector<FunctionContainer>(DE_ARRAY_BEGIN(funcs), DE_ARRAY_END(funcs)); } } // NegativeTestShared } // Functional } // gles31 } // deqp