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 * \file esextcGeometryShaderLimits.cpp
25 * \brief Geometry Shader Limits (Test Group 16)
26 */ /*-------------------------------------------------------------------*/
27
28#include "esextcGeometryShaderLimits.hpp"
29
30#include "gluContextInfo.hpp"
31#include "glwEnums.hpp"
32#include "glwFunctions.hpp"
33#include "tcuTestLog.hpp"
34
35#include <cstring>
36#include <sstream>
37#include <string>
38
39namespace glcts
40{
41/* Vertex Shader for GeometryShaderMaxUniformComponentsTest */
42const glw::GLchar* const GeometryShaderMaxUniformComponentsTest::m_vertex_shader_code =
43	"${VERSION}\n"
44	"\n"
45	"${GEOMETRY_SHADER_REQUIRE}\n"
46	"\n"
47	"void main()\n"
48	"{\n"
49	"    gl_Position = vec4(gl_VertexID, 0, 0, 1);\n"
50	"}\n";
51
52/* Geometry Shader parts for GeometryShaderMaxUniformComponentsTest */
53const glw::GLchar* const GeometryShaderMaxUniformComponentsTest::m_geometry_shader_code_preamble =
54	"${VERSION}\n"
55	"\n"
56	"${GEOMETRY_SHADER_REQUIRE}\n"
57	"\n"
58	"layout(points)                 in;\n"
59	"layout(points, max_vertices=1) out;\n"
60	"\n"
61	"// definition of NUMBER_OF_UNIFORMS goes here\n";
62
63const glw::GLchar* const GeometryShaderMaxUniformComponentsTest::m_geometry_shader_code_number_of_uniforms =
64	"#define NUMBER_OF_UNIFORMS ";
65
66const glw::GLchar* const GeometryShaderMaxUniformComponentsTest::m_geometry_shader_code_body =
67	"u\n"
68	"\n"
69	"uniform ivec4 uni_array[NUMBER_OF_UNIFORMS];\n"
70	"\n"
71	"flat out uint gs_out_sum;\n"
72	"\n"
73	"void main()\n"
74	"{\n"
75	"    gs_out_sum = 0u;\n"
76	"\n"
77	"    for (uint i = 0u; i < NUMBER_OF_UNIFORMS; ++i)\n"
78	"    {\n"
79	"        gs_out_sum += uint(uni_array[i].x);\n"
80	"        gs_out_sum += uint(uni_array[i].y);\n"
81	"        gs_out_sum += uint(uni_array[i].z);\n"
82	"        gs_out_sum += uint(uni_array[i].w);\n"
83	"    }\n"
84	"    EmitVertex();\n"
85	"    \n"
86	"    EndPrimitive();\n"
87	"}\n";
88
89/* Fragment Shader for GeometryShaderMaxUniformComponentsTest */
90const glw::GLchar* const GeometryShaderMaxUniformComponentsTest::m_fragment_shader_code =
91	"${VERSION}\n"
92	"${GEOMETRY_SHADER_REQUIRE}\n"
93	"precision mediump float;\n"
94	"out vec4 fs_out_color;\n"
95	"void main()\n"
96	"{\n"
97	"    fs_out_color = vec4(1, 1, 1, 1);\n"
98	"}\n";
99
100/** ***************************************************************************************************** **/
101/* Vertex Shader for GeometryShaderMaxUniformBlocksTest */
102const glw::GLchar* const GeometryShaderMaxUniformBlocksTest::m_vertex_shader_code =
103	"${VERSION}\n"
104	"\n"
105	"${GEOMETRY_SHADER_REQUIRE}\n"
106	"\n"
107	"void main()\n"
108	"{\n"
109	"    gl_Position = vec4(gl_VertexID, 0, 0, 1);\n"
110	"}\n";
111
112/* Geometry Shader Parts for GeometryShaderMaxUniformBlocksTest */
113const glw::GLchar* const GeometryShaderMaxUniformBlocksTest::m_geometry_shader_code_preamble =
114	"${VERSION}\n"
115	"\n"
116	"${GEOMETRY_SHADER_REQUIRE}\n"
117	"\n"
118	"layout(points)                 in;\n"
119	"layout(points, max_vertices=1) out;\n"
120	"\n"
121	"// definition of NUMBER_OF_UNIFORMS goes here\n";
122
123const glw::GLchar* const GeometryShaderMaxUniformBlocksTest::m_geometry_shader_code_number_of_uniforms =
124	"#define NUMBER_OF_UNIFORM_BLOCKS ";
125
126const glw::GLchar* const GeometryShaderMaxUniformBlocksTest::m_geometry_shader_code_body_str =
127	"u\n"
128	"\n"
129	"layout(binding = 0) uniform UniformBlock\n"
130	"{\n"
131	"    int entry;\n"
132	"} uni_block_array[NUMBER_OF_UNIFORM_BLOCKS];\n"
133	"\n"
134	"flat out int gs_out_sum;\n"
135	"\n"
136	"void main()\n"
137	"{\n"
138	"    gs_out_sum = 0;\n"
139	"\n";
140
141const glw::GLchar* const GeometryShaderMaxUniformBlocksTest::m_geometry_shader_code_body_end = "\n"
142																							   "    EmitVertex();\n"
143																							   "\n"
144																							   "    EndPrimitive();\n"
145																							   "}\n";
146
147/* Fragment Shader for GeometryShaderMaxUniformBlocksTest */
148const glw::GLchar* const GeometryShaderMaxUniformBlocksTest::m_fragment_shader_code =
149	"${VERSION}\n"
150	"${GEOMETRY_SHADER_REQUIRE}\n"
151	"precision mediump float;\n"
152	"out vec4 fs_out_color;\n"
153	"void main()\n"
154	"{\n"
155	"    fs_out_color = vec4(1, 1, 1, 1);\n"
156	"}\n";
157
158/** ****************************************************************************************** **/
159/* Vertex Shader for GeometryShaderMaxInputComponentsTest */
160const glw::GLchar* const GeometryShaderMaxInputComponentsTest::m_vertex_shader_code_preamble =
161	"${VERSION}\n"
162	"\n"
163	"${GEOMETRY_SHADER_REQUIRE}\n"
164	"\n"
165	"// definition of NUMBER_OF_GEOMETRY_INPUT_VECTORS\n";
166
167const glw::GLchar* const GeometryShaderMaxInputComponentsTest::m_vertex_shader_code_number_of_uniforms =
168	"#define NUMBER_OF_GEOMETRY_INPUT_VECTORS ";
169
170const glw::GLchar* const GeometryShaderMaxInputComponentsTest::m_vertex_shader_code_body =
171	"u\n"
172	"\n"
173	"out Vertex\n"
174	"{"
175	"   flat out ivec4 vs_gs_out[NUMBER_OF_GEOMETRY_INPUT_VECTORS];\n"
176	"};\n"
177	"\n"
178	"void main()\n"
179	"{\n"
180	"   int index = 1;\n"
181	"\n"
182	"   for (uint i = 0u; i < NUMBER_OF_GEOMETRY_INPUT_VECTORS; ++i)\n"
183	"   {\n"
184	"       vs_gs_out[i] = ivec4(index, index + 1, index + 2, index + 3);\n"
185	"       index       += 4;\n"
186	"   }\n"
187	"}\n";
188
189/* Geometry Shader Parts for GeometryShaderMaxInputComponentsTest */
190const glw::GLchar* const GeometryShaderMaxInputComponentsTest::m_geometry_shader_code_preamble =
191	"${VERSION}\n"
192	"\n"
193	"${GEOMETRY_SHADER_REQUIRE}\n"
194	"\n"
195	"layout(points)                 in;\n"
196	"layout(points, max_vertices=1) out;\n"
197	"\n"
198	"// definition of NUMBER_OF_GEOMETRY_INPUT_VECTORS goes here\n";
199
200const glw::GLchar* const GeometryShaderMaxInputComponentsTest::m_geometry_shader_code_number_of_uniforms =
201	"#define NUMBER_OF_GEOMETRY_INPUT_VECTORS ";
202
203const glw::GLchar* const GeometryShaderMaxInputComponentsTest::m_geometry_shader_code_body =
204	"u\n"
205	"\n"
206	"in Vertex\n"
207	"{\n"
208	"    flat in ivec4 vs_gs_out[NUMBER_OF_GEOMETRY_INPUT_VECTORS];\n"
209	"} vertex[1];\n"
210	"\n"
211	"flat out int gs_out_sum;\n"
212	"\n"
213	"void main()\n"
214	"{\n"
215	"    gs_out_sum = 0;\n"
216	"\n"
217	"    for (uint i = 0u; i < NUMBER_OF_GEOMETRY_INPUT_VECTORS; ++i)\n"
218	"    {\n"
219	"        gs_out_sum += vertex[0].vs_gs_out[i].x;\n"
220	"        gs_out_sum += vertex[0].vs_gs_out[i].y;\n"
221	"        gs_out_sum += vertex[0].vs_gs_out[i].z;\n"
222	"        gs_out_sum += vertex[0].vs_gs_out[i].w;\n"
223	"    }\n"
224	"    EmitVertex();\n"
225	"    \n"
226	"    EndPrimitive();\n"
227	"}\n";
228
229/* Fragment Shader for GeometryShaderMaxInputComponentsTest */
230const glw::GLchar* const GeometryShaderMaxInputComponentsTest::m_fragment_shader_code =
231	"${VERSION}\n"
232	"${GEOMETRY_SHADER_REQUIRE}\n"
233	"precision mediump float;\n"
234	"out vec4 fs_out_color;\n"
235	"void main()\n"
236	"{\n"
237	"    fs_out_color = vec4(1, 1, 1, 1);\n"
238	"}\n";
239
240/** **************************************************************************************************/
241/* Common shader parts for GeometryShaderMaxOutputComponentsTest */
242const glw::GLchar* const GeometryShaderMaxOutputComponentsTest::m_common_shader_code_gs_fs_out = "gs_fs_out_";
243
244const glw::GLchar* const GeometryShaderMaxOutputComponentsTest::m_common_shader_code_number_of_points =
245	"#define NUMBER_OF_POINTS ";
246
247const glw::GLchar* const GeometryShaderMaxOutputComponentsTest::m_common_shader_code_gs_fs_out_definitions =
248	"// definitions of gs_fs_out_ varyings go here\n";
249
250/* Vertex Shader for GeometryShaderMaxOutputComponentsTest */
251const glw::GLchar* const GeometryShaderMaxOutputComponentsTest::m_vertex_shader_code =
252	"${VERSION}\n"
253	"\n"
254	"${GEOMETRY_SHADER_REQUIRE}\n"
255	"\n"
256	"void main()\n"
257	"{\n"
258	"    gl_Position = vec4(gl_VertexID, 0, 0, 1);\n"
259	"}\n";
260
261/* Geometry Shader Parts for GeometryShaderMaxOutputComponentsTest */
262const glw::GLchar* const GeometryShaderMaxOutputComponentsTest::m_geometry_shader_code_preamble =
263	"${VERSION}\n"
264	"\n"
265	"${GEOMETRY_SHADER_REQUIRE}\n"
266	"${GEOMETRY_POINT_SIZE_ENABLE}\n"
267	"\n"
268	"// definition of NUMBER_OF_POINTS goes here\n";
269
270const glw::GLchar* const GeometryShaderMaxOutputComponentsTest::m_geometry_shader_code_layout =
271	"u\n"
272	"\n"
273	"layout(points)                                in;\n"
274	"layout(points, max_vertices=NUMBER_OF_POINTS) out;\n"
275	"\n";
276
277const glw::GLchar* const GeometryShaderMaxOutputComponentsTest::m_geometry_shader_code_flat_out_ivec4 =
278	"flat out ivec4";
279
280const glw::GLchar* const GeometryShaderMaxOutputComponentsTest::m_geometry_shader_code_assignment =
281	" = ivec4(index++, index++, index++, index++);\n";
282
283const glw::GLchar* const GeometryShaderMaxOutputComponentsTest::m_geometry_shader_code_body_begin =
284	"\n"
285	"void main()\n"
286	"{\n"
287	"    int index = 1;\n"
288	"\n"
289	"    for (uint point = 0u; point < NUMBER_OF_POINTS; ++point)\n"
290	"    {\n"
291	"        // gs_fs_out assignments go here\n";
292
293const glw::GLchar* const GeometryShaderMaxOutputComponentsTest::m_geometry_shader_code_body_end =
294	"\n"
295	"        gl_PointSize = 2.0;\n"
296	"        gl_Position = vec4(-1.0 + ((2.0 / float(NUMBER_OF_POINTS)) * float(point)) + (1.0 / "
297	"float(NUMBER_OF_POINTS)), 0.0, 0.0, 1.0);\n"
298	"\n"
299	"        EmitVertex();\n"
300	"        EndPrimitive();\n"
301	"    }\n"
302	"}\n";
303
304/* Fragment Shader for GeometryShaderMaxOutputComponentsTest */
305const glw::GLchar* const GeometryShaderMaxOutputComponentsTest::m_fragment_shader_code_preamble =
306	"${VERSION}\n"
307	"\n"
308	"${GEOMETRY_SHADER_REQUIRE}\n"
309	"precision highp int;\n"
310	"\n";
311
312const glw::GLchar* const GeometryShaderMaxOutputComponentsTest::m_fragment_shader_code_flat_in_ivec4 = "flat in ivec4";
313
314const glw::GLchar* const GeometryShaderMaxOutputComponentsTest::m_fragment_shader_code_sum = "sum += ";
315
316const glw::GLchar* const GeometryShaderMaxOutputComponentsTest::m_fragment_shader_code_body_begin =
317	"\n"
318	"layout(location = 0) out int fs_out;\n"
319	"\n"
320	"void main()\n"
321	"{\n"
322	"    int sum = 0;\n"
323	"\n"
324	"    // sum calculation go here\n";
325
326const glw::GLchar* const GeometryShaderMaxOutputComponentsTest::m_fragment_shader_code_body_end = "\n"
327																								  "    fs_out = sum;\n"
328																								  "}\n";
329
330/** ******************************************************************************************* **/
331/* Vertex Shader for GeometryShaderMaxOutputVerticesTest */
332const glw::GLchar* const GeometryShaderMaxOutputVerticesTest::m_vertex_shader_code =
333	"${VERSION}\n"
334	"\n"
335	"${GEOMETRY_SHADER_REQUIRE}\n"
336	"\n"
337	"void main()\n"
338	"{\n"
339	"    gl_Position = vec4(gl_VertexID, 0, 0, 1);\n"
340	"}\n";
341
342/* Geometry Shader for GeometryShaderMaxOutputVerticesTest */
343const glw::GLchar* const GeometryShaderMaxOutputVerticesTest::m_geometry_shader_code_preamble =
344	"${VERSION}\n"
345	"\n"
346	"${GEOMETRY_SHADER_REQUIRE}\n"
347	"\n"
348	"// definition of NUMBER_OF_POINTS goes here\n"
349	"#define NUMBER_OF_POINTS ";
350
351const glw::GLchar* const GeometryShaderMaxOutputVerticesTest::m_geometry_shader_code_body =
352	"u\n"
353	"\n"
354	"layout(points)                                in;\n"
355	"layout(points, max_vertices=NUMBER_OF_POINTS) out;\n"
356	"\n"
357	"void main()\n"
358	"{\n"
359	"    int index = 0;\n"
360	"\n"
361	"    for (uint point = 0u; point < NUMBER_OF_POINTS; ++point)\n"
362	"    {\n"
363	"        EmitVertex();\n"
364	"        EndPrimitive();\n"
365	"    }\n"
366	"\n"
367	"}\n";
368
369/* Fragment Shader for GeometryShaderMaxOutputVerticesTest */
370const glw::GLchar* const GeometryShaderMaxOutputVerticesTest::m_fragment_shader_code =
371	"${VERSION}\n"
372	"\n"
373	"${GEOMETRY_SHADER_REQUIRE}\n"
374	"\n"
375	"precision highp float;\n"
376	"\n"
377	"layout(location = 0) out vec4 fs_out;\n"
378	"\n"
379	"void main()\n"
380	"{\n"
381	"    fs_out = vec4(1, 1, 1, 1);\n"
382	"}\n";
383
384/** ***************************************************************************************************************** **/
385/* Common shader parts for GeometryShaderMaxOutputComponentsSinglePointTest */
386const glw::GLchar* const GeometryShaderMaxOutputComponentsSinglePointTest::m_common_shader_code_gs_fs_out =
387	"gs_fs_out_";
388
389const glw::GLchar* const GeometryShaderMaxOutputComponentsSinglePointTest::m_common_shader_code_gs_fs_out_definitions =
390	"// definitions of gs_fs_out_ varyings go here\n";
391
392/* Vertex Shader for GeometryShaderMaxOutputComponentsSinglePointTest */
393const glw::GLchar* const GeometryShaderMaxOutputComponentsSinglePointTest::m_vertex_shader_code =
394	"${VERSION}\n"
395	"\n"
396	"${GEOMETRY_SHADER_REQUIRE}\n"
397	"\n"
398	"void main()\n"
399	"{\n"
400	"    gl_Position = vec4(gl_VertexID, 0, 0, 1);\n"
401	"}\n";
402
403/* Geometry Shader Parts for GeometryShaderMaxOutputComponentsSinglePointTest */
404const glw::GLchar* const GeometryShaderMaxOutputComponentsSinglePointTest::m_geometry_shader_code_preamble =
405	"${VERSION}\n"
406	"\n"
407	"${GEOMETRY_SHADER_REQUIRE}\n"
408	"${GEOMETRY_POINT_SIZE_ENABLE}\n"
409	"\n"
410	"layout(points)                 in;\n"
411	"layout(points, max_vertices=1) out;\n"
412	"\n";
413
414const glw::GLchar* const GeometryShaderMaxOutputComponentsSinglePointTest::m_geometry_shader_code_flat_out_ivec4 =
415	"flat out ivec4";
416
417const glw::GLchar* const GeometryShaderMaxOutputComponentsSinglePointTest::m_geometry_shader_code_assignment =
418	" = ivec4(index++, index++, index++, index++);\n";
419
420const glw::GLchar* const GeometryShaderMaxOutputComponentsSinglePointTest::m_geometry_shader_code_body_begin =
421	"\n"
422	"void main()\n"
423	"{\n"
424	"    int index = 1;\n"
425	"\n"
426	"    // gs_fs_out assignments go here\n";
427
428const glw::GLchar* const GeometryShaderMaxOutputComponentsSinglePointTest::m_geometry_shader_code_body_end =
429	"\n"
430	"    gl_PointSize = 2.0;\n"
431	"    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
432	"\n"
433	"    EmitVertex();\n"
434	"    EndPrimitive();\n"
435	"}\n";
436
437/* Fragment Shader for GeometryShaderMaxOutputComponentsSinglePointTest */
438const glw::GLchar* const GeometryShaderMaxOutputComponentsSinglePointTest::m_fragment_shader_code_preamble =
439	"${VERSION}\n"
440	"\n"
441	"${GEOMETRY_SHADER_REQUIRE}\n"
442	"\n";
443
444const glw::GLchar* const GeometryShaderMaxOutputComponentsSinglePointTest::m_fragment_shader_code_flat_in_ivec4 =
445	"flat in ivec4";
446
447const glw::GLchar* const GeometryShaderMaxOutputComponentsSinglePointTest::m_fragment_shader_code_sum = "sum += ";
448
449const glw::GLchar* const GeometryShaderMaxOutputComponentsSinglePointTest::m_fragment_shader_code_body_begin =
450	"\n"
451	"layout(location = 0) out int fs_out;\n"
452	"\n"
453	"void main()\n"
454	"{\n"
455	"    int sum = 0;\n"
456	"\n"
457	"    // sum calculation go here\n";
458
459const glw::GLchar* const GeometryShaderMaxOutputComponentsSinglePointTest::m_fragment_shader_code_body_end =
460	"\n"
461	"    fs_out = sum;\n"
462	"}\n";
463
464/** ******************************************************************************************************************** **/
465/* Vertex Shader for GeometryShaderMaxTextureUnitsTest */
466const glw::GLchar* const GeometryShaderMaxTextureUnitsTest::m_vertex_shader_code_preamble =
467	"${VERSION}\n"
468	"\n"
469	"${GEOMETRY_SHADER_REQUIRE}\n"
470	"\n"
471	"precision highp float;\n"
472	"\n"
473	"#define NUMBER_OF_POINTS ";
474
475const glw::GLchar* const GeometryShaderMaxTextureUnitsTest::m_vertex_shader_code_body =
476	"u\n"
477	"\n"
478	"flat out int vs_gs_vertex_id;\n"
479	"\n"
480	"void main()\n"
481	"{\n"
482	"    gl_Position     = vec4(-1.0 + ((2.0 / float(NUMBER_OF_POINTS)) * float(gl_VertexID)) + (1.0 / "
483	"float(NUMBER_OF_POINTS)), 0, 0, 1.0);\n"
484	"    vs_gs_vertex_id = gl_VertexID;\n"
485	"}\n";
486
487/* Geometry Shader for GeometryShaderMaxTextureUnitsTest */
488const glw::GLchar* const GeometryShaderMaxTextureUnitsTest::m_geometry_shader_code_preamble =
489	"${VERSION}\n"
490	"\n"
491	"${GEOMETRY_SHADER_REQUIRE}\n"
492	"${GEOMETRY_POINT_SIZE_ENABLE}\n"
493	"${GPU_SHADER5_REQUIRE}\n"
494	"\n"
495	"precision highp float;\n"
496	"\n"
497	"layout(points)                           in;\n"
498	"layout(triangle_strip, max_vertices = 4) out;\n"
499	"\n"
500	"#define NUMBER_OF_POINTS ";
501
502const glw::GLchar* const GeometryShaderMaxTextureUnitsTest::m_geometry_shader_code_body =
503	"u\n"
504	"\n"
505	"// NUMBER_OF_POINTS == NUMBER_OF_SAMPLERS\n"
506	"     uniform lowp isampler2D gs_texture[NUMBER_OF_POINTS];\n"
507	"flat in      int        vs_gs_vertex_id[1];\n"
508	"flat out     int        gs_fs_color;\n"
509	"\n"
510	"void main()\n"
511	"{\n"
512	"    float half_of_edge = (1.0 / float(NUMBER_OF_POINTS));\n"
513	"    int   color        = 0;\n"
514	"\n"
515	"    for (uint i = 0u; i <= uint(vs_gs_vertex_id[0]); ++i)\n"
516	"    {\n"
517	"        color += texture(gs_texture[i], vec2(0.0, 0.0)).r;\n"
518	"    }\n"
519	"\n"
520	"    gl_Position = gl_in[0].gl_Position + vec4(-half_of_edge,  1.0, 0, 0);\n"
521	"    gs_fs_color = color;\n"
522	"    EmitVertex();\n"
523	"\n"
524	"    gl_Position = gl_in[0].gl_Position + vec4( half_of_edge,  1.0, 0, 0);\n"
525	"    gs_fs_color = color;\n"
526	"    EmitVertex();\n"
527	"\n"
528	"    gl_Position = gl_in[0].gl_Position + vec4(-half_of_edge, -1.0, 0, 0);\n"
529	"    gs_fs_color = color;\n"
530	"    EmitVertex();\n"
531	"\n"
532	"    gl_Position = gl_in[0].gl_Position + vec4( half_of_edge, -1.0, 0, 0);\n"
533	"    gs_fs_color = color;\n"
534	"    EmitVertex();\n"
535	"    EndPrimitive();\n"
536	"}\n";
537
538/* Fragment Shader for GeometryShaderMaxTextureUnitsTest */
539const glw::GLchar* const GeometryShaderMaxTextureUnitsTest::m_fragment_shader_code =
540	"${VERSION}\n"
541	"\n"
542	"${GEOMETRY_SHADER_REQUIRE}\n"
543	"\n"
544	"precision highp float;\n"
545	"\n"
546	"flat                 in  int gs_fs_color;\n"
547	"layout(location = 0) out int fs_out_color;\n"
548	"\n"
549	"void main()\n"
550	"{\n"
551	"    fs_out_color = gs_fs_color;\n"
552	"}\n";
553
554/** *******************************************************************************************************/
555/* Vertex Shader for GeometryShaderMaxInvocationsTest */
556const glw::GLchar* const GeometryShaderMaxInvocationsTest::m_vertex_shader_code =
557	"${VERSION}\n"
558	"\n"
559	"${GEOMETRY_SHADER_REQUIRE}\n"
560	"\n"
561	"precision highp float;\n"
562	"\n"
563	"void main()\n"
564	"{\n"
565	"    gl_Position = vec4(gl_VertexID, 0, 0, 1);\n"
566	"}\n";
567
568/* Geometry Shader for GeometryShaderMaxInvocationsTest */
569const glw::GLchar* const GeometryShaderMaxInvocationsTest::m_geometry_shader_code_preamble =
570	"${VERSION}\n"
571	"\n"
572	"${GEOMETRY_SHADER_REQUIRE}\n"
573	"\n"
574	"precision highp float;\n"
575	"\n"
576	"#define GEOMETRY_SHADER_INVOCATIONS ";
577
578const glw::GLchar* const GeometryShaderMaxInvocationsTest::m_geometry_shader_code_layout =
579	"u\n"
580	"\n"
581	"layout(points) in;\n"
582	"layout(triangle_strip, max_vertices = 3) out;\n";
583
584const glw::GLchar* const GeometryShaderMaxInvocationsTest::m_geometry_shader_code_layout_invocations =
585	"layout(invocations = GEOMETRY_SHADER_INVOCATIONS) in;\n";
586
587const glw::GLchar* const GeometryShaderMaxInvocationsTest::m_geometry_shader_code_body =
588	"\n"
589	"void main()\n"
590	"{\n"
591	"    float dx = (2.0 / float(GEOMETRY_SHADER_INVOCATIONS));\n"
592	"    \n"
593	"    gl_Position = vec4(-1.0 + (dx * float(gl_InvocationID)),      -1.001, 0.0, 1.0);\n"
594	"    EmitVertex();\n"
595	"    \n"
596	"    gl_Position = vec4(-1.0 + (dx * float(gl_InvocationID)),       1.001, 0.0, 1.0);\n"
597	"    EmitVertex();\n"
598	"    \n"
599	"    gl_Position = vec4(-1.0 + (dx * float(gl_InvocationID + 1)),   1.001, 0.0, 1.0);\n"
600	"    EmitVertex();\n"
601	"}\n";
602
603/* Fragment Shader for GeometryShaderMaxInvocationsTest */
604const glw::GLchar* const GeometryShaderMaxInvocationsTest::m_fragment_shader_code =
605	"${VERSION}\n"
606	"\n"
607	"${GEOMETRY_SHADER_REQUIRE}\n"
608	"\n"
609	"precision highp float;\n"
610	"\n"
611	"layout(location = 0) out vec4 fs_out_color;\n"
612	"\n"
613	"void main()\n"
614	"{\n"
615	"    fs_out_color = vec4(0.0, 1.0, 0.0, 0.0);\n"
616	"}\n";
617
618/** ***************************************************************************************************** **/
619/* Vertex Shader for GeometryShaderMaxCombinedTextureUnitsTest */
620const glw::GLchar* const GeometryShaderMaxCombinedTextureUnitsTest::m_vertex_shader_code_preamble =
621	"${VERSION}\n"
622	"\n"
623	"${GEOMETRY_SHADER_REQUIRE}\n"
624	"${GPU_SHADER5_ENABLE}\n"
625	"\n"
626	"precision highp float;\n"
627	"\n"
628	"#define NUMBER_OF_POINTS ";
629
630const glw::GLchar* const GeometryShaderMaxCombinedTextureUnitsTest::m_vertex_shader_code_body =
631	"u\n"
632	"\n"
633	"// NUMBER_OF_POINTS == NUMBER_OF_SAMPLERS\n"
634	"     uniform highp usampler2D sampler[NUMBER_OF_POINTS];"
635	"flat out     int        vs_gs_vertex_id;\n"
636	"flat out     uint       vs_gs_sum;\n"
637	"\n"
638	"void main()\n"
639	"{\n"
640	"    uint sum = 0u;\n"
641	"\n"
642	"    for (uint i = 0u; i < uint(gl_VertexID); ++i)\n"
643	"    {\n"
644	"        sum += texture(sampler[i], vec2(0.0, 0.0)).r;\n"
645	"    }\n"
646	"\n"
647	"    gl_Position     = vec4(-1.0 + ((2.0 / float(NUMBER_OF_POINTS)) * float(gl_VertexID)) + (1.0 / "
648	"float(NUMBER_OF_POINTS)), 0, 0, 1.0);\n"
649	"    vs_gs_vertex_id = gl_VertexID;\n"
650	"    vs_gs_sum       = sum;\n"
651	"}\n";
652
653/* Geometry Shader for GeometryShaderMaxCombinedTextureUnitsTest */
654const glw::GLchar* const GeometryShaderMaxCombinedTextureUnitsTest::m_geometry_shader_code_preamble =
655	"${VERSION}\n"
656	"\n"
657	"${GEOMETRY_SHADER_REQUIRE}\n"
658	"${GPU_SHADER5_ENABLE}\n"
659	"\n"
660	"precision highp float;\n"
661	"\n"
662	"layout(points)                   in;\n"
663	"layout(points, max_vertices = 1) out;\n"
664	"\n"
665	"#define NUMBER_OF_POINTS ";
666
667const glw::GLchar* const GeometryShaderMaxCombinedTextureUnitsTest::m_geometry_shader_code_body =
668	"u\n"
669	"\n"
670	"// NUMBER_OF_POINTS == NUMBER_OF_SAMPLERS\n"
671	"     uniform highp usampler2D sampler[NUMBER_OF_POINTS];\n"
672	"flat in      int        vs_gs_vertex_id[1];\n"
673	"flat in      uint       vs_gs_sum      [1];\n"
674	"flat out     int        gs_fs_vertex_id;\n"
675	"flat out     uint       gs_fs_vertex_sum;\n"
676	"flat out     uint       gs_fs_geometry_sum;\n"
677	"\n"
678	"void main()\n"
679	"{\n"
680	"    uint sum = 0u;\n"
681	"\n"
682	"    for (uint i = 0u; i < uint(vs_gs_vertex_id[0]); ++i)\n"
683	"    {\n"
684	"        sum += texture(sampler[i], vec2(0.0, 0.0)).r;\n"
685	"    }\n"
686	"\n"
687	"    gl_Position        = gl_in[0].gl_Position;\n"
688	"    gs_fs_vertex_id    = vs_gs_vertex_id[0];\n"
689	"    gs_fs_vertex_sum   = vs_gs_sum      [0];\n"
690	"    gs_fs_geometry_sum = sum;\n"
691	"    EmitVertex();\n"
692	"    EndPrimitive();\n"
693	"}\n";
694
695/* Fragment Shader for GeometryShaderMaxCombinedTextureUnitsTest */
696const glw::GLchar* const GeometryShaderMaxCombinedTextureUnitsTest::m_fragment_shader_code_preamble =
697	"${VERSION}\n"
698	"\n"
699	"${GEOMETRY_SHADER_REQUIRE}\n"
700	"${GPU_SHADER5_ENABLE}\n"
701	"\n"
702	"precision highp float;\n"
703	"\n"
704	"// NUMBER_OF_POINTS == NUMBER_OF_SAMPLERS\n"
705	"#define NUMBER_OF_POINTS ";
706
707const glw::GLchar* const GeometryShaderMaxCombinedTextureUnitsTest::m_fragment_shader_code_body =
708	"u\n"
709	"\n"
710	"                     uniform highp usampler2D sampler[NUMBER_OF_POINTS];\n"
711	"flat                 in      int        gs_fs_vertex_id;\n"
712	"flat                 in      uint       gs_fs_vertex_sum;\n"
713	"flat                 in      uint       gs_fs_geometry_sum;\n"
714	"layout(location = 0) out     uint       fs_out_color;\n"
715	"\n"
716	"void main()\n"
717	"{\n"
718	"    uint sum = 0u;\n"
719	"\n"
720	"    for (uint i = 0u; i < uint(gs_fs_vertex_id); ++i)\n"
721	"    {\n"
722	"        sum += texture(sampler[i], vec2(0.0, 0.0)).r;\n"
723	"    }\n"
724	"    fs_out_color = sum + gs_fs_vertex_sum + gs_fs_geometry_sum;\n"
725	"}\n";
726
727/** ***************************************************************************************************************** **/
728
729/* Constants for GeometryShaderMaxUniformComponentsTest */
730const unsigned int		 GeometryShaderMaxUniformComponentsTest::m_buffer_size			   = sizeof(glw::GLint);
731const glw::GLchar* const GeometryShaderMaxUniformComponentsTest::m_captured_varyings_names = "gs_out_sum";
732
733/* Constants for GeometryShaderMaxUniformBlocksTest */
734const unsigned int		 GeometryShaderMaxUniformBlocksTest::m_buffer_size			   = sizeof(glw::GLint);
735const glw::GLchar* const GeometryShaderMaxUniformBlocksTest::m_captured_varyings_names = "gs_out_sum";
736
737/* Constants for GeometryShaderMaxInputComponentsTest */
738const unsigned int		 GeometryShaderMaxInputComponentsTest::m_buffer_size			 = sizeof(glw::GLint);
739const glw::GLchar* const GeometryShaderMaxInputComponentsTest::m_captured_varyings_names = "gs_out_sum";
740
741/* Constants for GeometryShaderMaxOutputComponentsTest */
742const unsigned int GeometryShaderMaxOutputComponentsTest::m_point_size		   = 2;
743const unsigned int GeometryShaderMaxOutputComponentsTest::m_texture_height	 = m_point_size;
744const unsigned int GeometryShaderMaxOutputComponentsTest::m_texture_pixel_size = 4 * sizeof(glw::GLint);
745
746/* Constants for GeometryShaderMaxOutputComponentsSinglePointTest */
747const unsigned int GeometryShaderMaxOutputComponentsSinglePointTest::m_point_size		  = 2;
748const unsigned int GeometryShaderMaxOutputComponentsSinglePointTest::m_texture_height	 = m_point_size;
749const unsigned int GeometryShaderMaxOutputComponentsSinglePointTest::m_texture_pixel_size = 4 * sizeof(glw::GLint);
750const unsigned int GeometryShaderMaxOutputComponentsSinglePointTest::m_texture_width	  = m_point_size;
751
752/* Constants for GeometryShaderMaxTextureUnitsTest */
753const unsigned int GeometryShaderMaxTextureUnitsTest::m_point_size		   = 2;
754const unsigned int GeometryShaderMaxTextureUnitsTest::m_texture_height	 = m_point_size;
755const unsigned int GeometryShaderMaxTextureUnitsTest::m_texture_pixel_size = 4 * sizeof(glw::GLint);
756
757/* Constants for GeometryShaderMaxInvocationsTest */
758const unsigned int GeometryShaderMaxInvocationsTest::m_triangle_edge_length = 9;
759const unsigned int GeometryShaderMaxInvocationsTest::m_texture_height		= m_triangle_edge_length;
760const unsigned int GeometryShaderMaxInvocationsTest::m_texture_pixel_size   = 4 * sizeof(glw::GLubyte);
761
762/* Constants for GeometryShaderMaxCombinedTextureUnitsTest */
763const unsigned int GeometryShaderMaxCombinedTextureUnitsTest::m_point_size		   = 1;
764const unsigned int GeometryShaderMaxCombinedTextureUnitsTest::m_texture_height	 = m_point_size;
765const unsigned int GeometryShaderMaxCombinedTextureUnitsTest::m_texture_pixel_size = 4 * sizeof(glw::GLint);
766
767/** Constructor
768 *
769 *  @param context     Test context
770 *  @param name        Test case's name
771 *  @param description Test case's description
772 **/
773GeometryShaderLimitsTransformFeedbackBase::GeometryShaderLimitsTransformFeedbackBase(Context&			  context,
774																					 const ExtParameters& extParams,
775																					 const char*		  name,
776																					 const char*		  description)
777	: TestCaseBase(context, extParams, name, description)
778	, m_fragment_shader_id(0)
779	, m_geometry_shader_id(0)
780	, m_program_object_id(0)
781	, m_vertex_shader_id(0)
782	, m_buffer_object_id(0)
783	, m_vertex_array_object_id(0)
784	, m_fragment_shader_parts(0)
785	, m_geometry_shader_parts(0)
786	, m_vertex_shader_parts(0)
787	, m_n_fragment_shader_parts(0)
788	, m_n_geometry_shader_parts(0)
789	, m_n_vertex_shader_parts(0)
790	, m_captured_varyings_names(0)
791	, m_n_captured_varyings(0)
792	, m_buffer_size(0)
793{
794	/* Nothing to be done here */
795}
796
797/** Initializes GLES objects used during the test.
798 *
799 */
800void GeometryShaderLimitsTransformFeedbackBase::initTest()
801{
802	/* This test should only run if EXT_geometry_shader is supported */
803	if (!m_is_geometry_shader_extension_supported)
804	{
805		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
806	}
807
808	/* Retrieve ES entrypoints */
809	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
810
811	/* Get shaders code from child class */
812	getShaderParts(m_fragment_shader_parts, m_n_fragment_shader_parts, m_geometry_shader_parts,
813				   m_n_geometry_shader_parts, m_vertex_shader_parts, m_n_vertex_shader_parts);
814
815	/* Get captured varyings from inheriting class */
816	getCapturedVaryings(m_captured_varyings_names, m_n_captured_varyings);
817
818	/* Create program and shaders */
819	m_program_object_id = gl.createProgram();
820
821	m_fragment_shader_id = gl.createShader(GL_FRAGMENT_SHADER);
822	m_geometry_shader_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
823	m_vertex_shader_id   = gl.createShader(GL_VERTEX_SHADER);
824
825	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create program or shader object(s)");
826
827	/* Set up transform feedback */
828	gl.transformFeedbackVaryings(m_program_object_id, m_n_captured_varyings, m_captured_varyings_names,
829								 GL_INTERLEAVED_ATTRIBS);
830
831	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set transform feedback varyings");
832
833	/* Build program */
834	if (false == buildProgram(m_program_object_id, m_fragment_shader_id, m_n_fragment_shader_parts,
835							  m_fragment_shader_parts, m_geometry_shader_id, m_n_geometry_shader_parts,
836							  m_geometry_shader_parts, m_vertex_shader_id, m_n_vertex_shader_parts,
837							  m_vertex_shader_parts))
838	{
839		TCU_FAIL("Could not create program from valid vertex/geometry/fragment shader");
840	}
841
842	/* Generate and bind VAO */
843	gl.genVertexArrays(1, &m_vertex_array_object_id);
844	gl.bindVertexArray(m_vertex_array_object_id);
845
846	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create vertex array object");
847
848	/* Get size of buffer used by transform feedback from child class */
849	getTransformFeedbackBufferSize(m_buffer_size);
850
851	/* Generate, bind and allocate buffer */
852	gl.genBuffers(1, &m_buffer_object_id);
853	gl.bindBuffer(GL_ARRAY_BUFFER, m_buffer_object_id);
854	gl.bufferData(GL_ARRAY_BUFFER, m_buffer_size, 0 /* no start data */, GL_STATIC_COPY);
855
856	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create buffer object");
857}
858
859/** Executes the test.
860 *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
861 *
862 *  Note the function throws exception should an error occur!
863 *
864 *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
865 *
866 **/
867tcu::TestCase::IterateResult GeometryShaderLimitsTransformFeedbackBase::iterate()
868{
869	initTest();
870
871	/* Retrieve ES entrypoints */
872	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
873
874	/* Verification result */
875	bool result = false;
876
877	/* Setup transform feedback */
878	gl.enable(GL_RASTERIZER_DISCARD);
879	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) call failed");
880
881	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_buffer_object_id);
882	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed");
883
884	/* Setup draw call */
885	gl.useProgram(m_program_object_id);
886	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not use program");
887
888	gl.beginTransformFeedback(GL_POINTS);
889	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed");
890	{
891		/* Let child class prepare input data */
892		prepareProgramInput();
893
894		/* Draw */
895		gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* one point */);
896		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed");
897	}
898	/* Stop transform feedback */
899	gl.endTransformFeedback();
900	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed");
901
902	/* Map transfrom feedback results */
903	const void* transform_feedback_data =
904		gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* offset */, m_buffer_size, GL_MAP_READ_BIT);
905
906	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not map the buffer object into process space");
907
908	/* Verify data extracted from transfrom feedback */
909	result = verifyResult(transform_feedback_data);
910
911	/* Unmap transform feedback buffer */
912	gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
913	GLU_EXPECT_NO_ERROR(gl.getError(), "Error unmapping the buffer object");
914
915	/* Let child class clean itself */
916	clean();
917
918	/* Verify results */
919	if (true != result)
920	{
921		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
922	}
923	else
924	{
925		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
926	}
927
928	return STOP;
929}
930
931/** Deinitializes GLES objects created during the test.
932 *
933 */
934void GeometryShaderLimitsTransformFeedbackBase::deinit()
935{
936	/* Retrieve ES entrypoints */
937	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
938
939	/* Bind default values */
940	gl.useProgram(0);
941	gl.bindVertexArray(0);
942	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* offset */, 0 /* id */);
943	gl.bindBuffer(GL_ARRAY_BUFFER, 0);
944
945	/* Delete program object and shaders */
946	if (0 != m_program_object_id)
947	{
948		gl.deleteProgram(m_program_object_id);
949
950		m_program_object_id = 0;
951	}
952
953	if (0 != m_fragment_shader_id)
954	{
955		gl.deleteShader(m_fragment_shader_id);
956
957		m_fragment_shader_id = 0;
958	}
959
960	if (0 != m_geometry_shader_id)
961	{
962		gl.deleteShader(m_geometry_shader_id);
963
964		m_geometry_shader_id = 0;
965	}
966
967	if (0 != m_vertex_shader_id)
968	{
969		gl.deleteShader(m_vertex_shader_id);
970
971		m_vertex_shader_id = 0;
972	}
973
974	/* Delete buffer objects */
975	if (0 != m_buffer_object_id)
976	{
977		gl.deleteBuffers(1, &m_buffer_object_id);
978
979		m_buffer_object_id = 0;
980	}
981
982	if (0 != m_vertex_array_object_id)
983	{
984		gl.deleteVertexArrays(1, &m_vertex_array_object_id);
985
986		m_vertex_array_object_id = 0;
987	}
988
989	/* Deinitialize base class */
990	TestCaseBase::deinit();
991}
992
993/** Constructor
994 *
995 * @param context       Test context
996 * @param name          Test case's name
997 * @param description   Test case's description
998 **/
999GeometryShaderLimitsRenderingBase::GeometryShaderLimitsRenderingBase(Context& context, const ExtParameters& extParams,
1000																	 const char* name, const char* description)
1001	: TestCaseBase(context, extParams, name, description)
1002	, m_fragment_shader_id(0)
1003	, m_geometry_shader_id(0)
1004	, m_program_object_id(0)
1005	, m_vertex_shader_id(0)
1006	, m_framebuffer_object_id(0)
1007	, m_color_texture_id(0)
1008	, m_vertex_array_object_id(0)
1009	, m_fragment_shader_parts(0)
1010	, m_geometry_shader_parts(0)
1011	, m_vertex_shader_parts(0)
1012	, m_n_fragment_shader_parts(0)
1013	, m_n_geometry_shader_parts(0)
1014	, m_n_vertex_shader_parts(0)
1015	, m_texture_format(GL_RGBA8)
1016	, m_texture_height(0)
1017	, m_texture_pixel_size(0)
1018	, m_texture_read_format(GL_RGBA)
1019	, m_texture_read_type(GL_UNSIGNED_BYTE)
1020	, m_texture_width(0)
1021{
1022	/* Nothing to be done here */
1023}
1024
1025/** Initializes GLES objects used during the test.
1026 *
1027 */
1028void GeometryShaderLimitsRenderingBase::initTest()
1029{
1030	/* This test should only run if EXT_geometry_shader is supported */
1031	if (!m_is_geometry_shader_extension_supported)
1032	{
1033		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
1034	}
1035
1036	/* Query on support of EXT_gpu_shader5 */
1037	if (!m_is_gpu_shader5_supported)
1038	{
1039		throw tcu::NotSupportedError(GPU_SHADER5_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
1040	}
1041
1042	/* Retrieve ES entry-points */
1043	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1044
1045	/* Verify that point size range is supported */
1046	glw::GLfloat point_size_range[2] = { 0 };
1047	glw::GLfloat required_point_size = 0.0f;
1048
1049	if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
1050	{
1051		gl.getFloatv(GL_POINT_SIZE_RANGE, point_size_range);
1052	}
1053	else
1054	{
1055		gl.getFloatv(GL_ALIASED_POINT_SIZE_RANGE, point_size_range);
1056	}
1057
1058	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv() call failed");
1059
1060	getRequiredPointSize(required_point_size);
1061
1062	if (required_point_size > point_size_range[1])
1063	{
1064		m_testCtx.getLog() << tcu::TestLog::Message
1065						   << "Test requires a minimum maximum point size of: " << required_point_size
1066						   << ", implementation reports a maximum of : " << point_size_range[1]
1067						   << tcu::TestLog::EndMessage;
1068
1069		throw tcu::NotSupportedError("Required point size is not supported", "", __FILE__, __LINE__);
1070	}
1071	if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
1072	{
1073		gl.enable(GL_PROGRAM_POINT_SIZE);
1074	}
1075
1076	/* Get shaders code from child class */
1077	getShaderParts(m_fragment_shader_parts, m_n_fragment_shader_parts, m_geometry_shader_parts,
1078				   m_n_geometry_shader_parts, m_vertex_shader_parts, m_n_vertex_shader_parts);
1079
1080	/* Create program and shaders */
1081	m_program_object_id = gl.createProgram();
1082
1083	m_fragment_shader_id = gl.createShader(GL_FRAGMENT_SHADER);
1084	m_geometry_shader_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
1085	m_vertex_shader_id   = gl.createShader(GL_VERTEX_SHADER);
1086
1087	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create program or shader object(s)");
1088
1089	/* Build program */
1090	if (false == buildProgram(m_program_object_id, m_fragment_shader_id, m_n_fragment_shader_parts,
1091							  m_fragment_shader_parts, m_geometry_shader_id, m_n_geometry_shader_parts,
1092							  m_geometry_shader_parts, m_vertex_shader_id, m_n_vertex_shader_parts,
1093							  m_vertex_shader_parts))
1094	{
1095		TCU_FAIL("Could not create program from valid vertex/geometry/fragment shader");
1096	}
1097
1098	/* Set up a vertex array object */
1099	gl.genVertexArrays(1, &m_vertex_array_object_id);
1100	gl.bindVertexArray(m_vertex_array_object_id);
1101
1102	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create vertex array object");
1103
1104	/* Get framebuffer details */
1105	getFramebufferDetails(m_texture_format, m_texture_read_format, m_texture_read_type, m_texture_width,
1106						  m_texture_height, m_texture_pixel_size);
1107
1108	/* Set up texture object and a FBO */
1109	gl.genTextures(1, &m_color_texture_id);
1110	gl.genFramebuffers(1, &m_framebuffer_object_id);
1111
1112	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create framebuffer");
1113
1114	if (false == setupFramebufferWithTextureAsAttachment(m_framebuffer_object_id, m_color_texture_id, m_texture_format,
1115														 m_texture_width, m_texture_height))
1116	{
1117		TCU_FAIL("Failed to setup framebuffer");
1118	}
1119}
1120
1121/** Executes the test.
1122 *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
1123 *
1124 *  Note the function throws exception should an error occur!
1125 *
1126 *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
1127 *
1128 **/
1129tcu::TestCase::IterateResult GeometryShaderLimitsRenderingBase::iterate()
1130{
1131	initTest();
1132
1133	/* Retrieve ES entry-points */
1134	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1135
1136	/* Variables used for image verification purposes */
1137	std::vector<unsigned char> result_image(m_texture_width * m_texture_height * m_texture_pixel_size);
1138
1139	/* Render */
1140	gl.useProgram(m_program_object_id);
1141
1142	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not use program");
1143
1144	/* Let child class prepare input for program */
1145	prepareProgramInput();
1146
1147	gl.clearColor(0 /* red */, 0 /* green */, 0 /* blue */, 0 /* alpha */);
1148	gl.clear(GL_COLOR_BUFFER_BIT);
1149
1150	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not clear the color buffer");
1151
1152	/* Get draw call details from child class */
1153	glw::GLenum primitive_type = GL_POINTS;
1154	glw::GLuint n_vertices	 = 1;
1155
1156	getDrawCallDetails(primitive_type, n_vertices);
1157
1158	gl.drawArrays(primitive_type, 0 /* first */, n_vertices);
1159	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed");
1160
1161	/* Extract image from FBO */
1162	gl.readPixels(0 /* x */, 0 /* y */, m_texture_width, m_texture_height, m_texture_read_format, m_texture_read_type,
1163				  &result_image[0]);
1164
1165	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not read back pixels from color buffer");
1166
1167	/* Run verification */
1168	if (true == verifyResult(&result_image[0]))
1169	{
1170		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1171	}
1172	else
1173	{
1174		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1175	}
1176
1177	/* Let child class clean itself */
1178	clean();
1179
1180	return STOP;
1181}
1182
1183/** Deinitializes GLES objects created during the test.
1184 *
1185 */
1186void GeometryShaderLimitsRenderingBase::deinit()
1187{
1188	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1189
1190	/* Reset OpenGL ES state */
1191	gl.useProgram(0);
1192	gl.bindVertexArray(0);
1193	gl.bindTexture(GL_TEXTURE_2D, 0);
1194	gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
1195	if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
1196	{
1197		gl.disable(GL_PROGRAM_POINT_SIZE);
1198	}
1199
1200	/* Delete program object and shaders */
1201	if (m_program_object_id != 0)
1202	{
1203		gl.deleteProgram(m_program_object_id);
1204
1205		m_program_object_id = 0;
1206	}
1207
1208	if (m_fragment_shader_id != 0)
1209	{
1210		gl.deleteShader(m_fragment_shader_id);
1211
1212		m_fragment_shader_id = 0;
1213	}
1214
1215	if (m_geometry_shader_id != 0)
1216	{
1217		gl.deleteShader(m_geometry_shader_id);
1218
1219		m_geometry_shader_id = 0;
1220	}
1221
1222	if (m_vertex_shader_id != 0)
1223	{
1224		gl.deleteShader(m_vertex_shader_id);
1225
1226		m_vertex_shader_id = 0;
1227	}
1228
1229	/* Delete frambuffer and textures */
1230	if (m_framebuffer_object_id != 0)
1231	{
1232		gl.deleteFramebuffers(1, &m_framebuffer_object_id);
1233
1234		m_framebuffer_object_id = 0;
1235	}
1236
1237	if (m_color_texture_id != 0)
1238	{
1239		gl.deleteTextures(1, &m_color_texture_id);
1240
1241		m_color_texture_id = 0;
1242	}
1243
1244	if (m_vertex_array_object_id != 0)
1245	{
1246		gl.deleteVertexArrays(1, &m_vertex_array_object_id);
1247
1248		m_vertex_array_object_id = 0;
1249	}
1250
1251	/* Deinitialize base class */
1252	TestCaseBase::deinit();
1253}
1254
1255/** Constructor
1256 *
1257 *  @param context       Test context
1258 *  @param name          Test case's name
1259 *  @param description   Test case's description
1260 **/
1261GeometryShaderMaxUniformComponentsTest::GeometryShaderMaxUniformComponentsTest(Context&				context,
1262																			   const ExtParameters& extParams,
1263																			   const char*			name,
1264																			   const char*			description)
1265	: GeometryShaderLimitsTransformFeedbackBase(context, extParams, name, description)
1266	, m_max_uniform_components(0)
1267	, m_max_uniform_vectors(0)
1268	, m_uniform_location(0)
1269{
1270	/* Nothing to be done here */
1271}
1272
1273/** Clears data after draw call and result verification
1274 *
1275 **/
1276void GeometryShaderMaxUniformComponentsTest::clean()
1277{
1278	m_uniform_data.clear();
1279}
1280
1281/** Get names and number of varyings to be captured by transform feedback
1282 *
1283 *  @param out_captured_varyings_names Array of varying names
1284 *  @param out_n_captured_varyings     Number of varying names
1285 **/
1286void GeometryShaderMaxUniformComponentsTest::getCapturedVaryings(const glw::GLchar* const*& out_captured_varyings_names,
1287																 glw::GLuint&				out_n_captured_varyings)
1288{
1289	/* Varying names */
1290	out_captured_varyings_names = &m_captured_varyings_names;
1291
1292	/* Number of varyings */
1293	out_n_captured_varyings = 1;
1294}
1295
1296/** Get parts of shaders
1297 *
1298 *  @param out_fragment_shader_parts   Array of fragment shader parts
1299 *  @param out_n_fragment_shader_parts Number of fragment shader parts
1300 *  @param out_geometry_shader_parts   Array of geometry shader parts
1301 *  @param out_n_geometry_shader_parts Number of geometry shader parts
1302 *  @param out_vertex_shader_parts     Array of vertex shader parts
1303 *  @param out_n_vertex_shader_parts   Number of vertex shader parts
1304 **/
1305void GeometryShaderMaxUniformComponentsTest::getShaderParts(const glw::GLchar* const*& out_fragment_shader_parts,
1306															unsigned int&			   out_n_fragment_shader_parts,
1307															const glw::GLchar* const*& out_geometry_shader_parts,
1308															unsigned int&			   out_n_geometry_shader_parts,
1309															const glw::GLchar* const*& out_vertex_shader_parts,
1310															unsigned int&			   out_n_vertex_shader_parts)
1311{
1312	/* Retrieve ES entry-points */
1313	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1314
1315	/* Fragment Shader */
1316	out_fragment_shader_parts   = &m_fragment_shader_code;
1317	out_n_fragment_shader_parts = 1;
1318
1319	/* Get maximum number of uniform */
1320	gl.getIntegerv(m_glExtTokens.MAX_GEOMETRY_UNIFORM_COMPONENTS, &m_max_uniform_components);
1321	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT pname.");
1322
1323	m_max_uniform_vectors = m_max_uniform_components / 4 /* 4 components per vector */;
1324
1325	std::stringstream stream;
1326	stream << m_max_uniform_vectors;
1327	m_max_uniform_vectors_string = stream.str();
1328
1329	/* Geometry Shader */
1330	m_geometry_shader_parts[0] = m_geometry_shader_code_preamble;
1331	m_geometry_shader_parts[1] = m_geometry_shader_code_number_of_uniforms;
1332	m_geometry_shader_parts[2] = m_max_uniform_vectors_string.c_str();
1333	m_geometry_shader_parts[3] = m_geometry_shader_code_body;
1334
1335	out_geometry_shader_parts   = m_geometry_shader_parts;
1336	out_n_geometry_shader_parts = 4;
1337
1338	/* Vertex Shader */
1339	out_vertex_shader_parts   = &m_vertex_shader_code;
1340	out_n_vertex_shader_parts = 1;
1341}
1342
1343/** Get size of buffer used by transform feedback
1344 *
1345 *  @param out_buffer_size Size of buffer in bytes
1346 **/
1347void GeometryShaderMaxUniformComponentsTest::getTransformFeedbackBufferSize(unsigned int& out_buffer_size)
1348{
1349	out_buffer_size = m_buffer_size;
1350}
1351
1352/** Prepare test specific program input for draw call
1353 *
1354 **/
1355void GeometryShaderMaxUniformComponentsTest::prepareProgramInput()
1356{
1357	/* Retrieve ES entry-points */
1358	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1359
1360	/* Uniform location */
1361	m_uniform_location = gl.getUniformLocation(m_program_object_id, "uni_array");
1362
1363	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to get uniform location");
1364
1365	if (-1 == m_uniform_location)
1366	{
1367		TCU_FAIL("Invalid uniform location");
1368	}
1369
1370	/* 3. Configure the uniforms to use subsequently increasing values, starting
1371	 *  from 1 for R component of first vector, 2 for G component of that vector,
1372	 *  5 for first component of second vector, and so on.
1373	 **/
1374	m_uniform_data.resize(m_max_uniform_components);
1375
1376	for (glw::GLint i = 0; i < m_max_uniform_components; ++i)
1377	{
1378		m_uniform_data[i] = i + 1;
1379	}
1380
1381	/* Set uniform data */
1382	gl.uniform4iv(m_uniform_location, m_max_uniform_vectors, &m_uniform_data[0]);
1383
1384	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set uniform data");
1385}
1386
1387/** Verification of results
1388 *
1389 *  @param result Pointer to data mapped from transform feedback buffer.
1390 (                Size of data is equal to buffer_size set by getTransformFeedbackBufferSize()
1391 *
1392 *  @return true  Result matches expected value
1393 *          false Result has wrong value
1394 **/
1395bool GeometryShaderMaxUniformComponentsTest::verifyResult(const void* data)
1396{
1397	/* Expected data, sum of elements in range <x;y> with length n = ((x + y) / 2) * n */
1398	const glw::GLint expected_data = ((1 + m_max_uniform_components) * m_max_uniform_components) / 2;
1399
1400	/* Cast to const GLint */
1401	const glw::GLint* transform_feedback_data = (const glw::GLint*)data;
1402
1403	/* Verify data extracted from transfrom feedback */
1404	if (0 != memcmp(transform_feedback_data, &expected_data, m_buffer_size))
1405	{
1406		m_testCtx.getLog() << tcu::TestLog::Message << "Wrong result! Expected: " << expected_data
1407						   << " Extracted: " << *transform_feedback_data << tcu::TestLog::EndMessage;
1408
1409		return false;
1410	}
1411	else
1412	{
1413		return true;
1414	}
1415}
1416
1417/** Constructor
1418 *
1419 *  @param context       Test context
1420 *  @param name          Test case's name
1421 *  @param description   Test case's description
1422 **/
1423GeometryShaderMaxUniformBlocksTest::GeometryShaderMaxUniformBlocksTest(Context& context, const ExtParameters& extParams,
1424																	   const char* name, const char* description)
1425	: GeometryShaderLimitsTransformFeedbackBase(context, extParams, name, description), m_max_uniform_blocks(0)
1426{
1427	/* Nothing to be done here */
1428}
1429
1430/** Clears data after draw call and result verification
1431 *
1432 **/
1433void GeometryShaderMaxUniformBlocksTest::clean()
1434{
1435	/* Retrieve ES entry-points */
1436	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1437
1438	/* Bind default to uniform binding point */
1439	gl.bindBuffer(GL_UNIFORM_BUFFER, 0);
1440	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed");
1441
1442	/* Release buffers */
1443	for (glw::GLint i = 0; i < m_max_uniform_blocks; ++i)
1444	{
1445		/* Bind default to uniform block */
1446		gl.bindBufferBase(GL_UNIFORM_BUFFER, i, 0);
1447		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed");
1448
1449		/* Delete buffer */
1450		gl.deleteBuffers(1, &m_uniform_blocks[i].buffer_object_id);
1451		GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers() call failed");
1452	}
1453
1454	/* Free memory */
1455	m_uniform_blocks.clear();
1456}
1457
1458/** Get names and number of varyings to be captured by transform feedback
1459 *
1460 *  @param out_captured_varyings_names Array of varying names
1461 *  @param out_n_captured_varyings     Number of varying names
1462 **/
1463void GeometryShaderMaxUniformBlocksTest::getCapturedVaryings(const glw::GLchar* const*& out_captured_varyings_names,
1464															 glw::GLuint&				out_n_captured_varyings)
1465{
1466	/* Varying names */
1467	out_captured_varyings_names = &m_captured_varyings_names;
1468
1469	/* Number of varyings */
1470	out_n_captured_varyings = 1;
1471}
1472
1473/** Get parts of shaders
1474 *
1475 *  @param out_fragment_shader_parts   Array of fragment shader parts
1476 *  @param out_n_fragment_shader_parts Number of fragment shader parts
1477 *  @param out_geometry_shader_parts   Array of geometry shader parts
1478 *  @param out_n_geometry_shader_parts Number of geometry shader parts
1479 *  @param out_vertex_shader_parts     Array of vertex shader parts
1480 *  @param out_n_vertex_shader_parts   Number of vertex shader parts
1481 **/
1482void GeometryShaderMaxUniformBlocksTest::getShaderParts(const glw::GLchar* const*& out_fragment_shader_parts,
1483														unsigned int&			   out_n_fragment_shader_parts,
1484														const glw::GLchar* const*& out_geometry_shader_parts,
1485														unsigned int&			   out_n_geometry_shader_parts,
1486														const glw::GLchar* const*& out_vertex_shader_parts,
1487														unsigned int&			   out_n_vertex_shader_parts)
1488{
1489	/* Retrieve ES entry-points */
1490	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1491
1492	/* Fragment Shader */
1493	out_fragment_shader_parts   = &m_fragment_shader_code;
1494	out_n_fragment_shader_parts = 1;
1495
1496	/* Get maximum number of uniform blocks */
1497	gl.getIntegerv(m_glExtTokens.MAX_GEOMETRY_UNIFORM_BLOCKS, &m_max_uniform_blocks);
1498	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_GEOMETRY_UNIFORM_BLOCKS_EXT");
1499
1500	std::stringstream stream;
1501	stream << m_max_uniform_blocks;
1502	m_max_uniform_blocks_string = stream.str();
1503
1504	/* Geometry Shader */
1505	m_geometry_shader_parts[0] = m_geometry_shader_code_preamble;
1506	m_geometry_shader_parts[1] = m_geometry_shader_code_number_of_uniforms;
1507	m_geometry_shader_parts[2] = m_max_uniform_blocks_string.c_str();
1508	m_geometry_shader_parts[3] = m_geometry_shader_code_body_str;
1509
1510	stream.str(std::string());
1511	stream.clear();
1512	for (glw::GLint uniform_block_nr = 0; uniform_block_nr < m_max_uniform_blocks; ++uniform_block_nr)
1513	{
1514		stream << "    gs_out_sum += uni_block_array[" << uniform_block_nr << "].entry;\n";
1515	}
1516	m_uniform_block_access_string = stream.str();
1517
1518	m_geometry_shader_parts[4] = m_uniform_block_access_string.c_str();
1519	m_geometry_shader_parts[5] = m_geometry_shader_code_body_end;
1520
1521	out_geometry_shader_parts   = m_geometry_shader_parts;
1522	out_n_geometry_shader_parts = 6;
1523
1524	/* Vertex Shader */
1525	out_vertex_shader_parts   = &m_vertex_shader_code;
1526	out_n_vertex_shader_parts = 1;
1527}
1528
1529/** Get size of buffer used by transform feedback
1530 *
1531 *  @param out_buffer_size Size of buffer in bytes
1532 **/
1533void GeometryShaderMaxUniformBlocksTest::getTransformFeedbackBufferSize(unsigned int& out_buffer_size)
1534{
1535	out_buffer_size = m_buffer_size;
1536}
1537
1538/** Prepare test specific program input for draw call
1539 *
1540 **/
1541void GeometryShaderMaxUniformBlocksTest::prepareProgramInput()
1542{
1543	/* Retrieve ES entry-points */
1544	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1545
1546	/* Allocate memory */
1547	m_uniform_blocks.resize(m_max_uniform_blocks);
1548
1549	/* Setup uniform blocks */
1550	for (glw::GLint i = 0; i < m_max_uniform_blocks; ++i)
1551	{
1552		/* Generate and bind */
1553		gl.genBuffers(1, &m_uniform_blocks[i].buffer_object_id);
1554		gl.bindBuffer(GL_UNIFORM_BUFFER, m_uniform_blocks[i].buffer_object_id);
1555
1556		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed create buffer object");
1557
1558		/** Expected data is range <1;GL_MAX_GEOMETRY_UNIFORM_BLOCKS_EXT>
1559		 *  See test description for details
1560		 **/
1561		m_uniform_blocks[i].data = i + 1;
1562
1563		gl.bufferData(GL_UNIFORM_BUFFER, sizeof(glw::GLint), &m_uniform_blocks[i].data, GL_STATIC_DRAW);
1564		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set buffer data");
1565
1566		/* Bind buffer to uniform block */
1567		gl.bindBufferBase(GL_UNIFORM_BUFFER, i, m_uniform_blocks[i].buffer_object_id);
1568		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to bind buffer to uniform block");
1569	}
1570}
1571
1572/** Verification of results
1573 *
1574 *  @param result Pointer to data mapped from transform feedback buffer.
1575 *                Size of data is equal to buffer_size set by getTransformFeedbackBufferSize()
1576 *
1577 *  @return true  Result match expected value
1578 *          false Result has wrong value
1579 **/
1580bool GeometryShaderMaxUniformBlocksTest::verifyResult(const void* data)
1581{
1582	/* Expected data, sum of elements in range <x;y> with length n = ((x + y) / 2) * n */
1583	const glw::GLint expected_data = ((1 + m_max_uniform_blocks) * m_max_uniform_blocks) / 2;
1584
1585	/* Cast to const GLint */
1586	const glw::GLint* transform_feedback_data = (const glw::GLint*)data;
1587
1588	/* Verify data extracted from transfrom feedback */
1589	if (0 != memcmp(transform_feedback_data, &expected_data, m_buffer_size))
1590	{
1591		m_testCtx.getLog() << tcu::TestLog::Message << "Wrong result! Expected: " << expected_data
1592						   << " Extracted: " << *transform_feedback_data << tcu::TestLog::EndMessage;
1593
1594		return false;
1595	}
1596	else
1597	{
1598		return true;
1599	}
1600}
1601
1602/** Constructor
1603 *
1604 *  @param context       Test context
1605 *  @param name          Test case's name
1606 *  @param description   Test case's description
1607 **/
1608GeometryShaderMaxInputComponentsTest::GeometryShaderMaxInputComponentsTest(Context&				context,
1609																		   const ExtParameters& extParams,
1610																		   const char* name, const char* description)
1611	: GeometryShaderLimitsTransformFeedbackBase(context, extParams, name, description)
1612	, m_max_geometry_input_components(0)
1613	, m_max_geometry_input_vectors(0)
1614{
1615	/* Nothing to be done here */
1616}
1617
1618/** Clears data after draw call and result verification
1619 *
1620 **/
1621void GeometryShaderMaxInputComponentsTest::clean()
1622{
1623	/* Nothing to be done here */
1624}
1625
1626/** Get names and number of varyings to be captured by transform feedback
1627 *
1628 *  @param out_captured_varyings_names Array of varying names
1629 *  @param out_n_captured_varyings     Number of varying names
1630 **/
1631void GeometryShaderMaxInputComponentsTest::getCapturedVaryings(const glw::GLchar* const*& out_captured_varyings_names,
1632															   glw::GLuint&				  out_n_captured_varyings)
1633{
1634	/* Varying names */
1635	out_captured_varyings_names = &m_captured_varyings_names;
1636
1637	/* Number of varyings */
1638	out_n_captured_varyings = 1;
1639}
1640
1641/** Get parts of shaders
1642 *
1643 *  @param out_fragment_shader_parts   Array of fragment shader parts
1644 *  @param out_n_fragment_shader_parts Number of fragment shader parts
1645 *  @param out_geometry_shader_parts   Array of geometry shader parts
1646 *  @param out_n_geometry_shader_parts Number of geometry shader parts
1647 *  @param out_vertex_shader_parts     Array of vertex shader parts
1648 *  @param out_n_vertex_shader_parts   Number of vertex shader parts
1649 **/
1650void GeometryShaderMaxInputComponentsTest::getShaderParts(const glw::GLchar* const*& out_fragment_shader_parts,
1651														  unsigned int&				 out_n_fragment_shader_parts,
1652														  const glw::GLchar* const*& out_geometry_shader_parts,
1653														  unsigned int&				 out_n_geometry_shader_parts,
1654														  const glw::GLchar* const*& out_vertex_shader_parts,
1655														  unsigned int&				 out_n_vertex_shader_parts)
1656{
1657	/* Retrieve ES entry-points */
1658	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1659
1660	/* Fragment Shader */
1661	out_fragment_shader_parts   = &m_fragment_shader_code;
1662	out_n_fragment_shader_parts = 1;
1663
1664	/* Get maximum number of uniform */
1665	gl.getIntegerv(m_glExtTokens.MAX_GEOMETRY_INPUT_COMPONENTS, &m_max_geometry_input_components);
1666	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_GEOMETRY_INPUT_COMPONENTS_EXT pname");
1667
1668	m_max_geometry_input_vectors = m_max_geometry_input_components / 4 /* 4 components per vector */;
1669
1670	std::stringstream stream;
1671	stream << m_max_geometry_input_vectors;
1672	m_max_geometry_input_vectors_string = stream.str();
1673
1674	/* Geometry Shader */
1675	m_geometry_shader_parts[0] = m_geometry_shader_code_preamble;
1676	m_geometry_shader_parts[1] = m_geometry_shader_code_number_of_uniforms;
1677	m_geometry_shader_parts[2] = m_max_geometry_input_vectors_string.c_str();
1678	m_geometry_shader_parts[3] = m_geometry_shader_code_body;
1679
1680	out_geometry_shader_parts   = m_geometry_shader_parts;
1681	out_n_geometry_shader_parts = 4;
1682
1683	/* Vertex Shader */
1684	m_vertex_shader_parts[0] = m_vertex_shader_code_preamble;
1685	m_vertex_shader_parts[1] = m_vertex_shader_code_number_of_uniforms;
1686	m_vertex_shader_parts[2] = m_max_geometry_input_vectors_string.c_str();
1687	m_vertex_shader_parts[3] = m_vertex_shader_code_body;
1688
1689	out_vertex_shader_parts   = m_vertex_shader_parts;
1690	out_n_vertex_shader_parts = 4;
1691}
1692
1693/** Get size of buffer used by transform feedback
1694 *
1695 *  @param out_buffer_size  Size of buffer in bytes
1696 **/
1697void GeometryShaderMaxInputComponentsTest::getTransformFeedbackBufferSize(unsigned int& out_buffer_size)
1698{
1699	out_buffer_size = m_buffer_size;
1700}
1701
1702/** Prepare test specific program input for draw call
1703 *
1704 **/
1705void GeometryShaderMaxInputComponentsTest::prepareProgramInput()
1706{
1707	/* Nothing to be done here */
1708}
1709
1710/** Verification of results
1711 *
1712 *  @param result Pointer to data mapped from transform feedback buffer.
1713 *                Size of data is equal to buffer_size set by getTransformFeedbackBufferSize()
1714 *
1715 *  @return true  Result match expected value
1716 *          false Result has wrong value
1717 **/
1718bool GeometryShaderMaxInputComponentsTest::verifyResult(const void* data)
1719{
1720	/* Expected data, sum of elements in range <x;y> with length n = ((x + y) / 2) * n */
1721	const glw::GLint expected_data = ((1 + m_max_geometry_input_components) * m_max_geometry_input_components) / 2;
1722
1723	/* Cast to const GLint */
1724	const glw::GLint* transform_feedback_data = (const glw::GLint*)data;
1725
1726	/* Verify data extracted from transfrom feedback */
1727	if (0 != memcmp(transform_feedback_data, &expected_data, m_buffer_size))
1728	{
1729		m_testCtx.getLog() << tcu::TestLog::Message << "Wrong result! Expected: " << expected_data
1730						   << " Extracted: " << *transform_feedback_data << tcu::TestLog::EndMessage;
1731
1732		return false;
1733	}
1734	else
1735	{
1736		return true;
1737	}
1738}
1739
1740/** Constructor
1741 *
1742 * @param context       Test context
1743 * @param name          Test case's name
1744 * @param description   Test case's description
1745 **/
1746GeometryShaderMaxOutputComponentsTest::GeometryShaderMaxOutputComponentsTest(Context&			  context,
1747																			 const ExtParameters& extParams,
1748																			 const char* name, const char* description)
1749	: GeometryShaderLimitsRenderingBase(context, extParams, name, description)
1750	, m_fragment_shader_code_c_str(0)
1751	, m_geometry_shader_code_c_str(0)
1752	, m_texture_width(0)
1753	, m_max_output_components(0)
1754	, m_max_output_vectors(0)
1755	, m_max_total_output_components(0)
1756	, m_n_available_vectors(0)
1757	, m_n_output_points(0)
1758{
1759	/* Nothing to be done here */
1760}
1761
1762/** Clears data after draw call and result verification
1763 *
1764 **/
1765void GeometryShaderMaxOutputComponentsTest::clean()
1766{
1767	/* Nothing to be done here */
1768}
1769
1770/** Get details for draw call
1771 *
1772 *  @param out_primitive_type Type of primitive that will be used by next draw call
1773 *  @param out_n_vertices     Number of vertices that will used with next draw call
1774 **/
1775void GeometryShaderMaxOutputComponentsTest::getDrawCallDetails(glw::GLenum& out_primitive_type,
1776															   glw::GLuint& out_n_vertices)
1777{
1778	/* Draw one point */
1779	out_primitive_type = GL_POINTS;
1780	out_n_vertices	 = 1;
1781}
1782
1783/** Get dimensions and format for texture bind to color attachment 0, get format and type for glReadPixels
1784 *
1785 *  @param out_texture_format      Format for texture used as color attachment 0
1786 *  @param out_texture_read_format Format of data used with glReadPixels
1787 *  @param out_texture_read_type   Type of data used with glReadPixels
1788 *  @param out_texture_width       Width of texture used as color attachment 0
1789 *  @param out_texture_height      Height of texture used as color attachment 0
1790 *  @param out_texture_pixel_size  Size of single pixel in bytes
1791 **/
1792void GeometryShaderMaxOutputComponentsTest::getFramebufferDetails(
1793	glw::GLenum& out_texture_format, glw::GLenum& out_texture_read_format, glw::GLenum& out_texture_read_type,
1794	glw::GLuint& out_texture_width, glw::GLuint& out_texture_height, unsigned int& out_texture_pixel_size)
1795{
1796	out_texture_format		= GL_R32I;
1797	out_texture_read_format = GL_RGBA_INTEGER;
1798	out_texture_read_type   = GL_INT;
1799	out_texture_width		= m_texture_width;
1800	out_texture_height		= m_texture_height;
1801	out_texture_pixel_size  = 4 * 4;
1802}
1803
1804void GeometryShaderMaxOutputComponentsTest::getRequiredPointSize(glw::GLfloat& out_point_size)
1805{
1806	/* This test should only run if EXT_geometry_point_size is supported */
1807	if (!m_is_geometry_shader_point_size_supported)
1808	{
1809		throw tcu::NotSupportedError(GEOMETRY_SHADER_POINT_SIZE_NOT_SUPPORTED, "", __FILE__, __LINE__);
1810	}
1811
1812	out_point_size = (float)m_point_size;
1813}
1814
1815/** Get parts of shaders
1816 *
1817 *  @param out_fragment_shader_parts   Array of fragment shader parts
1818 *  @param out_n_fragment_shader_parts Number of fragment shader parts
1819 *  @param out_geometry_shader_parts   Array of geometry shader parts
1820 *  @param out_n_geometry_shader_parts Number of geometry shader parts
1821 *  @param out_vertex_shader_parts     Array of vertex shader parts
1822 *  @param out_n_vertex_shader_parts   Number of vertex shader parts
1823 **/
1824void GeometryShaderMaxOutputComponentsTest::getShaderParts(const glw::GLchar* const*& out_fragment_shader_parts,
1825														   unsigned int&			  out_n_fragment_shader_parts,
1826														   const glw::GLchar* const*& out_geometry_shader_parts,
1827														   unsigned int&			  out_n_geometry_shader_parts,
1828														   const glw::GLchar* const*& out_vertex_shader_parts,
1829														   unsigned int&			  out_n_vertex_shader_parts)
1830{
1831	/* GL functions */
1832	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1833
1834	/* Get maximum number of output components */
1835	gl.getIntegerv(m_glExtTokens.MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, &m_max_total_output_components);
1836	gl.getIntegerv(m_glExtTokens.MAX_GEOMETRY_OUTPUT_COMPONENTS, &m_max_output_components);
1837	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call(s) failed");
1838
1839	m_n_output_points	 = m_max_total_output_components / m_max_output_components;
1840	m_max_output_vectors  = m_max_output_components / 4; /* 4 components per vector */
1841	m_n_available_vectors = m_max_output_vectors - 2;	/* 2 vectors are reserved for gl_Position and gl_PointSize */
1842
1843	/* Framebuffer width */
1844	m_texture_width = m_point_size * m_n_output_points;
1845
1846	/* Fragment shader parts */
1847	prepareFragmentShader(m_fragment_shader_code);
1848
1849	m_fragment_shader_code_c_str = m_fragment_shader_code.c_str();
1850	out_fragment_shader_parts	= &m_fragment_shader_code_c_str;
1851	out_n_fragment_shader_parts  = 1;
1852
1853	/* Geometry shader parts */
1854	prepareGeometryShader(m_geometry_shader_code);
1855
1856	m_geometry_shader_code_c_str = m_geometry_shader_code.c_str();
1857	out_geometry_shader_parts	= &m_geometry_shader_code_c_str;
1858	out_n_geometry_shader_parts  = 1;
1859
1860	/* Vertex shader */
1861	out_vertex_shader_parts   = &m_vertex_shader_code;
1862	out_n_vertex_shader_parts = 1;
1863}
1864
1865/** Prepare test specific program input for draw call
1866 *
1867 **/
1868void GeometryShaderMaxOutputComponentsTest::prepareProgramInput()
1869{
1870	/* Nothing to be done here */
1871}
1872
1873/** Verify rendered image
1874 *
1875 *  @param data Image to verify
1876 *
1877 *  @return true  Image pixels match expected values
1878 *          false Some pixels have wrong values
1879 **/
1880bool GeometryShaderMaxOutputComponentsTest::verifyResult(const void* data)
1881{
1882	const unsigned char* result_image			= (const unsigned char*)data;
1883	const unsigned int   line_size				= m_texture_width * m_texture_pixel_size;
1884	const glw::GLint	 n_components_per_point = m_n_available_vectors * 4; /* 4 components per vector */
1885
1886	/* For each drawn point */
1887	for (glw::GLint point = 0; point < m_n_output_points; ++point)
1888	{
1889		const glw::GLint   first_value	= point * n_components_per_point + 1;
1890		const glw::GLint   last_value	 = (point + 1) * n_components_per_point;
1891		const glw::GLint   expected_value = ((first_value + last_value) * n_components_per_point) / 2;
1892		const unsigned int point_offset   = point * m_texture_pixel_size * m_point_size;
1893
1894		/* Verify all pixels that belong to point, area m_point_size x m_point_size */
1895		for (unsigned int y = 0; y < m_point_size; ++y)
1896		{
1897			const unsigned int line_offset		  = y * line_size;
1898			const unsigned int first_texel_offset = line_offset + point_offset;
1899
1900			for (unsigned int x = 0; x < m_point_size; ++x)
1901			{
1902				const unsigned int texel_offset = first_texel_offset + x * m_texture_pixel_size;
1903
1904				if (0 != memcmp(result_image + texel_offset, &expected_value, sizeof(expected_value)))
1905				{
1906					glw::GLint* result_value = (glw::GLint*)(result_image + texel_offset);
1907
1908					m_testCtx.getLog() << tcu::TestLog::Message << "Wrong result! Expected: " << expected_value
1909									   << " Extracted: " << *result_value << " Point: " << point << " X: " << x
1910									   << " Y: " << y << tcu::TestLog::EndMessage;
1911
1912					return false;
1913				}
1914			}
1915		}
1916	}
1917
1918	return true;
1919}
1920
1921/** Prepare fragment shader code
1922 *
1923 *  @param out_shader_code String that will be used to store shaders code
1924 **/
1925void GeometryShaderMaxOutputComponentsTest::prepareFragmentShader(std::string& out_shader_code) const
1926{
1927	std::stringstream stream;
1928
1929	stream << m_fragment_shader_code_preamble;
1930	stream << m_common_shader_code_gs_fs_out_definitions;
1931
1932	for (int i = 0; i < m_n_available_vectors; ++i)
1933	{
1934		stream << m_fragment_shader_code_flat_in_ivec4 << " " << m_common_shader_code_gs_fs_out << i << ";\n";
1935	}
1936
1937	stream << m_fragment_shader_code_body_begin;
1938
1939	for (int i = 0; i < m_n_available_vectors; ++i)
1940	{
1941		stream << "    " << m_fragment_shader_code_sum << m_common_shader_code_gs_fs_out << i << ".x + "
1942			   << m_common_shader_code_gs_fs_out << i << ".y + " << m_common_shader_code_gs_fs_out << i << ".z + "
1943			   << m_common_shader_code_gs_fs_out << i << ".w;\n";
1944	}
1945
1946	stream << m_fragment_shader_code_body_end;
1947
1948	out_shader_code = stream.str();
1949}
1950
1951/** Prepare geometry shader code
1952 *
1953 *  @param out_shader_code String that will be used to store shaders code
1954 **/
1955void GeometryShaderMaxOutputComponentsTest::prepareGeometryShader(std::string& out_shader_code) const
1956{
1957	std::stringstream stream;
1958
1959	stream << m_geometry_shader_code_preamble;
1960	stream << m_common_shader_code_number_of_points;
1961	stream << m_n_output_points;
1962	stream << m_geometry_shader_code_layout;
1963	stream << m_common_shader_code_gs_fs_out_definitions;
1964
1965	for (int i = 0; i < m_n_available_vectors; ++i)
1966	{
1967		stream << m_geometry_shader_code_flat_out_ivec4 << " " << m_common_shader_code_gs_fs_out << i << ";\n";
1968	}
1969
1970	stream << m_geometry_shader_code_body_begin;
1971
1972	for (int i = 0; i < m_n_available_vectors; ++i)
1973	{
1974		stream << "        " << m_common_shader_code_gs_fs_out << i << m_geometry_shader_code_assignment;
1975	}
1976
1977	stream << m_geometry_shader_code_body_end;
1978
1979	out_shader_code = stream.str();
1980}
1981
1982/** Constructor
1983 *
1984 * @param context       Test context
1985 * @param name          Test case's name
1986 * @param description   Test case's description
1987 **/
1988GeometryShaderMaxOutputVerticesTest::GeometryShaderMaxOutputVerticesTest(Context&			  context,
1989																		 const ExtParameters& extParams,
1990																		 const char* name, const char* description)
1991	: TestCaseBase(context, extParams, name, description)
1992{
1993	/* Nothing to be done here */
1994}
1995
1996/** Executes the test.
1997 *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
1998 *
1999 *  Note the function throws exception should an error occur!
2000 *
2001 *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
2002 *
2003 **/
2004tcu::TestCase::IterateResult GeometryShaderMaxOutputVerticesTest::iterate()
2005{
2006	/* This test should only run if EXT_geometry_shader is supported */
2007	if (!m_is_geometry_shader_extension_supported)
2008	{
2009		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
2010	}
2011
2012	/* GL */
2013	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2014
2015	/* Get maximum number of output vertices and prepare strings */
2016	glw::GLint  max_output_vertices;
2017	std::string valid_output_vertices_string;
2018	std::string invalid_output_vertices_string;
2019
2020	gl.getIntegerv(m_glExtTokens.MAX_GEOMETRY_OUTPUT_VERTICES, &max_output_vertices);
2021	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT pname");
2022
2023	std::stringstream stream_valid;
2024	stream_valid << max_output_vertices;
2025	valid_output_vertices_string = stream_valid.str();
2026
2027	std::stringstream stream_invalid;
2028	stream_invalid << max_output_vertices + 1;
2029	invalid_output_vertices_string = stream_invalid.str();
2030
2031	/* Geometry shader parts */
2032	const glw::GLchar* geometry_shader_valid_parts[] = { m_geometry_shader_code_preamble,
2033														 valid_output_vertices_string.c_str(),
2034														 m_geometry_shader_code_body };
2035
2036	const glw::GLchar* geometry_shader_invalid_parts[] = { m_geometry_shader_code_preamble,
2037														   invalid_output_vertices_string.c_str(),
2038														   m_geometry_shader_code_body };
2039
2040	/* Try to build programs */
2041	bool does_valid_build =
2042		doesProgramBuild(1, &m_fragment_shader_code, 3, geometry_shader_valid_parts, 1, &m_vertex_shader_code);
2043
2044	bool does_invalid_build =
2045		doesProgramBuild(1, &m_fragment_shader_code, 3, geometry_shader_invalid_parts, 1, &m_vertex_shader_code);
2046
2047	/* Verify results */
2048	if ((true == does_valid_build) && (false == does_invalid_build))
2049	{
2050		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2051	}
2052	else
2053	{
2054		if (true != does_valid_build)
2055		{
2056			m_testCtx.getLog() << tcu::TestLog::Message << "Failed to build valid program! GS::max_vertices "
2057														   "set to MAX_GEOMETRY_OUTPUT_VERTICES.\n"
2058							   << tcu::TestLog::EndMessage;
2059		}
2060
2061		if (false != does_invalid_build)
2062		{
2063			m_testCtx.getLog() << tcu::TestLog::Message << "Build of invalid program was successful! GS::max_vertices "
2064														   "set to MAX_GEOMETRY_OUTPUT_VERTICES + 1.\n"
2065							   << tcu::TestLog::EndMessage;
2066		}
2067
2068		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2069	}
2070
2071	return STOP;
2072}
2073
2074/** Constructor
2075 *
2076 * @param context       Test context
2077 * @param name          Test case's name
2078 * @param description   Test case's decsription
2079 **/
2080GeometryShaderMaxOutputComponentsSinglePointTest::GeometryShaderMaxOutputComponentsSinglePointTest(
2081	Context& context, const ExtParameters& extParams, const char* name, const char* description)
2082	: GeometryShaderLimitsRenderingBase(context, extParams, name, description)
2083	, m_fragment_shader_code_c_str(0)
2084	, m_geometry_shader_code_c_str(0)
2085	, m_max_output_components(0)
2086	, m_max_output_vectors(0)
2087	, m_n_available_vectors(0)
2088{
2089	/* Nothing to be done here */
2090}
2091
2092/** Clears data after draw call and result verification
2093 *
2094 **/
2095void GeometryShaderMaxOutputComponentsSinglePointTest::clean()
2096{
2097	/* Nothing to be done here */
2098}
2099
2100/** Get details for draw call
2101 *
2102 *  @param out_primitive_type Type of primitive that will be used by next draw call
2103 *  @param out_n_vertices     Number of vertices that will used with next draw call
2104 **/
2105void GeometryShaderMaxOutputComponentsSinglePointTest::getDrawCallDetails(glw::GLenum& out_primitive_type,
2106																		  glw::GLuint& out_n_vertices)
2107{
2108	/* Draw one point */
2109	out_primitive_type = GL_POINTS;
2110	out_n_vertices	 = 1;
2111}
2112
2113/** Get dimensions and format for texture bind to color attachment 0, get format and type for glReadPixels
2114 *
2115 *  @param out_texture_format      Format for texture used as color attachment 0
2116 *  @param out_texture_read_format Format of data used with glReadPixels
2117 *  @param out_texture_read_type   Type of data used with glReadPixels
2118 *  @param out_texture_width       Width of texture used as color attachment 0
2119 *  @param out_texture_height      Height of texture used as color attachment 0
2120 *  @param out_texture_pixel_size  Size of single pixel in bytes
2121 **/
2122void GeometryShaderMaxOutputComponentsSinglePointTest::getFramebufferDetails(
2123	glw::GLenum& out_texture_format, glw::GLenum& out_texture_read_format, glw::GLenum& out_texture_read_type,
2124	glw::GLuint& out_texture_width, glw::GLuint& out_texture_height, unsigned int& out_texture_pixel_size)
2125{
2126	out_texture_format		= GL_R32I;
2127	out_texture_read_format = GL_RGBA_INTEGER;
2128	out_texture_read_type   = GL_INT;
2129	out_texture_width		= m_texture_width;
2130	out_texture_height		= m_texture_height;
2131	out_texture_pixel_size  = 4 * 4;
2132}
2133
2134void GeometryShaderMaxOutputComponentsSinglePointTest::getRequiredPointSize(glw::GLfloat& out_point_size)
2135{
2136	/* This test should only run if EXT_geometry_point_size is supported */
2137	if (!m_is_geometry_shader_point_size_supported)
2138	{
2139		throw tcu::NotSupportedError(GEOMETRY_SHADER_POINT_SIZE_NOT_SUPPORTED, "", __FILE__, __LINE__);
2140	}
2141
2142	out_point_size = (float)m_point_size;
2143}
2144
2145/** Get parts of shaders
2146 *
2147 *  @param out_fragment_shader_parts   Array of fragment shader parts
2148 *  @param out_n_fragment_shader_parts Number of fragment shader parts
2149 *  @param out_geometry_shader_parts   Array of geometry shader parts
2150 *  @param out_n_geometry_shader_parts Number of geometry shader parts
2151 *  @param out_vertex_shader_parts     Array of vertex shader parts
2152 *  @param out_n_vertex_shader_parts   Number of vertex shader parts
2153 **/
2154void GeometryShaderMaxOutputComponentsSinglePointTest::getShaderParts(
2155	const glw::GLchar* const*& out_fragment_shader_parts, unsigned int& out_n_fragment_shader_parts,
2156	const glw::GLchar* const*& out_geometry_shader_parts, unsigned int& out_n_geometry_shader_parts,
2157	const glw::GLchar* const*& out_vertex_shader_parts, unsigned int& out_n_vertex_shader_parts)
2158{
2159	/* Retrieve ES entry-points */
2160	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2161
2162	/* Get maximum number of output components */
2163	gl.getIntegerv(m_glExtTokens.MAX_GEOMETRY_OUTPUT_COMPONENTS, &m_max_output_components);
2164	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_EXT pname");
2165
2166	m_max_output_vectors  = m_max_output_components / 4; /* 4 components per vector */
2167	m_n_available_vectors = m_max_output_vectors - 2;	/* 2 vectors are reserved for gl_Position and gl_PointSize */
2168
2169	/* Fragment shader parts */
2170	prepareFragmentShader(m_fragment_shader_code);
2171
2172	m_fragment_shader_code_c_str = m_fragment_shader_code.c_str();
2173	out_fragment_shader_parts	= &m_fragment_shader_code_c_str;
2174	out_n_fragment_shader_parts  = 1;
2175
2176	/* Geometry shader parts */
2177	prepareGeometryShader(m_geometry_shader_code);
2178
2179	m_geometry_shader_code_c_str = m_geometry_shader_code.c_str();
2180	out_geometry_shader_parts	= &m_geometry_shader_code_c_str;
2181	out_n_geometry_shader_parts  = 1;
2182
2183	/* Vertex shader */
2184	out_vertex_shader_parts   = &m_vertex_shader_code;
2185	out_n_vertex_shader_parts = 1;
2186}
2187
2188/** Prepare test specific program input for draw call
2189 *
2190 **/
2191void GeometryShaderMaxOutputComponentsSinglePointTest::prepareProgramInput()
2192{
2193	/* Nothing to be done here */
2194}
2195
2196/** Verify rendered image
2197 *
2198 *  @param data Image to verify
2199 *
2200 *  @return true  Image pixels match expected values
2201 *          false Some pixels have wrong values
2202 **/
2203bool GeometryShaderMaxOutputComponentsSinglePointTest::verifyResult(const void* data)
2204{
2205	const unsigned char* result_image			= (const unsigned char*)data;
2206	const unsigned int   line_size				= m_texture_width * m_texture_pixel_size;
2207	const glw::GLint	 n_components_per_point = m_n_available_vectors * 4; /* 4 components per vector */
2208
2209	const glw::GLint first_value	= 1;
2210	const glw::GLint last_value		= n_components_per_point;
2211	const glw::GLint expected_value = ((first_value + last_value) * n_components_per_point) / 2;
2212
2213	/* Verify all pixels that belong to point, area m_point_size x m_point_size */
2214	for (unsigned int y = 0; y < m_point_size; ++y)
2215	{
2216		const unsigned int line_offset = y * line_size;
2217
2218		for (unsigned int x = 0; x < m_point_size; ++x)
2219		{
2220			const unsigned int texel_offset = line_offset + x * m_texture_pixel_size;
2221
2222			if (0 != memcmp(result_image + texel_offset, &expected_value, sizeof(expected_value)))
2223			{
2224				const glw::GLint* result_value = (const glw::GLint*)(result_image + texel_offset);
2225
2226				m_testCtx.getLog() << tcu::TestLog::Message << "Wrong result! Expected: " << expected_value
2227								   << " Extracted: " << *result_value << "  X: " << x << " Y: " << y
2228								   << tcu::TestLog::EndMessage;
2229
2230				return false;
2231			}
2232		}
2233	}
2234
2235	return true;
2236}
2237
2238/** Prepare fragment shader code
2239 *
2240 *  @param out_shader_code String that will be used to store shaders code
2241 **/
2242void GeometryShaderMaxOutputComponentsSinglePointTest::prepareFragmentShader(std::string& out_shader_code) const
2243{
2244	std::stringstream stream;
2245
2246	stream << m_fragment_shader_code_preamble;
2247	stream << m_common_shader_code_gs_fs_out_definitions;
2248
2249	for (int i = 0; i < m_n_available_vectors; ++i)
2250	{
2251		stream << m_fragment_shader_code_flat_in_ivec4 << " " << m_common_shader_code_gs_fs_out << i << ";\n";
2252	}
2253
2254	stream << m_fragment_shader_code_body_begin;
2255
2256	for (int i = 0; i < m_n_available_vectors; ++i)
2257	{
2258		stream << "    " << m_fragment_shader_code_sum << m_common_shader_code_gs_fs_out << i << ".x + "
2259			   << m_common_shader_code_gs_fs_out << i << ".y + " << m_common_shader_code_gs_fs_out << i << ".z + "
2260			   << m_common_shader_code_gs_fs_out << i << ".w;\n";
2261	}
2262
2263	stream << m_fragment_shader_code_body_end;
2264
2265	out_shader_code = stream.str();
2266}
2267
2268/** Prepare geometry shader code
2269 *
2270 *  @param out_shader_code String that will be used to store shaders code
2271 **/
2272void GeometryShaderMaxOutputComponentsSinglePointTest::prepareGeometryShader(std::string& out_shader_code) const
2273{
2274	std::stringstream stream;
2275
2276	stream << m_geometry_shader_code_preamble;
2277	stream << m_common_shader_code_gs_fs_out_definitions;
2278
2279	for (int i = 0; i < m_n_available_vectors; ++i)
2280	{
2281		stream << m_geometry_shader_code_flat_out_ivec4 << " " << m_common_shader_code_gs_fs_out << i << ";\n";
2282	}
2283
2284	stream << m_geometry_shader_code_body_begin;
2285
2286	for (int i = 0; i < m_n_available_vectors; ++i)
2287	{
2288		stream << "    " << m_common_shader_code_gs_fs_out << i << m_geometry_shader_code_assignment;
2289	}
2290
2291	stream << m_geometry_shader_code_body_end;
2292
2293	out_shader_code = stream.str();
2294}
2295
2296/** Constructor
2297 *
2298 * @param context     Test context
2299 * @param name        Test case's name
2300 * @param description Test case's description
2301 **/
2302GeometryShaderMaxTextureUnitsTest::GeometryShaderMaxTextureUnitsTest(Context& context, const ExtParameters& extParams,
2303																	 const char* name, const char* description)
2304	: GeometryShaderLimitsRenderingBase(context, extParams, name, description)
2305	, m_texture_width(0)
2306	, m_max_texture_units(0)
2307{
2308	/* Nothing to be done here */
2309}
2310
2311/** Clears data after draw call and result verification
2312 *
2313 **/
2314void GeometryShaderMaxTextureUnitsTest::clean()
2315{
2316	/* GL functions */
2317	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2318
2319	/* Bind 0 to all texture units */
2320	for (int i = 0; i < m_max_texture_units; ++i)
2321	{
2322		gl.activeTexture(GL_TEXTURE0 + i);
2323		gl.bindTexture(GL_TEXTURE_2D, 0);
2324	}
2325	gl.activeTexture(GL_TEXTURE0);
2326
2327	/* Delete textures */
2328	for (int i = 0; i < m_max_texture_units; ++i)
2329	{
2330		gl.deleteTextures(1, &m_textures[i].texture_id);
2331	}
2332
2333	m_textures.clear();
2334}
2335
2336/** Get details for draw call
2337 *
2338 *  @param out_primitive_type Type of primitive that will be used by next draw call
2339 *  @param out_n_vertices     Number of vertices that will used with next draw call
2340 **/
2341void GeometryShaderMaxTextureUnitsTest::getDrawCallDetails(glw::GLenum& out_primitive_type, glw::GLuint& out_n_vertices)
2342{
2343	/* Draw GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT points */
2344	out_primitive_type = GL_POINTS;
2345	out_n_vertices	 = m_max_texture_units;
2346}
2347
2348/** Get dimensions and format for texture bind to color attachment 0, get format and type for glReadPixels
2349 *
2350 *  @param out_texture_format      Format for texture used as color attachment 0
2351 *  @param out_texture_read_format Format of data used with glReadPixels
2352 *  @param out_texture_read_type   Type of data used with glReadPixels
2353 *  @param out_texture_width       Width of texture used as color attachment 0
2354 *  @param out_texture_height      Height of texture used as color attachment 0
2355 *  @param out_texture_pixel_size  Size of single pixel in bytes
2356 **/
2357void GeometryShaderMaxTextureUnitsTest::getFramebufferDetails(
2358	glw::GLenum& out_texture_format, glw::GLenum& out_texture_read_format, glw::GLenum& out_texture_read_type,
2359	glw::GLuint& out_texture_width, glw::GLuint& out_texture_height, unsigned int& out_texture_pixel_size)
2360{
2361	out_texture_format		= GL_R32I;
2362	out_texture_read_format = GL_RGBA_INTEGER;
2363	out_texture_read_type   = GL_INT;
2364	out_texture_width		= m_texture_width;
2365	out_texture_height		= m_texture_height;
2366	out_texture_pixel_size  = 4 * 4;
2367}
2368
2369void GeometryShaderMaxTextureUnitsTest::getRequiredPointSize(glw::GLfloat& out_point_size)
2370{
2371	/* This test should only run if EXT_geometry_point_size is supported */
2372	if (!m_is_geometry_shader_point_size_supported)
2373	{
2374		throw tcu::NotSupportedError(GEOMETRY_SHADER_POINT_SIZE_NOT_SUPPORTED, "", __FILE__, __LINE__);
2375	}
2376
2377	out_point_size = (float)m_point_size;
2378}
2379
2380/** Get parts of shaders
2381 *
2382 *  @param out_fragment_shader_parts   Array of fragment shader parts
2383 *  @param out_n_fragment_shader_parts Number of fragment shader parts
2384 *  @param out_geometry_shader_parts   Array of geometry shader parts
2385 *  @param out_n_geometry_shader_parts Number of geometry shader parts
2386 *  @param out_vertex_shader_parts     Array of vertex shader parts
2387 *  @param out_n_vertex_shader_parts   Number of vertex shader parts
2388 **/
2389void GeometryShaderMaxTextureUnitsTest::getShaderParts(const glw::GLchar* const*& out_fragment_shader_parts,
2390													   unsigned int&			  out_n_fragment_shader_parts,
2391													   const glw::GLchar* const*& out_geometry_shader_parts,
2392													   unsigned int&			  out_n_geometry_shader_parts,
2393													   const glw::GLchar* const*& out_vertex_shader_parts,
2394													   unsigned int&			  out_n_vertex_shader_parts)
2395{
2396	/* Retrieve ES entry-points */
2397	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2398
2399	/* Get maximum number of texture units */
2400	gl.getIntegerv(m_glExtTokens.MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, &m_max_texture_units);
2401	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT pname");
2402
2403	/* Number of drawn points is equal to GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT */
2404	m_texture_width = m_max_texture_units * m_point_size;
2405
2406	/* Prepare texture units string */
2407	std::stringstream stream;
2408	stream << m_max_texture_units;
2409	m_max_texture_units_string = stream.str();
2410
2411	/* Fragment shader parts */
2412	out_fragment_shader_parts   = &m_fragment_shader_code;
2413	out_n_fragment_shader_parts = 1;
2414
2415	/* Geometry shader parts */
2416	m_geometry_shader_parts[0] = m_geometry_shader_code_preamble;
2417	m_geometry_shader_parts[1] = m_max_texture_units_string.c_str();
2418	m_geometry_shader_parts[2] = m_geometry_shader_code_body;
2419
2420	out_geometry_shader_parts   = m_geometry_shader_parts;
2421	out_n_geometry_shader_parts = 3;
2422
2423	/* Vertex shader parts */
2424	m_vertex_shader_parts[0] = m_vertex_shader_code_preamble;
2425	m_vertex_shader_parts[1] = m_max_texture_units_string.c_str();
2426	m_vertex_shader_parts[2] = m_vertex_shader_code_body;
2427
2428	out_vertex_shader_parts   = m_vertex_shader_parts;
2429	out_n_vertex_shader_parts = 3;
2430}
2431
2432/** Prepare test specific program input for draw call
2433 *
2434 **/
2435void GeometryShaderMaxTextureUnitsTest::prepareProgramInput()
2436{
2437	/* Retrieve ES entry-points */
2438	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2439
2440	m_textures.resize(m_max_texture_units);
2441
2442	/* Prepare texture storage and fill data */
2443	for (int i = 0; i < m_max_texture_units; ++i)
2444	{
2445		/* (starting from 1, delta: 2) */
2446		m_textures[i].data = i * 2 + 1;
2447
2448		/* Generate and bind texture */
2449		gl.genTextures(1, &m_textures[i].texture_id);
2450		gl.bindTexture(GL_TEXTURE_2D, m_textures[i].texture_id);
2451
2452		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create texture");
2453
2454		/* Allocate and upload texture data */
2455		gl.texImage2D(GL_TEXTURE_2D, 0 /* level */, GL_R32I, 1 /* width */, 1 /* height */, 0 /* border */,
2456					  GL_RED_INTEGER, GL_INT, &m_textures[i].data);
2457
2458		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2459		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2460
2461		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create storage and fill texture with data");
2462	}
2463
2464	/* Prepare sampler uniforms */
2465	for (int i = 0; i < m_max_texture_units; ++i)
2466	{
2467		/* Prepare name of sampler */
2468		std::stringstream stream;
2469
2470		stream << "gs_texture[" << i << "]";
2471
2472		/* Get sampler location */
2473		glw::GLint gs_texture_location = gl.getUniformLocation(m_program_object_id, stream.str().c_str());
2474
2475		if (-1 == gs_texture_location || (GL_NO_ERROR != gl.getError()))
2476		{
2477			TCU_FAIL("Failed to get uniform isampler2D location");
2478		}
2479
2480		/* Set uniform at sampler location value to index of texture unit */
2481		gl.uniform1i(gs_texture_location, i);
2482
2483		if (GL_NO_ERROR != gl.getError())
2484		{
2485			m_testCtx.getLog() << tcu::TestLog::Message << "Failed to set uniform at location: " << gs_texture_location
2486							   << " to value: " << i << tcu::TestLog::EndMessage;
2487
2488			TCU_FAIL("Failed to get uniform isampler2D location");
2489		}
2490	}
2491
2492	/* Bind textures to texture units */
2493	for (int i = 0; i < m_max_texture_units; ++i)
2494	{
2495		gl.activeTexture(GL_TEXTURE0 + i);
2496		gl.bindTexture(GL_TEXTURE_2D, m_textures[i].texture_id);
2497	}
2498
2499	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set texture units up");
2500}
2501
2502/** Verify rendered image
2503 *
2504 *  @param data Image to verify
2505 *
2506 *  @return true  Image pixels match expected values
2507 *          false Some pixels have wrong values
2508 **/
2509bool GeometryShaderMaxTextureUnitsTest::verifyResult(const void* data)
2510{
2511	const unsigned char* result_image = (const unsigned char*)data;
2512	const unsigned int   line_size	= m_texture_width * m_texture_pixel_size;
2513
2514	/* For each drawn point */
2515	for (glw::GLint point = 0; point < m_max_texture_units; ++point)
2516	{
2517		const glw::GLint   first_value	= m_textures[0].data;
2518		const glw::GLint   last_value	 = m_textures[point].data;
2519		const glw::GLint   expected_value = ((first_value + last_value) * (point + 1)) / 2;
2520		const unsigned int point_offset   = point * m_texture_pixel_size * m_point_size;
2521
2522		/* Verify all pixels that belong to point, area m_point_size x m_point_size */
2523		for (unsigned int y = 0; y < m_point_size; ++y)
2524		{
2525			const unsigned int line_offset		  = y * line_size;
2526			const unsigned int first_texel_offset = line_offset + point_offset;
2527
2528			for (unsigned int x = 0; x < m_point_size; ++x)
2529			{
2530				const unsigned int texel_offset = first_texel_offset + x * m_texture_pixel_size;
2531
2532				if (0 != memcmp(result_image + texel_offset, &expected_value, sizeof(expected_value)))
2533				{
2534					glw::GLint* result_value = (glw::GLint*)(result_image + texel_offset);
2535
2536					m_testCtx.getLog() << tcu::TestLog::Message << "Wrong result! "
2537																   "Expected: "
2538									   << expected_value << " Extracted: " << *result_value << " Point: " << point
2539									   << " X: " << x << " Y: " << y << tcu::TestLog::EndMessage;
2540
2541					return false;
2542				}
2543			}
2544		}
2545	}
2546
2547	return true;
2548}
2549
2550/** Constructor
2551 *
2552 * @param context     Test context
2553 * @param name        Test case's name
2554 * @param description Test case's description
2555 **/
2556GeometryShaderMaxInvocationsTest::GeometryShaderMaxInvocationsTest(Context& context, const ExtParameters& extParams,
2557																   const char* name, const char* description)
2558	: TestCaseBase(context, extParams, name, description)
2559	, m_fragment_shader_id_for_multiple_invocations_pass(0)
2560	, m_geometry_shader_id_for_multiple_invocations_pass(0)
2561	, m_program_object_id_for_multiple_invocations_pass(0)
2562	, m_vertex_shader_id_for_multiple_invocations_pass(0)
2563	, m_fragment_shader_id_for_single_invocation_pass(0)
2564	, m_geometry_shader_id_for_single_invocation_pass(0)
2565	, m_program_object_id_for_single_invocation_pass(0)
2566	, m_vertex_shader_id_for_single_invocation_pass(0)
2567	, m_max_geometry_shader_invocations(0)
2568	, m_framebuffer_object_id(0)
2569	, m_color_texture_id(0)
2570	, m_texture_width(0)
2571	, m_vertex_array_object_id(0)
2572{
2573	/* Nothing to be done here */
2574}
2575
2576/** Initializes GLES objects used during the test.
2577 *
2578 */
2579void GeometryShaderMaxInvocationsTest::initTest()
2580{
2581	/* This test should only run if EXT_geometry_shader is supported */
2582	if (!m_is_geometry_shader_extension_supported)
2583	{
2584		throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
2585	}
2586
2587	/* Retrieve ES entry-points */
2588	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2589
2590	/* Get GL_MAX_GEOMETRY_SHADER_INVOCATIONS_EXT */
2591	gl.getIntegerv(m_glExtTokens.MAX_GEOMETRY_SHADER_INVOCATIONS, &m_max_geometry_shader_invocations);
2592	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_GEOMETRY_SHADER_INVOCATIONS_EXT");
2593
2594	/* Prepare string for GL_MAX_GEOMETRY_SHADER_INVOCATIONS_EXT */
2595	std::stringstream stream;
2596	stream << m_max_geometry_shader_invocations;
2597	m_max_geometry_shader_invocations_string = stream.str();
2598
2599	/* Prepare gemetry shader parts for multiple invocations pass */
2600	const glw::GLuint n_geometry_shader_parts_for_multiple_invocations_pass = 5;
2601
2602	m_geometry_shader_parts_for_multiple_invocations_pass[0] = m_geometry_shader_code_preamble;
2603	m_geometry_shader_parts_for_multiple_invocations_pass[1] = m_max_geometry_shader_invocations_string.c_str();
2604	m_geometry_shader_parts_for_multiple_invocations_pass[2] = m_geometry_shader_code_layout;
2605	m_geometry_shader_parts_for_multiple_invocations_pass[3] = m_geometry_shader_code_layout_invocations;
2606	m_geometry_shader_parts_for_multiple_invocations_pass[4] = m_geometry_shader_code_body;
2607
2608	/* Prepare gemetry shader parts for single invocation pass */
2609	const glw::GLuint n_geometry_shader_parts_for_single_invocation_pass = 4;
2610
2611	m_geometry_shader_parts_for_single_invocation_pass[0] = m_geometry_shader_code_preamble;
2612	m_geometry_shader_parts_for_single_invocation_pass[1] = m_max_geometry_shader_invocations_string.c_str();
2613	m_geometry_shader_parts_for_single_invocation_pass[2] = m_geometry_shader_code_layout;
2614	m_geometry_shader_parts_for_single_invocation_pass[3] = m_geometry_shader_code_body;
2615
2616	/* Create program and shaders for multiple GS invocations */
2617	m_program_object_id_for_multiple_invocations_pass = gl.createProgram();
2618
2619	m_fragment_shader_id_for_multiple_invocations_pass = gl.createShader(GL_FRAGMENT_SHADER);
2620	m_geometry_shader_id_for_multiple_invocations_pass = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
2621	m_vertex_shader_id_for_multiple_invocations_pass   = gl.createShader(GL_VERTEX_SHADER);
2622
2623	/* Create program and shaders for single GS invocations */
2624	m_program_object_id_for_single_invocation_pass = gl.createProgram();
2625
2626	m_fragment_shader_id_for_single_invocation_pass = gl.createShader(GL_FRAGMENT_SHADER);
2627	m_geometry_shader_id_for_single_invocation_pass = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
2628	m_vertex_shader_id_for_single_invocation_pass   = gl.createShader(GL_VERTEX_SHADER);
2629
2630	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create program or shader objects");
2631
2632	/* Build program for multiple GS invocations */
2633	if (false == buildProgram(m_program_object_id_for_multiple_invocations_pass,
2634							  m_fragment_shader_id_for_multiple_invocations_pass, 1, &m_fragment_shader_code,
2635							  m_geometry_shader_id_for_multiple_invocations_pass,
2636							  n_geometry_shader_parts_for_multiple_invocations_pass,
2637							  m_geometry_shader_parts_for_multiple_invocations_pass,
2638							  m_vertex_shader_id_for_multiple_invocations_pass, 1, &m_vertex_shader_code))
2639	{
2640		TCU_FAIL("Could not create program from valid vertex/geometry/fragment shader");
2641	}
2642
2643	/* Build program for single GS invocations */
2644	if (false == buildProgram(m_program_object_id_for_single_invocation_pass,
2645							  m_fragment_shader_id_for_single_invocation_pass, 1, &m_fragment_shader_code,
2646							  m_geometry_shader_id_for_single_invocation_pass,
2647							  n_geometry_shader_parts_for_single_invocation_pass,
2648							  m_geometry_shader_parts_for_single_invocation_pass,
2649							  m_vertex_shader_id_for_single_invocation_pass, 1, &m_vertex_shader_code))
2650	{
2651		TCU_FAIL("Could not create program from valid vertex/geometry/fragment shader");
2652	}
2653
2654	/* Set up texture object and a FBO */
2655	gl.genTextures(1, &m_color_texture_id);
2656	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create texture object");
2657
2658	gl.genFramebuffers(1, &m_framebuffer_object_id);
2659	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create framebuffer object");
2660
2661	m_texture_width = m_triangle_edge_length * m_max_geometry_shader_invocations;
2662
2663	if (false == setupFramebufferWithTextureAsAttachment(m_framebuffer_object_id, m_color_texture_id, GL_RGBA8,
2664														 m_texture_width, m_texture_height))
2665	{
2666		TCU_FAIL("Failed to setup framebuffer");
2667	}
2668
2669	/* Set up a vertex array object */
2670	gl.genVertexArrays(1, &m_vertex_array_object_id);
2671	gl.bindVertexArray(m_vertex_array_object_id);
2672
2673	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create vertex array object");
2674}
2675
2676/** Executes the test.
2677 *
2678 *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
2679 *
2680 *  Note the function throws exception should an error occur!
2681 *
2682 *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
2683 **/
2684tcu::TestCase::IterateResult GeometryShaderMaxInvocationsTest::iterate()
2685{
2686	initTest();
2687
2688	/* Variables used for image verification purposes */
2689	std::vector<unsigned char> result_image(m_texture_width * m_texture_height * m_texture_pixel_size);
2690
2691	/* Retrieve ES entry-points */
2692	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2693
2694	/* Render with multiple GS invocations */
2695	gl.useProgram(m_program_object_id_for_multiple_invocations_pass);
2696	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not use program");
2697
2698	gl.clearColor(255 /* red */, 0 /* green */, 0 /* blue */, 0 /* alpha */);
2699	gl.clear(GL_COLOR_BUFFER_BIT);
2700
2701	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not clear the color buffer");
2702
2703	gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
2704	GLU_EXPECT_NO_ERROR(gl.getError(), "Call drawArrays() failed");
2705
2706	/* Extract image from FBO */
2707	gl.readPixels(0 /* x */, 0 /* y */, m_texture_width, m_texture_height, GL_RGBA, GL_UNSIGNED_BYTE, &result_image[0]);
2708
2709	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not read back pixels from color buffer");
2710
2711	/* Run verification */
2712	bool result_of_multiple_invocations_pass = verifyResultOfMultipleInvocationsPass(&result_image[0]);
2713
2714	/* Render with single GS invocations */
2715	gl.useProgram(m_program_object_id_for_single_invocation_pass);
2716	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not use program");
2717
2718	gl.clearColor(255 /* red */, 0 /* green */, 0 /* blue */, 0 /* alpha */);
2719	gl.clear(GL_COLOR_BUFFER_BIT);
2720
2721	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not clear the color buffer");
2722
2723	gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
2724	GLU_EXPECT_NO_ERROR(gl.getError(), "Call drawArrays() failed");
2725
2726	/* Extract image from FBO */
2727	gl.readPixels(0 /* x */, 0 /* y */, m_texture_width, m_texture_height, GL_RGBA, GL_UNSIGNED_BYTE, &result_image[0]);
2728
2729	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not read back pixels from color buffer");
2730
2731	/* Run verification */
2732	bool result_of_single_invocation_pass = verifyResultOfSingleInvocationPass(&result_image[0]);
2733
2734	/* Set test result */
2735	if (result_of_multiple_invocations_pass && result_of_single_invocation_pass)
2736	{
2737		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2738	}
2739	else
2740	{
2741		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2742	}
2743
2744	return STOP;
2745}
2746
2747/** Deinitializes GLES objects created during the test.
2748 *
2749 */
2750void GeometryShaderMaxInvocationsTest::deinit()
2751{
2752	/* Retrieve ES entry-points */
2753	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2754
2755	/* Reset OpenGL ES state */
2756	gl.useProgram(0);
2757	gl.bindVertexArray(0);
2758	gl.bindTexture(GL_TEXTURE_2D, 0);
2759	gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
2760
2761	/* Delete everything */
2762	if (m_program_object_id_for_multiple_invocations_pass != 0)
2763	{
2764		gl.deleteProgram(m_program_object_id_for_multiple_invocations_pass);
2765
2766		m_program_object_id_for_multiple_invocations_pass = 0;
2767	}
2768
2769	if (m_fragment_shader_id_for_multiple_invocations_pass != 0)
2770	{
2771		gl.deleteShader(m_fragment_shader_id_for_multiple_invocations_pass);
2772
2773		m_fragment_shader_id_for_multiple_invocations_pass = 0;
2774	}
2775
2776	if (m_geometry_shader_id_for_multiple_invocations_pass != 0)
2777	{
2778		gl.deleteShader(m_geometry_shader_id_for_multiple_invocations_pass);
2779
2780		m_geometry_shader_id_for_multiple_invocations_pass = 0;
2781	}
2782
2783	if (m_vertex_shader_id_for_multiple_invocations_pass != 0)
2784	{
2785		gl.deleteShader(m_vertex_shader_id_for_multiple_invocations_pass);
2786
2787		m_vertex_shader_id_for_multiple_invocations_pass = 0;
2788	}
2789
2790	if (m_program_object_id_for_single_invocation_pass != 0)
2791	{
2792		gl.deleteProgram(m_program_object_id_for_single_invocation_pass);
2793
2794		m_program_object_id_for_single_invocation_pass = 0;
2795	}
2796
2797	if (m_fragment_shader_id_for_single_invocation_pass != 0)
2798	{
2799		gl.deleteShader(m_fragment_shader_id_for_single_invocation_pass);
2800
2801		m_fragment_shader_id_for_single_invocation_pass = 0;
2802	}
2803
2804	if (m_geometry_shader_id_for_single_invocation_pass != 0)
2805	{
2806		gl.deleteShader(m_geometry_shader_id_for_single_invocation_pass);
2807
2808		m_geometry_shader_id_for_single_invocation_pass = 0;
2809	}
2810
2811	if (m_vertex_shader_id_for_single_invocation_pass != 0)
2812	{
2813		gl.deleteShader(m_vertex_shader_id_for_single_invocation_pass);
2814
2815		m_vertex_shader_id_for_single_invocation_pass = 0;
2816	}
2817
2818	if (m_vertex_array_object_id != 0)
2819	{
2820		gl.deleteVertexArrays(1, &m_vertex_array_object_id);
2821
2822		m_vertex_array_object_id = 0;
2823	}
2824
2825	if (m_color_texture_id != 0)
2826	{
2827		gl.deleteTextures(1, &m_color_texture_id);
2828
2829		m_color_texture_id = 0;
2830	}
2831
2832	if (m_framebuffer_object_id != 0)
2833	{
2834		gl.deleteFramebuffers(1, &m_framebuffer_object_id);
2835
2836		m_framebuffer_object_id = 0;
2837	}
2838
2839	/* Deinitilize base class */
2840	TestCaseBase::deinit();
2841}
2842
2843/** Verify image rendered during draw call for multiple invocations pass
2844 *
2845 *  @param result_image Image data
2846 *
2847 *  @return true  When image is as expected
2848 *          false When image is wrong
2849 **/
2850bool GeometryShaderMaxInvocationsTest::verifyResultOfMultipleInvocationsPass(unsigned char* result_image)
2851{
2852	for (unsigned int i = 0; i < (unsigned int)m_max_geometry_shader_invocations; ++i)
2853	{
2854		/* Verify that pixel at triangle's center was modified */
2855		const unsigned int x1 = m_triangle_edge_length * i;
2856		const unsigned int x2 = m_triangle_edge_length * i;
2857		const unsigned int x3 = m_triangle_edge_length * (i + 1) - 1;
2858
2859		const unsigned int y1 = 0;
2860		const unsigned int y2 = m_triangle_edge_length - 1;
2861		const unsigned int y3 = m_triangle_edge_length - 1;
2862
2863		const unsigned int center_x = (x1 + x2 + x3) / 3;
2864		const unsigned int center_y = (y1 + y2 + y3) / 3;
2865
2866		bool is_pixel_valid = comparePixel(result_image, center_x, center_y, m_texture_width, m_texture_height,
2867										   m_texture_pixel_size, 0, 255, 0, 0);
2868
2869		if (false == is_pixel_valid)
2870		{
2871			m_testCtx.getLog() << tcu::TestLog::Message << "Invalid pixel at "
2872														   "["
2873							   << center_x << ";" << center_y << "]! "
2874																 "Triangle index: "
2875							   << i << " from range <0:" << m_max_geometry_shader_invocations << ")."
2876							   << tcu::TestLog::EndMessage;
2877
2878			return false;
2879		}
2880
2881		/* Verify that background's pixel was not modified */
2882		const unsigned int x4 = m_triangle_edge_length * (i + 1) - 1;
2883		const unsigned int y4 = m_triangle_edge_length - 1;
2884
2885		is_pixel_valid =
2886			comparePixel(result_image, x4, y4, m_texture_width, m_texture_height, m_texture_pixel_size, 255, 0, 0, 0);
2887
2888		if (false == is_pixel_valid)
2889		{
2890			m_testCtx.getLog() << tcu::TestLog::Message << "Invalid pixel at [" << x4 << ";" << y4
2891							   << "]! "
2892								  "Background for index: "
2893							   << i << "from range <0:" << m_max_geometry_shader_invocations << ")."
2894							   << tcu::TestLog::EndMessage;
2895
2896			return false;
2897		}
2898	}
2899
2900	return true;
2901}
2902
2903/** Verify image rendered during draw call for single invocation pass
2904 *
2905 *  @param result_image Image data
2906 *
2907 *  @return true  When image is as expected
2908 *          false When image is wrong
2909 **/
2910bool GeometryShaderMaxInvocationsTest::verifyResultOfSingleInvocationPass(unsigned char* result_image)
2911{
2912	/* Only one triangle should be drawn, verify that pixel at its center was modified */
2913	{
2914		const unsigned int x1 = 0;
2915		const unsigned int x2 = 0;
2916		const unsigned int x3 = m_triangle_edge_length - 1;
2917
2918		const unsigned int y1 = 0;
2919		const unsigned int y2 = m_triangle_edge_length - 1;
2920		const unsigned int y3 = m_triangle_edge_length - 1;
2921
2922		const unsigned int center_x = (x1 + x2 + x3) / 3;
2923		const unsigned int center_y = (y1 + y2 + y3) / 3;
2924
2925		bool is_pixel_valid = comparePixel(result_image, center_x, center_y, m_texture_width, m_texture_height,
2926										   m_texture_pixel_size, 0, 255, 0, 0);
2927
2928		if (false == is_pixel_valid)
2929		{
2930			m_testCtx.getLog() << tcu::TestLog::Message << "Invalid pixel at [" << center_x << ";" << center_y
2931							   << "]! "
2932								  "Triangle index: "
2933							   << 0 << " from range <0:" << m_max_geometry_shader_invocations << ")."
2934							   << tcu::TestLog::EndMessage;
2935
2936			return false;
2937		}
2938
2939		/* Verify that background's pixel was not modified */
2940		const unsigned int x4 = m_triangle_edge_length - 1;
2941		const unsigned int y4 = m_triangle_edge_length - 1;
2942
2943		is_pixel_valid =
2944			comparePixel(result_image, x4, y4, m_texture_width, m_texture_height, m_texture_pixel_size, 255, 0, 0, 0);
2945
2946		if (false == is_pixel_valid)
2947		{
2948			m_testCtx.getLog() << tcu::TestLog::Message << "Invalid pixel at [" << x4 << ";" << y4
2949							   << "]! "
2950								  "Background for index: "
2951							   << 0 << " from range <0:" << m_max_geometry_shader_invocations << ")."
2952							   << tcu::TestLog::EndMessage;
2953
2954			return false;
2955		}
2956	}
2957
2958	for (unsigned int i = 1; i < (unsigned int)m_max_geometry_shader_invocations; ++i)
2959	{
2960		/* Verify that pixel at triangle's center was not modified */
2961		const unsigned int x1 = m_triangle_edge_length * i;
2962		const unsigned int x2 = m_triangle_edge_length * i;
2963		const unsigned int x3 = m_triangle_edge_length * (i + 1) - 1;
2964
2965		const unsigned int y1 = 0;
2966		const unsigned int y2 = m_triangle_edge_length - 1;
2967		const unsigned int y3 = m_triangle_edge_length - 1;
2968
2969		const unsigned int center_x = (x1 + x2 + x3) / 3;
2970		const unsigned int center_y = (y1 + y2 + y3) / 3;
2971
2972		bool is_pixel_valid = comparePixel(result_image, center_x, center_y, m_texture_width, m_texture_height,
2973										   m_texture_pixel_size, 255, 0, 0, 0);
2974
2975		if (false == is_pixel_valid)
2976		{
2977			m_testCtx.getLog() << tcu::TestLog::Message << "Invalid pixel at [" << center_x << ";" << center_y
2978							   << "]! "
2979								  "Triangle index: "
2980							   << i << " from range <0:" << m_max_geometry_shader_invocations << ")."
2981							   << tcu::TestLog::EndMessage;
2982
2983			return false;
2984		}
2985
2986		/* Verify that background's pixel was not modified */
2987		const unsigned int x4 = m_triangle_edge_length * (i + 1) - 1;
2988		const unsigned int y4 = m_triangle_edge_length - 1;
2989
2990		is_pixel_valid =
2991			comparePixel(result_image, x4, y4, m_texture_width, m_texture_height, m_texture_pixel_size, 255, 0, 0, 0);
2992
2993		if (false == is_pixel_valid)
2994		{
2995			m_testCtx.getLog() << tcu::TestLog::Message << "Invalid pixel at [" << x4 << ";" << y4
2996							   << "]! "
2997								  "Background for index: "
2998							   << i << " from range <0:" << m_max_geometry_shader_invocations << ")."
2999							   << tcu::TestLog::EndMessage;
3000
3001			return false;
3002		}
3003	}
3004
3005	return true;
3006}
3007
3008/** Constructor
3009 *
3010 * @param context       Test context
3011 * @param name          Test case's name
3012 * @param description   Test case's description
3013 **/
3014GeometryShaderMaxCombinedTextureUnitsTest::GeometryShaderMaxCombinedTextureUnitsTest(Context&			  context,
3015																					 const ExtParameters& extParams,
3016																					 const char*		  name,
3017																					 const char*		  description)
3018	: GeometryShaderLimitsRenderingBase(context, extParams, name, description)
3019	, m_texture_width(0)
3020	, m_max_combined_texture_units(0)
3021	, m_max_fragment_texture_units(0)
3022	, m_max_geometry_texture_units(0)
3023	, m_max_vertex_texture_units(0)
3024	, m_min_texture_units(0)
3025	, m_n_fragment_texture_units(0)
3026	, m_n_geometry_texture_units(0)
3027	, m_n_texture_units(0)
3028	, m_n_vertex_texture_units(0)
3029{
3030	/* Nothing to be done here */
3031}
3032
3033/** Clears data after draw call and result verification
3034 *
3035 **/
3036void GeometryShaderMaxCombinedTextureUnitsTest::clean()
3037{
3038	/* GL functions */
3039	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3040
3041	/* Bind 0 to all texture units */
3042	for (int i = 0; i < m_n_texture_units; ++i)
3043	{
3044		gl.activeTexture(GL_TEXTURE0 + i);
3045		gl.bindTexture(GL_TEXTURE_2D, 0);
3046	}
3047
3048	/* Delete textures */
3049	for (int i = 0; i < m_n_texture_units; ++i)
3050	{
3051		gl.deleteTextures(1, &m_textures[i].texture_id);
3052	}
3053
3054	m_textures.clear();
3055}
3056
3057/** Get details for draw call
3058 *
3059 *  @param out_primitive_type Type of primitive that will be used by next draw call
3060 *  @param out_n_vertices     Number of vertices that will used with next draw call
3061 **/
3062void GeometryShaderMaxCombinedTextureUnitsTest::getDrawCallDetails(glw::GLenum& out_primitive_type,
3063																   glw::GLuint& out_n_vertices)
3064{
3065	/* Draw GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT points */
3066	out_primitive_type = GL_POINTS;
3067	out_n_vertices	 = m_min_texture_units;
3068}
3069
3070/** Get dimensions and format for texture bind to color attachment 0, get format and type for glReadPixels
3071 *
3072 *  @param out_texture_format      Format for texture used as color attachment 0
3073 *  @param out_texture_read_format Format of data used with glReadPixels
3074 *  @param out_texture_read_type   Type of data used with glReadPixels
3075 *  @param out_texture_width       Width of texture used as color attachment 0
3076 *  @param out_texture_height      Height of texture used as color attachment 0
3077 *  @param out_texture_pixel_size  Size of single pixel in bytes
3078 **/
3079void GeometryShaderMaxCombinedTextureUnitsTest::getFramebufferDetails(
3080	glw::GLenum& out_texture_format, glw::GLenum& out_texture_read_format, glw::GLenum& out_texture_read_type,
3081	glw::GLuint& out_texture_width, glw::GLuint& out_texture_height, unsigned int& out_texture_pixel_size)
3082{
3083	out_texture_format		= GL_R32UI;
3084	out_texture_read_format = GL_RGBA_INTEGER;
3085	out_texture_read_type   = GL_UNSIGNED_INT;
3086	out_texture_width		= m_texture_width;
3087	out_texture_height		= m_texture_height;
3088	out_texture_pixel_size  = 4 * 4;
3089}
3090
3091void GeometryShaderMaxCombinedTextureUnitsTest::getRequiredPointSize(glw::GLfloat& out_point_size)
3092{
3093	out_point_size = (float)m_point_size;
3094}
3095
3096/** Get parts of shaders
3097 *
3098 *  @param out_fragment_shader_parts   Array of fragment shader parts
3099 *  @param out_n_fragment_shader_parts Number of fragment shader parts
3100 *  @param out_geometry_shader_parts   Array of geometry shader parts
3101 *  @param out_n_geometry_shader_parts Number of geometry shader parts
3102 *  @param out_vertex_shader_parts     Array of vertex shader parts
3103 *  @param out_n_vertex_shader_parts   Number of vertex shader parts
3104 **/
3105void GeometryShaderMaxCombinedTextureUnitsTest::getShaderParts(const glw::GLchar* const*& out_fragment_shader_parts,
3106															   unsigned int&			  out_n_fragment_shader_parts,
3107															   const glw::GLchar* const*& out_geometry_shader_parts,
3108															   unsigned int&			  out_n_geometry_shader_parts,
3109															   const glw::GLchar* const*& out_vertex_shader_parts,
3110															   unsigned int&			  out_n_vertex_shader_parts)
3111{
3112	/* GL functions */
3113	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3114
3115	/* Get maximum number of texture units */
3116	gl.getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &m_max_combined_texture_units);
3117	gl.getIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &m_max_vertex_texture_units);
3118	gl.getIntegerv(m_glExtTokens.MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, &m_max_geometry_texture_units);
3119	gl.getIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &m_max_fragment_texture_units);
3120	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call(s) failed");
3121
3122	m_n_texture_units =
3123		de::max(m_max_vertex_texture_units, de::max(m_max_geometry_texture_units, m_max_fragment_texture_units));
3124	m_n_vertex_texture_units = de::max(1, de::min(m_max_combined_texture_units - 2, m_max_vertex_texture_units));
3125	m_n_fragment_texture_units =
3126		de::max(1, de::min(m_max_combined_texture_units - m_n_vertex_texture_units - 1, m_max_fragment_texture_units));
3127	m_n_geometry_texture_units =
3128		de::max(1, de::min(m_max_combined_texture_units - m_n_vertex_texture_units - m_n_fragment_texture_units,
3129						   m_max_geometry_texture_units));
3130	m_min_texture_units =
3131		de::min(m_n_vertex_texture_units, de::min(m_n_fragment_texture_units, m_n_geometry_texture_units));
3132
3133	/* Number of drawn points is equal to GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT */
3134	m_texture_width = m_n_texture_units * m_point_size;
3135
3136	/* Prepare texture units string */
3137	std::stringstream stream_fragment;
3138	stream_fragment << m_n_fragment_texture_units;
3139	m_n_fragment_texture_units_string = stream_fragment.str();
3140
3141	std::stringstream stream_geometry;
3142	stream_geometry << m_n_geometry_texture_units;
3143	m_n_geometry_texture_units_string = stream_geometry.str();
3144
3145	std::stringstream stream_vertex;
3146	stream_vertex << m_n_vertex_texture_units;
3147	m_n_vertex_texture_units_string = stream_vertex.str();
3148
3149	/* Fragment shader parts */
3150	m_fragment_shader_parts[0] = m_fragment_shader_code_preamble;
3151	m_fragment_shader_parts[1] = m_n_fragment_texture_units_string.c_str();
3152	m_fragment_shader_parts[2] = m_fragment_shader_code_body;
3153
3154	out_fragment_shader_parts   = m_fragment_shader_parts;
3155	out_n_fragment_shader_parts = 3;
3156
3157	/* Geometry shader parts */
3158	m_geometry_shader_parts[0] = m_geometry_shader_code_preamble;
3159	m_geometry_shader_parts[1] = m_n_geometry_texture_units_string.c_str();
3160	m_geometry_shader_parts[2] = m_geometry_shader_code_body;
3161
3162	out_geometry_shader_parts   = m_geometry_shader_parts;
3163	out_n_geometry_shader_parts = 3;
3164
3165	/* Vertex shader parts */
3166	m_vertex_shader_parts[0] = m_vertex_shader_code_preamble;
3167	m_vertex_shader_parts[1] = m_n_vertex_texture_units_string.c_str();
3168	m_vertex_shader_parts[2] = m_vertex_shader_code_body;
3169
3170	out_vertex_shader_parts   = m_vertex_shader_parts;
3171	out_n_vertex_shader_parts = 3;
3172}
3173
3174/** Prepare test specific program input for draw call
3175 *
3176 **/
3177void GeometryShaderMaxCombinedTextureUnitsTest::prepareProgramInput()
3178{
3179	/* Retrieve ES entry-points */
3180	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3181
3182	m_textures.resize(m_n_texture_units);
3183
3184	/* Prepare texture storage and fill data */
3185	for (int i = 0; i < m_n_texture_units; ++i)
3186	{
3187		/* Reset texture data to 0 after each 16 iterations */
3188		m_textures[i].data = i % 16;
3189
3190		/* Generate and bind texture */
3191		gl.genTextures(1, &m_textures[i].texture_id);
3192		gl.bindTexture(GL_TEXTURE_2D, m_textures[i].texture_id);
3193
3194		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create texture");
3195
3196		/* Allocate and upload texture data */
3197		gl.texImage2D(GL_TEXTURE_2D, 0 /* level */, GL_R32UI, 1 /* width*/, 1 /* height */, 0 /* border */,
3198					  GL_RED_INTEGER, GL_UNSIGNED_INT, &m_textures[i].data);
3199
3200		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3201		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3202
3203		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create storage and fill texture with data");
3204	}
3205
3206	/* Prepare sampler uniforms */
3207	for (int i = 0; i < m_n_texture_units; ++i)
3208	{
3209		/* Prepare name of sampler */
3210		std::stringstream stream;
3211
3212		stream << "sampler[" << i << "]";
3213
3214		/* Get sampler location */
3215		glw::GLint sampler_location = gl.getUniformLocation(m_program_object_id, stream.str().c_str());
3216
3217		if (-1 == sampler_location || GL_NO_ERROR != gl.getError())
3218		{
3219			TCU_FAIL("Failed to get uniform usampler2D location");
3220		}
3221
3222		/* Set uniform at sampler location value to index of texture unit */
3223		gl.uniform1i(sampler_location, i);
3224
3225		if (GL_NO_ERROR != gl.getError())
3226		{
3227			m_testCtx.getLog() << tcu::TestLog::Message << "Failed to set uniform at location: " << sampler_location
3228							   << " to value: " << i << tcu::TestLog::EndMessage;
3229
3230			TCU_FAIL("Failed to get uniform isampler2D location");
3231		}
3232	}
3233
3234	/* Bind textures to texture units */
3235	for (int i = 0; i < m_n_texture_units; ++i)
3236	{
3237		gl.activeTexture(GL_TEXTURE0 + i);
3238		gl.bindTexture(GL_TEXTURE_2D, m_textures[i].texture_id);
3239
3240		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3241		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3242	}
3243
3244	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set texture units up");
3245}
3246
3247/** Verify rendered image
3248 *
3249 *  @param data Image to verify
3250 *
3251 *  @return true  Image pixels match expected values
3252 *          false Some pixels have wrong values
3253 **/
3254bool GeometryShaderMaxCombinedTextureUnitsTest::verifyResult(const void* data)
3255{
3256	const unsigned char* result_image = (const unsigned char*)data;
3257	const unsigned int   line_size	= m_texture_width * m_texture_pixel_size;
3258
3259	/* For each drawn point */
3260	for (glw::GLint point = 0; point < m_n_texture_units; ++point)
3261	{
3262		const unsigned int last_vertex_index = de::min(point, m_n_vertex_texture_units);
3263
3264		glw::GLint expected_vertex_value   = 0;
3265		glw::GLint expected_geometry_value = 0;
3266		glw::GLint expected_fragment_value = 0;
3267
3268		for (unsigned int i = 0; i < last_vertex_index; ++i)
3269		{
3270			expected_vertex_value += m_textures[i].data;
3271		}
3272
3273		for (unsigned int i = 0; i < last_vertex_index; ++i)
3274		{
3275			expected_geometry_value += m_textures[i].data;
3276		}
3277
3278		for (unsigned int i = 0; i < last_vertex_index; ++i)
3279		{
3280			expected_fragment_value += m_textures[i].data;
3281		}
3282
3283		const glw::GLint   expected_value = expected_vertex_value + expected_geometry_value + expected_fragment_value;
3284		const unsigned int point_offset   = point * m_texture_pixel_size * m_point_size;
3285
3286		/* Verify all pixels that belong to point, area m_point_size x m_point_size */
3287		for (unsigned int y = 0; y < m_point_size; ++y)
3288		{
3289			const unsigned int line_offset		  = y * line_size;
3290			const unsigned int first_texel_offset = line_offset + point_offset;
3291
3292			for (unsigned int x = 0; x < m_point_size; ++x)
3293			{
3294				const unsigned int texel_offset = first_texel_offset + x * m_texture_pixel_size;
3295
3296				if (0 != memcmp(result_image + texel_offset, &expected_value, sizeof(expected_value)))
3297				{
3298					glw::GLint* result_value = (glw::GLint*)(result_image + texel_offset);
3299
3300					m_testCtx.getLog() << tcu::TestLog::Message << "Wrong result!"
3301																   " Expected: "
3302									   << expected_value << " Extracted: " << *result_value << " Point: " << point
3303									   << " X: " << x << " Y: " << y << tcu::TestLog::EndMessage;
3304
3305					return false;
3306				}
3307			}
3308		}
3309	}
3310
3311	return true;
3312}
3313
3314} /* glcts */
3315