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 "esextcGeometryShaderNonarrayInput.hpp"
25
26#include "gluContextInfo.hpp"
27#include "gluDefs.hpp"
28#include "glwEnums.hpp"
29#include "glwFunctions.hpp"
30#include "tcuTestLog.hpp"
31
32#include <algorithm>
33#include <string>
34#include <vector>
35
36namespace glcts
37{
38
39/* Fragment shader code */
40const char* GeometryShaderNonarrayInputCase::m_fs_code = "${VERSION}\n"
41														 "\n"
42														 "precision highp float;\n"
43														 "\n"
44														 "out vec4 color;\n"
45														 "\n"
46														 "void main()\n"
47														 "{\n"
48														 "    color = vec4(0, 1, 0, 1);\n"
49														 "}\n";
50
51/* Geometry shader body parts */
52const char* GeometryShaderNonarrayInputCase::m_gs_code_preamble = "${VERSION}\n"
53																  "${GEOMETRY_SHADER_REQUIRE}\n"
54																  "\n";
55
56const char* GeometryShaderNonarrayInputCase::m_gs_code_body = "layout(points)                         in;\n"
57															  "layout(triangle_strip, max_vertices=4) out;\n"
58															  "\n"
59															  "#ifndef USE_BLOCK\n"
60															  "    #define V1 v1[0]\n"
61															  "    #define V2 v2[0]\n"
62															  "    #define V3 v3[0]\n"
63															  "\n"
64															  "    in vec4 v1[];\n"
65															  "    in vec4 v2[];\n"
66															  "    in vec4 v3[];\n"
67															  "    \n"
68															  "    #ifdef CORRUPT\n"
69															  "        #define V4 v4\n"
70															  "        in vec4 v4;\n"
71															  "    #else\n"
72															  "        #define V4 v4[0]\n"
73															  "        in vec4 v4[];\n"
74															  "    #endif\n"
75															  "#else\n"
76															  "    in VS_GS\n"
77															  "    {\n"
78															  "        in vec4 v1;\n"
79															  "        in vec4 v2;\n"
80															  "        in vec4 v3;\n"
81															  "        in vec4 v4;\n"
82															  "    #ifdef CORRUPT\n"
83															  "        } interface_block;\n"
84															  "\n"
85															  "        #define V1 interface_block.v1\n"
86															  "        #define V2 interface_block.v2\n"
87															  "        #define V3 interface_block.v3\n"
88															  "        #define V4 interface_block.v4\n"
89															  "    #else\n"
90															  "        } interface_block[];\n"
91															  "\n"
92															  "        #define V1 interface_block[0].v1\n"
93															  "        #define V2 interface_block[0].v2\n"
94															  "        #define V3 interface_block[0].v3\n"
95															  "        #define V4 interface_block[0].v4\n"
96															  "    #endif\n"
97															  "#endif\n"
98															  "\n"
99															  "void main()\n"
100															  "{\n"
101															  "    gl_Position = V1;\n"
102															  "    EmitVertex();\n"
103															  "    gl_Position = V2;\n"
104															  "    EmitVertex();\n"
105															  "    gl_Position = V3;\n"
106															  "    EmitVertex();\n"
107															  "    gl_Position = V4;\n"
108															  "    EmitVertex();\n"
109															  "    EndPrimitive();\n"
110															  "}\n";
111
112/* Vertex shader body parts */
113const char* GeometryShaderNonarrayInputCase::m_vs_code_preamble = "${VERSION}\n"
114																  "\n";
115
116const char* GeometryShaderNonarrayInputCase::m_vs_code_body = "#ifndef USE_BLOCK\n"
117															  "    #define V1 v1\n"
118															  "    #define V2 v2\n"
119															  "    #define V3 v3\n"
120															  "    #define V4 v4\n"
121															  "\n"
122															  "    out vec4 v1;\n"
123															  "    out vec4 v2;\n"
124															  "    out vec4 v3;\n"
125															  "    out vec4 v4;\n"
126															  "#else\n"
127															  "    ${SHADER_IO_BLOCKS_ENABLE}\n"
128															  "    #define V1 interface_block.v1\n"
129															  "    #define V2 interface_block.v2\n"
130															  "    #define V3 interface_block.v3\n"
131															  "    #define V4 interface_block.v4\n"
132															  "\n"
133															  "    out VS_GS\n"
134															  "    {\n"
135															  "        vec4 v1;\n"
136															  "        vec4 v2;\n"
137															  "        vec4 v3;\n"
138															  "        vec4 v4;\n"
139															  "    } interface_block;\n"
140															  "#endif\n"
141															  "\n"
142															  "void main()\n"
143															  "{\n"
144															  "    V1 = vec4(-1, -1, 0, 1);\n"
145															  "    V2 = vec4(-1,  1, 0, 1);\n"
146															  "    V3 = vec4( 1, -1, 0, 1);\n"
147															  "    V4 = vec4( 1,  1, 0, 1);\n"
148															  "}\n";
149
150/* Definitions */
151#define TEXTURE_HEIGHT (4)
152#define TEXTURE_WIDTH (4)
153
154/** Constructor
155 *
156 * @param context       Test context
157 * @param name          Test case's name
158 * @param description   Test case's desricption
159 **/
160GeometryShaderNonarrayInputCase::GeometryShaderNonarrayInputCase(Context& context, const ExtParameters& extParams,
161																 const char* name, const char* description)
162	: TestCaseBase(context, extParams, name, description)
163	, m_fbo_id(0)
164	, m_fs(0)
165	, m_gs_invalid_non_ib(0)
166	, m_gs_invalid_ib(0)
167	, m_gs_valid_non_ib(0)
168	, m_gs_valid_ib(0)
169	, m_po_a_invalid(0)
170	, m_po_b_invalid(0)
171	, m_po_a_valid(0)
172	, m_po_b_valid(0)
173	, m_to_id(0)
174	, m_vao_id(0)
175	, m_vs_valid_ib(0)
176	, m_vs_valid_non_ib(0)
177{
178}
179
180/** Executes the test.
181 *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
182 *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
183 *  Note the function throws exception should an error occur!
184 **/
185tcu::TestNode::IterateResult GeometryShaderNonarrayInputCase::iterate(void)
186{
187	glw::GLint			  compile_status = GL_FALSE;
188	const glw::Functions& gl			 = m_context.getRenderContext().getFunctions();
189	glw::GLint			  link_status	= GL_FALSE;
190	unsigned int		  m				 = 0;
191	unsigned int		  n				 = 0;
192
193	/* Form the shaders */
194	const char* fs_parts[]				  = { m_fs_code };
195	const char* gs_invalid_non_ib_parts[] = { m_gs_code_preamble, "#define CORRUPT\n", m_gs_code_body };
196	const char* gs_invalid_ib_parts[] = { m_gs_code_preamble, "#define CORRUPT\n#define USE_BLOCK\n", m_gs_code_body };
197	const char* gs_valid_non_ib_parts[] = { m_gs_code_preamble, m_gs_code_body };
198	const char* gs_valid_ib_parts[]		= { m_gs_code_preamble, "#define USE_BLOCK\n", m_gs_code_body };
199	const char* vs_valid_non_ib_parts[] = { m_vs_code_preamble, m_vs_code_body };
200	const char* vs_valid_ib_parts[]		= { m_vs_code_preamble, "#define USE_BLOCK\n", m_vs_code_body };
201
202	/* This test should only run if EXT_geometry_shader is supported.
203	 * Note that EXT_shader_io_blocks support is implied. */
204	if (!m_is_geometry_shader_extension_supported)
205	{
206		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
207	}
208
209	/* Create program objects */
210	m_po_a_invalid = gl.createProgram();
211	m_po_b_invalid = gl.createProgram();
212
213	/* Create shader objects */
214	m_fs				= gl.createShader(GL_FRAGMENT_SHADER);
215	m_gs_invalid_non_ib = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
216	m_gs_invalid_ib		= gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
217	m_gs_valid_non_ib   = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
218	m_gs_valid_ib		= gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
219	m_vs_valid_non_ib   = gl.createShader(GL_VERTEX_SHADER);
220	m_vs_valid_ib		= gl.createShader(GL_VERTEX_SHADER);
221
222	shaderSourceSpecialized(m_fs, DE_LENGTH_OF_ARRAY(fs_parts), fs_parts);
223	shaderSourceSpecialized(m_gs_invalid_non_ib, DE_LENGTH_OF_ARRAY(gs_invalid_non_ib_parts), gs_invalid_non_ib_parts);
224	shaderSourceSpecialized(m_gs_invalid_ib, DE_LENGTH_OF_ARRAY(gs_invalid_ib_parts), gs_invalid_ib_parts);
225	shaderSourceSpecialized(m_gs_valid_non_ib, DE_LENGTH_OF_ARRAY(gs_valid_non_ib_parts), gs_valid_non_ib_parts);
226	shaderSourceSpecialized(m_gs_valid_ib, DE_LENGTH_OF_ARRAY(gs_valid_ib_parts), gs_valid_ib_parts);
227	shaderSourceSpecialized(m_vs_valid_non_ib, DE_LENGTH_OF_ARRAY(vs_valid_non_ib_parts), vs_valid_non_ib_parts);
228	shaderSourceSpecialized(m_vs_valid_ib, DE_LENGTH_OF_ARRAY(vs_valid_ib_parts), vs_valid_ib_parts);
229
230	/* Create and form invalid programs */
231	gl.attachShader(m_po_a_invalid, m_fs);
232	gl.attachShader(m_po_a_invalid, m_gs_invalid_non_ib);
233	gl.attachShader(m_po_a_invalid, m_vs_valid_non_ib);
234
235	gl.attachShader(m_po_b_invalid, m_fs);
236	gl.attachShader(m_po_b_invalid, m_gs_invalid_ib);
237	gl.attachShader(m_po_b_invalid, m_vs_valid_ib);
238
239	/* Try to compile the shaders. Do not check GL_COMPILE_STATUS - we expect a linking failure */
240	gl.compileShader(m_fs);
241	gl.compileShader(m_gs_invalid_non_ib);
242	gl.compileShader(m_gs_invalid_ib);
243	gl.compileShader(m_vs_valid_non_ib);
244	gl.compileShader(m_vs_valid_ib);
245
246	/* Try to link the programs */
247	gl.linkProgram(m_po_a_invalid);
248	gl.getProgramiv(m_po_a_invalid, GL_LINK_STATUS, &link_status);
249
250	if (link_status != GL_FALSE)
251	{
252		m_testCtx.getLog() << tcu::TestLog::Message
253						   << "Program linked sucessfully although it shouldn't because geometry shaders are not "
254							  "expected to support non-array input attributes."
255						   << tcu::TestLog::EndMessage;
256
257		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
258		return STOP;
259	}
260
261	gl.linkProgram(m_po_b_invalid);
262	gl.getProgramiv(m_po_b_invalid, GL_LINK_STATUS, &link_status);
263
264	if (link_status != GL_FALSE)
265	{
266		m_testCtx.getLog() << tcu::TestLog::Message
267						   << "Program linked sucessfully although it shouldn't because geometry shaders are not "
268							  "expected to support non-array block input attributes."
269						   << tcu::TestLog::EndMessage;
270
271		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
272		return STOP;
273	}
274
275	/* Release the programs before we continue */
276	gl.deleteProgram(m_po_a_invalid);
277	gl.deleteProgram(m_po_b_invalid);
278
279	m_po_a_invalid = 0;
280	m_po_b_invalid = 0;
281
282	/* Release the invalid geometry shaders */
283	gl.deleteShader(m_gs_invalid_non_ib);
284	gl.deleteShader(m_gs_invalid_ib);
285
286	m_gs_invalid_non_ib = 0;
287	m_gs_invalid_ib		= 0;
288
289	/* Create and form valid programs */
290	m_po_a_valid = gl.createProgram();
291	m_po_b_valid = gl.createProgram();
292
293	gl.attachShader(m_po_a_valid, m_fs);
294	gl.attachShader(m_po_a_valid, m_gs_valid_non_ib);
295	gl.attachShader(m_po_a_valid, m_vs_valid_non_ib);
296
297	gl.attachShader(m_po_b_valid, m_fs);
298	gl.attachShader(m_po_b_valid, m_gs_valid_ib);
299	gl.attachShader(m_po_b_valid, m_vs_valid_ib);
300
301	gl.compileShader(m_gs_valid_non_ib);
302	gl.compileShader(m_gs_valid_ib);
303
304	gl.getShaderiv(m_gs_valid_non_ib, GL_COMPILE_STATUS, &compile_status);
305
306	if (compile_status != GL_TRUE)
307	{
308		std::string log = getCompilationInfoLog(m_gs_valid_non_ib);
309
310		m_testCtx.getLog() << tcu::TestLog::Message << "Valid geometry shader didn't compile. Error message: " << log
311						   << tcu::TestLog::EndMessage;
312
313		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
314		return STOP;
315	}
316
317	gl.getShaderiv(m_gs_valid_ib, GL_COMPILE_STATUS, &compile_status);
318
319	if (compile_status != GL_TRUE)
320	{
321		std::string log = getCompilationInfoLog(m_gs_valid_ib);
322
323		m_testCtx.getLog() << tcu::TestLog::Message << "Valid geometry shader didn't compile. Error message: " << log
324						   << tcu::TestLog::EndMessage;
325
326		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
327		return STOP;
328	}
329
330	gl.linkProgram(m_po_a_valid);
331	gl.getProgramiv(m_po_a_valid, GL_LINK_STATUS, &link_status);
332
333	if (link_status != GL_TRUE)
334	{
335		std::string log = getLinkingInfoLog(m_po_a_valid);
336
337		m_testCtx.getLog() << tcu::TestLog::Message
338						   << "Program failed to link although it was expected to link successfully. Error message: "
339						   << log << tcu::TestLog::EndMessage;
340
341		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
342		return STOP;
343	}
344
345	gl.linkProgram(m_po_b_valid);
346	gl.getProgramiv(m_po_b_valid, GL_LINK_STATUS, &link_status);
347
348	if (link_status != GL_TRUE)
349	{
350		std::string log = getLinkingInfoLog(m_po_b_valid);
351
352		m_testCtx.getLog() << tcu::TestLog::Message
353						   << "Program failed to link although it was expected to link successfully. Error message: "
354						   << log << tcu::TestLog::EndMessage;
355
356		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
357		return STOP;
358	}
359
360	/* Set up a FBO */
361	gl.genFramebuffers(1, &m_fbo_id);
362	gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
363
364	gl.genTextures(1, &m_to_id);
365	gl.bindTexture(GL_TEXTURE_2D, m_to_id);
366	gl.texStorage2D(GL_TEXTURE_2D, 1 /* levels */, GL_RGBA8, TEXTURE_WIDTH, TEXTURE_HEIGHT);
367	gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0 /* level */);
368
369	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set up a framebuffer object");
370
371	gl.viewport(0 /* x */, 0 /* y */, TEXTURE_WIDTH, TEXTURE_HEIGHT);
372
373	/* Generate and bind a VAO */
374	gl.genVertexArrays(1, &m_vao_id);
375	gl.bindVertexArray(m_vao_id);
376
377	/* Set up clear color */
378	gl.clearColor(1.0f, 0, 0, 0);
379
380	/* Use both program objects and verify they work correctly */
381	for (m = 0; m < 2 /* programs */; ++m)
382	{
383		glw::GLuint   program = (m == 0) ? m_po_a_valid : m_po_b_valid;
384		unsigned char result[TEXTURE_WIDTH * TEXTURE_HEIGHT * 4 /*components */];
385
386		/* Clear the color attachment before we continue */
387		gl.clear(GL_COLOR_BUFFER_BIT);
388
389		/* Render! */
390		gl.useProgram(program);
391		gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
392
393		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed");
394
395		/* Read back the result */
396		gl.readPixels(0 /* x */, 0 /* y */, TEXTURE_WIDTH, TEXTURE_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, result);
397
398		GLU_EXPECT_NO_ERROR(gl.getError(), "Could not read back pixels from color attachment 0");
399
400		/* Verify the result data is correct */
401		for (n = 0; n < TEXTURE_WIDTH * TEXTURE_HEIGHT; ++n)
402		{
403			if (result[n * 4 + 0] != 0 || result[n * 4 + 1] != 255 || result[n * 4 + 2] != 0 ||
404				result[n * 4 + 3] != 255)
405			{
406				m_testCtx.getLog() << tcu::TestLog::Message
407								   << "Pixel data isn't correct. All pixels should have green color. Pixel at: "
408								   << "[" << n / 4 << ", " << n % 4 << "] "
409								   << "has color: "
410								   << "[" << result[n * 4 + 0] << ", " << result[n * 4 + 1] << ", " << result[n * 4 + 2]
411								   << ", " << result[n * 4 + 3] << "]" << tcu::TestLog::EndMessage;
412
413				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
414				return STOP;
415			} /* if (result data is invalid) */
416		}	 /* for (all pixels) */
417	}		  /* for (all programs) */
418
419	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
420	return STOP;
421}
422
423/** Deinitializes GLES objects created during the test.
424 *
425 */
426void GeometryShaderNonarrayInputCase::deinit(void)
427{
428	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
429
430	/* Reset OpenGL ES state */
431	gl.useProgram(0);
432	gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
433	gl.bindVertexArray(0);
434
435	if (m_po_a_valid != 0)
436	{
437		gl.deleteProgram(m_po_a_valid);
438	}
439
440	if (m_po_b_valid != 0)
441	{
442		gl.deleteProgram(m_po_b_valid);
443	}
444
445	if (m_fs != 0)
446	{
447		gl.deleteShader(m_fs);
448	}
449
450	if (m_gs_invalid_ib != 0)
451	{
452		gl.deleteShader(m_gs_invalid_ib);
453	}
454
455	if (m_gs_invalid_non_ib != 0)
456	{
457		gl.deleteShader(m_gs_invalid_non_ib);
458	}
459
460	if (m_gs_valid_ib != 0)
461	{
462		gl.deleteShader(m_gs_valid_ib);
463	}
464
465	if (m_gs_valid_non_ib != 0)
466	{
467		gl.deleteShader(m_gs_valid_non_ib);
468	}
469
470	if (m_vs_valid_ib != 0)
471	{
472		gl.deleteShader(m_vs_valid_ib);
473	}
474
475	if (m_vs_valid_non_ib != 0)
476	{
477		gl.deleteShader(m_vs_valid_non_ib);
478	}
479
480	if (m_to_id != 0)
481	{
482		gl.deleteTextures(1, &m_to_id);
483	}
484
485	if (m_fbo_id != 0)
486	{
487		gl.deleteFramebuffers(1, &m_fbo_id);
488	}
489
490	if (m_vao_id != 0)
491	{
492		gl.deleteVertexArrays(1, &m_vao_id);
493	}
494
495	/* Release base class */
496	TestCaseBase::deinit();
497}
498
499} // namespace glcts
500