| /*------------------------------------------------------------------------- |
| * OpenGL Conformance Test Suite |
| * ----------------------------- |
| * |
| * Copyright (c) 2014-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 esextcTextureBufferOperations.cpp |
| * \brief Texture Buffer Operations (Test 1) |
| */ /*-------------------------------------------------------------------*/ |
| |
| #include "esextcTextureBufferOperations.hpp" |
| #include "gluContextInfo.hpp" |
| #include "gluDefs.hpp" |
| #include "glwEnums.hpp" |
| #include "glwFunctions.hpp" |
| #include "tcuTestLog.hpp" |
| #include <cstring> |
| #include <iostream> |
| #include <vector> |
| |
| namespace glcts |
| { |
| |
| const glw::GLuint TextureBufferOperations::m_n_vector_components = 4; |
| |
| /** Constructor |
| * |
| * @param context Test context |
| * @param name Test case's name |
| * @param description Test case's description |
| **/ |
| TextureBufferOperations::TextureBufferOperations(Context& context, const ExtParameters& extParams, const char* name, |
| const char* description) |
| : TestCaseBase(context, extParams, name, description) |
| , m_n_vectors_in_buffer_texture(0) |
| , m_tb_bo_id(0) |
| , m_texbuff_id(0) |
| , m_cs_id(0) |
| , m_po_cs_id(0) |
| , m_ssbo_bo_id(0) |
| , m_fbo_id(0) |
| , m_fs_id(0) |
| , m_po_vs_fs_id(0) |
| , m_to_id(0) |
| , m_vao_id(0) |
| , m_vbo_id(0) |
| , m_vbo_indicies_id(0) |
| , m_vs_id(0) |
| , m_vertex_location(-1) |
| , m_index_location(-1) |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Initializes GLES objects used during the test. |
| * |
| */ |
| void TextureBufferOperations::initTest(void) |
| { |
| /* Check if texture buffer extension is supported */ |
| if (!m_is_texture_buffer_supported) |
| { |
| throw tcu::NotSupportedError(TEXTURE_BUFFER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); |
| } |
| |
| /* Get GL entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.getIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &m_n_vectors_in_buffer_texture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error getting GL_MAX_COMPUTE_WORK_GROUP_SIZE parameter value!"); |
| |
| /* Create buffer object*/ |
| gl.genBuffers(1, &m_tb_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating buffer object!"); |
| |
| gl.bindBuffer(m_glExtTokens.TEXTURE_BUFFER, m_tb_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding buffer object !"); |
| |
| gl.bufferData(m_glExtTokens.TEXTURE_BUFFER, |
| m_n_vectors_in_buffer_texture * m_n_vector_components * sizeof(glw::GLint), 0, GL_DYNAMIC_DRAW); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocating data store for buffer object!"); |
| |
| /* Create texture buffer */ |
| gl.genTextures(1, &m_texbuff_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating texture object!"); |
| |
| gl.activeTexture(GL_TEXTURE0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting active texture unit!"); |
| |
| gl.bindTexture(m_glExtTokens.TEXTURE_BUFFER, m_texbuff_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding texture object!"); |
| |
| gl.texBuffer(m_glExtTokens.TEXTURE_BUFFER, GL_RGBA32I, m_tb_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding buffer object to texture buffer!"); |
| |
| /* Initialize texture buffer object */ |
| initializeBufferObjectData(); |
| |
| /* Initialize first phase */ |
| initFirstPhase(); |
| |
| /* Initialize second phase */ |
| initSecondPhase(); |
| } |
| |
| void TextureBufferOperations::initFirstPhase(void) |
| { |
| /* Get GL entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Create program object */ |
| m_po_cs_id = gl.createProgram(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating program object!"); |
| |
| m_cs_id = gl.createShader(GL_COMPUTE_SHADER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating shader object!"); |
| |
| std::string csSource = getComputeShaderCode(); |
| const char* csCode = csSource.c_str(); |
| |
| if (!buildProgram(m_po_cs_id, m_cs_id, 1, &csCode)) |
| { |
| TCU_FAIL("Could not create a program from valid compute shader code!"); |
| } |
| |
| /* Create Shader Storage Buffer Object */ |
| gl.genBuffers(1, &m_ssbo_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating buffer object!"); |
| gl.bindBuffer(GL_ARRAY_BUFFER, m_ssbo_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding buffer object!"); |
| gl.bufferData(GL_ARRAY_BUFFER, m_n_vectors_in_buffer_texture * m_n_vector_components * sizeof(glw::GLint), 0, |
| GL_DYNAMIC_DRAW); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocating data store for buffer object!"); |
| gl.bindBuffer(GL_ARRAY_BUFFER, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding buffer object!"); |
| } |
| |
| /** Returns Compute shader Code |
| * |
| * @return pointer to literal with Compute Shader Code |
| */ |
| std::string TextureBufferOperations::getComputeShaderCode() const |
| { |
| std::stringstream strstream; |
| |
| strstream << "${VERSION}\n" |
| "\n" |
| "${TEXTURE_BUFFER_REQUIRE}\n" |
| "\n" |
| "precision highp float;\n" |
| "\n" |
| "layout(rgba32i, binding = 0) uniform readonly highp iimageBuffer image_buffer;\n" |
| "\n" |
| "buffer ComputeSSBO\n" |
| "{\n" |
| " ivec4 value[];\n" |
| "} computeSSBO;\n" |
| "\n" |
| "layout (local_size_x = " |
| << m_n_vectors_in_buffer_texture << " ) in;\n" |
| "\n" |
| "void main(void)\n" |
| "{\n" |
| " int index = int(gl_LocalInvocationID.x);\n" |
| " computeSSBO.value[index] = imageLoad( image_buffer, index);\n" |
| "}\n"; |
| |
| return strstream.str(); |
| } |
| |
| void TextureBufferOperations::initSecondPhase(void) |
| { |
| /* Get GL entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Create vertex array object */ |
| gl.genVertexArrays(1, &m_vao_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating vertex array object!"); |
| |
| /* Create framebuffer object */ |
| gl.genFramebuffers(1, &m_fbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error genertaing framebuffer object!"); |
| |
| /* Prepare texture object */ |
| gl.genTextures(1, &m_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error genertaing texture buffer!"); |
| |
| gl.bindTexture(GL_TEXTURE_2D, m_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding texture object!"); |
| |
| gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32I, m_n_vectors_in_buffer_texture /* width */, 1 /* height */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocating texture object's texel data!"); |
| |
| /* Set GL_TEXTURE_MAG_FILTER and GL_TEXTURE_MIN_FILTER parameters values to GL_NEAREST*/ |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting value for GL_TEXTURE_MAG_FILTER parameter!"); |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting value for GL_TEXTURE_MIN_FILTER parameter!"); |
| |
| gl.bindTexture(GL_TEXTURE_2D, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding texture object!"); |
| |
| /* Create program object */ |
| m_po_vs_fs_id = gl.createProgram(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating program object!"); |
| |
| m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating fragment shader object!"); |
| |
| m_vs_id = gl.createShader(GL_VERTEX_SHADER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating vertex shader object!"); |
| |
| std::string fsSource = getFragmentShaderCode(); |
| std::string vsSource = getVertexShaderCode(); |
| |
| const char* fsCode = fsSource.c_str(); |
| const char* vsCode = vsSource.c_str(); |
| |
| if (!buildProgram(m_po_vs_fs_id, m_fs_id, 1, &fsCode, m_vs_id, 1, &vsCode)) |
| { |
| TCU_FAIL("Could not create a program from valid vertex/fragment shader source!"); |
| } |
| |
| /* Full screen quad */ |
| glw::GLfloat vertices[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, |
| 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f }; |
| |
| /* Generate buffer object */ |
| gl.genBuffers(1, &m_vbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating buffer object!"); |
| /* Bind buffer object */ |
| gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding buffer object!"); |
| /* Set data for buffer object */ |
| gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting data for buffer object!"); |
| |
| /* Indicies */ |
| glw::GLfloat indicies[] = { 0.f, 0.f, static_cast<glw::GLfloat>(m_n_vectors_in_buffer_texture) * 1.f, |
| static_cast<glw::GLfloat>(m_n_vectors_in_buffer_texture) * 1.f }; |
| |
| /* Generate buffer object */ |
| gl.genBuffers(1, &m_vbo_indicies_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating buffer object!"); |
| /* Bind buffer object */ |
| gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo_indicies_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding buffer object!"); |
| /* Set data for buffer object */ |
| gl.bufferData(GL_ARRAY_BUFFER, sizeof(indicies), indicies, GL_STATIC_DRAW); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error seting data for buffer object!"); |
| |
| gl.bindBuffer(GL_ARRAY_BUFFER, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding buffer object!"); |
| } |
| |
| /** Returns Fragment Shader Code |
| * |
| * @return pointer to literal with Fragment Shader Code |
| */ |
| std::string TextureBufferOperations::getFragmentShaderCode() const |
| { |
| std::stringstream strstream; |
| |
| strstream << "${VERSION}\n" |
| "\n" |
| "${TEXTURE_BUFFER_REQUIRE}\n" |
| "\n" |
| "precision highp float;\n" |
| "\n" |
| "in float fs_index;\n" |
| "\n" |
| "layout(location = 0) out ivec4 color;\n" |
| "\n" |
| "uniform highp isamplerBuffer sampler_buffer;\n" |
| "\n" |
| "void main(void)\n" |
| "{\n" |
| " color = texelFetch( sampler_buffer, int(fs_index) );\n " |
| "}\n"; |
| |
| return strstream.str(); |
| } |
| |
| /** Returns Vertex Shader Code |
| * |
| * @return pointer to literal with Vertex Shader Code |
| */ |
| std::string TextureBufferOperations::getVertexShaderCode() const |
| { |
| std::stringstream strstream; |
| |
| strstream << "${VERSION}\n" |
| "\n" |
| "${TEXTURE_BUFFER_REQUIRE}\n" |
| "\n" |
| "precision highp float;\n" |
| "\n" |
| "in vec4 vs_position;\n" |
| "in float vs_index;\n" |
| "\n" |
| "out float fs_index;\n" |
| "\n" |
| "void main(void)\n" |
| "{\n" |
| " gl_Position = vs_position;\n" |
| " fs_index = vs_index;\n" |
| "}\n"; |
| |
| return strstream.str(); |
| } |
| |
| /** 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 TextureBufferOperations::iterate(void) |
| { |
| /* Initialize */ |
| initTest(); |
| |
| /* Get GL entry points */ |
| glw::GLboolean test_result = true; |
| |
| /* Prepare expected data */ |
| std::vector<glw::GLint> reference(m_n_vectors_in_buffer_texture * m_n_vector_components); |
| fillBufferWithData(&reference[0], m_n_vectors_in_buffer_texture * m_n_vector_components); |
| |
| std::vector<glw::GLint> result(m_n_vectors_in_buffer_texture * m_n_vector_components); |
| |
| iterateFirstPhase(&result[0], static_cast<glw::GLuint>(m_n_vectors_in_buffer_texture * m_n_vector_components * |
| sizeof(glw::GLint))); |
| if (!verifyResults(&reference[0], &result[0], static_cast<glw::GLuint>(m_n_vectors_in_buffer_texture * |
| m_n_vector_components * sizeof(glw::GLint)), |
| "1st Phase Compute Shader\n")) |
| { |
| test_result = false; |
| } |
| |
| iterateSecondPhase(&result[0]); |
| if (!verifyResults(&reference[0], &result[0], static_cast<glw::GLuint>(m_n_vectors_in_buffer_texture * |
| m_n_vector_components * sizeof(glw::GLint)), |
| "2st Phase Vertex + Fragment Shader\n")) |
| { |
| test_result = false; |
| } |
| |
| if (test_result) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| } |
| else |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| |
| return STOP; |
| } |
| |
| void TextureBufferOperations::iterateFirstPhase(glw::GLint* result, glw::GLuint size) |
| { |
| /* Get GL entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.bindBuffer(GL_ARRAY_BUFFER, m_ssbo_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding buffer object!"); |
| |
| gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind buffer object to shader storage binding point!"); |
| |
| gl.useProgram(m_po_cs_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting active program!"); |
| |
| gl.memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting memory barrier!"); |
| |
| gl.bindImageTexture(0, m_texbuff_id, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32I); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding texture to image unit!"); |
| |
| gl.dispatchCompute(1, 1, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error running compute shader!"); |
| |
| gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting memory barrier!"); |
| |
| /* Get result data */ |
| glw::GLint* result_mapped = (glw::GLint*)gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, size, GL_MAP_READ_BIT); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error mapping buffer object's data store to client's address space!"); |
| |
| memcpy(result, result_mapped, size); |
| |
| gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error unmapping buffer object's data store from client's address space!"); |
| |
| gl.bindBuffer(GL_ARRAY_BUFFER, 0); |
| gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0); |
| gl.useProgram(0); |
| } |
| |
| void TextureBufferOperations::iterateSecondPhase(glw::GLint* result) |
| { |
| /* Get GL entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.bindVertexArray(m_vao_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!"); |
| |
| gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding framebuffer object!"); |
| |
| gl.bindTexture(GL_TEXTURE_2D, m_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding texture object!"); |
| |
| /* Attach output texture to framebuffer */ |
| gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error attaching texture to framebuffer's color attachment"); |
| |
| /* Check framebuffer status */ |
| checkFramebufferStatus(GL_DRAW_FRAMEBUFFER); |
| |
| /* Configure view port */ |
| gl.viewport(0, 0, m_n_vectors_in_buffer_texture, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting viewport!"); |
| |
| /* Use program */ |
| gl.useProgram(m_po_vs_fs_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error using program object!"); |
| |
| glw::GLint sampler_location = gl.getUniformLocation(m_po_vs_fs_id, "sampler_buffer"); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not get attribute location!"); |
| if (sampler_location == -1) |
| { |
| TCU_FAIL("Could not get uniform location"); |
| } |
| |
| gl.uniform1i(sampler_location, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding sampler with texture unit!"); |
| |
| /* Configure vertex position attribute */ |
| gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind buffer object!"); |
| |
| m_vertex_location = gl.getAttribLocation(m_po_vs_fs_id, "vs_position"); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not get attribute location!"); |
| if (m_vertex_location == -1) |
| { |
| TCU_FAIL("Could not get uniform location"); |
| } |
| |
| gl.vertexAttribPointer(m_vertex_location, 4, GL_FLOAT, GL_FALSE, 0, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set vertex attribute pointer!"); |
| |
| gl.enableVertexAttribArray(m_vertex_location); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not enable vertex attribute array!"); |
| |
| /* Configure index attribute */ |
| gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo_indicies_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind buffer object!"); |
| |
| m_index_location = gl.getAttribLocation(m_po_vs_fs_id, "vs_index"); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not get attribute location!"); |
| if (m_index_location == -1) |
| { |
| TCU_FAIL("Could not get uniform location"); |
| } |
| |
| gl.vertexAttribPointer(m_index_location, 1, GL_FLOAT, GL_FALSE, 0, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set vertex attribute pointer!"); |
| |
| gl.enableVertexAttribArray(m_index_location); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not enable vertex attribute array!"); |
| |
| /* Clear texture */ |
| gl.clearColor(0.0f, 0.0f, 0.0f, 0.0f); |
| gl.clear(GL_COLOR_BUFFER_BIT); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error clearing color buffer"); |
| |
| /* Render */ |
| gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed!"); |
| |
| /* Read result data */ |
| gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding framebuffer object !"); |
| |
| gl.readPixels(0, 0, m_n_vectors_in_buffer_texture, 1, GL_RGBA_INTEGER, GL_INT, result); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error reading pixels !"); |
| |
| gl.bindVertexArray(0); |
| gl.bindTexture(GL_TEXTURE_2D, 0); |
| gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); |
| gl.bindFramebuffer(GL_READ_FRAMEBUFFER, 0); |
| gl.bindBuffer(GL_ARRAY_BUFFER, 0); |
| gl.disableVertexAttribArray(m_vertex_location); |
| gl.disableVertexAttribArray(m_index_location); |
| gl.useProgram(0); |
| |
| m_vertex_location = -1; |
| m_index_location = -1; |
| } |
| |
| /** Check if result data is the same as reference data - log error if not |
| * |
| * @param reference pointer to buffer with reference data |
| * @param result pointer to buffer with result data |
| * @param size size of buffers |
| * @param message pointer to literal with message (informing about test phase) |
| * |
| * @return returns true if reference data equals result data, otherwise log error and return false |
| */ |
| glw::GLboolean TextureBufferOperations::verifyResults(glw::GLint* reference, glw::GLint* result, glw::GLuint size, |
| const char* message) |
| { |
| /* Log error if expected and result data is not equal */ |
| if (memcmp(reference, result, size)) |
| { |
| std::stringstream referenceData; |
| std::stringstream resultData; |
| |
| referenceData << "["; |
| resultData << "["; |
| |
| glw::GLuint n_entries = static_cast<glw::GLuint>(size / sizeof(glw::GLint)); |
| |
| for (glw::GLuint i = 0; i < n_entries; ++i) |
| { |
| referenceData << reference[i] << ","; |
| resultData << result[i] << ","; |
| } |
| |
| referenceData << "]"; |
| resultData << "]"; |
| |
| m_testCtx.getLog() << tcu::TestLog::Message << message |
| << "Result buffer contains different data than reference buffer\n" |
| << "Reference Buffer: " << referenceData.str() << "\n" |
| << "Result Buffer: " << resultData.str() << "\n" |
| << tcu::TestLog::EndMessage; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** Fill buffer with test data |
| * |
| * @param buffer pointer to buffer |
| * @param bufferLenth buffer length |
| */ |
| void TextureBufferOperations::fillBufferWithData(glw::GLint* buffer, glw::GLuint bufferLength) |
| { |
| for (glw::GLuint i = 0; i < bufferLength; ++i) |
| { |
| buffer[i] = (glw::GLint)i; |
| } |
| } |
| |
| /** Check Framebuffer Status - throw exception if status is different than GL_FRAMEBUFFER_COMPLETE |
| * |
| * @param framebuffer - GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER or GL_FRAMEBUFFER |
| * |
| */ |
| void TextureBufferOperations::checkFramebufferStatus(glw::GLenum framebuffer) |
| { |
| /* Get GL entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Check framebuffer status */ |
| glw::GLenum framebufferStatus = gl.checkFramebufferStatus(framebuffer); |
| |
| if (GL_FRAMEBUFFER_COMPLETE != framebufferStatus) |
| { |
| switch (framebufferStatus) |
| { |
| 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: GL_FRAMEBUFFER_UNSUPPORTED"); |
| } |
| |
| default: |
| { |
| TCU_FAIL("Framebuffer incomplete, status not recognized"); |
| } |
| } |
| } /* if (GL_FRAMEBUFFER_COMPLETE != framebuffer_status) */ |
| } |
| |
| /** Deinitializes GLES objects created during the test. |
| * |
| */ |
| void TextureBufferOperations::deinit(void) |
| { |
| /* Get GLES entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Reset GLES state */ |
| gl.bindBuffer(m_glExtTokens.TEXTURE_BUFFER, 0); |
| gl.bindTexture(m_glExtTokens.TEXTURE_BUFFER, 0); |
| |
| /* Delete GLES objects */ |
| if (0 != m_texbuff_id) |
| { |
| gl.deleteTextures(1, &m_texbuff_id); |
| m_texbuff_id = 0; |
| } |
| |
| if (0 != m_tb_bo_id) |
| { |
| gl.deleteBuffers(1, &m_tb_bo_id); |
| m_tb_bo_id = 0; |
| } |
| |
| deinitFirstPhase(); |
| deinitSecondPhase(); |
| |
| /* Deinitialize base class */ |
| TestCaseBase::deinit(); |
| } |
| |
| void TextureBufferOperations::deinitFirstPhase(void) |
| { |
| /* Get GLES entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Reset GLES state */ |
| gl.bindBuffer(GL_ARRAY_BUFFER, 0); |
| gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0); |
| gl.useProgram(0); |
| |
| /* Delete GLES objects */ |
| if (0 != m_po_cs_id) |
| { |
| gl.deleteProgram(m_po_cs_id); |
| m_po_cs_id = 0; |
| } |
| |
| if (0 != m_cs_id) |
| { |
| gl.deleteShader(m_cs_id); |
| m_cs_id = 0; |
| } |
| |
| if (0 != m_ssbo_bo_id) |
| { |
| gl.deleteBuffers(1, &m_ssbo_bo_id); |
| m_ssbo_bo_id = 0; |
| } |
| } |
| |
| void TextureBufferOperations::deinitSecondPhase(void) |
| { |
| /* Get GLES entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Reset GLES state */ |
| gl.bindVertexArray(0); |
| gl.bindTexture(GL_TEXTURE_2D, 0); |
| gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); |
| gl.bindFramebuffer(GL_READ_FRAMEBUFFER, 0); |
| gl.bindBuffer(GL_ARRAY_BUFFER, 0); |
| |
| if (m_vertex_location != -1) |
| { |
| gl.disableVertexAttribArray(m_vertex_location); |
| m_vertex_location = -1; |
| } |
| |
| if (m_index_location != -1) |
| { |
| gl.disableVertexAttribArray(m_index_location); |
| m_index_location = -1; |
| } |
| |
| gl.useProgram(0); |
| |
| /* Delete GLES objects */ |
| if (0 != m_po_vs_fs_id) |
| { |
| gl.deleteProgram(m_po_vs_fs_id); |
| m_po_vs_fs_id = 0; |
| } |
| |
| if (0 != m_fs_id) |
| { |
| gl.deleteShader(m_fs_id); |
| m_fs_id = 0; |
| } |
| |
| if (0 != m_vs_id) |
| { |
| gl.deleteShader(m_vs_id); |
| m_vs_id = 0; |
| } |
| |
| if (0 != m_fbo_id) |
| { |
| gl.deleteFramebuffers(1, &m_fbo_id); |
| m_fbo_id = 0; |
| } |
| |
| if (0 != m_to_id) |
| { |
| gl.deleteTextures(1, &m_to_id); |
| m_to_id = 0; |
| } |
| |
| if (0 != m_vao_id) |
| { |
| gl.deleteVertexArrays(1, &m_vao_id); |
| m_vao_id = 0; |
| } |
| |
| if (0 != m_vbo_id) |
| { |
| gl.deleteBuffers(1, &m_vbo_id); |
| m_vbo_id = 0; |
| } |
| |
| if (0 != m_vbo_indicies_id) |
| { |
| gl.deleteBuffers(1, &m_vbo_indicies_id); |
| m_vbo_indicies_id = 0; |
| } |
| } |
| |
| /** Constructor for Test Case 1 |
| * |
| * @param context Test context |
| * @param name Test case's name |
| * @param description Test case's description |
| **/ |
| TextureBufferOperationsViaBufferObjectLoad::TextureBufferOperationsViaBufferObjectLoad(Context& context, |
| const ExtParameters& extParams, |
| const char* name, |
| const char* description) |
| : TextureBufferOperations(context, extParams, name, description) |
| { |
| } |
| |
| /** Initialize texture buffer object with test data using glBufferSubData() |
| * |
| **/ |
| void TextureBufferOperationsViaBufferObjectLoad::initializeBufferObjectData(void) |
| { |
| /* Get GL entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| std::vector<glw::GLint> data(m_n_vectors_in_buffer_texture * m_n_vector_components); |
| fillBufferWithData(&data[0], m_n_vectors_in_buffer_texture * m_n_vector_components); |
| |
| gl.bufferSubData(m_glExtTokens.TEXTURE_BUFFER, 0, |
| m_n_vectors_in_buffer_texture * m_n_vector_components * sizeof(glw::GLint), &data[0]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting buffer object data!"); |
| } |
| |
| /** Constructor for Test Case 2 |
| * |
| * @param context Test context |
| * @param name Test case's name |
| * @param description Test case's description |
| **/ |
| TextureBufferOperationsViaCPUWrites::TextureBufferOperationsViaCPUWrites(Context& context, |
| const ExtParameters& extParams, |
| const char* name, const char* description) |
| : TextureBufferOperations(context, extParams, name, description) |
| { |
| } |
| |
| /** Initialize texture buffer object with test data using CPU Write |
| * |
| **/ |
| void TextureBufferOperationsViaCPUWrites::initializeBufferObjectData(void) |
| { |
| /* Get GL entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| std::vector<glw::GLint> data(m_n_vectors_in_buffer_texture * m_n_vector_components); |
| fillBufferWithData(&data[0], m_n_vectors_in_buffer_texture * m_n_vector_components); |
| |
| glw::GLint* tempBuffer = (glw::GLint*)gl.mapBufferRange( |
| m_glExtTokens.TEXTURE_BUFFER, 0, m_n_vectors_in_buffer_texture * m_n_vector_components * sizeof(glw::GLint), |
| GL_MAP_WRITE_BIT); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error mapping buffer object's data store to client's address space!"); |
| |
| for (glw::GLuint i = 0; i < data.size(); ++i) |
| { |
| tempBuffer[i] = data[i]; |
| } |
| |
| gl.unmapBuffer(m_glExtTokens.TEXTURE_BUFFER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error ummapping buffer object's data store from client's address space!"); |
| } |
| |
| /** Constructor for Test Case 3 |
| * |
| * @param context Test context |
| * @param name Test case's name |
| * @param description Test case's description |
| **/ |
| TextureBufferOperationsViaFrambufferReadBack::TextureBufferOperationsViaFrambufferReadBack( |
| Context& context, const ExtParameters& extParams, const char* name, const char* description) |
| : TextureBufferOperations(context, extParams, name, description) |
| , m_fb_fbo_id(0) |
| , m_fb_fs_id(0) |
| , m_fb_po_id(0) |
| , m_fb_to_id(0) |
| , m_fb_vao_id(0) |
| , m_fb_vbo_id(0) |
| , m_fb_vs_id(0) |
| , m_position_location(-1) |
| { |
| } |
| |
| /** Initialize texture buffer object with test data using framebuffer readbacks to pixel buffer object |
| * |
| **/ |
| void TextureBufferOperationsViaFrambufferReadBack::initializeBufferObjectData() |
| { |
| /* Get GL entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| std::vector<glw::GLint> data(m_n_vectors_in_buffer_texture * m_n_vector_components); |
| fillBufferWithData(&data[0], m_n_vectors_in_buffer_texture * m_n_vector_components); |
| |
| /* Configure vertex array object */ |
| gl.genVertexArrays(1, &m_fb_vao_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating vertex array object!"); |
| |
| gl.bindVertexArray(m_fb_vao_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!"); |
| |
| /* Prepare framebuffer object */ |
| gl.genFramebuffers(1, &m_fb_fbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error genertaing framebuffer object!"); |
| |
| gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fb_fbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding framebuffer object!"); |
| |
| /* Prepare texture object */ |
| gl.genTextures(1, &m_fb_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating texture object!"); |
| |
| gl.bindTexture(GL_TEXTURE_2D, m_fb_to_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding texture object!"); |
| |
| gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32I, m_n_vectors_in_buffer_texture /* width */, 1 /* height */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocating texture object's data store!"); |
| |
| /* Attach texture to framebuffer */ |
| gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_fb_to_id, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error attaching texture to framebuffer's color attachment!"); |
| |
| /* Check framebuffer status */ |
| checkFramebufferStatus(GL_DRAW_FRAMEBUFFER); |
| |
| /* Configure view port */ |
| gl.viewport(0, 0, m_n_vectors_in_buffer_texture, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting viewport!"); |
| |
| /* Create program object */ |
| m_fb_po_id = gl.createProgram(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating program object!"); |
| |
| m_fb_fs_id = gl.createShader(GL_FRAGMENT_SHADER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating fragment shader object!"); |
| |
| m_fb_vs_id = gl.createShader(GL_VERTEX_SHADER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating vertex shader object!"); |
| |
| std::string fsSource = getFBFragmentShaderCode(); |
| std::string vsSource = getFBVertexShaderCode(); |
| |
| const char* fsCode = fsSource.c_str(); |
| const char* vsCode = vsSource.c_str(); |
| |
| if (!buildProgram(m_fb_po_id, m_fb_fs_id, 1, &fsCode, m_fb_vs_id, 1, &vsCode)) |
| { |
| TCU_FAIL("Could not create a program from valid vertex/fragment shader code!"); |
| } |
| |
| /* Full screen quad */ |
| glw::GLfloat vertices[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, |
| 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f }; |
| |
| /* Generate buffer object */ |
| gl.genBuffers(1, &m_fb_vbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating buffer object!"); |
| |
| /* Bind buffer object */ |
| gl.bindBuffer(GL_ARRAY_BUFFER, m_fb_vbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding buffer object!"); |
| |
| /* Set data for buffer object */ |
| gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting data for buffer object!"); |
| |
| gl.useProgram(m_fb_po_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting active program object!"); |
| |
| m_position_location = gl.getAttribLocation(m_fb_po_id, "inPosition"); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not get attribute location!"); |
| if (m_position_location == -1) |
| { |
| TCU_FAIL("Could not get uniform location"); |
| } |
| |
| gl.vertexAttribPointer(m_position_location, 4, GL_FLOAT, GL_FALSE, 0, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set vertex attribute pointer!"); |
| |
| gl.enableVertexAttribArray(m_position_location); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not enable vertex attribute array!"); |
| |
| /* Clear texture */ |
| gl.clearColor(0.0f, 0.0f, 0.0f, 0.0f); |
| gl.clear(GL_COLOR_BUFFER_BIT); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error clearing color buffer"); |
| |
| /* Render */ |
| gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed!"); |
| |
| gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fb_fbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding frame buffer object!"); |
| |
| /* Bind buffer object to pixel pack buffer */ |
| gl.bindBuffer(GL_PIXEL_PACK_BUFFER, m_tb_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding buffer object !"); |
| |
| gl.pixelStorei(GL_UNPACK_ALIGNMENT, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting GL_UNPACK_ALIGNMENT parameter to 1"); |
| |
| gl.pixelStorei(GL_PACK_ALIGNMENT, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting GL_PACK_ALIGNMENT parameter to 1"); |
| |
| /* Fill buffer object with data from framebuffer object's color attachment */ |
| gl.readPixels(0, 0, m_n_vectors_in_buffer_texture, 1, GL_RGBA_INTEGER, GL_INT, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error reading pixels !"); |
| |
| gl.pixelStorei(GL_UNPACK_ALIGNMENT, 4); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting GL_UNPACK_ALIGNMENT parameter to default value"); |
| |
| gl.pixelStorei(GL_PACK_ALIGNMENT, 4); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting GL_PACK_ALIGNMENT parameter to default value"); |
| |
| gl.bindBuffer(GL_PIXEL_PACK_BUFFER, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding buffer object!"); |
| |
| gl.bindBuffer(m_glExtTokens.TEXTURE_BUFFER, m_tb_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding buffer object!"); |
| |
| gl.bindVertexArray(0); |
| gl.bindTexture(GL_TEXTURE_2D, 0); |
| gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); |
| gl.bindFramebuffer(GL_READ_FRAMEBUFFER, 0); |
| gl.bindBuffer(GL_ARRAY_BUFFER, 0); |
| |
| if (glu::isContextTypeES(m_context.getRenderContext().getType())) |
| gl.disableVertexAttribArray(m_position_location); |
| |
| gl.useProgram(0); |
| |
| m_position_location = -1; |
| } |
| |
| /** Returns Fragment Shader Code |
| * |
| * @return pointer to literal with Fragment Shader Code |
| */ |
| std::string TextureBufferOperationsViaFrambufferReadBack::getFBFragmentShaderCode() const |
| { |
| std::stringstream strstream; |
| |
| strstream << "${VERSION}\n" |
| "\n" |
| "precision highp float;\n" |
| "\n" |
| "out ivec4 color;\n" |
| "\n" |
| "void main(void)\n" |
| "{\n" |
| " color = ivec4(0, 1, 0, 1);\n" |
| "}\n"; |
| |
| return strstream.str(); |
| } |
| |
| /** Returns Vertex Shader Code |
| * |
| * @return pointer to literal with Vertex Shader Code |
| */ |
| std::string TextureBufferOperationsViaFrambufferReadBack::getFBVertexShaderCode() const |
| { |
| std::stringstream strstream; |
| |
| strstream << "${VERSION}\n" |
| "\n" |
| "precision highp float;\n" |
| "\n" |
| "in vec4 inPosition;\n" |
| "\n" |
| "void main(void)\n" |
| "{\n" |
| " gl_Position = inPosition;\n" |
| "}\n"; |
| |
| return strstream.str(); |
| } |
| |
| /** Fills buffer with test data |
| * |
| * @param buffer pointer to buffer |
| * @param bufferLenth buffer length |
| */ |
| void TextureBufferOperationsViaFrambufferReadBack::fillBufferWithData(glw::GLint* buffer, glw::GLuint bufferLength) |
| { |
| for (glw::GLuint i = 0; i < bufferLength; ++i) |
| { |
| buffer[i] = (glw::GLint)(i % 2); /* Reference color is 0, 1, 0, 1 */ |
| } |
| } |
| |
| /** Deinitializes GLES objects created during the test. |
| * |
| */ |
| void TextureBufferOperationsViaFrambufferReadBack::deinit(void) |
| { |
| /* Get GL entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Reset GLES state */ |
| gl.bindVertexArray(0); |
| gl.bindTexture(GL_TEXTURE_2D, 0); |
| gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); |
| gl.bindFramebuffer(GL_READ_FRAMEBUFFER, 0); |
| gl.bindBuffer(GL_ARRAY_BUFFER, 0); |
| |
| if (m_position_location != -1) |
| { |
| gl.disableVertexAttribArray(m_position_location); |
| m_position_location = -1; |
| } |
| |
| gl.useProgram(0); |
| |
| /* Delete GLES objects */ |
| if (0 != m_fb_po_id) |
| { |
| gl.deleteProgram(m_fb_po_id); |
| m_fb_po_id = 0; |
| } |
| |
| if (0 != m_fb_fs_id) |
| { |
| gl.deleteShader(m_fb_fs_id); |
| m_fb_fs_id = 0; |
| } |
| |
| if (0 != m_fb_vs_id) |
| { |
| gl.deleteShader(m_fb_vs_id); |
| m_fb_vs_id = 0; |
| } |
| |
| if (0 != m_fb_fbo_id) |
| { |
| gl.deleteFramebuffers(1, &m_fb_fbo_id); |
| m_fb_fbo_id = 0; |
| } |
| |
| if (0 != m_fb_to_id) |
| { |
| gl.deleteTextures(1, &m_fb_to_id); |
| m_fb_to_id = 0; |
| } |
| |
| if (0 != m_fb_vbo_id) |
| { |
| gl.deleteBuffers(1, &m_fb_vbo_id); |
| m_fb_vbo_id = 0; |
| } |
| |
| if (0 != m_fb_vao_id) |
| { |
| gl.deleteVertexArrays(1, &m_fb_vao_id); |
| m_fb_vao_id = 0; |
| } |
| |
| /* Deinitialize base class */ |
| TextureBufferOperations::deinit(); |
| } |
| |
| /** Constructor for Test Case 4 |
| * |
| * @param context Test context |
| * @param name Test case's name |
| * @param description Test case's description |
| **/ |
| TextureBufferOperationsViaTransformFeedback::TextureBufferOperationsViaTransformFeedback(Context& context, |
| const ExtParameters& extParams, |
| const char* name, |
| const char* description) |
| : TextureBufferOperations(context, extParams, name, description) |
| , m_tf_fs_id(0) |
| , m_tf_po_id(0) |
| , m_tf_vao_id(0) |
| , m_tf_vbo_id(0) |
| , m_tf_vs_id(0) |
| , m_position_location(-1) |
| { |
| } |
| |
| /** Initialize buffer object with test data using transform feedback |
| * |
| **/ |
| void TextureBufferOperationsViaTransformFeedback::initializeBufferObjectData() |
| { |
| /* Get GL entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| std::vector<glw::GLint> data(m_n_vectors_in_buffer_texture * m_n_vector_components); |
| fillBufferWithData(&data[0], m_n_vectors_in_buffer_texture * m_n_vector_components); |
| |
| /* Configure vertex array object */ |
| gl.genVertexArrays(1, &m_tf_vao_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating vertex array object!"); |
| |
| gl.bindVertexArray(m_tf_vao_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!"); |
| |
| /* Configure buffer object*/ |
| gl.genBuffers(1, &m_tf_vbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating vertex buffer object!"); |
| |
| gl.bindBuffer(GL_ARRAY_BUFFER, m_tf_vbo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex buffer object!"); |
| |
| gl.bufferData(GL_ARRAY_BUFFER, m_n_vectors_in_buffer_texture * m_n_vector_components * sizeof(glw::GLint), &data[0], |
| GL_DYNAMIC_DRAW); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocating buffer object's data store!"); |
| |
| m_tf_po_id = gl.createProgram(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating program object!"); |
| |
| /* Setup transform feedback varyings */ |
| const char* varyings[] = { "outPosition" }; |
| gl.transformFeedbackVaryings(m_tf_po_id, 1, varyings, GL_SEPARATE_ATTRIBS); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error specifying transform feedback varyings!"); |
| |
| m_tf_fs_id = gl.createShader(GL_FRAGMENT_SHADER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating fragment shader object!"); |
| |
| m_tf_vs_id = gl.createShader(GL_VERTEX_SHADER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating vertex shader object!"); |
| |
| std::string fsSource = getTFFragmentShaderCode(); |
| std::string vsSource = getTFVertexShaderCode(); |
| |
| const char* fsCode = fsSource.c_str(); |
| const char* vsCode = vsSource.c_str(); |
| |
| if (!buildProgram(m_tf_po_id, m_tf_fs_id, 1, &fsCode, m_tf_vs_id, 1, &vsCode)) |
| { |
| TCU_FAIL("Could not create a program from valid vertex/fragment shader code!"); |
| } |
| |
| gl.useProgram(m_tf_po_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting active program object!"); |
| |
| m_position_location = gl.getAttribLocation(m_tf_po_id, "inPosition"); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error getting attrib location!"); |
| |
| gl.vertexAttribIPointer(m_position_location, m_n_vector_components, GL_INT, 0, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting vertex attrib pointer!"); |
| |
| gl.enableVertexAttribArray(m_position_location); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error enabling vertex attrib array!"); |
| |
| gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_tb_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding buffer object to transform feedback binding point!"); |
| |
| gl.beginTransformFeedback(GL_POINTS); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error starting transform feedback!"); |
| |
| /* Render */ |
| gl.drawArrays(GL_POINTS, 0, m_n_vectors_in_buffer_texture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error during rendering!"); |
| |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error ending transform feedback!"); |
| |
| gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0); |
| gl.bindBuffer(GL_ARRAY_BUFFER, 0); |
| gl.bindVertexArray(0); |
| |
| if (glu::isContextTypeES(m_context.getRenderContext().getType())) |
| gl.disableVertexAttribArray(m_position_location); |
| |
| gl.useProgram(0); |
| |
| gl.memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); |
| |
| m_position_location = -1; |
| } |
| |
| /** Returns Fragment shader Code |
| * |
| * @return pointer to literal with Fragment Shader Code |
| */ |
| std::string TextureBufferOperationsViaTransformFeedback::getTFFragmentShaderCode() const |
| { |
| std::stringstream strstream; |
| |
| strstream << "${VERSION}\n" |
| "\n" |
| "${TEXTURE_BUFFER_REQUIRE}\n" |
| "\n" |
| "in flat ivec4 outPosition;\n" |
| "\n" |
| "precision highp float;\n" |
| "\n" |
| "void main(void)\n" |
| "{\n" |
| "}\n"; |
| |
| return strstream.str(); |
| } |
| |
| /** Returns Vertex Shader Code |
| * |
| * @return pointer to literal with Vertex Shader Code |
| */ |
| std::string TextureBufferOperationsViaTransformFeedback::getTFVertexShaderCode() const |
| { |
| std::stringstream strstream; |
| |
| strstream << "${VERSION}\n" |
| "\n" |
| "${TEXTURE_BUFFER_REQUIRE}\n" |
| "\n" |
| "precision highp float;\n" |
| "\n" |
| "in ivec4 inPosition;\n" |
| "\n" |
| "flat out ivec4 outPosition;\n" |
| "\n" |
| "void main(void)\n" |
| "{\n" |
| " gl_Position = vec4(0.0, 0.0, 0.0, 0.0);\n" |
| " outPosition = inPosition;\n" |
| "}\n"; |
| |
| return strstream.str(); |
| } |
| |
| /** Deinitializes GLES objects created during the test. */ |
| void TextureBufferOperationsViaTransformFeedback::deinit(void) |
| { |
| /* Get GL entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Reset GLES state */ |
| gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0); |
| gl.bindBuffer(GL_ARRAY_BUFFER, 0); |
| gl.bindVertexArray(0); |
| |
| if (m_position_location != -1) |
| { |
| gl.disableVertexAttribArray(m_position_location); |
| m_position_location = -1; |
| } |
| |
| gl.useProgram(0); |
| |
| /* Delete GLES objects */ |
| if (0 != m_tf_po_id) |
| { |
| gl.deleteProgram(m_tf_po_id); |
| m_tf_po_id = 0; |
| } |
| |
| if (0 != m_tf_vs_id) |
| { |
| gl.deleteShader(m_tf_vs_id); |
| m_tf_vs_id = 0; |
| } |
| |
| if (0 != m_tf_fs_id) |
| { |
| gl.deleteShader(m_tf_fs_id); |
| m_tf_fs_id = 0; |
| } |
| |
| if (0 != m_tf_vbo_id) |
| { |
| gl.deleteBuffers(1, &m_tf_vbo_id); |
| m_tf_vbo_id = 0; |
| } |
| |
| if (0 != m_tf_vao_id) |
| { |
| gl.deleteVertexArrays(1, &m_tf_vao_id); |
| m_tf_vao_id = 0; |
| } |
| |
| /* Deinitialize base class */ |
| TextureBufferOperations::deinit(); |
| } |
| |
| const glw::GLuint TextureBufferOperationsViaImageStore::m_image_unit = 0; |
| |
| /** Constructor for Test Case 5 |
| * |
| * @param context Test context |
| * @param name Test case's name |
| * @param description Test case's description |
| **/ |
| TextureBufferOperationsViaImageStore::TextureBufferOperationsViaImageStore(Context& context, |
| const ExtParameters& extParams, |
| const char* name, const char* description) |
| : TextureBufferOperations(context, extParams, name, description), m_is_cs_id(0), m_is_po_id(0) |
| { |
| } |
| |
| /** Initialize buffer object with test data using image store |
| * |
| **/ |
| void TextureBufferOperationsViaImageStore::initializeBufferObjectData() |
| { |
| /* Get Gl entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Configure program object */ |
| m_is_po_id = gl.createProgram(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating program object!"); |
| |
| m_is_cs_id = gl.createShader(GL_COMPUTE_SHADER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating compute shader object!"); |
| |
| std::string csSource = getISComputeShaderCode(); |
| const char* csCode = csSource.c_str(); |
| |
| if (!buildProgram(m_is_po_id, m_is_cs_id, 1, &csCode)) |
| { |
| TCU_FAIL("Could not create a program from valid compute shader source!"); |
| } |
| |
| gl.useProgram(m_is_po_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting active program object!"); |
| |
| gl.bindImageTexture(m_image_unit, m_texbuff_id, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32I); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding texture object to image unit!"); |
| |
| gl.dispatchCompute(1, 1, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error running compute shader!"); |
| |
| gl.memoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting memory barrier!"); |
| |
| gl.useProgram(0); |
| } |
| |
| /** Returns Compute Shader Code |
| * |
| * @return pointer to literal with Compute Shader Code |
| */ |
| std::string TextureBufferOperationsViaImageStore::getISComputeShaderCode() const |
| { |
| std::stringstream strstream; |
| |
| strstream << "${VERSION}\n" |
| "\n" |
| "${TEXTURE_BUFFER_REQUIRE}\n" |
| "\n" |
| "precision highp float;\n" |
| "\n" |
| "layout(rgba32i, binding = 0) uniform writeonly highp iimageBuffer image_buffer;\n" |
| "\n" |
| "layout (local_size_x = " |
| << m_n_vectors_in_buffer_texture |
| << " ) in;\n" |
| "\n" |
| "void main(void)\n" |
| "{\n" |
| " imageStore(image_buffer, int(gl_LocalInvocationID.x), ivec4(gl_LocalInvocationID.x) );\n" |
| "}\n"; |
| |
| return strstream.str(); |
| } |
| |
| /** Fill buffer with test data |
| * |
| * @param buffer pointer to buffer |
| * @param bufferLenth buffer length |
| */ |
| void TextureBufferOperationsViaImageStore::fillBufferWithData(glw::GLint* buffer, glw::GLuint bufferLength) |
| { |
| for (glw::GLuint i = 0; i < bufferLength; ++i) |
| { |
| buffer[i] = (glw::GLint)(i / m_n_vector_components); |
| } |
| } |
| |
| /** Deinitializes GLES objects created during the test. */ |
| void TextureBufferOperationsViaImageStore::deinit(void) |
| { |
| /* Get Gl entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Reset GLES state */ |
| gl.useProgram(0); |
| |
| /* Delete GLES objects */ |
| if (0 != m_is_po_id) |
| { |
| gl.deleteProgram(m_is_po_id); |
| m_is_po_id = 0; |
| } |
| |
| if (0 != m_is_cs_id) |
| { |
| gl.deleteShader(m_is_cs_id); |
| m_is_cs_id = 0; |
| } |
| |
| /* Deinitalize base class */ |
| TextureBufferOperations::deinit(); |
| } |
| |
| /** Constructor for Test Case 6 |
| * |
| * @param context Test context |
| * @param name Test case's name |
| * @param description Test case's description |
| **/ |
| TextureBufferOperationsViaSSBOWrites::TextureBufferOperationsViaSSBOWrites(Context& context, |
| const ExtParameters& extParams, |
| const char* name, const char* description) |
| : TextureBufferOperations(context, extParams, name, description), m_ssbo_cs_id(0), m_ssbo_po_id(0) |
| { |
| } |
| |
| /** Initialize buffer object with test data using ssbo writes |
| * |
| **/ |
| void TextureBufferOperationsViaSSBOWrites::initializeBufferObjectData() |
| { |
| /* Get Gl entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Configure program object */ |
| m_ssbo_po_id = gl.createProgram(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating program object!"); |
| |
| m_ssbo_cs_id = gl.createShader(GL_COMPUTE_SHADER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating compute shader object!"); |
| |
| std::string csSource = getSSBOComputeShaderCode(); |
| const char* csCode = csSource.c_str(); |
| |
| if (!buildProgram(m_ssbo_po_id, m_ssbo_cs_id, 1, &csCode)) |
| { |
| TCU_FAIL("Could not create a program from valid compute shader source!"); |
| } |
| |
| gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_tb_bo_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind buffer object to shader storage binding point!"); |
| |
| gl.useProgram(m_ssbo_po_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting active program object!"); |
| |
| gl.dispatchCompute(1, 1, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error running compute shader!"); |
| |
| gl.memoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting memory barrier!"); |
| |
| gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, 0); |
| gl.useProgram(0); |
| } |
| |
| /** Returns Compute Shader Code |
| * |
| * @return pointer to literal with Compute Shader Code |
| */ |
| std::string TextureBufferOperationsViaSSBOWrites::getSSBOComputeShaderCode() const |
| { |
| std::stringstream strstream; |
| |
| strstream << "${VERSION}\n" |
| "\n" |
| "${TEXTURE_BUFFER_REQUIRE}\n" |
| "\n" |
| "precision highp float;\n" |
| "\n" |
| "buffer ComputeSSBO\n" |
| "{\n" |
| " ivec4 value[];\n" |
| "} computeSSBO;\n" |
| "\n" |
| "layout (local_size_x = " |
| << m_n_vectors_in_buffer_texture |
| << " ) in;\n" |
| "\n" |
| "void main(void)\n" |
| "{\n" |
| " computeSSBO.value[gl_LocalInvocationID.x] = ivec4(gl_LocalInvocationID.x);\n" |
| "}\n"; |
| |
| return strstream.str(); |
| } |
| |
| /** Fill buffer with test data |
| * |
| * @param buffer pointer to buffer |
| * @param bufferLenth buffer length |
| */ |
| void TextureBufferOperationsViaSSBOWrites::fillBufferWithData(glw::GLint* buffer, glw::GLuint bufferLength) |
| { |
| for (glw::GLuint i = 0; i < bufferLength; ++i) |
| { |
| buffer[i] = (glw::GLint)(i / m_n_vector_components); |
| } |
| } |
| |
| /** Deinitializes GLES objects created during the test. */ |
| void TextureBufferOperationsViaSSBOWrites::deinit(void) |
| { |
| /* Get Gl entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Reset GLES state */ |
| gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, 0); |
| gl.useProgram(0); |
| |
| /* Delete GLES objects */ |
| if (0 != m_ssbo_po_id) |
| { |
| gl.deleteProgram(m_ssbo_po_id); |
| m_ssbo_po_id = 0; |
| } |
| |
| if (0 != m_ssbo_cs_id) |
| { |
| gl.deleteShader(m_ssbo_cs_id); |
| m_ssbo_cs_id = 0; |
| } |
| |
| /* Deinitalize base class */ |
| TextureBufferOperations::deinit(); |
| } |
| |
| } // namespace glcts |