void ShaderAtomicCounterOpsTestBase::ShaderPipeline::create(deqp::Context& context) { glu::ProgramSources sources; for (unsigned int i = 0; i < glu::SHADERTYPE_COMPUTE; ++i) { if (!m_shaders[i].empty()) { sources.sources[i].push_back(m_shaders[i]); } } m_program = new glu::ShaderProgram(context.getRenderContext(), sources); if (!m_program->isOk()) { TCU_FAIL("Shader compilation failed"); } glu::ProgramSources sourcesCompute; sourcesCompute.sources[glu::SHADERTYPE_COMPUTE].push_back(m_shaders[glu::SHADERTYPE_COMPUTE]); m_programCompute = new glu::ShaderProgram(context.getRenderContext(), sourcesCompute); if (!m_programCompute->isOk()) { TCU_FAIL("Shader compilation failed"); } }
void VarTokenizer::advance (void) { DE_ASSERT(m_token != TOKEN_END); m_tokenStart += m_tokenLen; m_token = TOKEN_LAST; m_tokenLen = 1; if (m_str[m_tokenStart] == '[') m_token = TOKEN_LEFT_BRACKET; else if (m_str[m_tokenStart] == ']') m_token = TOKEN_RIGHT_BRACKET; else if (m_str[m_tokenStart] == 0) m_token = TOKEN_END; else if (m_str[m_tokenStart] == '.') m_token = TOKEN_PERIOD; else if (isNum(m_str[m_tokenStart])) { m_token = TOKEN_NUMBER; while (isNum(m_str[m_tokenStart+m_tokenLen])) m_tokenLen += 1; } else if (isIdentifierChar(m_str[m_tokenStart])) { m_token = TOKEN_IDENTIFIER; while (isIdentifierChar(m_str[m_tokenStart+m_tokenLen])) m_tokenLen += 1; } else TCU_FAIL("Unexpected character"); }
/* Determines depth internalformat that can be used for a draw framebuffer. * The result is stored in m_depth_internal_format and m_depth_type. **/ void TextureCubeMapArrayColorDepthAttachmentsTest::determineSupportedDepthFormat() { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Start with 16-bit depth internalformat */ m_depth_internal_format = GL_DEPTH_COMPONENT16; m_depth_type = GL_UNSIGNED_SHORT; while (true) { /* Create color and depth texture objectss */ generateAndConfigureTextureObjects(8, /* texture_width */ 1, /* n_cubemaps */ false); /* should_generate_mutable_textures */ /* Set framebuffer attachments up */ configureNonLayeredFramebufferAttachment(m_color_texture_id, 0 /* layer */, true /* is_color_attachment */, true /* should_update_draw_framebuffer */); configureNonLayeredFramebufferAttachment(m_depth_texture_id, 0 /* layer */, false /* is_color_attachment */, true /* should_update_draw_framebuffer */); /* Check framebuffer status */ const glw::GLenum framebuffer_status = gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER); if (GL_FRAMEBUFFER_COMPLETE == framebuffer_status) { return; } /* Current format does not work too well, try another one */ switch (m_depth_internal_format) { case GL_DEPTH_COMPONENT16: { m_depth_internal_format = GL_DEPTH_COMPONENT24; m_depth_type = GL_UNSIGNED_INT; break; } case GL_DEPTH_COMPONENT24: { m_depth_internal_format = GL_DEPTH_COMPONENT32F; m_depth_type = GL_FLOAT; break; } case GL_DEPTH_COMPONENT32F: { throw tcu::NotSupportedError("Implementation does not support any known depth format"); } default: { TCU_FAIL("Unrecognized depth internalformat"); } } /* switch (m_depth_internal_format) */ } /* while (true) */ }
void ShaderBallotBaseTestCase::createShaderPrograms(ShaderPipeline& pipeline) { glu::ProgramSources sourcesRender; for (unsigned int i = 0; i < glu::SHADERTYPE_COMPUTE; ++i) { glu::ShaderType shaderType = (glu::ShaderType)i; std::map<std::string, std::string>::const_iterator mapIter; for (mapIter = pipeline.getSpecializationMap().begin(); mapIter != pipeline.getSpecializationMap().end(); mapIter++) m_specializationMap[mapIter->first] = mapIter->second; std::string shader = specializeShader(pipeline.getShaderPartsCount(shaderType), pipeline.getShaderParts(shaderType)); sourcesRender.sources[i].push_back(shader); } glu::ShaderProgram* programRender = new glu::ShaderProgram(m_context.getRenderContext(), sourcesRender); if (!programRender->isOk()) { TCU_FAIL("Shader compilation failed"); } glu::ProgramSources sourcesCompute; m_specializationMap.insert(pipeline.getSpecializationMap().begin(), pipeline.getSpecializationMap().end()); std::string shaderCompute = specializeShader(pipeline.getShaderPartsCount(glu::SHADERTYPE_COMPUTE), pipeline.getShaderParts(glu::SHADERTYPE_COMPUTE)); sourcesCompute.sources[glu::SHADERTYPE_COMPUTE].push_back(shaderCompute); glu::ShaderProgram* programCompute = new glu::ShaderProgram(m_context.getRenderContext(), sourcesCompute); if (!programCompute->isOk()) { TCU_FAIL("Shader compilation failed"); } pipeline.setShaderPrograms(programRender, programCompute); }
/** Check Framebuffer Status. * Throws a TestError exception, should the framebuffer be found incomplete. * * @param framebuffer - GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER or GL_FRAMEBUFFER * */ void TestCaseBase::checkFramebufferStatus(glw::GLenum framebuffer) const { /* Get GL entry points */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); glw::GLenum framebuffer_status = gl.checkFramebufferStatus(framebuffer); GLU_EXPECT_NO_ERROR(gl.getError(), "Error getting framebuffer status!"); if (GL_FRAMEBUFFER_COMPLETE != framebuffer_status) { switch (framebuffer_status) { case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: { TCU_FAIL("Framebuffer incomplete, status: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"); } case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: { TCU_FAIL("Framebuffer incomplete, status: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS"); } case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: { TCU_FAIL("Framebuffer incomplete, status: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"); } case GL_FRAMEBUFFER_UNSUPPORTED: { TCU_FAIL("Framebuffer incomplete, status: Error: GL_FRAMEBUFFER_UNSUPPORTED"); } default: { TCU_FAIL("Framebuffer incomplete, status not recognized"); } } /* switch (framebuffer_status) */ } /* if (GL_FRAMEBUFFER_COMPLETE != framebuffer_status) */ }
/** Retrieves compilation OR linking info log for a shader/program object with GLES id * @param id. * * @param is_compilation_info_log true if @param id is a GLES id of a shader object; * false if it represents a program object. * @param id GLES id of a shader OR a program object to * retrieve info log for. * * @return String instance containing the log.. **/ std::string TestCaseBase::getInfoLog(LOG_TYPE log_type, glw::GLuint id) { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); glw::GLint n_characters = 0; /* Retrieve amount of characters needed to store the info log (terminator-inclusive) */ switch (log_type) { case LT_SHADER_OBJECT: gl.getShaderiv(id, GL_INFO_LOG_LENGTH, &n_characters); break; case LT_PROGRAM_OBJECT: gl.getProgramiv(id, GL_INFO_LOG_LENGTH, &n_characters); break; case LT_PIPELINE_OBJECT: gl.getProgramPipelineiv(id, GL_INFO_LOG_LENGTH, &n_characters); break; default: TCU_FAIL("Invalid parameter"); } /* Check if everything is fine so far */ GLU_EXPECT_NO_ERROR(gl.getError(), "Could not query info log length!"); /* Allocate buffer */ std::vector<char> result_vec(n_characters + 1); /* Retrieve the info log */ switch (log_type) { case LT_SHADER_OBJECT: gl.getShaderInfoLog(id, n_characters + 1, 0, &result_vec[0]); break; case LT_PROGRAM_OBJECT: gl.getProgramInfoLog(id, n_characters + 1, 0, &result_vec[0]); break; case LT_PIPELINE_OBJECT: gl.getProgramPipelineInfoLog(id, n_characters + 1, 0, &result_vec[0]); break; } GLU_EXPECT_NO_ERROR(gl.getError(), "Could not retrieve info log!"); return std::string(&result_vec[0]); }
/** Set contents of texture * * @param gl GL functions * @param target Texture target * @param level Mipmap level * @param internal_format Format of data * @param width Width of texture * @param height Height of texture * @param depth Depth of texture * @param format Format of data * @param type Type of data * @param data Buffer with image data **/ void texImage(const Functions& gl, GLenum target, GLint level, GLenum internal_format, GLuint width, GLuint height, GLuint depth, GLenum format, GLenum type, const GLvoid* data) { switch (target) { case GL_TEXTURE_2D: gl.texImage2D(target, level, internal_format, width, height, 0 /* border */, format, type, data); GLU_EXPECT_NO_ERROR(gl.getError(), "texImage"); break; case GL_TEXTURE_2D_ARRAY: gl.texImage3D(target, level, internal_format, width, height, depth, 0 /* border */, format, type, data); GLU_EXPECT_NO_ERROR(gl.getError(), "texImage"); break; default: TCU_FAIL("Invalid enum"); break; } }
/** Set contents of texture * * @param gl GL functions * @param target Texture target * @param level Mipmap level * @param x X offset * @param y Y offset * @param z Z offset * @param width Width of texture * @param height Height of texture * @param depth Depth of texture * @param format Format of data * @param type Type of data * @param pixels Buffer with image data **/ void subImage(const Functions& gl, GLenum target, GLint level, GLint x, GLint y, GLint z, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels) { switch (target) { case GL_TEXTURE_2D: gl.texSubImage2D(target, level, x, y, width, height, format, type, pixels); GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D"); break; case GL_TEXTURE_2D_ARRAY: gl.texSubImage3D(target, level, x, y, z, width, height, depth, format, type, pixels); GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage3D"); break; default: TCU_FAIL("Invalid enum"); break; } }
/** Executes test iteration. * * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. */ tcu::TestNode::IterateResult MultisampleTextureSampleMaskiGettersTest::iterate() { /* Get GL_MAX_SAMPLE_MASK_WORDS value */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); glw::GLint gl_max_sample_mask_words_value = 0; gl.getIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &gl_max_sample_mask_words_value); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to retrieve GL_MAX_SAMPLE_MASK_WORDS value"); /* Iterate over valid index & mask values */ const glw::GLuint valid_masks[] = { 0, 0xFFFFFFFF, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF }; const unsigned int n_valid_masks = sizeof(valid_masks) / sizeof(valid_masks[0]); for (int index = 0; index < gl_max_sample_mask_words_value; ++index) { for (unsigned int n_mask = 0; n_mask < n_valid_masks; ++n_mask) { glw::GLint mask = valid_masks[n_mask]; /* Make sure a valid glSampleMaski() call does not result in an error */ gl.sampleMaski(index, mask); GLU_EXPECT_NO_ERROR(gl.getError(), "A valid glSampleMaski() call resulted in an error"); /* Check the property value as reported by implementation */ glw::GLint int_value = -1; gl.getIntegeri_v(GL_SAMPLE_MASK_VALUE, index, &int_value); GLU_EXPECT_NO_ERROR(gl.getError(), "A valid glGetIntegeri_v() call resulted in an error"); if (int_value != mask) { TCU_FAIL("Invalid sample mask reported"); } } /* for (all masks) */ } /* for (all valid index argument values) */ /* Test case passed */ m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return STOP; }
/** Executes test iteration. * * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. */ tcu::TestNode::IterateResult MultisampleTextureSampleMaskiIndexEqualToGLMaxSampleMaskWordsTest::iterate() { /* Get GL_MAX_SAMPLE_MASK_WORDS value */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); glw::GLint gl_max_sample_mask_words_value = 0; gl.getIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &gl_max_sample_mask_words_value); GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to retrieve GL_MAX_SAMPLE_MASK_WORDS value"); /* Issue call with valid parameters, but invalid index equal to GL_MAX_SAMPLE_MASK_WORDS value */ gl.sampleMaski(gl_max_sample_mask_words_value, 0); if (gl.getError() != GL_INVALID_VALUE) { TCU_FAIL("Invalid error code reported"); } /* Test case passed */ m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return STOP; }
void CompareData::exec (Thread& thread) { bool result = true; DE_ASSERT(m_a->getSize() == m_b->getSize()); thread.newMessage() << "Begin -- CompareData" << Message::End; for (int byteNdx = 0; byteNdx < (int)m_a->getSize(); byteNdx++) { if (m_a->getData()[byteNdx] != m_b->getData()[byteNdx]) { result = false; thread.newMessage() << "CompareData failed at offset :" << byteNdx << Message::End; break; } } if (result) thread.newMessage() << "CompareData passed" << Message::End; else TCU_FAIL("Data comparision failed"); thread.newMessage() << "End -- CompareData" << Message::End; }
void parseTypePath (const char* nameWithPath, const VarType& type, TypeComponentVector& path) { VarTokenizer tokenizer(nameWithPath); if (tokenizer.getToken() == VarTokenizer::TOKEN_IDENTIFIER) tokenizer.advance(); path.clear(); while (tokenizer.getToken() != VarTokenizer::TOKEN_END) { VarType curType = getVarType(type, path); if (tokenizer.getToken() == VarTokenizer::TOKEN_PERIOD) { tokenizer.advance(); TCU_CHECK(tokenizer.getToken() == VarTokenizer::TOKEN_IDENTIFIER); TCU_CHECK_MSG(curType.isStructType(), "Invalid field selector"); // Find member. std::string memberName = tokenizer.getIdentifier(); int ndx = 0; for (; ndx < curType.getStructPtr()->getNumMembers(); ndx++) { if (memberName == curType.getStructPtr()->getMember(ndx).getName()) break; } TCU_CHECK_MSG(ndx < curType.getStructPtr()->getNumMembers(), "Member not found in type"); path.push_back(VarTypeComponent(VarTypeComponent::STRUCT_MEMBER, ndx)); tokenizer.advance(); } else if (tokenizer.getToken() == VarTokenizer::TOKEN_LEFT_BRACKET) { tokenizer.advance(); TCU_CHECK(tokenizer.getToken() == VarTokenizer::TOKEN_NUMBER); int ndx = tokenizer.getNumber(); if (curType.isArrayType()) { TCU_CHECK(de::inBounds(ndx, 0, curType.getArraySize())); path.push_back(VarTypeComponent(VarTypeComponent::ARRAY_ELEMENT, ndx)); } else if (curType.isBasicType() && isDataTypeMatrix(curType.getBasicType())) { TCU_CHECK(de::inBounds(ndx, 0, getDataTypeMatrixNumColumns(curType.getBasicType()))); path.push_back(VarTypeComponent(VarTypeComponent::MATRIX_COLUMN, ndx)); } else if (curType.isBasicType() && isDataTypeVector(curType.getBasicType())) { TCU_CHECK(de::inBounds(ndx, 0, getDataTypeScalarSize(curType.getBasicType()))); path.push_back(VarTypeComponent(VarTypeComponent::VECTOR_COMPONENT, ndx)); } else TCU_FAIL("Invalid subscript"); tokenizer.advance(); TCU_CHECK(tokenizer.getToken() == VarTokenizer::TOKEN_RIGHT_BRACKET); tokenizer.advance(); } else TCU_FAIL("Unexpected token"); } }
/** Initializes ES objects necessary to run the test. */ void TessellationShaderQuadsDegenerateCase::initTest() { /* Skip if required extensions are not supported. */ if (!m_is_tessellation_shader_supported) { throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED); } /* Initialize Utils instance */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); m_utils = new TessellationShaderUtils(gl, this); /* Initialize vertex array object */ gl.genVertexArrays(1, &m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object"); gl.bindVertexArray(m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!"); /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */ glw::GLint gl_max_tess_gen_level_value = 0; gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_TESS_GEN_LEVEL_EXT pname"); /* Initialize all test runs */ const glw::GLint tess_levels[] = { -gl_max_tess_gen_level_value / 2, -1, 1 }; const unsigned int n_tess_levels = sizeof(tess_levels) / sizeof(tess_levels[0]); const _tessellation_shader_vertex_spacing vs_modes[] = { /* NOTE: We do not check "fractional even" vertex spacing since it will always * clamp to 2 which is out of scope for this test. */ TESSELLATION_SHADER_VERTEX_SPACING_DEFAULT, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD }; const unsigned int n_vs_modes = sizeof(vs_modes) / sizeof(vs_modes[0]); /* Iterate through all vertex spacing modes */ bool has_failed = false; for (unsigned int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode) { _tessellation_shader_vertex_spacing vs_mode = vs_modes[n_vs_mode]; /* Iterate through all values that should be used for irrelevant tessellation levels */ for (unsigned int n_tess_level = 0; n_tess_level < n_tess_levels; ++n_tess_level) { const glw::GLint tess_level = tess_levels[n_tess_level]; /* Set up the run descriptor. * * Round outer tesellation levels to 1 if necessary, since otherwise no geometry will * be generated. **/ _run run; run.inner[0] = (float)tess_level; run.inner[1] = (float)tess_level; run.outer[0] = (float)((tess_level < 0) ? 1 : tess_level); run.outer[1] = (float)((tess_level < 0) ? 1 : tess_level); run.outer[2] = (float)((tess_level < 0) ? 1 : tess_level); run.outer[3] = (float)((tess_level < 0) ? 1 : tess_level); run.vertex_spacing = vs_mode; /* Retrieve vertex data for both passes */ run.n_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator( TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS, run.inner, run.outer, run.vertex_spacing, false); /* is_point_mode_enabled */ if (run.n_vertices == 0) { std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vs_mode); m_testCtx.getLog() << tcu::TestLog::Message << "No vertices were generated by tessellator for: " "inner tess levels:" "[" << run.inner[0] << ", " << run.inner[1] << "]" ", outer tess levels:" "[" << run.outer[0] << ", " << run.outer[1] << ", " << run.outer[2] << ", " << run.outer[3] << "]" ", primitive mode: quads, " "vertex spacing: " << vs_mode_string << tcu::TestLog::EndMessage; has_failed = true; } else { /* Retrieve the data buffers */ run.data = m_utils->getDataGeneratedByTessellator(run.inner, false, /* is_point_mode_enabled */ TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS, TESSELLATION_SHADER_VERTEX_ORDERING_CCW, run.vertex_spacing, run.outer); } /* Store the run data */ m_runs.push_back(run); } /* for (all tessellation levels) */ } /* for (all vertex spacing modes) */ if (has_failed) { TCU_FAIL("Zero vertices were generated by tessellator for at least one run which is not " "a correct behavior"); } }
/* Initializes all ES objects needed to run the test */ void TextureCubeMapArrayColorDepthAttachmentsTest::initTest() { const glw::GLchar* depth_calculation_code = DE_NULL; const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Check if EXT_texture_cube_map_array extension is supported */ if (true != m_is_texture_cube_map_array_supported) { throw tcu::NotSupportedError(TEXTURE_CUBE_MAP_ARRAY_EXTENSION_NOT_SUPPORTED); } /* This test should only run if EXT_geometry_shader is supported */ if (true != m_is_geometry_shader_extension_supported) { throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED); } /* Generate and bind VAO */ gl.genVertexArrays(1, &m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object"); gl.bindVertexArray(m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!"); /* Create a framebuffer object */ gl.genFramebuffers(1, &m_framebuffer_object_id); GLU_EXPECT_NO_ERROR(gl.getError(), "genFramebuffers"); /* Determine which depth format can be used as a depth attachment without * making the FBO incomplete */ determineSupportedDepthFormat(); /* Decide which code snippet to use for depth value calculation */ switch (m_depth_internal_format) { case GL_DEPTH_COMPONENT16: { depth_calculation_code = "-1.0 + float(2 * layer) / float(0xffff)"; break; } case GL_DEPTH_COMPONENT24: { depth_calculation_code = "-1.0 + float(2 * layer) / float(0xffffff)"; break; } case GL_DEPTH_COMPONENT32F: { depth_calculation_code = "-1.0 + float(2 * layer) / 256.0"; break; } default: { TCU_FAIL("Unrecognized depth internal format"); } } /* switch (m_depth_internal_format) */ /* Create shader objects */ m_fragment_shader_id = gl.createShader(GL_FRAGMENT_SHADER); m_layered_geometry_shader_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER); m_non_layered_geometry_shader_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER); m_vertex_shader_id = gl.createShader(GL_VERTEX_SHADER); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed."); /* Create program objects */ m_layered_program_id = gl.createProgram(); m_non_layered_program_id = gl.createProgram(); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call(s) failed"); /* Build up an array of snippets making up bodies of two geometry shaders * we'll be using for the test. */ const glw::GLchar* const layered_geometry_shader_parts[] = { m_geometry_shader_code_preamble, m_geometry_shader_code_layered, " float depth = ", depth_calculation_code, m_geometry_shader_code_body }; const glw::GLchar* const non_layered_geometry_shader_parts[] = { m_geometry_shader_code_preamble, m_geometry_shader_code_non_layered, " float depth = ", depth_calculation_code, m_geometry_shader_code_body }; const glw::GLuint n_layered_geometry_shader_parts = sizeof(layered_geometry_shader_parts) / sizeof(layered_geometry_shader_parts[0]); const glw::GLuint n_non_layered_geometry_shader_parts = sizeof(non_layered_geometry_shader_parts) / sizeof(non_layered_geometry_shader_parts[0]); /* Build both programs */ if (!buildProgram(m_layered_program_id, m_fragment_shader_id, 1, &m_fragment_shader_code, m_layered_geometry_shader_id, n_layered_geometry_shader_parts, layered_geometry_shader_parts, m_vertex_shader_id, 1, &m_vertex_shader_code)) { TCU_FAIL("Could not build layered-case program object"); } if (!buildProgram(m_non_layered_program_id, m_fragment_shader_id, 1, &m_fragment_shader_code, m_non_layered_geometry_shader_id, n_non_layered_geometry_shader_parts, non_layered_geometry_shader_parts, m_vertex_shader_id, 1, &m_vertex_shader_code)) { TCU_FAIL("Could not build non-layered-case program object"); } /* Get location of "uni_layer" uniform */ m_non_layered_program_id_uni_layer_uniform_location = gl.getUniformLocation(m_non_layered_program_id, "uni_layer"); if ((-1 == m_non_layered_program_id_uni_layer_uniform_location) || (GL_NO_ERROR != gl.getError())) { TCU_FAIL("Could not retrieve location of uni_layer uniform for non-layered program"); } }
/** Initializes ES objects necessary to run the test. */ void TessellationShaderQuadsInnerTessellationLevelRounding::initTest() { /* Skip if required extensions are not supported. */ if (!m_is_tessellation_shader_supported) { throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED); } /* Initialize Utils instance */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); m_utils = new TessellationShaderUtils(gl, this); /* Initialize vertex array object */ gl.genVertexArrays(1, &m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object"); gl.bindVertexArray(m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!"); /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */ glw::GLint gl_max_tess_gen_level_value = 0; gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_TESS_GEN_LEVEL_EXT pname"); /* Initialize all test runs */ const glw::GLint tess_levels[] = { 2, gl_max_tess_gen_level_value / 2, gl_max_tess_gen_level_value }; const glw::GLint tess_levels_odd[] = { 2 + 1, gl_max_tess_gen_level_value / 2 + 1, gl_max_tess_gen_level_value - 1 }; const unsigned int n_tess_levels = sizeof(tess_levels) / sizeof(tess_levels[0]); const _tessellation_shader_vertex_spacing vs_modes[] = { TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD }; const unsigned int n_vs_modes = sizeof(vs_modes) / sizeof(vs_modes[0]); /* Iterate through all vertex spacing modes */ for (unsigned int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode) { _tessellation_shader_vertex_spacing vs_mode = vs_modes[n_vs_mode]; /* Iterate through all values that should be used for irrelevant tessellation levels */ for (unsigned int n_tess_level = 0; n_tess_level < n_tess_levels; ++n_tess_level) { /* We need to test two cases in this test: * * a) inner[0] is set to 1 for set A and, for set B, to the value we're expecting the level to * round, given the vertex spacing mode. inner[1] is irrelevant. * b) inner[0] is irrelevant. inner[1] is set to 1 for set A and, for set B, to the value we're * expecting the level to round, given the vertex spacing mode. */ for (unsigned int n_inner_tess_level_combination = 0; n_inner_tess_level_combination < 2; /* inner[0], inner[1] */ ++n_inner_tess_level_combination) { /* Set up the run descriptor */ glw::GLint tess_level = (vs_mode == TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD) ? tess_levels_odd[n_tess_level] : tess_levels[n_tess_level]; _run run; /* Determine inner tessellation level values for two cases */ switch (n_inner_tess_level_combination) { case 0: { run.set1_inner[0] = 1.0f; run.set1_inner[1] = (glw::GLfloat)tess_level; run.set2_inner[1] = (glw::GLfloat)tess_level; TessellationShaderUtils::getTessellationLevelAfterVertexSpacing( vs_mode, run.set1_inner[0] + 1.0f /* epsilon */, gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */ run.set2_inner); break; } /* case 0: */ case 1: { run.set1_inner[0] = (glw::GLfloat)tess_level; run.set1_inner[1] = 1.0f; run.set2_inner[0] = (glw::GLfloat)tess_level; TessellationShaderUtils::getTessellationLevelAfterVertexSpacing( vs_mode, run.set1_inner[1] + 1.0f /* epsilon */, gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */ run.set2_inner + 1); break; } /* case 1: */ default: TCU_FAIL("Invalid inner tessellation level combination index"); } /* switch (n_inner_tess_level_combination) */ /* Configure outer tessellation level values */ run.set1_outer[0] = (glw::GLfloat)tess_level; run.set2_outer[0] = (glw::GLfloat)tess_level; run.set1_outer[1] = (glw::GLfloat)tess_level; run.set2_outer[1] = (glw::GLfloat)tess_level; run.set1_outer[2] = (glw::GLfloat)tess_level; run.set2_outer[2] = (glw::GLfloat)tess_level; run.set1_outer[3] = (glw::GLfloat)tess_level; run.set2_outer[3] = (glw::GLfloat)tess_level; /* Set up remaining run properties */ run.vertex_spacing = vs_mode; /* Retrieve vertex data for both passes */ glw::GLint n_set1_vertices = 0; glw::GLint n_set2_vertices = 0; n_set1_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator( TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS, run.set1_inner, run.set1_outer, run.vertex_spacing, false); /* is_point_mode_enabled */ n_set2_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator( TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS, run.set2_inner, run.set2_outer, run.vertex_spacing, false); /* is_point_mode_enabled */ if (n_set1_vertices == 0) { std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vs_mode); m_testCtx.getLog() << tcu::TestLog::Message << "No vertices were generated by tessellator for: " "inner tess levels:" "[" << run.set1_inner[0] << ", " << run.set1_inner[1] << "]" ", outer tess levels:" "[" << run.set1_outer[0] << ", " << run.set1_outer[1] << ", " << run.set1_outer[2] << ", " << run.set1_outer[3] << "]" ", primitive mode: quads, " "vertex spacing: " << vs_mode_string << tcu::TestLog::EndMessage; TCU_FAIL("Zero vertices were generated by tessellator for first test pass"); } if (n_set2_vertices == 0) { std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vs_mode); m_testCtx.getLog() << tcu::TestLog::Message << "No vertices were generated by tessellator for: " "inner tess levels:" "[" << run.set2_inner[0] << ", " << run.set2_inner[1] << "]" ", outer tess levels:" "[" << run.set2_outer[0] << ", " << run.set2_outer[1] << ", " << run.set2_outer[2] << ", " << run.set2_outer[3] << "]" ", primitive mode: quads, " "vertex spacing: " << vs_mode_string << tcu::TestLog::EndMessage; TCU_FAIL("Zero vertices were generated by tessellator for second test pass"); } if (n_set1_vertices != n_set2_vertices) { std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vs_mode); m_testCtx.getLog() << tcu::TestLog::Message << "Amount of vertices generated by the tessellator differs" " for the following inner/outer configs: " "inner tess levels:" "[" << run.set1_inner[0] << ", " << run.set1_inner[1] << "]" ", outer tess levels:" "[" << run.set1_outer[0] << ", " << run.set1_outer[1] << ", " << run.set1_outer[2] << ", " << run.set1_outer[3] << "]" " and inner tess levels:" "[" << run.set2_inner[0] << ", " << run.set2_inner[1] << "]" ", outer tess levels:" "[" << run.set2_outer[0] << ", " << run.set2_outer[1] << ", " << run.set2_outer[2] << ", " << run.set2_outer[3] << "]" ", primitive mode: quads, vertex spacing: " << vs_mode_string << tcu::TestLog::EndMessage; TCU_FAIL("Amount of vertices generated by tessellator differs between base and references passes"); } /* Store the amount of vertices in run properties */ run.n_vertices = n_set1_vertices; /* Retrieve the data buffers */ run.set1_data = m_utils->getDataGeneratedByTessellator( run.set1_inner, false, /* is_point_mode_enabled */ TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS, TESSELLATION_SHADER_VERTEX_ORDERING_CCW, run.vertex_spacing, run.set1_outer); run.set2_data = m_utils->getDataGeneratedByTessellator( run.set2_inner, false, /* is_point_mode_enabled */ TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS, TESSELLATION_SHADER_VERTEX_ORDERING_CCW, run.vertex_spacing, run.set2_outer); /* Store the run data */ m_runs.push_back(run); } /* for (all inner tess level combinations) */ } /* for (all sets) */ } /* for (all vertex spacing modes) */ }
/** Executes the test. * * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * * Note the function throws exception should an error occur! * * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again. **/ tcu::TestNode::IterateResult TessellationShaderQuadsInnerTessellationLevelRounding::iterate(void) { /* Do not execute if required extensions are not supported. */ if (!m_is_tessellation_shader_supported) { throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED); } /* Initialize the test */ initTest(); /* Iterate through all runs */ for (_runs_const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++) { const _run& run = *run_iterator; if (run.vertex_spacing != TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD) { /* Make sure the vertex data generated for two passes matches */ const glw::GLint n_triangles = run.n_vertices / 3 /* vertices per triangle */; std::vector<bool> triangleMatched; triangleMatched.assign(n_triangles, false); for (int n_triangle = 0; n_triangle < n_triangles; ++n_triangle) { const float* triangle_a = (const float*)(&run.set1_data[0]) + n_triangle * 3 /* vertices */ * 3; /* components */ /* Look up matching triangle */ bool triangleFound = false; for (int n_triangle_b = 0; n_triangle_b < n_triangles; ++n_triangle_b) { if (!triangleMatched[n_triangle_b]) { const float* triangle_b = (const float*)(&run.set2_data[0]) + n_triangle_b * 3 /* vertices */ * 3; /* components */ if (TessellationShaderUtils::isTriangleDefined(triangle_a, triangle_b)) { triangleMatched[n_triangle_b] = true; triangleFound = true; break; } } } if (!triangleFound) { std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(run.vertex_spacing); m_testCtx.getLog() << tcu::TestLog::Message << "The following triangle, generated in the first pass, was not " "generated in the second one. " "First pass' configuration: inner tess levels:" "[" << run.set1_inner[0] << ", " << run.set1_inner[1] << "]" ", outer tess levels:" "[" << run.set1_outer[0] << ", " << run.set1_outer[1] << ", " << run.set1_outer[2] << ", " << run.set1_outer[3] << "]" "; second pass' configuration: inner tess levels:" "[" << run.set2_inner[0] << ", " << run.set2_inner[1] << "]" ", outer tess levels:" "[" << run.set2_outer[0] << ", " << run.set2_outer[1] << ", " << run.set2_outer[2] << ", " << run.set2_outer[3] << "]" ", primitive mode: quads, vertex spacing: " << vs_mode_string << tcu::TestLog::EndMessage; TCU_FAIL("A triangle from first pass' data set was not found in second pass' data set."); } } /* for (all vertices) */ } /* if (run.vertex_spacing != TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD) */ else { /* For Fractional Odd vertex spacing, we cannot apply the above methodology because of the fact * two of the inner edges (the ones subdivided with tessellation level of 1.0) will have been * subdivided differently between two runs, causing the vertex positions to shift, ultimately * leading to isTriangleDefined() failure. * * Hence, we need to take a bit different approach for this case. If you look at a visualization * of a tessellated quad, for which one of the inner tess levels has been set to 1 (let's assume * inner[0] for the sake of discussion), and then looked at a list of points that were generated by the * tessellator, you'll notice that even though it looks like we only have one span of triangles * horizontally, there are actually three. The two outermost spans on each side (the "outer * tessellation regions") are actually degenerate, because they have epsilon spacing allocated to * them. * * Using the theory above, we look for a so-called "marker triangle". In the inner[0] = 1.0 case, * it's one of the two triangles, one edge of which spans horizontally across the whole domain, and * the other two edges touch the outermost edge of the quad. In the inner[1] = 1.0 case, Xs are flipped * with Ys, but the general idea stays the same. * * So for fractional odd vertex spacing, this test verifies that the two marker triangles capping the * opposite ends of the inner quad tessellation region exist. */ /* Convert arrayed triangle-based representation to a vector storing unique tessellation * coordinates. */ std::vector<_vec2> set1_tess_coordinates = getUniqueTessCoordinatesFromVertexDataSet((const float*)(&run.set1_data[0]), run.n_vertices); /* Extract and sort the coordinate components we have from * the minimum to the maximum */ std::vector<float> set1_tess_coordinates_x_sorted; std::vector<float> set1_tess_coordinates_y_sorted; for (std::vector<_vec2>::iterator coordinate_iterator = set1_tess_coordinates.begin(); coordinate_iterator != set1_tess_coordinates.end(); coordinate_iterator++) { const _vec2& coordinate = *coordinate_iterator; if (std::find(set1_tess_coordinates_x_sorted.begin(), set1_tess_coordinates_x_sorted.end(), coordinate.x) == set1_tess_coordinates_x_sorted.end()) { set1_tess_coordinates_x_sorted.push_back(coordinate.x); } if (std::find(set1_tess_coordinates_y_sorted.begin(), set1_tess_coordinates_y_sorted.end(), coordinate.y) == set1_tess_coordinates_y_sorted.end()) { set1_tess_coordinates_y_sorted.push_back(coordinate.y); } } /* for (all tessellation coordinates) */ std::sort(set1_tess_coordinates_x_sorted.begin(), set1_tess_coordinates_x_sorted.end()); std::sort(set1_tess_coordinates_y_sorted.begin(), set1_tess_coordinates_y_sorted.end()); /* Sanity checks */ DE_ASSERT(set1_tess_coordinates_x_sorted.size() > 2); DE_ASSERT(set1_tess_coordinates_y_sorted.size() > 2); /* NOTE: This code could have been merged for both cases at the expense of code readability. */ if (run.set1_inner[0] == 1.0f) { /* Look for the second horizontal line segment, starting from top and bottom */ const float second_y_from_top = set1_tess_coordinates_y_sorted[1]; const float second_y_from_bottom = set1_tess_coordinates_y_sorted[set1_tess_coordinates_y_sorted.size() - 2]; /* In this particular case, there should be exactly one triangle spanning * from U=0 to U=1 at both these heights, with the third coordinate located * at the "outer" edge. */ for (int n = 0; n < 2 /* cases */; ++n) { float y1_y2 = 0.0f; float y3 = 0.0f; if (n == 0) { y1_y2 = second_y_from_bottom; y3 = 1.0f; } else { y1_y2 = second_y_from_top; y3 = 0.0f; } /* Try to find the triangle */ bool has_found_triangle = false; DE_ASSERT((run.n_vertices % 3) == 0); for (unsigned int n_triangle = 0; n_triangle < run.n_vertices / 3; ++n_triangle) { const float* vertex1_data = (const float*)(&run.set1_data[0]) + 3 /* vertices */ * 3 /* components */ * n_triangle; const float* vertex2_data = vertex1_data + 3 /* components */; const float* vertex3_data = vertex2_data + 3 /* components */; /* Make sure at least two Y coordinates are equal to y1_y2. */ const float* y1_vertex_data = DE_NULL; const float* y2_vertex_data = DE_NULL; const float* y3_vertex_data = DE_NULL; if (vertex1_data[1] == y1_y2) { if (vertex2_data[1] == y1_y2 && vertex3_data[1] == y3) { y1_vertex_data = vertex1_data; y2_vertex_data = vertex2_data; y3_vertex_data = vertex3_data; } else if (vertex2_data[1] == y3 && vertex3_data[1] == y1_y2) { y1_vertex_data = vertex1_data; y2_vertex_data = vertex3_data; y3_vertex_data = vertex2_data; } } else if (vertex2_data[1] == y1_y2 && vertex3_data[1] == y1_y2 && vertex1_data[1] == y3) { y1_vertex_data = vertex2_data; y2_vertex_data = vertex3_data; y3_vertex_data = vertex1_data; } if (y1_vertex_data != DE_NULL && y2_vertex_data != DE_NULL && y3_vertex_data != DE_NULL) { /* Vertex 1 and 2 should span across whole domain horizontally */ if ((y1_vertex_data[0] == 0.0f && y2_vertex_data[0] == 1.0f) || (y1_vertex_data[0] == 1.0f && y2_vertex_data[0] == 0.0f)) { has_found_triangle = true; break; } } } /* for (all triangles) */ if (!has_found_triangle) { TCU_FAIL("Could not find a marker triangle"); } } /* for (both cases) */ } /* if (run.set1_inner[0] == 1.0f) */ else { DE_ASSERT(run.set1_inner[1] == 1.0f); /* Look for the second vertical line segment, starting from left and right */ const float second_x_from_left = set1_tess_coordinates_x_sorted[1]; const float second_x_from_right = set1_tess_coordinates_x_sorted[set1_tess_coordinates_x_sorted.size() - 2]; /* In this particular case, there should be exactly one triangle spanning * from V=0 to V=1 at both these widths, with the third coordinate located * at the "outer" edge. */ for (int n = 0; n < 2 /* cases */; ++n) { float x1_x2 = 0.0f; float x3 = 0.0f; if (n == 0) { x1_x2 = second_x_from_right; x3 = 1.0f; } else { x1_x2 = second_x_from_left; x3 = 0.0f; } /* Try to find the triangle */ bool has_found_triangle = false; DE_ASSERT((run.n_vertices % 3) == 0); for (unsigned int n_triangle = 0; n_triangle < run.n_vertices / 3; ++n_triangle) { const float* vertex1_data = (const float*)(&run.set1_data[0]) + 3 /* vertices */ * 3 /* components */ * n_triangle; const float* vertex2_data = vertex1_data + 3 /* components */; const float* vertex3_data = vertex2_data + 3 /* components */; /* Make sure at least two X coordinates are equal to x1_x2. */ const float* x1_vertex_data = DE_NULL; const float* x2_vertex_data = DE_NULL; const float* x3_vertex_data = DE_NULL; if (vertex1_data[0] == x1_x2) { if (vertex2_data[0] == x1_x2 && vertex3_data[0] == x3) { x1_vertex_data = vertex1_data; x2_vertex_data = vertex2_data; x3_vertex_data = vertex3_data; } else if (vertex2_data[0] == x3 && vertex3_data[0] == x1_x2) { x1_vertex_data = vertex1_data; x2_vertex_data = vertex3_data; x3_vertex_data = vertex2_data; } } else if (vertex2_data[0] == x1_x2 && vertex3_data[0] == x1_x2 && vertex1_data[0] == x3) { x1_vertex_data = vertex2_data; x2_vertex_data = vertex3_data; x3_vertex_data = vertex1_data; } if (x1_vertex_data != DE_NULL && x2_vertex_data != DE_NULL && x3_vertex_data != DE_NULL) { /* Vertex 1 and 2 should span across whole domain vertically */ if ((x1_vertex_data[1] == 0.0f && x2_vertex_data[1] == 1.0f) || (x1_vertex_data[1] == 1.0f && x2_vertex_data[1] == 0.0f)) { has_found_triangle = true; break; } } } /* for (all triangles) */ if (!has_found_triangle) { TCU_FAIL("Could not find a marker triangle (implies invalid quad tessellation for the case " "considered)"); } } /* for (both cases) */ } } } /* for (all runs) */ /* All done */ m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return STOP; }
/** Verifies layered rendering works correctly. * * @param texture_size Resolution of texture * @param should_use_mutable_texture true if an immutable texture should be used for * the invocation; false if mutable. **/ void TextureCubeMapArrayColorDepthAttachmentsTest::testNonLayeredRendering(const _texture_size& texture_size, bool should_use_mutable_texture) { const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Activate a program object that renders in a non-layered fashion */ gl.useProgram(m_non_layered_program_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed."); /* Create relevant textures */ generateAndConfigureTextureObjects(texture_size.m_size, texture_size.m_n_cubemaps, should_use_mutable_texture); /* Iterate over all layer-faces */ for (glw::GLuint n_layer_face = 0; n_layer_face < texture_size.m_n_cubemaps * 6 /* layer-faces per cube-map */; ++n_layer_face) { /* Set up non-layered framebuffer attachments */ configureNonLayeredFramebufferAttachment(m_color_texture_id, n_layer_face, true /* is_color_attachment */); configureNonLayeredFramebufferAttachment(m_depth_texture_id, n_layer_face, false /* is_color_attachment */); /* Update value assigned to "uni_layer" uniform */ gl.uniform1i(m_non_layered_program_id_uni_layer_uniform_location, n_layer_face); GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i() call failed."); /* Execute a draw call */ draw(texture_size); /* Restore default framebuffer attachments */ configureNonLayeredFramebufferAttachment(0 /* texture_id */, 0 /* n_layer */, true /* should_use_as_color_attachment */); configureNonLayeredFramebufferAttachment(0 /* texture_id */, 0 /* n_layer */, false /* should_use_as_color_attachment */); /* Remove draw framebuffer binding */ gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed."); /* Verify the results. First, make sure the read framebuffer binding is configured * accordingly. */ gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_framebuffer_object_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed."); /* Configure read framebuffer attachments to point to the layer of our current interest */ configureNonLayeredFramebufferAttachment(m_color_texture_id, n_layer_face, true, /* should_use_as_color_attachment */ false); /* should_update_draw_framebuffer */ configureNonLayeredFramebufferAttachment(m_depth_texture_id, n_layer_face, false, /* should_use_as_color_attachment */ false); /* should_update_draw_framebuffer */ /* Verify contents of color and depth attachments */ bool is_color_data_ok = verifyColorData(texture_size, n_layer_face); bool is_depth_data_ok = false; if (!glu::isContextTypeES(m_context.getRenderContext().getType())) { switch (m_depth_internal_format) { case GL_DEPTH_COMPONENT16: { is_depth_data_ok = verifyDepth16Data(texture_size, n_layer_face); break; } case GL_DEPTH_COMPONENT24: { is_depth_data_ok = verifyDepth24Data(texture_size, n_layer_face); break; } case GL_DEPTH_COMPONENT32F: { is_depth_data_ok = verifyDepth32FData(texture_size, n_layer_face); break; } default: { TCU_FAIL("Unrecognized depth internalformat"); } } /* switch (m_depth_internal_format) */ } else { is_depth_data_ok = true; } /* Any errors? Increment relevant counters */ if (false == is_color_data_ok) { m_n_invalid_color_checks++; } if (false == is_depth_data_ok) { m_n_invalid_depth_checks++; } } /* for (all layer-faces) */ }
/** Executes the test. * * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * * Note the function throws exception should an error occur! * * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again. **/ tcu::TestNode::IterateResult TessellationShaderQuadsDegenerateCase::iterate(void) { /* Do not execute if required extensions are not supported. */ if (!m_is_tessellation_shader_supported) { throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED); } /* Initialize the test */ initTest(); /* Iterate through all runs */ /* The test fails if any of the runs did not generate exactly 6 coordinates */ for (_runs_const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++) { const _run& run = *run_iterator; if (run.n_vertices != (2 /* triangles */ * 3 /* vertices */)) { std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(run.vertex_spacing); m_testCtx.getLog() << tcu::TestLog::Message << "Invalid number of coordinates (" << run.n_vertices << ", instead of 6)" " was generated for the following tessellation configuration: " "primitive mode:quads, " "vertex spacing mode:" << vs_mode_string << " inner tessellation levels:" << run.inner[0] << ", " << run.inner[1] << " outer tessellation levels:" << run.outer[0] << ", " << run.outer[1] << ", " << run.outer[2] << ", " << run.outer[3] << tcu::TestLog::EndMessage; TCU_FAIL("Invalid number of coordinates was generated for at least one run"); } } /* for (all runs) */ /* All runs should generate exactly the same set of triangles. * * Note: we must not assume any specific vertex ordering, so we cannot * just do a plain memcmp() here. */ const _run& base_run = *m_runs.begin(); for (unsigned int n_triangle = 0; n_triangle < base_run.n_vertices / 3 /* vertices per triangle */; n_triangle++) { const float* base_triangle_data = (const float*)(&base_run.data[0]) + 3 /* vertices per triangle */ * 3 /* components */ * n_triangle; for (_runs_const_iterator ref_run_iterator = m_runs.begin() + 1; ref_run_iterator != m_runs.end(); ref_run_iterator++) { const _run& ref_run = *ref_run_iterator; const float* ref_triangle_data1 = (const float*)(&ref_run.data[0]); const float* ref_triangle_data2 = (const float*)(&ref_run.data[0]) + 3 /* vertices per triangle */ * 3 /* components */; if (!TessellationShaderUtils::isTriangleDefined(base_triangle_data, ref_triangle_data1) && !TessellationShaderUtils::isTriangleDefined(base_triangle_data, ref_triangle_data2)) { std::string base_vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(base_run.vertex_spacing); std::string ref_vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(ref_run.vertex_spacing); m_testCtx.getLog() << tcu::TestLog::Message << "Reference run does not contain a triangle found in a base run" " generated for the following tessellation configuration: " "primitive mode:quads, " "base vertex spacing mode:" << base_vs_mode_string << " base inner tessellation levels:" << base_run.inner[0] << ", " << base_run.inner[1] << " base outer tessellation levels:" << base_run.outer[0] << ", " << base_run.outer[1] << ", " << base_run.outer[2] << ", " << base_run.outer[3] << "reference vertex spacing mode:" << ref_vs_mode_string << " reference inner tessellation levels:" << ref_run.inner[0] << ", " << ref_run.inner[1] << " reference outer tessellation levels:" << ref_run.outer[0] << ", " << ref_run.outer[1] << ", " << ref_run.outer[2] << ", " << ref_run.outer[3] << tcu::TestLog::EndMessage; TCU_FAIL("Reference run does not contain a triangle found in a base run"); } } /* for (all reference runs) */ } /* for (all triangles) */ /* All done */ m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return STOP; }
/** @brief Function builds test's GLSL program. * If succeded, the program will be set to be used. * * @note The function may throw if unexpected error has occured. */ void TextureCubeMapArrayETC2Support::prepareProgram() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); struct Shader { glw::GLchar const* const source; glw::GLenum const type; glw::GLuint id; } shader[] = { { s_vertex_shader, GL_VERTEX_SHADER, 0 }, { s_fragment_shader, GL_FRAGMENT_SHADER, 0 } }; bool programPreparationFailed = false; glw::GLuint const shader_count = sizeof(shader) / sizeof(shader[0]); /* Create program. */ m_program = gl.createProgram(); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram call failed."); /* Shader compilation. */ for (glw::GLuint i = 0; i < shader_count; ++i) { if (DE_NULL != shader[i].source) { shader[i].id = gl.createShader(shader[i].type); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader call failed."); gl.attachShader(m_program, shader[i].id); GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader call failed."); glu::ContextType contextType = m_context.getRenderContext().getType(); glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(contextType); std::string shaderSource(glu::getGLSLVersionDeclaration(glslVersion)); shaderSource += shader[i].source; const char* source = shaderSource.c_str(); gl.shaderSource(shader[i].id, 1, &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 error, log:\n" << log_text << "\n" << "Shader source code:\n" << shaderSource << "\n" << tcu::TestLog::EndMessage; delete[] log_text; GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderInfoLog call failed."); programPreparationFailed = true; break; } } } if (programPreparationFailed) { if (m_program) { gl.deleteProgram(m_program); m_program = 0; } } else { /* Link. */ gl.linkProgram(m_program); GLU_EXPECT_NO_ERROR(gl.getError(), "glLlinkProgram call failed."); glw::GLint status = GL_FALSE; gl.getProgramiv(m_program, GL_LINK_STATUS, &status); if (GL_TRUE == status) { for (glw::GLuint i = 0; i < shader_count; ++i) { if (shader[i].id) { gl.detachShader(m_program, shader[i].id); GLU_EXPECT_NO_ERROR(gl.getError(), "glDetachShader call failed."); } } } else { glw::GLint log_size = 0; gl.getProgramiv(m_program, 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_program, 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."); programPreparationFailed = true; } } for (glw::GLuint i = 0; i < shader_count; ++i) { if (0 != shader[i].id) { gl.deleteShader(shader[i].id); shader[i].id = 0; } } if (m_program) { glw::GLint textureSampler = gl.getUniformLocation(m_program, "texture_sampler"); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformLocation call failed."); gl.useProgram(m_program); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed."); gl.uniform1i(textureSampler, 0); GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i call failed."); } else TCU_FAIL("Failed to prepare program"); }
void ShaderBallotBaseTestCase::ShaderPipeline::executeComputeShader(deqp::Context& context) { const glw::Functions& gl = context.getRenderContext().getFunctions(); const glu::Texture outputTexture(context.getRenderContext()); gl.useProgram(m_programCompute->getProgram()); // output image gl.bindTexture(GL_TEXTURE_2D, *outputTexture); gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32UI, 16, 16); gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading image data failed"); // bind image gl.bindImageTexture(1, *outputTexture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32UI); GLU_EXPECT_NO_ERROR(gl.getError(), "Image setup failed"); // dispatch compute gl.dispatchCompute(1, 1, 1); GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute()"); gl.memoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT); GLU_EXPECT_NO_ERROR(gl.getError(), "glMemoryBarrier()"); // render output texture std::string vs = "#version 450 core\n" "in highp vec2 position;\n" "in vec2 inTexcoord;\n" "out vec2 texcoord;\n" "void main()\n" "{\n" " texcoord = inTexcoord;\n" " gl_Position = vec4(position, 0.0, 1.0);\n" "}\n"; std::string fs = "#version 450 core\n" "uniform sampler2D sampler;\n" "in vec2 texcoord;\n" "out vec4 color;\n" "void main()\n" "{\n" " color = texture(sampler, texcoord);\n" "}\n"; glu::ProgramSources sources; sources.sources[glu::SHADERTYPE_VERTEX].push_back(vs); sources.sources[glu::SHADERTYPE_FRAGMENT].push_back(fs); glu::ShaderProgram renderShader(context.getRenderContext(), sources); if (!m_programRender->isOk()) { TCU_FAIL("Shader compilation failed"); } gl.bindTexture(GL_TEXTURE_2D, *outputTexture); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); gl.useProgram(renderShader.getProgram()); gl.uniform1i(gl.getUniformLocation(renderShader.getProgram(), "sampler"), 0); GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i failed"); deUint16 const quadIndices[] = { 0, 1, 2, 2, 1, 3 }; float const position[] = { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f }; float const texCoord[] = { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f }; glu::VertexArrayBinding vertexArrays[] = { glu::va::Float("position", 2, 4, 0, position), glu::va::Float("inTexcoord", 2, 4, 0, texCoord) }; glu::draw(context.getRenderContext(), renderShader.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), vertexArrays, glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), quadIndices)); GLU_EXPECT_NO_ERROR(gl.getError(), "glu::draw error"); }
/** Initializes all ES objects necessary to run a specific test pass. * * @param test Test descriptor to fill with IDs of initialized objects. * @param vertex_spacing Vertex spacing mode to use for the run. **/ void TessellationShaderTrianglesDegenerateTriangle::initTestDescriptor( _test_descriptor& test, _tessellation_shader_vertex_spacing vertex_spacing) { test.vertex_spacing = vertex_spacing; /* Set up a program object for the descriptor */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); test.po_id = gl.createProgram(); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed"); /* Set up a pass-specific tessellation evaluation shader object. */ test.te_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed"); /* Configure tessellation evaluation shader body */ const char* te_template = "${VERSION}\n" "\n" "${TESSELLATION_SHADER_REQUIRE}\n" "\n" "layout (triangles, VERTEX_SPACING_MODE) in;\n" "\n" "out vec3 result_uvw;\n" "\n" "void main()\n" "{\n" " gl_Position = gl_in[0].gl_Position;\n" " result_uvw = gl_TessCoord;\n" "}\n"; const char* te_body_raw_ptr = DE_NULL; std::string te_body_string = te_template; std::string vertex_spacing_mode_string; const char* vertex_spacing_token = "VERTEX_SPACING_MODE"; std::size_t vertex_spacing_token_index = std::string::npos; switch (vertex_spacing) { case TESSELLATION_SHADER_VERTEX_SPACING_EQUAL: { vertex_spacing_mode_string = "equal_spacing"; break; } case TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD: { vertex_spacing_mode_string = "fractional_odd_spacing"; break; } default: { TCU_FAIL("Invalid vertex spacing mode requested"); } } while ((vertex_spacing_token_index = te_body_string.find(vertex_spacing_token)) != std::string::npos) { te_body_string = te_body_string.replace(vertex_spacing_token_index, strlen(vertex_spacing_token), vertex_spacing_mode_string); vertex_spacing_token_index = te_body_string.find(vertex_spacing_token); } te_body_raw_ptr = te_body_string.c_str(); shaderSourceSpecialized(test.te_id, 1 /* count */, &te_body_raw_ptr); GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation evaluation shader"); /* Compile the tessellation evaluation shader */ glw::GLint compile_status = GL_FALSE; gl.compileShader(test.te_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed for tessellation evaluation shader"); gl.getShaderiv(test.te_id, GL_COMPILE_STATUS, &compile_status); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed for tessellation evaluation shader"); if (compile_status != GL_TRUE) { TCU_FAIL("Tessellation evaluation shader compilation failed"); } /* Attach all shader to the program object */ gl.attachShader(test.po_id, m_fs_id); gl.attachShader(test.po_id, m_tc_id); gl.attachShader(test.po_id, test.te_id); gl.attachShader(test.po_id, m_vs_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() failed"); /* Set up XFB */ const char* varyings[] = { "result_uvw" }; const unsigned int n_varyings = sizeof(varyings) / sizeof(varyings[0]); gl.transformFeedbackVaryings(test.po_id, n_varyings, varyings, GL_INTERLEAVED_ATTRIBS); GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed"); /* Link the program object */ glw::GLint link_status = GL_FALSE; gl.linkProgram(test.po_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() failed"); gl.getProgramiv(test.po_id, GL_LINK_STATUS, &link_status); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed"); if (link_status != GL_TRUE) { TCU_FAIL("Program linking failed"); } }
/** Initializes ES objects necessary to run the test. */ void TessellationShaderTrianglesDegenerateTriangle::initTest() { /* Skip if required extensions are not supported. */ if (!m_is_tessellation_shader_supported) { throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED); } /* Generate all test-wide objects needed for test execution */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); gl.genVertexArrays(1, &m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object"); gl.bindVertexArray(m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!"); gl.genBuffers(1, &m_bo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed"); m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); m_tc_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER); m_vs_id = gl.createShader(GL_VERTEX_SHADER); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed"); /* Configure fragment shader body */ const char* fs_body = "${VERSION}\n" "\n" "void main()\n" "{\n" "}\n"; shaderSourceSpecialized(m_fs_id, 1 /* count */, &fs_body); GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader"); /* Configure tessellation control shader body */ const char* tc_body = "${VERSION}\n" "\n" "${TESSELLATION_SHADER_REQUIRE}\n" "\n" "layout (vertices=3) out;\n" "\n" "void main()\n" "{\n" " gl_out [gl_InvocationID].gl_Position = gl_in[0].gl_Position;\n" "\n" " gl_TessLevelInner[0] = 1.0;\n" " gl_TessLevelOuter[0] = 1.0;\n" " gl_TessLevelOuter[1] = 1.0;\n" " gl_TessLevelOuter[2] = 1.0;\n" "}\n"; shaderSourceSpecialized(m_tc_id, 1 /* count */, &tc_body); GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation control shader"); /* Configure vertex shader body */ const char* vs_body = "${VERSION}\n" "\n" "void main()\n" "{\n" " gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n" "}\n"; shaderSourceSpecialized(m_vs_id, 1 /* count */, &vs_body); GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader"); /* Compile all the shaders */ const glw::GLuint shaders[] = { m_fs_id, m_tc_id, m_vs_id }; const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]); for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader) { glw::GLuint shader = shaders[n_shader]; if (shader != 0) { glw::GLint compile_status = GL_FALSE; gl.compileShader(shader); GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed"); gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed"); if (compile_status != GL_TRUE) { TCU_FAIL("Shader compilation failed"); } } } /* for (all shaders) */ /* Initialize all test passes */ _test_descriptor test_equal_spacing; _test_descriptor test_fractional_odd_spacing; initTestDescriptor(test_equal_spacing, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL); initTestDescriptor(test_fractional_odd_spacing, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD); m_tests.push_back(test_equal_spacing); m_tests.push_back(test_fractional_odd_spacing); /* Set up buffer object storage */ gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed"); gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 3 /* components */ * 3 /* UVW sets */, NULL, /* data */ GL_STATIC_DRAW); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed"); /* Bind the buffer object to indiced TF binding point */ gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed"); }
/** Executes the test. * * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * * Note the function throws exception should an error occur! * * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again. **/ tcu::TestNode::IterateResult TessellationShaderTrianglesDegenerateTriangle::iterate(void) { /* Do not execute if required extensions are not supported. */ if (!m_is_tessellation_shader_supported) { throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED); } /* Initialize ES test objects */ initTest(); /* We only need to use one vertex per so go for it */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1); GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname"); /* Iterate through all tests configured */ for (_tests_const_iterator test_iterator = m_tests.begin(); test_iterator != m_tests.end(); test_iterator++) { const _test_descriptor& test = *test_iterator; /* Run the iteration */ gl.useProgram(test.po_id); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed"); /* Draw the test geometry */ gl.beginTransformFeedback(GL_TRIANGLES); GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback(GL_TRIANGLES) failed."); gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, 1 /* count */); GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed"); gl.endTransformFeedback(); GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed"); /* Map the BO with result data into user space */ const float* triangle_vertex_data = (const float*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */ sizeof(float) * 3 /* vec3 */ * 3 /* points */, GL_MAP_READ_BIT); GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed"); /* Make sure the triangle data is correct. Since we cannot rely on any specific order * of the result vertices, raise corresponding flag for each of the expected vertices. */ const float epsilon = 1e-5f; bool is_zero_zero_one_present = false; bool is_zero_one_zero_present = false; bool is_one_zero_zero_present = false; for (unsigned int n_vertex = 0; n_vertex < 3 /* vertices */; ++n_vertex) { const float* triangle_ptr = triangle_vertex_data + 3 * n_vertex; if (de::abs(triangle_ptr[0]) < epsilon && de::abs(triangle_ptr[1]) < epsilon && de::abs(triangle_ptr[2] - 1.0f) < epsilon) { if (!is_zero_zero_one_present) { is_zero_zero_one_present = true; } else { TCU_FAIL("(0, 0, 1) vertex outputted more than once"); } } else if (de::abs(triangle_ptr[0]) < epsilon && de::abs(triangle_ptr[1] - 1.0f) < epsilon && de::abs(triangle_ptr[2]) < epsilon) { if (!is_zero_one_zero_present) { is_zero_one_zero_present = true; } else { TCU_FAIL("(0, 1, 0) vertex outputted more than once"); } } else if (de::abs(triangle_ptr[0] - 1.0f) < epsilon && de::abs(triangle_ptr[1]) < epsilon && de::abs(triangle_ptr[2]) < epsilon) { if (!is_one_zero_zero_present) { is_one_zero_zero_present = true; } else { TCU_FAIL("(1, 0, 0) vertex outputted more than once"); } } else { m_testCtx.getLog() << tcu::TestLog::Message << "Unexpected vertex" << " (" << triangle_vertex_data[0] << ", " << triangle_vertex_data[1] << ", " << triangle_vertex_data[2] << ")" << " encountered for a degenerate triangle." << tcu::TestLog::EndMessage; TCU_FAIL("Invalid vertex was generated by the tessellator"); } } /* for (all vertices) */ /* Unmap the BO */ gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed"); } /* All done */ m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return STOP; }
/** Initializes ES objects necessary to run the test. */ void TessellationShaderTrianglesIdenticalTriangles::initTest() { /* Skip if required extensions are not supported. */ if (!m_is_tessellation_shader_supported) { throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED); } /* Initialize Utils instance */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); m_utils = new TessellationShaderUtils(gl, this); /* Initialize vertex array object */ gl.genVertexArrays(1, &m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object"); gl.bindVertexArray(m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!"); /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */ glw::GLint gl_max_tess_gen_level_value = 0; gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_TESS_GEN_LEVEL_EXT pname"); /* Initialize all test runs */ _tessellation_level_set_filter filter = (_tessellation_level_set_filter)((int)TESSELLATION_LEVEL_SET_FILTER_ALL_COMBINATIONS | (int)TESSELLATION_LEVEL_SET_FILTER_EXCLUDE_NEGATIVE_BASE_VALUE); _tessellation_levels_set levels_sets = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode( TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, gl_max_tess_gen_level_value, filter); for (_tessellation_levels_set_const_iterator set_iterator = levels_sets.begin(); set_iterator != levels_sets.end(); set_iterator++) { _run run; const _tessellation_levels& set = *set_iterator; memcpy(run.base_inner, set.inner, sizeof(run.base_inner)); memcpy(run.base_outer, set.outer, sizeof(run.base_outer)); run.reference_inner[0] = run.base_inner[0]; run.reference_inner[1] = run.base_inner[1] * 0.25f; run.reference_outer[0] = run.base_outer[0]; run.reference_outer[1] = run.base_outer[1]; run.reference_outer[2] = run.base_outer[2]; run.reference_outer[3] = run.base_outer[3] * 0.25f; /* Retrieve vertex data for both passes */ glw::GLint n_base_vertices = 0; glw::GLint n_reference_vertices = 0; n_base_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator( TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, run.base_inner, run.base_outer, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, false); n_reference_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator( TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, run.reference_inner, run.reference_outer, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, false); /* is_point_mode_enabled */ if (n_base_vertices == 0) { m_testCtx.getLog() << tcu::TestLog::Message << "No vertices were generated by tessellator for: " "inner tess levels:" "[" << run.base_inner[0] << ", " << run.base_inner[1] << "]" ", outer tess levels:" "[" << run.base_outer[0] << ", " << run.base_outer[1] << ", " << run.base_outer[2] << ", " << run.base_outer[3] << "]" ", primitive mode: triangles, vertex spacing: equal." << tcu::TestLog::EndMessage; TCU_FAIL("Zero vertices were generated by tessellator for base test pass"); } if (n_reference_vertices == 0) { m_testCtx.getLog() << tcu::TestLog::Message << "No vertices were generated by tessellator for: " "inner tess levels:" "[" << run.reference_inner[0] << ", " << run.reference_inner[1] << "]" ", outer tess levels:" "[" << run.reference_outer[0] << ", " << run.reference_outer[1] << ", " << run.reference_outer[2] << ", " << run.reference_outer[3] << "]" ", primitive mode: triangles, vertex spacing: equal." << tcu::TestLog::EndMessage; TCU_FAIL("Zero vertices were generated by tessellator for reference test pass"); } if (n_base_vertices != n_reference_vertices) { m_testCtx.getLog() << tcu::TestLog::Message << "Amount of vertices generated by the tessellator differs" " for the following inner/outer configs: " "inner tess levels:" "[" << run.base_inner[0] << ", " << run.base_inner[1] << "]" ", outer tess levels:" "[" << run.base_outer[0] << ", " << run.base_outer[1] << ", " << run.base_outer[2] << ", " << run.base_outer[3] << "]" " and inner tess levels:" "[" << run.reference_inner[0] << ", " << run.reference_inner[1] << "]" ", outer tess levels:" "[" << run.reference_outer[0] << ", " << run.reference_outer[1] << ", " << run.reference_outer[2] << ", " << run.reference_outer[3] << "]" ", primitive mode: triangles, vertex spacing: equal." << tcu::TestLog::EndMessage; TCU_FAIL("Amount of vertices generated by tessellator differs between base and references passes"); } run.n_vertices = n_base_vertices; run.base_data = m_utils->getDataGeneratedByTessellator( run.base_inner, false, /* is_point_mode_enabled */ TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, TESSELLATION_SHADER_VERTEX_ORDERING_CCW, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, run.base_outer); run.reference_data = m_utils->getDataGeneratedByTessellator( run.reference_inner, false, /* is_point_mode_enabled */ TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, TESSELLATION_SHADER_VERTEX_ORDERING_CCW, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, run.reference_outer); /* Store the run data */ m_runs.push_back(run); } /* for (all sets) */ }
/** Executes the test. * * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * * Note the function throws exception should an error occur! * * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again. **/ tcu::TestNode::IterateResult TessellationShaderTrianglesIdenticalTriangles::iterate(void) { /* Do not execute if required extensions are not supported. */ if (!m_is_tessellation_shader_supported) { throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED); } /* Initialize the test */ initTest(); /* Iterate through all runs */ for (_runs_const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++) { const _run& run = *run_iterator; /* Make sure the vertex data generated for two passes matches */ const glw::GLint n_triangles = run.n_vertices / 3 /* vertices per triangle */; for (int n_triangle = 0; n_triangle < n_triangles; ++n_triangle) { const float* triangle_a = (const float*)(&run.base_data[0]) + n_triangle * 3 /* vertices */ * 3; /* components */ const float* triangle_b = (const float*)(&run.reference_data[0]) + n_triangle * 3 /* vertices */ * 3; /* components */ if (!TessellationShaderUtils::isTriangleDefined(triangle_a, triangle_b)) { m_testCtx.getLog() << tcu::TestLog::Message << "The following triangle, generated in the first pass, was not " "generated in the other. " "First pass' configuration: inner tess levels:" "[" << run.base_inner[0] << ", " << run.base_inner[1] << "]" ", outer tess levels:" "[" << run.base_outer[0] << ", " << run.base_outer[1] << ", " << run.base_outer[2] << ", " << run.base_outer[3] << "]" "; second pass' configuration: inner tess levels:" "[" << run.reference_inner[0] << ", " << run.reference_inner[1] << "]" ", outer tess levels:" "[" << run.reference_outer[0] << ", " << run.reference_outer[1] << ", " << run.reference_outer[2] << ", " << run.reference_outer[3] << "]" ", primitive mode: triangles, vertex spacing: equal." << tcu::TestLog::EndMessage; TCU_FAIL("A triangle from base vertex data set was not found in reference vertex data set."); } } /* for (all vertices) */ } /* for (all runs) */ /* All done */ m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return STOP; }
/** Runs all test iterations needed to generate data for later verification. */ void TessellationShaderTrianglesInnerTessellationLevelRounding::runTestIterations() { /* Skip if required extensions are not supported. */ if (!m_is_tessellation_shader_supported) { throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED); } /* Initialize Utils instance */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); m_utils = new TessellationShaderUtils(gl, this); /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */ glw::GLint gl_max_tess_gen_level_value = 0; gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_TESS_GEN_LEVEL_EXT pname"); /* Initialize all test runs */ const glw::GLint tess_levels[] = { 2, gl_max_tess_gen_level_value / 2, gl_max_tess_gen_level_value }; const unsigned int n_tess_levels = sizeof(tess_levels) / sizeof(tess_levels[0]); const _tessellation_shader_vertex_spacing vs_modes[] = { TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD }; const unsigned int n_vs_modes = sizeof(vs_modes) / sizeof(vs_modes[0]); for (unsigned int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode) { _tessellation_shader_vertex_spacing vs_mode = vs_modes[n_vs_mode]; for (unsigned int n_tess_level = 0; n_tess_level < n_tess_levels; ++n_tess_level) { /* Set up the run descriptor */ glw::GLint tess_level = tess_levels[n_tess_level]; _run run; run.set1_inner[0] = 1.0f; run.set1_inner[1] = 0.0f; run.set2_inner[1] = 0.0f; TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(vs_mode, 1.5f, gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */ run.set2_inner); run.set1_outer[0] = (glw::GLfloat)tess_level; run.set2_outer[0] = (glw::GLfloat)tess_level; run.set1_outer[1] = (glw::GLfloat)tess_level; run.set2_outer[1] = (glw::GLfloat)tess_level; run.set1_outer[2] = (glw::GLfloat)tess_level; run.set2_outer[2] = (glw::GLfloat)tess_level; run.set1_outer[3] = (glw::GLfloat)tess_level; run.set2_outer[3] = (glw::GLfloat)tess_level; run.vertex_spacing = vs_mode; /* Retrieve vertex data for both passes */ glw::GLint n_set1_vertices = 0; glw::GLint n_set2_vertices = 0; n_set1_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator( TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, run.set1_inner, run.set1_outer, run.vertex_spacing, false); /* is_point_mode_enabled */ n_set2_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator( TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, run.set2_inner, run.set2_outer, run.vertex_spacing, false); /* is_point_mode_enabled */ if (n_set1_vertices == 0) { std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vs_mode); m_testCtx.getLog() << tcu::TestLog::Message << "No vertices were generated by tessellator for: " "inner tess levels:" "[" << run.set1_inner[0] << ", " << run.set1_inner[1] << "]" ", outer tess levels:" "[" << run.set1_outer[0] << ", " << run.set1_outer[1] << ", " << run.set1_outer[2] << ", " << run.set1_outer[3] << "]" ", primitive mode: triangles, " "vertex spacing: " << vs_mode_string << tcu::TestLog::EndMessage; TCU_FAIL("Zero vertices were generated by tessellator for first test pass"); } if (n_set2_vertices == 0) { std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vs_mode); m_testCtx.getLog() << tcu::TestLog::Message << "No vertices were generated by tessellator for: " "inner tess levels:" "[" << run.set2_inner[0] << ", " << run.set2_inner[1] << "]" ", outer tess levels:" "[" << run.set2_outer[0] << ", " << run.set2_outer[1] << ", " << run.set2_outer[2] << ", " << run.set2_outer[3] << "]" ", primitive mode: triangles, " "vertex spacing: " << vs_mode_string << tcu::TestLog::EndMessage; TCU_FAIL("Zero vertices were generated by tessellator for second test pass"); } if (n_set1_vertices != n_set2_vertices) { std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vs_mode); m_testCtx.getLog() << tcu::TestLog::Message << "Amount of vertices generated by the tessellator differs" " for the following inner/outer configs: " "inner tess levels:" "[" << run.set1_inner[0] << ", " << run.set1_inner[1] << "]" ", outer tess levels:" "[" << run.set1_outer[0] << ", " << run.set1_outer[1] << ", " << run.set1_outer[2] << ", " << run.set1_outer[3] << "]" " and inner tess levels:" "[" << run.set2_inner[0] << ", " << run.set2_inner[1] << "]" ", outer tess levels:" "[" << run.set2_outer[0] << ", " << run.set2_outer[1] << ", " << run.set2_outer[2] << ", " << run.set2_outer[3] << "]" ", primitive mode: triangles, vertex spacing: " << vs_mode_string << tcu::TestLog::EndMessage; TCU_FAIL("Amount of vertices generated by tessellator differs between base and references passes"); } run.n_vertices = n_set1_vertices; run.set1_data = m_utils->getDataGeneratedByTessellator(run.set1_inner, false, /* is_point_mode_enabled */ TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, TESSELLATION_SHADER_VERTEX_ORDERING_CCW, run.vertex_spacing, run.set1_outer); run.set2_data = m_utils->getDataGeneratedByTessellator(run.set2_inner, false, /* is_point_mode_enabled */ TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, TESSELLATION_SHADER_VERTEX_ORDERING_CCW, run.vertex_spacing, run.set2_outer); /* Store the run data */ m_runs.push_back(run); } /* for (all sets) */ } /* for (all vertex spacing modes) */ }
/** Executes the test. * * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. * * Note the function throws exception should an error occur! * * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again. **/ tcu::TestNode::IterateResult TessellationShaderTrianglesInnerTessellationLevelRounding::iterate(void) { /* Do not execute if required extensions are not supported. */ if (!m_is_tessellation_shader_supported) { throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED); } const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Initialize vertex array object */ gl.genVertexArrays(1, &m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object"); gl.bindVertexArray(m_vao_id); GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!"); /* Initialize and run test iterations. In later part, we will verify the generated data. */ runTestIterations(); /* Iterate through all runs */ for (_runs_const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++) { const _run& run = *run_iterator; if (run.vertex_spacing == TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD && de::abs(run.set1_inner[0] - run.set2_inner[0]) > 1e-5f && de::min(run.set1_inner[0], run.set2_inner[0]) >= 1.0f) { /* In fractional_odd_spacing mode with inner level <f> >= 1.0f, the clamped and rounded integer level <n> is at least 3. These results in inner subdivision into at least <n>-2=1 segment and two additional, typically shorter segments. The length of these two additional segments relative to the others will decrease monotonically with the value of <n>-<f>, so if different <f> levels were used, we cannot proceed with matching the exact vertex data. */ continue; } /* Make sure the vertex data generated for two passes matches */ const glw::GLint n_triangles = run.n_vertices / 3 /* vertices per triangle */; for (int n_triangle = 0; n_triangle < n_triangles; ++n_triangle) { const float* triangle_a = (const float*)(&run.set1_data[0]) + n_triangle * 3 /* vertices */ * 3; /* components */ const float* triangle_b = (const float*)(&run.set2_data[0]) + n_triangle * 3 /* vertices */ * 3; /* components */ if (!TessellationShaderUtils::isTriangleDefined(triangle_a, triangle_b)) { std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(run.vertex_spacing); m_testCtx.getLog() << tcu::TestLog::Message << "The following triangle, generated in the first pass, was not " "generated in the second one. " "First pass' configuration: inner tess levels:" "[" << run.set1_inner[0] << ", " << run.set1_inner[1] << "]" ", outer tess levels:" "[" << run.set1_outer[0] << ", " << run.set1_outer[1] << ", " << run.set1_outer[2] << ", " << run.set1_outer[3] << "]" "; second pass' configuration: inner tess levels:" "[" << run.set2_inner[0] << ", " << run.set2_inner[1] << "]" ", outer tess levels:" "[" << run.set2_outer[0] << ", " << run.set2_outer[1] << ", " << run.set2_outer[2] << ", " << run.set2_outer[3] << "]" ", primitive mode: triangles, vertex spacing: " << vs_mode_string << tcu::TestLog::EndMessage; TCU_FAIL("A triangle from first pass' data set was not found in second pass' data set."); } } /* for (all vertices) */ } /* for (all runs) */ /* All done */ m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return STOP; }