1/*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2014-2016 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 */ /*!
20 * \file
21 * \brief
22 */ /*-------------------------------------------------------------------*/
23
24#include "esextcGeometryShaderLayeredRenderingFBONoAttachment.hpp"
25
26#include "gluDefs.hpp"
27#include "tcuTestLog.hpp"
28
29namespace glcts
30{
31/* Fragment shader code */
32const char* GeometryShaderLayeredRenderingFBONoAttachment::m_fs_code =
33	"${VERSION}\n"
34	"\n"
35	"${GEOMETRY_SHADER_REQUIRE}\n"
36	"\n"
37	"precision highp float;\n"
38	"\n"
39	"layout(rgba32i, binding = 0) writeonly uniform highp iimage2DArray array_image;\n"
40	"\n"
41	"     in  vec2 uv;\n"
42	"flat in  int  layer_id;\n"
43	"out vec4 color;\n"
44	"\n"
45	"void main()\n"
46	"{\n"
47	"    imageStore(array_image, ivec3( int(128.0 * uv.x), int(128.0 * uv.y), layer_id ), ivec4(0, 255, 0, 0) );\n"
48	"}\n";
49
50/* Geometry shader code */
51const char* GeometryShaderLayeredRenderingFBONoAttachment::m_gs_code = "${VERSION}\n"
52																	   "\n"
53																	   "${GEOMETRY_SHADER_REQUIRE}\n"
54																	   "\n"
55																	   "precision highp float;\n"
56																	   "\n"
57																	   "layout(points)                          in;\n"
58																	   "layout(triangle_strip, max_vertices=16) out;\n"
59																	   "\n"
60																	   "     out vec2 uv;\n"
61																	   "flat out int  layer_id;\n"
62																	   "\n"
63																	   "void main()\n"
64																	   "{\n"
65																	   "    for (int n = 0; n < 4; ++n)\n"
66																	   "    {\n"
67																	   "        gl_Position = vec4(1, -1, 0, 1);\n"
68																	   "        gl_Layer    = n;\n"
69																	   "        layer_id    = n;\n"
70																	   "        uv          = vec2(1, 0);\n"
71																	   "        EmitVertex();\n"
72																	   "\n"
73																	   "        gl_Position = vec4(1,  1, 0, 1);\n"
74																	   "        gl_Layer    = n;\n"
75																	   "        layer_id    = n;\n"
76																	   "        uv          = vec2(1, 1);\n"
77																	   "        EmitVertex();\n"
78																	   "\n"
79																	   "        gl_Position = vec4(-1, -1, 0, 1);\n"
80																	   "        gl_Layer    = n;\n"
81																	   "        layer_id    = n;\n"
82																	   "        uv          = vec2(0, 0);\n"
83																	   "        EmitVertex();\n"
84																	   "\n"
85																	   "        gl_Position = vec4(-1,  1, 0, 1);\n"
86																	   "        gl_Layer    = n;\n"
87																	   "        layer_id    = n;\n"
88																	   "        uv          = vec2(0, 1);\n"
89																	   "        EmitVertex();\n"
90																	   "\n"
91																	   "        EndPrimitive();\n"
92																	   "    }\n"
93																	   "}\n";
94
95/* Vertex shader code */
96const char* GeometryShaderLayeredRenderingFBONoAttachment::m_vs_code = "${VERSION}\n"
97																	   "\n"
98																	   "${GEOMETRY_SHADER_REQUIRE}\n"
99																	   "\n"
100																	   "precision highp float;\n"
101																	   "\n"
102																	   "void main()\n"
103																	   "{\n"
104																	   "}\n";
105
106/* Constants */
107const glw::GLint GeometryShaderLayeredRenderingFBONoAttachment::m_height			   = 128;
108const glw::GLint GeometryShaderLayeredRenderingFBONoAttachment::m_width				   = 128;
109const int		 GeometryShaderLayeredRenderingFBONoAttachment::m_n_layers			   = 4;
110const glw::GLint GeometryShaderLayeredRenderingFBONoAttachment::m_n_texture_components = 4;
111
112/** Constructor
113 *
114 * @param context       Test context
115 * @param name          Test case's name
116 * @param description   Test case's description
117 **/
118GeometryShaderLayeredRenderingFBONoAttachment::GeometryShaderLayeredRenderingFBONoAttachment(
119	Context& context, const ExtParameters& extParams, const char* name, const char* description)
120	: TestCaseBase(context, extParams, name, description)
121	, m_fbo_id(0)
122	, m_fs_id(0)
123	, m_gs_id(0)
124	, m_po_id(0)
125	, m_to_id(0)
126	, m_vao_id(0)
127	, m_vs_id(0)
128	, m_all_layers_data(DE_NULL)
129	, m_layer_data(DE_NULL)
130{
131	/* Nothing to be done here */
132}
133
134/** Deinitializes GLES objects created during the test.
135 *
136 */
137void GeometryShaderLayeredRenderingFBONoAttachment::deinit(void)
138{
139	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
140
141	/* Reset OpenGL ES state */
142	gl.useProgram(0);
143	gl.bindTexture(GL_TEXTURE_2D_ARRAY, 0 /* texture */);
144	gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
145	gl.bindVertexArray(0);
146
147	if (m_po_id != 0)
148	{
149		gl.deleteProgram(m_po_id);
150		m_po_id = 0;
151	}
152
153	if (m_fs_id != 0)
154	{
155		gl.deleteShader(m_fs_id);
156		m_fs_id = 0;
157	}
158
159	if (m_gs_id != 0)
160	{
161		gl.deleteShader(m_gs_id);
162		m_gs_id = 0;
163	}
164
165	if (m_vs_id != 0)
166	{
167		gl.deleteShader(m_vs_id);
168		m_vs_id = 0;
169	}
170
171	if (m_to_id != 0)
172	{
173		gl.deleteTextures(1, &m_to_id);
174		m_to_id = 0;
175	}
176
177	if (m_fbo_id != 0)
178	{
179		gl.deleteFramebuffers(1, &m_fbo_id);
180		m_fbo_id = 0;
181	}
182
183	if (m_vao_id != 0)
184	{
185		gl.deleteVertexArrays(1, &m_vao_id);
186		m_vao_id = 0;
187	}
188
189	if (m_all_layers_data != DE_NULL)
190	{
191		delete[] m_all_layers_data;
192		m_all_layers_data = DE_NULL;
193	}
194
195	if (m_layer_data != DE_NULL)
196	{
197		delete[] m_layer_data;
198		m_layer_data = DE_NULL;
199	}
200
201	/* Release base class */
202	TestCaseBase::deinit();
203}
204
205/** Executes the test.
206 *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
207 *
208 *  Note the function throws exception should an error occur!
209 *
210 *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
211 *
212 **/
213tcu::TestNode::IterateResult GeometryShaderLayeredRenderingFBONoAttachment::iterate(void)
214{
215	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
216
217	/* Check if required extensions are supported */
218	if (!m_is_geometry_shader_extension_supported)
219	{
220		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
221	}
222
223	if (!m_is_framebuffer_no_attachments_supported)
224	{
225		throw tcu::NotSupportedError("framebuffer_no_attachment, is not supported", "", __FILE__, __LINE__);
226	}
227
228	if (!m_is_shader_image_load_store_supported)
229	{
230		throw tcu::NotSupportedError("shader_image_load_store, is not supported", "", __FILE__, __LINE__);
231	}
232
233	/* Generate and bind a framebuffer object */
234	gl.genFramebuffers(1, &m_fbo_id);
235	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_id);
236
237	/* Get the default number of layers of a newly created framebuffer object */
238	glw::GLint nLayers = -1;
239
240	gl.getFramebufferParameteriv(GL_DRAW_FRAMEBUFFER, m_glExtTokens.FRAMEBUFFER_DEFAULT_LAYERS, &nLayers);
241
242	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not query a framebuffer object for the number of default layers!");
243
244	/* check 14.2 test condition - if default number of layer equals 0 */
245	if (nLayers != 0)
246	{
247		m_testCtx.getLog() << tcu::TestLog::Message << "Number of default layers should be equal to 0 but is "
248						   << nLayers << tcu::TestLog::EndMessage;
249
250		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
251		return STOP;
252	}
253
254	/* Set the default resolution to 128x128 */
255	glw::GLint width  = 0;
256	glw::GLint height = 0;
257
258	gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH, m_width);
259	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set the default framebuffer's width!");
260	gl.getFramebufferParameteriv(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH, &width);
261	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not get the default framebuffer's width!");
262	gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT, m_height);
263	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set the default framebuffer's height!");
264	gl.getFramebufferParameteriv(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT, &height);
265	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not get the default framebuffer's height!");
266
267	if (m_width != width || m_height != height)
268	{
269		m_testCtx.getLog() << tcu::TestLog::Message << "Framebuffer's default width/height is not equal to" << m_width
270						   << "\\" << m_height << " but is " << width << "\\" << height << tcu::TestLog::EndMessage;
271
272		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
273		return STOP;
274	}
275
276	/* Configure program object to be used for functional part of the test */
277	m_po_id = gl.createProgram();
278
279	m_vs_id = gl.createShader(GL_VERTEX_SHADER);
280	m_gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
281	m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
282
283	if (!buildProgram(m_po_id, m_fs_id, 1 /* part */, &m_fs_code, m_gs_id, 1 /* part */, &m_gs_code, m_vs_id,
284					  1 /* part */, &m_vs_code))
285	{
286		TCU_FAIL("Could not create program object from a valid vertex/geometry/fragment shader code!");
287	}
288
289	/* Configure texture objects and fill them with initial data */
290	m_all_layers_data = new glw::GLint[m_n_layers * m_width * m_height * m_n_texture_components];
291
292	for (int n = 0; n < m_n_layers * m_width * m_height; ++n)
293	{
294		m_all_layers_data[n * m_n_texture_components + 0] = 255;
295		m_all_layers_data[n * m_n_texture_components + 1] = 0;
296		m_all_layers_data[n * m_n_texture_components + 2] = 0;
297		m_all_layers_data[n * m_n_texture_components + 3] = 0;
298	}
299
300	gl.genTextures(1, &m_to_id);
301	gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_to_id);
302	gl.texStorage3D(GL_TEXTURE_2D_ARRAY, 1 /* levels */, GL_RGBA32I, m_width, m_height, m_n_layers);
303	gl.texParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
304	gl.texParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
305
306	GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating texture objects!");
307
308	/* Activate the test program object */
309	gl.useProgram(m_po_id);
310	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not use program!");
311
312	/* Bind texture to image unit */
313	gl.bindImageTexture(0, m_to_id, 0 /* level */, GL_TRUE, 0 /* layer */, GL_WRITE_ONLY, GL_RGBA32I);
314	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind texture to image unit!");
315
316	/* Generate & bind a VAO */
317	gl.genVertexArrays(1, &m_vao_id);
318	gl.bindVertexArray(m_vao_id);
319
320	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create a vertex array object!");
321
322	/* Set up the viewport */
323	gl.viewport(0 /* x */, 0 /* y */, m_width /* width */, m_height /* height */);
324	GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed.");
325
326	/* Test 21.4 adjusts the behavior of the original tests. The test now needs to run
327	 * in two iterations:
328	 *
329	 * a) Original behavior is left intact
330	 * b) GL_FRAMEBUFFER_DEFAULT_LAYERS_EXT should be set to 0.
331	 */
332	glw::GLboolean test_failed = false;
333
334	m_layer_data = new glw::GLint[m_width * m_height * m_n_texture_components];
335
336	for (unsigned int n_test_iteration = 0; n_test_iteration < 2 && !test_failed; ++n_test_iteration)
337	{
338		const glw::GLint current_n_layers = (n_test_iteration == 1) ? 0 : m_n_layers;
339
340		/* Reset render-target contents */
341		gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0, /* level   */
342						 0,						 /* xoffset */
343						 0,						 /* yoffset */
344						 0,						 /* zoffset */
345						 m_width, m_height, m_n_layers, GL_RGBA_INTEGER, GL_INT, m_all_layers_data);
346		GLU_EXPECT_NO_ERROR(gl.getError(), "glTexSubImage3D() call failed.");
347
348		/* Set the default number of layers to m_n_layers */
349		gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, m_glExtTokens.FRAMEBUFFER_DEFAULT_LAYERS, current_n_layers);
350
351		GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set the default number of layers of a framebuffer object!");
352
353		gl.getFramebufferParameteriv(GL_DRAW_FRAMEBUFFER, m_glExtTokens.FRAMEBUFFER_DEFAULT_LAYERS, &nLayers);
354
355		/* check if the reported value equals m_n_layers */
356		if (current_n_layers != nLayers)
357		{
358			m_testCtx.getLog() << tcu::TestLog::Message << "FBO's default layers should be equal to " << m_n_layers
359							   << "but is " << nLayers << tcu::TestLog::EndMessage;
360
361			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
362			return STOP;
363		}
364
365		/* Render! */
366		gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
367
368		GLU_EXPECT_NO_ERROR(gl.getError(), "Could not execute a draw call!");
369
370		/* Verify result texture data */
371		gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_id);
372
373		for (int n_layer = 0; n_layer < m_n_layers && !test_failed; ++n_layer)
374		{
375			gl.framebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_to_id, 0 /* level */, n_layer);
376
377			GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind texture as color attachment to framebuffer!");
378
379			if (gl.checkFramebufferStatus(GL_READ_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
380			{
381				TCU_FAIL("Read framebuffer is not complete!");
382			}
383
384			gl.memoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
385
386			gl.readPixels(0 /* x */, 0 /* y */, m_width, m_height, GL_RGBA_INTEGER, GL_INT, m_layer_data);
387
388			GLU_EXPECT_NO_ERROR(gl.getError(),
389								"Could not read back pixels from the texture bound to color attachment!");
390
391			/* Perform the verification */
392			const int referenceColor[4] = { 0, 255, 0, 0 };
393
394			for (int nPx = 0; nPx < m_width * m_height; ++nPx)
395			{
396				if (m_layer_data[nPx * m_n_texture_components + 0] != referenceColor[0] ||
397					m_layer_data[nPx * m_n_texture_components + 1] != referenceColor[1] ||
398					m_layer_data[nPx * m_n_texture_components + 2] != referenceColor[2] ||
399					m_layer_data[nPx * m_n_texture_components + 3] != referenceColor[3])
400				{
401					m_testCtx.getLog() << tcu::TestLog::Message << "The test failed: Pixel " << nPx << " from layer "
402									   << n_layer << " is set to [" << m_layer_data[nPx * m_n_texture_components + 0]
403									   << "," << m_layer_data[nPx * m_n_texture_components + 1] << ","
404									   << m_layer_data[nPx * m_n_texture_components + 2] << ","
405									   << m_layer_data[nPx * m_n_texture_components + 3] << "] but should be equal to ["
406									   << referenceColor[0] << "," << referenceColor[1] << "," << referenceColor[2]
407									   << "," << referenceColor[3] << ","
408									   << "]" << tcu::TestLog::EndMessage;
409
410					test_failed = true;
411					break;
412				} /* if (result pixel is invalid) */
413			}	 /* for (all pixels) */
414		}		  /* for (all layers) */
415
416		/* Restore the FBO to no-attachment state for the next iteration */
417		gl.framebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 0, 0, 0);
418
419	} /* for (both iterations) */
420
421	if (test_failed)
422		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
423	else
424		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
425
426	return STOP;
427}
428
429} // namespace glcts
430