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 "esextcGeometryShaderClipping.hpp"
25
26#include "gluDefs.hpp"
27#include "glwEnums.hpp"
28#include "glwFunctions.hpp"
29#include "tcuTestLog.hpp"
30#include <cstring>
31
32namespace glcts
33{
34/* Fragment shader code */
35const char* GeometryShaderClipping::m_fs_code = "${VERSION}\n"
36												"\n"
37												"precision highp float;\n"
38												"\n"
39												"out vec4 result;\n"
40												"\n"
41												"void main()\n"
42												"{\n"
43												"    result = vec4(0, 1, 0, 0);\n"
44												"}\n";
45
46/* Vertex shader code */
47const char* GeometryShaderClipping::m_vs_code = "${VERSION}\n"
48												"\n"
49												"precision highp float;\n"
50												"\n"
51												"void main()\n"
52												"{\n"
53												"    gl_Position = vec4(-10, -10, -10, 0);\n"
54												"}\n";
55
56/* Geometry shader code */
57const char* GeometryShaderClipping::m_gs_code = "${VERSION}\n"
58												"${GEOMETRY_SHADER_REQUIRE}\n"
59												"\n"
60												"precision highp float;\n"
61												"\n"
62												"layout(points)                                    in;\n"
63												"layout(triangle_strip, max_vertices=4) out;\n"
64												"\n"
65												"void main()\n"
66												"{\n"
67												"\n"
68												"    gl_Position = vec4(1, 1, 0, 1);\n"
69												"    EmitVertex();\n"
70												"\n"
71												"    gl_Position = vec4(1, -1, 0, 1);\n"
72												"    EmitVertex();\n"
73												"\n"
74												"    gl_Position = vec4(-1, 1, 0, 1);\n"
75												"    EmitVertex();\n"
76												"\n"
77												"    gl_Position = vec4(-1, -1, 0, 1);\n"
78												"    EmitVertex();\n"
79												"\n"
80												"    EndPrimitive();\n"
81												"}\n";
82
83/** Constructor
84 *
85 * @param context       Test context
86 * @param name          Test case's name
87 * @param description   Test case's desricption
88 **/
89GeometryShaderClipping::GeometryShaderClipping(Context& context, const ExtParameters& extParams, const char* name,
90											   const char* description)
91	: TestCaseBase(context, extParams, name, description)
92	, m_fbo_id(0)
93	, m_fs_id(0)
94	, m_gs_id(0)
95	, m_po_id(0)
96	, m_to_id(0)
97	, m_vao_id(0)
98	, m_vs_id(0)
99{
100}
101
102/** Deinitializes GLES objects created during the test.
103 *
104 */
105void GeometryShaderClipping::deinit(void)
106{
107	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
108
109	/* Reset OpenGL ES state */
110	gl.useProgram(0);
111	gl.bindTexture(GL_TEXTURE_2D, 0);
112	gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
113	gl.bindVertexArray(0);
114
115	if (m_po_id != 0)
116	{
117		gl.deleteProgram(m_po_id);
118	}
119
120	if (m_fs_id != 0)
121	{
122		gl.deleteShader(m_fs_id);
123	}
124
125	if (m_gs_id != 0)
126	{
127		gl.deleteShader(m_gs_id);
128	}
129
130	if (m_vs_id != 0)
131	{
132		gl.deleteShader(m_vs_id);
133	}
134
135	if (m_to_id != 0)
136	{
137		gl.deleteTextures(1, &m_to_id);
138	}
139
140	if (m_fbo_id != 0)
141	{
142		gl.deleteFramebuffers(1, &m_fbo_id);
143	}
144
145	if (m_vao_id != 0)
146	{
147		gl.deleteVertexArrays(1, &m_vao_id);
148	}
149
150	/* Release base class */
151	TestCaseBase::deinit();
152}
153
154/** Executes the test.
155 *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
156 *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
157 *  Note the function throws exception should an error occur!
158 **/
159tcu::TestNode::IterateResult GeometryShaderClipping::iterate(void)
160{
161	unsigned char buffer[m_texture_width * m_texture_height * m_texture_n_components];
162
163	const glw::Functions& gl				= m_context.getRenderContext().getFunctions();
164	const unsigned char   reference_color[] = { 0, 255, 0, 0 };
165	const unsigned int	row_size			= m_texture_width * m_texture_n_components;
166
167	if (!m_is_geometry_shader_extension_supported)
168	{
169		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
170	}
171
172	/* Create shader objects we'll need */
173	m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
174	m_gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
175	m_vs_id = gl.createShader(GL_VERTEX_SHADER);
176	m_po_id = gl.createProgram();
177
178	if (!buildProgram(m_po_id, m_fs_id, 1 /* part */, &m_fs_code, m_gs_id, 1 /* part */, &m_gs_code, m_vs_id,
179					  1 /* part */, &m_vs_code))
180	{
181		TCU_FAIL("Could not create program object from valid vertex/geometry/fragment shaders!");
182	}
183
184	/* Create and configure texture object we'll be rendering to */
185	gl.genTextures(1, &m_to_id);
186	gl.bindTexture(GL_TEXTURE_2D, m_to_id);
187	gl.texStorage2D(GL_TEXTURE_2D, m_texture_n_levels, GL_RGBA8, m_texture_width, m_texture_height);
188
189	GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating texture object!");
190
191	/* Create and configure the framebuffer object */
192	gl.genFramebuffers(1, &m_fbo_id);
193	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_id);
194	gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0 /* level */);
195
196	GLU_EXPECT_NO_ERROR(gl.getError(), "Error configuring framebuffer object!");
197
198	/* Create and bind vertex array object */
199	gl.genVertexArrays(1, &m_vao_id);
200	gl.bindVertexArray(m_vao_id);
201
202	GLU_EXPECT_NO_ERROR(gl.getError(), "Error configuring vertex array object");
203
204	/* Render */
205	gl.viewport(0 /* x */, 0 /* y */, m_texture_width /* width */, m_texture_height /* height */);
206	gl.useProgram(m_po_id);
207
208	gl.clearColor(1.0f, 0.0f, 0.0f, 0.0f);
209	gl.clear(GL_COLOR_BUFFER_BIT);
210
211	gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
212
213	GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed!");
214
215	/* Read the rendered data */
216	gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_id);
217	gl.readPixels(0 /* x */, 0 /* y */, m_texture_height /* width */, m_texture_width /* height */, GL_RGBA,
218				  GL_UNSIGNED_BYTE, buffer);
219
220	GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels failed!");
221
222	/* Loop over all pixels and compare the rendered data with reference value */
223	for (int y = 0; y < m_texture_height; ++y)
224	{
225		unsigned char* data_row = buffer + y * row_size;
226
227		for (int x = 0; x < m_texture_width; ++x)
228		{
229			unsigned char* data = data_row + x * m_texture_n_components;
230
231			if (memcmp(data, reference_color, sizeof(reference_color)) != 0)
232			{
233				m_testCtx.getLog() << tcu::TestLog::Message << "Rendered data [" << data[0] << ", " << data[1] << ", "
234								   << data[2] << ", " << data[3] << "] is different from reference data ["
235								   << reference_color[0] << ", " << reference_color[1] << ", " << reference_color[2]
236								   << ", " << reference_color[3] << "] !" << tcu::TestLog::EndMessage;
237
238				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
239
240				return STOP;
241			} /* if (memcmp(data, reference_color, sizeof(reference_color)) != 0) */
242		}	 /* for (all columns) */
243	}		  /* for (all rows) */
244
245	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
246	return STOP;
247}
248
249} // namespace glcts
250