blob: ae17cbfccff42a0ee7ef591dba57f37160e4197d [file] [log] [blame]
#ifndef _ESEXTCTEXTUREBUFFEROPERATIONS_HPP
#define _ESEXTCTEXTUREBUFFEROPERATIONS_HPP
/*-------------------------------------------------------------------------
* 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.hpp
* \brief Texture Buffer Operations (Test 1)
*/ /*-------------------------------------------------------------------*/
#include "../esextcTestCaseBase.hpp"
namespace glcts
{
/** Implementation of (Test 1) from CTS_EXT_texture_buffer. Description follows
*
* Check whether texture data for the texture buffer can be specified in a number
* of different ways:
*
* 1. via buffer object loads
* 2. via direct CPU writes
* 3. via framebuffer readbacks to pixel buffer objects
* 4. via transform feedback
* 5. via image store
* 6. via ssbo writes
*
* Category: API, Functional Test.
*
* The test should create a texture object and bind it to GL_TEXTURE_BUFFER_EXT
* texture target at texture unit 0. It should also create buffer object
* and bind it to TEXTURE_BUFFER_EXT target. Call glBufferData with NULL data
* pointer to allocate storage for the buffer object. The size of the storage
* should be equal to value(GL_MAX_COMPUTE_WORK_GROUP_SIZE, X axis) *
* sizeof(GLint) * 4.
*
* The buffer object should be used as texture buffer's data store by calling
*
* TexBufferExt(TEXTURE_BUFFER_EXT, GL_RGBA32I, buffer_id );
*
* The data for the buffer object should be specified in the following ways:
*
* ---------------------------------------------------------------------------
*
* 1. Use glBufferSubData to fill buffer object's data store.
* glBufferSubData should be given a pointer to data that will be copied into
* the data store for initialization.
*
* ---------------------------------------------------------------------------
*
* 2. Map the buffer object's data store to client's address space by using
* glMapBufferRange function (map the whole data store). The data store should
* then be filled with values up to the size of the data store.
* The data store should be unmapped using glUnmapBuffer function.
*
* ---------------------------------------------------------------------------
*
* 3. Create a framebuffer object and bind it to GL_DRAW_FRAMEBUFFER target.
* Create a 2d texture object with size
* value(GL_MAX_COMPUTE_WORK_GROUP_SIZE, X axis) x 1 and RGBA32I internal
* format. Attach the texture object to framebuffer's GL_COLOR_ATTACHMENT0
* attachment. Render to texture filling it completely with some predefined
* integer values.
*
* Bind the framebuffer object to GL_READ_FRAMEBUFFER target.
*
* Bind the buffer object to GL_PIXEL_PACK_BUFFER target.
*
* Set the alignment requirements by calling glPixelStorei(GL_UNPACK_ALIGNMENT,1)
* and glPixelStorei(GL_PACK_ALIGNMENT,1).
*
* Call glReadPixels(0, 0, value(GL_MAX_COMPUTE_WORK_GROUP_SIZE, X axis),
* 1, GL_RGBA, GL_INT, 0).
*
* Bind the buffer object once again to TEXTURE_BUFFER_EXT target.
*
* ---------------------------------------------------------------------------
*
* 4. Write a vertex shader that declares in ivec4 inPosition and
* out ivec4 outPosition variables and a matching fragment shader. The vertex
* shader should assign the value of inPosition to outPosition. The buffer object
* being a data source for the inPosition attribute should be filled with some
* integer values. Configure transform feedback to capture value of outPosition.
* Bind our texture buffer's buffer object as destination buffer for transform
* feedback operations.
*
* Execute a draw call.
*
* ---------------------------------------------------------------------------
*
* 5. Write a compute shader that defines
*
* layout(rgba32i, binding = 0) uniform highp iimageBuffer image_buffer;
*
* The work group size should be equal to
* value(GL_MAX_COMPUTE_WORK_GROUP_SIZE, X axis) x 1 x 1.
*
* Bind the texture buffer to image unit 0.
*
* In the compute shader execute:
*
* imageStore(image_buffer, gl_LocalInvocationID.x, ivec4(gl_LocalInvocationID.x) );
*
* Call:
*
* glDispatchCompute(1, 1, 1);
* glMemoryBarrier(TEXTURE_FETCH_BARRIER_BIT);
*
* ---------------------------------------------------------------------------
*
* 6. Write a compute shader that defines
*
* buffer ComputeSSBO
* {
* ivec4 value[];
*
* } computeSSBO;
*
* Work group size should be equal to
* value(GL_MAX_COMPUTE_WORK_GROUP_SIZE, X axis) x 1 x 1.
*
* Bind the buffer object to GL_SHADER_STORAGE_BUFFER target.
*
* In the compute shader execute:
*
* computeSSBO.value[gl_LocalInvocationID.x] = vec4(gl_LocalInvocationID.x);
*
* Call:
*
* glDispatchCompute(1, 1, 1);
* glMemoryBarrier(TEXTURE_FETCH_BARRIER_BIT);
*
* Bind the buffer object once again to TEXTURE_BUFFER_EXT target.
*
* ---------------------------------------------------------------------------
*
* The test checks whether data for the texture buffer has been correctly
* specified in the above 6 different ways and if it can be accessed via imageLoad
* and texelFetch. In the first phase we try to access the data via imageLoad in
* a compute shader and in the second phase we try to access the same data
* via texelFetch in a vertex shader.
*
* For the first phase write a compute shader that defines
*
* layout(rgba32i, binding = 0) uniform highp iimageBuffer image_buffer;
*
* Bind the texture buffer to image unit 0.
*
* Work group size should be equal to
* value(GL_MAX_COMPUTE_WORK_GROUP_SIZE, X axis) x 1 x 1.
*
* The shader should also define a shader storage buffer object
*
* buffer ComputeSSBO
* {
* ivec4 value[];
*
* } computeSSBO;
*
* Initialize a buffer object to be assigned as ssbo data store. The size of
* this buffer object's data store should be equal to the size of
* the data store of the buffer object associated with texture buffer.
*
* In the compute shader execute:
*
* int index = int(gl_LocalInvocationID.x);
*
* computeSSBO.value[index] = imageLoad( image_buffer, index);
*
* Call:
*
* glDispatchCompute(1, 1, 1);
* glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
*
* For each case compare the contents of the data store of ssbo's buffer object
* with the values that this case should have written to the data store of the
* texture buffer. This phase of the test passes if for each case we get equality.
*
* For the second phase of the test write a vertex shader that defines
*
* in vec4 vs_position;
* in float vs_index;
* out float fs_index;
*
* The shader should execute the following operations:
*
* gl_Position = vs_position;
* fs_index = vs_index;
*
* Configure buffer object as data source for the vs_position attribute.
* The buffer object should be filled with data:
* (-1,-1,0,1), (1,-1,0,1), (-1,1,0,1), (1,1,0,1).
*
* Configure buffer object as data source for the vs_index attribute.
* The buffer object should be filled with data:
* 0.0f , 0.0f , value(GL_MAX_COMPUTE_WORK_GROUP_SIZE, X axis),
* value(GL_MAX_COMPUTE_WORK_GROUP_SIZE, X axis).
*
* Write a fragment shader that defines;
*
* in float fs_index;
*
* uniform highp isamplerBuffer sampler_buffer;
*
* layout(location = 0) out ivec4 color;
*
* The shader should execute the following operations:
*
* color = texelFetch( sampler_buffer, int(fs_index) );
*
* Create a program from the above vertex shader and fragment shader and use it.
*
* Bind the sampler_buffer location to texture unit 0.
*
* The test should set up a FBO. A 2D texture of
* value(GL_MAX_COMPUTE_WORK_GROUP_SIZE, X axis) x 1 resolution using
* GL_RGBA32I internal format and GL_NEAREST magnification and
* minification filter should be attached to its color attachment 0.
*
* Execute a draw call glDrawArrays(GL_TRIANGLE_STRIP, 0, 4).
*
* Use glReadPixels to read the texel data from the texture attached to color
* attachment 0.
*
* For each case compare the contents of retrieved texel data with the values
* that this case should have written to the data store of the texture buffer.
* This phase of the test passes if for each case we get equality.
*/
/* Base Class */
class TextureBufferOperations : public TestCaseBase
{
public:
/* Public methods */
TextureBufferOperations(Context& context, const ExtParameters& extParams, const char* name,
const char* description);
virtual ~TextureBufferOperations()
{
}
virtual void deinit(void);
virtual IterateResult iterate(void);
protected:
/* Protected methods */
void checkFramebufferStatus(glw::GLenum framebuffer);
virtual void initTest(void);
virtual void initializeBufferObjectData(void) = 0;
virtual void fillBufferWithData(glw::GLint* buffer, glw::GLuint bufferLength);
/* Protected static constants */
static const glw::GLuint m_n_vector_components;
/* Protected variables */
glw::GLint m_n_vectors_in_buffer_texture;
glw::GLuint m_tb_bo_id;
glw::GLuint m_texbuff_id;
private:
std::string getComputeShaderCode(void) const;
std::string getFragmentShaderCode(void) const;
std::string getVertexShaderCode(void) const;
void initFirstPhase(void);
void initSecondPhase(void);
void iterateFirstPhase(glw::GLint* result, glw::GLuint size);
void iterateSecondPhase(glw::GLint* result);
void deinitFirstPhase(void);
void deinitSecondPhase(void);
glw::GLboolean verifyResults(glw::GLint* reference, glw::GLint* result, glw::GLuint size, const char* message);
/* Private variables */
glw::GLuint m_cs_id;
glw::GLuint m_po_cs_id;
glw::GLuint m_ssbo_bo_id;
glw::GLuint m_fbo_id;
glw::GLuint m_fs_id;
glw::GLuint m_po_vs_fs_id;
glw::GLuint m_to_id;
glw::GLuint m_vao_id;
glw::GLuint m_vbo_id;
glw::GLuint m_vbo_indicies_id;
glw::GLuint m_vs_id;
glw::GLint m_vertex_location;
glw::GLint m_index_location;
};
/* Test Case 1 - buffer object loads */
class TextureBufferOperationsViaBufferObjectLoad : public TextureBufferOperations
{
public:
/* Public methods */
TextureBufferOperationsViaBufferObjectLoad(Context& context, const ExtParameters& extParams, const char* name,
const char* description);
virtual ~TextureBufferOperationsViaBufferObjectLoad()
{
}
protected:
/* Protected methods */
virtual void initializeBufferObjectData(void);
};
/* Test Case 2 - direct CPU writes */
class TextureBufferOperationsViaCPUWrites : public TextureBufferOperations
{
public:
/* Public methods */
TextureBufferOperationsViaCPUWrites(Context& context, const ExtParameters& extParams, const char* name,
const char* description);
virtual ~TextureBufferOperationsViaCPUWrites()
{
}
protected:
/* Protected methods */
virtual void initializeBufferObjectData(void);
};
/* Test Case 3 - framebuffer readbacks to pixel buffer objects */
class TextureBufferOperationsViaFrambufferReadBack : public TextureBufferOperations
{
public:
/* Public methods */
TextureBufferOperationsViaFrambufferReadBack(Context& context, const ExtParameters& extParams, const char* name,
const char* description);
virtual ~TextureBufferOperationsViaFrambufferReadBack()
{
}
virtual void deinit(void);
private:
/* Private methods */
virtual void initializeBufferObjectData(void);
virtual void fillBufferWithData(glw::GLint* buffer, glw::GLuint bufferLength);
std::string getFBFragmentShaderCode() const;
std::string getFBVertexShaderCode() const;
glw::GLuint m_fb_fbo_id;
glw::GLuint m_fb_fs_id;
glw::GLuint m_fb_po_id;
glw::GLuint m_fb_to_id;
glw::GLuint m_fb_vao_id;
glw::GLuint m_fb_vbo_id;
glw::GLuint m_fb_vs_id;
glw::GLint m_position_location;
};
/* Test Case 4 - transform feedback */
class TextureBufferOperationsViaTransformFeedback : public TextureBufferOperations
{
public:
/* Public methods */
TextureBufferOperationsViaTransformFeedback(Context& context, const ExtParameters& extParams, const char* name,
const char* description);
virtual ~TextureBufferOperationsViaTransformFeedback()
{
}
virtual void deinit(void);
private:
/* Private methods */
virtual void initializeBufferObjectData(void);
std::string getTFVertexShaderCode() const;
std::string getTFFragmentShaderCode() const;
/* Private variables */
glw::GLuint m_tf_fs_id;
glw::GLuint m_tf_po_id;
glw::GLuint m_tf_vao_id;
glw::GLuint m_tf_vbo_id;
glw::GLuint m_tf_vs_id;
glw::GLint m_position_location;
};
/* Test Case 5 - image store */
class TextureBufferOperationsViaImageStore : public TextureBufferOperations
{
public:
/* Public methods */
TextureBufferOperationsViaImageStore(Context& context, const ExtParameters& extParams, const char* name,
const char* description);
virtual ~TextureBufferOperationsViaImageStore()
{
}
virtual void deinit(void);
private:
/* Private methods */
virtual void initializeBufferObjectData(void);
virtual void fillBufferWithData(glw::GLint* buffer, glw::GLuint bufferLength);
std::string getISComputeShaderCode() const;
/* Private Variables */
glw::GLuint m_is_cs_id;
glw::GLuint m_is_po_id;
/* Private static constants */
static const glw::GLuint m_image_unit;
};
/* Test Case 6 - ssbo writes */
class TextureBufferOperationsViaSSBOWrites : public TextureBufferOperations
{
public:
/* Public methods */
TextureBufferOperationsViaSSBOWrites(Context& context, const ExtParameters& extParams, const char* name,
const char* description);
virtual ~TextureBufferOperationsViaSSBOWrites()
{
}
virtual void deinit(void);
private:
/* Private methods */
virtual void initializeBufferObjectData(void);
virtual void fillBufferWithData(glw::GLint* buffer, glw::GLuint bufferLength);
std::string getSSBOComputeShaderCode() const;
/* Private variables */
glw::GLuint m_ssbo_cs_id;
glw::GLuint m_ssbo_po_id;
};
} // namespace glcts
#endif // _ESEXTCTEXTUREBUFFEROPERATIONS_HPP