| /*------------------------------------------------------------------------- |
| * OpenGL Conformance Test Suite |
| * ----------------------------- |
| * |
| * Copyright (c) 2015-2016 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 gl4cSyncTests.cpp |
| * \brief Declares test classes for synchronization functionality. |
| */ /*-------------------------------------------------------------------*/ |
| |
| #include "gl4cIncompleteTextureAccessTests.hpp" |
| |
| #include "deSharedPtr.hpp" |
| |
| #include "gluContextInfo.hpp" |
| #include "gluDefs.hpp" |
| #include "gluPixelTransfer.hpp" |
| #include "gluStrUtil.hpp" |
| |
| #include "tcuFuzzyImageCompare.hpp" |
| #include "tcuImageCompare.hpp" |
| #include "tcuRenderTarget.hpp" |
| #include "tcuSurface.hpp" |
| #include "tcuTestLog.hpp" |
| |
| #include "glw.h" |
| #include "glwFunctions.hpp" |
| |
| namespace gl4cts |
| { |
| namespace IncompleteTextureAccess |
| { |
| /****************************************** Incomplete Texture Access Tests Group ***********************************************/ |
| |
| /** @brief Incomplete Texture Access Tests Group constructor. |
| * |
| * @param [in] context OpenGL context. |
| */ |
| Tests::Tests(deqp::Context& context) |
| : TestCaseGroup(context, "incomplete_texture_access", "Incomplete Texture Access Tests Suite") |
| { |
| } |
| |
| /** @brief Incomplete Texture Access Tests initializer. */ |
| void Tests::init() |
| { |
| addChild(new IncompleteTextureAccess::SamplerTest(m_context)); |
| } |
| |
| /*************************************** Sampler Incomplete Texture Access Test Test *******************************************/ |
| |
| /** @brief Sampler Incomplete Texture Access Test constructor. |
| * |
| * @param [in] context OpenGL context. |
| */ |
| SamplerTest::SamplerTest(deqp::Context& context) |
| : deqp::TestCase(context, "sampler", "Fetch using sampler test"), m_po(0), m_to(0), m_fbo(0), m_rbo(0), m_vao(0) |
| { |
| /* Intentionally left blank. */ |
| } |
| |
| /** @brief Iterate Incomplete Texture Access Test cases. |
| * |
| * @return Iteration result. |
| */ |
| tcu::TestNode::IterateResult SamplerTest::iterate() |
| { |
| /* Get context setup. */ |
| bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5))); |
| |
| if (!is_at_least_gl_45) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported"); |
| |
| return STOP; |
| } |
| |
| /* Running tests. */ |
| bool is_ok = true; |
| bool is_error = false; |
| |
| try |
| { |
| PrepareFramebuffer(); |
| PrepareVertexArrays(); |
| |
| for (glw::GLuint i = 0; i < s_configurations_count; ++i) |
| { |
| PrepareProgram(s_configurations[i]); |
| PrepareTexture(s_configurations[i]); |
| |
| Draw(); |
| |
| if (!Check(s_configurations[i])) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Incomplete texture sampler access test failed with sampler " |
| << s_configurations[i].sampler_template << "." << tcu::TestLog::EndMessage; |
| |
| is_ok = false; |
| } |
| |
| CleanCase(); |
| } |
| } |
| catch (...) |
| { |
| is_ok = false; |
| is_error = true; |
| } |
| |
| /* Cleanup. */ |
| CleanCase(); |
| CleanTest(); |
| |
| /* Result's setup. */ |
| if (is_ok) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| } |
| else |
| { |
| if (is_error) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error"); |
| } |
| else |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| } |
| |
| return STOP; |
| } |
| |
| void SamplerTest::PrepareProgram(Configuration configuration) |
| { |
| /* Shortcut for GL functionality */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| struct Shader |
| { |
| glw::GLchar const* source[5]; |
| glw::GLsizei const count; |
| glw::GLenum const type; |
| glw::GLuint id; |
| } shader[] = { { { s_vertex_shader, NULL, NULL, NULL, NULL }, 1, GL_VERTEX_SHADER, 0 }, |
| { { s_fragment_shader_head, configuration.sampler_template, s_fragment_shader_body, |
| configuration.fetch_template, s_fragment_shader_tail }, |
| 5, |
| GL_FRAGMENT_SHADER, |
| 0 } }; |
| |
| glw::GLuint const shader_count = sizeof(shader) / sizeof(shader[0]); |
| |
| try |
| { |
| /* Create program. */ |
| m_po = gl.createProgram(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram call failed."); |
| |
| /* Shader compilation. */ |
| |
| for (glw::GLuint i = 0; i < shader_count; ++i) |
| { |
| { |
| shader[i].id = gl.createShader(shader[i].type); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader call failed."); |
| |
| gl.attachShader(m_po, shader[i].id); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader call failed."); |
| |
| gl.shaderSource(shader[i].id, shader[i].count, shader[i].source, NULL); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource call failed."); |
| |
| gl.compileShader(shader[i].id); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader call failed."); |
| |
| glw::GLint status = GL_FALSE; |
| |
| gl.getShaderiv(shader[i].id, GL_COMPILE_STATUS, &status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv call failed."); |
| |
| if (GL_FALSE == status) |
| { |
| glw::GLint log_size = 0; |
| gl.getShaderiv(shader[i].id, GL_INFO_LOG_LENGTH, &log_size); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv call failed."); |
| |
| glw::GLchar* log_text = new glw::GLchar[log_size]; |
| |
| gl.getShaderInfoLog(shader[i].id, log_size, NULL, &log_text[0]); |
| |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Shader compilation has failed.\n" |
| << "Shader type: " << glu::getShaderTypeStr(shader[i].type) << "\n" |
| << "Shader compilation error log:\n" |
| << log_text << "\n" |
| << "Shader source code:\n" |
| << shader[i].source[0] << (shader[i].source[1] ? shader[i].source[1] : "") |
| << (shader[i].source[2] ? shader[i].source[2] : "") |
| << (shader[i].source[3] ? shader[i].source[3] : "") |
| << (shader[i].source[4] ? shader[i].source[4] : "") << "\n" |
| << tcu::TestLog::EndMessage; |
| |
| delete[] log_text; |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderInfoLog call failed."); |
| |
| throw 0; |
| } |
| } |
| } |
| |
| /* Link. */ |
| gl.linkProgram(m_po); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings call failed."); |
| |
| glw::GLint status = GL_FALSE; |
| |
| gl.getProgramiv(m_po, GL_LINK_STATUS, &status); |
| |
| if (GL_TRUE == status) |
| { |
| for (glw::GLuint i = 0; i < shader_count; ++i) |
| { |
| if (shader[i].id) |
| { |
| gl.detachShader(m_po, shader[i].id); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDetachShader call failed."); |
| } |
| } |
| } |
| else |
| { |
| glw::GLint log_size = 0; |
| |
| gl.getProgramiv(m_po, GL_INFO_LOG_LENGTH, &log_size); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv call failed."); |
| |
| glw::GLchar* log_text = new glw::GLchar[log_size]; |
| |
| gl.getProgramInfoLog(m_po, log_size, NULL, &log_text[0]); |
| |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Program linkage has failed due to:\n" |
| << log_text << "\n" |
| << tcu::TestLog::EndMessage; |
| |
| delete[] log_text; |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog call failed."); |
| |
| throw 0; |
| } |
| } |
| catch (...) |
| { |
| if (m_po) |
| { |
| gl.deleteProgram(m_po); |
| |
| m_po = 0; |
| } |
| } |
| |
| for (glw::GLuint i = 0; i < shader_count; ++i) |
| { |
| if (0 != shader[i].id) |
| { |
| gl.deleteShader(shader[i].id); |
| |
| shader[i].id = 0; |
| } |
| } |
| |
| if (0 == m_po) |
| { |
| throw 0; |
| } |
| else |
| { |
| gl.useProgram(m_po); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUsePrograms has failed"); |
| } |
| } |
| |
| void SamplerTest::PrepareTexture(Configuration configuration) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| if (m_to) |
| { |
| throw 0; |
| } |
| |
| gl.genTextures(1, &m_to); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures has failed"); |
| |
| gl.bindTexture(configuration.texture_target, m_to); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture has failed"); |
| } |
| |
| void SamplerTest::PrepareFramebuffer() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Sanity checks. */ |
| if (m_fbo || m_rbo) |
| { |
| throw 0; |
| } |
| |
| /* Framebuffer creation. */ |
| gl.genFramebuffers(1, &m_fbo); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers has failed"); |
| |
| gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer has failed"); |
| |
| gl.genRenderbuffers(1, &m_rbo); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers has failed"); |
| |
| gl.bindRenderbuffer(GL_RENDERBUFFER, m_rbo); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer has failed"); |
| |
| gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA32F, 1 /* x size */, 1 /* y size */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage has failed"); |
| |
| gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer has failed"); |
| |
| /* Sanity checks. */ |
| if (GL_FRAMEBUFFER_COMPLETE != gl.checkFramebufferStatus(GL_FRAMEBUFFER)) |
| { |
| throw 0; |
| } |
| } |
| |
| void SamplerTest::PrepareVertexArrays() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Sanity checks.*/ |
| if (m_vao) |
| { |
| throw 0; |
| } |
| |
| /* Empty vao creation. */ |
| gl.genVertexArrays(1, &m_vao); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "gGenVertexArrays has failed"); |
| |
| gl.bindVertexArray(m_vao); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "gBindVertexArrays has failed"); |
| } |
| |
| void SamplerTest::Draw() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Draw setup. */ |
| gl.activeTexture(GL_TEXTURE0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glActiveTexture has failed"); |
| |
| gl.uniform1i(gl.getUniformLocation(m_po, "texture_input"), 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i has failed"); |
| |
| /* Draw. */ |
| gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays has failed"); |
| } |
| |
| bool SamplerTest::Check(Configuration configuration) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Return storage. */ |
| glw::GLfloat result[4] = { 7.f, 7.f, 7.f, 7.f }; |
| |
| /* Fetch. */ |
| gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, result); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels has failed"); |
| |
| /* Comparison. */ |
| for (glw::GLuint i = 0; i < 4 /* # components */; ++i) |
| { |
| if (de::abs(configuration.expected_result[i] - result[i]) > 0.0125 /* precision */) |
| { |
| /* Fail.*/ |
| return false; |
| } |
| } |
| |
| /* Comparsion passed.*/ |
| return true; |
| } |
| |
| void SamplerTest::CleanCase() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Program cleanup. */ |
| if (m_po) |
| { |
| gl.deleteProgram(m_po); |
| |
| m_po = 0; |
| } |
| |
| /* Texture cleanup. */ |
| if (m_to) |
| { |
| gl.deleteTextures(1, &m_to); |
| |
| m_to = 0; |
| } |
| |
| /* Errors cleanup. */ |
| while (gl.getError()) |
| ; |
| } |
| |
| void SamplerTest::CleanTest() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Framebuffer cleanup. */ |
| if (m_fbo) |
| { |
| gl.deleteFramebuffers(1, &m_fbo); |
| |
| m_fbo = 0; |
| } |
| |
| /* Renderbuffer cleanup. */ |
| if (m_rbo) |
| { |
| gl.deleteRenderbuffers(1, &m_rbo); |
| |
| m_rbo = 0; |
| } |
| |
| /* Vertex arrays cleanup. */ |
| if (m_vao) |
| { |
| gl.deleteVertexArrays(1, &m_vao); |
| |
| m_vao = 0; |
| } |
| |
| /* Errors cleanup. */ |
| while (gl.getError()) |
| ; |
| } |
| |
| const struct SamplerTest::Configuration SamplerTest::s_configurations[] = { |
| /* regular floating point sampling */ |
| { GL_TEXTURE_1D, "sampler1D", "texture(texture_input, 0.0)", { 0.f, 0.f, 0.f, 1.f } }, |
| { GL_TEXTURE_2D, "sampler2D", "texture(texture_input, vec2(0.0))", { 0.f, 0.f, 0.f, 1.f } }, |
| { GL_TEXTURE_3D, "sampler3D", "texture(texture_input, vec3(0.0))", { 0.f, 0.f, 0.f, 1.f } }, |
| { GL_TEXTURE_CUBE_MAP, "samplerCube", "texture(texture_input, vec3(0.0))", { 0.f, 0.f, 0.f, 1.f } }, |
| { GL_TEXTURE_RECTANGLE, "sampler2DRect", "texture(texture_input, vec2(0.0))", { 0.f, 0.f, 0.f, 1.f } }, |
| { GL_TEXTURE_1D_ARRAY, "sampler1DArray", "texture(texture_input, vec2(0.0))", { 0.f, 0.f, 0.f, 1.f } }, |
| { GL_TEXTURE_2D_ARRAY, "sampler2DArray", "texture(texture_input, vec3(0.0))", { 0.f, 0.f, 0.f, 1.f } }, |
| { GL_TEXTURE_CUBE_MAP_ARRAY, "samplerCubeArray", "texture(texture_input, vec4(0.0))", { 0.f, 0.f, 0.f, 1.f } }, |
| |
| /* Shadow textures. */ |
| { GL_TEXTURE_1D, |
| "sampler1DShadow", |
| "vec4(texture(texture_input, vec3(0.0)), 0.0, 0.0, 0.0)", |
| { 0.f, 0.f, 0.f, 0.f } }, |
| { GL_TEXTURE_2D, |
| "sampler2DShadow", |
| "vec4(texture(texture_input, vec3(0.0)), 0.0, 0.0, 0.0)", |
| { 0.f, 0.f, 0.f, 0.f } }, |
| { GL_TEXTURE_CUBE_MAP, |
| "samplerCubeShadow", |
| "vec4(texture(texture_input, vec4(0.0)), 0.0, 0.0, 0.0)", |
| { 0.f, 0.f, 0.f, 0.f } }, |
| { GL_TEXTURE_RECTANGLE, |
| "sampler2DRectShadow", |
| "vec4(texture(texture_input, vec3(0.0)), 0.0, 0.0, 0.0)", |
| { 0.f, 0.f, 0.f, 0.f } }, |
| { GL_TEXTURE_1D_ARRAY, |
| "sampler1DArrayShadow", |
| "vec4(texture(texture_input, vec3(0.0)), 0.0, 0.0, 0.0)", |
| { 0.f, 0.f, 0.f, 0.f } }, |
| { GL_TEXTURE_2D_ARRAY, |
| "sampler2DArrayShadow", |
| "vec4(texture(texture_input, vec4(0.0)), 0.0, 0.0, 0.0)", |
| { 0.f, 0.f, 0.f, 0.f } }, |
| { GL_TEXTURE_CUBE_MAP_ARRAY, |
| "samplerCubeArrayShadow", |
| "vec4(texture(texture_input, vec4(0.0), 1.0), 0.0, 0.0, 0.0)", |
| { 0.f, 0.f, 0.f, 0.f } } |
| }; |
| |
| const glw::GLuint SamplerTest::s_configurations_count = sizeof(s_configurations) / sizeof(s_configurations[0]); |
| |
| const glw::GLchar* SamplerTest::s_vertex_shader = "#version 450\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " switch(gl_VertexID)\n" |
| " {\n" |
| " case 0:\n" |
| " gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n" |
| " break;\n" |
| " case 1:\n" |
| " gl_Position = vec4( 1.0, 1.0, 0.0, 1.0);\n" |
| " break;\n" |
| " case 2:\n" |
| " gl_Position = vec4(-1.0,-1.0, 0.0, 1.0);\n" |
| " break;\n" |
| " case 3:\n" |
| " gl_Position = vec4( 1.0,-1.0, 0.0, 1.0);\n" |
| " break;\n" |
| " }\n" |
| "}\n"; |
| |
| const glw::GLchar* SamplerTest::s_fragment_shader_head = "#version 450\n" |
| "\n" |
| "uniform "; |
| |
| const glw::GLchar* SamplerTest::s_fragment_shader_body = " texture_input;\n" |
| "out vec4 texture_output;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " texture_output = "; |
| |
| const glw::GLchar* SamplerTest::s_fragment_shader_tail = ";\n" |
| "}\n"; |
| |
| } /* IncompleteTextureAccess namespace */ |
| } /* gl4cts namespace */ |