/*------------------------------------------------------------------------- * drawElements Quality Program OpenGL ES 3.1 Module * ------------------------------------------------- * * Copyright 2014 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 Shader state query tests *//*--------------------------------------------------------------------*/ #include "es31fShaderStateQueryTests.hpp" #include "es31fInfoLogQueryShared.hpp" #include "glsStateQueryUtil.hpp" #include "tcuTestLog.hpp" #include "tcuStringTemplate.hpp" #include "gluShaderProgram.hpp" #include "gluRenderContext.hpp" #include "gluCallLogWrapper.hpp" #include "gluContextInfo.hpp" #include "gluStrUtil.hpp" #include "glwFunctions.hpp" #include "glwEnums.hpp" namespace deqp { namespace gles31 { namespace Functional { namespace { static inline std::string brokenShaderSource (const glu::ContextType &contextType) { const std::string glslVersionDecl = glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(contextType)); return glslVersionDecl + "\n" "broken, this should not compile,\n" "{"; } class BaseTypeCase : public TestCase { public: struct TestTypeInfo { glw::GLenum glType; const char* declarationStr; const char* accessStr; }; BaseTypeCase (Context& ctx, const char* name, const char* desc, const char* extension); private: IterateResult iterate (void); virtual std::vector getInfos (void) const = 0; virtual void checkRequirements (void) const; const char* const m_extension; }; BaseTypeCase::BaseTypeCase (Context& ctx, const char* name, const char* desc, const char* extension) : TestCase (ctx, name, desc) , m_extension (extension) { } BaseTypeCase::IterateResult BaseTypeCase::iterate (void) { static const char* const vertexSourceTemplate = "${VERSIONDECL}\n" "in highp vec4 a_position;\n" "void main(void)\n" "{\n" " gl_Position = a_position;\n" "}\n"; static const char* const fragmentSourceTemplate = "${VERSIONDECL}\n" "${EXTENSIONSTATEMENT}" "${DECLARATIONSTR};\n" "layout(location = 0) out highp vec4 dEQP_FragColor;\n" "void main(void)\n" "{\n" " dEQP_FragColor = vec4(${ACCESSSTR});\n" "}\n"; tcu::ResultCollector result (m_testCtx.getLog()); std::vector samplerTypes = getInfos(); const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)); if (m_extension && !m_context.getContextInfo().isExtensionSupported(m_extension) && !supportsES32) throw tcu::NotSupportedError("Test requires " + std::string(m_extension)); checkRequirements(); for (int typeNdx = 0; typeNdx < (int)samplerTypes.size(); ++typeNdx) { const tcu::ScopedLogSection section (m_testCtx.getLog(), std::string(glu::getShaderVarTypeStr(samplerTypes[typeNdx].glType).toString()), "Uniform type " + glu::getShaderVarTypeStr(samplerTypes[typeNdx].glType).toString()); std::map shaderArgs; shaderArgs["DECLARATIONSTR"] = samplerTypes[typeNdx].declarationStr; shaderArgs["ACCESSSTR"] = samplerTypes[typeNdx].accessStr; shaderArgs["EXTENSIONSTATEMENT"] = (m_extension && !supportsES32) ? (std::string() + "#extension " + m_extension + " : require\n") : (""); shaderArgs["VERSIONDECL"] = glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType())); const std::string fragmentSource = tcu::StringTemplate(fragmentSourceTemplate).specialize(shaderArgs); const std::string vertexSource = tcu::StringTemplate(vertexSourceTemplate).specialize(shaderArgs); const glw::Functions& gl = m_context.getRenderContext().getFunctions(); glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vertexSource) << glu::FragmentSource(fragmentSource)); m_testCtx.getLog() << tcu::TestLog::Message << "Building program with uniform sampler of type " << glu::getShaderVarTypeStr(samplerTypes[typeNdx].glType) << tcu::TestLog::EndMessage; if (!program.isOk()) { m_testCtx.getLog() << program; result.fail("could not build shader"); } else { // only one uniform -- uniform at index 0 int uniforms = 0; gl.getProgramiv(program.getProgram(), GL_ACTIVE_UNIFORMS, &uniforms); if (uniforms != 1) result.fail("Unexpected GL_ACTIVE_UNIFORMS, expected 1"); else { // check type const glw::GLuint uniformIndex = 0; glw::GLint type = 0; m_testCtx.getLog() << tcu::TestLog::Message << "Verifying uniform type." << tcu::TestLog::EndMessage; gl.getActiveUniformsiv(program.getProgram(), 1, &uniformIndex, GL_UNIFORM_TYPE, &type); if (type != (glw::GLint)samplerTypes[typeNdx].glType) { std::ostringstream buf; buf << "Invalid type, expected " << samplerTypes[typeNdx].glType << ", got " << type; result.fail(buf.str()); } } } GLU_EXPECT_NO_ERROR(gl.getError(), ""); } result.setTestContextResult(m_testCtx); return STOP; } void BaseTypeCase::checkRequirements (void) const { } class CoreSamplerTypeCase : public BaseTypeCase { public: CoreSamplerTypeCase (Context& ctx, const char* name, const char* desc); private: std::vector getInfos (void) const; }; CoreSamplerTypeCase::CoreSamplerTypeCase (Context& ctx, const char* name, const char* desc) : BaseTypeCase(ctx, name, desc, DE_NULL) { } std::vector CoreSamplerTypeCase::getInfos (void) const { static const TestTypeInfo samplerTypes[] = { { GL_SAMPLER_2D_MULTISAMPLE, "uniform highp sampler2DMS u_sampler", "texelFetch(u_sampler, ivec2(gl_FragCoord.xy), 0)" }, { GL_INT_SAMPLER_2D_MULTISAMPLE, "uniform highp isampler2DMS u_sampler", "texelFetch(u_sampler, ivec2(gl_FragCoord.xy), 0)" }, { GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE, "uniform highp usampler2DMS u_sampler", "texelFetch(u_sampler, ivec2(gl_FragCoord.xy), 0)" }, }; std::vector infos; for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(samplerTypes); ++ndx) infos.push_back(samplerTypes[ndx]); return infos; } class MSArraySamplerTypeCase : public BaseTypeCase { public: MSArraySamplerTypeCase (Context& ctx, const char* name, const char* desc); private: std::vector getInfos (void) const; }; MSArraySamplerTypeCase::MSArraySamplerTypeCase (Context& ctx, const char* name, const char* desc) : BaseTypeCase(ctx, name, desc, "GL_OES_texture_storage_multisample_2d_array") { } std::vector MSArraySamplerTypeCase::getInfos (void) const { static const TestTypeInfo samplerTypes[] = { { GL_SAMPLER_2D_MULTISAMPLE_ARRAY, "uniform highp sampler2DMSArray u_sampler", "texelFetch(u_sampler, ivec3(gl_FragCoord.xyz), 0)" }, { GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, "uniform highp isampler2DMSArray u_sampler", "texelFetch(u_sampler, ivec3(gl_FragCoord.xyz), 0)" }, { GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, "uniform highp usampler2DMSArray u_sampler", "texelFetch(u_sampler, ivec3(gl_FragCoord.xyz), 0)" }, }; std::vector infos; for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(samplerTypes); ++ndx) infos.push_back(samplerTypes[ndx]); return infos; } class TextureBufferSamplerTypeCase : public BaseTypeCase { public: TextureBufferSamplerTypeCase (Context& ctx, const char* name, const char* desc); private: std::vector getInfos (void) const; }; TextureBufferSamplerTypeCase::TextureBufferSamplerTypeCase (Context& ctx, const char* name, const char* desc) : BaseTypeCase(ctx, name, desc, "GL_EXT_texture_buffer") { } std::vector TextureBufferSamplerTypeCase::getInfos (void) const { static const TestTypeInfo samplerTypes[] = { { GL_SAMPLER_BUFFER, "uniform highp samplerBuffer u_sampler", "texelFetch(u_sampler, int(gl_FragCoord.x))" }, { GL_INT_SAMPLER_BUFFER, "uniform highp isamplerBuffer u_sampler", "texelFetch(u_sampler, int(gl_FragCoord.x))" }, { GL_UNSIGNED_INT_SAMPLER_BUFFER, "uniform highp usamplerBuffer u_sampler", "texelFetch(u_sampler, int(gl_FragCoord.x))" }, }; std::vector infos; for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(samplerTypes); ++ndx) infos.push_back(samplerTypes[ndx]); return infos; } class TextureBufferImageTypeCase : public BaseTypeCase { public: TextureBufferImageTypeCase (Context& ctx, const char* name, const char* desc); private: std::vector getInfos (void) const; void checkRequirements (void) const; }; TextureBufferImageTypeCase::TextureBufferImageTypeCase (Context& ctx, const char* name, const char* desc) : BaseTypeCase(ctx, name, desc, "GL_EXT_texture_buffer") { } std::vector TextureBufferImageTypeCase::getInfos (void) const { static const TestTypeInfo samplerTypes[] = { { GL_IMAGE_BUFFER, "layout(binding=0, rgba8) readonly uniform highp imageBuffer u_image", "imageLoad(u_image, int(gl_FragCoord.x))" }, { GL_INT_IMAGE_BUFFER, "layout(binding=0, r32i) readonly uniform highp iimageBuffer u_image", "imageLoad(u_image, int(gl_FragCoord.x))" }, { GL_UNSIGNED_INT_IMAGE_BUFFER, "layout(binding=0, r32ui) readonly uniform highp uimageBuffer u_image", "imageLoad(u_image, int(gl_FragCoord.x))" }, }; std::vector infos; for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(samplerTypes); ++ndx) infos.push_back(samplerTypes[ndx]); return infos; } void TextureBufferImageTypeCase::checkRequirements (void) const { if (m_context.getContextInfo().getInt(GL_MAX_FRAGMENT_IMAGE_UNIFORMS) < 1) throw tcu::NotSupportedError("Test requires fragment images"); } class CubeArraySamplerTypeCase : public BaseTypeCase { public: CubeArraySamplerTypeCase (Context& ctx, const char* name, const char* desc); private: std::vector getInfos (void) const; }; CubeArraySamplerTypeCase::CubeArraySamplerTypeCase (Context& ctx, const char* name, const char* desc) : BaseTypeCase(ctx, name, desc, "GL_EXT_texture_cube_map_array") { } std::vector CubeArraySamplerTypeCase::getInfos (void) const { static const TestTypeInfo samplerTypes[] = { { GL_SAMPLER_CUBE_MAP_ARRAY, "uniform highp samplerCubeArray u_sampler", "texture(u_sampler, gl_FragCoord.xxyz)" }, { GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW, "uniform highp samplerCubeArrayShadow u_sampler", "texture(u_sampler, gl_FragCoord.xxyz, 0.5)" }, { GL_INT_SAMPLER_CUBE_MAP_ARRAY, "uniform highp isamplerCubeArray u_sampler", "texture(u_sampler, gl_FragCoord.xxyz)" }, { GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY, "uniform highp usamplerCubeArray u_sampler", "texture(u_sampler, gl_FragCoord.xxyz)" }, }; std::vector infos; for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(samplerTypes); ++ndx) infos.push_back(samplerTypes[ndx]); return infos; } class CubeArrayImageTypeCase : public BaseTypeCase { public: CubeArrayImageTypeCase (Context& ctx, const char* name, const char* desc); private: std::vector getInfos (void) const; void checkRequirements (void) const; }; CubeArrayImageTypeCase::CubeArrayImageTypeCase (Context& ctx, const char* name, const char* desc) : BaseTypeCase(ctx, name, desc, "GL_EXT_texture_cube_map_array") { } std::vector CubeArrayImageTypeCase::getInfos (void) const { static const TestTypeInfo samplerTypes[] = { { GL_IMAGE_CUBE_MAP_ARRAY, "layout(binding=0, rgba8) readonly uniform highp imageCubeArray u_image", "imageLoad(u_image, ivec3(gl_FragCoord.xyx))" }, { GL_INT_IMAGE_CUBE_MAP_ARRAY, "layout(binding=0, r32i) readonly uniform highp iimageCubeArray u_image", "imageLoad(u_image, ivec3(gl_FragCoord.xyx))" }, { GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY, "layout(binding=0, r32ui) readonly uniform highp uimageCubeArray u_image", "imageLoad(u_image, ivec3(gl_FragCoord.xyx))" }, }; std::vector infos; for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(samplerTypes); ++ndx) infos.push_back(samplerTypes[ndx]); return infos; } void CubeArrayImageTypeCase::checkRequirements (void) const { if (m_context.getContextInfo().getInt(GL_MAX_FRAGMENT_IMAGE_UNIFORMS) < 1) throw tcu::NotSupportedError("Test requires fragment images"); } class ShaderLogCase : public TestCase { public: ShaderLogCase (Context& ctx, const char* name, const char* desc, glu::ShaderType shaderType); private: void init (void); IterateResult iterate (void); const glu::ShaderType m_shaderType; }; ShaderLogCase::ShaderLogCase (Context& ctx, const char* name, const char* desc, glu::ShaderType shaderType) : TestCase (ctx, name, desc) , m_shaderType (shaderType) { } void ShaderLogCase::init (void) { const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)); switch (m_shaderType) { case glu::SHADERTYPE_VERTEX: case glu::SHADERTYPE_FRAGMENT: case glu::SHADERTYPE_COMPUTE: break; case glu::SHADERTYPE_GEOMETRY: if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader") && !supportsES32) throw tcu::NotSupportedError("Test requires GL_EXT_geometry_shader extension or an OpenGL ES 3.2 or higher context."); break; case glu::SHADERTYPE_TESSELLATION_CONTROL: case glu::SHADERTYPE_TESSELLATION_EVALUATION: if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader") && !supportsES32) throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader extension or an OpenGL ES 3.2 or higher context."); break; default: DE_ASSERT(false); break; } } ShaderLogCase::IterateResult ShaderLogCase::iterate (void) { using gls::StateQueryUtil::StateQueryMemoryWriteGuard; tcu::ResultCollector result (m_testCtx.getLog()); glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); deUint32 shader = 0; const std::string source = brokenShaderSource(m_context.getRenderContext().getType()); const char* const brokenSource = source.c_str(); StateQueryMemoryWriteGuard logLen; gl.enableLogging(true); m_testCtx.getLog() << tcu::TestLog::Message << "Trying to compile broken shader source." << tcu::TestLog::EndMessage; shader = gl.glCreateShader(glu::getGLShaderType(m_shaderType)); GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "create shader"); gl.glShaderSource(shader, 1, &brokenSource, DE_NULL); gl.glCompileShader(shader); GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "compile"); gl.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLen); logLen.verifyValidity(result); if (!logLen.isUndefined()) verifyInfoLogQuery(result, gl, logLen, shader, &glu::CallLogWrapper::glGetShaderInfoLog, "glGetShaderInfoLog"); gl.glDeleteShader(shader); GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "delete"); result.setTestContextResult(m_testCtx); return STOP; } } // anonymous ShaderStateQueryTests::ShaderStateQueryTests (Context& context) : TestCaseGroup(context, "shader", "Shader state query tests") { } ShaderStateQueryTests::~ShaderStateQueryTests (void) { } void ShaderStateQueryTests::init (void) { addChild(new CoreSamplerTypeCase (m_context, "sampler_type", "Sampler type cases")); addChild(new MSArraySamplerTypeCase (m_context, "sampler_type_multisample_array", "MSAA array sampler type cases")); addChild(new TextureBufferSamplerTypeCase (m_context, "sampler_type_texture_buffer", "Texture buffer sampler type cases")); addChild(new TextureBufferImageTypeCase (m_context, "image_type_texture_buffer", "Texture buffer image type cases")); addChild(new CubeArraySamplerTypeCase (m_context, "sampler_type_cube_array", "Cube array sampler type cases")); addChild(new CubeArrayImageTypeCase (m_context, "image_type_cube_array", "Cube array image type cases")); // shader info log tests // \note, there exists similar tests in gles3 module. However, the gles31 could use a different // shader compiler with different INFO_LOG bugs. { static const struct { const char* caseName; glu::ShaderType caseType; } shaderTypes[] = { { "info_log_vertex", glu::SHADERTYPE_VERTEX }, { "info_log_fragment", glu::SHADERTYPE_FRAGMENT }, { "info_log_geometry", glu::SHADERTYPE_GEOMETRY }, { "info_log_tess_ctrl", glu::SHADERTYPE_TESSELLATION_CONTROL }, { "info_log_tess_eval", glu::SHADERTYPE_TESSELLATION_EVALUATION }, { "info_log_compute", glu::SHADERTYPE_COMPUTE }, }; for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(shaderTypes); ++ndx) addChild(new ShaderLogCase(m_context, shaderTypes[ndx].caseName, "", shaderTypes[ndx].caseType)); } } } // Functional } // gles31 } // deqp