blob: 40e14b10df286b5117317a216b5ffef139122e75 [file] [log] [blame]
/*-------------------------------------------------------------------------
* 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
*/ /*-------------------------------------------------------------------*/
#include "esextcGeometryShaderLayeredFramebuffer.hpp"
#include "gluContextInfo.hpp"
#include "gluDefs.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include "tcuTestLog.hpp"
#include <cstring>
namespace glcts
{
/** Constructor
*
* @param context Test context
* @param name Test case's name
* @param description Test case's desricption
**/
GeometryShaderLayeredFramebufferBlending::GeometryShaderLayeredFramebufferBlending(Context& context,
const ExtParameters& extParams,
const char* name,
const char* description)
: TestCaseBase(context, extParams, name, description)
, m_fbo_id(0)
, m_fs_id(0)
, m_gs_id(0)
, m_po_id(0)
, m_read_fbo_id(0)
, m_to_id(0)
, m_vao_id(0)
, m_vs_id(0)
{
/* Left blank on purpose */
}
/** Deinitializes GLES objects created during the test. */
void GeometryShaderLayeredFramebufferBlending::deinit(void)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Clean up */
if (m_fbo_id != 0)
{
gl.deleteFramebuffers(1, &m_fbo_id);
}
if (m_fs_id != 0)
{
gl.deleteShader(m_fs_id);
}
if (m_gs_id != 0)
{
gl.deleteShader(m_gs_id);
}
if (m_po_id != 0)
{
gl.deleteProgram(m_po_id);
}
if (m_read_fbo_id != 0)
{
gl.deleteFramebuffers(1, &m_read_fbo_id);
}
if (m_to_id != 0)
{
gl.deleteTextures(1, &m_to_id);
}
if (m_vao_id != 0)
{
gl.deleteVertexArrays(1, &m_vao_id);
}
if (m_vs_id != 0)
{
gl.deleteShader(m_vs_id);
}
/* Release base class */
TestCaseBase::deinit();
}
/** Executes the test.
* Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
* @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
* Note the function throws exception should an error occur!
**/
tcu::TestNode::IterateResult GeometryShaderLayeredFramebufferBlending::iterate(void)
{
/* Test-wide constants */
#define N_TEXTURE_COMPONENTS (4)
#define TEXTURE_DEPTH (4)
#define TEXTURE_HEIGHT (4)
#define TEXTURE_WIDTH (4)
/* Fragment shader code */
const char* fs_code = "${VERSION}\n"
"\n"
"precision highp float;\n"
"\n"
"out vec4 result;\n"
"\n"
"void main()\n"
"{\n"
" result = vec4(0.2);\n"
"}\n";
/* Geometry shader code */
const char* gs_code = "${VERSION}\n"
"${GEOMETRY_SHADER_REQUIRE}\n"
"\n"
"layout(points) in;\n"
"layout(triangle_strip, max_vertices=64) out;\n"
"\n"
"void main()\n"
"{\n"
" for (int n = 0; n < 4; ++n)\n"
" {\n"
" gl_Layer = n;\n"
" gl_Position = vec4(1, 1, 0, 1);\n"
" EmitVertex();\n"
"\n"
" gl_Layer = n;\n"
" gl_Position = vec4(1, -1, 0, 1);\n"
" EmitVertex();\n"
"\n"
" gl_Layer = n;\n"
" gl_Position = vec4(-1, 1, 0, 1);\n"
" EmitVertex();\n"
"\n"
" gl_Layer = n;\n"
" gl_Position = vec4(-1, -1, 0, 1);\n"
" EmitVertex();\n"
"\n"
" EndPrimitive();\n"
" }\n"
"}\n";
/* General variables */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
unsigned int n = 0;
unsigned int n_component = 0;
unsigned int n_layer = 0;
unsigned int n_slice = 0;
unsigned int x = 0;
unsigned int y = 0;
unsigned char buffer[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
unsigned char buffer_slice1[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
unsigned char buffer_slice2[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
unsigned char buffer_slice3[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
unsigned char buffer_slice4[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
unsigned char ref_buffer_slice1[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
unsigned char ref_buffer_slice2[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
unsigned char ref_buffer_slice3[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
unsigned char ref_buffer_slice4[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
if (!m_is_geometry_shader_extension_supported)
{
throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
}
/* Set up shader objects */
m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
m_gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
m_vs_id = gl.createShader(GL_VERTEX_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate shader objects");
/* Set up program objects */
m_po_id = gl.createProgram();
if (!buildProgram(m_po_id, m_fs_id, 1 /* part */, &fs_code, m_gs_id, 1 /* part */, &gs_code, m_vs_id, 1 /* part */,
&m_boilerplate_vs_code))
{
TCU_FAIL("Could not build program object");
}
/* Prepare texture data we will use for each slice */
for (n = 0; n < TEXTURE_WIDTH * TEXTURE_HEIGHT; ++n)
{
unsigned char* slice_pixels_ptr[] = { buffer_slice1 + n * N_TEXTURE_COMPONENTS,
buffer_slice2 + n * N_TEXTURE_COMPONENTS,
buffer_slice3 + n * N_TEXTURE_COMPONENTS,
buffer_slice4 + n * N_TEXTURE_COMPONENTS };
for (n_slice = 0; n_slice < sizeof(slice_pixels_ptr) / sizeof(slice_pixels_ptr[0]); ++n_slice)
{
slice_pixels_ptr[n_slice][0] = 0;
slice_pixels_ptr[n_slice][1] = (unsigned char)(n_slice * 255 / 4);
slice_pixels_ptr[n_slice][2] = (unsigned char)(n_slice * 255 / 8);
slice_pixels_ptr[n_slice][3] = (unsigned char)(n_slice * 255 / 12);
} /* for (all slices) */
} /* for (all pixels) */
/* Calculate reference texture data we will later use when verifying the rendered data */
for (n = 0; n < TEXTURE_WIDTH * TEXTURE_HEIGHT; ++n)
{
unsigned char* ref_slice_pixels_ptr[] = { ref_buffer_slice1 + n * N_TEXTURE_COMPONENTS,
ref_buffer_slice2 + n * N_TEXTURE_COMPONENTS,
ref_buffer_slice3 + n * N_TEXTURE_COMPONENTS,
ref_buffer_slice4 + n * N_TEXTURE_COMPONENTS };
unsigned char* slice_pixels_ptr[] = { buffer_slice1 + n * N_TEXTURE_COMPONENTS,
buffer_slice2 + n * N_TEXTURE_COMPONENTS,
buffer_slice3 + n * N_TEXTURE_COMPONENTS,
buffer_slice4 + n * N_TEXTURE_COMPONENTS };
for (n_slice = 0; n_slice < sizeof(slice_pixels_ptr) / sizeof(slice_pixels_ptr[0]); ++n_slice)
{
unsigned char* ref_slice_ptr = ref_slice_pixels_ptr[n_slice];
unsigned char* slice_ptr = slice_pixels_ptr[n_slice];
float slice_rgba[] = {
float(slice_ptr[0]) / 255.0f, /* convert to FP representation */
float(slice_ptr[1]) / 255.0f, /* convert to FP representation */
float(slice_ptr[2]) / 255.0f, /* convert to FP representation */
float(slice_ptr[3]) / 255.0f /* convert to FP representation */
};
for (n_component = 0; n_component < N_TEXTURE_COMPONENTS; ++n_component)
{
float temp_component = slice_rgba[n_component] /* dst_color */ * slice_rgba[n_component] /* dst_color */
+ 0.8f /* 1-src_color */ * 0.2f /* src_color */;
/* Clamp if necessary */
if (temp_component < 0)
{
temp_component = 0.0f;
}
else if (temp_component > 1)
{
temp_component = 1.0f;
}
/* Convert back to GL_RGBA8 */
ref_slice_ptr[n_component] = (unsigned char)(temp_component * 255.0f);
} /* for (all components) */
} /* for (all slices) */
} /* for (all pixels) */
/* Set up texture object used for the test */
gl.genTextures(1, &m_to_id);
gl.bindTexture(GL_TEXTURE_3D, m_to_id);
gl.texStorage3D(GL_TEXTURE_3D, 1 /* levels */, GL_RGBA8, TEXTURE_WIDTH, TEXTURE_HEIGHT, TEXTURE_DEPTH);
gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 0 /* zoffset */, TEXTURE_WIDTH,
TEXTURE_HEIGHT, 1 /* depth */, GL_RGBA, GL_UNSIGNED_BYTE, buffer_slice1);
gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 1 /* zoffset */, TEXTURE_WIDTH,
TEXTURE_HEIGHT, 1 /* depth */, GL_RGBA, GL_UNSIGNED_BYTE, buffer_slice2);
gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 2 /* zoffset */, TEXTURE_WIDTH,
TEXTURE_HEIGHT, 1 /* depth */, GL_RGBA, GL_UNSIGNED_BYTE, buffer_slice3);
gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 3 /* zoffset */, TEXTURE_WIDTH,
TEXTURE_HEIGHT, 1 /* depth */, GL_RGBA, GL_UNSIGNED_BYTE, buffer_slice4);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up texture object");
/* Set up framebuffer object used for the test */
gl.genFramebuffers(1, &m_fbo_id);
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_id);
gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_to_id, 0 /* level */);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up draw framebuffer");
/* Generate and bind a vertex array object */
gl.genVertexArrays(1, &m_vao_id);
gl.bindVertexArray(m_vao_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up vertex array object");
/* Set up blending */
gl.blendFunc(GL_ONE_MINUS_SRC_COLOR, GL_DST_COLOR);
gl.enable(GL_BLEND);
/* Render */
gl.useProgram(m_po_id);
gl.viewport(0 /* x */, 0 /* y */, TEXTURE_WIDTH, TEXTURE_HEIGHT);
gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
GLU_EXPECT_NO_ERROR(gl.getError(), "Draw call failed");
/* Verify rendered data in the layers */
gl.genFramebuffers(1, &m_read_fbo_id);
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_read_fbo_id);
for (n_layer = 0; n_layer < TEXTURE_DEPTH; ++n_layer)
{
bool has_layer_failed = false;
const unsigned char* ref_buffer =
(n_layer == 0) ?
ref_buffer_slice1 :
(n_layer == 1) ? ref_buffer_slice2 : (n_layer == 2) ? ref_buffer_slice3 : ref_buffer_slice4;
gl.framebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_to_id, 0 /* level */, n_layer);
gl.readPixels(0 /* x */, 0 /* y */, TEXTURE_WIDTH, TEXTURE_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not read back pixel data!");
for (y = 0; y < TEXTURE_HEIGHT; ++y)
{
const unsigned int pixel_size = N_TEXTURE_COMPONENTS;
const unsigned char* ref_row = ref_buffer + y * pixel_size;
const unsigned char* row = buffer + y * pixel_size;
for (x = 0; x < TEXTURE_WIDTH; ++x)
{
#define EPSILON (1)
const unsigned char* data = row + x * pixel_size;
const unsigned char* ref_data = ref_row + x * pixel_size;
if (de::abs((int)data[0] - (int)ref_data[0]) > EPSILON ||
de::abs((int)data[1] - (int)ref_data[1]) > EPSILON ||
de::abs((int)data[2] - (int)ref_data[2]) > EPSILON ||
de::abs((int)data[3] - (int)ref_data[3]) > EPSILON)
{
m_testCtx.getLog() << tcu::TestLog::Message << "(layer=" << n_layer << " x=" << x << " y=" << y
<< ") "
<< "Reference value is different than the rendered data (epsilon > " << EPSILON
<< "): "
<< "(" << (unsigned int)ref_data[0] << ", " << (unsigned int)ref_data[1] << ", "
<< (unsigned int)ref_data[2] << ", " << (unsigned int)ref_data[3] << ") vs "
<< "(" << (unsigned int)data[0] << ", " << (unsigned int)data[1] << ", "
<< (unsigned int)data[2] << ", " << (unsigned int)data[3] << ")."
<< tcu::TestLog::EndMessage;
has_layer_failed = true;
} /* if (regions are different) */
#undef EPSILON
} /* for (all pixels in a row) */
} /* for (all rows) */
if (has_layer_failed)
{
TCU_FAIL("Pixel data comparison failed");
}
} /* for (all layers) */
/* Done */
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
return STOP;
#undef N_TEXTURE_COMPONENTS
#undef TEXTURE_DEPTH
#undef TEXTURE_HEIGHT
#undef TEXTURE_WIDTH
}
/** Constructor
*
* @param context Test context
* @param name Test case's name
* @param description Test case's description
**/
GeometryShaderLayeredFramebufferClear::GeometryShaderLayeredFramebufferClear(Context& context,
const ExtParameters& extParams,
const char* name, const char* description)
: TestCaseBase(context, extParams, name, description)
, m_fbo_char_id(0)
, m_fbo_int_id(0)
, m_fbo_uint_id(0)
, m_read_fbo_id(0)
, m_to_rgba32i_id(0)
, m_to_rgba32ui_id(0)
, m_to_rgba8_id(0)
{
/* Left blank on purpose */
}
/** Executes the test.
* Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
* @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
* Note the function throws exception should an error occur!
**/
tcu::TestNode::IterateResult GeometryShaderLayeredFramebufferClear::iterate(void)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Test-wide definitions */
#define N_TEXTURE_COMPONENTS (4)
#define TEXTURE_DEPTH (4)
#define TEXTURE_HEIGHT (4)
#define TEXTURE_WIDTH (4)
/* Type definitions */
typedef enum {
/* Always first */
CLEAR_FIRST = 0,
/* glClear() */
CLEAR_PLAIN = CLEAR_FIRST,
/* glClearBufferfv() */
CLEAR_BUFFERFV,
/* glClearBufferiv() */
CLEAR_BUFFERIV,
/* glClearBufferuiv() */
CLEAR_BUFFERUIV,
/* Always last */
CLEAR_COUNT
} _clear_type;
/* General variables */
const glw::GLenum fbo_draw_buffer = GL_COLOR_ATTACHMENT0;
int n = 0;
int n_layer = 0;
int x = 0;
int y = 0;
unsigned char buffer_char[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
int buffer_int[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
unsigned int buffer_uint[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
unsigned char slice_1_data_char[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
int slice_1_data_int[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
unsigned int slice_1_data_uint[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
unsigned char slice_2_data_char[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
int slice_2_data_int[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
unsigned int slice_2_data_uint[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
unsigned char slice_3_data_char[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
int slice_3_data_int[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
unsigned int slice_3_data_uint[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
unsigned char slice_4_data_char[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
int slice_4_data_int[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
unsigned int slice_4_data_uint[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
/* Only carry on if geometry shaders are supported */
if (!m_is_geometry_shader_extension_supported)
{
throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
}
/* Set up slice data */
memset(slice_1_data_char, 0, sizeof(slice_1_data_char));
memset(slice_1_data_int, 0, sizeof(slice_1_data_int));
memset(slice_1_data_uint, 0, sizeof(slice_1_data_uint));
memset(slice_2_data_char, 0, sizeof(slice_2_data_char));
memset(slice_2_data_int, 0, sizeof(slice_2_data_int));
memset(slice_2_data_uint, 0, sizeof(slice_2_data_uint));
memset(slice_3_data_char, 0, sizeof(slice_3_data_char));
memset(slice_3_data_int, 0, sizeof(slice_3_data_int));
memset(slice_3_data_uint, 0, sizeof(slice_3_data_uint));
memset(slice_4_data_char, 0, sizeof(slice_4_data_char));
memset(slice_4_data_int, 0, sizeof(slice_4_data_int));
memset(slice_4_data_uint, 0, sizeof(slice_4_data_uint));
for (n = 0; n < 4 /* width */ * 4 /* height */; ++n)
{
slice_1_data_char[4 * n + 0] = 255;
slice_1_data_int[4 * n + 0] = 255;
slice_1_data_uint[4 * n + 0] = 255;
slice_2_data_char[4 * n + 1] = 255;
slice_2_data_int[4 * n + 1] = 255;
slice_2_data_uint[4 * n + 1] = 255;
slice_3_data_char[4 * n + 2] = 255;
slice_3_data_int[4 * n + 2] = 255;
slice_3_data_uint[4 * n + 2] = 255;
slice_4_data_char[4 * n + 0] = 255;
slice_4_data_char[4 * n + 1] = 255;
slice_4_data_int[4 * n + 0] = 255;
slice_4_data_int[4 * n + 1] = 255;
slice_4_data_uint[4 * n + 0] = 255;
slice_4_data_uint[4 * n + 1] = 255;
} /* for (all pixels) */
/* Set up texture objects */
gl.genTextures(1, &m_to_rgba8_id);
gl.genTextures(1, &m_to_rgba32i_id);
gl.genTextures(1, &m_to_rgba32ui_id);
for (n = 0; n < 3 /* textures */; ++n)
{
void* to_data_1 =
(n == 0) ? (void*)slice_1_data_char : (n == 1) ? (void*)slice_1_data_int : (void*)slice_1_data_uint;
void* to_data_2 =
(n == 0) ? (void*)slice_2_data_char : (n == 1) ? (void*)slice_2_data_int : (void*)slice_2_data_uint;
void* to_data_3 =
(n == 0) ? (void*)slice_3_data_char : (n == 1) ? (void*)slice_3_data_int : (void*)slice_3_data_uint;
void* to_data_4 =
(n == 0) ? (void*)slice_4_data_char : (n == 1) ? (void*)slice_4_data_int : (void*)slice_4_data_uint;
glw::GLenum to_format = (n == 0) ? GL_RGBA : (n == 1) ? GL_RGBA_INTEGER : GL_RGBA_INTEGER;
glw::GLenum to_internalformat = (n == 0) ? GL_RGBA8 : (n == 1) ? GL_RGBA32I : GL_RGBA32UI;
glw::GLuint to_id = (n == 0) ? m_to_rgba8_id : (n == 1) ? m_to_rgba32i_id : m_to_rgba32ui_id;
glw::GLenum to_type = (n == 0) ? GL_UNSIGNED_BYTE : (n == 1) ? GL_INT : GL_UNSIGNED_INT;
gl.bindTexture(GL_TEXTURE_3D, to_id);
gl.texStorage3D(GL_TEXTURE_3D, 1 /* levels */, to_internalformat, TEXTURE_WIDTH, TEXTURE_HEIGHT, TEXTURE_DEPTH);
gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 0 /* zoffset */, TEXTURE_WIDTH,
TEXTURE_HEIGHT, 1 /* depth */, to_format, to_type, to_data_1);
gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 1 /* zoffset */, TEXTURE_WIDTH,
TEXTURE_HEIGHT, 1 /* depth */, to_format, to_type, to_data_2);
gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 2 /* zoffset */, TEXTURE_WIDTH,
TEXTURE_HEIGHT, 1 /* depth */, to_format, to_type, to_data_3);
gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 3 /* zoffset */, TEXTURE_WIDTH,
TEXTURE_HEIGHT, 1 /* depth */, to_format, to_type, to_data_4);
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 0);
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0);
gl.texParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not initialize texture object");
} /* for (all texture objects) */
/* Set up framebuffer object */
gl.genFramebuffers(1, &m_fbo_char_id);
gl.genFramebuffers(1, &m_fbo_int_id);
gl.genFramebuffers(1, &m_fbo_uint_id);
gl.genFramebuffers(1, &m_read_fbo_id);
for (n = 0; n < 3 /* framebuffers */; ++n)
{
glw::GLuint fbo_id = (n == 0) ? m_fbo_char_id : (n == 1) ? m_fbo_int_id : m_fbo_uint_id;
glw::GLuint to_id = (n == 0) ? m_to_rgba8_id : (n == 1) ? m_to_rgba32i_id : m_to_rgba32ui_id;
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_id);
gl.drawBuffers(1, &fbo_draw_buffer);
gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, to_id, 0 /* level */);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not initialize framebuffer object");
} /* for (all framebuffers) */
/* Try reading from the layered framebuffer. */
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_char_id);
gl.readPixels(0 /* x */, 0 /* y */, TEXTURE_WIDTH, TEXTURE_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, buffer_char);
/* Is the returned data an exact copy of what we've uploaded for layer zero? */
if (memcmp(buffer_char, slice_1_data_char, sizeof(slice_1_data_char)) != 0)
{
TCU_FAIL("Retrieved data is different from data uploaded for layer 0 of a layered framebuffer.");
}
/* Iterate through all clear calls supported */
for (int current_test = static_cast<int>(CLEAR_FIRST); current_test < static_cast<int>(CLEAR_COUNT); current_test++)
{
void* buffer = NULL;
const float clear_color_float[] = { 0.25f, 0.5f, 1.0f, 32.0f / 255.0f };
const int clear_color_int[] = { 64, 128, 255, 32 };
glw::GLuint fbo_id = 0;
int pixel_size = 0;
void* slice_1_data = NULL;
void* slice_2_data = NULL;
void* slice_3_data = NULL;
void* slice_4_data = NULL;
glw::GLenum to_format = GL_NONE;
glw::GLuint to_id = 0;
glw::GLenum to_type = GL_NONE;
switch (static_cast<_clear_type>(current_test))
{
case CLEAR_BUFFERFV:
case CLEAR_PLAIN:
{
buffer = buffer_char;
fbo_id = m_fbo_char_id;
pixel_size = N_TEXTURE_COMPONENTS;
slice_1_data = slice_1_data_char;
slice_2_data = slice_2_data_char;
slice_3_data = slice_3_data_char;
slice_4_data = slice_4_data_char;
to_format = GL_RGBA;
to_id = m_to_rgba8_id;
to_type = GL_UNSIGNED_BYTE;
break;
}
case CLEAR_BUFFERIV:
{
buffer = (void*)buffer_int;
fbo_id = m_fbo_int_id;
pixel_size = N_TEXTURE_COMPONENTS * sizeof(int);
slice_1_data = slice_1_data_int;
slice_2_data = slice_2_data_int;
slice_3_data = slice_3_data_int;
slice_4_data = slice_4_data_int;
to_format = GL_RGBA_INTEGER;
to_id = m_to_rgba32i_id;
to_type = GL_INT;
break;
}
case CLEAR_BUFFERUIV:
{
buffer = (void*)buffer_uint;
fbo_id = m_fbo_uint_id;
pixel_size = N_TEXTURE_COMPONENTS * sizeof(unsigned int);
slice_1_data = slice_1_data_uint;
slice_2_data = slice_2_data_uint;
slice_3_data = slice_3_data_uint;
slice_4_data = slice_4_data_uint;
to_format = GL_RGBA_INTEGER;
to_id = m_to_rgba32ui_id;
to_type = GL_UNSIGNED_INT;
break;
}
default:
{
/* This location should never be reached */
TCU_FAIL("Execution flow failure");
}
} /* switch (current_test)*/
/* Restore layer data just in case */
gl.bindTexture(GL_TEXTURE_3D, to_id);
gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 0 /* zoffset */, TEXTURE_WIDTH,
TEXTURE_HEIGHT, 1 /* depth */, to_format, to_type, slice_1_data);
gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 1 /* zoffset */, TEXTURE_WIDTH,
TEXTURE_HEIGHT, 1 /* depth */, to_format, to_type, slice_2_data);
gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 2 /* zoffset */, TEXTURE_WIDTH,
TEXTURE_HEIGHT, 1 /* depth */, to_format, to_type, slice_3_data);
gl.texSubImage3D(GL_TEXTURE_3D, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 3 /* zoffset */, TEXTURE_WIDTH,
TEXTURE_HEIGHT, 1 /* depth */, to_format, to_type, slice_4_data);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexSubImage3D() call failed.");
/* Issue requested clear call */
gl.bindFramebuffer(GL_FRAMEBUFFER, fbo_id);
switch (current_test)
{
case CLEAR_PLAIN:
{
gl.clearColor(clear_color_float[0], clear_color_float[1], clear_color_float[2], clear_color_float[3]);
gl.clear(GL_COLOR_BUFFER_BIT);
break;
}
case CLEAR_BUFFERIV:
{
gl.clearBufferiv(GL_COLOR, 0 /* draw buffer index */, clear_color_int);
break;
}
case CLEAR_BUFFERUIV:
{
gl.clearBufferuiv(GL_COLOR, 0 /* draw buffer index */, (const glw::GLuint*)clear_color_int);
break;
}
case CLEAR_BUFFERFV:
{
gl.clearBufferfv(GL_COLOR, 0 /* draw buffer index */, clear_color_float);
break;
}
default:
{
/* This location should never be reached */
TCU_FAIL("Execution flow failure");
}
} /* switch (current_test) */
/* Make sure no error was generated */
GLU_EXPECT_NO_ERROR(gl.getError(), "Clear call failed.");
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_read_fbo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create read framebuffer object!");
/* Check the layer data after a clear call */
for (n_layer = 0; n_layer < TEXTURE_DEPTH; ++n_layer)
{
gl.framebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, to_id, 0 /* level */, n_layer);
gl.readPixels(0 /* x */, 0 /* y */, TEXTURE_WIDTH, TEXTURE_HEIGHT, to_format, to_type, buffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed.");
/* If we requested an integer clear, the pixels we obtained should be reset to specific values.
* If we asked for a FP-based clear, consider an epsilon. */
for (y = 0; y < TEXTURE_HEIGHT; ++y)
{
const int row_size = TEXTURE_WIDTH * pixel_size;
unsigned char* row = (unsigned char*)buffer + y * row_size;
for (x = 0; x < TEXTURE_WIDTH; ++x)
{
if (current_test == CLEAR_BUFFERIV || current_test == CLEAR_BUFFERUIV)
{
unsigned int* pixel = (unsigned int*)(row + x * pixel_size);
if (memcmp(pixel, clear_color_int, sizeof(clear_color_int)) != 0)
{
/* Test fails at this point */
m_testCtx.getLog()
<< tcu::TestLog::Message << "(x=" << x << " y=" << y << ") Reference pixel ["
<< clear_color_int[0] << ", " << clear_color_int[1] << ", " << clear_color_int[2]
<< ", " << clear_color_int[3] << "] is different from the one retrieved ["
<< (int)pixel[0] << ", " << (int)pixel[1] << ", " << (int)pixel[2] << ", "
<< (int)pixel[3] << "]" << tcu::TestLog::EndMessage;
TCU_FAIL("Data comparison failure");
} /* if (memcmp(pixel, clear_color_int, sizeof(clear_color_int) ) != 0) */
} /* if (current_test == CLEAR_BUFFERIV || current_test == CLEAR_BUFFERUIV) */
else
{
#define EPSILON (1)
unsigned char* pixel = (unsigned char*)(row + x * pixel_size);
if (de::abs((int)pixel[0] - clear_color_int[0]) > EPSILON ||
de::abs((int)pixel[1] - clear_color_int[1]) > EPSILON ||
de::abs((int)pixel[2] - clear_color_int[2]) > EPSILON ||
de::abs((int)pixel[3] - clear_color_int[3]) > EPSILON)
{
/* Test fails at this point */
m_testCtx.getLog()
<< tcu::TestLog::Message << "(x=" << x << " y=" << y << ") Reference pixel ["
<< clear_color_int[0] << ", " << clear_color_int[1] << ", " << clear_color_int[2]
<< ", " << clear_color_int[3] << "] is different from the one retrieved ["
<< (int)pixel[0] << ", " << (int)pixel[1] << ", " << (int)pixel[2] << ", "
<< (int)pixel[3] << "]" << tcu::TestLog::EndMessage;
TCU_FAIL("Data comparison failure");
} /* if (pixel component has exceeded an allowed epsilon) */
#undef EPSILON
}
} /* for (all pixels) */
} /* for (all rows) */
} /* for (all layers) */
} /* for (all clear call types) */
/* Done */
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
return STOP;
#undef TEXTURE_DEPTH
#undef TEXTURE_HEIGHT
#undef TEXTURE_WIDTH
}
/** Deinitializes GLES objects created during the test. */
void GeometryShaderLayeredFramebufferClear::deinit(void)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (m_fbo_char_id != 0)
{
gl.deleteFramebuffers(1, &m_fbo_char_id);
}
if (m_fbo_int_id != 0)
{
gl.deleteFramebuffers(1, &m_fbo_int_id);
}
if (m_fbo_uint_id != 0)
{
gl.deleteFramebuffers(1, &m_fbo_uint_id);
}
if (m_to_rgba32i_id != 0)
{
gl.deleteTextures(1, &m_to_rgba32i_id);
}
if (m_to_rgba32ui_id != 0)
{
gl.deleteTextures(1, &m_to_rgba32ui_id);
}
if (m_to_rgba8_id != 0)
{
gl.deleteTextures(1, &m_to_rgba8_id);
}
if (m_read_fbo_id != 0)
{
gl.deleteFramebuffers(1, &m_read_fbo_id);
}
/* Release base class */
TestCaseBase::deinit();
}
/** Constructor
*
* @param context Test context
* @param name Test case's name
* @param description Test case's desricption
**/
GeometryShaderLayeredFramebufferDepth::GeometryShaderLayeredFramebufferDepth(Context& context,
const ExtParameters& extParams,
const char* name, const char* description)
: TestCaseBase(context, extParams, name, description)
, m_fbo_id(0)
, m_fs_id(0)
, m_gs_id(0)
, m_po_id(0)
, m_read_fbo_id(0)
, m_to_a_id(0)
, m_to_b_id(0)
, m_vao_id(0)
, m_vs_id(0)
{
/* Left blank on purpose */
}
/** Deinitializes GLES objects created during the test. */
void GeometryShaderLayeredFramebufferDepth::deinit(void)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Clean up */
if (m_fbo_id != 0)
{
gl.deleteFramebuffers(1, &m_fbo_id);
}
if (m_fs_id != 0)
{
gl.deleteShader(m_fs_id);
}
if (m_gs_id != 0)
{
gl.deleteShader(m_gs_id);
}
if (m_po_id != 0)
{
gl.deleteProgram(m_po_id);
}
if (m_read_fbo_id != 0)
{
gl.deleteFramebuffers(1, &m_read_fbo_id);
}
if (m_to_a_id != 0)
{
gl.deleteTextures(1, &m_to_a_id);
}
if (m_to_b_id != 0)
{
gl.deleteTextures(1, &m_to_b_id);
}
if (m_vao_id != 0)
{
gl.deleteVertexArrays(1, &m_vao_id);
}
if (m_vs_id != 0)
{
gl.deleteShader(m_vs_id);
}
/* Release base class */
TestCaseBase::deinit();
}
/** Executes the test.
* Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
* @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
* Note the function throws exception should an error occur!
**/
tcu::TestNode::IterateResult GeometryShaderLayeredFramebufferDepth::iterate(void)
{
/* General variables */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
unsigned int n = 0;
unsigned int x = 0;
unsigned int y = 0;
/* Test-wide definitions */
#define N_TEXTURE_COMPONENTS (4)
#define TEXTURE_DEPTH (4)
#define TEXTURE_HEIGHT (4)
#define TEXTURE_WIDTH (4)
/* Fragment shader code */
const char* fs_code = "${VERSION}\n"
"\n"
"precision highp float;\n"
"\n"
"out vec4 result;\n"
"\n"
"void main()\n"
"{\n"
" result = vec4(1.0);\n"
"}\n";
const char* gs_code = "${VERSION}\n"
"${GEOMETRY_SHADER_REQUIRE}\n"
"\n"
"layout(points) in;\n"
"layout(triangle_strip, max_vertices=64) out;\n"
"\n"
"void main()\n"
"{\n"
" for (int n = 0; n < 4; ++n)\n"
" {\n"
" float depth = -1.0 + float(n) * 0.5;\n"
"\n"
" gl_Layer = n;\n"
" gl_Position = vec4(1, 1, depth, 1);\n"
" EmitVertex();\n"
"\n"
" gl_Layer = n;\n"
" gl_Position = vec4(1, -1, depth, 1);\n"
" EmitVertex();\n"
"\n"
" gl_Layer = n;\n"
" gl_Position = vec4(-1, 1, depth, 1);\n"
" EmitVertex();\n"
"\n"
" gl_Layer = n;\n"
" gl_Position = vec4(-1, -1, depth, 1);\n"
" EmitVertex();\n"
"\n"
" EndPrimitive();\n"
" }\n"
"}\n";
/* This test should only run if EXT_geometry_shader is supported */
if (!m_is_geometry_shader_extension_supported)
{
throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
}
/* Set up texture objects we will be using for the test */
gl.genTextures(1, &m_to_a_id);
gl.genTextures(1, &m_to_b_id);
gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_to_a_id);
gl.texStorage3D(GL_TEXTURE_2D_ARRAY, 1 /* levels */, GL_RGBA8, TEXTURE_WIDTH, TEXTURE_HEIGHT, TEXTURE_DEPTH);
gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_to_b_id);
gl.texStorage3D(GL_TEXTURE_2D_ARRAY, 1 /* levels */, GL_DEPTH_COMPONENT32F, TEXTURE_WIDTH, TEXTURE_HEIGHT,
TEXTURE_DEPTH);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not initialize texture objects");
/* Set up framebuffer object we will use for the test */
gl.genFramebuffers(1, &m_fbo_id);
gl.genFramebuffers(1, &m_read_fbo_id);
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_id);
gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_to_a_id, 0 /* level */);
gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_to_b_id, 0 /* level */);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not initialize framebuffer object");
if (gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "Draw framebuffer is incomplete: " << gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER)
<< tcu::TestLog::EndMessage;
TCU_FAIL("Draw framebuffer is incomplete.");
}
/* Set up shader objects */
m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
m_gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
m_vs_id = gl.createShader(GL_VERTEX_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not initialize shader objects");
/* Set up program object */
m_po_id = gl.createProgram();
if (!buildProgram(m_po_id, m_fs_id, 1 /* part */, &fs_code, m_gs_id, 1 /* part */, &gs_code, m_vs_id, 1 /* part */,
&m_boilerplate_vs_code))
{
TCU_FAIL("Could not build program object");
}
/* Set up vertex array object */
gl.genVertexArrays(1, &m_vao_id);
gl.bindVertexArray(m_vao_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind vertex array object");
/* Clear the depth attachment before we continue */
gl.clearColor(0.0f /* red */, 0.0f /* green */, 0.0f /* blue */, 0.0f /* alpha */);
gl.clearDepthf(0.5f);
gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "Depth buffer clear operation failed");
/* Render */
gl.useProgram(m_po_id);
gl.viewport(0 /* x */, 0 /* y */, TEXTURE_WIDTH, TEXTURE_HEIGHT);
gl.enable(GL_DEPTH_TEST);
gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed");
/* Verify the output */
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_read_fbo_id);
for (n = 0; n < TEXTURE_DEPTH; ++n)
{
unsigned char buffer[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS];
unsigned char ref_color[4];
/* Determine reference color */
if (n < 2)
{
memset(ref_color, 0xFF, sizeof(ref_color));
}
else
{
memset(ref_color, 0, sizeof(ref_color));
}
/* Read the rendered layer data */
gl.framebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_to_a_id, 0 /* level */, n);
gl.readPixels(0 /* x */, 0 /* y */, TEXTURE_WIDTH, TEXTURE_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed");
/* Compare all pixels against the reference value */
for (y = 0; y < TEXTURE_HEIGHT; ++y)
{
const unsigned int pixel_size = N_TEXTURE_COMPONENTS;
const unsigned int row_width = TEXTURE_WIDTH * pixel_size;
const unsigned char* row_data = buffer + y * row_width;
for (x = 0; x < TEXTURE_WIDTH; ++x)
{
const unsigned char* result = row_data + x * pixel_size;
if (memcmp(result, ref_color, sizeof(ref_color)) != 0)
{
m_testCtx.getLog() << tcu::TestLog::Message << "(x=" << x << " y=" << y << ") "
<< "Reference value is different than the rendered data: "
<< "(" << (unsigned int)ref_color[0] << ", " << (unsigned int)ref_color[1]
<< ", " << (unsigned int)ref_color[2] << ", " << (unsigned int)ref_color[3]
<< ") vs "
<< "(" << (unsigned int)result[0] << ", " << (unsigned int)result[1] << ", "
<< (unsigned int)result[2] << ", " << (unsigned int)result[3] << ")."
<< tcu::TestLog::EndMessage;
TCU_FAIL("Rendered data mismatch");
} /* if (memcmp(row_data + x * pixel_size, ref_color, sizeof(ref_color) ) != 0)*/
} /* for (all pixels in a row) */
} /* for (all rows) */
} /* for (all layers) */
/* Done */
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
return STOP;
#undef N_TEXTURE_COMPONENTS
#undef TEXTURE_DEPTH
#undef TEXTURE_HEIGHT
#undef TEXTURE_WIDTH
}
/** Constructor
*
* @param context Test context
* @param name Test case's name
* @param description Test case's desricption
**/
GeometryShaderLayeredFramebufferStencil::GeometryShaderLayeredFramebufferStencil(Context& context,
const ExtParameters& extParams,
const char* name,
const char* description)
: TestCaseBase(context, extParams, name, description)
, m_fbo_id(0)
, m_fs_id(0)
, m_gs_id(0)
, m_po_id(0)
, m_to_a_id(0)
, m_to_b_id(0)
, m_vao_id(0)
, m_vs_id(0)
{
/* Left blank on purpose */
}
/** Deinitializes GLES objects created during the test. */
void GeometryShaderLayeredFramebufferStencil::deinit(void)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Clean up */
if (m_fbo_id != 0)
{
gl.deleteFramebuffers(1, &m_fbo_id);
}
if (m_fs_id != 0)
{
gl.deleteShader(m_fs_id);
}
if (m_gs_id != 0)
{
gl.deleteShader(m_gs_id);
}
if (m_po_id != 0)
{
gl.deleteProgram(m_po_id);
}
if (m_to_a_id != 0)
{
gl.deleteTextures(1, &m_to_a_id);
}
if (m_to_b_id != 0)
{
gl.deleteTextures(1, &m_to_b_id);
}
if (m_vao_id != 0)
{
gl.deleteVertexArrays(1, &m_vao_id);
}
if (m_vs_id != 0)
{
gl.deleteShader(m_vs_id);
}
/* Release base class */
TestCaseBase::deinit();
}
/** Executes the test.
* Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
* @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
* Note the function throws exception should an error occur!
**/
tcu::TestNode::IterateResult GeometryShaderLayeredFramebufferStencil::iterate(void)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Test-wide definitions */
#define N_TEXTURE_COMPONENTS (4)
#define TEXTURE_DEPTH (4)
#define TEXTURE_HEIGHT (4)
#define TEXTURE_WIDTH (8)
/* Fragment shader code */
const char* fs_code = "${VERSION}\n"
"\n"
"precision highp float;\n"
"\n"
"out vec4 result;\n"
"\n"
"void main()\n"
"{\n"
" result = vec4(1, 1, 1, 1);\n"
"}\n";
/* Geometry shader code */
const char* gs_code = "${VERSION}\n"
"${GEOMETRY_SHADER_REQUIRE}\n"
"\n"
"precision highp float;\n"
"\n"
"layout (points) in;\n"
"layout (triangle_strip, max_vertices = 16) out;\n"
"\n"
"void main()\n"
"{\n"
" for (int n = 0; n < 4; ++n)\n"
" {\n"
" gl_Position = vec4(1, -1, 0, 1);\n"
" gl_Layer = n;\n"
" EmitVertex();\n"
"\n"
" gl_Position = vec4(1, 1, 0, 1);\n"
" gl_Layer = n;\n"
" EmitVertex();\n"
"\n"
" gl_Position = vec4(-1, -1, 0, 1);\n"
" gl_Layer = n;\n"
" EmitVertex();\n"
"\n"
" gl_Position = vec4(-1, 1, 0, 1);\n"
" gl_Layer = n;\n"
" EmitVertex();\n"
"\n"
" EndPrimitive();\n"
" }\n"
"\n"
"}\n";
/* General variables */
int n = 0;
unsigned char slice_null_data[TEXTURE_DEPTH * TEXTURE_WIDTH * TEXTURE_HEIGHT * 1 /* byte per texel */] = { 0 };
unsigned char slice_1_data[TEXTURE_DEPTH * TEXTURE_WIDTH * TEXTURE_HEIGHT * 8 /* bytes per texel */] = { 0 };
unsigned char slice_2_data[TEXTURE_DEPTH * TEXTURE_WIDTH * TEXTURE_HEIGHT * 8 /* bytes per texel */] = { 0 };
unsigned char slice_3_data[TEXTURE_DEPTH * TEXTURE_WIDTH * TEXTURE_HEIGHT * 8 /* bytes per texel */] = { 0 };
unsigned char slice_4_data[TEXTURE_DEPTH * TEXTURE_WIDTH * TEXTURE_HEIGHT * 8 /* bytes per texel */] = { 0 };
/* This test should only run if EXT_geometry_shader is supported */
if (!m_is_geometry_shader_extension_supported)
{
throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
}
/* Create shader & program objects */
m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
m_gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
m_po_id = gl.createProgram();
m_vs_id = gl.createShader(GL_VERTEX_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create shader or program objects");
/* Build test program object */
if (!buildProgram(m_po_id, m_fs_id, 1 /* parts */, &fs_code, m_gs_id, 1 /* parts */, &gs_code, m_vs_id,
1 /* parts */, &m_boilerplate_vs_code))
{
TCU_FAIL("Could not build test program object");
}
/* Generate and bind a vertex array object */
gl.genVertexArrays(1, &m_vao_id);
gl.bindVertexArray(m_vao_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create & bind a vertex array object.");
/* Configure slice data */
for (n = 0; n < TEXTURE_DEPTH * TEXTURE_WIDTH * TEXTURE_HEIGHT * 8 /* bytes per texel */; ++n)
{
/* We are okay with depth data being filled with glitch, but need the stencil data to be
* as per test spec. To keep code simple, we do not differentiate between floating-point and
* stencil part.
*/
slice_1_data[n] = 2;
slice_2_data[n] = 1;
/* Slices 3 and 4 should be filled with 0s */
slice_3_data[n] = 0;
slice_4_data[n] = 0;
} /* for (all pixels making up slices) */
/* Set up texture objects */
gl.genTextures(1, &m_to_a_id);
gl.genTextures(1, &m_to_b_id);
gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_to_a_id);
gl.texImage3D(GL_TEXTURE_2D_ARRAY, 0 /* level */, GL_RGBA8, TEXTURE_WIDTH, TEXTURE_HEIGHT, TEXTURE_DEPTH,
0 /* border */, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 0 /* zoffset */,
TEXTURE_WIDTH, TEXTURE_HEIGHT, 1 /* depth */, GL_RGBA, GL_UNSIGNED_BYTE, slice_null_data);
gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 1 /* zoffset */,
TEXTURE_WIDTH, TEXTURE_HEIGHT, 1 /* depth */, GL_RGBA, GL_UNSIGNED_BYTE, slice_null_data);
gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 2 /* zoffset */,
TEXTURE_WIDTH, TEXTURE_HEIGHT, 1 /* depth */, GL_RGBA, GL_UNSIGNED_BYTE, slice_null_data);
gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 3 /* zoffset */,
TEXTURE_WIDTH, TEXTURE_HEIGHT, 1 /* depth */, GL_RGBA, GL_UNSIGNED_BYTE, slice_null_data);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up texture object A.");
gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_to_b_id);
gl.texImage3D(GL_TEXTURE_2D_ARRAY, 0 /* level */, GL_DEPTH32F_STENCIL8, TEXTURE_WIDTH, TEXTURE_HEIGHT,
TEXTURE_DEPTH, 0 /* border */, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, NULL);
gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 0 /* zoffset */,
TEXTURE_WIDTH, TEXTURE_HEIGHT, 1 /* depth */, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV,
slice_1_data);
gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 1 /* zoffset */,
TEXTURE_WIDTH, TEXTURE_HEIGHT, 1 /* depth */, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV,
slice_2_data);
gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 2 /* zoffset */,
TEXTURE_WIDTH, TEXTURE_HEIGHT, 1 /* depth */, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV,
slice_3_data);
gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0 /* level */, 0 /* xoffset */, 0 /* yoffset */, 3 /* zoffset */,
TEXTURE_WIDTH, TEXTURE_HEIGHT, 1 /* depth */, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV,
slice_4_data);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up texture object B.");
/* Set up depth tests */
gl.disable(GL_DEPTH_TEST);
/* Set up stencil tests */
gl.enable(GL_STENCIL_TEST);
gl.stencilFunc(GL_LESS, 0, /* reference value */ 0xFFFFFFFF /* mask */);
/* Set up framebuffer objects */
gl.genFramebuffers(1, &m_fbo_id);
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_id);
gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_to_a_id, 0 /* level */);
gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, m_to_b_id, 0 /* level */);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up draw framebuffer.");
/* Issue the draw call. */
gl.useProgram(m_po_id);
gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
GLU_EXPECT_NO_ERROR(gl.getError(), "Draw call failed.");
/* Check the results */
for (n = 0; n < 4 /* layers */; ++n)
{
glw::GLenum fbo_completeness = GL_NONE;
int m = 0;
unsigned char ref_data[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS] = { 0 };
unsigned char result_data[TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS] = { 0 };
int x = 0;
int y = 0;
/* Configure the read framebuffer */
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_id);
gl.framebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_to_a_id, 0 /* level */, n);
gl.framebufferTexture(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0 /* texture */, 0 /* level */);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up read framebuffer.");
/* Verify read framebuffer is considered complete */
fbo_completeness = gl.checkFramebufferStatus(GL_READ_FRAMEBUFFER);
if (fbo_completeness != GL_FRAMEBUFFER_COMPLETE)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Read FBO is incomplete: "
<< "[" << fbo_completeness << "]" << tcu::TestLog::EndMessage;
TCU_FAIL("Read FBO is incomplete.");
}
/* Build reference data */
for (m = 0; m < TEXTURE_WIDTH * TEXTURE_HEIGHT * N_TEXTURE_COMPONENTS; ++m)
{
if (n < 2)
{
ref_data[m] = 255;
}
else
{
ref_data[m] = 0;
}
} /* for (all reference pixels) */
/* Read the rendered data */
gl.readPixels(0 /* x */, 0 /* y */, TEXTURE_WIDTH, TEXTURE_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, result_data);
GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() failed");
for (y = 0; y < TEXTURE_HEIGHT; ++y)
{
int pixel_size = N_TEXTURE_COMPONENTS;
int row_size = pixel_size * TEXTURE_WIDTH;
unsigned char* ref_row = ref_data + y * row_size;
unsigned char* result_row = result_data + y * row_size;
for (x = 0; x < TEXTURE_WIDTH; ++x)
{
if (memcmp(ref_row, result_row, pixel_size) != 0)
{
m_testCtx.getLog() << tcu::TestLog::Message << "(x=" << x << " y=" << y << "): Rendered data "
<< "(" << result_row[0] << ", " << result_row[1] << ", " << result_row[2] << ", "
<< result_row[3] << ")"
<< " is different from reference data "
<< "(" << ref_row[0] << ", " << ref_row[1] << ", " << ref_row[2] << ", "
<< ref_row[3] << ")" << tcu::TestLog::EndMessage;
TCU_FAIL("Data comparison failed");
} /* if (memcmp(ref_row, result_row, pixel_size) != 0) */
ref_row += pixel_size;
result_row += pixel_size;
} /* for (all pixels in a row) */
} /* for (all pixels) */
} /* for (all layers) */
/* Done */
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
return STOP;
#undef N_TEXTURE_COMPONENTS
#undef TEXTURE_DEPTH
#undef TEXTURE_HEIGHT
#undef TEXTURE_WIDTH
}
} // namespace glcts