xref: /aosp_15_r20/external/deqp/external/openglcts/modules/gl/gl4cShaderSubroutineTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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 /**
25  * \file  gl4cShaderSubroutineTests.cpp
26  * \brief Implements conformance tests for "Shader Subroutine" functionality.
27  */ /*-------------------------------------------------------------------*/
28 
29 #include "gl4cShaderSubroutineTests.hpp"
30 #include "gluContextInfo.hpp"
31 #include "glwEnums.hpp"
32 #include "glwFunctions.hpp"
33 #include "tcuMatrix.hpp"
34 #include <cmath>
35 #include <cstring>
36 #include <deMath.h>
37 
38 using namespace glw;
39 
40 namespace gl4cts
41 {
42 namespace ShaderSubroutine
43 {
44 /** Constructor.
45  *
46  * @param context CTS context.
47  **/
buffer(deqp::Context & context)48 Utils::buffer::buffer(deqp::Context &context) : m_id(0), m_context(context)
49 {
50 }
51 
52 /** Destructor
53  *
54  **/
~buffer()55 Utils::buffer::~buffer()
56 {
57     if (0 != m_id)
58     {
59         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
60 
61         gl.deleteBuffers(1, &m_id);
62         m_id = 0;
63     }
64 }
65 
66 /** Execute BindBufferRange
67  *
68  * @param target <target> parameter
69  * @param index  <index> parameter
70  * @param offset <offset> parameter
71  * @param size   <size> parameter
72  **/
bindRange(glw::GLenum target,glw::GLuint index,glw::GLintptr offset,glw::GLsizeiptr size)73 void Utils::buffer::bindRange(glw::GLenum target, glw::GLuint index, glw::GLintptr offset, glw::GLsizeiptr size)
74 {
75     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
76 
77     gl.bindBufferRange(target, index, m_id, offset, size);
78     GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferRange");
79 }
80 
81 /** Execute GenBuffer
82  *
83  **/
generate()84 void Utils::buffer::generate()
85 {
86     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
87 
88     gl.genBuffers(1, &m_id);
89     GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers");
90 }
91 
92 /** Execute BufferData
93  *
94  * @param target <target> parameter
95  * @param size   <size> parameter
96  * @param data   <data> parameter
97  * @param usage  <usage> parameter
98  **/
update(glw::GLenum target,glw::GLsizeiptr size,glw::GLvoid * data,glw::GLenum usage)99 void Utils::buffer::update(glw::GLenum target, glw::GLsizeiptr size, glw::GLvoid *data, glw::GLenum usage)
100 {
101     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
102 
103     gl.bindBuffer(target, m_id);
104     GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer");
105 
106     gl.bufferData(target, size, data, usage);
107     GLU_EXPECT_NO_ERROR(gl.getError(), "bufferData");
108 }
109 
110 /** Constructor
111  *
112  * @param context CTS context
113  **/
framebuffer(deqp::Context & context)114 Utils::framebuffer::framebuffer(deqp::Context &context) : m_id(0), m_context(context)
115 {
116     /* Nothing to be done here */
117 }
118 
119 /** Destructor
120  *
121  **/
~framebuffer()122 Utils::framebuffer::~framebuffer()
123 {
124     if (0 != m_id)
125     {
126         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
127 
128         gl.deleteFramebuffers(1, &m_id);
129         m_id = 0;
130     }
131 }
132 
133 /** Attach texture to specified attachment
134  *
135  * @param attachment Attachment
136  * @param texture_id Texture id
137  * @param width      Texture width
138  * @param height     Texture height
139  **/
attachTexture(glw::GLenum attachment,glw::GLuint texture_id,glw::GLuint width,glw::GLuint height)140 void Utils::framebuffer::attachTexture(glw::GLenum attachment, glw::GLuint texture_id, glw::GLuint width,
141                                        glw::GLuint height)
142 {
143     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
144 
145     bind();
146 
147     gl.bindTexture(GL_TEXTURE_2D, texture_id);
148     GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
149 
150     gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, GL_TEXTURE_2D, texture_id, 0 /* level */);
151 
152     GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture2D");
153 
154     gl.viewport(0 /* x */, 0 /* y */, width, height);
155     GLU_EXPECT_NO_ERROR(gl.getError(), "Viewport");
156 }
157 
158 /** Binds framebuffer to DRAW_FRAMEBUFFER
159  *
160  **/
bind()161 void Utils::framebuffer::bind()
162 {
163     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
164 
165     gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_id);
166     GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
167 }
168 
169 /** Clear framebuffer
170  *
171  * @param mask <mask> parameter of glClear. Decides which shall be cleared
172  **/
clear(glw::GLenum mask)173 void Utils::framebuffer::clear(glw::GLenum mask)
174 {
175     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
176 
177     gl.clear(mask);
178     GLU_EXPECT_NO_ERROR(gl.getError(), "Clear");
179 }
180 
181 /** Specifie clear color
182  *
183  * @param red   Red channel
184  * @param green Green channel
185  * @param blue  Blue channel
186  * @param alpha Alpha channel
187  **/
clearColor(GLfloat red,GLfloat green,GLfloat blue,GLfloat alpha)188 void Utils::framebuffer::clearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
189 {
190     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
191 
192     gl.clearColor(red, green, blue, alpha);
193     GLU_EXPECT_NO_ERROR(gl.getError(), "ClearColor");
194 }
195 
196 /** Generate framebuffer
197  *
198  **/
generate()199 void Utils::framebuffer::generate()
200 {
201     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
202 
203     gl.genFramebuffers(1, &m_id);
204     GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers");
205 }
206 
207 const glw::GLenum Utils::program::ARB_COMPUTE_SHADER = 0x91B9;
208 
209 /** Constructor.
210  *
211  * @param context CTS context.
212  **/
program(deqp::Context & context)213 Utils::program::program(deqp::Context &context)
214     : m_compute_shader_id(0)
215     , m_fragment_shader_id(0)
216     , m_geometry_shader_id(0)
217     , m_program_object_id(0)
218     , m_tesselation_control_shader_id(0)
219     , m_tesselation_evaluation_shader_id(0)
220     , m_vertex_shader_id(0)
221     , m_context(context)
222 {
223     /* Nothing to be done here */
224 }
225 
226 /** Destructor
227  *
228  **/
~program()229 Utils::program::~program()
230 {
231     remove();
232 }
233 
234 /** Build program
235  *
236  * @param compute_shader_code                Compute shader source code
237  * @param fragment_shader_code               Fragment shader source code
238  * @param geometry_shader_code               Geometry shader source code
239  * @param tesselation_control_shader_code    Tesselation control shader source code
240  * @param tesselation_evaluation_shader_code Tesselation evaluation shader source code
241  * @param vertex_shader_code                 Vertex shader source code
242  * @param varying_names                      Array of strings containing names of varyings to be captured with transfrom feedback
243  * @param n_varying_names                    Number of varyings to be captured with transfrom feedback
244  * @param is_separable                       Selects if monolithis or separable program should be built. Defaults to false
245  **/
build(const glw::GLchar * compute_shader_code,const glw::GLchar * fragment_shader_code,const glw::GLchar * geometry_shader_code,const glw::GLchar * tesselation_control_shader_code,const glw::GLchar * tesselation_evaluation_shader_code,const glw::GLchar * vertex_shader_code,const glw::GLchar * const * varying_names,glw::GLuint n_varying_names,bool is_separable)246 void Utils::program::build(const glw::GLchar *compute_shader_code, const glw::GLchar *fragment_shader_code,
247                            const glw::GLchar *geometry_shader_code, const glw::GLchar *tesselation_control_shader_code,
248                            const glw::GLchar *tesselation_evaluation_shader_code, const glw::GLchar *vertex_shader_code,
249                            const glw::GLchar *const *varying_names, glw::GLuint n_varying_names, bool is_separable)
250 {
251     /* GL entry points */
252     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
253 
254     /* Create shader objects and compile */
255     if (0 != compute_shader_code)
256     {
257         m_compute_shader_id = gl.createShader(ARB_COMPUTE_SHADER);
258         GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
259 
260         compile(m_compute_shader_id, compute_shader_code);
261     }
262 
263     if (0 != fragment_shader_code)
264     {
265         m_fragment_shader_id = gl.createShader(GL_FRAGMENT_SHADER);
266         GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
267 
268         compile(m_fragment_shader_id, fragment_shader_code);
269     }
270 
271     if (0 != geometry_shader_code)
272     {
273         m_geometry_shader_id = gl.createShader(GL_GEOMETRY_SHADER);
274         GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
275 
276         compile(m_geometry_shader_id, geometry_shader_code);
277     }
278 
279     if (0 != tesselation_control_shader_code)
280     {
281         m_tesselation_control_shader_id = gl.createShader(GL_TESS_CONTROL_SHADER);
282         GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
283 
284         compile(m_tesselation_control_shader_id, tesselation_control_shader_code);
285     }
286 
287     if (0 != tesselation_evaluation_shader_code)
288     {
289         m_tesselation_evaluation_shader_id = gl.createShader(GL_TESS_EVALUATION_SHADER);
290         GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
291 
292         compile(m_tesselation_evaluation_shader_id, tesselation_evaluation_shader_code);
293     }
294 
295     if (0 != vertex_shader_code)
296     {
297         m_vertex_shader_id = gl.createShader(GL_VERTEX_SHADER);
298         GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
299 
300         compile(m_vertex_shader_id, vertex_shader_code);
301     }
302 
303     /* Create program object */
304     m_program_object_id = gl.createProgram();
305     GLU_EXPECT_NO_ERROR(gl.getError(), "CreateProgram");
306 
307     /* Set up captyured varyings' names */
308     if (0 != n_varying_names)
309     {
310         gl.transformFeedbackVaryings(m_program_object_id, n_varying_names, varying_names, GL_INTERLEAVED_ATTRIBS);
311         GLU_EXPECT_NO_ERROR(gl.getError(), "TransformFeedbackVaryings");
312     }
313 
314     /* Set separable parameter */
315     if (true == is_separable)
316     {
317         gl.programParameteri(m_program_object_id, GL_PROGRAM_SEPARABLE, GL_TRUE);
318         GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramParameteri");
319     }
320 
321     /* Link program */
322     link();
323 }
324 
325 /** Compile shader
326  *
327  * @param shader_id   Shader object id
328  * @param shader_code Shader source code
329  **/
compile(glw::GLuint shader_id,const glw::GLchar * shader_code) const330 void Utils::program::compile(glw::GLuint shader_id, const glw::GLchar *shader_code) const
331 {
332     /* GL entry points */
333     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
334 
335     /* Compilation status */
336     glw::GLint status = GL_FALSE;
337 
338     /* Set source code */
339     gl.shaderSource(shader_id, 1 /* count */, &shader_code, 0);
340     GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderSource");
341 
342     /* Compile */
343     gl.compileShader(shader_id);
344     GLU_EXPECT_NO_ERROR(gl.getError(), "CompileShader");
345 
346     /* Get compilation status */
347     gl.getShaderiv(shader_id, GL_COMPILE_STATUS, &status);
348     GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
349 
350     /* Log compilation error */
351     if (GL_TRUE != status)
352     {
353         glw::GLint length = 0;
354         std::vector<glw::GLchar> message;
355 
356         /* Error log length */
357         gl.getShaderiv(shader_id, GL_INFO_LOG_LENGTH, &length);
358         GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
359 
360         /* Prepare storage */
361         message.resize(length);
362 
363         /* Get error log */
364         gl.getShaderInfoLog(shader_id, length, 0, &message[0]);
365         GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderInfoLog");
366 
367         /* Log */
368         m_context.getTestContext().getLog() << tcu::TestLog::Message << "Failed to compile shader:\n"
369                                             << &message[0] << "\nShader source\n"
370                                             << shader_code << tcu::TestLog::EndMessage;
371 
372         TCU_FAIL("Failed to compile shader");
373     }
374 }
375 
376 /** Checks whether the tested driver supports GL_ARB_get_program_binary
377  *
378  *  @return true if the extension is supported and, also, at least one binary format.
379  **/
isProgramBinarySupported() const380 bool Utils::program::isProgramBinarySupported() const
381 {
382     glw::GLint n_program_binary_formats = 0;
383 
384     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
385 
386     if (m_context.getContextInfo().isExtensionSupported("GL_ARB_get_program_binary"))
387     {
388         gl.getIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &n_program_binary_formats);
389         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed.");
390     }
391 
392     return n_program_binary_formats > 0;
393 }
394 
395 /** Create program from provided binary
396  *
397  * @param binary        Buffer with binary form of program
398  * @param binary_format Format of <binary> data
399  **/
createFromBinary(const std::vector<GLubyte> & binary,GLenum binary_format)400 void Utils::program::createFromBinary(const std::vector<GLubyte> &binary, GLenum binary_format)
401 {
402     /* GL entry points */
403     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
404 
405     /* Create program object */
406     m_program_object_id = gl.createProgram();
407     GLU_EXPECT_NO_ERROR(gl.getError(), "CreateProgram");
408 
409     gl.programBinary(m_program_object_id, binary_format, &binary[0], (GLsizei)binary.size());
410     GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramBinary");
411 }
412 
413 /** Get binary form of program
414  *
415  * @param binary        Buffer for binary data
416  * @param binary_format Format of binary data
417  **/
getBinary(std::vector<GLubyte> & binary,GLenum & binary_format) const418 void Utils::program::getBinary(std::vector<GLubyte> &binary, GLenum &binary_format) const
419 {
420     /* GL entry points */
421     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
422 
423     /* Get binary size */
424     GLint length = 0;
425     gl.getProgramiv(m_program_object_id, GL_PROGRAM_BINARY_LENGTH, &length);
426     GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
427 
428     /* Allocate storage */
429     binary.resize(length);
430 
431     /* Get binary */
432     gl.getProgramBinary(m_program_object_id, (GLsizei)binary.size(), &length, &binary_format, &binary[0]);
433     GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramBinary");
434 }
435 
436 /** Get subroutine index
437  *
438  * @param subroutine_name Subroutine name
439  *
440  * @return Index of subroutine
441  **/
getSubroutineIndex(const glw::GLchar * subroutine_name,glw::GLenum shader_stage) const442 GLuint Utils::program::getSubroutineIndex(const glw::GLchar *subroutine_name, glw::GLenum shader_stage) const
443 {
444     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
445     GLuint index             = -1;
446 
447     index = gl.getSubroutineIndex(m_program_object_id, shader_stage, subroutine_name);
448     GLU_EXPECT_NO_ERROR(gl.getError(), "GetSubroutineIndex");
449 
450     if (GL_INVALID_INDEX == index)
451     {
452         m_context.getTestContext().getLog() << tcu::TestLog::Message << "Subroutine: " << subroutine_name
453                                             << " is not available" << tcu::TestLog::EndMessage;
454 
455         TCU_FAIL("Subroutine is not available");
456     }
457 
458     return index;
459 }
460 
461 /** Get subroutine uniform location
462  *
463  * @param uniform_name Subroutine uniform name
464  *
465  * @return Location of subroutine uniform
466  **/
getSubroutineUniformLocation(const glw::GLchar * uniform_name,glw::GLenum shader_stage) const467 GLint Utils::program::getSubroutineUniformLocation(const glw::GLchar *uniform_name, glw::GLenum shader_stage) const
468 {
469     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
470     GLint location           = -1;
471 
472     location = gl.getSubroutineUniformLocation(m_program_object_id, shader_stage, uniform_name);
473     GLU_EXPECT_NO_ERROR(gl.getError(), "GetSubroutineUniformLocation");
474 
475     if (-1 == location)
476     {
477         m_context.getTestContext().getLog() << tcu::TestLog::Message << "Subroutine uniform: " << uniform_name
478                                             << " is not available" << tcu::TestLog::EndMessage;
479 
480         TCU_FAIL("Subroutine uniform is not available");
481     }
482 
483     return location;
484 }
485 
486 /** Get uniform location
487  *
488  * @param uniform_name Subroutine uniform name
489  *
490  * @return Location of uniform
491  **/
getUniformLocation(const glw::GLchar * uniform_name) const492 GLint Utils::program::getUniformLocation(const glw::GLchar *uniform_name) const
493 {
494     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
495     GLint location           = -1;
496 
497     location = gl.getUniformLocation(m_program_object_id, uniform_name);
498     GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation");
499 
500     if (-1 == location)
501     {
502         m_context.getTestContext().getLog()
503             << tcu::TestLog::Message << "Uniform: " << uniform_name << " is not available" << tcu::TestLog::EndMessage;
504 
505         TCU_FAIL("Uniform is not available");
506     }
507 
508     return location;
509 }
510 
511 /** Attach shaders and link program
512  *
513  **/
link() const514 void Utils::program::link() const
515 {
516     /* GL entry points */
517     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
518 
519     /* Link status */
520     glw::GLint status = GL_FALSE;
521 
522     /* Attach shaders */
523     if (0 != m_compute_shader_id)
524     {
525         gl.attachShader(m_program_object_id, m_compute_shader_id);
526         GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
527     }
528 
529     if (0 != m_fragment_shader_id)
530     {
531         gl.attachShader(m_program_object_id, m_fragment_shader_id);
532         GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
533     }
534 
535     if (0 != m_geometry_shader_id)
536     {
537         gl.attachShader(m_program_object_id, m_geometry_shader_id);
538         GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
539     }
540 
541     if (0 != m_tesselation_control_shader_id)
542     {
543         gl.attachShader(m_program_object_id, m_tesselation_control_shader_id);
544         GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
545     }
546 
547     if (0 != m_tesselation_evaluation_shader_id)
548     {
549         gl.attachShader(m_program_object_id, m_tesselation_evaluation_shader_id);
550         GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
551     }
552 
553     if (0 != m_vertex_shader_id)
554     {
555         gl.attachShader(m_program_object_id, m_vertex_shader_id);
556         GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
557     }
558 
559     /* Link */
560     gl.linkProgram(m_program_object_id);
561     GLU_EXPECT_NO_ERROR(gl.getError(), "LinkProgram");
562 
563     /* Get link status */
564     gl.getProgramiv(m_program_object_id, GL_LINK_STATUS, &status);
565     GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
566 
567     /* Log link error */
568     if (GL_TRUE != status)
569     {
570         glw::GLint length = 0;
571         std::vector<glw::GLchar> message;
572 
573         /* Get error log length */
574         gl.getProgramiv(m_program_object_id, GL_INFO_LOG_LENGTH, &length);
575         GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
576 
577         message.resize(length);
578 
579         /* Get error log */
580         gl.getProgramInfoLog(m_program_object_id, length, 0, &message[0]);
581         GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramInfoLog");
582 
583         /* Log */
584         m_context.getTestContext().getLog() << tcu::TestLog::Message << "Failed to link program:\n"
585                                             << &message[0] << tcu::TestLog::EndMessage;
586 
587         TCU_FAIL("Failed to link program");
588     }
589 }
590 
591 /** Delete program object and all attached shaders
592  *
593  **/
remove()594 void Utils::program::remove()
595 {
596     /* GL entry points */
597     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
598 
599     /* Make sure program object is no longer used by GL */
600     gl.useProgram(0);
601 
602     /* Clean program object */
603     if (0 != m_program_object_id)
604     {
605         gl.deleteProgram(m_program_object_id);
606         m_program_object_id = 0;
607     }
608 
609     /* Clean shaders */
610     if (0 != m_compute_shader_id)
611     {
612         gl.deleteShader(m_compute_shader_id);
613         m_compute_shader_id = 0;
614     }
615 
616     if (0 != m_fragment_shader_id)
617     {
618         gl.deleteShader(m_fragment_shader_id);
619         m_fragment_shader_id = 0;
620     }
621 
622     if (0 != m_geometry_shader_id)
623     {
624         gl.deleteShader(m_geometry_shader_id);
625         m_geometry_shader_id = 0;
626     }
627 
628     if (0 != m_tesselation_control_shader_id)
629     {
630         gl.deleteShader(m_tesselation_control_shader_id);
631         m_tesselation_control_shader_id = 0;
632     }
633 
634     if (0 != m_tesselation_evaluation_shader_id)
635     {
636         gl.deleteShader(m_tesselation_evaluation_shader_id);
637         m_tesselation_evaluation_shader_id = 0;
638     }
639 
640     if (0 != m_vertex_shader_id)
641     {
642         gl.deleteShader(m_vertex_shader_id);
643         m_vertex_shader_id = 0;
644     }
645 }
646 
647 /** Execute UseProgram
648  *
649  **/
use() const650 void Utils::program::use() const
651 {
652     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
653 
654     gl.useProgram(m_program_object_id);
655     GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
656 }
657 
658 /** Constructor.
659  *
660  * @param context CTS context.
661  **/
texture(deqp::Context & context)662 Utils::texture::texture(deqp::Context &context) : m_id(0), m_context(context)
663 {
664     /* Nothing to done here */
665 }
666 
667 /** Destructor
668  *
669  **/
~texture()670 Utils::texture::~texture()
671 {
672     if (0 != m_id)
673     {
674         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
675 
676         gl.deleteTextures(1, &m_id);
677         m_id = 0;
678     }
679 }
680 
681 /** Bind texture to GL_TEXTURE_2D
682  *
683  **/
bind()684 void Utils::texture::bind()
685 {
686     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
687 
688     gl.bindTexture(GL_TEXTURE_2D, m_id);
689     GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
690 }
691 
692 /** Create 2d texture
693  *
694  * @param width           Width of texture
695  * @param height          Height of texture
696  * @param internal_format Internal format of texture
697  **/
create(glw::GLuint width,glw::GLuint height,glw::GLenum internal_format)698 void Utils::texture::create(glw::GLuint width, glw::GLuint height, glw::GLenum internal_format)
699 {
700     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
701 
702     gl.genTextures(1, &m_id);
703     GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures");
704 
705     bind();
706 
707     gl.texStorage2D(GL_TEXTURE_2D, 1 /* levels */, internal_format, width, height);
708     GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D");
709 }
710 
711 /** Get contents of texture
712  *
713  * @param format   Format of image
714  * @param type     Type of image
715  * @param out_data Buffer for image
716  **/
get(glw::GLenum format,glw::GLenum type,glw::GLvoid * out_data)717 void Utils::texture::get(glw::GLenum format, glw::GLenum type, glw::GLvoid *out_data)
718 {
719     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
720 
721     bind();
722 
723     gl.getTexImage(GL_TEXTURE_2D, 0, format, type, out_data);
724     GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexImage");
725 }
726 
727 /** Update contents of texture
728  *
729  * @param width  Width of texture
730  * @param height Height of texture
731  * @param format Format of data
732  * @param type   Type of data
733  * @param data   Buffer with image
734  **/
update(glw::GLuint width,glw::GLuint height,glw::GLenum format,glw::GLenum type,glw::GLvoid * data)735 void Utils::texture::update(glw::GLuint width, glw::GLuint height, glw::GLenum format, glw::GLenum type,
736                             glw::GLvoid *data)
737 {
738     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
739 
740     bind();
741 
742     gl.texSubImage2D(GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, width, height, format, type, data);
743     GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D");
744 }
745 
746 /** Constructor.
747  *
748  * @param context CTS context.
749  **/
vertexArray(deqp::Context & context)750 Utils::vertexArray::vertexArray(deqp::Context &context) : m_id(0), m_context(context)
751 {
752 }
753 
754 /** Destructor
755  *
756  **/
~vertexArray()757 Utils::vertexArray::~vertexArray()
758 {
759     if (0 != m_id)
760     {
761         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
762 
763         gl.deleteVertexArrays(1, &m_id);
764 
765         m_id = 0;
766     }
767 }
768 
769 /** Execute BindVertexArray
770  *
771  **/
bind()772 void Utils::vertexArray::bind()
773 {
774     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
775 
776     gl.bindVertexArray(m_id);
777     GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArray");
778 }
779 
780 /** Execute GenVertexArrays
781  *
782  **/
generate()783 void Utils::vertexArray::generate()
784 {
785     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
786 
787     gl.genVertexArrays(1, &m_id);
788     GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays");
789 }
790 
791 /** Builds a program object consisting of up to 5 shader stages
792  *  (vertex/tessellation control/tessellation evaluation/geometry/fragment).
793  *  The shaders are attached to the program object, then compiled. Finally,
794  *  the program object is linked.
795  *
796  *  XFB can be optionally configured for the program object.
797  *
798  *  Should an error be reported by GL implementation, a TestError
799  *  exception will be thrown.
800  *
801  *  @param gl             OpenGL functions from the active rendering context.
802  *  @param vs_body        Body to use for the vertex shader. Can be an empty string.
803  *  @param tc_body        Body to use for the tessellation control shader. Can be
804  *                        an empty string.
805  *  @param te_body        Body to use for the tessellation evaluation shader. Can be
806  *                        an empty string.
807  *  @param gs_body        Body to use for the geometry shader. Can be an empty string.
808  *  @param fs_body        Body to use for the fragment shader. Can be an empty string.
809  *  @param xfb_varyings   An array of names of varyings to use for XFB. Can be NULL.
810  *  @param n_xfb_varyings Amount of XFB varyings defined in @param xfb_varyings.Can be 0.
811  *  @param out_vs_id      Deref will be used to store GL id of a generated vertex shader.
812  *                        Can be NULL in which case no vertex shader will be used for the
813  *                        program object.
814  *  @param out_tc_id      Deref will be used to store GL id of a generated tess control shader.
815  *                        Can be NULL in which case no tess control shader will be used for the
816  *                        program object.
817  *  @param out_te_id      Deref will be used to store GL id of a generated tess evaluation shader.
818  *                        Can be NULL in which case no tess evaluation shader will be used for the
819  *                        program object.
820  *  @param out_gs_id      Deref will be used to store GL id of a generated geometry shader.
821  *                        Can be NULL in which case no geometry shader will be used for the
822  *                        program object.
823  *  @param out_fs_id      Deref will be used to store GL id of a generated fragment shader.
824  *                        Can be NULL in which case no fragment shader will be used for the
825  *                        program object.
826  *  @param out_po_id      Deref will be used to store GL id of a generated program object.
827  *                        Must not be NULL.
828  *
829  *  @return true if the program was built successfully, false otherwise.
830  *  */
buildProgram(const glw::Functions & gl,const std::string & vs_body,const std::string & tc_body,const std::string & te_body,const std::string & gs_body,const std::string & fs_body,const glw::GLchar ** xfb_varyings,const unsigned int & n_xfb_varyings,glw::GLuint * out_vs_id,glw::GLuint * out_tc_id,glw::GLuint * out_te_id,glw::GLuint * out_gs_id,glw::GLuint * out_fs_id,glw::GLuint * out_po_id)831 bool Utils::buildProgram(const glw::Functions &gl, const std::string &vs_body, const std::string &tc_body,
832                          const std::string &te_body, const std::string &gs_body, const std::string &fs_body,
833                          const glw::GLchar **xfb_varyings, const unsigned int &n_xfb_varyings, glw::GLuint *out_vs_id,
834                          glw::GLuint *out_tc_id, glw::GLuint *out_te_id, glw::GLuint *out_gs_id, glw::GLuint *out_fs_id,
835                          glw::GLuint *out_po_id)
836 {
837     bool result = false;
838 
839     /* Link the program object */
840     glw::GLint link_status = GL_FALSE;
841 
842     /* Create objects, set up shader bodies and attach all requested shaders to the program object */
843     *out_po_id = gl.createProgram();
844     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
845 
846     if (out_vs_id != DE_NULL)
847     {
848         const char *vs_body_raw_ptr = vs_body.c_str();
849 
850         *out_vs_id = gl.createShader(GL_VERTEX_SHADER);
851         GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
852 
853         gl.attachShader(*out_po_id, *out_vs_id);
854         GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
855 
856         gl.shaderSource(*out_vs_id, 1 /* count */, &vs_body_raw_ptr, DE_NULL /* length */);
857         GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
858     }
859 
860     if (out_tc_id != DE_NULL)
861     {
862         const char *tc_body_raw_ptr = tc_body.c_str();
863 
864         *out_tc_id = gl.createShader(GL_TESS_CONTROL_SHADER);
865         GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
866 
867         gl.attachShader(*out_po_id, *out_tc_id);
868         GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
869 
870         gl.shaderSource(*out_tc_id, 1 /* count */, &tc_body_raw_ptr, DE_NULL /* length */);
871         GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
872     }
873 
874     if (out_te_id != DE_NULL)
875     {
876         const char *te_body_raw_ptr = te_body.c_str();
877 
878         *out_te_id = gl.createShader(GL_TESS_EVALUATION_SHADER);
879         GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
880 
881         gl.attachShader(*out_po_id, *out_te_id);
882         GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
883 
884         gl.shaderSource(*out_te_id, 1 /* count */, &te_body_raw_ptr, DE_NULL /* length */);
885         GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
886     }
887 
888     if (out_gs_id != DE_NULL)
889     {
890         const char *gs_body_raw_ptr = gs_body.c_str();
891 
892         *out_gs_id = gl.createShader(GL_GEOMETRY_SHADER);
893         GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
894 
895         gl.attachShader(*out_po_id, *out_gs_id);
896         GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
897 
898         gl.shaderSource(*out_gs_id, 1 /* count */, &gs_body_raw_ptr, DE_NULL /* length */);
899         GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
900     }
901 
902     if (out_fs_id != DE_NULL)
903     {
904         const char *fs_body_raw_ptr = fs_body.c_str();
905 
906         *out_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
907         GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
908 
909         gl.attachShader(*out_po_id, *out_fs_id);
910         GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
911 
912         gl.shaderSource(*out_fs_id, 1 /* count */, &fs_body_raw_ptr, DE_NULL /* length */);
913         GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
914     }
915 
916     /* Compile all shaders */
917     const glw::GLuint so_ids[] = {(out_vs_id != DE_NULL) ? *out_vs_id : 0, (out_tc_id != DE_NULL) ? *out_tc_id : 0,
918                                   (out_te_id != DE_NULL) ? *out_te_id : 0, (out_gs_id != DE_NULL) ? *out_gs_id : 0,
919                                   (out_fs_id != DE_NULL) ? *out_fs_id : 0};
920     const unsigned int n_so_ids = sizeof(so_ids) / sizeof(so_ids[0]);
921 
922     for (unsigned int n_so_id = 0; n_so_id < n_so_ids; ++n_so_id)
923     {
924         glw::GLuint so_id = so_ids[n_so_id];
925 
926         if (so_id != 0)
927         {
928             glw::GLint compile_status = GL_FALSE;
929 
930             gl.compileShader(so_id);
931             GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
932 
933             gl.getShaderiv(so_id, GL_COMPILE_STATUS, &compile_status);
934             GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
935 
936             if (compile_status != GL_TRUE)
937             {
938                 goto end;
939             }
940         } /* if (so_id != 0) */
941     }     /* for (all shader objects) */
942 
943     /* Set up XFB */
944     if (xfb_varyings != NULL)
945     {
946         gl.transformFeedbackVaryings(*out_po_id, n_xfb_varyings, xfb_varyings, GL_INTERLEAVED_ATTRIBS);
947         GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed.");
948     }
949 
950     gl.linkProgram(*out_po_id);
951     GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
952 
953     gl.getProgramiv(*out_po_id, GL_LINK_STATUS, &link_status);
954     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
955 
956     if (link_status != GL_TRUE)
957     {
958         goto end;
959     }
960 
961     /* All done */
962     result = true;
963 
964 end:
965     return result;
966 }
967 
968 /** Retrieves base variable type for user-specified variable type
969  *  (eg. float for vec4)
970  *
971  *  @param variable_type Variable type to use for the query.
972  *
973  *  @return As per description.
974  **/
getBaseVariableType(const _variable_type & variable_type)975 Utils::_variable_type Utils::getBaseVariableType(const _variable_type &variable_type)
976 {
977     _variable_type result = VARIABLE_TYPE_UNKNOWN;
978 
979     switch (variable_type)
980     {
981     case VARIABLE_TYPE_BOOL:
982     case VARIABLE_TYPE_BVEC2:
983     case VARIABLE_TYPE_BVEC3:
984     case VARIABLE_TYPE_BVEC4:
985     {
986         result = VARIABLE_TYPE_BOOL;
987 
988         break;
989     }
990 
991     case VARIABLE_TYPE_DOUBLE:
992     case VARIABLE_TYPE_DVEC2:
993     case VARIABLE_TYPE_DVEC3:
994     case VARIABLE_TYPE_DVEC4:
995     {
996         result = VARIABLE_TYPE_DOUBLE;
997 
998         break;
999     }
1000 
1001     case VARIABLE_TYPE_FLOAT:
1002     case VARIABLE_TYPE_MAT2:
1003     case VARIABLE_TYPE_MAT2X3:
1004     case VARIABLE_TYPE_MAT2X4:
1005     case VARIABLE_TYPE_MAT3:
1006     case VARIABLE_TYPE_MAT3X2:
1007     case VARIABLE_TYPE_MAT3X4:
1008     case VARIABLE_TYPE_MAT4:
1009     case VARIABLE_TYPE_MAT4X2:
1010     case VARIABLE_TYPE_MAT4X3:
1011     case VARIABLE_TYPE_VEC2:
1012     case VARIABLE_TYPE_VEC3:
1013     case VARIABLE_TYPE_VEC4:
1014     {
1015         result = VARIABLE_TYPE_FLOAT;
1016 
1017         break;
1018     }
1019 
1020     case VARIABLE_TYPE_INT:
1021     case VARIABLE_TYPE_IVEC2:
1022     case VARIABLE_TYPE_IVEC3:
1023     case VARIABLE_TYPE_IVEC4:
1024     {
1025         result = VARIABLE_TYPE_INT;
1026 
1027         break;
1028     }
1029 
1030     case VARIABLE_TYPE_UINT:
1031     case VARIABLE_TYPE_UVEC2:
1032     case VARIABLE_TYPE_UVEC3:
1033     case VARIABLE_TYPE_UVEC4:
1034     {
1035         result = VARIABLE_TYPE_UINT;
1036 
1037         break;
1038     }
1039 
1040     default:
1041     {
1042         TCU_FAIL("Unrecognized variable type");
1043     }
1044     } /* switch (variable_type) */
1045 
1046     return result;
1047 }
1048 
1049 /** Retrieves size of a single component (in bytes) for user-specified
1050  *  variable type.
1051  *
1052  *  @param variable_type Variable type to use for the query.
1053  *
1054  *  @return As per description.
1055  **/
getComponentSizeForVariableType(const _variable_type & variable_type)1056 unsigned int Utils::getComponentSizeForVariableType(const _variable_type &variable_type)
1057 {
1058     _variable_type base_variable_type = getBaseVariableType(variable_type);
1059     unsigned int result               = 0;
1060 
1061     switch (base_variable_type)
1062     {
1063     case VARIABLE_TYPE_BOOL:
1064         result = sizeof(bool);
1065         break;
1066     case VARIABLE_TYPE_DOUBLE:
1067         result = sizeof(double);
1068         break;
1069     case VARIABLE_TYPE_FLOAT:
1070         result = sizeof(float);
1071         break;
1072     case VARIABLE_TYPE_INT:
1073         result = sizeof(int);
1074         break;
1075     case VARIABLE_TYPE_UINT:
1076         result = sizeof(unsigned int);
1077         break;
1078 
1079     default:
1080     {
1081         TCU_FAIL("Unrecognized base variable type");
1082     }
1083     } /* switch (variable_type) */
1084 
1085     return result;
1086 }
1087 
1088 /** Retrieves a GLenum value corresponding to internal shader stage
1089  *  representation.
1090  *
1091  *  @param shader_stage Shader stage to user for the query.
1092  *
1093  *  @return Requested value or GL_NONE if the stage was not recognized.
1094  **/
getGLenumForShaderStage(const _shader_stage & shader_stage)1095 glw::GLenum Utils::getGLenumForShaderStage(const _shader_stage &shader_stage)
1096 {
1097     glw::GLenum result = GL_NONE;
1098 
1099     switch (shader_stage)
1100     {
1101     case SHADER_STAGE_VERTEX:
1102         result = GL_VERTEX_SHADER;
1103         break;
1104     case SHADER_STAGE_TESSELLATION_CONTROL:
1105         result = GL_TESS_CONTROL_SHADER;
1106         break;
1107     case SHADER_STAGE_TESSELLATION_EVALUATION:
1108         result = GL_TESS_EVALUATION_SHADER;
1109         break;
1110     case SHADER_STAGE_GEOMETRY:
1111         result = GL_GEOMETRY_SHADER;
1112         break;
1113     case SHADER_STAGE_FRAGMENT:
1114         result = GL_FRAGMENT_SHADER;
1115         break;
1116 
1117     default:
1118     {
1119         TCU_FAIL("Unrecognized shader stage requested");
1120     }
1121     } /* switch (shader_stage) */
1122 
1123     return result;
1124 }
1125 
1126 /** Retrieves number of components that user-specified variable type supports.
1127  *
1128  *  @param variable_type GLSL variable type to use for the query.
1129  *
1130  *  @return As per description.
1131  **/
getNumberOfComponentsForVariableType(const _variable_type & variable_type)1132 unsigned int Utils::getNumberOfComponentsForVariableType(const _variable_type &variable_type)
1133 {
1134     unsigned int result = 0;
1135 
1136     switch (variable_type)
1137     {
1138     case VARIABLE_TYPE_BOOL:
1139     case VARIABLE_TYPE_DOUBLE:
1140     case VARIABLE_TYPE_FLOAT:
1141     case VARIABLE_TYPE_INT:
1142     case VARIABLE_TYPE_UINT:
1143     {
1144         result = 1;
1145 
1146         break;
1147     }
1148 
1149     case VARIABLE_TYPE_BVEC2:
1150     case VARIABLE_TYPE_DVEC2:
1151     case VARIABLE_TYPE_IVEC2:
1152     case VARIABLE_TYPE_UVEC2:
1153     case VARIABLE_TYPE_VEC2:
1154     {
1155         result = 2;
1156 
1157         break;
1158     }
1159 
1160     case VARIABLE_TYPE_BVEC3:
1161     case VARIABLE_TYPE_DVEC3:
1162     case VARIABLE_TYPE_IVEC3:
1163     case VARIABLE_TYPE_UVEC3:
1164     case VARIABLE_TYPE_VEC3:
1165     {
1166         result = 3;
1167 
1168         break;
1169     }
1170 
1171     case VARIABLE_TYPE_BVEC4:
1172     case VARIABLE_TYPE_DVEC4:
1173     case VARIABLE_TYPE_IVEC4:
1174     case VARIABLE_TYPE_MAT2:
1175     case VARIABLE_TYPE_UVEC4:
1176     case VARIABLE_TYPE_VEC4:
1177     {
1178         result = 4;
1179 
1180         break;
1181     }
1182 
1183     case VARIABLE_TYPE_MAT2X3:
1184     case VARIABLE_TYPE_MAT3X2:
1185     {
1186         result = 6;
1187 
1188         break;
1189     }
1190 
1191     case VARIABLE_TYPE_MAT2X4:
1192     case VARIABLE_TYPE_MAT4X2:
1193     {
1194         result = 8;
1195 
1196         break;
1197     }
1198 
1199     case VARIABLE_TYPE_MAT3:
1200     {
1201         result = 9;
1202 
1203         break;
1204     }
1205 
1206     case VARIABLE_TYPE_MAT3X4:
1207     case VARIABLE_TYPE_MAT4X3:
1208     {
1209         result = 12;
1210 
1211         break;
1212     }
1213 
1214     case VARIABLE_TYPE_MAT4:
1215     {
1216         result = 16;
1217 
1218         break;
1219     }
1220 
1221     default:
1222         break;
1223     } /* switch (variable_type) */
1224 
1225     return result;
1226 }
1227 
1228 /** Retrieves a literal defining user-specified shader stage enum.
1229  *
1230  *  @param shader_stage Shader stage to use for the query.
1231  *
1232  *  @return Requested string or "?" if the stage was not recognized.
1233  **/
getShaderStageString(const _shader_stage & shader_stage)1234 std::string Utils::getShaderStageString(const _shader_stage &shader_stage)
1235 {
1236     std::string result = "?";
1237 
1238     switch (shader_stage)
1239     {
1240     case SHADER_STAGE_FRAGMENT:
1241         result = "Fragment Shader";
1242         break;
1243     case SHADER_STAGE_GEOMETRY:
1244         result = "Geometry Shader";
1245         break;
1246     case SHADER_STAGE_TESSELLATION_CONTROL:
1247         result = "Tessellation Control Shader";
1248         break;
1249     case SHADER_STAGE_TESSELLATION_EVALUATION:
1250         result = "Tessellation Evaluation Shader";
1251         break;
1252     case SHADER_STAGE_VERTEX:
1253         result = "Vertex Shader";
1254         break;
1255 
1256     default:
1257     {
1258         TCU_FAIL("Unrecognized shader stage");
1259     }
1260     } /* switch (shader_stage) */
1261 
1262     return result;
1263 }
1264 
1265 /** Retrieves a literal defining user-specified shader stage enum.
1266  *
1267  *  @param shader_stage_glenum Shader stage to use for the query.
1268  *
1269  *  @return Requested string or "?" if the stage was not recognized.
1270  **/
getShaderStageStringFromGLEnum(const glw::GLenum shader_stage_glenum)1271 std::string Utils::getShaderStageStringFromGLEnum(const glw::GLenum shader_stage_glenum)
1272 {
1273     std::string result = "?";
1274 
1275     switch (shader_stage_glenum)
1276     {
1277     case GL_FRAGMENT_SHADER:
1278         result = "Fragment Shader";
1279         break;
1280     case GL_GEOMETRY_SHADER:
1281         result = "Geometry Shader";
1282         break;
1283     case GL_TESS_CONTROL_SHADER:
1284         result = "Tessellation Control Shader";
1285         break;
1286     case GL_TESS_EVALUATION_SHADER:
1287         result = "Tessellation Evaluation Shader";
1288         break;
1289     case GL_VERTEX_SHADER:
1290         result = "Vertex Shader";
1291         break;
1292 
1293     default:
1294     {
1295         TCU_FAIL("Unrecognized shader string");
1296     }
1297     } /* switch (shader_stage_glenum) */
1298 
1299     return result;
1300 }
1301 
1302 /** Returns string that represents program interface name
1303  *
1304  * @param program_interface Program interface
1305  *
1306  * @return String representation of known program interface
1307  **/
programInterfaceToStr(glw::GLenum program_interface)1308 const GLchar *Utils::programInterfaceToStr(glw::GLenum program_interface)
1309 {
1310     const GLchar *string = "Unknown program interface";
1311 
1312     switch (program_interface)
1313     {
1314     case GL_VERTEX_SUBROUTINE:
1315         string = "GL_VERTEX_SUBROUTINE";
1316         break;
1317     case GL_VERTEX_SUBROUTINE_UNIFORM:
1318         string = "GL_VERTEX_SUBROUTINE_UNIFORM";
1319         break;
1320     default:
1321         TCU_FAIL("Not implemented");
1322     }
1323 
1324     return string;
1325 }
1326 
1327 /** Returns string that represents pname's name
1328  *
1329  * @param pname pname
1330  *
1331  * @return String representation of known pnames
1332  **/
pnameToStr(glw::GLenum pname)1333 const GLchar *Utils::pnameToStr(glw::GLenum pname)
1334 {
1335     const GLchar *string = "Unknown pname";
1336 
1337     switch (pname)
1338     {
1339     case GL_ACTIVE_SUBROUTINE_UNIFORMS:
1340         string = "GL_ACTIVE_SUBROUTINE_UNIFORMS";
1341         break;
1342     case GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS:
1343         string = "GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS";
1344         break;
1345     case GL_ACTIVE_SUBROUTINES:
1346         string = "GL_ACTIVE_SUBROUTINES";
1347         break;
1348     case GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH:
1349         string = "GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH";
1350         break;
1351     case GL_ACTIVE_SUBROUTINE_MAX_LENGTH:
1352         string = "GL_ACTIVE_SUBROUTINE_MAX_LENGTH";
1353         break;
1354     case GL_NUM_COMPATIBLE_SUBROUTINES:
1355         string = "GL_NUM_COMPATIBLE_SUBROUTINES";
1356         break;
1357     case GL_UNIFORM_SIZE:
1358         string = "GL_UNIFORM_SIZE";
1359         break;
1360     case GL_COMPATIBLE_SUBROUTINES:
1361         string = "GL_COMPATIBLE_SUBROUTINES";
1362         break;
1363     case GL_UNIFORM_NAME_LENGTH:
1364         string = "GL_UNIFORM_NAME_LENGTH";
1365         break;
1366     case GL_ACTIVE_RESOURCES:
1367         string = "GL_ACTIVE_RESOURCES";
1368         break;
1369     case GL_MAX_NAME_LENGTH:
1370         string = "GL_MAX_NAME_LENGTH";
1371         break;
1372     case GL_MAX_NUM_COMPATIBLE_SUBROUTINES:
1373         string = "GL_MAX_NUM_COMPATIBLE_SUBROUTINES";
1374         break;
1375     case GL_NAME_LENGTH:
1376         string = "GL_NAME_LENGTH";
1377         break;
1378     case GL_ARRAY_SIZE:
1379         string = "GL_ARRAY_SIZE";
1380         break;
1381     case GL_LOCATION:
1382         string = "GL_LOCATION";
1383         break;
1384     default:
1385         TCU_FAIL("Not implemented");
1386     }
1387 
1388     return string;
1389 }
1390 
compare(const glw::GLfloat & left,const glw::GLfloat & right)1391 bool Utils::compare(const glw::GLfloat &left, const glw::GLfloat &right)
1392 {
1393     static const glw::GLfloat m_epsilon = 0.00001f;
1394 
1395     if (m_epsilon < std::abs(right - left))
1396     {
1397         return false;
1398     }
1399     else
1400     {
1401         return true;
1402     }
1403 }
1404 
1405 /** Returns a variable type enum corresponding to user-specified base variable type
1406  *  and the number of components it should support.
1407  *
1408  *  @param base_variable_type Base variable type to use for the query.
1409  *  @param n_components       Number of components to consider for the query.
1410  *
1411  *  @return As per description.
1412  **/
getVariableTypeFromProperties(const _variable_type & base_variable_type,const unsigned int & n_components)1413 Utils::_variable_type Utils::getVariableTypeFromProperties(const _variable_type &base_variable_type,
1414                                                            const unsigned int &n_components)
1415 {
1416     _variable_type result = VARIABLE_TYPE_UNKNOWN;
1417 
1418     switch (base_variable_type)
1419     {
1420     case VARIABLE_TYPE_BOOL:
1421     {
1422         switch (n_components)
1423         {
1424         case 1:
1425             result = VARIABLE_TYPE_BOOL;
1426             break;
1427         case 2:
1428             result = VARIABLE_TYPE_BVEC2;
1429             break;
1430         case 3:
1431             result = VARIABLE_TYPE_BVEC3;
1432             break;
1433         case 4:
1434             result = VARIABLE_TYPE_BVEC4;
1435             break;
1436 
1437         default:
1438         {
1439             TCU_FAIL("Unsupported number of components requested");
1440         }
1441         } /* switch (n_components) */
1442 
1443         break;
1444     }
1445 
1446     case VARIABLE_TYPE_DOUBLE:
1447     {
1448         switch (n_components)
1449         {
1450         case 1:
1451             result = VARIABLE_TYPE_DOUBLE;
1452             break;
1453         case 2:
1454             result = VARIABLE_TYPE_DVEC2;
1455             break;
1456         case 3:
1457             result = VARIABLE_TYPE_DVEC3;
1458             break;
1459         case 4:
1460             result = VARIABLE_TYPE_DVEC4;
1461             break;
1462 
1463         default:
1464         {
1465             TCU_FAIL("Unsupported number of components requested");
1466         }
1467         } /* switch (n_components) */
1468 
1469         break;
1470     }
1471 
1472     case VARIABLE_TYPE_FLOAT:
1473     {
1474         switch (n_components)
1475         {
1476         case 1:
1477             result = VARIABLE_TYPE_FLOAT;
1478             break;
1479         case 2:
1480             result = VARIABLE_TYPE_VEC2;
1481             break;
1482         case 3:
1483             result = VARIABLE_TYPE_VEC3;
1484             break;
1485         case 4:
1486             result = VARIABLE_TYPE_VEC4;
1487             break;
1488 
1489         default:
1490         {
1491             TCU_FAIL("Unsupported number of components requested");
1492         }
1493         } /* switch (n_components) */
1494 
1495         break;
1496     }
1497 
1498     case VARIABLE_TYPE_INT:
1499     {
1500         switch (n_components)
1501         {
1502         case 1:
1503             result = VARIABLE_TYPE_INT;
1504             break;
1505         case 2:
1506             result = VARIABLE_TYPE_IVEC2;
1507             break;
1508         case 3:
1509             result = VARIABLE_TYPE_IVEC3;
1510             break;
1511         case 4:
1512             result = VARIABLE_TYPE_IVEC4;
1513             break;
1514 
1515         default:
1516         {
1517             TCU_FAIL("Unsupported number of components requested");
1518         }
1519         } /* switch (n_components) */
1520 
1521         break;
1522     }
1523 
1524     case VARIABLE_TYPE_UINT:
1525     {
1526         switch (n_components)
1527         {
1528         case 1:
1529             result = VARIABLE_TYPE_UINT;
1530             break;
1531         case 2:
1532             result = VARIABLE_TYPE_UVEC2;
1533             break;
1534         case 3:
1535             result = VARIABLE_TYPE_UVEC3;
1536             break;
1537         case 4:
1538             result = VARIABLE_TYPE_UVEC4;
1539             break;
1540 
1541         default:
1542         {
1543             TCU_FAIL("Unsupported number of components requested");
1544         }
1545         } /* switch (n_components) */
1546 
1547         break;
1548     }
1549 
1550     default:
1551     {
1552         TCU_FAIL("Unrecognized base variable type");
1553     }
1554     } /* switch (base_variable_type) */
1555 
1556     return result;
1557 }
1558 
1559 /** Returns a GLSL literal corresponding to user-specified variable type.
1560  *
1561  *  @param variable_type Variable type to use for the query.
1562  *
1563  *  @return As per description or [?] if @param variable_type was not
1564  *          recognized.
1565  **/
getVariableTypeGLSLString(const _variable_type & variable_type)1566 std::string Utils::getVariableTypeGLSLString(const _variable_type &variable_type)
1567 {
1568     std::string result = "[?]";
1569 
1570     switch (variable_type)
1571     {
1572     case VARIABLE_TYPE_BOOL:
1573         result = "bool";
1574         break;
1575     case VARIABLE_TYPE_BVEC2:
1576         result = "bvec2";
1577         break;
1578     case VARIABLE_TYPE_BVEC3:
1579         result = "bvec3";
1580         break;
1581     case VARIABLE_TYPE_BVEC4:
1582         result = "bvec4";
1583         break;
1584     case VARIABLE_TYPE_DOUBLE:
1585         result = "double";
1586         break;
1587     case VARIABLE_TYPE_DVEC2:
1588         result = "dvec2";
1589         break;
1590     case VARIABLE_TYPE_DVEC3:
1591         result = "dvec3";
1592         break;
1593     case VARIABLE_TYPE_DVEC4:
1594         result = "dvec4";
1595         break;
1596     case VARIABLE_TYPE_FLOAT:
1597         result = "float";
1598         break;
1599     case VARIABLE_TYPE_INT:
1600         result = "int";
1601         break;
1602     case VARIABLE_TYPE_IVEC2:
1603         result = "ivec2";
1604         break;
1605     case VARIABLE_TYPE_IVEC3:
1606         result = "ivec3";
1607         break;
1608     case VARIABLE_TYPE_IVEC4:
1609         result = "ivec4";
1610         break;
1611     case VARIABLE_TYPE_MAT2:
1612         result = "mat2";
1613         break;
1614     case VARIABLE_TYPE_MAT2X3:
1615         result = "mat2x3";
1616         break;
1617     case VARIABLE_TYPE_MAT2X4:
1618         result = "mat2x4";
1619         break;
1620     case VARIABLE_TYPE_MAT3:
1621         result = "mat3";
1622         break;
1623     case VARIABLE_TYPE_MAT3X2:
1624         result = "mat3x2";
1625         break;
1626     case VARIABLE_TYPE_MAT3X4:
1627         result = "mat3x4";
1628         break;
1629     case VARIABLE_TYPE_MAT4:
1630         result = "mat4";
1631         break;
1632     case VARIABLE_TYPE_MAT4X2:
1633         result = "mat4x2";
1634         break;
1635     case VARIABLE_TYPE_MAT4X3:
1636         result = "mat4x3";
1637         break;
1638     case VARIABLE_TYPE_UINT:
1639         result = "uint";
1640         break;
1641     case VARIABLE_TYPE_UVEC2:
1642         result = "uvec2";
1643         break;
1644     case VARIABLE_TYPE_UVEC3:
1645         result = "uvec3";
1646         break;
1647     case VARIABLE_TYPE_UVEC4:
1648         result = "uvec4";
1649         break;
1650     case VARIABLE_TYPE_VEC2:
1651         result = "vec2";
1652         break;
1653     case VARIABLE_TYPE_VEC3:
1654         result = "vec3";
1655         break;
1656     case VARIABLE_TYPE_VEC4:
1657         result = "vec4";
1658         break;
1659 
1660     default:
1661     {
1662         TCU_FAIL("Unrecognized variable type");
1663     }
1664     } /* switch (variable_type) */
1665 
1666     return result;
1667 }
1668 
1669 /** Constructor.
1670  *
1671  *  @param context Rendering context.
1672  *
1673  **/
APITest1(deqp::Context & context)1674 APITest1::APITest1(deqp::Context &context)
1675     : TestCase(context, "min_maxes",
1676                "Verifies the implementation returns valid GL_MAX_SUBROUTINE* pnames "
1677                "which meet the minimum maximum requirements enforced by the spec.")
1678     , m_has_test_passed(true)
1679 {
1680     /* Left blank intentionally */
1681 }
1682 
1683 /** Executes test iteration.
1684  *
1685  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
1686  */
iterate()1687 tcu::TestNode::IterateResult APITest1::iterate()
1688 {
1689     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1690 
1691     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
1692     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
1693     {
1694         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
1695     }
1696 
1697     /* Iterate over all pnames */
1698     const struct
1699     {
1700         glw::GLenum pname;
1701         const char *pname_string;
1702         glw::GLint min_value;
1703     } pnames[]                  = {{GL_MAX_SUBROUTINES, "GL_MAX_SUBROUTINES", 256},
1704                                    {GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS, "GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS", 1024}};
1705     const unsigned int n_pnames = sizeof(pnames) / sizeof(pnames[0]);
1706 
1707     for (unsigned int n_pname = 0; n_pname < n_pnames; ++n_pname)
1708     {
1709         glw::GLboolean bool_value  = GL_FALSE;
1710         glw::GLdouble double_value = 0.0;
1711         glw::GLfloat float_value   = 0.0f;
1712         glw::GLint int_value       = 0;
1713         glw::GLint64 int64_value   = 0;
1714         const glw::GLint min_value = pnames[n_pname].min_value;
1715         const glw::GLenum &pname   = pnames[n_pname].pname;
1716         const char *pname_string   = pnames[n_pname].pname_string;
1717 
1718         /* Retrieve the pname values */
1719         gl.getBooleanv(pname, &bool_value);
1720         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetBooleanv() call failed.");
1721 
1722         gl.getDoublev(pname, &double_value);
1723         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetDoublev() call failed.");
1724 
1725         gl.getFloatv(pname, &float_value);
1726         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv() call failed.");
1727 
1728         gl.getIntegerv(pname, &int_value);
1729         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed.");
1730 
1731         gl.getInteger64v(pname, &int64_value);
1732         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInteger64v() call failed.");
1733 
1734         /* Make sure the value reported meets the min max requirement */
1735         if (int_value < min_value)
1736         {
1737             m_testCtx.getLog() << tcu::TestLog::Message << "GL implementation reports a value of [" << int_value
1738                                << "]"
1739                                   " for property ["
1740                                << pname_string
1741                                << "]"
1742                                   ", whereas the min max for the property is ["
1743                                << min_value << "]." << tcu::TestLog::EndMessage;
1744 
1745             m_has_test_passed = false;
1746         }
1747 
1748         /* Verify the other getters reported valid values */
1749         const float epsilon = 1e-5f;
1750 
1751         if (((int_value == 0) && (bool_value == GL_TRUE)) || ((int_value != 0) && (bool_value != GL_TRUE)))
1752         {
1753             m_testCtx.getLog() << tcu::TestLog::Message << "Invalid boolean value [" << bool_value
1754                                << "]"
1755                                   " reported for property ["
1756                                << pname_string
1757                                << "]"
1758                                   " (int value:["
1759                                << int_value << "])" << tcu::TestLog::EndMessage;
1760 
1761             m_has_test_passed = false;
1762         }
1763 
1764         if (de::abs(double_value - (double)int_value) > epsilon)
1765         {
1766             m_testCtx.getLog() << tcu::TestLog::Message << "Invalid double value [" << double_value
1767                                << "]"
1768                                   " reported for property ["
1769                                << pname_string
1770                                << "]"
1771                                   " (int value:["
1772                                << int_value << "])" << tcu::TestLog::EndMessage;
1773 
1774             m_has_test_passed = false;
1775         }
1776 
1777         if (de::abs(float_value - (float)int_value) > epsilon)
1778         {
1779             m_testCtx.getLog() << tcu::TestLog::Message << "Invalid float value [" << float_value
1780                                << "]"
1781                                   " reported for property ["
1782                                << pname_string
1783                                << "]"
1784                                   " (int value:["
1785                                << int_value << "])" << tcu::TestLog::EndMessage;
1786 
1787             m_has_test_passed = false;
1788         }
1789 
1790         if (int64_value != int_value)
1791         {
1792             m_testCtx.getLog() << tcu::TestLog::Message << "Invalid 64-bit integer value [" << float_value
1793                                << "]"
1794                                   " reported for property ["
1795                                << pname_string
1796                                << "]"
1797                                   " (int value:["
1798                                << int_value << "])" << tcu::TestLog::EndMessage;
1799 
1800             m_has_test_passed = false;
1801         }
1802     } /* for (all pnames) */
1803 
1804     if (m_has_test_passed)
1805     {
1806         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1807     }
1808     else
1809     {
1810         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1811     }
1812 
1813     return STOP;
1814 }
1815 
1816 /** Constructor.
1817  *
1818  *  @param context Rendering context.
1819  *
1820  **/
APITest2(deqp::Context & context)1821 APITest2::APITest2(deqp::Context &context)
1822     : TestCase(context, "name_getters",
1823                "Verifies glGetActiveSubroutineName() and glGetActiveSubroutineUniformName() "
1824                "functions work correctly.")
1825     , m_buffer(DE_NULL)
1826     , m_has_test_passed(true)
1827     , m_po_id(0)
1828     , m_subroutine_name1("subroutine1")
1829     , m_subroutine_name2("subroutine2")
1830     , m_subroutine_uniform_name("data_provider")
1831     , m_vs_id(0)
1832 {
1833     /* Left blank intentionally */
1834 }
1835 
1836 /** Destroys all ES objects that may have been created during test initialization,
1837  *  as well as releases any buffers that may have been allocated during the process.
1838  */
deinit()1839 void APITest2::deinit()
1840 {
1841     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1842 
1843     if (m_buffer != DE_NULL)
1844     {
1845         delete[] m_buffer;
1846 
1847         m_buffer = DE_NULL;
1848     }
1849 
1850     if (m_po_id != 0)
1851     {
1852         gl.deleteProgram(m_po_id);
1853 
1854         m_po_id = 0;
1855     }
1856 
1857     if (m_vs_id != 0)
1858     {
1859         gl.deleteShader(m_vs_id);
1860 
1861         m_vs_id = 0;
1862     }
1863 }
1864 
1865 /** Returns body of a vertex shader that should be used for the test.
1866  *
1867  *  @return As per description.
1868  **/
getVertexShaderBody()1869 std::string APITest2::getVertexShaderBody()
1870 {
1871     return "#version 400\n"
1872            "\n"
1873            "#extension GL_ARB_shader_subroutine : require\n"
1874            "\n"
1875            "subroutine int ExampleSubroutineType(int example_argument);\n"
1876            "\n"
1877            "subroutine(ExampleSubroutineType) int subroutine1(int example_argument)\n"
1878            "{\n"
1879            "    return 1;\n"
1880            "}\n"
1881            "\n"
1882            "subroutine(ExampleSubroutineType) int subroutine2(int example_argument)\n"
1883            "{\n"
1884            "    return 2;\n"
1885            "}\n"
1886            "\n"
1887            "subroutine uniform ExampleSubroutineType data_provider;\n"
1888            "\n"
1889            "void main()\n"
1890            "{\n"
1891            "    gl_Position = vec4(float(data_provider(0)), vec3(1) );\n"
1892            "}\n";
1893 }
1894 
1895 /** Initializes all ES objects required to run the test. */
initTest()1896 void APITest2::initTest()
1897 {
1898     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1899 
1900     /* Generate program & shader objects */
1901     m_po_id = gl.createProgram();
1902     m_vs_id = gl.createShader(GL_VERTEX_SHADER);
1903 
1904     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() or glCreateShader() call(s) failed.");
1905 
1906     /* Attach the shader to the program object */
1907     gl.attachShader(m_po_id, m_vs_id);
1908     GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
1909 
1910     /* Compile the shader */
1911     glw::GLint compile_status   = GL_FALSE;
1912     std::string vs_body         = getVertexShaderBody();
1913     const char *vs_body_raw_ptr = vs_body.c_str();
1914 
1915     gl.shaderSource(m_vs_id, 1 /* count */, &vs_body_raw_ptr, DE_NULL /* length */);
1916     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
1917 
1918     gl.compileShader(m_vs_id);
1919     GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
1920 
1921     gl.getShaderiv(m_vs_id, GL_COMPILE_STATUS, &compile_status);
1922     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
1923 
1924     if (compile_status != GL_TRUE)
1925     {
1926         TCU_FAIL("Shader compilation failed.");
1927     }
1928 
1929     /* Try to link the program object */
1930     glw::GLint link_status = GL_FALSE;
1931 
1932     gl.linkProgram(m_po_id);
1933     GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
1934 
1935     gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
1936     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
1937 
1938     if (link_status != GL_TRUE)
1939     {
1940         TCU_FAIL("Program linking failed.");
1941     }
1942 
1943     /* Perform a few quick checks */
1944     glw::GLint n_active_subroutines         = 0;
1945     glw::GLint n_active_subroutine_uniforms = 0;
1946 
1947     gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINES, &n_active_subroutines);
1948     gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORMS, &n_active_subroutine_uniforms);
1949     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramStageiv() call failed.");
1950 
1951     if (n_active_subroutines != 2 /* subroutines declared in vertex shader */)
1952     {
1953         m_testCtx.getLog() << tcu::TestLog::Message
1954                            << "Invalid amount of active subroutines reported; expected: 2,"
1955                               " reported:"
1956                            << n_active_subroutines << tcu::TestLog::EndMessage;
1957 
1958         TCU_FAIL("Invalid GL_ACTIVE_SUBROUTINES property value.");
1959     }
1960 
1961     if (n_active_subroutine_uniforms != 1)
1962     {
1963         m_testCtx.getLog() << tcu::TestLog::Message
1964                            << "Invalid amount of active subroutine uniforms reported: expected: 1,"
1965                               " reported: "
1966                            << n_active_subroutine_uniforms << tcu::TestLog::EndMessage;
1967 
1968         TCU_FAIL("Invalid GL_ACTIVE_SUBROUTINE_UNIFORMS property value.");
1969     }
1970 }
1971 
1972 /** Executes test iteration.
1973  *
1974  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
1975  */
iterate()1976 tcu::TestNode::IterateResult APITest2::iterate()
1977 {
1978     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
1979     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
1980     {
1981         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
1982     }
1983 
1984     /* Initialize a test program object */
1985     initTest();
1986 
1987     /* Verify glGetActiveSubroutineName() works correctly */
1988     verifyGLGetActiveSubroutineNameFunctionality();
1989 
1990     /* Verify glGetActiveSubroutineUniformName() works correctly */
1991     verifyGLGetActiveSubroutineUniformNameFunctionality();
1992 
1993     /* Done */
1994     if (m_has_test_passed)
1995     {
1996         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1997     }
1998     else
1999     {
2000         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2001     }
2002 
2003     return STOP;
2004 }
2005 
2006 /** Verifies glGetActiveSubroutineName() behaves as per GL_ARB_shader_subroutine
2007  *  specification.
2008  **/
verifyGLGetActiveSubroutineNameFunctionality()2009 void APITest2::verifyGLGetActiveSubroutineNameFunctionality()
2010 {
2011     GLsizei expected_length1 = (GLsizei)strlen(m_subroutine_name1) + 1;
2012     GLsizei expected_length2 = (GLsizei)strlen(m_subroutine_name1) + 1;
2013     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2014     GLsizei reported_length  = 0;
2015 
2016     gl.getActiveSubroutineName(m_po_id, GL_VERTEX_SHADER, 0, /* index */
2017                                0,                            /* bufsize */
2018                                DE_NULL,                      /* length */
2019                                DE_NULL);                     /* name */
2020     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineName() call failed.");
2021 
2022     gl.getProgramInterfaceiv(m_po_id, GL_VERTEX_SUBROUTINE, GL_MAX_NAME_LENGTH, &reported_length);
2023     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineName() call failed.");
2024 
2025     if ((reported_length != expected_length1) && (reported_length != expected_length2))
2026     {
2027         m_testCtx.getLog() << tcu::TestLog::Message
2028                            << "Invalid active subroutine name length reported:" << reported_length
2029                            << ", instead of: " << expected_length1 << " or " << expected_length2
2030                            << tcu::TestLog::EndMessage;
2031 
2032         TCU_FAIL("Incorrect length of active subroutine name");
2033     }
2034 
2035     m_buffer = new glw::GLchar[reported_length];
2036 
2037     memset(m_buffer, 0, reported_length);
2038 
2039     gl.getActiveSubroutineName(m_po_id, GL_VERTEX_SHADER, 0, reported_length, DE_NULL, /* length */
2040                                m_buffer);
2041     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineName() call failed.");
2042 
2043     if (strcmp(m_buffer, m_subroutine_name1) != 0 && strcmp(m_buffer, m_subroutine_name2) != 0)
2044     {
2045         m_testCtx.getLog() << tcu::TestLog::Message << "Invalid active subroutine name reported:[" << m_buffer
2046                            << "]"
2047                               " instead of:["
2048                            << m_subroutine_name1
2049                            << "]"
2050                               " or:["
2051                            << m_subroutine_name2 << "]." << tcu::TestLog::EndMessage;
2052 
2053         TCU_FAIL("Invalid active subroutine name reported.");
2054     }
2055 
2056     delete[] m_buffer;
2057     m_buffer = DE_NULL;
2058 }
2059 
2060 /** Verifies glGetActiveSubroutineUniformName() behaves as per GL_ARB_shader_subroutine
2061  *  specification.
2062  **/
verifyGLGetActiveSubroutineUniformNameFunctionality()2063 void APITest2::verifyGLGetActiveSubroutineUniformNameFunctionality()
2064 {
2065     GLsizei expected_length  = (GLsizei)strlen(m_subroutine_uniform_name);
2066     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2067     GLsizei reported_length  = 0;
2068 
2069     gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, 0, /* index */
2070                                       0,                            /* bufsize */
2071                                       DE_NULL,                      /* length */
2072                                       DE_NULL);                     /* name */
2073     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineUniformName() call failed.");
2074 
2075     gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, 0, /* index */
2076                                       0,                            /* bufsize */
2077                                       &reported_length, DE_NULL);   /* name */
2078     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineUniformName() call failed.");
2079 
2080     // reported_length is the actual number of characters written into <name>
2081     // If <bufSize> is 0, reported_length should be 0
2082     if (reported_length != 0)
2083     {
2084         m_testCtx.getLog() << tcu::TestLog::Message
2085                            << "Invalid active subroutine uniform name length reported:" << reported_length
2086                            << ", instead of: " << 0 << tcu::TestLog::EndMessage;
2087 
2088         TCU_FAIL("Incorrect length of active subroutine uniform name");
2089     }
2090 
2091     m_buffer = new glw::GLchar[expected_length + 1];
2092 
2093     memset(m_buffer, 0, expected_length + 1);
2094 
2095     gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, 0, expected_length + 1, &reported_length, m_buffer);
2096     GLU_EXPECT_NO_ERROR(gl.getError(), "getActiveSubroutineUniformName() call failed.");
2097 
2098     if (reported_length != expected_length)
2099     {
2100         m_testCtx.getLog() << tcu::TestLog::Message
2101                            << "Invalid active subroutine uniform name length reported:" << reported_length
2102                            << ", instead of: " << expected_length << tcu::TestLog::EndMessage;
2103 
2104         TCU_FAIL("Incorrect length of active subroutine uniform name");
2105     }
2106 
2107     if (strcmp(m_buffer, m_subroutine_uniform_name) != 0)
2108     {
2109         m_testCtx.getLog() << tcu::TestLog::Message << "Invalid active subroutine uniform name reported:[" << m_buffer
2110                            << "]"
2111                               " instead of:["
2112                            << m_subroutine_uniform_name << "]" << tcu::TestLog::EndMessage;
2113 
2114         TCU_FAIL("Invalid active subroutine uniform name reported.");
2115     }
2116 
2117     delete[] m_buffer;
2118     m_buffer = DE_NULL;
2119 }
2120 
2121 /** Constructor.
2122  *
2123  *  @param context Rendering context.
2124  *
2125  **/
FunctionalTest1_2(deqp::Context & context)2126 FunctionalTest1_2::FunctionalTest1_2(deqp::Context &context)
2127     : TestCase(context, "two_subroutines_single_subroutine_uniform",
2128                "Verifies the subroutines work correctly in a vertex shader for"
2129                " bool/float/int/uint/double/*vec*/*mat* argument and return types")
2130     , m_has_test_passed(true)
2131     , m_po_id(0)
2132     , m_po_getter0_subroutine_index(GL_INVALID_INDEX)
2133     , m_po_getter1_subroutine_index(GL_INVALID_INDEX)
2134     , m_po_subroutine_uniform_index(-1)
2135     , m_xfb_bo_id(0)
2136     , m_vao_id(0)
2137     , m_vs_id(0)
2138 {
2139     /* Left blank intentionally */
2140 }
2141 
2142 /** Destroys all ES objects that may have been created during test initialization,
2143  *  as well as releases any buffers that may have been allocated during the process.
2144  */
deinit()2145 void FunctionalTest1_2::deinit()
2146 {
2147     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2148 
2149     deinitTestIteration();
2150 
2151     if (m_xfb_bo_id != 0)
2152     {
2153         gl.deleteBuffers(1, &m_xfb_bo_id);
2154 
2155         m_xfb_bo_id = 0;
2156     }
2157 
2158     if (m_vao_id != 0)
2159     {
2160         gl.deleteVertexArrays(1, &m_vao_id);
2161 
2162         m_vao_id = 0;
2163     }
2164 }
2165 
2166 /** Deinitializes GL objects that are iteration-specific */
deinitTestIteration()2167 void FunctionalTest1_2::deinitTestIteration()
2168 {
2169     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2170 
2171     if (m_po_id != 0)
2172     {
2173         gl.deleteProgram(m_po_id);
2174 
2175         m_po_id = 0;
2176     }
2177 
2178     if (m_vs_id != 0)
2179     {
2180         gl.deleteShader(m_vs_id);
2181 
2182         m_vs_id = 0;
2183     }
2184 }
2185 
2186 /** Executes a single test iteration using user-specified test case propertiesz.
2187  *
2188  *  @param test-case Test case descriptor.
2189  *
2190  *  @return true if the test iteration passed, false otherwise.
2191  **/
executeTestIteration(const _test_case & test_case)2192 bool FunctionalTest1_2::executeTestIteration(const _test_case &test_case)
2193 {
2194     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2195     bool result              = true;
2196 
2197     /* Build the test program */
2198     std::string empty_body;
2199     std::string vs_body               = getVertexShaderBody(test_case.variable_type, test_case.array_size);
2200     const glw::GLchar *xfb_varyings[] = {"result"};
2201     const unsigned int n_xfb_varyings = sizeof(xfb_varyings) / sizeof(xfb_varyings[0]);
2202 
2203     if (!Utils::buildProgram(gl, vs_body, empty_body, empty_body, empty_body, empty_body, xfb_varyings, n_xfb_varyings,
2204                              &m_vs_id, NULL, /* out_tc_id */
2205                              NULL,           /* out_te_id */
2206                              NULL,           /* out_gs_id */
2207                              NULL, &m_po_id))
2208     {
2209         TCU_FAIL("Test program failed to build.");
2210     }
2211 
2212     /* Retrieve subroutine locations */
2213     m_po_getter0_subroutine_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "getter0");
2214     m_po_getter1_subroutine_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "getter1");
2215 
2216     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineIndex() call(s) failed.");
2217 
2218     if (m_po_getter0_subroutine_index == GL_INVALID_INDEX || m_po_getter1_subroutine_index == GL_INVALID_INDEX)
2219     {
2220         TCU_FAIL("At least one subroutine is considered inactive which is invalid.");
2221     }
2222 
2223     /* Retrieve subroutine uniform location */
2224     m_po_subroutine_uniform_index = gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "colorGetterUniform");
2225 
2226     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineUniformLocation() call failed.");
2227 
2228     if (m_po_subroutine_uniform_index == -1)
2229     {
2230         TCU_FAIL("Subroutine uniform is considered inactive which is invalid.");
2231     }
2232 
2233     /* Set up XFB BO storage */
2234     const Utils::_variable_type base_variable_type = Utils::getBaseVariableType(test_case.variable_type);
2235     unsigned int iteration_xfb_bo_size             = Utils::getComponentSizeForVariableType(base_variable_type) *
2236                                          Utils::getNumberOfComponentsForVariableType(test_case.variable_type);
2237     unsigned int total_xfb_bo_size = 0;
2238 
2239     if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2240     {
2241         /* Boolean varyings are not supported by OpenGL. Instead, we use ints to output
2242          * boolean values. */
2243         iteration_xfb_bo_size = static_cast<unsigned int>(iteration_xfb_bo_size * sizeof(int));
2244     }
2245 
2246     total_xfb_bo_size = iteration_xfb_bo_size * 2 /* subroutines we will be testing */;
2247 
2248     gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, total_xfb_bo_size, DE_NULL /* data */, GL_STATIC_DRAW);
2249     GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
2250 
2251     /* Activate test program object */
2252     gl.useProgram(m_po_id);
2253     GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
2254 
2255     /* Run two iterations. Each iteration should invoke different subroutine. */
2256     const glw::GLuint subroutine_indices[]  = {m_po_getter0_subroutine_index, m_po_getter1_subroutine_index};
2257     const unsigned int n_subroutine_indices = sizeof(subroutine_indices) / sizeof(subroutine_indices[0]);
2258 
2259     for (unsigned int n_subroutine_index = 0; n_subroutine_index < n_subroutine_indices; ++n_subroutine_index)
2260     {
2261         /* Configure which subroutine should be used for the draw call */
2262         glw::GLuint current_subroutine_index = subroutine_indices[n_subroutine_index];
2263 
2264         gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, 1 /* count */, &current_subroutine_index);
2265         GLU_EXPECT_NO_ERROR(gl.getError(), "glUniformSubroutinesuiv() call failed.");
2266 
2267         /* Update XFB binding so that we do not overwrite data XFBed in previous iterations */
2268         gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
2269                            m_xfb_bo_id, iteration_xfb_bo_size * n_subroutine_index, iteration_xfb_bo_size);
2270         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange() call failed.");
2271 
2272         /* Draw a single point */
2273         gl.beginTransformFeedback(GL_POINTS);
2274         GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed.");
2275         {
2276             gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
2277             GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
2278         }
2279         gl.endTransformFeedback();
2280         GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed.");
2281     } /* for (all subroutine indices) */
2282 
2283     /* Map the BO storage into process space */
2284     const void *xfb_data_ptr = gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
2285     GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer() call failed.");
2286 
2287     result &= verifyXFBData(xfb_data_ptr, test_case.variable_type);
2288 
2289     gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
2290     GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffeR() call failed.");
2291 
2292     return result;
2293 }
2294 
2295 /** Retrieves body of a vertex shader that should be used to verify
2296  *  subroutine support, given user-specified test iteration properties.
2297  *
2298  *  @param variable_type GLSL type that should be used for argument and
2299  *                       return type definition in a subroutine. This setting
2300  *                       also affects type of the only output variable in the shader.
2301  *  @param array_size    1 if non-arrayed arguments/return types should be tested;
2302  *                       2 if arrayed arguments/return types should be tested.
2303  *
2304  *  @return Requested string.
2305  **/
getVertexShaderBody(const Utils::_variable_type & variable_type,unsigned int array_size)2306 std::string FunctionalTest1_2::getVertexShaderBody(const Utils::_variable_type &variable_type, unsigned int array_size)
2307 {
2308     Utils::_variable_type base_variable_type = Utils::getBaseVariableType(variable_type);
2309     unsigned int n_variable_type_components  = Utils::getNumberOfComponentsForVariableType(variable_type);
2310     std::stringstream result_sstream;
2311     std::string variable_type_glsl = Utils::getVariableTypeGLSLString(variable_type);
2312     std::stringstream variable_type_glsl_array_sstream;
2313     std::stringstream variable_type_glsl_arrayed_sstream;
2314 
2315     variable_type_glsl_arrayed_sstream << variable_type_glsl;
2316 
2317     if (array_size > 1)
2318     {
2319         variable_type_glsl_array_sstream << "[" << array_size << "]";
2320         variable_type_glsl_arrayed_sstream << variable_type_glsl_array_sstream.str();
2321     }
2322 
2323     /* Form pre-amble */
2324     result_sstream << "#version 400\n"
2325                       "\n"
2326                       "#extension GL_ARB_shader_subroutine : require\n";
2327 
2328     if (variable_type == Utils::VARIABLE_TYPE_DOUBLE)
2329     {
2330         result_sstream << "#extension GL_ARB_gpu_shader_fp64 : require\n";
2331     }
2332 
2333     /* Form subroutine type declaration */
2334     result_sstream << "\n"
2335                       "subroutine "
2336                    << variable_type_glsl_arrayed_sstream.str() << " colorGetter(in " << variable_type_glsl
2337                    << " in_value" << variable_type_glsl_array_sstream.str()
2338                    << ");\n"
2339                       "\n";
2340 
2341     /* Declare getter functions */
2342     for (int n_getter = 0; n_getter < 2; ++n_getter)
2343     {
2344         result_sstream << "subroutine(colorGetter) " << variable_type_glsl_arrayed_sstream.str() << " getter"
2345                        << n_getter << "(in " << variable_type_glsl << " in_value"
2346                        << variable_type_glsl_array_sstream.str()
2347                        << ")\n"
2348                           "{\n";
2349 
2350         if (array_size > 1)
2351         {
2352             result_sstream << variable_type_glsl << " temp" << variable_type_glsl_array_sstream.str() << ";\n";
2353         }
2354 
2355         if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2356         {
2357             if (array_size > 1)
2358             {
2359                 for (unsigned int array_index = 0; array_index < array_size; ++array_index)
2360                 {
2361                     result_sstream << "    temp[" << array_index
2362                                    << "]"
2363                                       " = "
2364                                    << ((n_getter == 0) ? ((variable_type_glsl == "bool") ? "!" : "not") : "")
2365                                    << "(in_value[" << array_index << "]);\n";
2366                 }
2367 
2368                 result_sstream << "    return temp;\n";
2369             }
2370             else
2371             {
2372                 result_sstream << "    return "
2373                                << ((n_getter == 0) ? ((variable_type_glsl == "bool") ? "!" : "not") : "")
2374                                << "(in_value);\n";
2375             }
2376         } /* if (base_variable_type == Utils::VARIABLE_TYPE_BOOL) */
2377         else
2378         {
2379             if (array_size > 1)
2380             {
2381                 for (unsigned int array_index = 0; array_index < array_size; ++array_index)
2382                 {
2383                     result_sstream << "    temp[" << array_index
2384                                    << "]"
2385                                       " = in_value["
2386                                    << array_index << "] + " << (n_getter + 1) << ";\n";
2387                 }
2388 
2389                 result_sstream << "    return temp;\n";
2390             }
2391             else
2392             {
2393                 result_sstream << "    return (in_value + " << (n_getter + 1) << ");\n";
2394             }
2395         }
2396 
2397         result_sstream << "}\n";
2398     } /* for (both getter functions) */
2399 
2400     /* Declare subroutine uniform */
2401     result_sstream << "subroutine uniform colorGetter colorGetterUniform;\n"
2402                       "\n";
2403 
2404     /* Declare output variable */
2405     result_sstream << "out ";
2406 
2407     if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2408     {
2409         Utils::_variable_type result_as_int_variable_type =
2410             Utils::getVariableTypeFromProperties(Utils::VARIABLE_TYPE_INT, n_variable_type_components);
2411         std::string variable_type_glsl_as_int = Utils::getVariableTypeGLSLString(result_as_int_variable_type);
2412 
2413         result_sstream << variable_type_glsl_as_int;
2414     }
2415     else
2416     {
2417         result_sstream << variable_type_glsl;
2418     }
2419 
2420     result_sstream << " result;\n"
2421                       "\n";
2422 
2423     /* Declare main(): prepare input argument for the subroutine function */
2424     result_sstream << "void main()\n"
2425                       "{\n"
2426                       "    "
2427                    << variable_type_glsl << " temp";
2428 
2429     if (array_size > 1)
2430     {
2431         result_sstream << "[" << array_size << "]";
2432     }
2433 
2434     result_sstream << ";\n";
2435 
2436     for (unsigned int array_index = 0; array_index < array_size; ++array_index)
2437     {
2438         result_sstream << "    temp";
2439 
2440         if (array_size > 1)
2441         {
2442             result_sstream << "[" << array_index << "]";
2443         }
2444 
2445         result_sstream << " = " << variable_type_glsl << "(";
2446 
2447         if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2448         {
2449             result_sstream << "true";
2450         }
2451         else
2452         {
2453             for (unsigned int n_component = 0; n_component < n_variable_type_components; ++n_component)
2454             {
2455                 result_sstream << "3";
2456 
2457                 if (n_component != (n_variable_type_components - 1))
2458                 {
2459                     result_sstream << ", ";
2460                 }
2461             } /* for (all components) */
2462         }
2463 
2464         result_sstream << ");\n";
2465     } /* for (all array indices) */
2466 
2467     /* Declare main(): call the subroutine. Verify the input and write the result
2468      *                 to the output variable.
2469      **/
2470     if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2471     {
2472         Utils::_variable_type result_as_int_variable_type =
2473             Utils::getVariableTypeFromProperties(Utils::VARIABLE_TYPE_INT, n_variable_type_components);
2474         std::string variable_type_glsl_as_int = Utils::getVariableTypeGLSLString(result_as_int_variable_type);
2475 
2476         result_sstream << variable_type_glsl_arrayed_sstream.str()
2477                        << " subroutine_result = colorGetterUniform(temp);\n"
2478                           "result = ";
2479 
2480         for (unsigned int array_index = 0; array_index < array_size; ++array_index)
2481         {
2482             if (variable_type_glsl == "bool")
2483                 result_sstream << "bool(subroutine_result";
2484             else
2485                 result_sstream << "all(subroutine_result";
2486 
2487             if (array_size > 1)
2488             {
2489                 result_sstream << "[" << array_index << "]";
2490             }
2491 
2492             result_sstream << ")";
2493 
2494             if (array_index != (array_size - 1))
2495             {
2496                 result_sstream << "&& ";
2497             }
2498         }
2499 
2500         result_sstream << " == true ? " << variable_type_glsl_as_int << "(1) : " << variable_type_glsl_as_int << "(0);";
2501     }
2502     else
2503     {
2504         if (array_size > 1)
2505         {
2506             DE_ASSERT(array_size == 2);
2507 
2508             result_sstream << variable_type_glsl << " subroutine_result" << variable_type_glsl_array_sstream.str()
2509                            << " = colorGetterUniform(temp);\n"
2510                               "\n"
2511                               "if (subroutine_result[0] == subroutine_result[1]) result = subroutine_result[0];\n"
2512                               "else\n"
2513                               "result = "
2514                            << variable_type_glsl << "(-1);\n";
2515         }
2516         else
2517         {
2518             result_sstream << "result = colorGetterUniform(temp);\n";
2519         }
2520     }
2521 
2522     /* All done */
2523     result_sstream << "}\n";
2524 
2525     return result_sstream.str();
2526 }
2527 
2528 /** Initializes all GL objects required to run the test. */
initTest()2529 void FunctionalTest1_2::initTest()
2530 {
2531     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2532 
2533     /* Generate buffer object to hold result XFB data */
2534     gl.genBuffers(1, &m_xfb_bo_id);
2535     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
2536 
2537     /* Set up XFB BO bindings */
2538     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_xfb_bo_id);
2539     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
2540 
2541     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_xfb_bo_id);
2542     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed.");
2543 
2544     /* Generate VAO to use for the draw calls */
2545     gl.genVertexArrays(1, &m_vao_id);
2546     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
2547 
2548     gl.bindVertexArray(m_vao_id);
2549     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
2550 }
2551 
2552 /** Executes test iteration.
2553  *
2554  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
2555  */
iterate()2556 tcu::TestNode::IterateResult FunctionalTest1_2::iterate()
2557 {
2558     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
2559     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
2560     {
2561         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
2562     }
2563 
2564     /* Initialize a test program object */
2565     initTest();
2566 
2567     /* Construct test case descriptors: first, iIerate over all
2568      * variable types we want to cover */
2569     const Utils::_variable_type variable_types[] = {
2570         Utils::VARIABLE_TYPE_BOOL,   Utils::VARIABLE_TYPE_BVEC2,  Utils::VARIABLE_TYPE_BVEC3,
2571         Utils::VARIABLE_TYPE_BVEC4,  Utils::VARIABLE_TYPE_DOUBLE, Utils::VARIABLE_TYPE_FLOAT,
2572         Utils::VARIABLE_TYPE_INT,    Utils::VARIABLE_TYPE_IVEC2,  Utils::VARIABLE_TYPE_IVEC3,
2573         Utils::VARIABLE_TYPE_IVEC4,  Utils::VARIABLE_TYPE_MAT2,   Utils::VARIABLE_TYPE_MAT2X3,
2574         Utils::VARIABLE_TYPE_MAT2X4, Utils::VARIABLE_TYPE_MAT3,   Utils::VARIABLE_TYPE_MAT3X2,
2575         Utils::VARIABLE_TYPE_MAT3X4, Utils::VARIABLE_TYPE_MAT4,   Utils::VARIABLE_TYPE_MAT4X2,
2576         Utils::VARIABLE_TYPE_MAT4X3, Utils::VARIABLE_TYPE_UINT,   Utils::VARIABLE_TYPE_UVEC2,
2577         Utils::VARIABLE_TYPE_UVEC3,  Utils::VARIABLE_TYPE_UVEC4,  Utils::VARIABLE_TYPE_VEC2,
2578         Utils::VARIABLE_TYPE_VEC3,   Utils::VARIABLE_TYPE_VEC4};
2579     const unsigned int n_variable_types = sizeof(variable_types) / sizeof(variable_types[0]);
2580 
2581     for (unsigned int n_variable_type = 0; n_variable_type < n_variable_types; ++n_variable_type)
2582     {
2583         Utils::_variable_type current_variable_type = variable_types[n_variable_type];
2584 
2585         /* We need to test both arrayed and non-arrayed arguments */
2586         for (unsigned int array_size = 1; array_size < 3; ++array_size)
2587         {
2588             /* Exclude double variables if the relevant extension is unavailable */
2589             if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gpu_shader_fp64") &&
2590                 current_variable_type == Utils::VARIABLE_TYPE_DOUBLE)
2591             {
2592                 continue;
2593             }
2594 
2595             /* Form the descriptor */
2596             _test_case test_case;
2597 
2598             test_case.array_size    = array_size;
2599             test_case.variable_type = current_variable_type;
2600 
2601             /* Store the test case descriptor */
2602             m_test_cases.push_back(test_case);
2603         } /* for (both arrayed and non-arrayed arguments) */
2604     }     /* for (all variable types) */
2605 
2606     /* Iterate over all test cases and execute the test */
2607     for (_test_cases_const_iterator test_case_iterator = m_test_cases.begin(); test_case_iterator != m_test_cases.end();
2608          ++test_case_iterator)
2609     {
2610         const _test_case &test_case = *test_case_iterator;
2611 
2612         m_has_test_passed &= executeTestIteration(test_case);
2613 
2614         /* Release GL objects that were created during the execution */
2615         deinitTestIteration();
2616     } /* for (all test cases) */
2617 
2618     /* Done */
2619     if (m_has_test_passed)
2620     {
2621         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2622     }
2623     else
2624     {
2625         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2626     }
2627 
2628     return STOP;
2629 }
2630 
2631 /** Verifies data that has been XFBed out by the vertex shader.
2632  *
2633  *  @param xfb_data      Buffer holding the data.
2634  *  @param variable_type GLSL type used for the test iteration
2635  *                       that generated the data at @param xfb_data.
2636  *
2637  *  @return true if the data was found to be valid, false if it
2638  *               was detected to be incorrect.
2639  **/
verifyXFBData(const void * xfb_data,const Utils::_variable_type & variable_type)2640 bool FunctionalTest1_2::verifyXFBData(const void *xfb_data, const Utils::_variable_type &variable_type)
2641 {
2642     const Utils::_variable_type base_variable_type = Utils::getBaseVariableType(variable_type);
2643     const float epsilon                            = 1e-5f;
2644     const unsigned int n_variable_type_components  = Utils::getNumberOfComponentsForVariableType(variable_type);
2645     bool result                                    = true;
2646     const unsigned char *traveller_ptr             = (const unsigned char *)xfb_data;
2647 
2648     /* Boolean arguments/return types are tested with a slightly different shader so we
2649      * need to test them in a separate code-path.
2650      */
2651     if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2652     {
2653         /* 0 should be returned when getter0 is used, 1 otherwise */
2654         const unsigned int ref_values[] = {0, 1};
2655         const unsigned int n_ref_values = sizeof(ref_values) / sizeof(ref_values[0]);
2656 
2657         for (unsigned int n_ref_value = 0; n_ref_value < n_ref_values; ++n_ref_value)
2658         {
2659             const unsigned int ref_value = ref_values[n_ref_value];
2660 
2661             for (unsigned int n_component = 0; n_component < n_variable_type_components; ++n_component)
2662             {
2663                 int *result_value_ptr = (int *)(traveller_ptr);
2664 
2665                 if (*result_value_ptr != (int)ref_value)
2666                 {
2667                     m_testCtx.getLog() << tcu::TestLog::Message
2668                                        << "Invalid value reported by subroutine using "
2669                                           "["
2670                                        << Utils::getVariableTypeGLSLString(variable_type) << "]"
2671                                        << " argument/return types ("
2672                                           "expected:["
2673                                        << ref_value << "], found:[" << *result_value_ptr << "])"
2674                                        << tcu::TestLog::EndMessage;
2675 
2676                     result = false;
2677                     break;
2678                 }
2679 
2680                 traveller_ptr += sizeof(int);
2681             } /* for (all components) */
2682         }     /* for (all reference values) */
2683     }         /* if (base_variable_type == Utils::VARIABLE_TYPE_BOOL) */
2684     else
2685     {
2686         /* 4 should be returned when getter0 is used, 5 otherwise */
2687         const unsigned int ref_values[] = {4, 5};
2688         const unsigned int n_ref_values = sizeof(ref_values) / sizeof(ref_values[0]);
2689 
2690         for (unsigned int n_ref_value = 0; n_ref_value < n_ref_values; ++n_ref_value)
2691         {
2692             const unsigned int ref_value = ref_values[n_ref_value];
2693 
2694             DE_ASSERT(
2695                 base_variable_type == Utils::VARIABLE_TYPE_DOUBLE || base_variable_type == Utils::VARIABLE_TYPE_FLOAT ||
2696                 base_variable_type == Utils::VARIABLE_TYPE_INT || base_variable_type == Utils::VARIABLE_TYPE_UINT);
2697 
2698             for (unsigned int n_component = 0; n_component < n_variable_type_components; ++n_component)
2699             {
2700                 const double *double_value_ptr = (double *)traveller_ptr;
2701                 const float *float_value_ptr   = (float *)traveller_ptr;
2702                 const int *int_value_ptr       = (int *)traveller_ptr;
2703 
2704                 switch (base_variable_type)
2705                 {
2706                 case Utils::VARIABLE_TYPE_DOUBLE:
2707                 {
2708                     if (de::abs(*double_value_ptr - (double)ref_value) > epsilon)
2709                     {
2710                         m_testCtx.getLog()
2711                             << tcu::TestLog::Message
2712                             << "Invalid value reported by subroutine using "
2713                                "["
2714                             << Utils::getVariableTypeGLSLString(variable_type) << "]"
2715                             << " argument/return types ("
2716                                "expected:["
2717                             << ref_value << "], found:[" << *double_value_ptr << "])" << tcu::TestLog::EndMessage;
2718 
2719                         result = false;
2720                     }
2721 
2722                     traveller_ptr += sizeof(double);
2723                     break;
2724                 }
2725 
2726                 case Utils::VARIABLE_TYPE_FLOAT:
2727                 {
2728                     if (de::abs(*float_value_ptr - (float)ref_value) > epsilon)
2729                     {
2730                         m_testCtx.getLog()
2731                             << tcu::TestLog::Message
2732                             << "Invalid value reported by subroutine using "
2733                                "["
2734                             << Utils::getVariableTypeGLSLString(variable_type) << "]"
2735                             << " argument/return types ("
2736                                "expected:["
2737                             << ref_value << "], found:[" << *float_value_ptr << "])" << tcu::TestLog::EndMessage;
2738 
2739                         result = false;
2740                     }
2741 
2742                     traveller_ptr += sizeof(float);
2743                     break;
2744                 }
2745 
2746                 case Utils::VARIABLE_TYPE_INT:
2747                 case Utils::VARIABLE_TYPE_UINT:
2748                 {
2749                     if (*int_value_ptr != (int)ref_value)
2750                     {
2751                         m_testCtx.getLog()
2752                             << tcu::TestLog::Message
2753                             << "Invalid value reported by subroutine using "
2754                                "["
2755                             << Utils::getVariableTypeGLSLString(variable_type) << "]"
2756                             << " argument/return types ("
2757                                "expected:["
2758                             << ref_value << "], found:[" << *int_value_ptr << "])" << tcu::TestLog::EndMessage;
2759 
2760                         result = false;
2761                     }
2762 
2763                     traveller_ptr += sizeof(int);
2764                     break;
2765                 }
2766 
2767                 default:
2768                     break;
2769                 } /* switch (base_variable_type) */
2770             }     /* for (all components) */
2771         }         /* for (all reference values) */
2772     }
2773 
2774     return result;
2775 }
2776 
2777 /** Constructor
2778  *
2779  * @param context CTS context
2780  **/
FunctionalTest3_4(deqp::Context & context)2781 FunctionalTest3_4::FunctionalTest3_4(deqp::Context &context)
2782     : TestCase(context, "four_subroutines_with_two_uniforms", "Verify Get* API and draw calls")
2783     , m_n_active_subroutine_uniforms(0)
2784     , m_n_active_subroutine_uniform_locations(0)
2785     , m_n_active_subroutines(0)
2786     , m_n_active_subroutine_uniform_name_length(0)
2787     , m_n_active_subroutine_name_length(0)
2788     , m_n_active_subroutine_uniform_size(0)
2789 {
2790     /* Nothing to be done here */
2791 }
2792 
2793 /** Execute test
2794  *
2795  * @return tcu::TestNode::STOP
2796  **/
iterate()2797 tcu::TestNode::IterateResult FunctionalTest3_4::iterate()
2798 {
2799     static const glw::GLchar *vertex_shader_code =
2800         "#version 400 core\n"
2801         "#extension GL_ARB_shader_subroutine : require\n"
2802         "\n"
2803         "precision highp float;\n"
2804         "\n"
2805         "// Sub routine type declaration\n"
2806         "subroutine vec4 routine_type(in vec4 iparam);\n"
2807         "\n"
2808         "// Sub routine definitions\n"
2809         "subroutine(routine_type) vec4 inverse_order(in vec4 iparam)\n"
2810         "{\n"
2811         "    return iparam.wzyx;\n"
2812         "}\n"
2813         "\n"
2814         "subroutine(routine_type) vec4 negate(in vec4 iparam)\n"
2815         "{\n"
2816         "    return -iparam;\n"
2817         "}\n"
2818         "\n"
2819         "subroutine(routine_type) vec4 inverse(in vec4 iparam)\n"
2820         "{\n"
2821         "    return 1 / iparam;\n"
2822         "}\n"
2823         "\n"
2824         "subroutine(routine_type) vec4 square(in vec4 iparam)\n"
2825         "{\n"
2826         "    return iparam * iparam;\n"
2827         "}\n"
2828         "\n"
2829         "// Sub routine uniforms\n"
2830         "subroutine uniform routine_type first_routine;\n"
2831         "subroutine uniform routine_type second_routine;\n"
2832         "\n"
2833         "// Input data\n"
2834         "uniform vec4 input_data;\n"
2835         "\n"
2836         "// Output\n"
2837         "out vec4 out_input_data;\n"
2838         "out vec4 out_result_from_first_routine;\n"
2839         "out vec4 out_result_from_second_routine;\n"
2840         "out vec4 out_result_from_combined_routines;\n"
2841         "out vec4 out_result_from_routines_combined_in_reveresed_order;\n"
2842         "\n"
2843         "void main()\n"
2844         "{\n"
2845         "    out_input_data                                       = input_data;\n"
2846         "    out_result_from_first_routine                        = first_routine(input_data);\n"
2847         "    out_result_from_second_routine                       = second_routine(input_data);\n"
2848         "    out_result_from_combined_routines                    = second_routine(first_routine(input_data));\n"
2849         "    out_result_from_routines_combined_in_reveresed_order = first_routine(second_routine(input_data));\n"
2850         "}\n"
2851         "\n";
2852 
2853     static const GLchar *varying_names[] = {
2854         "out_input_data",
2855         "out_result_from_first_routine",
2856         "out_result_from_second_routine",
2857         "out_result_from_combined_routines",
2858         "out_result_from_routines_combined_in_reveresed_order",
2859     };
2860 
2861     static const GLchar *subroutine_uniform_names[] = {"first_routine", "second_routine"};
2862 
2863     static const GLchar *subroutine_names[] = {"inverse_order", "negate", "inverse", "square"};
2864 
2865     static const GLuint n_varyings                     = sizeof(varying_names) / sizeof(varying_names[0]);
2866     static const GLuint transform_feedback_buffer_size = n_varyings * sizeof(GLfloat) * 4 /* vec4 */;
2867 
2868     static const GLuint inverse_order_routine_index = 0;
2869     static const GLuint negate_routine_index        = 1;
2870     static const GLuint inverse_routine_index       = 2;
2871     static const GLuint square_routine_index        = 3;
2872 
2873     /* Test data */
2874     static const Utils::vec4<GLfloat> inverse_order_negate_data[5] = {
2875         Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
2876         Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f), Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f),
2877         Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f),
2878     };
2879 
2880     static const Utils::vec4<GLfloat> inverse_order_inverse_data[5] = {
2881         Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
2882         Utils::vec4<GLfloat>(-0.5f, -1.0f, 1.0f, 0.5f), Utils::vec4<GLfloat>(0.5f, 1.0f, -1.0f, -0.5f),
2883         Utils::vec4<GLfloat>(0.5f, 1.0f, -1.0f, -0.5f),
2884     };
2885 
2886     static const Utils::vec4<GLfloat> inverse_order_square_data[5] = {
2887         Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
2888         Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f),   Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f),
2889         Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f),
2890     };
2891 
2892     static const Utils::vec4<GLfloat> negate_inverse_data[5] = {
2893         Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
2894         Utils::vec4<GLfloat>(-0.5f, -1.0f, 1.0f, 0.5f), Utils::vec4<GLfloat>(0.5f, 1.0f, -1.0f, -0.5f),
2895         Utils::vec4<GLfloat>(0.5f, 1.0f, -1.0f, -0.5f),
2896     };
2897 
2898     static const Utils::vec4<GLfloat> negate_square_data[5] = {
2899         Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f),   Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
2900         Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f),     Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f),
2901         Utils::vec4<GLfloat>(-4.0f, -1.0f, -1.0f, -4.0f),
2902     };
2903 
2904     static const Utils::vec4<GLfloat> inverse_square_data[5] = {
2905         Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(-0.5f, -1.0f, 1.0f, 0.5f),
2906         Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f),   Utils::vec4<GLfloat>(0.25f, 1.0f, 1.0f, 0.25f),
2907         Utils::vec4<GLfloat>(0.25f, 1.0f, 1.0f, 0.25f),
2908     };
2909 
2910     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
2911     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
2912     {
2913         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
2914     }
2915 
2916     m_n_active_subroutine_uniforms            = 2;
2917     m_n_active_subroutine_uniform_locations   = 2;
2918     m_n_active_subroutines                    = 4;
2919     m_n_active_subroutine_uniform_name_length = 0;
2920     m_n_active_subroutine_name_length         = 0;
2921     m_n_active_subroutine_uniform_size        = 1;
2922 
2923     /* GL objects */
2924     Utils::program program(m_context);
2925     Utils::buffer transform_feedback_buffer(m_context);
2926     Utils::vertexArray vao(m_context);
2927 
2928     bool result = true;
2929 
2930     /* Calculate max name lengths for subroutines and subroutine uniforms */
2931     for (GLint i = 0; i < m_n_active_subroutine_uniforms; ++i)
2932     {
2933         const GLsizei length = (GLsizei)strlen(subroutine_uniform_names[i]);
2934 
2935         if (length > m_n_active_subroutine_uniform_name_length)
2936         {
2937             m_n_active_subroutine_uniform_name_length = length;
2938         }
2939     }
2940 
2941     for (GLint i = 0; i < m_n_active_subroutines; ++i)
2942     {
2943         const GLsizei length = (GLsizei)strlen(subroutine_names[i]);
2944 
2945         if (length > m_n_active_subroutine_name_length)
2946         {
2947             m_n_active_subroutine_name_length = length;
2948         }
2949     }
2950 
2951     /* Init */
2952     program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code, varying_names,
2953                   n_varyings);
2954 
2955     vao.generate();
2956     vao.bind();
2957 
2958     transform_feedback_buffer.generate();
2959     transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
2960                                      GL_DYNAMIC_COPY);
2961     transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
2962 
2963     program.use();
2964 
2965     /* Inspect Get* API */
2966     if ((false == inspectProgramStageiv(program.m_program_object_id)) ||
2967         (false == inspectActiveSubroutineUniformiv(program.m_program_object_id, subroutine_uniform_names)) ||
2968         (false == inspectActiveSubroutineUniformName(program.m_program_object_id, subroutine_uniform_names)) ||
2969         (false == inspectActiveSubroutineName(program.m_program_object_id, subroutine_names)) ||
2970         (false ==
2971          inspectSubroutineBinding(program.m_program_object_id, subroutine_names, subroutine_uniform_names, false)))
2972     {
2973         result = false;
2974     }
2975 
2976     /* Inspect GetProgram* API */
2977     if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_program_interface_query"))
2978     {
2979         if ((false == inspectProgramInterfaceiv(program.m_program_object_id)) ||
2980             (false ==
2981              inspectProgramResourceiv(program.m_program_object_id, subroutine_names, subroutine_uniform_names)) ||
2982             (false ==
2983              inspectSubroutineBinding(program.m_program_object_id, subroutine_names, subroutine_uniform_names, true)))
2984         {
2985             result = false;
2986         }
2987     }
2988 
2989     /* Test shader execution */
2990     if ((false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
2991                            subroutine_names[negate_routine_index], subroutine_uniform_names, inverse_order_negate_data,
2992                            false)) ||
2993         (false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
2994                            subroutine_names[inverse_routine_index], subroutine_uniform_names,
2995                            inverse_order_inverse_data, false)) ||
2996         (false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
2997                            subroutine_names[square_routine_index], subroutine_uniform_names, inverse_order_square_data,
2998                            false)) ||
2999         (false == testDraw(program.m_program_object_id, subroutine_names[negate_routine_index],
3000                            subroutine_names[inverse_routine_index], subroutine_uniform_names, negate_inverse_data,
3001                            false)) ||
3002         (false == testDraw(program.m_program_object_id, subroutine_names[negate_routine_index],
3003                            subroutine_names[square_routine_index], subroutine_uniform_names, negate_square_data,
3004                            false)) ||
3005         (false == testDraw(program.m_program_object_id, subroutine_names[inverse_routine_index],
3006                            subroutine_names[square_routine_index], subroutine_uniform_names, inverse_square_data,
3007                            false)))
3008     {
3009         result = false;
3010     }
3011 
3012     if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_program_interface_query"))
3013     {
3014         if ((false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
3015                                subroutine_names[negate_routine_index], subroutine_uniform_names,
3016                                inverse_order_negate_data, true)) ||
3017             (false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
3018                                subroutine_names[inverse_routine_index], subroutine_uniform_names,
3019                                inverse_order_inverse_data, true)) ||
3020             (false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
3021                                subroutine_names[square_routine_index], subroutine_uniform_names,
3022                                inverse_order_square_data, true)) ||
3023             (false == testDraw(program.m_program_object_id, subroutine_names[negate_routine_index],
3024                                subroutine_names[inverse_routine_index], subroutine_uniform_names, negate_inverse_data,
3025                                true)) ||
3026             (false == testDraw(program.m_program_object_id, subroutine_names[negate_routine_index],
3027                                subroutine_names[square_routine_index], subroutine_uniform_names, negate_square_data,
3028                                true)) ||
3029             (false == testDraw(program.m_program_object_id, subroutine_names[inverse_routine_index],
3030                                subroutine_names[square_routine_index], subroutine_uniform_names, inverse_square_data,
3031                                true)))
3032         {
3033             result = false;
3034         }
3035     }
3036 
3037     /* Done */
3038     if (true == result)
3039     {
3040         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3041     }
3042     else
3043     {
3044         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
3045     }
3046 
3047     return tcu::TestNode::STOP;
3048 }
3049 
3050 /** Verify result of getProgramStageiv
3051  *
3052  * @param program_id Program object id
3053  * @param pname      <pname> parameter for getProgramStageiv
3054  * @param expected   Expected value
3055  *
3056  * @return true if result is equal to expected value, flase otherwise
3057  **/
checkProgramStageiv(glw::GLuint program_id,glw::GLenum pname,glw::GLint expected) const3058 bool FunctionalTest3_4::checkProgramStageiv(glw::GLuint program_id, glw::GLenum pname, glw::GLint expected) const
3059 {
3060     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3061     GLint value              = 0;
3062 
3063     gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, pname, &value);
3064     GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3065 
3066     if (expected != value)
3067     {
3068         m_context.getTestContext().getLog()
3069             << tcu::TestLog::Message << "Error. Invalid result. Function: getProgramStageiv. "
3070             << "pname: " << Utils::pnameToStr(pname) << ". "
3071             << "Result: " << value << ". "
3072             << "Expected: " << expected << "." << tcu::TestLog::EndMessage;
3073 
3074         return false;
3075     }
3076     else
3077     {
3078         return true;
3079     }
3080 }
3081 
3082 /** Verify result of getProgramResourceiv
3083  *
3084  * @param program_id        Program object id
3085  * @param program_interface Program interface
3086  * @param pname             <pname> parameter for getProgramStageiv
3087  * @param resource_name     Resource name
3088  * @param expected          Expected value
3089  *
3090  * @return true if result is equal to expected value, false otherwise
3091  **/
checkProgramResourceiv(GLuint program_id,GLenum program_interface,GLenum pname,const glw::GLchar * resource_name,GLint expected) const3092 bool FunctionalTest3_4::checkProgramResourceiv(GLuint program_id, GLenum program_interface, GLenum pname,
3093                                                const glw::GLchar *resource_name, GLint expected) const
3094 {
3095     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3096     GLuint index             = gl.getProgramResourceIndex(program_id, program_interface, resource_name);
3097     GLint value              = 0;
3098 
3099     if (GL_INVALID_INDEX == index)
3100     {
3101         return false;
3102     }
3103 
3104     gl.getProgramResourceiv(program_id, program_interface, index, 1, &pname, 1, 0, &value);
3105     GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramResourceiv");
3106 
3107     if (expected != value)
3108     {
3109         m_context.getTestContext().getLog()
3110             << tcu::TestLog::Message << "Error. Invalid result. Function: getProgramResourceiv. "
3111             << "Program interface: " << Utils::programInterfaceToStr(program_interface) << ". "
3112             << "Resource name: " << resource_name << ". "
3113             << "Property: " << Utils::pnameToStr(pname) << ". "
3114             << "Result: " << value << ". "
3115             << "Expected: " << expected << "." << tcu::TestLog::EndMessage;
3116 
3117         return false;
3118     }
3119     else
3120     {
3121         return true;
3122     }
3123 }
3124 
3125 /** Verify result of getProgramInterfaceiv
3126  *
3127  * @param program_id        Program object id
3128  * @param program_interface Program interface
3129  * @param pname             <pname> parameter for getProgramStageiv
3130  * @param expected          Expected value
3131  *
3132  * @return true if result is equal to expected value, flase otherwise
3133  **/
checkProgramInterfaceiv(GLuint program_id,GLenum program_interface,GLenum pname,GLint expected) const3134 bool FunctionalTest3_4::checkProgramInterfaceiv(GLuint program_id, GLenum program_interface, GLenum pname,
3135                                                 GLint expected) const
3136 {
3137     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3138     GLint value              = 0;
3139 
3140     gl.getProgramInterfaceiv(program_id, program_interface, pname, &value);
3141     GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramInterfaceiv");
3142 
3143     if (expected != value)
3144     {
3145         m_context.getTestContext().getLog()
3146             << tcu::TestLog::Message << "Error. Invalid result. Function: getProgramInterfaceiv. "
3147             << "Program interface: " << Utils::programInterfaceToStr(program_interface) << ". "
3148             << "pname: " << Utils::pnameToStr(pname) << ". "
3149             << "Result: " << value << ". "
3150             << "Expected: " << expected << "." << tcu::TestLog::EndMessage;
3151 
3152         return false;
3153     }
3154     else
3155     {
3156         return true;
3157     }
3158 }
3159 
3160 /** Verify result of getActiveSubroutineUniformiv
3161  *
3162  * @param program_id Program object id
3163  * @param index      <index> parameter for getActiveSubroutineUniformiv
3164  * @param pname      <pname> parameter for getActiveSubroutineUniformiv
3165  * @param expected   Expected value
3166  *
3167  * @return true if result is equal to expected value, flase otherwise
3168  **/
checkActiveSubroutineUniformiv(GLuint program_id,GLuint index,GLenum pname,GLint expected) const3169 bool FunctionalTest3_4::checkActiveSubroutineUniformiv(GLuint program_id, GLuint index, GLenum pname,
3170                                                        GLint expected) const
3171 {
3172     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3173     GLint value              = 0;
3174 
3175     gl.getActiveSubroutineUniformiv(program_id, GL_VERTEX_SHADER, index, pname, &value);
3176     GLU_EXPECT_NO_ERROR(gl.getError(), "getActiveSubroutineUniformiv");
3177 
3178     if (expected != value)
3179     {
3180         m_context.getTestContext().getLog()
3181             << tcu::TestLog::Message << "Error. Invalid result. Function: getActiveSubroutineUniformiv. "
3182             << "idnex: " << index << ". "
3183             << "pname: " << Utils::pnameToStr(pname) << ". "
3184             << "Result: " << value << ". "
3185             << "Expected: " << expected << "." << tcu::TestLog::EndMessage;
3186 
3187         return false;
3188     }
3189     else
3190     {
3191         return true;
3192     }
3193 }
3194 
3195 /** Returns index of program resource
3196  *
3197  * @param program_id        Program object id
3198  * @param program_interface Program interface
3199  * @param resource_name     Name of resource
3200  *
3201  * @return Index of specified resource
3202  **/
getProgramResourceIndex(GLuint program_id,GLenum program_interface,const glw::GLchar * resource_name) const3203 GLuint FunctionalTest3_4::getProgramResourceIndex(GLuint program_id, GLenum program_interface,
3204                                                   const glw::GLchar *resource_name) const
3205 {
3206     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3207     GLuint index             = gl.getProgramResourceIndex(program_id, program_interface, resource_name);
3208 
3209     GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramResourceIndex");
3210 
3211     if (GL_INVALID_INDEX == index)
3212     {
3213         m_context.getTestContext().getLog()
3214             << tcu::TestLog::Message << "Error. Program resource is not available. "
3215             << "Program interface: " << Utils::programInterfaceToStr(program_interface) << ". "
3216             << "Resource name: " << resource_name << "." << tcu::TestLog::EndMessage;
3217     }
3218 
3219     return index;
3220 }
3221 
3222 /** Get subroutine index
3223  *
3224  * @param program_id        Program object id
3225  * @param subroutine_name   Subroutine name
3226  * @param use_program_query If true getProgramResourceIndex is used, otherwise getSubroutineIndex
3227  *
3228  * @return Index of subroutine
3229  **/
getSubroutineIndex(GLuint program_id,const glw::GLchar * subroutine_name,bool use_program_query) const3230 GLuint FunctionalTest3_4::getSubroutineIndex(GLuint program_id, const glw::GLchar *subroutine_name,
3231                                              bool use_program_query) const
3232 {
3233     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3234     GLuint index             = -1;
3235 
3236     if (false == use_program_query)
3237     {
3238         index = gl.getSubroutineIndex(program_id, GL_VERTEX_SHADER, subroutine_name);
3239         GLU_EXPECT_NO_ERROR(gl.getError(), "GetSubroutineIndex");
3240     }
3241     else
3242     {
3243         index = gl.getProgramResourceIndex(program_id, GL_VERTEX_SUBROUTINE, subroutine_name);
3244         GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramResourceIndex");
3245     }
3246 
3247     if (GL_INVALID_INDEX == index)
3248     {
3249         TCU_FAIL("Subroutine is not available");
3250     }
3251 
3252     return index;
3253 }
3254 
3255 /** Get subroutine uniform location
3256  *
3257  * @param program_id        Program object id
3258  * @param uniform_name      Subroutine uniform name
3259  * @param use_program_query If true getProgramResourceLocation is used, otherwise getSubroutineUniformLocation
3260  *
3261  * @return Location of subroutine uniform
3262  **/
getSubroutineUniformLocation(GLuint program_id,const glw::GLchar * uniform_name,bool use_program_query) const3263 GLint FunctionalTest3_4::getSubroutineUniformLocation(GLuint program_id, const glw::GLchar *uniform_name,
3264                                                       bool use_program_query) const
3265 {
3266     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3267     GLint location           = -1;
3268 
3269     if (false == use_program_query)
3270     {
3271         location = gl.getSubroutineUniformLocation(program_id, GL_VERTEX_SHADER, uniform_name);
3272         GLU_EXPECT_NO_ERROR(gl.getError(), "GetSubroutineUniformLocation");
3273     }
3274     else
3275     {
3276         location = gl.getProgramResourceLocation(program_id, GL_VERTEX_SUBROUTINE_UNIFORM, uniform_name);
3277         GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramResourceLocation");
3278     }
3279 
3280     if (-1 == location)
3281     {
3282         TCU_FAIL("Subroutine uniform is not available");
3283     }
3284 
3285     return location;
3286 }
3287 
3288 /** Test if getProgramStageiv results are as expected
3289  *
3290  * @param program_id Program object id
3291  *
3292  * @result false in case of invalid result for any pname, true otherwise
3293  **/
inspectProgramStageiv(glw::GLuint program_id) const3294 bool FunctionalTest3_4::inspectProgramStageiv(glw::GLuint program_id) const
3295 {
3296     bool result = true;
3297 
3298     const inspectionDetails details[] = {
3299         {GL_ACTIVE_SUBROUTINE_UNIFORMS, m_n_active_subroutine_uniforms},
3300         {GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS, m_n_active_subroutine_uniform_locations},
3301         {GL_ACTIVE_SUBROUTINES, m_n_active_subroutines},
3302         {GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH, m_n_active_subroutine_uniform_name_length + 1},
3303         {GL_ACTIVE_SUBROUTINE_MAX_LENGTH, m_n_active_subroutine_name_length + 1}};
3304     const GLuint n_details = sizeof(details) / sizeof(details[0]);
3305 
3306     for (GLuint i = 0; i < n_details; ++i)
3307     {
3308         if (false == checkProgramStageiv(program_id, details[i].pname, details[i].expected_value))
3309         {
3310             result = false;
3311         }
3312     }
3313 
3314     return result;
3315 }
3316 
3317 /** Test if checkProgramInterfaceiv results are as expected
3318  *
3319  * @param program_id Program object id
3320  *
3321  * @result false in case of invalid result for any pname, true otherwise
3322  **/
inspectProgramInterfaceiv(glw::GLuint program_id) const3323 bool FunctionalTest3_4::inspectProgramInterfaceiv(glw::GLuint program_id) const
3324 {
3325     bool result = true;
3326 
3327     const inspectionDetailsForProgramInterface details[] = {
3328         {GL_VERTEX_SUBROUTINE_UNIFORM, GL_ACTIVE_RESOURCES, m_n_active_subroutine_uniforms},
3329         {GL_VERTEX_SUBROUTINE_UNIFORM, GL_MAX_NAME_LENGTH, m_n_active_subroutine_uniform_name_length + 1},
3330         {GL_VERTEX_SUBROUTINE_UNIFORM, GL_MAX_NUM_COMPATIBLE_SUBROUTINES, m_n_active_subroutines},
3331         {GL_VERTEX_SUBROUTINE, GL_ACTIVE_RESOURCES, m_n_active_subroutines},
3332         {GL_VERTEX_SUBROUTINE, GL_MAX_NAME_LENGTH, m_n_active_subroutine_name_length + 1}};
3333     const GLuint n_details = sizeof(details) / sizeof(details[0]);
3334 
3335     for (GLuint i = 0; i < n_details; ++i)
3336     {
3337         if (false == checkProgramInterfaceiv(program_id, details[i].program_interface, details[i].pname,
3338                                              details[i].expected_value))
3339         {
3340             result = false;
3341         }
3342     }
3343 
3344     return result;
3345 }
3346 
3347 /** Test if checkProgramResourceiv results are as expected
3348  *
3349  * @param program_id       Program object id
3350  * @param subroutine_names Array of subroutine names
3351  * @param uniform_names    Array of uniform names
3352  *
3353  * @result false in case of invalid result for any pname, true otherwise
3354  **/
inspectProgramResourceiv(GLuint program_id,const GLchar ** subroutine_names,const GLchar ** uniform_names) const3355 bool FunctionalTest3_4::inspectProgramResourceiv(GLuint program_id, const GLchar **subroutine_names,
3356                                                  const GLchar **uniform_names) const
3357 {
3358     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3359     bool result              = true;
3360 
3361     for (GLint subroutine = 0; subroutine < m_n_active_subroutines; ++subroutine)
3362     {
3363         const GLchar *subroutine_name = subroutine_names[subroutine];
3364         const GLint length            = (GLint)strlen(subroutine_name) + 1;
3365 
3366         if (false == checkProgramResourceiv(program_id, GL_VERTEX_SUBROUTINE, GL_NAME_LENGTH, subroutine_name, length))
3367         {
3368             result = false;
3369         }
3370     }
3371 
3372     inspectionDetails details[] = {
3373         {GL_NAME_LENGTH, 0},
3374         {GL_ARRAY_SIZE, 1},
3375         {GL_NUM_COMPATIBLE_SUBROUTINES, m_n_active_subroutines},
3376         {GL_LOCATION, 0},
3377     };
3378     const GLuint n_details = sizeof(details) / sizeof(details[0]);
3379 
3380     for (GLint uniform = 0; uniform < m_n_active_subroutine_uniforms; ++uniform)
3381     {
3382         const GLchar *uniform_name = uniform_names[uniform];
3383         const GLint length         = (GLint)strlen(uniform_name) + 1;
3384         const GLint location       = getSubroutineUniformLocation(program_id, uniform_name, true);
3385 
3386         details[0].expected_value = length;
3387         details[3].expected_value = location;
3388 
3389         for (GLuint i = 0; i < n_details; ++i)
3390         {
3391             if (false == checkProgramResourceiv(program_id, GL_VERTEX_SUBROUTINE_UNIFORM, details[i].pname,
3392                                                 uniform_name, details[i].expected_value))
3393             {
3394                 result = false;
3395             }
3396         }
3397 
3398         /* Check compatible subroutines */
3399         GLuint index = getProgramResourceIndex(program_id, GL_VERTEX_SUBROUTINE_UNIFORM, uniform_name);
3400 
3401         if (GL_INVALID_INDEX != index)
3402         {
3403             std::vector<GLint> compatible_subroutines;
3404             GLint index_sum = 0;
3405             GLenum prop     = GL_COMPATIBLE_SUBROUTINES;
3406 
3407             compatible_subroutines.resize(m_n_active_subroutines);
3408 
3409             gl.getProgramResourceiv(program_id, GL_VERTEX_SUBROUTINE_UNIFORM, index, 1, &prop, m_n_active_subroutines,
3410                                     0, &compatible_subroutines[0]);
3411 
3412             GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramResourceiv");
3413 
3414             /* Expected indices are 0, 1, 2, ... N */
3415             for (GLint i = 0; i < m_n_active_subroutines; ++i)
3416             {
3417                 index_sum += compatible_subroutines[i];
3418             }
3419 
3420             /* Sum of E1, ..., EN = (E1 + EN) * N / 2 */
3421             if (((m_n_active_subroutines - 1) * m_n_active_subroutines) / 2 != index_sum)
3422             {
3423                 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
3424 
3425                 message << "Error. Invalid result. Function: getProgramResourceiv. "
3426                         << "Program interface: GL_VERTEX_SUBROUTINE_UNIFORM. "
3427                         << "Resource name: " << uniform_name << ". "
3428                         << "Property: GL_COMPATIBLE_SUBROUTINES. "
3429                         << "Results: ";
3430 
3431                 for (GLint i = 1; i < m_n_active_subroutines; ++i)
3432                 {
3433                     message << compatible_subroutines[i];
3434                 }
3435 
3436                 message << tcu::TestLog::EndMessage;
3437 
3438                 result = false;
3439             }
3440         }
3441     }
3442 
3443     return result;
3444 }
3445 
3446 /** Test if getActiveSubroutineUniformiv results are as expected
3447  *
3448  * @param program_id    Program object id
3449  * @param uniform_names Array of subroutine uniform names available in program
3450  *
3451  * @result false in case of invalid result for any pname, true otherwise
3452  **/
inspectActiveSubroutineUniformiv(GLuint program_id,const GLchar ** uniform_names) const3453 bool FunctionalTest3_4::inspectActiveSubroutineUniformiv(GLuint program_id, const GLchar **uniform_names) const
3454 {
3455     const glw::Functions &gl           = m_context.getRenderContext().getFunctions();
3456     bool result                        = true;
3457     GLint n_active_subroutine_uniforms = 0;
3458 
3459     inspectionDetails details[] = {
3460         {GL_NUM_COMPATIBLE_SUBROUTINES, m_n_active_subroutines},
3461         {GL_UNIFORM_SIZE, m_n_active_subroutine_uniform_size},
3462         {GL_UNIFORM_NAME_LENGTH, 0},
3463     };
3464     const GLuint n_details = sizeof(details) / sizeof(details[0]);
3465 
3466     /* Get amount of active subroutine uniforms */
3467     gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORMS, &n_active_subroutine_uniforms);
3468     GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3469 
3470     for (GLint uniform = 0; uniform < n_active_subroutine_uniforms; ++uniform)
3471     {
3472         GLint name_length = (GLint)strlen(uniform_names[uniform]);
3473 
3474         details[2].expected_value = name_length + 1;
3475 
3476         /* Checks from "details" */
3477         for (GLuint i = 0; i < n_details; ++i)
3478         {
3479             if (false ==
3480                 checkActiveSubroutineUniformiv(program_id, uniform, details[i].pname, details[i].expected_value))
3481             {
3482                 result = false;
3483             }
3484         }
3485 
3486         /* Check compatible subroutines */
3487         std::vector<GLint> compatible_subroutines;
3488         compatible_subroutines.resize(m_n_active_subroutines);
3489         GLint index_sum = 0;
3490 
3491         gl.getActiveSubroutineUniformiv(program_id, GL_VERTEX_SHADER, uniform, GL_COMPATIBLE_SUBROUTINES,
3492                                         &compatible_subroutines[0]);
3493         GLU_EXPECT_NO_ERROR(gl.getError(), "getActiveSubroutineUniformiv");
3494 
3495         /* Expected indices are 0, 1, 2, ... N */
3496         for (GLint i = 0; i < m_n_active_subroutines; ++i)
3497         {
3498             index_sum += compatible_subroutines[i];
3499         }
3500 
3501         /* Sum of E1, ..., EN = (E1 + EN) * N / 2 */
3502         if (((m_n_active_subroutines - 1) * m_n_active_subroutines) / 2 != index_sum)
3503         {
3504             tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
3505 
3506             message << "Error. Invalid result. Function: getActiveSubroutineUniformiv. idnex: " << uniform
3507                     << ". pname: " << Utils::pnameToStr(GL_COMPATIBLE_SUBROUTINES) << ". Results: ";
3508 
3509             for (GLint i = 1; i < m_n_active_subroutines; ++i)
3510             {
3511                 message << compatible_subroutines[i];
3512             }
3513 
3514             message << tcu::TestLog::EndMessage;
3515 
3516             result = false;
3517         }
3518     }
3519 
3520     return result;
3521 }
3522 
3523 /** Test if getActiveSubroutineUniformName results are as expected
3524  *
3525  * @param program_id    Program object id
3526  * @param uniform_names Array of subroutine uniform names available in program
3527  *
3528  * @result false in case of invalid result, true otherwise
3529  **/
inspectActiveSubroutineUniformName(GLuint program_id,const GLchar ** uniform_names) const3530 bool FunctionalTest3_4::inspectActiveSubroutineUniformName(GLuint program_id, const GLchar **uniform_names) const
3531 {
3532     const glw::Functions &gl           = m_context.getRenderContext().getFunctions();
3533     bool result                        = true;
3534     GLint n_active_subroutine_uniforms = 0;
3535     std::vector<GLchar> active_uniform_name;
3536 
3537     gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORMS, &n_active_subroutine_uniforms);
3538     GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3539 
3540     active_uniform_name.resize(m_n_active_subroutine_uniform_name_length + 1);
3541 
3542     for (GLint uniform = 0; uniform < n_active_subroutine_uniforms; ++uniform)
3543     {
3544         bool is_name_ok = false;
3545 
3546         gl.getActiveSubroutineUniformName(program_id, GL_VERTEX_SHADER, uniform, (GLsizei)active_uniform_name.size(),
3547                                           0 /* length */, &active_uniform_name[0]);
3548         GLU_EXPECT_NO_ERROR(gl.getError(), "GetActiveSubroutineUniformName");
3549 
3550         for (GLint name = 0; name < n_active_subroutine_uniforms; ++name)
3551         {
3552             if (0 == strcmp(uniform_names[name], &active_uniform_name[0]))
3553             {
3554                 is_name_ok = true;
3555                 break;
3556             }
3557         }
3558 
3559         if (false == is_name_ok)
3560         {
3561             m_context.getTestContext().getLog()
3562                 << tcu::TestLog::Message
3563                 << "Error. Invalid result. Function: getActiveSubroutineUniformName. idnex: " << uniform
3564                 << ". Result: " << &active_uniform_name[0] << tcu::TestLog::EndMessage;
3565 
3566             result = false;
3567             break;
3568         }
3569     }
3570 
3571     return result;
3572 }
3573 
3574 /** Test if getActiveSubroutineUniformName results are as expected
3575  *
3576  * @param program_id       Program object id
3577  * @param subroutine_names Array of subroutine names available in program
3578  *
3579  * @result false in case of invalid result, true otherwise
3580  **/
inspectActiveSubroutineName(GLuint program_id,const GLchar ** subroutine_names) const3581 bool FunctionalTest3_4::inspectActiveSubroutineName(GLuint program_id, const GLchar **subroutine_names) const
3582 {
3583     const glw::Functions &gl   = m_context.getRenderContext().getFunctions();
3584     bool result                = true;
3585     GLint n_active_subroutines = 0;
3586     std::vector<GLchar> active_subroutine_name;
3587 
3588     gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINES, &n_active_subroutines);
3589     GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3590 
3591     active_subroutine_name.resize(m_n_active_subroutine_name_length + 1);
3592 
3593     for (GLint uniform = 0; uniform < n_active_subroutines; ++uniform)
3594     {
3595         bool is_name_ok = false;
3596 
3597         gl.getActiveSubroutineName(program_id, GL_VERTEX_SHADER, uniform, (GLsizei)active_subroutine_name.size(),
3598                                    0 /* length */, &active_subroutine_name[0]);
3599         GLU_EXPECT_NO_ERROR(gl.getError(), "getActiveSubroutineName");
3600 
3601         for (GLint name = 0; name < n_active_subroutines; ++name)
3602         {
3603             if (0 == strcmp(subroutine_names[name], &active_subroutine_name[0]))
3604             {
3605                 is_name_ok = true;
3606                 break;
3607             }
3608         }
3609 
3610         if (false == is_name_ok)
3611         {
3612             m_context.getTestContext().getLog()
3613                 << tcu::TestLog::Message
3614                 << "Error. Invalid result. Function: getActiveSubroutineName. idnex: " << uniform
3615                 << ". Result: " << &active_subroutine_name[0] << tcu::TestLog::EndMessage;
3616 
3617             result = false;
3618             break;
3619         }
3620     }
3621 
3622     return result;
3623 }
3624 
3625 /** Test if it is possible to "bind" all subroutines uniforms with all subroutines
3626  *
3627  * @param program_id       Program object id
3628  * @param subroutine_names Array of subroutine names available in program
3629  * @param uniform_names    Array of subroutine uniform names available in program
3630  *
3631  * @result false in case of invalid result, true otherwise
3632  **/
inspectSubroutineBinding(GLuint program_id,const GLchar ** subroutine_names,const GLchar ** uniform_names,bool use_program_query) const3633 bool FunctionalTest3_4::inspectSubroutineBinding(GLuint program_id, const GLchar **subroutine_names,
3634                                                  const GLchar **uniform_names, bool use_program_query) const
3635 {
3636     const glw::Functions &gl           = m_context.getRenderContext().getFunctions();
3637     bool result                        = true;
3638     GLint n_active_subroutines         = 0;
3639     GLint n_active_subroutine_uniforms = 0;
3640     std::vector<GLuint> subroutine_uniforms;
3641     GLuint queried_subroutine_index = 0;
3642 
3643     gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINES, &n_active_subroutines);
3644     GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3645 
3646     gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORMS, &n_active_subroutine_uniforms);
3647     GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3648 
3649     subroutine_uniforms.resize(n_active_subroutine_uniforms);
3650 
3651     for (GLint uniform = 0; uniform < n_active_subroutine_uniforms; ++uniform)
3652     {
3653         GLuint uniform_location = getSubroutineUniformLocation(program_id, uniform_names[uniform], use_program_query);
3654 
3655         for (GLint routine = 0; routine < n_active_subroutines; ++routine)
3656         {
3657             GLuint routine_index = getSubroutineIndex(program_id, subroutine_names[routine], use_program_query);
3658 
3659             subroutine_uniforms[uniform] = routine_index;
3660 
3661             gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, n_active_subroutine_uniforms, &subroutine_uniforms[0]);
3662             GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
3663 
3664             gl.getUniformSubroutineuiv(GL_VERTEX_SHADER, uniform_location, &queried_subroutine_index);
3665             GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv");
3666 
3667             if (queried_subroutine_index != routine_index)
3668             {
3669                 m_context.getTestContext().getLog()
3670                     << tcu::TestLog::Message << "Error. Invalid result. Function: gl.getUniformSubroutineuiv."
3671                     << " Subroutine uniform: " << uniform << ", name: " << uniform_names[uniform]
3672                     << ", location: " << uniform_location << ". Subroutine: " << routine
3673                     << ", name: " << subroutine_names[routine] << ", index: " << routine_index
3674                     << ". Result: " << queried_subroutine_index << tcu::TestLog::EndMessage;
3675 
3676                 result = false;
3677             }
3678         }
3679     }
3680 
3681     return result;
3682 }
3683 
3684 /** Execute draw call and verify results
3685  *
3686  * @param program_id                   Program object id
3687  * @param first_routine_name           Name of subroutine that shall be used aas first_routine
3688  * @param second_routine_name          Name of subroutine that shall be used aas second_routine
3689  * @param uniform_names                Name of uniforms
3690  * @param expected_results             Test data. [0] is used as input data. All are used as expected_results
3691  * @param use_program_query            If true GetProgram* API will be used
3692  *
3693  * @return false in case of invalid result, true otherwise
3694  **/
testDraw(GLuint program_id,const GLchar * first_routine_name,const GLchar * second_routine_name,const GLchar ** uniform_names,const Utils::vec4<GLfloat> expected_results[5],bool use_program_query) const3695 bool FunctionalTest3_4::testDraw(GLuint program_id, const GLchar *first_routine_name, const GLchar *second_routine_name,
3696                                  const GLchar **uniform_names, const Utils::vec4<GLfloat> expected_results[5],
3697                                  bool use_program_query) const
3698 {
3699     static const GLuint n_varyings = 5;
3700     const glw::Functions &gl       = m_context.getRenderContext().getFunctions();
3701     bool result                    = true;
3702     GLuint subroutine_uniforms[2]  = {0};
3703 
3704     /* Get subroutine uniform locations */
3705     GLint first_routine_location = getSubroutineUniformLocation(program_id, uniform_names[0], use_program_query);
3706 
3707     GLint second_routine_location = getSubroutineUniformLocation(program_id, uniform_names[1], use_program_query);
3708 
3709     /* Get subroutine indices */
3710     GLuint first_routine_index = getSubroutineIndex(program_id, first_routine_name, use_program_query);
3711 
3712     GLuint second_routine_index = getSubroutineIndex(program_id, second_routine_name, use_program_query);
3713 
3714     /* Map uniforms with subroutines */
3715     subroutine_uniforms[first_routine_location]  = first_routine_index;
3716     subroutine_uniforms[second_routine_location] = second_routine_index;
3717 
3718     gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, 2 /* number of uniforms */, &subroutine_uniforms[0]);
3719     GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
3720 
3721     /* Get location of input_data */
3722     GLint input_data_location = gl.getUniformLocation(program_id, "input_data");
3723     GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation");
3724 
3725     if (-1 == input_data_location)
3726     {
3727         TCU_FAIL("Uniform is not available");
3728     }
3729 
3730     /* Set up input_data */
3731     gl.uniform4f(input_data_location, expected_results[0].m_x, expected_results[0].m_y, expected_results[0].m_z,
3732                  expected_results[0].m_w);
3733     GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
3734 
3735     /* Execute draw call with transform feedback */
3736     gl.beginTransformFeedback(GL_POINTS);
3737     GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
3738 
3739     gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
3740     GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
3741 
3742     gl.endTransformFeedback();
3743     GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
3744 
3745     /* Verify results */
3746     GLfloat *feedback_data = (GLfloat *)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
3747     GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
3748 
3749     Utils::vec4<GLfloat> results[5];
3750 
3751     results[0].m_x = feedback_data[0];
3752     results[0].m_y = feedback_data[1];
3753     results[0].m_z = feedback_data[2];
3754     results[0].m_w = feedback_data[3];
3755 
3756     results[1].m_x = feedback_data[4];
3757     results[1].m_y = feedback_data[5];
3758     results[1].m_z = feedback_data[6];
3759     results[1].m_w = feedback_data[7];
3760 
3761     results[2].m_x = feedback_data[8];
3762     results[2].m_y = feedback_data[9];
3763     results[2].m_z = feedback_data[10];
3764     results[2].m_w = feedback_data[11];
3765 
3766     results[3].m_x = feedback_data[12];
3767     results[3].m_y = feedback_data[13];
3768     results[3].m_z = feedback_data[14];
3769     results[3].m_w = feedback_data[15];
3770 
3771     results[4].m_x = feedback_data[16];
3772     results[4].m_y = feedback_data[17];
3773     results[4].m_z = feedback_data[18];
3774     results[4].m_w = feedback_data[19];
3775 
3776     gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
3777     GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
3778 
3779     for (GLuint i = 0; i < n_varyings; ++i)
3780     {
3781         result = result && (results[i] == expected_results[i]);
3782     }
3783 
3784     if (false == result)
3785     {
3786         m_context.getTestContext().getLog()
3787             << tcu::TestLog::Message << "Error. Invalid result. First routine: " << first_routine_name
3788             << ". Second routine: " << second_routine_name << tcu::TestLog::EndMessage;
3789 
3790         tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
3791 
3792         message << "Results:";
3793 
3794         for (GLuint i = 0; i < n_varyings; ++i)
3795         {
3796             results[i].log(message);
3797         }
3798 
3799         message << tcu::TestLog::EndMessage;
3800 
3801         message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
3802 
3803         message << "Expected:";
3804 
3805         for (GLuint i = 0; i < n_varyings; ++i)
3806         {
3807             expected_results[i].log(message);
3808         }
3809 
3810         message << tcu::TestLog::EndMessage;
3811     }
3812 
3813     return result;
3814 }
3815 
3816 /** Constructor
3817  *
3818  * @param context CTS context
3819  **/
FunctionalTest5(deqp::Context & context)3820 FunctionalTest5::FunctionalTest5(deqp::Context &context)
3821     : TestCase(context, "eight_subroutines_four_uniforms", "Verify multiple subroutine sets")
3822 {
3823 }
3824 
3825 /** Execute test
3826  *
3827  * @return tcu::TestNode::STOP
3828  **/
iterate()3829 tcu::TestNode::IterateResult FunctionalTest5::iterate()
3830 {
3831     static const GLchar *vertex_shader_code =
3832         "#version 400 core\n"
3833         "#extension GL_ARB_shader_subroutine : require\n"
3834         "\n"
3835         "precision highp float;\n"
3836         "\n"
3837         "// Subroutine types\n"
3838         "subroutine vec4  routine_type_1(in vec4 left, in vec4 right);\n"
3839         "subroutine vec4  routine_type_2(in vec4 iparam);\n"
3840         "subroutine vec4  routine_type_3(in vec4 a,    in vec4 b,    in vec4 c);\n"
3841         "subroutine bvec4 routine_type_4(in vec4 left, in vec4 right);\n"
3842         "\n"
3843         "// Subroutine definitions\n"
3844         "// 1st type\n"
3845         "subroutine(routine_type_1) vec4 add(in vec4 left, in vec4 right)\n"
3846         "{\n"
3847         "    return left + right;\n"
3848         "}\n"
3849         "\n"
3850         "subroutine(routine_type_1) vec4 subtract(in vec4 left, in vec4 right)\n"
3851         "{\n"
3852         "    return left - right;\n"
3853         "}\n"
3854         "\n"
3855         "// 2nd type\n"
3856         "subroutine(routine_type_2) vec4 square(in vec4 iparam)\n"
3857         "{\n"
3858         "    return iparam * iparam;\n"
3859         "}\n"
3860         "\n"
3861         "subroutine(routine_type_2) vec4 square_root(in vec4 iparam)\n"
3862         "{\n"
3863         "    return sqrt(iparam);\n"
3864         "}\n"
3865         "\n"
3866         "// 3rd type\n"
3867         "subroutine(routine_type_3) vec4 do_fma(in vec4 a, in vec4 b, in vec4 c)\n"
3868         "{\n"
3869         "    return fma(a, b, c);\n"
3870         "}\n"
3871         "\n"
3872         "subroutine(routine_type_3) vec4 blend(in vec4 a, in vec4 b, in vec4 c)\n"
3873         "{\n"
3874         "    return c * a + (vec4(1) - c) * b;\n"
3875         "}\n"
3876         "\n"
3877         "// 4th type\n"
3878         "subroutine(routine_type_4) bvec4 are_equal(in vec4 left, in vec4 right)\n"
3879         "{\n"
3880         "    return equal(left, right);\n"
3881         "}\n"
3882         "\n"
3883         "subroutine(routine_type_4) bvec4 are_greater(in vec4 left, in vec4 right)\n"
3884         "{\n"
3885         "    return greaterThan(left, right);\n"
3886         "}\n"
3887         "\n"
3888         "// Sub routine uniforms\n"
3889         "subroutine uniform routine_type_1 first_routine;\n"
3890         "subroutine uniform routine_type_2 second_routine;\n"
3891         "subroutine uniform routine_type_3 third_routine;\n"
3892         "subroutine uniform routine_type_4 fourth_routine;\n"
3893         "\n"
3894         "// Input data\n"
3895         "uniform vec4 first_input;\n"
3896         "uniform vec4 second_input;\n"
3897         "uniform vec4 third_input;\n"
3898         "\n"
3899         "// Output\n"
3900         "out  vec4 out_result_from_first_routine;\n"
3901         "out  vec4 out_result_from_second_routine;\n"
3902         "out  vec4 out_result_from_third_routine;\n"
3903         "out uvec4 out_result_from_fourth_routine;\n"
3904         "\n"
3905         "void main()\n"
3906         "{\n"
3907         "    out_result_from_first_routine  =       first_routine (first_input, second_input);\n"
3908         "    out_result_from_second_routine =       second_routine(first_input);\n"
3909         "    out_result_from_third_routine  =       third_routine (first_input, second_input, third_input);\n"
3910         "    out_result_from_fourth_routine = uvec4(fourth_routine(first_input, second_input));\n"
3911         "}\n"
3912         "\n";
3913 
3914     static const GLchar *subroutine_names[4][2] = {
3915         {"add", "subtract"}, {"square", "square_root"}, {"do_fma", "blend"}, {"are_equal", "are_greater"}};
3916 
3917     static const GLchar *subroutine_uniform_names[4][1] = {
3918         {"first_routine"}, {"second_routine"}, {"third_routine"}, {"fourth_routine"}};
3919 
3920     static const GLuint n_subroutine_types     = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
3921     static const GLuint n_subroutines_per_type = sizeof(subroutine_names[0]) / sizeof(subroutine_names[0][0]);
3922     static const GLuint n_subroutine_uniforms_per_type =
3923         sizeof(subroutine_uniform_names[0]) / sizeof(subroutine_uniform_names[0][0]);
3924 
3925     static const GLchar *uniform_names[] = {"first_input", "second_input", "third_input"};
3926     static const GLuint n_uniform_names  = sizeof(uniform_names) / sizeof(uniform_names[0]);
3927 
3928     static const GLchar *varying_names[] = {"out_result_from_first_routine", "out_result_from_second_routine",
3929                                             "out_result_from_third_routine", "out_result_from_fourth_routine"};
3930     static const GLuint n_varyings       = sizeof(varying_names) / sizeof(varying_names[0]);
3931     static const GLuint transform_feedback_buffer_size = n_varyings * sizeof(GLfloat) * 4 /* vec4 */;
3932 
3933     /* Test data */
3934     static const Utils::vec4<GLfloat> input_data[3] = {Utils::vec4<GLfloat>(1.0f, 4.0f, 9.0f, 16.0f),
3935                                                        Utils::vec4<GLfloat>(16.0f, 9.0f, 4.0f, 1.0f),
3936                                                        Utils::vec4<GLfloat>(0.25f, 0.5f, 0.75f, 1.0f)};
3937 
3938     static const Utils::vec4<GLfloat> expected_result_from_first_routine[2] = {
3939         Utils::vec4<GLfloat>(17.0f, 13.0f, 13.0f, 17.0f), Utils::vec4<GLfloat>(-15.0f, -5.0f, 5.0f, 15.0f)};
3940 
3941     static const Utils::vec4<GLfloat> expected_result_from_second_routine[2] = {
3942         Utils::vec4<GLfloat>(1.0f, 16.0f, 81.0f, 256.0f), Utils::vec4<GLfloat>(1.0f, 2.0f, 3.0f, 4.0f)};
3943 
3944     static const Utils::vec4<GLfloat> expected_result_from_third_routine[2] = {
3945         Utils::vec4<GLfloat>(16.25f, 36.5f, 36.75f, 17.0f), Utils::vec4<GLfloat>(12.25f, 6.5f, 7.75f, 16.0f)};
3946 
3947     static const Utils::vec4<GLuint> expected_result_from_fourth_routine[2] = {Utils::vec4<GLuint>(0, 0, 0, 0),
3948                                                                                Utils::vec4<GLuint>(0, 0, 1, 1)};
3949 
3950     /* All combinations of subroutines */
3951     static const GLuint subroutine_combinations[][4] = {
3952         {0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 0}, {0, 0, 1, 1}, {0, 1, 0, 0}, {0, 1, 0, 1}, {0, 1, 1, 0}, {0, 1, 1, 1},
3953         {1, 0, 0, 0}, {1, 0, 0, 1}, {1, 0, 1, 0}, {1, 0, 1, 1}, {1, 1, 0, 0}, {1, 1, 0, 1}, {1, 1, 1, 0}, {1, 1, 1, 1}};
3954     static const GLuint n_subroutine_combinations =
3955         sizeof(subroutine_combinations) / sizeof(subroutine_combinations[0]);
3956 
3957     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
3958     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
3959     {
3960         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
3961     }
3962 
3963     /* Result */
3964     bool result = true;
3965 
3966     /* GL objects */
3967     Utils::program program(m_context);
3968     Utils::buffer transform_feedback_buffer(m_context);
3969     Utils::vertexArray vao(m_context);
3970 
3971     /* Init GL objects */
3972     program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code, varying_names,
3973                   n_varyings);
3974 
3975     program.use();
3976 
3977     vao.generate();
3978     vao.bind();
3979 
3980     transform_feedback_buffer.generate();
3981     transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
3982                                      GL_DYNAMIC_COPY);
3983     transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
3984 
3985     /* Get subroutine uniform locations and subroutine indices */
3986     for (GLuint type = 0; type < n_subroutine_types; ++type)
3987     {
3988         for (GLuint uniform = 0; uniform < n_subroutine_uniforms_per_type; ++uniform)
3989         {
3990             m_subroutine_uniform_locations[type][uniform] =
3991                 program.getSubroutineUniformLocation(subroutine_uniform_names[type][uniform], GL_VERTEX_SHADER);
3992         }
3993 
3994         for (GLuint routine = 0; routine < n_subroutines_per_type; ++routine)
3995         {
3996             m_subroutine_indices[type][routine] =
3997                 program.getSubroutineIndex(subroutine_names[type][routine], GL_VERTEX_SHADER);
3998         }
3999     }
4000 
4001     /* Get uniform locations */
4002     for (GLuint i = 0; i < n_uniform_names; ++i)
4003     {
4004         m_uniform_locations[i] = program.getUniformLocation(uniform_names[i]);
4005     }
4006 
4007     /* Draw with each routine combination */
4008     for (GLuint i = 0; i < n_subroutine_combinations; ++i)
4009     {
4010         Utils::vec4<GLfloat> first_routine_result;
4011         Utils::vec4<GLfloat> second_routine_result;
4012         Utils::vec4<GLfloat> third_routine_result;
4013         Utils::vec4<GLuint> fourth_routine_result;
4014 
4015         testDraw(subroutine_combinations[i], input_data, first_routine_result, second_routine_result,
4016                  third_routine_result, fourth_routine_result);
4017 
4018         if (false == verify(first_routine_result, second_routine_result, third_routine_result, fourth_routine_result,
4019                             expected_result_from_first_routine[subroutine_combinations[i][0]],
4020                             expected_result_from_second_routine[subroutine_combinations[i][1]],
4021                             expected_result_from_third_routine[subroutine_combinations[i][2]],
4022                             expected_result_from_fourth_routine[subroutine_combinations[i][3]]))
4023         {
4024             logError(subroutine_names, subroutine_combinations[i], input_data, first_routine_result,
4025                      second_routine_result, third_routine_result, fourth_routine_result,
4026                      expected_result_from_first_routine[subroutine_combinations[i][0]],
4027                      expected_result_from_second_routine[subroutine_combinations[i][1]],
4028                      expected_result_from_third_routine[subroutine_combinations[i][2]],
4029                      expected_result_from_fourth_routine[subroutine_combinations[i][3]]);
4030 
4031             result = false;
4032         }
4033     }
4034 
4035     /* Done */
4036     if (true == result)
4037     {
4038         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4039     }
4040     else
4041     {
4042         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
4043     }
4044 
4045     return tcu::TestNode::STOP;
4046 }
4047 
4048 /** Log error message
4049  *
4050  * @param subroutine_names               Array of subroutine names
4051  * @param subroutine_combination         Combination of subroutines
4052  * @param input_data                     Input data
4053  * @param first_routine_result           Result of first routine
4054  * @param second_routine_result          Result of second routine
4055  * @param third_routine_result           Result of third routine
4056  * @param fourth_routine_result          Result of fourth routine
4057  * @param first_routine_expected_result  Expected result of first routine
4058  * @param second_routine_expected_result Expected result of second routine
4059  * @param third_routine_expected_result  Expected result of third routine
4060  * @param fourth_routine_expected_result Expected result of fourth routine
4061  **/
logError(const glw::GLchar * subroutine_names[4][2],const glw::GLuint subroutine_combination[4],const Utils::vec4<glw::GLfloat> input_data[3],const Utils::vec4<glw::GLfloat> & first_routine_result,const Utils::vec4<glw::GLfloat> & second_routine_result,const Utils::vec4<glw::GLfloat> & third_routine_result,const Utils::vec4<glw::GLuint> & fourth_routine_result,const Utils::vec4<glw::GLfloat> & first_routine_expected_result,const Utils::vec4<glw::GLfloat> & second_routine_expected_result,const Utils::vec4<glw::GLfloat> & third_routine_expected_result,const Utils::vec4<glw::GLuint> & fourth_routine_expected_result) const4062 void FunctionalTest5::logError(const glw::GLchar *subroutine_names[4][2], const glw::GLuint subroutine_combination[4],
4063                                const Utils::vec4<glw::GLfloat> input_data[3],
4064                                const Utils::vec4<glw::GLfloat> &first_routine_result,
4065                                const Utils::vec4<glw::GLfloat> &second_routine_result,
4066                                const Utils::vec4<glw::GLfloat> &third_routine_result,
4067                                const Utils::vec4<glw::GLuint> &fourth_routine_result,
4068                                const Utils::vec4<glw::GLfloat> &first_routine_expected_result,
4069                                const Utils::vec4<glw::GLfloat> &second_routine_expected_result,
4070                                const Utils::vec4<glw::GLfloat> &third_routine_expected_result,
4071                                const Utils::vec4<glw::GLuint> &fourth_routine_expected_result) const
4072 {
4073     m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error. Invalid result."
4074                                         << tcu::TestLog::EndMessage;
4075 
4076     tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4077 
4078     message << "Function: " << subroutine_names[0][subroutine_combination[0]] << "( ";
4079     input_data[0].log(message);
4080     message << ", ";
4081     input_data[1].log(message);
4082     message << " ). Result: ";
4083     first_routine_result.log(message);
4084     message << ". Expected: ";
4085     first_routine_expected_result.log(message);
4086 
4087     message << tcu::TestLog::EndMessage;
4088 
4089     message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4090 
4091     message << "Function: " << subroutine_names[1][subroutine_combination[1]] << "( ";
4092     input_data[0].log(message);
4093     message << " ). Result: ";
4094     second_routine_result.log(message);
4095     message << ". Expected: ";
4096     second_routine_expected_result.log(message);
4097 
4098     message << tcu::TestLog::EndMessage;
4099 
4100     message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4101 
4102     message << "Function: " << subroutine_names[2][subroutine_combination[2]] << "( ";
4103     input_data[0].log(message);
4104     message << ", ";
4105     input_data[1].log(message);
4106     message << ", ";
4107     input_data[2].log(message);
4108     message << "). Result: ";
4109     third_routine_result.log(message);
4110     message << ". Expected: ";
4111     third_routine_expected_result.log(message);
4112 
4113     message << tcu::TestLog::EndMessage;
4114 
4115     message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4116 
4117     message << "Function: " << subroutine_names[3][subroutine_combination[3]] << "( ";
4118     input_data[0].log(message);
4119     message << ", ";
4120     input_data[1].log(message);
4121     message << ", ";
4122     message << " ). Result: ";
4123     fourth_routine_result.log(message);
4124     message << ". Expected: ";
4125     fourth_routine_expected_result.log(message);
4126 
4127     message << tcu::TestLog::EndMessage;
4128 }
4129 
4130 /** Execute draw call and capture results
4131  *
4132  * @param subroutine_combination    Combination of subroutines
4133  * @param input_data                Input data
4134  * @param out_first_routine_result  Result of first routine
4135  * @param out_second_routine_result Result of second routine
4136  * @param out_third_routine_result  Result of third routine
4137  * @param out_fourth_routine_result Result of fourth routine
4138  **/
testDraw(const glw::GLuint subroutine_combination[4],const Utils::vec4<glw::GLfloat> input_data[3],Utils::vec4<glw::GLfloat> & out_first_routine_result,Utils::vec4<glw::GLfloat> & out_second_routine_result,Utils::vec4<glw::GLfloat> & out_third_routine_result,Utils::vec4<glw::GLuint> & out_fourth_routine_result) const4139 void FunctionalTest5::testDraw(const glw::GLuint subroutine_combination[4],
4140                                const Utils::vec4<glw::GLfloat> input_data[3],
4141                                Utils::vec4<glw::GLfloat> &out_first_routine_result,
4142                                Utils::vec4<glw::GLfloat> &out_second_routine_result,
4143                                Utils::vec4<glw::GLfloat> &out_third_routine_result,
4144                                Utils::vec4<glw::GLuint> &out_fourth_routine_result) const
4145 {
4146     static const GLuint n_uniforms = sizeof(m_uniform_locations) / sizeof(m_uniform_locations[0]);
4147     const glw::Functions &gl       = m_context.getRenderContext().getFunctions();
4148     GLuint subroutine_indices[4];
4149     static const GLuint n_subroutine_uniforms = sizeof(subroutine_indices) / sizeof(subroutine_indices[0]);
4150 
4151     /* Prepare subroutine uniform data */
4152     for (GLuint i = 0; i < n_subroutine_uniforms; ++i)
4153     {
4154         const GLuint location = m_subroutine_uniform_locations[i][0];
4155 
4156         subroutine_indices[location] = m_subroutine_indices[i][subroutine_combination[i]];
4157     }
4158 
4159     /* Set up subroutine uniforms */
4160     gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, n_subroutine_uniforms, &subroutine_indices[0]);
4161     GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
4162 
4163     /* Set up input data uniforms */
4164     for (GLuint i = 0; i < n_uniforms; ++i)
4165     {
4166         gl.uniform4f(m_uniform_locations[i], input_data[i].m_x, input_data[i].m_y, input_data[i].m_z,
4167                      input_data[i].m_w);
4168         GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
4169     }
4170 
4171     /* Execute draw call with transform feedback */
4172     gl.beginTransformFeedback(GL_POINTS);
4173     GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
4174 
4175     gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
4176     GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
4177 
4178     gl.endTransformFeedback();
4179     GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
4180 
4181     /* Capture results */
4182     GLvoid *feedback_data = gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
4183     GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
4184 
4185     GLfloat *float_ptr = (GLfloat *)feedback_data;
4186 
4187     /* First result */
4188     out_first_routine_result.m_x = float_ptr[0];
4189     out_first_routine_result.m_y = float_ptr[1];
4190     out_first_routine_result.m_z = float_ptr[2];
4191     out_first_routine_result.m_w = float_ptr[3];
4192 
4193     /* Second result */
4194     out_second_routine_result.m_x = float_ptr[4];
4195     out_second_routine_result.m_y = float_ptr[5];
4196     out_second_routine_result.m_z = float_ptr[6];
4197     out_second_routine_result.m_w = float_ptr[7];
4198 
4199     /* Third result */
4200     out_third_routine_result.m_x = float_ptr[8];
4201     out_third_routine_result.m_y = float_ptr[9];
4202     out_third_routine_result.m_z = float_ptr[10];
4203     out_third_routine_result.m_w = float_ptr[11];
4204 
4205     /* Fourth result */
4206     GLuint *uint_ptr              = (GLuint *)(float_ptr + 12);
4207     out_fourth_routine_result.m_x = uint_ptr[0];
4208     out_fourth_routine_result.m_y = uint_ptr[1];
4209     out_fourth_routine_result.m_z = uint_ptr[2];
4210     out_fourth_routine_result.m_w = uint_ptr[3];
4211 
4212     gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
4213     GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
4214 }
4215 
4216 /** Verify if results match expected results
4217  *
4218  * @param first_routine_result           Result of first routine
4219  * @param second_routine_result          Result of second routine
4220  * @param third_routine_result           Result of third routine
4221  * @param fourth_routine_result          Result of fourth routine
4222  * @param first_routine_expected_result  Expected result of first routine
4223  * @param second_routine_expected_result Expected result of second routine
4224  * @param third_routine_expected_result  Expected result of third routine
4225  * @param fourth_routine_expected_result Expected result of fourth routine
4226  **/
verify(const Utils::vec4<glw::GLfloat> & first_routine_result,const Utils::vec4<glw::GLfloat> & second_routine_result,const Utils::vec4<glw::GLfloat> & third_routine_result,const Utils::vec4<glw::GLuint> & fourth_routine_result,const Utils::vec4<glw::GLfloat> & first_routine_expected_result,const Utils::vec4<glw::GLfloat> & second_routine_expected_result,const Utils::vec4<glw::GLfloat> & third_routine_expected_result,const Utils::vec4<glw::GLuint> & fourth_routine_expected_result) const4227 bool FunctionalTest5::verify(const Utils::vec4<glw::GLfloat> &first_routine_result,
4228                              const Utils::vec4<glw::GLfloat> &second_routine_result,
4229                              const Utils::vec4<glw::GLfloat> &third_routine_result,
4230                              const Utils::vec4<glw::GLuint> &fourth_routine_result,
4231                              const Utils::vec4<glw::GLfloat> &first_routine_expected_result,
4232                              const Utils::vec4<glw::GLfloat> &second_routine_expected_result,
4233                              const Utils::vec4<glw::GLfloat> &third_routine_expected_result,
4234                              const Utils::vec4<glw::GLuint> &fourth_routine_expected_result) const
4235 {
4236     bool result = true;
4237 
4238     result = result && (first_routine_result == first_routine_expected_result);
4239     result = result && (second_routine_result == second_routine_expected_result);
4240     result = result && (third_routine_result == third_routine_expected_result);
4241     result = result && (fourth_routine_result == fourth_routine_expected_result);
4242 
4243     return result;
4244 }
4245 
4246 /** Constructor
4247  *
4248  * @param context CTS context
4249  **/
FunctionalTest6(deqp::Context & context)4250 FunctionalTest6::FunctionalTest6(deqp::Context &context)
4251     : TestCase(context, "static_subroutine_call", "Verify that subroutine can be called in a static manner")
4252 {
4253 }
4254 
4255 /** Execute test
4256  *
4257  * @return tcu::TestNode::STOP
4258  **/
iterate()4259 tcu::TestNode::IterateResult FunctionalTest6::iterate()
4260 {
4261     static const GLchar *vertex_shader_code = "#version 400 core\n"
4262                                               "#extension GL_ARB_shader_subroutine : require\n"
4263                                               "\n"
4264                                               "precision highp float;\n"
4265                                               "\n"
4266                                               "// Subroutine type\n"
4267                                               "subroutine vec4 routine_type(in vec4 iparam);\n"
4268                                               "\n"
4269                                               "// Subroutine definition\n"
4270                                               "subroutine(routine_type) vec4 square(in vec4 iparam)\n"
4271                                               "{\n"
4272                                               "    return iparam * iparam;\n"
4273                                               "}\n"
4274                                               "\n"
4275                                               "// Sub routine uniform\n"
4276                                               "subroutine uniform routine_type routine;\n"
4277                                               "\n"
4278                                               "// Input data\n"
4279                                               "uniform vec4 input_data;\n"
4280                                               "\n"
4281                                               "// Output\n"
4282                                               "out  vec4 out_result;\n"
4283                                               "\n"
4284                                               "void main()\n"
4285                                               "{\n"
4286                                               "    out_result  = square(input_data);\n"
4287                                               "}\n"
4288                                               "\n";
4289 
4290     static const GLchar *varying_name = "out_result";
4291 
4292     /* Test data */
4293     static const Utils::vec4<GLfloat> input_data(1.0f, 4.0f, 9.0f, 16.0f);
4294 
4295     static const Utils::vec4<GLfloat> expected_result(1.0f, 16.0f, 81.0f, 256.0f);
4296 
4297     static const GLuint transform_feedback_buffer_size = 4 * sizeof(GLfloat);
4298 
4299     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
4300     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
4301     {
4302         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
4303     }
4304 
4305     /* GL objects */
4306     Utils::program program(m_context);
4307     Utils::buffer transform_feedback_buffer(m_context);
4308     Utils::vertexArray vao(m_context);
4309 
4310     /* Init GL objects */
4311     program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code, &varying_name,
4312                   1 /* n_varyings */);
4313 
4314     program.use();
4315 
4316     vao.generate();
4317     vao.bind();
4318 
4319     transform_feedback_buffer.generate();
4320     transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
4321                                      GL_DYNAMIC_COPY);
4322     transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
4323 
4324     /* Test */
4325     {
4326         const glw::Functions &gl     = m_context.getRenderContext().getFunctions();
4327         const GLint uniform_location = gl.getUniformLocation(program.m_program_object_id, "input_data");
4328 
4329         GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation");
4330 
4331         if (-1 == uniform_location)
4332         {
4333             TCU_FAIL("Uniform is not available");
4334         }
4335 
4336         /* Set up input data uniforms */
4337         gl.uniform4f(uniform_location, input_data.m_x, input_data.m_y, input_data.m_z, input_data.m_w);
4338         GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
4339 
4340         /* Execute draw call with transform feedback */
4341         gl.beginTransformFeedback(GL_POINTS);
4342         GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
4343 
4344         gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
4345         GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
4346 
4347         gl.endTransformFeedback();
4348         GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
4349 
4350         /* Capture results */
4351         GLfloat *feedback_data = (GLfloat *)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
4352         GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
4353 
4354         Utils::vec4<GLfloat> result(feedback_data[0], feedback_data[1], feedback_data[2], feedback_data[3]);
4355 
4356         gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
4357         GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
4358 
4359         /* Verify */
4360         if (expected_result == result)
4361         {
4362             m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4363         }
4364         else
4365         {
4366             m_context.getTestContext().getLog()
4367                 << tcu::TestLog::Message << "Error. Invalid result." << tcu::TestLog::EndMessage;
4368 
4369             tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4370 
4371             message << "Function: square( ";
4372             input_data.log(message);
4373             message << " ). Result: ";
4374             result.log(message);
4375             message << ". Expected: ";
4376             expected_result.log(message);
4377 
4378             message << tcu::TestLog::EndMessage;
4379 
4380             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
4381         }
4382     }
4383 
4384     /* Done */
4385     return tcu::TestNode::STOP;
4386 }
4387 
4388 /** Constructor
4389  *
4390  * @param context CTS context
4391  **/
FunctionalTest7_8(deqp::Context & context)4392 FunctionalTest7_8::FunctionalTest7_8(deqp::Context &context)
4393     : TestCase(context, "arrayed_subroutine_uniforms", "Verify that subroutine can be called in a static manner")
4394 {
4395 }
4396 
4397 /** Execute test
4398  *
4399  * @return tcu::TestNode::STOP
4400  **/
iterate()4401 tcu::TestNode::IterateResult FunctionalTest7_8::iterate()
4402 {
4403     static const GLchar *vertex_shader_code =
4404         "#version 400 core\n"
4405         "#extension GL_ARB_shader_subroutine : require\n"
4406         "\n"
4407         "precision highp float;\n"
4408         "\n"
4409         "// Subroutine type\n"
4410         "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n"
4411         "\n"
4412         "// Subroutine definitions\n"
4413         "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n"
4414         "{\n"
4415         "    return left + right;\n"
4416         "}\n"
4417         "\n"
4418         "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n"
4419         "{\n"
4420         "    return left * right;\n"
4421         "}\n"
4422         "\n"
4423         "// Sub routine uniform\n"
4424         "subroutine uniform routine_type routine[4];\n"
4425         "\n"
4426         "// Input data\n"
4427         "uniform vec4  uni_left;\n"
4428         "uniform vec4  uni_right;\n"
4429         "uniform uvec4 uni_indices;\n"
4430         "\n"
4431         "// Output\n"
4432         "out vec4 out_combined;\n"
4433         "out vec4 out_combined_inverted;\n"
4434         "out vec4 out_constant;\n"
4435         "out vec4 out_constant_inverted;\n"
4436         "out vec4 out_dynamic;\n"
4437         "out vec4 out_dynamic_inverted;\n"
4438         "out vec4 out_loop;\n"
4439         "out uint out_array_length;\n"
4440         "\n"
4441         "void main()\n"
4442         "{\n"
4443         "    out_combined          = routine[3](routine[2](routine[1](routine[0](uni_left, uni_right), uni_right), "
4444         "uni_right), uni_right);\n"
4445         "    out_combined_inverted = routine[0](routine[1](routine[2](routine[3](uni_left, uni_right), uni_right), "
4446         "uni_right), uni_right);\n"
4447         "    \n"
4448         "    out_constant          = routine[3](routine[2](routine[1](routine[0](vec4(1, 2, 3, 4), vec4(-5, -6, -7, "
4449         "-8)), vec4(-1, -2, -3, -4)), vec4(5, 6, 7, 8)), vec4(1, 2, 3, 4));\n"
4450         "    out_constant_inverted = routine[0](routine[1](routine[2](routine[3](vec4(1, 2, 3, 4), vec4(-5, -6, -7, "
4451         "-8)), vec4(-1, -2, -3, -4)), vec4(5, 6, 7, 8)), vec4(1, 2, 3, 4));\n"
4452         "    \n"
4453         "    out_dynamic           = "
4454         "routine[uni_indices.w](routine[uni_indices.z](routine[uni_indices.y](routine[uni_indices.x](uni_left, "
4455         "uni_right), uni_right), uni_right), uni_right);\n"
4456         "    out_dynamic_inverted  = "
4457         "routine[uni_indices.x](routine[uni_indices.y](routine[uni_indices.z](routine[uni_indices.w](uni_left, "
4458         "uni_right), uni_right), uni_right), uni_right);\n"
4459         "    \n"
4460         "    out_loop              = uni_left;\n"
4461         "    for (uint i = 0u; i < routine.length(); ++i)\n"
4462         "    {\n"
4463         "        out_loop          = routine[i](out_loop, uni_right);\n"
4464         "    }\n"
4465         "    \n"
4466         "    out_array_length      = routine.length() + 6 - (uni_indices.x + uni_indices.y + uni_indices.z + "
4467         "uni_indices.w);\n"
4468         "}\n"
4469         "\n";
4470 
4471     static const GLchar *subroutine_names[] = {
4472         "add",
4473         "multiply",
4474     };
4475     static const GLuint n_subroutine_names = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
4476 
4477     static const GLchar *subroutine_uniform_names[] = {"routine[0]", "routine[1]", "routine[2]", "routine[3]"};
4478     static const GLuint n_subroutine_uniform_names =
4479         sizeof(subroutine_uniform_names) / sizeof(subroutine_uniform_names[0]);
4480 
4481     static const GLchar *uniform_names[] = {
4482         "uni_left",
4483         "uni_right",
4484         "uni_indices",
4485     };
4486     static const GLuint n_uniform_names = sizeof(uniform_names) / sizeof(uniform_names[0]);
4487 
4488     static const GLchar *varying_names[] = {
4489         "out_combined", "out_combined_inverted", "out_constant", "out_constant_inverted",
4490         "out_dynamic",  "out_dynamic_inverted",  "out_loop",     "out_array_length"};
4491 
4492     static const GLuint n_varyings                     = sizeof(varying_names) / sizeof(varying_names[0]);
4493     static const GLuint transform_feedback_buffer_size = n_varyings * 4 * sizeof(GLfloat);
4494 
4495     /* Test data */
4496     static const Utils::vec4<GLfloat> uni_left(-1.0f, 0.75f, -0.5f, 0.25f);
4497     static const Utils::vec4<GLfloat> uni_right(1.0f, -0.75f, 0.5f, -0.25f);
4498     static const Utils::vec4<GLuint> uni_indices(1, 2, 0, 3);
4499 
4500     static const GLuint subroutine_combinations[][4] = {
4501         {0, 0, 0, 0}, /* + + + + */
4502         {0, 0, 0, 1}, /* + + + * */
4503         {0, 0, 1, 0}, /* + + * + */
4504         {0, 0, 1, 1}, /* + + * * */
4505         {0, 1, 0, 0}, /* + * + + */
4506         {0, 1, 0, 1}, /* + * + * */
4507         {0, 1, 1, 0}, /* + * * + */
4508         {0, 1, 1, 1}, /* + * * * */
4509         {1, 0, 0, 0}, /* * + + + */
4510         {1, 0, 0, 1}, /* * + + * */
4511         {1, 0, 1, 0}, /* * + * + */
4512         {1, 0, 1, 1}, /* * + * * */
4513         {1, 1, 0, 0}, /* * * + + */
4514         {1, 1, 0, 1}, /* * * + * */
4515         {1, 1, 1, 0}, /* * * * + */
4516         {1, 1, 1, 1}  /* * * * * */
4517     };
4518     static const GLuint n_subroutine_combinations =
4519         sizeof(subroutine_combinations) / sizeof(subroutine_combinations[0]);
4520 
4521     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
4522     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
4523     {
4524         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
4525     }
4526 
4527     /* GL objects */
4528     Utils::program program(m_context);
4529     Utils::buffer transform_feedback_buffer(m_context);
4530     Utils::vertexArray vao(m_context);
4531 
4532     bool result = true;
4533 
4534     /* Init GL objects */
4535     program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code, varying_names,
4536                   n_varyings);
4537 
4538     program.use();
4539 
4540     vao.generate();
4541     vao.bind();
4542 
4543     transform_feedback_buffer.generate();
4544 
4545     /* Get subroutine indices */
4546     for (GLuint routine = 0; routine < n_subroutine_names; ++routine)
4547     {
4548         m_subroutine_indices[routine] = program.getSubroutineIndex(subroutine_names[routine], GL_VERTEX_SHADER);
4549     }
4550 
4551     /* Get subroutine uniform locations */
4552     for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
4553     {
4554         m_subroutine_uniform_locations[uniform] =
4555             program.getSubroutineUniformLocation(subroutine_uniform_names[uniform], GL_VERTEX_SHADER);
4556     }
4557 
4558     /* Get uniform locations */
4559     for (GLuint i = 0; i < n_uniform_names; ++i)
4560     {
4561         m_uniform_locations[i] = program.getUniformLocation(uniform_names[i]);
4562     }
4563 
4564     /* Test */
4565     for (GLuint i = 0; i < n_subroutine_combinations; ++i)
4566     {
4567         /* Clean */
4568         transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
4569                                          GL_DYNAMIC_COPY);
4570         transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
4571 
4572         /* Verify */
4573         if (false == testDraw(subroutine_combinations[i], uni_left, uni_right, uni_indices))
4574         {
4575             result = false;
4576         }
4577     }
4578 
4579     if (true == result)
4580     {
4581         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4582     }
4583     else
4584     {
4585         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
4586     }
4587 
4588     /* Done */
4589     return tcu::TestNode::STOP;
4590 }
4591 
4592 /* Calculate result of function applied to operands
4593  *
4594  * @param function Function id, 0 is sum, 1 is multiplication
4595  * @param left     Left operand
4596  * @param right    Right operand
4597  * @param out      Function result
4598  **/
calculate(glw::GLuint function,const Utils::vec4<glw::GLfloat> & left,const Utils::vec4<glw::GLfloat> & right,Utils::vec4<glw::GLfloat> & out) const4599 void FunctionalTest7_8::calculate(glw::GLuint function, const Utils::vec4<glw::GLfloat> &left,
4600                                   const Utils::vec4<glw::GLfloat> &right, Utils::vec4<glw::GLfloat> &out) const
4601 {
4602     if (0 == function)
4603     {
4604         out.m_x = left.m_x + right.m_x;
4605         out.m_y = left.m_y + right.m_y;
4606         out.m_z = left.m_z + right.m_z;
4607         out.m_w = left.m_w + right.m_w;
4608     }
4609     else
4610     {
4611         out.m_x = left.m_x * right.m_x;
4612         out.m_y = left.m_y * right.m_y;
4613         out.m_z = left.m_z * right.m_z;
4614         out.m_w = left.m_w * right.m_w;
4615     }
4616 }
4617 
4618 /** Calculate expected values for all operations
4619  *
4620  * @param combination           Function combination, first applied function is at index [0]
4621  * @param left                  Left operand
4622  * @param right                 Right operand
4623  * @param indices               Indices used by dynamic calls
4624  * @param out_combined          Expected result of "combined" operation
4625  * @param out_combined_inverted Expected result of "combined_inverted" operation
4626  * @param out_constant          Expected result of "constant" operation
4627  * @param out_constant_inverted Expected result of "constant_inverted" operation
4628  * @param out_dynamic           Expected result of "dynamic" operation
4629  * @param out_dynamic_inverted  Expected result of "out_dynamic_inverted" operation
4630  * @param out_loop              Expected result of "loop" operation
4631  **/
calculate(const glw::GLuint combination[4],const Utils::vec4<glw::GLfloat> & left,const Utils::vec4<glw::GLfloat> & right,const Utils::vec4<glw::GLuint> & indices,Utils::vec4<glw::GLfloat> & out_combined,Utils::vec4<glw::GLfloat> & out_combined_inverted,Utils::vec4<glw::GLfloat> & out_constant,Utils::vec4<glw::GLfloat> & out_constant_inverted,Utils::vec4<glw::GLfloat> & out_dynamic,Utils::vec4<glw::GLfloat> & out_dynamic_inverted,Utils::vec4<glw::GLfloat> & out_loop) const4632 void FunctionalTest7_8::calculate(
4633     const glw::GLuint combination[4], const Utils::vec4<glw::GLfloat> &left, const Utils::vec4<glw::GLfloat> &right,
4634     const Utils::vec4<glw::GLuint> &indices, Utils::vec4<glw::GLfloat> &out_combined,
4635     Utils::vec4<glw::GLfloat> &out_combined_inverted, Utils::vec4<glw::GLfloat> &out_constant,
4636     Utils::vec4<glw::GLfloat> &out_constant_inverted, Utils::vec4<glw::GLfloat> &out_dynamic,
4637     Utils::vec4<glw::GLfloat> &out_dynamic_inverted, Utils::vec4<glw::GLfloat> &out_loop) const
4638 {
4639     /* Indices used by "dynamic" operations, range <0..4> */
4640     const GLuint dynamic_combination[4] = {combination[indices.m_x], combination[indices.m_y], combination[indices.m_z],
4641                                            combination[indices.m_w]};
4642 
4643     /* Values used by "constant" operations, come from shader code */
4644     const Utils::vec4<glw::GLfloat> constant_values[] = {
4645         Utils::vec4<glw::GLfloat>(1, 2, 3, 4), Utils::vec4<glw::GLfloat>(-5, -6, -7, -8),
4646         Utils::vec4<glw::GLfloat>(-1, -2, -3, -4), Utils::vec4<glw::GLfloat>(5, 6, 7, 8),
4647         Utils::vec4<glw::GLfloat>(1, 2, 3, 4)};
4648 
4649     /* Start values */
4650     Utils::vec4<glw::GLfloat> combined          = left;
4651     Utils::vec4<glw::GLfloat> combined_inverted = left;
4652     Utils::vec4<glw::GLfloat> constant          = constant_values[0];
4653     Utils::vec4<glw::GLfloat> constant_inverted = constant_values[0];
4654     Utils::vec4<glw::GLfloat> dynamic           = left;
4655     Utils::vec4<glw::GLfloat> dynamic_inverted  = left;
4656 
4657     /* Calculate expected results */
4658     for (GLuint i = 0; i < 4; ++i)
4659     {
4660         GLuint function                  = combination[i];
4661         GLuint function_inverted         = combination[3 - i];
4662         GLuint dynamic_function          = dynamic_combination[i];
4663         GLuint dynamic_function_inverted = dynamic_combination[3 - i];
4664 
4665         calculate(function, combined, right, combined);
4666         calculate(function_inverted, combined_inverted, right, combined_inverted);
4667         calculate(function, constant, constant_values[i + 1], constant);
4668         calculate(function_inverted, constant_inverted, constant_values[i + 1], constant_inverted);
4669         calculate(dynamic_function, dynamic, right, dynamic);
4670         calculate(dynamic_function_inverted, dynamic_inverted, right, dynamic_inverted);
4671     }
4672 
4673     /* Store results */
4674     out_combined          = combined;
4675     out_combined_inverted = combined_inverted;
4676     out_constant          = constant;
4677     out_constant_inverted = constant_inverted;
4678     out_dynamic           = dynamic;
4679     out_dynamic_inverted  = dynamic_inverted;
4680     out_loop              = combined;
4681 }
4682 
4683 /** Log error
4684  *
4685  * @param combination   Operations combination
4686  * @param left          Left operand
4687  * @param right         Right operand
4688  * @param indices       Inidices used by "dynamic" calls
4689  * @param vec4_expected Expected results
4690  * @param vec4_result   Results
4691  * @param array_length  Length of array
4692  * @param result        Comparison results
4693  **/
logError(const glw::GLuint combination[4],const Utils::vec4<glw::GLfloat> & left,const Utils::vec4<glw::GLfloat> & right,const Utils::vec4<glw::GLuint> & indices,const Utils::vec4<glw::GLfloat> vec4_expected[7],const Utils::vec4<glw::GLfloat> vec4_result[7],glw::GLuint array_length,bool result[7]) const4694 void FunctionalTest7_8::logError(const glw::GLuint combination[4], const Utils::vec4<glw::GLfloat> &left,
4695                                  const Utils::vec4<glw::GLfloat> &right, const Utils::vec4<glw::GLuint> &indices,
4696                                  const Utils::vec4<glw::GLfloat> vec4_expected[7],
4697                                  const Utils::vec4<glw::GLfloat> vec4_result[7], glw::GLuint array_length,
4698                                  bool result[7]) const
4699 {
4700     static const GLuint n_functions  = 4;
4701     static const GLuint n_operations = 7;
4702 
4703     /* Indices used by "dynamic" operations, range <0..4> */
4704     const GLuint dynamic_combination[4] = {combination[indices.m_x], combination[indices.m_y], combination[indices.m_z],
4705                                            combination[indices.m_w]};
4706 
4707     /* Function symbols */
4708     GLchar functions[4];
4709     GLchar functions_inverted[4];
4710     GLchar functions_dynamic[4];
4711     GLchar functions_dynamic_inverted[4];
4712 
4713     for (GLuint i = 0; i < n_functions; ++i)
4714     {
4715         GLchar function         = (0 == combination[i]) ? '+' : '*';
4716         GLchar dynamic_function = (0 == dynamic_combination[i]) ? '+' : '*';
4717 
4718         functions[i]                                    = function;
4719         functions_inverted[n_functions - i - 1]         = function;
4720         functions_dynamic[i]                            = dynamic_function;
4721         functions_dynamic_inverted[n_functions - i - 1] = dynamic_function;
4722     }
4723 
4724     /* Values used by "constant" operations, come from shader code */
4725     const Utils::vec4<glw::GLfloat> constant_values[] = {
4726         Utils::vec4<glw::GLfloat>(1, 2, 3, 4), Utils::vec4<glw::GLfloat>(-5, -6, -7, -8),
4727         Utils::vec4<glw::GLfloat>(-1, -2, -3, -4), Utils::vec4<glw::GLfloat>(5, 6, 7, 8),
4728         Utils::vec4<glw::GLfloat>(1, 2, 3, 4)};
4729 
4730     /* Values used by non-"constant" operations */
4731     Utils::vec4<glw::GLfloat> dynamic_values[5];
4732     dynamic_values[0] = left;
4733     dynamic_values[1] = right;
4734     dynamic_values[2] = right;
4735     dynamic_values[3] = right;
4736     dynamic_values[4] = right;
4737 
4738     /* For each operation */
4739     for (GLuint i = 0; i < n_operations; ++i)
4740     {
4741         /* If result is failure */
4742         if (false == result[i])
4743         {
4744             const GLchar *description              = 0;
4745             const Utils::vec4<glw::GLfloat> *input = 0;
4746             const GLchar *operation                = 0;
4747 
4748             switch (i)
4749             {
4750             case 0:
4751                 description = "Call made with predefined array indices";
4752                 input       = dynamic_values;
4753                 operation   = functions;
4754                 break;
4755             case 1:
4756                 description = "Call made with predefined array indices in inverted order";
4757                 input       = dynamic_values;
4758                 operation   = functions_inverted;
4759                 break;
4760             case 2:
4761                 description = "Call made with predefined array indices, for constant values";
4762                 input       = constant_values;
4763                 operation   = functions;
4764                 break;
4765             case 3:
4766                 description = "Call made with predefined array indices in inverted order, for constant values";
4767                 input       = constant_values;
4768                 operation   = functions_inverted;
4769                 break;
4770             case 4:
4771                 description = "Call made with dynamic array indices";
4772                 input       = dynamic_values;
4773                 operation   = functions_dynamic;
4774                 break;
4775             case 5:
4776                 description = "Call made with dynamic array indices in inverted order";
4777                 input       = dynamic_values;
4778                 operation   = functions_dynamic_inverted;
4779                 break;
4780             case 6:
4781                 description = "Call made with loop";
4782                 input       = dynamic_values;
4783                 operation   = functions;
4784                 break;
4785             }
4786 
4787             m_context.getTestContext().getLog()
4788                 << tcu::TestLog::Message << "Error. Invalid result." << tcu::TestLog::EndMessage;
4789 
4790             m_context.getTestContext().getLog() << tcu::TestLog::Message << description << tcu::TestLog::EndMessage;
4791 
4792             tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4793 
4794             message << "Operation: ((((";
4795             input[0].log(message);
4796             for (GLuint function = 0; function < n_functions; ++function)
4797             {
4798                 message << " " << operation[function] << " ";
4799 
4800                 input[function + 1].log(message);
4801 
4802                 message << ")";
4803             }
4804 
4805             message << tcu::TestLog::EndMessage;
4806 
4807             message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4808 
4809             message << "Result: ";
4810             vec4_result[i].log(message);
4811 
4812             message << tcu::TestLog::EndMessage;
4813 
4814             message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4815 
4816             message << "Expected: ";
4817             vec4_expected[i].log(message);
4818 
4819             message << tcu::TestLog::EndMessage;
4820         }
4821 
4822         /* Check array length, it should be 4 */
4823         if (4 != array_length)
4824         {
4825             m_context.getTestContext().getLog()
4826                 << tcu::TestLog::Message << "Error. Invalid array length: " << array_length << ". Expected 4."
4827                 << tcu::TestLog::EndMessage;
4828         }
4829     }
4830 }
4831 
4832 /** Execute draw call and verifies captrued varyings
4833  *
4834  * @param combination           Function combination, first applied function is at index [0]
4835  * @param left                  Left operand
4836  * @param right                 Right operand
4837  * @param indices               Indices used by dynamic calls
4838  *
4839  * @return true if all results match expected values, false otherwise
4840  **/
testDraw(const glw::GLuint combination[4],const Utils::vec4<glw::GLfloat> & left,const Utils::vec4<glw::GLfloat> & right,const Utils::vec4<glw::GLuint> & indices) const4841 bool FunctionalTest7_8::testDraw(const glw::GLuint combination[4], const Utils::vec4<glw::GLfloat> &left,
4842                                  const Utils::vec4<glw::GLfloat> &right, const Utils::vec4<glw::GLuint> &indices) const
4843 {
4844     const glw::Functions &gl            = m_context.getRenderContext().getFunctions();
4845     static const GLuint n_vec4_varyings = 7;
4846     bool result                         = true;
4847     GLuint subroutine_indices[4];
4848     static const GLuint n_subroutine_uniforms = sizeof(subroutine_indices) / sizeof(subroutine_indices[0]);
4849 
4850     /* Prepare expected results */
4851     Utils::vec4<glw::GLfloat> expected_results[7];
4852     calculate(combination, left, right, indices, expected_results[0], expected_results[1], expected_results[2],
4853               expected_results[3], expected_results[4], expected_results[5], expected_results[6]);
4854 
4855     /* Set up input data uniforms */
4856     gl.uniform4f(m_uniform_locations[0], left.m_x, left.m_y, left.m_z, left.m_w);
4857     GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
4858 
4859     gl.uniform4f(m_uniform_locations[1], right.m_x, right.m_y, right.m_z, right.m_w);
4860     GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
4861 
4862     gl.uniform4ui(m_uniform_locations[2], indices.m_x, indices.m_y, indices.m_z, indices.m_w);
4863     GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4ui");
4864 
4865     /* Prepare subroutine uniform data */
4866     for (GLuint i = 0; i < n_subroutine_uniforms; ++i)
4867     {
4868         const GLuint location = m_subroutine_uniform_locations[i];
4869 
4870         subroutine_indices[location] = m_subroutine_indices[combination[i]];
4871     }
4872 
4873     /* Set up subroutine uniforms */
4874     gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, n_subroutine_uniforms, &subroutine_indices[0]);
4875     GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
4876 
4877     /* Execute draw call with transform feedback */
4878     gl.beginTransformFeedback(GL_POINTS);
4879     GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
4880 
4881     gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
4882     GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
4883 
4884     gl.endTransformFeedback();
4885     GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
4886 
4887     /* Capture results */
4888     GLvoid *feedback_data = (GLvoid *)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
4889     GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
4890 
4891     Utils::vec4<GLfloat> vec4_results[7];
4892     bool results[7];
4893     GLfloat *float_data = (GLfloat *)feedback_data;
4894     for (GLuint i = 0; i < n_vec4_varyings; ++i)
4895     {
4896         vec4_results[i].m_x = float_data[i * 4 + 0];
4897         vec4_results[i].m_y = float_data[i * 4 + 1];
4898         vec4_results[i].m_z = float_data[i * 4 + 2];
4899         vec4_results[i].m_w = float_data[i * 4 + 3];
4900     }
4901 
4902     GLuint *uint_data   = (GLuint *)(float_data + (n_vec4_varyings)*4);
4903     GLuint array_length = uint_data[0];
4904 
4905     /* Unmap buffer */
4906     gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
4907     GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
4908 
4909     /* Verification */
4910     for (GLuint i = 0; i < n_vec4_varyings; ++i)
4911     {
4912         results[i] = (vec4_results[i] == expected_results[i]);
4913         result     = result && results[i];
4914     }
4915 
4916     result = result && (4 == array_length);
4917 
4918     /* Log error if any */
4919     if (false == result)
4920     {
4921         logError(combination, left, right, indices, expected_results, vec4_results, array_length, results);
4922     }
4923 
4924     /* Done */
4925     return result;
4926 }
4927 
4928 /** Constructor.
4929  *
4930  *  @param context Rendering context.
4931  *
4932  **/
FunctionalTest9(deqp::Context & context)4933 FunctionalTest9::FunctionalTest9(deqp::Context &context)
4934     : TestCase(context, "subroutines_3_subroutine_types_and_subroutine_uniforms_one_function",
4935                "Makes sure that program with one function associated with 3 different "
4936                "subroutine types and 3 subroutine uniforms using that function compiles "
4937                "and works as expected")
4938     , m_has_test_passed(true)
4939     , m_n_points_to_draw(16) /* arbitrary value */
4940     , m_po_id(0)
4941     , m_vao_id(0)
4942     , m_vs_id(0)
4943     , m_xfb_bo_id(0)
4944 {
4945     /* Left blank intentionally */
4946 }
4947 
4948 /** De-initializes GL objects that may have been created during test execution. */
deinit()4949 void FunctionalTest9::deinit()
4950 {
4951     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
4952 
4953     if (m_po_id != 0)
4954     {
4955         gl.deleteProgram(m_po_id);
4956 
4957         m_po_id = 0;
4958     }
4959 
4960     if (m_vao_id != 0)
4961     {
4962         gl.deleteVertexArrays(1, &m_vao_id);
4963 
4964         m_vao_id = 0;
4965     }
4966 
4967     if (m_vs_id != 0)
4968     {
4969         gl.deleteShader(m_vs_id);
4970 
4971         m_vs_id = 0;
4972     }
4973 
4974     if (m_xfb_bo_id != 0)
4975     {
4976         gl.deleteBuffers(1, &m_xfb_bo_id);
4977 
4978         m_xfb_bo_id = 0;
4979     }
4980 }
4981 
4982 /** Retrieves body of a vertex shader that should be used
4983  *  for the testing purposes.
4984  **/
getVertexShaderBody() const4985 std::string FunctionalTest9::getVertexShaderBody() const
4986 {
4987     return "#version 400\n"
4988            "\n"
4989            "#extension GL_ARB_shader_subroutine : require\n"
4990            "\n"
4991            "subroutine void subroutineType1(inout float);\n"
4992            "subroutine void subroutineType2(inout float);\n"
4993            "subroutine void subroutineType3(inout float);\n"
4994            "\n"
4995            "subroutine(subroutineType1, subroutineType2, subroutineType3) void function(inout float result)\n"
4996            "{\n"
4997            "    result += float(0.123) + float(gl_VertexID);\n"
4998            "}\n"
4999            "\n"
5000            "subroutine uniform subroutineType1 subroutine_uniform1;\n"
5001            "subroutine uniform subroutineType2 subroutine_uniform2;\n"
5002            "subroutine uniform subroutineType3 subroutine_uniform3;\n"
5003            "\n"
5004            "out vec4 result;\n"
5005            "\n"
5006            "void main()\n"
5007            "{\n"
5008            "    result = vec4(0, 1, 2, 3);\n"
5009            "\n"
5010            "    subroutine_uniform1(result.x);\n"
5011            "    subroutine_uniform2(result.y);\n"
5012            "    subroutine_uniform3(result.z);\n"
5013            "\n"
5014            "    result.w += result.x + result.y + result.z;\n"
5015            "}\n";
5016 }
5017 
5018 /** Initializes all GL objects required to run the test. */
initTest()5019 void FunctionalTest9::initTest()
5020 {
5021     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
5022 
5023     /* Set up program object */
5024     const char *xfb_varyings[] = {"result"};
5025 
5026     const unsigned int n_xfb_varyings = sizeof(xfb_varyings) / sizeof(xfb_varyings[0]);
5027     if (!Utils::buildProgram(gl, getVertexShaderBody(), "",                   /* tc_body */
5028                              "",                                              /* te_body */
5029                              "",                                              /* gs_body */
5030                              "",                                              /* fs_body */
5031                              xfb_varyings, n_xfb_varyings, &m_vs_id, DE_NULL, /* out_tc_id */
5032                              DE_NULL,                                         /* out_te_id */
5033                              DE_NULL,                                         /* out_gs_id */
5034                              DE_NULL,                                         /* out_fs_id */
5035                              &m_po_id))
5036     {
5037         TCU_FAIL("Program failed to link successfully");
5038     }
5039 
5040     /* Set up a buffer object we will use to hold XFB data */
5041     const unsigned int xfb_bo_size = static_cast<unsigned int>(sizeof(float) * 4 /* components */ * m_n_points_to_draw);
5042 
5043     gl.genBuffers(1, &m_xfb_bo_id);
5044     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
5045 
5046     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_xfb_bo_id);
5047     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
5048 
5049     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_xfb_bo_id);
5050     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed.");
5051 
5052     gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_bo_size, DE_NULL, /* data */
5053                   GL_STATIC_COPY);
5054     GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
5055 
5056     /* Generate & bind a VAO */
5057     gl.genVertexArrays(1, &m_vao_id);
5058     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
5059 
5060     gl.bindVertexArray(m_vao_id);
5061     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
5062 }
5063 
5064 /** Executes test iteration.
5065  *
5066  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
5067  */
iterate()5068 tcu::TestNode::IterateResult FunctionalTest9::iterate()
5069 {
5070     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
5071 
5072     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
5073     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
5074     {
5075         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
5076     }
5077     initTest();
5078 
5079     /* Issue a draw call to make use of the three subroutine uniforms that we've defined */
5080     gl.useProgram(m_po_id);
5081     GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
5082 
5083     gl.beginTransformFeedback(GL_POINTS);
5084     GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed.");
5085     {
5086         gl.drawArrays(GL_POINTS, 0 /* first */, m_n_points_to_draw);
5087         GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
5088     }
5089     gl.endTransformFeedback();
5090     GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed.");
5091 
5092     /* Map the XFB BO storage into process space */
5093     const glw::GLvoid *xfb_data_ptr = gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
5094     GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer() call failed.");
5095 
5096     verifyXFBData(xfb_data_ptr);
5097 
5098     gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
5099     GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
5100 
5101     /* All done */
5102     if (m_has_test_passed)
5103     {
5104         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5105     }
5106     else
5107     {
5108         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
5109     }
5110 
5111     return STOP;
5112 }
5113 
5114 /** Verifies the data XFBed out by the vertex shader. Should the data
5115  *  be found invalid, m_has_test_passed will be set to false.
5116  *
5117  *  @param data_ptr XFB data.
5118  **/
verifyXFBData(const glw::GLvoid * data_ptr)5119 void FunctionalTest9::verifyXFBData(const glw::GLvoid *data_ptr)
5120 {
5121     const float epsilon               = 1e-5f;
5122     bool should_continue              = true;
5123     const glw::GLfloat *traveller_ptr = (const glw::GLfloat *)data_ptr;
5124 
5125     for (unsigned int n_point = 0; n_point < m_n_points_to_draw && should_continue; ++n_point)
5126     {
5127         tcu::Vec4 expected_result(0, 1, 2, 3);
5128 
5129         for (unsigned int n_component = 0; n_component < 3 /* xyz */; ++n_component)
5130         {
5131             expected_result[n_component] += 0.123f + float(n_point);
5132         }
5133 
5134         expected_result[3 /* w */] += expected_result[0] + expected_result[1] + expected_result[2];
5135 
5136         if (de::abs(expected_result[0] - traveller_ptr[0]) > epsilon ||
5137             de::abs(expected_result[1] - traveller_ptr[1]) > epsilon ||
5138             de::abs(expected_result[2] - traveller_ptr[2]) > epsilon ||
5139             de::abs(expected_result[3] - traveller_ptr[3]) > epsilon)
5140         {
5141             m_testCtx.getLog() << tcu::TestLog::Message
5142                                << "XFBed data is invalid. Expected:"
5143                                   "("
5144                                << expected_result[0] << ", " << expected_result[1] << ", " << expected_result[2] << ", "
5145                                << expected_result[3] << "), found:(" << traveller_ptr[0] << ", " << traveller_ptr[1]
5146                                << ", " << traveller_ptr[2] << ", " << traveller_ptr[3] << ")."
5147                                << tcu::TestLog::EndMessage;
5148 
5149             m_has_test_passed = false;
5150             should_continue   = false;
5151         }
5152 
5153         traveller_ptr += 4; /* xyzw */
5154     }                       /* for (all rendered points) */
5155 }
5156 
5157 /** Constructor
5158  *
5159  * @param context CTS context
5160  **/
FunctionalTest10(deqp::Context & context)5161 FunctionalTest10::FunctionalTest10(deqp::Context &context)
5162     : TestCase(context, "arrays_of_arrays_of_uniforms", "Verify that arrays of arrays of uniforms works as expected")
5163 {
5164 }
5165 
5166 /** Execute test
5167  *
5168  * @return tcu::TestNode::STOP
5169  **/
iterate()5170 tcu::TestNode::IterateResult FunctionalTest10::iterate()
5171 {
5172     static const GLchar *vertex_shader_code = "#version 400 core\n"
5173                                               "#extension GL_ARB_arrays_of_arrays  : require\n"
5174                                               "#extension GL_ARB_shader_subroutine : require\n"
5175                                               "\n"
5176                                               "precision highp float;\n"
5177                                               "\n"
5178                                               "// Subroutine type\n"
5179                                               "subroutine int routine_type(in int iparam);\n"
5180                                               "\n"
5181                                               "// Subroutine definitions\n"
5182                                               "subroutine(routine_type) int increment(in int iparam)\n"
5183                                               "{\n"
5184                                               "    return iparam + 1;\n"
5185                                               "}\n"
5186                                               "\n"
5187                                               "subroutine(routine_type) int decrement(in int iparam)\n"
5188                                               "{\n"
5189                                               "    return iparam - 1;\n"
5190                                               "}\n"
5191                                               "\n"
5192                                               "// Sub routine uniform\n"
5193                                               "subroutine uniform routine_type routine[4][4];\n"
5194                                               "\n"
5195                                               "// Output\n"
5196                                               "out int out_result;\n"
5197                                               "\n"
5198                                               "void main()\n"
5199                                               "{\n"
5200                                               "    int result = 0;\n"
5201                                               "    \n"
5202                                               "    for (uint j = 0; j < routine.length(); ++j)\n"
5203                                               "    {\n"
5204                                               "        for (uint i = 0; i < routine[j].length(); ++i)\n"
5205                                               "        {\n"
5206                                               "            result = routine[j][i](result);\n"
5207                                               "        }\n"
5208                                               "    }\n"
5209                                               "    \n"
5210                                               "    out_result = result;\n"
5211                                               "}\n"
5212                                               "\n";
5213 
5214     static const GLchar *subroutine_names[] = {
5215         "increment",
5216         "decrement",
5217     };
5218     static const GLuint n_subroutine_names = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
5219 
5220     static const GLchar *subroutine_uniform_names[] = {
5221         "routine[0][0]", "routine[1][0]", "routine[2][0]", "routine[3][0]", "routine[0][1]", "routine[1][1]",
5222         "routine[2][1]", "routine[3][1]", "routine[0][2]", "routine[1][2]", "routine[2][2]", "routine[3][2]",
5223         "routine[0][3]", "routine[1][3]", "routine[2][3]", "routine[3][3]"};
5224     static const GLuint n_subroutine_uniform_names =
5225         sizeof(subroutine_uniform_names) / sizeof(subroutine_uniform_names[0]);
5226 
5227     static const GLchar *varying_name                  = "out_result";
5228     static const GLuint transform_feedback_buffer_size = sizeof(GLint);
5229 
5230     static const GLuint configuration_increment[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
5231 
5232     static const GLuint configuration_decrement[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
5233 
5234     static const GLuint configuration_mix[16] = {1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1};
5235 
5236     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
5237     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
5238     {
5239         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
5240     }
5241 
5242     /* Do not execute the test if GL_ARB_arrays_of_arrays is not supported */
5243     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_arrays_of_arrays"))
5244     {
5245         throw tcu::NotSupportedError("GL_ARB_arrays_of_arrays is not supported.");
5246     }
5247 
5248     bool result = true;
5249 
5250     /* GL objects */
5251     Utils::program program(m_context);
5252     Utils::buffer transform_feedback_buffer(m_context);
5253     Utils::vertexArray vao(m_context);
5254 
5255     /* Init GL objects */
5256     program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code, &varying_name,
5257                   1 /* n_varyings */);
5258 
5259     program.use();
5260 
5261     vao.generate();
5262     vao.bind();
5263 
5264     transform_feedback_buffer.generate();
5265     transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
5266                                      GL_DYNAMIC_COPY);
5267     transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
5268 
5269     /* Get subroutine indices */
5270     for (GLuint routine = 0; routine < n_subroutine_names; ++routine)
5271     {
5272         m_subroutine_indices[routine] = program.getSubroutineIndex(subroutine_names[routine], GL_VERTEX_SHADER);
5273     }
5274 
5275     /* Get subroutine uniform locations */
5276     for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
5277     {
5278         m_subroutine_uniform_locations[uniform] =
5279             program.getSubroutineUniformLocation(subroutine_uniform_names[uniform], GL_VERTEX_SHADER);
5280     }
5281 
5282     /* Test */
5283     GLint increment_result = testDraw(configuration_increment);
5284     GLint decrement_result = testDraw(configuration_decrement);
5285     GLint mix_result       = testDraw(configuration_mix);
5286 
5287     /* Verify */
5288     if (16 != increment_result)
5289     {
5290         result = false;
5291     }
5292 
5293     if (-16 != decrement_result)
5294     {
5295         result = false;
5296     }
5297     if (0 != mix_result)
5298     {
5299         result = false;
5300     }
5301 
5302     /* Set test result */
5303     if (true == result)
5304     {
5305         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5306     }
5307     else
5308     {
5309         m_context.getTestContext().getLog()
5310             << tcu::TestLog::Message << "Error. Invalid result."
5311             << " Incrementation applied 16 times: " << increment_result
5312             << ". Decrementation applied 16 times: " << decrement_result
5313             << ". Incrementation and decrementation applied 8 times: " << mix_result << tcu::TestLog::EndMessage;
5314 
5315         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
5316     }
5317 
5318     /* Done */
5319     return tcu::TestNode::STOP;
5320 }
5321 
5322 /** Execute draw call and return captured varying
5323  *
5324  * @param routine_indices Configuration of subroutine uniforms
5325  *
5326  * @return Value of varying captured with transform feedback
5327  **/
testDraw(const GLuint routine_indices[16]) const5328 GLint FunctionalTest10::testDraw(const GLuint routine_indices[16]) const
5329 {
5330     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
5331     GLuint subroutine_indices[16];
5332     static const GLuint n_subroutine_uniforms = sizeof(subroutine_indices) / sizeof(subroutine_indices[0]);
5333 
5334     /* Prepare subroutine uniform data */
5335     for (GLuint i = 0; i < n_subroutine_uniforms; ++i)
5336     {
5337         const GLuint location = m_subroutine_uniform_locations[i];
5338 
5339         subroutine_indices[location] = m_subroutine_indices[routine_indices[i]];
5340     }
5341 
5342     /* Set up subroutine uniforms */
5343     gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, n_subroutine_uniforms, &subroutine_indices[0]);
5344     GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
5345 
5346     /* Execute draw call with transform feedback */
5347     gl.beginTransformFeedback(GL_POINTS);
5348     GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
5349 
5350     gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
5351     GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
5352 
5353     gl.endTransformFeedback();
5354     GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
5355 
5356     /* Capture results */
5357     GLint *feedback_data = (GLint *)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
5358     GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
5359 
5360     GLint result = feedback_data[0];
5361 
5362     /* Unmap buffer */
5363     gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
5364     GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
5365 
5366     return result;
5367 }
5368 
5369 /* Definitions of constants used by FunctionalTest11 */
5370 const GLuint FunctionalTest11::m_texture_height = 32;
5371 const GLuint FunctionalTest11::m_texture_width  = 32;
5372 
5373 /** Constructor
5374  *
5375  * @param context CTS context
5376  **/
FunctionalTest11(deqp::Context & context)5377 FunctionalTest11::FunctionalTest11(deqp::Context &context)
5378     : TestCase(context, "globals_sampling_output_discard_function_calls",
5379                "Verify that global variables, texture "
5380                "sampling, fragment output, fragment discard "
5381                "and function calls work as expected")
5382 {
5383 }
5384 
5385 /** Execute test
5386  *
5387  * @return tcu::TestNode::STOP
5388  **/
iterate()5389 tcu::TestNode::IterateResult FunctionalTest11::iterate()
5390 {
5391     static const GLchar *fragment_shader_code =
5392         "#version 400 core\n"
5393         "#extension GL_ARB_shader_subroutine : require\n"
5394         "\n"
5395         "precision highp float;\n"
5396         "\n"
5397         "// Output\n"
5398         "layout(location = 0) out vec4 out_color;\n"
5399         "\n"
5400         "// Global variables\n"
5401         "vec4 success_color;\n"
5402         "vec4 failure_color;\n"
5403         "\n"
5404         "// Samplers\n"
5405         "uniform sampler2D sampler_1;\n"
5406         "uniform sampler2D sampler_2;\n"
5407         "\n"
5408         "// Functions\n"
5409         "bool are_same(in vec4 left, in vec4 right)\n"
5410         "{\n"
5411         "    bvec4 result;\n"
5412         "\n"
5413         "    result.x = (left.x == right.x);\n"
5414         "    result.y = (left.y == right.y);\n"
5415         "    result.z = (left.z == right.z);\n"
5416         "    result.w = (left.w == right.w);\n"
5417         "\n"
5418         "    return all(result);\n"
5419         "}\n"
5420         "\n"
5421         "bool are_different(in vec4 left, in vec4 right)\n"
5422         "{\n"
5423         "    bvec4 result;\n"
5424         "\n"
5425         "    result.x = (left.x != right.x);\n"
5426         "    result.y = (left.y != right.y);\n"
5427         "    result.z = (left.z != right.z);\n"
5428         "    result.w = (left.w != right.w);\n"
5429         "\n"
5430         "    return any(result);\n"
5431         "}\n"
5432         "\n"
5433         "// Subroutine types\n"
5434         "subroutine void discard_fragment_type(void);\n"
5435         "subroutine void set_global_colors_type(void);\n"
5436         "subroutine vec4 sample_texture_type(in vec2);\n"
5437         "subroutine bool comparison_type(in vec4 left, in vec4 right);\n"
5438         "subroutine void test_type(void);\n"
5439         "\n"
5440         "// Subroutine definitions\n"
5441         "// discard_fragment_type\n"
5442         "subroutine(discard_fragment_type) void discard_yes(void)\n"
5443         "{\n"
5444         "    discard;\n"
5445         "}\n"
5446         "\n"
5447         "subroutine(discard_fragment_type) void discard_no(void)\n"
5448         "{\n"
5449         "}\n"
5450         "\n"
5451         "// set_global_colors_type\n"
5452         "subroutine(set_global_colors_type) void red_pass_blue_fail(void)\n"
5453         "{\n"
5454         "    success_color = vec4(1, 0, 0, 1);\n"
5455         "    failure_color = vec4(0, 0, 1, 1);\n"
5456         "}\n"
5457         "\n"
5458         "subroutine(set_global_colors_type) void blue_pass_red_fail(void)\n"
5459         "{\n"
5460         "    success_color = vec4(0, 0, 1, 1);\n"
5461         "    failure_color = vec4(1, 0, 0, 1);\n"
5462         "}\n"
5463         "\n"
5464         "// sample_texture_type\n"
5465         "subroutine(sample_texture_type) vec4 first_sampler(in vec2 coord)\n"
5466         "{\n"
5467         "    return texture(sampler_1, coord);\n"
5468         "}\n"
5469         "\n"
5470         "subroutine(sample_texture_type) vec4 second_sampler(in vec2 coord)\n"
5471         "{\n"
5472         "    return texture(sampler_2, coord);\n"
5473         "}\n"
5474         "\n"
5475         "// comparison_type\n"
5476         "subroutine(comparison_type) bool check_equal(in vec4 left, in vec4 right)\n"
5477         "{\n"
5478         "    return are_same(left, right);\n"
5479         "}\n"
5480         "\n"
5481         "subroutine(comparison_type) bool check_not_equal(in vec4 left, in vec4 right)\n"
5482         "{\n"
5483         "    return are_different(left, right);\n"
5484         "}\n"
5485         "\n"
5486         "// Subroutine uniforms\n"
5487         "subroutine uniform discard_fragment_type  discard_fragment;\n"
5488         "subroutine uniform set_global_colors_type set_global_colors;\n"
5489         "subroutine uniform sample_texture_type    sample_texture;\n"
5490         "subroutine uniform comparison_type        compare;\n"
5491         "\n"
5492         "// Subroutine definitions\n"
5493         "// test_type\n"
5494         "subroutine(test_type) void test_with_discard(void)\n"
5495         "{\n"
5496         "    discard_fragment();"
5497         "\n"
5498         "    out_color = failure_color;\n"
5499         "\n"
5500         "    set_global_colors();\n"
5501         "\n"
5502         "    vec4 sampled_color = sample_texture(gl_PointCoord);\n"
5503         "\n"
5504         "    bool comparison_result = compare(success_color, sampled_color);\n"
5505         "\n"
5506         "    if (true == comparison_result)\n"
5507         "    {\n"
5508         "        out_color = success_color;\n"
5509         "    }\n"
5510         "    else\n"
5511         "    {\n"
5512         "        out_color = failure_color;\n"
5513         "    }\n"
5514         "}\n"
5515         "\n"
5516         "subroutine(test_type) void test_without_discard(void)\n"
5517         "{\n"
5518         "    set_global_colors();\n"
5519         "\n"
5520         "    vec4 sampled_color = sample_texture(gl_PointCoord);\n"
5521         "\n"
5522         "    bool comparison_result = compare(success_color, sampled_color);\n"
5523         "\n"
5524         "    if (true == comparison_result)\n"
5525         "    {\n"
5526         "        out_color = success_color;\n"
5527         "    }\n"
5528         "    else\n"
5529         "    {\n"
5530         "        out_color = failure_color;\n"
5531         "    }\n"
5532         "}\n"
5533         "\n"
5534         "// Subroutine uniforms\n"
5535         "subroutine uniform test_type test;\n"
5536         "\n"
5537         "void main()\n"
5538         "{\n"
5539         "    // Set colors\n"
5540         "    success_color = vec4(0.5, 0.5, 0.5, 0.5);\n"
5541         "    failure_color = vec4(0.5, 0.5, 0.5, 0.5);\n"
5542         "\n"
5543         "    test();\n"
5544         "}\n"
5545         "\n";
5546 
5547     static const GLchar *geometry_shader_code = "#version 400 core\n"
5548                                                 "#extension GL_ARB_shader_subroutine : require\n"
5549                                                 "\n"
5550                                                 "precision highp float;\n"
5551                                                 "\n"
5552                                                 "layout(points)                           in;\n"
5553                                                 "layout(triangle_strip, max_vertices = 4) out;\n"
5554                                                 "\n"
5555                                                 "void main()\n"
5556                                                 "{\n"
5557                                                 "    gl_Position = vec4(-1, -1, 0, 1);\n"
5558                                                 "    EmitVertex();\n"
5559                                                 "    \n"
5560                                                 "    gl_Position = vec4(-1,  1, 0, 1);\n"
5561                                                 "    EmitVertex();\n"
5562                                                 "    \n"
5563                                                 "    gl_Position = vec4( 1, -1, 0, 1);\n"
5564                                                 "    EmitVertex();\n"
5565                                                 "    \n"
5566                                                 "    gl_Position = vec4( 1,  1, 0, 1);\n"
5567                                                 "    EmitVertex();\n"
5568                                                 "    \n"
5569                                                 "    EndPrimitive();\n"
5570                                                 "}\n"
5571                                                 "\n";
5572 
5573     static const GLchar *vertex_shader_code = "#version 400 core\n"
5574                                               "#extension GL_ARB_shader_subroutine : require\n"
5575                                               "\n"
5576                                               "precision highp float;\n"
5577                                               "\n"
5578                                               "void main()\n"
5579                                               "{\n"
5580                                               "}\n"
5581                                               "\n";
5582 
5583     static const GLchar *subroutine_names[][2] = {{"discard_yes", "discard_no"},
5584                                                   {"red_pass_blue_fail", "blue_pass_red_fail"},
5585                                                   {"first_sampler", "second_sampler"},
5586                                                   {"check_equal", "check_not_equal"},
5587                                                   {"test_with_discard", "test_without_discard"}};
5588     static const GLuint n_subroutine_types     = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
5589 
5590     static const GLchar *subroutine_uniform_names[] = {"discard_fragment", "set_global_colors", "sample_texture",
5591                                                        "compare", "test"};
5592     static const GLuint n_subroutine_uniform_names =
5593         sizeof(subroutine_uniform_names) / sizeof(subroutine_uniform_names[0]);
5594 
5595     static const GLchar *uniform_names[] = {
5596         "sampler_1",
5597         "sampler_2",
5598     };
5599     static const GLuint n_uniform_names = sizeof(uniform_names) / sizeof(uniform_names[0]);
5600 
5601     /* Colors */
5602     static const GLubyte blue_color[4]  = {0, 0, 255, 255};
5603     static const GLubyte clean_color[4] = {0, 0, 0, 0};
5604     static const GLubyte red_color[4]   = {255, 0, 0, 255};
5605 
5606     /* Configurations */
5607     static const testConfiguration test_configurations[] = {
5608         testConfiguration(
5609             "Expect red color from 1st sampler", red_color, 1 /* discard_fragment  : discard_no         */,
5610             0 /* set_global_colors : red_pass_blue_fail */, 0 /* sample_texture    : first_sampler      */,
5611             0 /* compare           : check_equal        */, 0 /* test              : test_with_discard  */, 1 /* red */,
5612             0 /* blue */),
5613 
5614         testConfiguration(
5615             "Test \"without discard\" option, expect no blue color from 2nd sampler", blue_color,
5616             0 /* discard_fragment  : discard_yes           */, 1 /* set_global_colors : blue_pass_red_fail    */,
5617             1 /* sample_texture    : second_sampler        */, 1 /* compare           : check_not_equal       */,
5618             1 /* test              : test_without_discard  */, 0 /* blue */, 1 /* red */),
5619 
5620         testConfiguration("Fragment shoud be discarded", clean_color, 0 /* discard_fragment  : discard_yes        */,
5621                           0 /* set_global_colors : red_pass_blue_fail */,
5622                           0 /* sample_texture    : first_sampler      */,
5623                           0 /* compare           : check_equal        */,
5624                           0 /* test              : test_with_discard  */, 1 /* red */, 0 /* blue */),
5625 
5626         testConfiguration(
5627             "Expect blue color from 1st sampler", blue_color, 1 /* discard_fragment  : discard_no         */,
5628             1 /* set_global_colors : blue_pass_red_fail */, 0 /* sample_texture    : first_sampler      */,
5629             0 /* compare           : check_equal        */, 0 /* test              : test_with_discard  */,
5630             0 /* blue */, 1 /* red */),
5631 
5632         testConfiguration(
5633             "Expect red color from 2nd sampler", red_color, 1 /* discard_fragment  : discard_no         */,
5634             0 /* set_global_colors : red_pass_blue_fail */, 1 /* sample_texture    : second_sampler     */,
5635             0 /* compare           : check_equal        */, 0 /* test              : test_with_discard  */,
5636             0 /* blue */, 1 /* red */),
5637 
5638         testConfiguration(
5639             "Expect no blue color from 2nd sampler", blue_color, 1 /* discard_fragment  : discard_no         */,
5640             1 /* set_global_colors : blue_pass_red_fail */, 1 /* sample_texture    : second_sampler     */,
5641             1 /* compare           : check_not_equal    */, 0 /* test              : test_with_discard  */,
5642             0 /* blue */, 1 /* red */),
5643     };
5644     static const GLuint n_test_cases = sizeof(test_configurations) / sizeof(test_configurations[0]);
5645 
5646     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
5647     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
5648     {
5649         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
5650     }
5651 
5652     /* GL objects */
5653     Utils::texture blue_texture(m_context);
5654     Utils::texture color_texture(m_context);
5655     Utils::framebuffer framebuffer(m_context);
5656     Utils::program program(m_context);
5657     Utils::texture red_texture(m_context);
5658     Utils::vertexArray vao(m_context);
5659 
5660     /* Init GL objects */
5661     program.build(0 /* cs */, fragment_shader_code /* fs */, geometry_shader_code /* gs */, 0 /* tcs */, 0 /* test */,
5662                   vertex_shader_code, 0 /* varying_names */, 0 /* n_varyings */);
5663 
5664     program.use();
5665 
5666     vao.generate();
5667     vao.bind();
5668 
5669     blue_texture.create(m_texture_width, m_texture_height, GL_RGBA8);
5670     color_texture.create(m_texture_width, m_texture_height, GL_RGBA8);
5671     red_texture.create(m_texture_width, m_texture_height, GL_RGBA8);
5672 
5673     framebuffer.generate();
5674     framebuffer.bind();
5675     framebuffer.attachTexture(GL_COLOR_ATTACHMENT0, color_texture.m_id, m_texture_width, m_texture_height);
5676 
5677     /* Get subroutine indices */
5678     for (GLuint type = 0; type < n_subroutine_types; ++type)
5679     {
5680         m_subroutine_indices[type][0] = program.getSubroutineIndex(subroutine_names[type][0], GL_FRAGMENT_SHADER);
5681         m_subroutine_indices[type][1] = program.getSubroutineIndex(subroutine_names[type][1], GL_FRAGMENT_SHADER);
5682     }
5683 
5684     /* Get subroutine uniform locations */
5685     for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
5686     {
5687         m_subroutine_uniform_locations[uniform] =
5688             program.getSubroutineUniformLocation(subroutine_uniform_names[uniform], GL_FRAGMENT_SHADER);
5689     }
5690 
5691     /* Get uniform locations */
5692     for (GLuint i = 0; i < n_uniform_names; ++i)
5693     {
5694         m_uniform_locations[i] = program.getUniformLocation(uniform_names[i]);
5695     }
5696 
5697     /* Prepare textures */
5698     fillTexture(blue_texture, blue_color);
5699     fillTexture(color_texture, clean_color);
5700     fillTexture(red_texture, red_color);
5701 
5702     m_source_textures[0] = blue_texture.m_id;
5703     m_source_textures[1] = red_texture.m_id;
5704 
5705     framebuffer.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
5706 
5707     /* Test */
5708     bool result = true;
5709     for (GLuint i = 0; i < n_test_cases; ++i)
5710     {
5711         /* Clean output texture */
5712         framebuffer.clear(GL_COLOR_BUFFER_BIT);
5713 
5714         /* Execute test */
5715         if (false == testDraw(test_configurations[i].m_routines, test_configurations[i].m_samplers,
5716                               test_configurations[i].m_expected_color, color_texture))
5717         {
5718             m_context.getTestContext().getLog()
5719                 << tcu::TestLog::Message << "Error. Failure for configuration: " << test_configurations[i].m_description
5720                 << tcu::TestLog::EndMessage;
5721 
5722             result = false;
5723         }
5724     }
5725 
5726     /* Set result */
5727     if (true == result)
5728     {
5729         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5730     }
5731     else
5732     {
5733         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
5734     }
5735 
5736     /* Done */
5737     return tcu::TestNode::STOP;
5738 }
5739 
5740 /** Fill texture with specified color
5741  *
5742  * @param texture Texture instance
5743  * @param color   Color
5744  **/
fillTexture(Utils::texture & texture,const glw::GLubyte color[4]) const5745 void FunctionalTest11::fillTexture(Utils::texture &texture, const glw::GLubyte color[4]) const
5746 {
5747     std::vector<GLubyte> texture_data;
5748 
5749     /* Prepare texture data */
5750     texture_data.resize(m_texture_width * m_texture_height * 4);
5751 
5752     for (GLuint y = 0; y < m_texture_height; ++y)
5753     {
5754         const GLuint line_offset = y * m_texture_width * 4;
5755 
5756         for (GLuint x = 0; x < m_texture_width; ++x)
5757         {
5758             const GLuint point_offset = x * 4 + line_offset;
5759 
5760             texture_data[point_offset + 0] = color[0]; /* red */
5761             texture_data[point_offset + 1] = color[1]; /* green */
5762             texture_data[point_offset + 2] = color[2]; /* blue */
5763             texture_data[point_offset + 3] = color[3]; /* alpha */
5764         }
5765     }
5766 
5767     texture.update(m_texture_width, m_texture_height, GL_RGBA, GL_UNSIGNED_BYTE, &texture_data[0]);
5768 }
5769 
5770 /** Execute draw call and verify results
5771  *
5772  * @param routine_configuration Configurations of routines to be used
5773  * @param sampler_configuration Configuration of textures to be bound to samplers
5774  * @param expected_color        Expected color of result image
5775  *
5776  * @return true if result image is filled with expected color, false otherwise
5777  **/
testDraw(const glw::GLuint routine_configuration[5],const glw::GLuint sampler_configuration[2],const glw::GLubyte expected_color[4],Utils::texture & color_texture) const5778 bool FunctionalTest11::testDraw(const glw::GLuint routine_configuration[5], const glw::GLuint sampler_configuration[2],
5779                                 const glw::GLubyte expected_color[4], Utils::texture &color_texture) const
5780 {
5781     const glw::Functions &gl                 = m_context.getRenderContext().getFunctions();
5782     static const GLint n_samplers            = 2;
5783     static const GLint n_subroutine_uniforms = 5;
5784     GLuint subroutine_indices[5];
5785 
5786     /* Set samplers */
5787     for (GLuint i = 0; i < n_samplers; ++i)
5788     {
5789         const GLuint location = m_uniform_locations[i];
5790         const GLuint texture  = m_source_textures[sampler_configuration[i]];
5791 
5792         gl.activeTexture(GL_TEXTURE0 + i);
5793         GLU_EXPECT_NO_ERROR(gl.getError(), "ActiveTexture");
5794 
5795         gl.bindTexture(GL_TEXTURE_2D, texture);
5796         GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
5797 
5798         gl.uniform1i(location, i);
5799         GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
5800     }
5801 
5802     gl.activeTexture(GL_TEXTURE0 + 0);
5803 
5804     /* Set subroutine uniforms */
5805     for (GLuint i = 0; i < n_subroutine_uniforms; ++i)
5806     {
5807         const GLuint location = m_subroutine_uniform_locations[i];
5808         const GLuint routine  = routine_configuration[i];
5809 
5810         subroutine_indices[location] = m_subroutine_indices[i][routine];
5811     }
5812 
5813     gl.uniformSubroutinesuiv(GL_FRAGMENT_SHADER, 5, subroutine_indices);
5814     GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
5815 
5816     /* Draw */
5817     gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
5818     GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
5819 
5820     /* Capture result */
5821     std::vector<GLubyte> captured_data;
5822     captured_data.resize(m_texture_width * m_texture_height * 4);
5823 
5824     color_texture.get(GL_RGBA, GL_UNSIGNED_BYTE, &captured_data[0]);
5825 
5826     /* Verify result */
5827     for (GLuint y = 0; y < m_texture_height; ++y)
5828     {
5829         const GLuint line_offset = y * m_texture_width * 4;
5830 
5831         for (GLuint x = 0; x < m_texture_width; ++x)
5832         {
5833             const GLuint point_offset = x * 4 + line_offset;
5834             bool is_as_expected       = true;
5835 
5836             is_as_expected = is_as_expected && (expected_color[0] == captured_data[point_offset + 0]); /* red */
5837             is_as_expected = is_as_expected && (expected_color[1] == captured_data[point_offset + 1]); /* green */
5838             is_as_expected = is_as_expected && (expected_color[2] == captured_data[point_offset + 2]); /* blue */
5839             is_as_expected = is_as_expected && (expected_color[3] == captured_data[point_offset + 3]); /* alpha */
5840 
5841             if (false == is_as_expected)
5842             {
5843                 return false;
5844             }
5845         }
5846     }
5847 
5848     /* Done */
5849     return true;
5850 }
5851 
5852 /* Constatns used by FunctionalTest12 */
5853 const glw::GLuint FunctionalTest12::m_texture_height = 16;
5854 const glw::GLuint FunctionalTest12::m_texture_width  = 16;
5855 
5856 /** Constructor
5857  *
5858  * @param context CTS context
5859  **/
FunctionalTest12(deqp::Context & context)5860 FunctionalTest12::FunctionalTest12(deqp::Context &context)
5861     : TestCase(context, "ssbo_atomic_image_load_store",
5862                "Verify that SSBO, atomic counters and image load store work as expected")
5863     , m_left_image(0)
5864     , m_right_image(0)
5865 {
5866 }
5867 
5868 /** Execute test
5869  *
5870  * @return tcu::TestNode::STOP
5871  **/
iterate()5872 tcu::TestNode::IterateResult FunctionalTest12::iterate()
5873 {
5874     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
5875     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
5876     {
5877         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
5878     }
5879 
5880     bool result = true;
5881 
5882     /* Test atomic counters */
5883     if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_atomic_counters"))
5884     {
5885         if (false == testAtomic())
5886         {
5887             result = false;
5888         }
5889     }
5890 
5891     /* Test shader storage buffer */
5892     if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_storage_buffer_object"))
5893     {
5894         if (false == testSSBO())
5895         {
5896             result = false;
5897         }
5898     }
5899 
5900     /* Test image load store */
5901     if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_image_load_store"))
5902     {
5903         if (false == testImage())
5904         {
5905             result = false;
5906         }
5907     }
5908 
5909     /* Set result */
5910     if (true == result)
5911     {
5912         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5913     }
5914     else
5915     {
5916         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
5917     }
5918 
5919     /* Done */
5920     return tcu::TestNode::STOP;
5921 }
5922 
5923 /** Fill texture with specified color
5924  *
5925  * @param texture Texture instance
5926  * @param color   Color
5927  **/
fillTexture(Utils::texture & texture,const glw::GLuint color[4]) const5928 void FunctionalTest12::fillTexture(Utils::texture &texture, const glw::GLuint color[4]) const
5929 {
5930     std::vector<GLuint> texture_data;
5931 
5932     /* Prepare texture data */
5933     texture_data.resize(m_texture_width * m_texture_height * 4);
5934 
5935     for (GLuint y = 0; y < m_texture_height; ++y)
5936     {
5937         const GLuint line_offset = y * m_texture_width * 4;
5938 
5939         for (GLuint x = 0; x < m_texture_width; ++x)
5940         {
5941             const GLuint point_offset = x * 4 + line_offset;
5942 
5943             texture_data[point_offset + 0] = color[0]; /* red */
5944             texture_data[point_offset + 1] = color[1]; /* green */
5945             texture_data[point_offset + 2] = color[2]; /* blue */
5946             texture_data[point_offset + 3] = color[3]; /* alpha */
5947         }
5948     }
5949 
5950     texture.update(m_texture_width, m_texture_height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &texture_data[0]);
5951 }
5952 
5953 /** Test atomic counters
5954  *
5955  * @return true if test pass, false otherwise
5956  **/
testAtomic()5957 bool FunctionalTest12::testAtomic()
5958 {
5959     static const GLchar *fragment_shader_code = "#version 410 core\n"
5960                                                 "#extension GL_ARB_shader_atomic_counters : require\n"
5961                                                 "#extension GL_ARB_shader_subroutine      : require\n"
5962                                                 "\n"
5963                                                 "precision highp float;\n"
5964                                                 "\n"
5965                                                 "layout(location = 0) out uint out_color;\n"
5966                                                 "\n"
5967                                                 "layout(binding = 0, offset = 8) uniform atomic_uint one;\n"
5968                                                 "layout(binding = 0, offset = 4) uniform atomic_uint two;\n"
5969                                                 "layout(binding = 0, offset = 0) uniform atomic_uint three;\n"
5970                                                 "\n"
5971                                                 "subroutine void atomic_routine(void)\n;"
5972                                                 "\n"
5973                                                 "subroutine(atomic_routine) void increment_two(void)\n"
5974                                                 "{\n"
5975                                                 "    out_color = atomicCounterIncrement(two);\n"
5976                                                 "}\n"
5977                                                 "\n"
5978                                                 "subroutine(atomic_routine) void decrement_three(void)\n"
5979                                                 "{\n"
5980                                                 "    out_color = atomicCounterDecrement(three);\n"
5981                                                 "}\n"
5982                                                 "\n"
5983                                                 "subroutine(atomic_routine) void read_one(void)\n"
5984                                                 "{\n"
5985                                                 "    out_color = atomicCounter(one);\n"
5986                                                 "}\n"
5987                                                 "\n"
5988                                                 "subroutine uniform atomic_routine routine;\n"
5989                                                 "\n"
5990                                                 "void main()\n"
5991                                                 "{\n"
5992                                                 "    routine();\n"
5993                                                 "}\n"
5994                                                 "\n";
5995 
5996     static const GLchar *geometry_shader_code = "#version 400 core\n"
5997                                                 "#extension GL_ARB_shader_subroutine : require\n"
5998                                                 "\n"
5999                                                 "precision highp float;\n"
6000                                                 "\n"
6001                                                 "layout(points)                           in;\n"
6002                                                 "layout(triangle_strip, max_vertices = 4) out;\n"
6003                                                 "\n"
6004                                                 "void main()\n"
6005                                                 "{\n"
6006                                                 "    gl_Position = vec4(-1, -1, 0, 1);\n"
6007                                                 "    EmitVertex();\n"
6008                                                 "    \n"
6009                                                 "    gl_Position = vec4(-1,  1, 0, 1);\n"
6010                                                 "    EmitVertex();\n"
6011                                                 "    \n"
6012                                                 "    gl_Position = vec4( 1, -1, 0, 1);\n"
6013                                                 "    EmitVertex();\n"
6014                                                 "    \n"
6015                                                 "    gl_Position = vec4( 1,  1, 0, 1);\n"
6016                                                 "    EmitVertex();\n"
6017                                                 "    \n"
6018                                                 "    EndPrimitive();\n"
6019                                                 "}\n"
6020                                                 "\n";
6021 
6022     static const GLchar *vertex_shader_code = "#version 400 core\n"
6023                                               "#extension GL_ARB_shader_subroutine : require\n"
6024                                               "\n"
6025                                               "precision highp float;\n"
6026                                               "\n"
6027                                               "void main()\n"
6028                                               "{\n"
6029                                               "}\n"
6030                                               "\n";
6031 
6032     static const GLchar *subroutine_names[] = {"increment_two", "decrement_three", "read_one"};
6033 
6034     /* Test data */
6035     static const glw::GLuint atomic_buffer_data[] = {
6036         m_texture_width * m_texture_height, m_texture_width * m_texture_height, m_texture_width * m_texture_height};
6037 
6038     static const glw::GLuint expected_incremented_two[] = {atomic_buffer_data[0], 2 * atomic_buffer_data[1],
6039                                                            atomic_buffer_data[2]};
6040 
6041     static const glw::GLuint expected_decremented_three[] = {0, expected_incremented_two[1],
6042                                                              expected_incremented_two[2]};
6043 
6044     static const glw::GLuint expected_read_one[] = {expected_decremented_three[0], expected_decremented_three[1],
6045                                                     expected_decremented_three[2]};
6046 
6047     /* GL objects */
6048     Utils::buffer atomic_buffer(m_context);
6049     Utils::texture color_texture(m_context);
6050     Utils::framebuffer framebuffer(m_context);
6051     Utils::program program(m_context);
6052     Utils::vertexArray vao(m_context);
6053 
6054     /* Init GL objects */
6055     program.build(0 /* cs */, fragment_shader_code /* fs */, geometry_shader_code /* gs */, 0 /* tcs */, 0 /* test */,
6056                   vertex_shader_code, 0 /* varying_names */, 0 /* n_varyings */);
6057 
6058     program.use();
6059 
6060     vao.generate();
6061     vao.bind();
6062 
6063     color_texture.create(m_texture_width, m_texture_height, GL_R32UI);
6064 
6065     atomic_buffer.generate();
6066     atomic_buffer.update(GL_ATOMIC_COUNTER_BUFFER, sizeof(atomic_buffer_data), (GLvoid *)atomic_buffer_data,
6067                          GL_STATIC_DRAW);
6068     atomic_buffer.bindRange(GL_ATOMIC_COUNTER_BUFFER, 0 /* index */, 0 /* offset */, sizeof(atomic_buffer_data));
6069 
6070     framebuffer.generate();
6071     framebuffer.bind();
6072     framebuffer.attachTexture(GL_COLOR_ATTACHMENT0, color_texture.m_id, m_texture_width, m_texture_height);
6073     framebuffer.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
6074     framebuffer.clear(GL_COLOR_BUFFER_BIT);
6075 
6076     /* Subroutine indices */
6077     GLuint increment_two   = program.getSubroutineIndex(subroutine_names[0], GL_FRAGMENT_SHADER);
6078     GLuint decrement_three = program.getSubroutineIndex(subroutine_names[1], GL_FRAGMENT_SHADER);
6079     GLuint read_one        = program.getSubroutineIndex(subroutine_names[2], GL_FRAGMENT_SHADER);
6080 
6081     /* Test */
6082     bool result = true;
6083 
6084     if (false == testAtomicDraw(increment_two, expected_incremented_two))
6085     {
6086         result = false;
6087     }
6088 
6089     if (false == testAtomicDraw(decrement_three, expected_decremented_three))
6090     {
6091         result = false;
6092     }
6093 
6094     if (false == testAtomicDraw(read_one, expected_read_one))
6095     {
6096         result = false;
6097     }
6098 
6099     /* Done */
6100     return result;
6101 }
6102 
6103 /** Execture draw call and verify results
6104  *
6105  * @param subroutine_index Index of subroutine that shall be used during draw call
6106  * @param expected_results Expected results
6107  *
6108  * @return true if results are as expected, false otherwise
6109  **/
testAtomicDraw(GLuint subroutine_index,const GLuint expected_results[3]) const6110 bool FunctionalTest12::testAtomicDraw(GLuint subroutine_index, const GLuint expected_results[3]) const
6111 {
6112     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
6113 
6114     /* Set subroutine uniforms */
6115     gl.uniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &subroutine_index);
6116     GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
6117 
6118     /* Draw */
6119     gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
6120     GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
6121 
6122     /* Capture results */
6123     GLuint *atomic_results = (GLuint *)gl.mapBuffer(GL_ATOMIC_COUNTER_BUFFER, GL_READ_ONLY);
6124     GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
6125 
6126     /* Verify */
6127     bool result = (0 == memcmp(expected_results, atomic_results, 3 * sizeof(GLuint)));
6128 
6129     if (false == result)
6130     {
6131         m_context.getTestContext().getLog()
6132             << tcu::TestLog::Message << "Error. Invalid result. "
6133             << "Result: [ " << atomic_results[0] << ", " << atomic_results[1] << ", " << atomic_results[2] << " ] "
6134             << "Expected: [ " << expected_results[0] << ", " << expected_results[1] << ", " << expected_results[2]
6135             << " ]" << tcu::TestLog::EndMessage;
6136     }
6137 
6138     /* Unmap buffer */
6139     gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
6140     GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
6141 
6142     /* Done */
6143     return result;
6144 }
6145 
6146 /** Test image load store
6147  *
6148  * @return true if test pass, false otherwise
6149  **/
testImage()6150 bool FunctionalTest12::testImage()
6151 {
6152     static const GLchar *fragment_shader_code =
6153         "#version 400 core\n"
6154         "#extension GL_ARB_shader_image_load_store : require\n"
6155         "#extension GL_ARB_shader_subroutine       : require\n"
6156         "\n"
6157         "precision highp float;\n"
6158         "\n"
6159         "layout(location = 0) out uvec4 out_color;\n"
6160         "\n"
6161         "layout(rgba32ui) uniform uimage2D left_image;\n"
6162         "layout(rgba32ui) uniform uimage2D right_image;\n"
6163         "\n"
6164         "subroutine void image_routine(void);\n"
6165         "\n"
6166         "subroutine(image_routine) void left_to_right(void)\n"
6167         "{\n"
6168         "    out_color = imageLoad (left_image,  ivec2(gl_FragCoord.xy));\n"
6169         "                imageStore(right_image, ivec2(gl_FragCoord.xy), out_color);\n"
6170         "}\n"
6171         "\n"
6172         "subroutine(image_routine) void right_to_left(void)\n"
6173         "{\n"
6174         "    out_color = imageLoad (right_image, ivec2(gl_FragCoord.xy));\n"
6175         "                imageStore(left_image,  ivec2(gl_FragCoord.xy), out_color);\n"
6176         "}\n"
6177         "\n"
6178         "subroutine uniform image_routine routine;\n"
6179         "\n"
6180         "void main()\n"
6181         "{\n"
6182         "    routine();\n"
6183         "}\n"
6184         "\n";
6185 
6186     static const GLchar *geometry_shader_code = "#version 400 core\n"
6187                                                 "#extension GL_ARB_shader_subroutine : require\n"
6188                                                 "\n"
6189                                                 "precision highp float;\n"
6190                                                 "\n"
6191                                                 "layout(points)                           in;\n"
6192                                                 "layout(triangle_strip, max_vertices = 4) out;\n"
6193                                                 "\n"
6194                                                 "void main()\n"
6195                                                 "{\n"
6196                                                 "    gl_Position = vec4(-1, -1, 0, 1);\n"
6197                                                 "    EmitVertex();\n"
6198                                                 "    \n"
6199                                                 "    gl_Position = vec4(-1,  1, 0, 1);\n"
6200                                                 "    EmitVertex();\n"
6201                                                 "    \n"
6202                                                 "    gl_Position = vec4( 1, -1, 0, 1);\n"
6203                                                 "    EmitVertex();\n"
6204                                                 "    \n"
6205                                                 "    gl_Position = vec4( 1,  1, 0, 1);\n"
6206                                                 "    EmitVertex();\n"
6207                                                 "    \n"
6208                                                 "    EndPrimitive();\n"
6209                                                 "}\n"
6210                                                 "\n";
6211 
6212     static const GLchar *vertex_shader_code = "#version 400 core\n"
6213                                               "#extension GL_ARB_shader_subroutine : require\n"
6214                                               "\n"
6215                                               "precision highp float;\n"
6216                                               "\n"
6217                                               "void main()\n"
6218                                               "{\n"
6219                                               "}\n"
6220                                               "\n";
6221 
6222     static const GLchar *subroutine_names[] = {"left_to_right", "right_to_left"};
6223 
6224     static const GLchar *uniform_names[] = {"left_image", "right_image"};
6225 
6226     /* Test data */
6227     static const GLuint blue_color[4]  = {0, 0, 255, 255};
6228     static const GLuint clean_color[4] = {16, 32, 64, 128};
6229     static const GLuint red_color[4]   = {255, 0, 0, 255};
6230 
6231     /* GL objects */
6232     Utils::texture blue_texture(m_context);
6233     Utils::texture destination_texture(m_context);
6234     Utils::texture color_texture(m_context);
6235     Utils::framebuffer framebuffer(m_context);
6236     Utils::program program(m_context);
6237     Utils::texture red_texture(m_context);
6238     Utils::vertexArray vao(m_context);
6239 
6240     /* Init GL objects */
6241     program.build(0 /* cs */, fragment_shader_code /* fs */, geometry_shader_code /* gs */, 0 /* tcs */, 0 /* test */,
6242                   vertex_shader_code, 0 /* varying_names */, 0 /* n_varyings */);
6243 
6244     program.use();
6245 
6246     vao.generate();
6247     vao.bind();
6248 
6249     blue_texture.create(m_texture_width, m_texture_height, GL_RGBA32UI);
6250     destination_texture.create(m_texture_width, m_texture_height, GL_RGBA32UI);
6251     color_texture.create(m_texture_width, m_texture_height, GL_RGBA32UI);
6252     red_texture.create(m_texture_width, m_texture_height, GL_RGBA32UI);
6253 
6254     fillTexture(blue_texture, blue_color);
6255     fillTexture(destination_texture, clean_color);
6256     fillTexture(red_texture, red_color);
6257 
6258     framebuffer.generate();
6259     framebuffer.bind();
6260     framebuffer.attachTexture(GL_COLOR_ATTACHMENT0, color_texture.m_id, m_texture_width, m_texture_height);
6261     framebuffer.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
6262     framebuffer.clear(GL_COLOR_BUFFER_BIT);
6263 
6264     /* Subroutine indices */
6265     GLuint left_to_right = program.getSubroutineIndex(subroutine_names[0], GL_FRAGMENT_SHADER);
6266     GLuint right_to_left = program.getSubroutineIndex(subroutine_names[1], GL_FRAGMENT_SHADER);
6267 
6268     /* Uniform locations */
6269     m_left_image  = program.getUniformLocation(uniform_names[0]);
6270     m_right_image = program.getUniformLocation(uniform_names[1]);
6271 
6272     /* Test */
6273     bool result = true;
6274 
6275     if (false == testImageDraw(left_to_right, blue_texture, destination_texture, blue_color, blue_color))
6276     {
6277         result = false;
6278     }
6279 
6280     if (false == testImageDraw(left_to_right, red_texture, destination_texture, red_color, red_color))
6281     {
6282         result = false;
6283     }
6284 
6285     if (false == testImageDraw(right_to_left, destination_texture, blue_texture, blue_color, blue_color))
6286     {
6287         result = false;
6288     }
6289 
6290     if (false == testImageDraw(right_to_left, destination_texture, red_texture, red_color, red_color))
6291     {
6292         result = false;
6293     }
6294 
6295     if (false == testImageDraw(left_to_right, blue_texture, red_texture, blue_color, blue_color))
6296     {
6297         result = false;
6298     }
6299 
6300     /* Done */
6301     return result;
6302 }
6303 
6304 /** Execute draw call and verifies results
6305  *
6306  * @param subroutine_index     Index of subroutine that shall be used during draw call
6307  * @param left                 "Left" texture
6308  * @param right                "Right" texture
6309  * @param expected_left_color  Expected color of "left" texture
6310  * @param expected_right_color Expected color of "right" texture
6311  *
6312  * @return true if verification result is positive, false otherwise
6313  **/
testImageDraw(GLuint subroutine_index,Utils::texture & left,Utils::texture & right,const GLuint expected_left_color[4],const GLuint expected_right_color[4]) const6314 bool FunctionalTest12::testImageDraw(GLuint subroutine_index, Utils::texture &left, Utils::texture &right,
6315                                      const GLuint expected_left_color[4], const GLuint expected_right_color[4]) const
6316 {
6317     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
6318 
6319     /* Set subroutine uniforms */
6320     gl.uniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &subroutine_index);
6321     GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
6322 
6323     /* Set up image units */
6324     gl.uniform1i(m_left_image, 0);
6325     GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
6326 
6327     gl.uniform1i(m_right_image, 1);
6328     GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
6329 
6330     gl.bindImageTexture(0, left.m_id, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32UI);
6331     GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
6332 
6333     gl.bindImageTexture(1, right.m_id, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32UI);
6334     GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
6335 
6336     /* Draw */
6337     gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
6338     GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
6339 
6340     /* Verify results */
6341     bool result = true;
6342 
6343     if (false == verifyTexture(left, expected_left_color))
6344     {
6345         m_context.getTestContext().getLog()
6346             << tcu::TestLog::Message << "Error. Invalid result. Left texture is filled with wrong color."
6347             << tcu::TestLog::EndMessage;
6348         result = false;
6349     }
6350 
6351     if (false == verifyTexture(right, expected_right_color))
6352     {
6353         m_context.getTestContext().getLog()
6354             << tcu::TestLog::Message << "Error. Invalid result. Right texture is filled with wrong color."
6355             << tcu::TestLog::EndMessage;
6356         result = false;
6357     }
6358 
6359     /* Done */
6360     return result;
6361 }
6362 
6363 /** Test shader storage buffer
6364  *
6365  * @return true if test pass, false otherwise
6366  **/
testSSBO()6367 bool FunctionalTest12::testSSBO()
6368 {
6369     static const GLchar *fragment_shader_code = "#version 400 core\n"
6370                                                 "#extension GL_ARB_shader_storage_buffer_object : require\n"
6371                                                 "#extension GL_ARB_shader_subroutine            : require\n"
6372                                                 "\n"
6373                                                 "precision highp float;\n"
6374                                                 "\n"
6375                                                 "layout(location = 0) out uvec4 out_color;\n"
6376                                                 "\n"
6377                                                 "layout(std140, binding = 0) buffer Buffer\n"
6378                                                 "{\n"
6379                                                 "    uvec4 entry;\n"
6380                                                 "};\n"
6381                                                 "\n"
6382                                                 "subroutine void ssbo_routine(void)\n;"
6383                                                 "\n"
6384                                                 "subroutine(ssbo_routine) void increment(void)\n"
6385                                                 "{\n"
6386                                                 "    out_color.x = atomicAdd(entry.x, 1);\n"
6387                                                 "    out_color.y = atomicAdd(entry.y, 1);\n"
6388                                                 "    out_color.z = atomicAdd(entry.z, 1);\n"
6389                                                 "    out_color.w = atomicAdd(entry.w, 1);\n"
6390                                                 "}\n"
6391                                                 "\n"
6392                                                 "subroutine(ssbo_routine) void decrement(void)\n"
6393                                                 "{\n"
6394                                                 "    out_color.x = atomicAdd(entry.x, -1);\n"
6395                                                 "    out_color.y = atomicAdd(entry.y, -1);\n"
6396                                                 "    out_color.z = atomicAdd(entry.z, -1);\n"
6397                                                 "    out_color.w = atomicAdd(entry.w, -1);\n"
6398                                                 "}\n"
6399                                                 "\n"
6400                                                 "subroutine uniform ssbo_routine routine;\n"
6401                                                 "\n"
6402                                                 "void main()\n"
6403                                                 "{\n"
6404                                                 "    routine();\n"
6405                                                 "}\n"
6406                                                 "\n";
6407 
6408     static const GLchar *geometry_shader_code = "#version 400 core\n"
6409                                                 "#extension GL_ARB_shader_subroutine : require\n"
6410                                                 "\n"
6411                                                 "precision highp float;\n"
6412                                                 "\n"
6413                                                 "layout(points)                           in;\n"
6414                                                 "layout(triangle_strip, max_vertices = 4) out;\n"
6415                                                 "\n"
6416                                                 "void main()\n"
6417                                                 "{\n"
6418                                                 "    gl_Position = vec4(-1, -1, 0, 1);\n"
6419                                                 "    EmitVertex();\n"
6420                                                 "    \n"
6421                                                 "    gl_Position = vec4(-1,  1, 0, 1);\n"
6422                                                 "    EmitVertex();\n"
6423                                                 "    \n"
6424                                                 "    gl_Position = vec4( 1, -1, 0, 1);\n"
6425                                                 "    EmitVertex();\n"
6426                                                 "    \n"
6427                                                 "    gl_Position = vec4( 1,  1, 0, 1);\n"
6428                                                 "    EmitVertex();\n"
6429                                                 "    \n"
6430                                                 "    EndPrimitive();\n"
6431                                                 "}\n"
6432                                                 "\n";
6433 
6434     static const GLchar *vertex_shader_code = "#version 400 core\n"
6435                                               "#extension GL_ARB_shader_subroutine : require\n"
6436                                               "\n"
6437                                               "precision highp float;\n"
6438                                               "\n"
6439                                               "void main()\n"
6440                                               "{\n"
6441                                               "}\n"
6442                                               "\n";
6443 
6444     static const GLchar *subroutine_names[] = {"increment", "decrement"};
6445 
6446     /* Test data */
6447     static const glw::GLuint buffer_data[] = {
6448         m_texture_width * m_texture_height + 1, m_texture_width * m_texture_height + 2,
6449         m_texture_width * m_texture_height + 3, m_texture_width * m_texture_height + 4};
6450 
6451     static const glw::GLuint expected_incremented[] = {
6452         m_texture_width * m_texture_height + buffer_data[0], m_texture_width * m_texture_height + buffer_data[1],
6453         m_texture_width * m_texture_height + buffer_data[2], m_texture_width * m_texture_height + buffer_data[3]};
6454 
6455     static const glw::GLuint expected_decremented[] = {buffer_data[0], buffer_data[1], buffer_data[2], buffer_data[3]};
6456 
6457     /* GL objects */
6458     Utils::buffer buffer(m_context);
6459     Utils::texture color_texture(m_context);
6460     Utils::framebuffer framebuffer(m_context);
6461     Utils::program program(m_context);
6462     Utils::vertexArray vao(m_context);
6463 
6464     /* Init GL objects */
6465     program.build(0 /* cs */, fragment_shader_code /* fs */, geometry_shader_code /* gs */, 0 /* tcs */, 0 /* test */,
6466                   vertex_shader_code, 0 /* varying_names */, 0 /* n_varyings */);
6467 
6468     program.use();
6469 
6470     vao.generate();
6471     vao.bind();
6472 
6473     color_texture.create(m_texture_width, m_texture_height, GL_RGBA32UI);
6474 
6475     buffer.generate();
6476     buffer.update(GL_SHADER_STORAGE_BUFFER, sizeof(buffer_data), (GLvoid *)buffer_data, GL_STATIC_DRAW);
6477     buffer.bindRange(GL_SHADER_STORAGE_BUFFER, 0 /* index */, 0 /* offset */, sizeof(buffer_data));
6478 
6479     framebuffer.generate();
6480     framebuffer.bind();
6481     framebuffer.attachTexture(GL_COLOR_ATTACHMENT0, color_texture.m_id, m_texture_width, m_texture_height);
6482     framebuffer.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
6483     framebuffer.clear(GL_COLOR_BUFFER_BIT);
6484 
6485     /* Subroutine indices */
6486     GLuint increment = program.getSubroutineIndex(subroutine_names[0], GL_FRAGMENT_SHADER);
6487     GLuint decrement = program.getSubroutineIndex(subroutine_names[1], GL_FRAGMENT_SHADER);
6488 
6489     /* Test */
6490     bool result = true;
6491 
6492     if (false == testSSBODraw(increment, expected_incremented))
6493     {
6494         result = false;
6495     }
6496 
6497     if (false == testSSBODraw(decrement, expected_decremented))
6498     {
6499         result = false;
6500     }
6501 
6502     /* Done */
6503     return result;
6504 }
6505 
6506 /** Execute draw call and verify results
6507  *
6508  * @param subroutine_index Index of subroutine that shall be used by draw call
6509  * @param expected_results Expected results
6510  *
6511  *
6512  **/
testSSBODraw(GLuint subroutine_index,const GLuint expected_results[4]) const6513 bool FunctionalTest12::testSSBODraw(GLuint subroutine_index, const GLuint expected_results[4]) const
6514 {
6515     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
6516 
6517     /* Set subroutine uniforms */
6518     gl.uniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &subroutine_index);
6519     GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
6520 
6521     /* Draw */
6522     gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
6523     GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
6524 
6525     /* Capture results */
6526     GLuint *ssbo_results = (GLuint *)gl.mapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
6527     GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
6528 
6529     /* Verify */
6530     bool result = (0 == memcmp(expected_results, ssbo_results, 4 * sizeof(GLuint)));
6531 
6532     if (false == result)
6533     {
6534         m_context.getTestContext().getLog()
6535             << tcu::TestLog::Message << "Error. Invalid result. "
6536             << "Result: [ " << ssbo_results[0] << ", " << ssbo_results[1] << ", " << ssbo_results[2] << ", "
6537             << ssbo_results[3] << " ] "
6538             << "Expected: [ " << expected_results[0] << ", " << expected_results[1] << ", " << expected_results[2]
6539             << ", " << expected_results[3] << " ]" << tcu::TestLog::EndMessage;
6540     }
6541 
6542     /* Unmap buffer */
6543     gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
6544     GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
6545 
6546     /* Done */
6547     return result;
6548 }
6549 
6550 /** Check if texture is filled with expected color
6551  *
6552  * @param texture        Texture instance
6553  * @param expected_color Expected color
6554  *
6555  * @return true if texture is filled with specified color, false otherwise
6556  **/
verifyTexture(Utils::texture & texture,const GLuint expected_color[4]) const6557 bool FunctionalTest12::verifyTexture(Utils::texture &texture, const GLuint expected_color[4]) const
6558 {
6559     std::vector<GLuint> results;
6560     results.resize(m_texture_width * m_texture_height * 4);
6561 
6562     texture.get(GL_RGBA_INTEGER, GL_UNSIGNED_INT, &results[0]);
6563 
6564     for (GLuint y = 0; y < m_texture_height; ++y)
6565     {
6566         const GLuint line_offset = y * m_texture_width * 4;
6567 
6568         for (GLuint x = 0; x < m_texture_width; ++x)
6569         {
6570             const GLuint point_offset = line_offset + x * 4;
6571             bool result               = true;
6572 
6573             result = result && (results[point_offset + 0] == expected_color[0]);
6574             result = result && (results[point_offset + 1] == expected_color[1]);
6575             result = result && (results[point_offset + 2] == expected_color[2]);
6576             result = result && (results[point_offset + 3] == expected_color[3]);
6577 
6578             if (false == result)
6579             {
6580                 return false;
6581             }
6582         }
6583     }
6584 
6585     return true;
6586 }
6587 
6588 /** Constructor.
6589  *
6590  *  @param context Rendering context.
6591  *
6592  **/
FunctionalTest13(deqp::Context & context)6593 FunctionalTest13::FunctionalTest13(deqp::Context &context)
6594     : TestCase(context, "subroutines_with_separate_shader_objects",
6595                "Verifies that subroutines work correctly when used in separate "
6596                "shader objects")
6597     , m_fbo_id(0)
6598     , m_pipeline_id(0)
6599     , m_read_buffer(DE_NULL)
6600     , m_to_height(4)
6601     , m_to_id(0)
6602     , m_to_width(4)
6603     , m_vao_id(0)
6604     , m_has_test_passed(true)
6605 {
6606     memset(m_fs_po_ids, 0, sizeof(m_fs_po_ids));
6607     memset(m_gs_po_ids, 0, sizeof(m_gs_po_ids));
6608     memset(m_tc_po_ids, 0, sizeof(m_tc_po_ids));
6609     memset(m_te_po_ids, 0, sizeof(m_te_po_ids));
6610     memset(m_vs_po_ids, 0, sizeof(m_vs_po_ids));
6611 }
6612 
6613 /** Deinitializes all GL objects that may have been created during test
6614  *  execution, as well as releases all process-side buffers that may have
6615  *  been allocated during the process.
6616  *  The function also restores default GL state configuration.
6617  **/
deinit()6618 void FunctionalTest13::deinit()
6619 {
6620     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
6621 
6622     if (m_fbo_id != 0)
6623     {
6624         gl.deleteFramebuffers(1, &m_fbo_id);
6625 
6626         m_fbo_id = 0;
6627     }
6628 
6629     if (m_pipeline_id != 0)
6630     {
6631         gl.deleteProgramPipelines(1, &m_pipeline_id);
6632 
6633         m_pipeline_id = 0;
6634     }
6635 
6636     if (m_read_buffer != DE_NULL)
6637     {
6638         delete[] m_read_buffer;
6639 
6640         m_read_buffer = DE_NULL;
6641     }
6642 
6643     for (unsigned int n_id = 0; n_id < 2 /* po id variants */; ++n_id)
6644     {
6645         if (m_fs_po_ids[n_id] != 0)
6646         {
6647             gl.deleteProgram(m_fs_po_ids[n_id]);
6648 
6649             m_fs_po_ids[n_id] = 0;
6650         }
6651 
6652         if (m_gs_po_ids[n_id] != 0)
6653         {
6654             gl.deleteProgram(m_gs_po_ids[n_id]);
6655 
6656             m_gs_po_ids[n_id] = 0;
6657         }
6658 
6659         if (m_tc_po_ids[n_id] != 0)
6660         {
6661             gl.deleteProgram(m_tc_po_ids[n_id]);
6662 
6663             m_tc_po_ids[n_id] = 0;
6664         }
6665 
6666         if (m_te_po_ids[n_id] != 0)
6667         {
6668             gl.deleteProgram(m_te_po_ids[n_id]);
6669 
6670             m_te_po_ids[n_id] = 0;
6671         }
6672 
6673         if (m_vs_po_ids[n_id] != 0)
6674         {
6675             gl.deleteProgram(m_vs_po_ids[n_id]);
6676 
6677             m_vs_po_ids[n_id] = 0;
6678         }
6679     } /* for (both shader program object variants) */
6680 
6681     if (m_to_id != 0)
6682     {
6683         gl.deleteTextures(1, &m_to_id);
6684 
6685         m_to_id = 0;
6686     }
6687 
6688     if (m_vao_id != 0)
6689     {
6690         gl.deleteVertexArrays(1, &m_vao_id);
6691 
6692         m_vao_id = 0;
6693     }
6694 
6695     /* Restore default GL_PATCH_VERTICES setting value */
6696     gl.patchParameteri(GL_PATCH_VERTICES, 3);
6697 
6698     /* Restore default GL_PACK_ALIGNMENT setting value */
6699     gl.pixelStorei(GL_PACK_ALIGNMENT, 4);
6700 }
6701 
6702 /** Retrieves body of a fragment shader that should be used for the test.
6703  *  The subroutine implementations are slightly changed, depending on the
6704  *  index of the shader, as specified by the caller.
6705  *
6706  *  @param n_id Index of the shader.
6707  *
6708  *  @return Requested string.
6709  **/
getFragmentShaderBody(unsigned int n_id)6710 std::string FunctionalTest13::getFragmentShaderBody(unsigned int n_id)
6711 {
6712     std::stringstream result_sstream;
6713 
6714     /* Pre-amble */
6715     result_sstream << "#version 400\n"
6716                       "\n"
6717                       "#extension GL_ARB_shader_subroutine : require\n"
6718                       "\n"
6719                       /* Sub-routine */
6720                       "subroutine void SubroutineFSType(inout vec4 result);\n"
6721                       "\n"
6722                       "subroutine(SubroutineFSType) void SubroutineFS1(inout vec4 result)\n"
6723                       "{\n"
6724                       "    result += vec4("
6725                    << float(n_id + 1) / 10.0f << ", " << float(n_id + 2) / 10.0f << ", " << float(n_id + 3) / 10.0f
6726                    << ", " << float(n_id + 4) / 10.0f
6727                    << ");\n"
6728                       "}\n"
6729                       "subroutine(SubroutineFSType) void SubroutineFS2(inout vec4 result)\n"
6730                       "{\n"
6731                       "    result += vec4("
6732                    << float(n_id + 1) / 20.0f << ", " << float(n_id + 2) / 20.0f << ", " << float(n_id + 3) / 20.0f
6733                    << ", " << float(n_id + 4) / 20.0f
6734                    << ");\n"
6735                       "}\n"
6736                       "\n"
6737                       "subroutine uniform SubroutineFSType function;\n"
6738                       "\n"
6739                       /* Input block */
6740                       "in GS_DATA\n"
6741                       "{\n"
6742                       "    vec4 data;\n"
6743                       "} in_gs;\n"
6744                       "\n"
6745                       "out vec4 result;\n"
6746                       /* main() declaration */
6747                       "void main()\n"
6748                       "{\n"
6749                       "    vec4 data = in_gs.data;\n"
6750                       "    function(data);\n"
6751                       "\n"
6752                       "    result = data;\n"
6753                       "}\n";
6754 
6755     return result_sstream.str();
6756 }
6757 
6758 /** Retrieves body of a geometry shader that should be used for the test.
6759  *  The subroutine implementations are slightly changed, depending on the
6760  *  index of the shader, as specified by the caller.
6761  *
6762  *  @param n_id Index of the shader.
6763  *
6764  *  @return Requested string.
6765  **/
getGeometryShaderBody(unsigned int n_id)6766 std::string FunctionalTest13::getGeometryShaderBody(unsigned int n_id)
6767 {
6768     std::stringstream result_sstream;
6769 
6770     /* Pre-amble */
6771     result_sstream << "#version 400\n"
6772                       "\n"
6773                       "#extension GL_ARB_shader_subroutine : require\n"
6774                       "\n"
6775                       "layout(points)                           in;\n"
6776                       "layout(triangle_strip, max_vertices = 4) out;\n"
6777                       /* Sub-routine */
6778                       "subroutine void SubroutineGSType(inout vec4 result);\n"
6779                       "\n"
6780                       "subroutine(SubroutineGSType) void SubroutineGS1(inout vec4 result)\n"
6781                       "{\n"
6782                       "    result += vec4(0, 0, 0, "
6783                    << float(n_id + 1) * 0.425f
6784                    << ");\n"
6785                       "}\n"
6786                       "subroutine(SubroutineGSType) void SubroutineGS2(inout vec4 result)\n"
6787                       "{\n"
6788                       "    result += vec4(0, 0, 0, "
6789                    << float(n_id + 1) * 0.0425f
6790                    << ");\n"
6791                       "}\n"
6792                       "\n"
6793                       "subroutine uniform SubroutineGSType function;\n"
6794                       "\n"
6795                       /* Input block */
6796                       "in TE_DATA\n"
6797                       "{\n"
6798                       "    vec4 data;\n"
6799                       "} in_te[];\n"
6800                       "\n"
6801                       /* Output block */
6802                       "out GS_DATA\n"
6803                       "{\n"
6804                       "    vec4 data;\n"
6805                       "} out_gs;\n"
6806                       "\n"
6807                       "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n"
6808                       "out gl_PerVertex { vec4 gl_Position; };\n"
6809                       /* main() declaration */
6810                       "void main()\n"
6811                       "{\n"
6812                       "    vec4 data = in_te[0].data;\n"
6813                       "\n"
6814                       "    function(data);\n"
6815                       "\n"
6816                       "    gl_Position = vec4(1, -1, 0, 1);\n"
6817                       "    out_gs.data = data;\n"
6818                       "    EmitVertex();\n"
6819                       "\n"
6820                       "    gl_Position = vec4(-1, -1, 0, 1);\n"
6821                       "    out_gs.data = data;\n"
6822                       "    EmitVertex();\n"
6823                       "\n"
6824                       "    gl_Position = vec4(1, 1, 0, 1);\n"
6825                       "    out_gs.data = data;\n"
6826                       "    EmitVertex();\n"
6827                       "\n"
6828                       "    gl_Position = vec4(-1, 1, 0, 1);\n"
6829                       "    out_gs.data = data;\n"
6830                       "    EmitVertex();\n"
6831                       "    EndPrimitive();\n"
6832                       "}\n";
6833 
6834     return result_sstream.str();
6835 }
6836 
6837 /** Retrieves body of a tessellation control shader that should be used for the test.
6838  *  The subroutine implementations are slightly changed, depending on the
6839  *  index of the shader, as specified by the caller.
6840  *
6841  *  @param n_id Index of the shader.
6842  *
6843  *  @return Requested string.
6844  **/
getTessellationControlShaderBody(unsigned int n_id)6845 std::string FunctionalTest13::getTessellationControlShaderBody(unsigned int n_id)
6846 {
6847     std::stringstream result_sstream;
6848 
6849     /* Pre-amble */
6850     result_sstream << "#version 400\n"
6851                       "\n"
6852                       "#extension GL_ARB_shader_subroutine : require\n"
6853                       "\n"
6854                       "layout(vertices = 4) out;\n"
6855                       /* Sub-routine */
6856                       "subroutine void SubroutineTCType(inout vec4 result);\n"
6857                       "\n"
6858                       "subroutine(SubroutineTCType) void SubroutineTC1(inout vec4 result)\n"
6859                       "{\n"
6860                       "    result += vec4(0, "
6861                    << float(n_id + 1) * 0.25f
6862                    << ", 0, 0);\n"
6863                       "}\n"
6864                       "subroutine(SubroutineTCType) void SubroutineTC2(inout vec4 result)\n"
6865                       "{\n"
6866                       "    result += vec4(0, "
6867                    << float(n_id + 1) * 0.025f
6868                    << ", 0, 0);\n"
6869                       "}\n"
6870                       "\n"
6871                       "subroutine uniform SubroutineTCType function;\n"
6872                       "\n"
6873                       /* Input block */
6874                       "in VS_DATA\n"
6875                       "{\n"
6876                       "    vec4 data;\n"
6877                       "} in_vs[];\n"
6878                       "\n"
6879                       /* Output block */
6880                       "out TC_DATA\n"
6881                       "{\n"
6882                       "    vec4 data;\n"
6883                       "} out_tc[];\n"
6884                       "\n"
6885                       "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n"
6886                       "out gl_PerVertex { vec4 gl_Position; } gl_out[];\n"
6887                       /* main() declaration */
6888                       "void main()\n"
6889                       "{\n"
6890                       "    gl_TessLevelOuter[0]                = 1.0;\n"
6891                       "    gl_TessLevelOuter[1]                = 1.0;\n"
6892                       "    gl_TessLevelOuter[2]                = 1.0;\n"
6893                       "    gl_TessLevelOuter[3]                = 1.0;\n"
6894                       "    gl_TessLevelInner[0]                = 1.0;\n"
6895                       "    gl_TessLevelInner[1]                = 1.0;\n"
6896                       "    gl_out[gl_InvocationID].gl_Position = gl_in[0].gl_Position;\n"
6897                       "    out_tc[gl_InvocationID].data        = in_vs[0].data;\n"
6898                       "\n"
6899                       "    function(out_tc[gl_InvocationID].data);\n"
6900                       "}\n";
6901 
6902     return result_sstream.str();
6903 }
6904 
6905 /** Retrieves body of a tessellation evaluation shader that should be used for the test.
6906  *  The subroutine implementations are slightly changed, depending on the
6907  *  index of the shader, as specified by the caller.
6908  *
6909  *  @param n_id Index of the shader.
6910  *
6911  *  @return Requested string.
6912  **/
getTessellationEvaluationShaderBody(unsigned int n_id)6913 std::string FunctionalTest13::getTessellationEvaluationShaderBody(unsigned int n_id)
6914 {
6915     std::stringstream result_sstream;
6916 
6917     /* Pre-amble */
6918     result_sstream << "#version 400\n"
6919                       "\n"
6920                       "#extension GL_ARB_shader_subroutine : require\n"
6921                       "\n"
6922                       "layout(quads, point_mode) in;\n"
6923                       /* Sub-routine */
6924                       "subroutine void SubroutineTEType(inout vec4 result);\n"
6925                       "\n"
6926                       "subroutine(SubroutineTEType) void SubroutineTE1(inout vec4 result)\n"
6927                       "{\n"
6928                       "    result += vec4(0, 0, "
6929                    << float(n_id + 1) * 0.325f
6930                    << ", 0);\n"
6931                       "}\n"
6932                       "subroutine(SubroutineTEType) void SubroutineTE2(inout vec4 result)\n"
6933                       "{\n"
6934                       "    result += vec4(0, 0, "
6935                    << float(n_id + 1) * 0.0325f
6936                    << ", 0);\n"
6937                       "}\n"
6938                       "\n"
6939                       "subroutine uniform SubroutineTEType function;\n"
6940                       "\n"
6941                       /* Input block */
6942                       "in TC_DATA\n"
6943                       "{\n"
6944                       "    vec4 data;\n"
6945                       "} in_tc[];\n"
6946                       "\n"
6947                       /* Output block */
6948                       "out TE_DATA\n"
6949                       "{\n"
6950                       "    vec4 data;\n"
6951                       "} out_te;\n"
6952                       "\n"
6953                       "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n"
6954                       "out gl_PerVertex { vec4 gl_Position; };\n"
6955                       /* main() declaration */
6956                       "void main()\n"
6957                       "{\n"
6958                       "    gl_Position = gl_in[0].gl_Position;\n"
6959                       "    out_te.data = in_tc[0].data;\n"
6960                       "\n"
6961                       "    function(out_te.data);\n"
6962                       "}\n";
6963 
6964     return result_sstream.str();
6965 }
6966 
6967 /** Retrieves body of a vertex shader that should be used for the test.
6968  *  The subroutine implementations are slightly changed, depending on the
6969  *  index of the shader, as specified by the caller.
6970  *
6971  *  @param n_id Index of the shader.
6972  *
6973  *  @return Requested string.
6974  **/
getVertexShaderBody(unsigned int n_id)6975 std::string FunctionalTest13::getVertexShaderBody(unsigned int n_id)
6976 {
6977     std::stringstream result_sstream;
6978 
6979     /* Pre-amble */
6980     result_sstream << "#version 400\n"
6981                       "\n"
6982                       "#extension GL_ARB_shader_subroutine : require\n"
6983                       "#extension GL_ARB_separate_shader_objects: require\n"
6984                       "\n"
6985                       /* Sub-routine */
6986                       "subroutine void SubroutineVSType(inout vec4 result);\n"
6987                       "\n"
6988                       "subroutine(SubroutineVSType) void SubroutineVS1(inout vec4 result)\n"
6989                       "{\n"
6990                       "    result += vec4("
6991                    << float(n_id + 1) * 0.125f
6992                    << ", 0, 0, 0);\n"
6993                       "}\n"
6994                       "subroutine(SubroutineVSType) void SubroutineVS2(inout vec4 result)\n"
6995                       "{\n"
6996                       "    result += vec4("
6997                    << float(n_id + 1) * 0.0125f
6998                    << ", 0, 0, 0);\n"
6999                       "}\n"
7000                       "\n"
7001                       "subroutine uniform SubroutineVSType function;\n"
7002                       "\n"
7003                       /* Output block */
7004                       "out VS_DATA\n"
7005                       "{\n"
7006                       "    vec4 data;\n"
7007                       "} out_vs;\n"
7008                       "\n"
7009                       "out gl_PerVertex { vec4 gl_Position; };\n"
7010                       /* main() declaration */
7011                       "void main()\n"
7012                       "{\n"
7013                       "    gl_Position = vec4(0, 0, 0, 1);\n"
7014                       "    out_vs.data = vec4(0);\n"
7015                       "\n"
7016                       "    function(out_vs.data);\n"
7017                       "\n"
7018                       "}\n";
7019 
7020     return result_sstream.str();
7021 }
7022 
7023 /** Initializes all GL objects required to run the test. Also modifies a few
7024  *  GL states in order for the test to run correctly.
7025  **/
initTest()7026 void FunctionalTest13::initTest()
7027 {
7028     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
7029 
7030     /* Set up viewport */
7031     gl.viewport(0 /* x */, 0 /* y */, m_to_width, m_to_height);
7032     GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed.");
7033 
7034     /* Make sure no program is used */
7035     gl.useProgram(0);
7036     GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
7037 
7038     /* Generate a pipeline object */
7039     gl.genProgramPipelines(1, &m_pipeline_id);
7040     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() call failed.");
7041 
7042     gl.bindProgramPipeline(m_pipeline_id);
7043     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
7044 
7045     /* Initialize all shader programs */
7046     for (unsigned int n_id = 0; n_id < 2 /* variants for each shader type */; ++n_id)
7047     {
7048         std::string fs_body         = getFragmentShaderBody(n_id);
7049         const char *fs_body_raw_ptr = fs_body.c_str();
7050         std::string gs_body         = getGeometryShaderBody(n_id);
7051         const char *gs_body_raw_ptr = gs_body.c_str();
7052         std::string tc_body         = getTessellationControlShaderBody(n_id);
7053         const char *tc_body_raw_ptr = tc_body.c_str();
7054         std::string te_body         = getTessellationEvaluationShaderBody(n_id);
7055         const char *te_body_raw_ptr = te_body.c_str();
7056         std::string vs_body         = getVertexShaderBody(n_id);
7057         const char *vs_body_raw_ptr = vs_body.c_str();
7058 
7059         m_fs_po_ids[n_id] = gl.createShaderProgramv(GL_FRAGMENT_SHADER, 1 /* count */, &fs_body_raw_ptr);
7060         GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
7061 
7062         m_gs_po_ids[n_id] = gl.createShaderProgramv(GL_GEOMETRY_SHADER, 1 /* count */, &gs_body_raw_ptr);
7063         GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
7064 
7065         m_tc_po_ids[n_id] = gl.createShaderProgramv(GL_TESS_CONTROL_SHADER, 1 /* count */, &tc_body_raw_ptr);
7066         GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
7067 
7068         m_te_po_ids[n_id] = gl.createShaderProgramv(GL_TESS_EVALUATION_SHADER, 1 /* count */, &te_body_raw_ptr);
7069         GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
7070 
7071         m_vs_po_ids[n_id] = gl.createShaderProgramv(GL_VERTEX_SHADER, 1 /* count */, &vs_body_raw_ptr);
7072         GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
7073 
7074         /* Verify that all shader program objects have been linked successfully */
7075         const glw::GLuint po_ids[] = {
7076             m_fs_po_ids[n_id], m_gs_po_ids[n_id], m_tc_po_ids[n_id], m_te_po_ids[n_id], m_vs_po_ids[n_id],
7077         };
7078         const unsigned int n_po_ids = sizeof(po_ids) / sizeof(po_ids[0]);
7079 
7080         for (unsigned int n_po_id = 0; n_po_id < n_po_ids; ++n_po_id)
7081         {
7082             glw::GLint link_status = GL_FALSE;
7083             glw::GLuint po_id      = po_ids[n_po_id];
7084 
7085             gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status);
7086             GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
7087 
7088             if (link_status != GL_TRUE)
7089             {
7090                 TCU_FAIL("Shader program object linking failed.");
7091             }
7092         } /* for (all shader program objects) */
7093     }     /* for (both shader program object variants) */
7094 
7095     /* Generate a texture object. We will use the base mip-map as a render-target */
7096     gl.genTextures(1, &m_to_id);
7097     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed.");
7098 
7099     gl.bindTexture(GL_TEXTURE_2D, m_to_id);
7100     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
7101 
7102     gl.texStorage2D(GL_TEXTURE_2D, 1 /* levels */, GL_RGBA32F, m_to_width, m_to_height);
7103     GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed");
7104 
7105     /* Generate and configure a FBO we will use for the draw call */
7106     gl.genFramebuffers(1, &m_fbo_id);
7107     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed.");
7108 
7109     gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
7110     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed.");
7111 
7112     gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0 /* level */);
7113     GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
7114 
7115     /* Generate & bind a VAO */
7116     gl.genVertexArrays(1, &m_vao_id);
7117     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
7118 
7119     gl.bindVertexArray(m_vao_id);
7120     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
7121 
7122     /* Set up tessellation */
7123     gl.patchParameteri(GL_PATCH_VERTICES, 1);
7124     GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteri() call failed.");
7125 
7126     /* Set up pixel storage alignment */
7127     gl.pixelStorei(GL_PACK_ALIGNMENT, 1);
7128     GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call failed.");
7129 
7130     /* Allocate enough space to hold color attachment data */
7131     m_read_buffer = (unsigned char *)new float[m_to_width * m_to_height * 4 /* rgba */];
7132 }
7133 
7134 /** Executes test iteration.
7135  *
7136  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
7137  */
iterate()7138 tcu::TestNode::IterateResult FunctionalTest13::iterate()
7139 {
7140     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
7141 
7142     /* Do not execute the test if GL_ARB_shader_subroutine and GL_ARB_separate_shader_objects
7143      * are not supported */
7144     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
7145     {
7146         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
7147     }
7148 
7149     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_separate_shader_objects"))
7150     {
7151         throw tcu::NotSupportedError("GL_ARB_separate_shader_objects is not supported");
7152     }
7153 
7154     /* Initialize all GL objects before we continue */
7155     initTest();
7156 
7157     /* Iterate over all possible FS/GS/TC/TE/VS permutations */
7158     for (int n_shader_permutation = 0; n_shader_permutation < 32 /* 2^5 */; ++n_shader_permutation)
7159     {
7160         const unsigned int n_fs_idx = ((n_shader_permutation & (1 << 0)) != 0) ? 1 : 0;
7161         const unsigned int n_gs_idx = ((n_shader_permutation & (1 << 1)) != 0) ? 1 : 0;
7162         const unsigned int n_tc_idx = ((n_shader_permutation & (1 << 2)) != 0) ? 1 : 0;
7163         const unsigned int n_te_idx = ((n_shader_permutation & (1 << 3)) != 0) ? 1 : 0;
7164         const unsigned int n_vs_idx = ((n_shader_permutation & (1 << 4)) != 0) ? 1 : 0;
7165         const unsigned int fs_po_id = m_fs_po_ids[n_fs_idx];
7166         const unsigned int gs_po_id = m_gs_po_ids[n_gs_idx];
7167         const unsigned int tc_po_id = m_tc_po_ids[n_tc_idx];
7168         const unsigned int te_po_id = m_te_po_ids[n_te_idx];
7169         const unsigned int vs_po_id = m_vs_po_ids[n_vs_idx];
7170 
7171         /* Configure fragment shader stage */
7172         gl.useProgramStages(m_pipeline_id, GL_FRAGMENT_SHADER_BIT, fs_po_id);
7173         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed for GL_FRAGMENT_SHADER_BIT bit");
7174 
7175         /* Configure geometry shader stage */
7176         gl.useProgramStages(m_pipeline_id, GL_GEOMETRY_SHADER_BIT, gs_po_id);
7177         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed for GL_GEOMETRY_SHADER_BIT bit");
7178 
7179         /* Configure tessellation control shader stage */
7180         gl.useProgramStages(m_pipeline_id, GL_TESS_CONTROL_SHADER_BIT, tc_po_id);
7181         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed for GL_TESS_CONTROL_SHADER_BIT bit");
7182 
7183         /* Configure tessellation evaluation shader stage */
7184         gl.useProgramStages(m_pipeline_id, GL_TESS_EVALUATION_SHADER_BIT, te_po_id);
7185         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed for GL_TESS_EVALUATION_SHADER_BIT bit");
7186 
7187         /* Configure vertex shader stage */
7188         gl.useProgramStages(m_pipeline_id, GL_VERTEX_SHADER_BIT, vs_po_id);
7189         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed for GL_VERTEX_SHADER_BIT bit");
7190 
7191         /* Validate the pipeline */
7192         glw::GLint validate_status = GL_FALSE;
7193 
7194         gl.validateProgramPipeline(m_pipeline_id);
7195         GLU_EXPECT_NO_ERROR(gl.getError(), "glValidateProgramPipeline() call failed.");
7196 
7197         gl.getProgramPipelineiv(m_pipeline_id, GL_VALIDATE_STATUS, &validate_status);
7198         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramPipelineiv() call failed.");
7199 
7200         if (validate_status != GL_TRUE)
7201         {
7202             TCU_FAIL("Program pipeline has not been validated successfully.");
7203         }
7204 
7205         /* Retrieve subroutine indices */
7206         GLuint fs_subroutine_indices[2]   = {(GLuint)-1};
7207         GLint fs_subroutine_uniform_index = 0;
7208         GLuint gs_subroutine_indices[2]   = {(GLuint)-1};
7209         GLint gs_subroutine_uniform_index = 0;
7210         GLuint tc_subroutine_indices[2]   = {(GLuint)-1};
7211         GLint tc_subroutine_uniform_index = 0;
7212         GLuint te_subroutine_indices[2]   = {(GLuint)-1};
7213         GLint te_subroutine_uniform_index = 0;
7214         GLuint vs_subroutine_indices[2]   = {(GLuint)-1};
7215         GLint vs_subroutine_uniform_index = 0;
7216 
7217         for (unsigned int n_subroutine = 0; n_subroutine < 2; ++n_subroutine)
7218         {
7219             std::stringstream fs_subroutine_name_sstream;
7220             std::stringstream gs_subroutine_name_sstream;
7221             std::stringstream tc_subroutine_name_sstream;
7222             std::stringstream te_subroutine_name_sstream;
7223             std::stringstream vs_subroutine_name_sstream;
7224 
7225             fs_subroutine_name_sstream << "SubroutineFS" << (n_subroutine + 1);
7226             gs_subroutine_name_sstream << "SubroutineGS" << (n_subroutine + 1);
7227             tc_subroutine_name_sstream << "SubroutineTC" << (n_subroutine + 1);
7228             te_subroutine_name_sstream << "SubroutineTE" << (n_subroutine + 1);
7229             vs_subroutine_name_sstream << "SubroutineVS" << (n_subroutine + 1);
7230 
7231             fs_subroutine_indices[n_subroutine] =
7232                 gl.getSubroutineIndex(fs_po_id, GL_FRAGMENT_SHADER, fs_subroutine_name_sstream.str().c_str());
7233             gs_subroutine_indices[n_subroutine] =
7234                 gl.getSubroutineIndex(gs_po_id, GL_GEOMETRY_SHADER, gs_subroutine_name_sstream.str().c_str());
7235             tc_subroutine_indices[n_subroutine] =
7236                 gl.getSubroutineIndex(tc_po_id, GL_TESS_CONTROL_SHADER, tc_subroutine_name_sstream.str().c_str());
7237             te_subroutine_indices[n_subroutine] =
7238                 gl.getSubroutineIndex(te_po_id, GL_TESS_EVALUATION_SHADER, te_subroutine_name_sstream.str().c_str());
7239             vs_subroutine_indices[n_subroutine] =
7240                 gl.getSubroutineIndex(vs_po_id, GL_VERTEX_SHADER, vs_subroutine_name_sstream.str().c_str());
7241             GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineIndex() call(s) failed.");
7242 
7243             if (fs_subroutine_indices[n_subroutine] == (GLuint)-1 ||
7244                 gs_subroutine_indices[n_subroutine] == (GLuint)-1 ||
7245                 tc_subroutine_indices[n_subroutine] == (GLuint)-1 ||
7246                 te_subroutine_indices[n_subroutine] == (GLuint)-1 || vs_subroutine_indices[n_subroutine] == (GLuint)-1)
7247             {
7248                 m_testCtx.getLog() << tcu::TestLog::Message
7249                                    << "At least one subroutine was not recognized by glGetSubroutineIndex() call. "
7250                                       "(fs:"
7251                                    << fs_subroutine_indices[n_subroutine]
7252                                    << ", gs:" << gs_subroutine_indices[n_subroutine]
7253                                    << ", tc:" << tc_subroutine_indices[n_subroutine]
7254                                    << ", te:" << te_subroutine_indices[n_subroutine]
7255                                    << ", vs:" << vs_subroutine_indices[n_subroutine] << ")."
7256                                    << tcu::TestLog::EndMessage;
7257 
7258                 TCU_FAIL("At least one subroutine was not recognized");
7259             }
7260         } /* for (both subroutines) */
7261 
7262         /* Retrieve subroutine uniform indices */
7263         fs_subroutine_uniform_index = gl.getSubroutineUniformLocation(fs_po_id, GL_FRAGMENT_SHADER, "function");
7264         gs_subroutine_uniform_index = gl.getSubroutineUniformLocation(gs_po_id, GL_GEOMETRY_SHADER, "function");
7265         tc_subroutine_uniform_index = gl.getSubroutineUniformLocation(tc_po_id, GL_TESS_CONTROL_SHADER, "function");
7266         te_subroutine_uniform_index = gl.getSubroutineUniformLocation(te_po_id, GL_TESS_EVALUATION_SHADER, "function");
7267         vs_subroutine_uniform_index = gl.getSubroutineUniformLocation(vs_po_id, GL_VERTEX_SHADER, "function");
7268 
7269         if (fs_subroutine_uniform_index == -1 || gs_subroutine_uniform_index == -1 ||
7270             tc_subroutine_uniform_index == -1 || te_subroutine_uniform_index == -1 || vs_subroutine_uniform_index == -1)
7271         {
7272             m_testCtx.getLog() << tcu::TestLog::Message
7273                                << "At least one subroutine uniform is considered inactive by "
7274                                   "glGetSubroutineUniformLocation ("
7275                                   "fs:"
7276                                << fs_subroutine_uniform_index << ", gs:" << gs_subroutine_uniform_index
7277                                << ", tc:" << tc_subroutine_uniform_index << ", te:" << te_subroutine_uniform_index
7278                                << ", vs:" << vs_subroutine_uniform_index << ")." << tcu::TestLog::EndMessage;
7279 
7280             TCU_FAIL("At least one subroutine uniform is considered inactive");
7281         }
7282 
7283         /* Check if both subroutines work correctly in each stage */
7284         for (int n_subroutine_permutation = 0; n_subroutine_permutation < 32; /* 2^5 */
7285              ++n_subroutine_permutation)
7286         {
7287             unsigned int n_fs_subroutine = ((n_subroutine_permutation & (1 << 0)) != 0) ? 1 : 0;
7288             unsigned int n_gs_subroutine = ((n_subroutine_permutation & (1 << 1)) != 0) ? 1 : 0;
7289             unsigned int n_tc_subroutine = ((n_subroutine_permutation & (1 << 2)) != 0) ? 1 : 0;
7290             unsigned int n_te_subroutine = ((n_subroutine_permutation & (1 << 3)) != 0) ? 1 : 0;
7291             unsigned int n_vs_subroutine = ((n_subroutine_permutation & (1 << 4)) != 0) ? 1 : 0;
7292 
7293             /* Configure subroutine uniforms */
7294             struct
7295             {
7296                 glw::GLenum stage;
7297                 glw::GLuint po_id;
7298                 glw::GLuint *indices;
7299             } configurations[] = {
7300                 {GL_FRAGMENT_SHADER, fs_po_id, fs_subroutine_indices + n_fs_subroutine},
7301                 {GL_GEOMETRY_SHADER, gs_po_id, gs_subroutine_indices + n_gs_subroutine},
7302                 {GL_TESS_CONTROL_SHADER, tc_po_id, tc_subroutine_indices + n_tc_subroutine},
7303                 {GL_TESS_EVALUATION_SHADER, te_po_id, te_subroutine_indices + n_te_subroutine},
7304                 {GL_VERTEX_SHADER, vs_po_id, vs_subroutine_indices + n_vs_subroutine},
7305             };
7306 
7307             for (int i = 0; i < 5; ++i)
7308             {
7309                 gl.activeShaderProgram(m_pipeline_id, configurations[i].po_id);
7310                 GLU_EXPECT_NO_ERROR(gl.getError(), "glActiveShaderProgram() call failed.");
7311 
7312                 gl.uniformSubroutinesuiv(configurations[i].stage, 1 /* count */, configurations[i].indices);
7313                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniformSubroutinesuiv() call failed.");
7314             }
7315 
7316             /* Render a full-screen quad with the pipeline */
7317             gl.clear(GL_COLOR_BUFFER_BIT);
7318             GLU_EXPECT_NO_ERROR(gl.getError(), "glClear() call failed.");
7319 
7320             gl.drawArrays(GL_PATCHES, 0 /* first */, 1 /* count */);
7321             GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
7322 
7323             /* Read color attachment's contents */
7324             gl.readPixels(0, /* x */
7325                           0, /* y */
7326                           m_to_width, m_to_height, GL_RGBA, GL_FLOAT, m_read_buffer);
7327             GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed.");
7328 
7329             /* Verify the contents */
7330             verifyReadBuffer(n_fs_idx, n_fs_subroutine, n_gs_idx, n_gs_subroutine, n_tc_idx, n_tc_subroutine, n_te_idx,
7331                              n_te_subroutine, n_vs_idx, n_vs_subroutine);
7332         } /* for (all subroutine permutations) */
7333     }     /* for (all program shader object permutations) */
7334 
7335     /** All done */
7336     if (m_has_test_passed)
7337     {
7338         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
7339     }
7340     else
7341     {
7342         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
7343     }
7344 
7345     return STOP;
7346 }
7347 
7348 /** Verifies the data that have been rendered using a pipeline object.
7349  *  Contents of the data depends on indices of the shaders, as well as
7350  *  on the subroutines that have been activated for particular iteration.
7351  *
7352  *  @param n_fs_id         Index of the fragment shader used for the iteration;
7353  *  @param n_fs_subroutine Index of the subroutine used in the fragment shader
7354  *                         for the iteration;
7355  *  @param n_gs_id         Index of the geometry shader used for the iteration;
7356  *  @param n_gs_subroutine Index of the subroutine used in the geometry shader
7357  *                         for the iteration;
7358  *  @param n_tc_id         Index of the tessellation control shader used for the iteration;
7359  *  @param n_tc_subroutine Index of the subroutine used in the tessellation control
7360  *                         shader for the iteration;
7361  *  @param n_te_id         Index of the tessellation evaluation shader used for the iteration;
7362  *  @param n_te_subroutine Index of the subroutine used in the tessellation evaluation
7363  *                         shader for the iteration;
7364  *  @param n_vs_id         Index of the vertex shader used for the iteration;
7365  *  @param n_vs_subroutine Index of the subroutine used in the vertex shader for
7366  *                         the iteration.
7367  */
verifyReadBuffer(unsigned int n_fs_id,unsigned int n_fs_subroutine,unsigned int n_gs_id,unsigned int n_gs_subroutine,unsigned int n_tc_id,unsigned int n_tc_subroutine,unsigned int n_te_id,unsigned int n_te_subroutine,unsigned int n_vs_id,unsigned int n_vs_subroutine)7368 void FunctionalTest13::verifyReadBuffer(unsigned int n_fs_id, unsigned int n_fs_subroutine, unsigned int n_gs_id,
7369                                         unsigned int n_gs_subroutine, unsigned int n_tc_id,
7370                                         unsigned int n_tc_subroutine, unsigned int n_te_id,
7371                                         unsigned int n_te_subroutine, unsigned int n_vs_id,
7372                                         unsigned int n_vs_subroutine)
7373 {
7374     float expected_color[4] = {0};
7375     float fs_modifier[4]    = {0};
7376     float gs_modifier[4]    = {0};
7377     float tc_modifier[4]    = {0};
7378     float te_modifier[4]    = {0};
7379     float vs_modifier[4]    = {0};
7380 
7381     if (n_fs_subroutine == 0)
7382     {
7383         for (unsigned int n_component = 0; n_component < 4; ++n_component)
7384         {
7385             fs_modifier[n_component] = float(n_fs_id + n_component + 1) / 10.0f;
7386         }
7387     }
7388     else
7389     {
7390         for (unsigned int n_component = 0; n_component < 4; ++n_component)
7391         {
7392             fs_modifier[n_component] = float(n_fs_id + n_component + 1) / 20.0f;
7393         }
7394     }
7395 
7396     if (n_gs_subroutine == 0)
7397     {
7398         gs_modifier[3] = float(n_gs_id + 1) * 0.425f;
7399     }
7400     else
7401     {
7402         gs_modifier[3] = float(n_gs_id + 1) * 0.0425f;
7403     }
7404 
7405     if (n_tc_subroutine == 0)
7406     {
7407         tc_modifier[1] = float(n_tc_id + 1) * 0.25f;
7408     }
7409     else
7410     {
7411         tc_modifier[1] = float(n_tc_id + 1) * 0.025f;
7412     }
7413 
7414     if (n_te_subroutine == 0)
7415     {
7416         te_modifier[2] = float(n_te_id + 1) * 0.325f;
7417     }
7418     else
7419     {
7420         te_modifier[2] = float(n_te_id + 1) * 0.0325f;
7421     }
7422 
7423     if (n_vs_subroutine == 0)
7424     {
7425         vs_modifier[0] = float(n_vs_id + 1) * 0.125f;
7426     }
7427     else
7428     {
7429         vs_modifier[0] = float(n_vs_id + 1) * 0.0125f;
7430     }
7431 
7432     /* Determine the expected color */
7433     for (unsigned int n_component = 0; n_component < 4 /* rgba */; ++n_component)
7434     {
7435         expected_color[n_component] = fs_modifier[n_component] + gs_modifier[n_component] + tc_modifier[n_component] +
7436                                       te_modifier[n_component] + vs_modifier[n_component];
7437     }
7438 
7439     /* Verify all read texels are valid */
7440     const float epsilon  = 1e-5f;
7441     bool should_continue = true;
7442 
7443     for (unsigned int y = 0; y < m_to_height && should_continue; ++y)
7444     {
7445         const float *row_ptr = (const float *)m_read_buffer + y * m_to_width * 4; /* rgba */
7446 
7447         for (unsigned int x = 0; x < m_to_width && should_continue; ++x)
7448         {
7449             const float *texel_ptr = row_ptr + x * 4; /* rgba */
7450 
7451             if (de::abs(texel_ptr[0] - expected_color[0]) > epsilon ||
7452                 de::abs(texel_ptr[1] - expected_color[1]) > epsilon ||
7453                 de::abs(texel_ptr[2] - expected_color[2]) > epsilon ||
7454                 de::abs(texel_ptr[3] - expected_color[3]) > epsilon)
7455             {
7456                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid texel rendered at (" << x << ", " << y
7457                                    << ") for "
7458                                       "the following configuration: "
7459                                       "n_fs_id:"
7460                                    << n_fs_id << " n_fs_subroutine:" << n_fs_subroutine << " n_gs_id:" << n_gs_id
7461                                    << " n_gs_subroutine:" << n_gs_subroutine << " n_tc_id:" << n_tc_id
7462                                    << " n_tc_subroutine:" << n_tc_subroutine << " n_te_id:" << n_te_id
7463                                    << " n_te_subroutine:" << n_te_subroutine << " n_vs_id:" << n_vs_id
7464                                    << " n_vs_subroutine:" << n_vs_subroutine
7465                                    << "; expected:"
7466                                       "("
7467                                    << expected_color[0] << ", " << expected_color[1] << ", " << expected_color[2]
7468                                    << ", " << expected_color[3]
7469                                    << "), found:"
7470                                       "("
7471                                    << texel_ptr[0] << ", " << texel_ptr[1] << ", " << texel_ptr[2] << ", "
7472                                    << texel_ptr[3] << ")." << tcu::TestLog::EndMessage;
7473 
7474                 m_has_test_passed = false;
7475                 should_continue   = false;
7476             }
7477         } /* for (all columns) */
7478     }     /* for (all rows) */
7479 }
7480 
7481 /** Constructor
7482  *
7483  * @param context CTS context
7484  **/
FunctionalTest14_15(deqp::Context & context)7485 FunctionalTest14_15::FunctionalTest14_15(deqp::Context &context)
7486     : TestCase(context, "structure_parameters_program_binary", "Verify structures can be used as parameters")
7487     , m_uniform_location(0)
7488 {
7489 }
7490 
7491 /** Execute test
7492  *
7493  * @return tcu::TestNode::STOP
7494  **/
iterate()7495 tcu::TestNode::IterateResult FunctionalTest14_15::iterate()
7496 {
7497     static const GLchar *vertex_shader_code =
7498         "#version 400 core\n"
7499         "#extension GL_ARB_shader_subroutine : require\n"
7500         "\n"
7501         "precision highp float;\n"
7502         "\n"
7503         "struct data\n"
7504         "{\n"
7505         "    uint r;\n"
7506         "    uint g;\n"
7507         "    uint b;\n"
7508         "    uint a;\n"
7509         "};\n"
7510         "\n"
7511         "subroutine void routine_type_1(in data iparam, out data oparam);\n"
7512         "subroutine void routine_type_2(inout data arg);\n"
7513         "\n"
7514         "subroutine (routine_type_1) void invert(in data iparam, out data oparam)\n"
7515         "{\n"
7516         "    oparam.r = iparam.a;\n"
7517         "    oparam.g = iparam.b;\n"
7518         "    oparam.b = iparam.g;\n"
7519         "    oparam.a = iparam.r;\n"
7520         "}\n"
7521         "\n"
7522         "subroutine (routine_type_1) void increment(in data iparam, out data oparam)\n"
7523         "{\n"
7524         "    oparam.r = 1 + iparam.r;\n"
7525         "    oparam.g = 1 + iparam.g;\n"
7526         "    oparam.b = 1 + iparam.b;\n"
7527         "    oparam.a = 1 + iparam.a;\n"
7528         "}\n"
7529         "\n"
7530         "subroutine (routine_type_2) void div_by_2(inout data arg)\n"
7531         "{\n"
7532         "    arg.r = arg.r / 2;\n"
7533         "    arg.g = arg.g / 2;\n"
7534         "    arg.b = arg.b / 2;\n"
7535         "    arg.a = arg.a / 2;\n"
7536         "}\n"
7537         "\n"
7538         "subroutine (routine_type_2) void decrement(inout data arg)\n"
7539         "{\n"
7540         "    arg.r = arg.r - 1;\n"
7541         "    arg.g = arg.g - 1;\n"
7542         "    arg.b = arg.b - 1;\n"
7543         "    arg.a = arg.a - 1;\n"
7544         "}\n"
7545         "\n"
7546         "subroutine uniform routine_type_1 routine_1;\n"
7547         "subroutine uniform routine_type_2 routine_2;\n"
7548         "\n"
7549         "uniform uvec4 uni_input;\n"
7550         "\n"
7551         "out uvec4 out_routine_1;\n"
7552         "out uvec4 out_routine_2;\n"
7553         "\n"
7554         "\n"
7555         "void main()\n"
7556         "{\n"
7557         "    data routine_1_input;\n"
7558         "    data routine_1_output;\n"
7559         "    data routine_2_arg;\n"
7560         "\n"
7561         "    routine_1_input.r = uni_input.r;\n"
7562         "    routine_1_input.g = uni_input.g;\n"
7563         "    routine_1_input.b = uni_input.b;\n"
7564         "    routine_1_input.a = uni_input.a;\n"
7565         "\n"
7566         "    routine_2_arg.r = uni_input.r;\n"
7567         "    routine_2_arg.g = uni_input.g;\n"
7568         "    routine_2_arg.b = uni_input.b;\n"
7569         "    routine_2_arg.a = uni_input.a;\n"
7570         "\n"
7571         "    routine_1(routine_1_input, routine_1_output);\n"
7572         "    routine_2(routine_2_arg);\n"
7573         "\n"
7574         "    out_routine_1.r = routine_1_output.r;\n"
7575         "    out_routine_1.g = routine_1_output.g;\n"
7576         "    out_routine_1.b = routine_1_output.b;\n"
7577         "    out_routine_1.a = routine_1_output.a;\n"
7578         "\n"
7579         "    out_routine_2.r = routine_2_arg.r;\n"
7580         "    out_routine_2.g = routine_2_arg.g;\n"
7581         "    out_routine_2.b = routine_2_arg.b;\n"
7582         "    out_routine_2.a = routine_2_arg.a;\n"
7583         "}\n"
7584         "\n";
7585 
7586     static const GLchar *subroutine_names[][2] = {{"invert", "increment"}, {"div_by_2", "decrement"}};
7587     static const GLuint n_subroutine_types     = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
7588 
7589     static const GLchar *subroutine_uniform_names[] = {"routine_1", "routine_2"};
7590     static const GLuint n_subroutine_uniform_names =
7591         sizeof(subroutine_uniform_names) / sizeof(subroutine_uniform_names[0]);
7592 
7593     static const GLchar *uniform_name    = "uni_input";
7594     static const GLchar *varying_names[] = {"out_routine_1", "out_routine_2"};
7595 
7596     static const GLuint n_varying_names                = sizeof(varying_names) / sizeof(varying_names[0]);
7597     static const GLuint transform_feedback_buffer_size = n_varying_names * 4 * sizeof(GLuint);
7598 
7599     /* Test data */
7600     static const Utils::vec4<GLuint> uni_input[] = {Utils::vec4<GLuint>(8, 64, 4096, 16777216),
7601                                                     Utils::vec4<GLuint>(8, 64, 4096, 16777216)};
7602 
7603     static const Utils::vec4<GLuint> out_routine_1[] = {Utils::vec4<GLuint>(16777216, 4096, 64, 8),
7604                                                         Utils::vec4<GLuint>(9, 65, 4097, 16777217)};
7605 
7606     static const Utils::vec4<GLuint> out_routine_2[] = {Utils::vec4<GLuint>(4, 32, 2048, 8388608),
7607                                                         Utils::vec4<GLuint>(7, 63, 4095, 16777215)};
7608 
7609     static const GLuint n_test_cases = 2;
7610 
7611     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
7612     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
7613     {
7614         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
7615     }
7616 
7617     /* GL objects */
7618     Utils::program program(m_context);
7619     Utils::buffer transform_feedback_buffer(m_context);
7620     Utils::vertexArray vao(m_context);
7621 
7622     bool is_program_binary_supported = program.isProgramBinarySupported();
7623 
7624     /* Init GL objects */
7625     program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code,
7626                   varying_names /* varying_names */, n_varying_names /* n_varyings */);
7627 
7628     /* Do not execute the test if GL_ARB_get_program_binary is not supported */
7629     if (true == is_program_binary_supported)
7630     {
7631         /* Get subroutine indices */
7632         for (GLuint type = 0; type < n_subroutine_types; ++type)
7633         {
7634             m_initial_subroutine_indices[type][0] =
7635                 program.getSubroutineIndex(subroutine_names[type][0], GL_VERTEX_SHADER);
7636 
7637             m_initial_subroutine_indices[type][1] =
7638                 program.getSubroutineIndex(subroutine_names[type][1], GL_VERTEX_SHADER);
7639         }
7640 
7641         /* Get subroutine uniform locations */
7642         for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
7643         {
7644             m_initial_subroutine_uniform_locations[uniform] =
7645                 program.getSubroutineUniformLocation(subroutine_uniform_names[uniform], GL_VERTEX_SHADER);
7646         }
7647 
7648         /* Delete program and recreate it from binary */
7649         std::vector<GLubyte> program_binary;
7650         GLenum binary_format;
7651 
7652         program.getBinary(program_binary, binary_format);
7653         program.remove();
7654         program.createFromBinary(program_binary, binary_format);
7655     }
7656 
7657     program.use();
7658 
7659     vao.generate();
7660     vao.bind();
7661 
7662     transform_feedback_buffer.generate();
7663     transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
7664                                      GL_DYNAMIC_COPY);
7665     transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
7666 
7667     /* Get subroutine indices */
7668     for (GLuint type = 0; type < n_subroutine_types; ++type)
7669     {
7670         m_subroutine_indices[type][0] = program.getSubroutineIndex(subroutine_names[type][0], GL_VERTEX_SHADER);
7671         m_subroutine_indices[type][1] = program.getSubroutineIndex(subroutine_names[type][1], GL_VERTEX_SHADER);
7672     }
7673 
7674     /* Get subroutine uniform locations */
7675     for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
7676     {
7677         m_subroutine_uniform_locations[uniform] =
7678             program.getSubroutineUniformLocation(subroutine_uniform_names[uniform], GL_VERTEX_SHADER);
7679     }
7680 
7681     /* Get uniform locations */
7682     m_uniform_location = program.getUniformLocation(uniform_name);
7683 
7684     /* Test */
7685     bool result = true;
7686 
7687     /* Test program binary */
7688     if (true == is_program_binary_supported)
7689     {
7690         /* Test indices and locations */
7691         if (false == testIndicesAndLocations())
7692         {
7693             static const GLuint n_subroutines_per_type = 2;
7694 
7695             m_context.getTestContext().getLog()
7696                 << tcu::TestLog::Message << "Error. Subroutine indices or subroutine uniform location changed."
7697                 << tcu::TestLog::EndMessage;
7698 
7699             for (GLuint type = 0; type < n_subroutine_types; ++type)
7700             {
7701                 for (GLuint i = 0; i < n_subroutines_per_type; ++i)
7702                 {
7703                     m_context.getTestContext().getLog()
7704                         << tcu::TestLog::Message << "Subroutine: " << subroutine_names[type][i]
7705                         << " index: " << m_subroutine_indices[type][i]
7706                         << " initial index: " << m_initial_subroutine_indices[type][i] << tcu::TestLog::EndMessage;
7707                 }
7708             }
7709 
7710             for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
7711             {
7712                 m_context.getTestContext().getLog()
7713                     << tcu::TestLog::Message << "Subroutine uniform: " << subroutine_uniform_names[uniform]
7714                     << " location: " << m_subroutine_uniform_locations[uniform]
7715                     << " initial location: " << m_initial_subroutine_uniform_locations[uniform]
7716                     << tcu::TestLog::EndMessage;
7717             }
7718 
7719             result = false;
7720         }
7721 
7722         /* Test draw with deafult set of subroutines */
7723         if (false == testDefaultSubroutineSet(uni_input[0], out_routine_1, out_routine_2))
7724         {
7725             result = false;
7726         }
7727     }
7728 
7729     for (GLuint i = 0; i < n_test_cases; ++i)
7730     {
7731         if (false == testDraw(i, uni_input[i], out_routine_1[i], out_routine_2[i]))
7732         {
7733             result = false;
7734         }
7735     }
7736 
7737     /* Set result */
7738     if (true == result)
7739     {
7740         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
7741     }
7742     else
7743     {
7744         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
7745     }
7746 
7747     /* Done */
7748     return tcu::TestNode::STOP;
7749 }
7750 
7751 /** Execute draw call and verify results
7752  *
7753  * @param uni_input                 Input data
7754  * @param expected_routine_1_result Set of expected results of "routine_1"
7755  * @param expected_routine_2_result Set of expected results of "routine_2"
7756  *
7757  * @return true if test pass, false otherwise
7758  **/
testDefaultSubroutineSet(const Utils::vec4<glw::GLuint> & uni_input,const Utils::vec4<glw::GLuint> expected_routine_1_result[2],const Utils::vec4<glw::GLuint> expected_routine_2_result[2]) const7759 bool FunctionalTest14_15::testDefaultSubroutineSet(const Utils::vec4<glw::GLuint> &uni_input,
7760                                                    const Utils::vec4<glw::GLuint> expected_routine_1_result[2],
7761                                                    const Utils::vec4<glw::GLuint> expected_routine_2_result[2]) const
7762 {
7763     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
7764     bool result              = true;
7765 
7766     /* Set up input data uniforms */
7767     gl.uniform4ui(m_uniform_location, uni_input.m_x, uni_input.m_y, uni_input.m_z, uni_input.m_w);
7768     GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
7769 
7770     /* Execute draw call with transform feedback */
7771     gl.beginTransformFeedback(GL_POINTS);
7772     GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
7773 
7774     gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
7775     GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
7776 
7777     gl.endTransformFeedback();
7778     GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
7779 
7780     /* Capture results */
7781     GLuint *feedback_data = (GLuint *)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
7782     GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
7783 
7784     Utils::vec4<GLuint> routine_1_result;
7785     Utils::vec4<GLuint> routine_2_result;
7786 
7787     routine_1_result.m_x = feedback_data[0 + 0];
7788     routine_1_result.m_y = feedback_data[0 + 1];
7789     routine_1_result.m_z = feedback_data[0 + 2];
7790     routine_1_result.m_w = feedback_data[0 + 3];
7791 
7792     routine_2_result.m_x = feedback_data[4 + 0];
7793     routine_2_result.m_y = feedback_data[4 + 1];
7794     routine_2_result.m_z = feedback_data[4 + 2];
7795     routine_2_result.m_w = feedback_data[4 + 3];
7796 
7797     /* Unmap buffer */
7798     gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
7799     GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
7800 
7801     /* Verifiy */
7802     result = result &&
7803              ((routine_1_result == expected_routine_1_result[0]) || (routine_1_result == expected_routine_1_result[1]));
7804 
7805     result = result &&
7806              ((routine_2_result == expected_routine_2_result[0]) || (routine_2_result == expected_routine_2_result[1]));
7807 
7808     /* Log error if any */
7809     if (false == result)
7810     {
7811         m_context.getTestContext().getLog()
7812             << tcu::TestLog::Message << "Error. Invalid result." << tcu::TestLog::EndMessage;
7813 
7814         tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
7815 
7816         message << "Routine_1, result: ";
7817 
7818         routine_1_result.log(message);
7819 
7820         message << "Routine_2, result: ";
7821 
7822         routine_2_result.log(message);
7823 
7824         message << tcu::TestLog::EndMessage;
7825     }
7826 
7827     /* Done */
7828     return result;
7829 }
7830 
7831 /** Execute draw call and verify results
7832  *
7833  * @param routine_configuration     Subroutine "type" ordinal
7834  * @param uni_input                 Input data
7835  * @param expected_routine_1_result Expected results of "routine_1"
7836  * @param expected_routine_2_result Expected results of "routine_2"
7837  *
7838  * @return true if test pass, false otherwise
7839  **/
testDraw(glw::GLuint routine_configuration,const Utils::vec4<glw::GLuint> & uni_input,const Utils::vec4<glw::GLuint> & expected_routine_1_result,const Utils::vec4<glw::GLuint> & expected_routine_2_result) const7840 bool FunctionalTest14_15::testDraw(glw::GLuint routine_configuration, const Utils::vec4<glw::GLuint> &uni_input,
7841                                    const Utils::vec4<glw::GLuint> &expected_routine_1_result,
7842                                    const Utils::vec4<glw::GLuint> &expected_routine_2_result) const
7843 {
7844     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
7845     bool result              = true;
7846     GLuint subroutine_indices[2];
7847     static const GLuint n_subroutine_uniforms = sizeof(subroutine_indices) / sizeof(subroutine_indices[0]);
7848 
7849     /* Set up input data uniforms */
7850     gl.uniform4ui(m_uniform_location, uni_input.m_x, uni_input.m_y, uni_input.m_z, uni_input.m_w);
7851     GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
7852 
7853     /* Prepare subroutine uniform data */
7854     for (GLuint i = 0; i < n_subroutine_uniforms; ++i)
7855     {
7856         const GLuint location = m_subroutine_uniform_locations[i];
7857 
7858         subroutine_indices[location] = m_subroutine_indices[i][routine_configuration];
7859     }
7860 
7861     /* Set up subroutine uniforms */
7862     gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, n_subroutine_uniforms, &subroutine_indices[0]);
7863     GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
7864 
7865     /* Execute draw call with transform feedback */
7866     gl.beginTransformFeedback(GL_POINTS);
7867     GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
7868 
7869     gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
7870     GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
7871 
7872     gl.endTransformFeedback();
7873     GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
7874 
7875     /* Capture results */
7876     GLuint *feedback_data = (GLuint *)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
7877     GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
7878 
7879     Utils::vec4<GLuint> routine_1_result;
7880     Utils::vec4<GLuint> routine_2_result;
7881 
7882     routine_1_result.m_x = feedback_data[0 + 0];
7883     routine_1_result.m_y = feedback_data[0 + 1];
7884     routine_1_result.m_z = feedback_data[0 + 2];
7885     routine_1_result.m_w = feedback_data[0 + 3];
7886 
7887     routine_2_result.m_x = feedback_data[4 + 0];
7888     routine_2_result.m_y = feedback_data[4 + 1];
7889     routine_2_result.m_z = feedback_data[4 + 2];
7890     routine_2_result.m_w = feedback_data[4 + 3];
7891 
7892     /* Unmap buffer */
7893     gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
7894     GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
7895 
7896     /* Verifiy */
7897     result = result && (routine_1_result == expected_routine_1_result);
7898     result = result && (routine_2_result == expected_routine_2_result);
7899 
7900     /* Log error if any */
7901     if (false == result)
7902     {
7903         m_context.getTestContext().getLog()
7904             << tcu::TestLog::Message << "Error. Invalid result." << tcu::TestLog::EndMessage;
7905 
7906         tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
7907 
7908         message << "Routine_1, result: ";
7909 
7910         routine_1_result.log(message);
7911 
7912         message << ", expected: ";
7913 
7914         expected_routine_1_result.log(message);
7915 
7916         message << "Routine_2, result: ";
7917 
7918         routine_2_result.log(message);
7919 
7920         message << ", expected: ";
7921 
7922         expected_routine_2_result.log(message);
7923 
7924         message << tcu::TestLog::EndMessage;
7925     }
7926 
7927     /* Done */
7928     return result;
7929 }
7930 
7931 /** Verify initial and current values of subroutine indices and subroutines uniform locations
7932  *
7933  * @return true if test pass, false otherwise
7934  **/
testIndicesAndLocations() const7935 bool FunctionalTest14_15::testIndicesAndLocations() const
7936 {
7937     static const GLuint n_subroutine_types = 2;
7938     bool result                            = true;
7939 
7940     /* Verify subroutine indices */
7941     for (GLuint type = 0; type < n_subroutine_types; ++type)
7942     {
7943         result = result && (m_subroutine_indices[type][0] == m_initial_subroutine_indices[type][0]);
7944         result = result && (m_subroutine_indices[type][1] == m_initial_subroutine_indices[type][1]);
7945     }
7946 
7947     /* Verify subroutine uniform locations */
7948     for (GLuint uniform = 0; uniform < n_subroutine_types; ++uniform)
7949     {
7950         result = result && (m_subroutine_uniform_locations[uniform] == m_initial_subroutine_uniform_locations[uniform]);
7951     }
7952 
7953     return result;
7954 }
7955 
7956 /** Constructor.
7957  *
7958  *  @param context Rendering context.
7959  *
7960  **/
FunctionalTest16(deqp::Context & context)7961 FunctionalTest16::FunctionalTest16(deqp::Context &context)
7962     : TestCase(context, "subroutine_uniform_reset",
7963                "Checks that when the active program for a shader stage is re-linke or "
7964                "changed by a call to UseProgram, BindProgramPipeline, or UseProgramStages,"
7965                " subroutine uniforms for that stage are reset to arbitrarily chosen default "
7966                "functions with compatible subroutine types.")
7967     , m_are_pipeline_objects_supported(false)
7968     , m_has_test_passed(true)
7969 {
7970     memset(m_fs_ids, 0, sizeof(m_fs_ids));
7971     memset(m_gs_ids, 0, sizeof(m_gs_ids));
7972     memset(m_po_ids, 0, sizeof(m_po_ids));
7973     memset(m_tc_ids, 0, sizeof(m_tc_ids));
7974     memset(m_te_ids, 0, sizeof(m_te_ids));
7975     memset(m_vs_ids, 0, sizeof(m_vs_ids));
7976 
7977     memset(m_fs_po_ids, 0, sizeof(m_fs_po_ids));
7978     memset(m_gs_po_ids, 0, sizeof(m_gs_po_ids));
7979     memset(m_pipeline_object_ids, 0, sizeof(m_pipeline_object_ids));
7980     memset(m_tc_po_ids, 0, sizeof(m_tc_po_ids));
7981     memset(m_te_po_ids, 0, sizeof(m_te_po_ids));
7982     memset(m_vs_po_ids, 0, sizeof(m_vs_po_ids));
7983 }
7984 
7985 /** Deinitializes all GL objects that may have been created during test execution. */
deinit()7986 void FunctionalTest16::deinit()
7987 {
7988     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
7989 
7990     for (unsigned int n_id = 0; n_id < 2; ++n_id)
7991     {
7992         if (m_fs_ids[n_id] != 0)
7993         {
7994             gl.deleteShader(m_fs_ids[n_id]);
7995 
7996             m_fs_ids[n_id] = 0;
7997         }
7998 
7999         if (m_fs_po_ids[n_id] != 0)
8000         {
8001             gl.deleteProgram(m_fs_po_ids[n_id]);
8002 
8003             m_fs_po_ids[n_id] = 0;
8004         }
8005 
8006         if (m_gs_ids[n_id] != 0)
8007         {
8008             gl.deleteShader(m_gs_ids[n_id]);
8009 
8010             m_gs_ids[n_id] = 0;
8011         }
8012 
8013         if (m_gs_po_ids[n_id] != 0)
8014         {
8015             gl.deleteProgram(m_gs_po_ids[n_id]);
8016 
8017             m_gs_po_ids[n_id] = 0;
8018         }
8019 
8020         if (m_pipeline_object_ids[n_id] != 0)
8021         {
8022             gl.deleteProgramPipelines(1 /* n */, m_pipeline_object_ids + n_id);
8023         }
8024 
8025         if (m_po_ids[n_id] != 0)
8026         {
8027             gl.deleteProgram(m_po_ids[n_id]);
8028 
8029             m_po_ids[n_id] = 0;
8030         }
8031 
8032         if (m_tc_ids[n_id] != 0)
8033         {
8034             gl.deleteShader(m_tc_ids[n_id]);
8035 
8036             m_tc_ids[n_id] = 0;
8037         }
8038 
8039         if (m_tc_po_ids[n_id] != 0)
8040         {
8041             gl.deleteProgram(m_tc_po_ids[n_id]);
8042 
8043             m_tc_po_ids[n_id] = 0;
8044         }
8045 
8046         if (m_te_ids[n_id] != 0)
8047         {
8048             gl.deleteShader(m_te_ids[n_id]);
8049 
8050             m_te_ids[n_id] = 0;
8051         }
8052 
8053         if (m_te_po_ids[n_id] != 0)
8054         {
8055             gl.deleteProgram(m_te_po_ids[n_id]);
8056 
8057             m_te_po_ids[n_id] = 0;
8058         }
8059 
8060         if (m_vs_ids[n_id] != 0)
8061         {
8062             gl.deleteShader(m_vs_ids[n_id]);
8063 
8064             m_vs_ids[n_id] = 0;
8065         }
8066 
8067         if (m_vs_po_ids[n_id] != 0)
8068         {
8069             gl.deleteProgram(m_vs_po_ids[n_id]);
8070 
8071             m_vs_po_ids[n_id] = 0;
8072         }
8073     } /* for (both IDs) */
8074 }
8075 
8076 /** Retrieves body of a shader that should be used for user-specified shader stage.
8077  *  This function returns slightly different implementations, depending on index of
8078  *  the program/pipeline object the shader will be used for.
8079  *
8080  *  @param shader_stage Stage the shader body is to be returned for.
8081  *  @param n_id         Index of the shader (as per description).
8082  *
8083  *  @return Requested string.
8084  **/
getShaderBody(const Utils::_shader_stage & shader_stage,const unsigned int & n_id) const8085 std::string FunctionalTest16::getShaderBody(const Utils::_shader_stage &shader_stage, const unsigned int &n_id) const
8086 {
8087     std::stringstream result_sstream;
8088 
8089     result_sstream << "#version 400\n"
8090                       "\n"
8091                       "#extension GL_ARB_shader_subroutine : require\n"
8092                       "\n";
8093 
8094     switch (shader_stage)
8095     {
8096     case Utils::SHADER_STAGE_VERTEX:
8097     {
8098         result_sstream << "out gl_PerVertex { vec4 gl_Position; } ;\n";
8099         break;
8100     }
8101     case Utils::SHADER_STAGE_GEOMETRY:
8102     {
8103         result_sstream << "layout(points)                   in;\n"
8104                           "layout(points, max_vertices = 1) out;\n";
8105         result_sstream << "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n";
8106         result_sstream << "out gl_PerVertex { vec4 gl_Position; } ;\n";
8107         break;
8108     }
8109 
8110     case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
8111     {
8112         result_sstream << "layout(vertices = 4) out;\n";
8113         result_sstream << "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n";
8114         result_sstream << "out gl_PerVertex { vec4 gl_Position; } gl_out[];\n";
8115         break;
8116     }
8117 
8118     case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
8119     {
8120         result_sstream << "layout(quads) in;\n";
8121         result_sstream << "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n";
8122         result_sstream << "out gl_PerVertex { vec4 gl_Position; };\n";
8123         break;
8124     }
8125 
8126     default:
8127         break;
8128     } /* switch (shader_stage) */
8129 
8130     result_sstream << "\n"
8131                       "subroutine void subroutineType (inout vec4 result);\n"
8132                       "subroutine vec4 subroutineType2(in    vec4 data);\n"
8133                       "\n"
8134                       "subroutine(subroutineType) void function1(inout vec4 result)\n"
8135                       "{\n"
8136                       "    result += vec4("
8137                    << (n_id + 1) << ", " << (n_id + 2) << ", " << (n_id + 3) << ", " << (n_id + 4)
8138                    << ");\n"
8139                       "}\n"
8140                       "subroutine(subroutineType) void function2(inout vec4 result)\n"
8141                       "{\n"
8142                       "    result += vec4("
8143                    << (n_id + 2) << ", " << (n_id + 3) << ", " << (n_id + 4) << ", " << (n_id + 5)
8144                    << ");\n"
8145                       "}\n"
8146                       "\n"
8147                       "subroutine(subroutineType2) vec4 function3(in vec4 data)\n"
8148                       "{\n"
8149                       "    return data * data;\n"
8150                       "}\n"
8151                       "subroutine(subroutineType2) vec4 function4(in vec4 data)\n"
8152                       "{\n"
8153                       "    return data + data;\n"
8154                       "}\n"
8155                       "\n"
8156                       "subroutine uniform subroutineType  subroutine1;\n"
8157                       "subroutine uniform subroutineType  subroutine2;\n"
8158                       "subroutine uniform subroutineType2 subroutine3;\n"
8159                       "subroutine uniform subroutineType2 subroutine4;\n"
8160                       "\n";
8161 
8162     if (shader_stage == Utils::SHADER_STAGE_FRAGMENT)
8163     {
8164         result_sstream << "out vec4 result;\n";
8165     }
8166 
8167     result_sstream << "void main()\n"
8168                       "{\n";
8169 
8170     switch (shader_stage)
8171     {
8172     case Utils::SHADER_STAGE_FRAGMENT:
8173     {
8174         result_sstream << "    result = vec4(0);\n"
8175                        << "    subroutine1(result);\n"
8176                           "    subroutine2(result);\n"
8177                           "    result = subroutine3(result) + subroutine4(result);\n";
8178 
8179         break;
8180     }
8181 
8182     case Utils::SHADER_STAGE_GEOMETRY:
8183     {
8184         result_sstream << "    gl_Position = vec4(0);\n"
8185                           "    subroutine1(gl_Position);\n"
8186                           "    subroutine2(gl_Position);\n"
8187                           "    gl_Position = subroutine3(gl_Position) + subroutine4(gl_Position);\n"
8188                           "    EmitVertex();\n";
8189 
8190         break;
8191     }
8192 
8193     case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
8194     {
8195         result_sstream << "    gl_out[gl_InvocationID].gl_Position = vec4(0);\n"
8196                           "    subroutine1(gl_out[gl_InvocationID].gl_Position);\n"
8197                           "    subroutine2(gl_out[gl_InvocationID].gl_Position);\n"
8198                           "    gl_out[gl_InvocationID].gl_Position = subroutine3(gl_in[0].gl_Position) + "
8199                           "subroutine4(gl_in[0].gl_Position);\n";
8200 
8201         break;
8202     }
8203 
8204     case Utils::SHADER_STAGE_VERTEX:
8205     case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
8206     {
8207         result_sstream << "    gl_Position = vec4(0);\n"
8208                           "    subroutine1(gl_Position);\n"
8209                           "    subroutine2(gl_Position);\n"
8210                           "    gl_Position = subroutine3(gl_Position) + subroutine4(gl_Position);\n";
8211 
8212         break;
8213     }
8214 
8215     default:
8216         break;
8217     } /* switch (shader_stage) */
8218 
8219     result_sstream << "}\n";
8220 
8221     return result_sstream.str();
8222 }
8223 
8224 /** Initializes all objects required to run the test. */
initTest()8225 void FunctionalTest16::initTest()
8226 {
8227     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
8228 
8229     for (unsigned int n_id = 0; n_id < 2 /* test program/shader objects */; ++n_id)
8230     {
8231         const std::string fs_body = getShaderBody(Utils::SHADER_STAGE_FRAGMENT, n_id);
8232         const std::string gs_body = getShaderBody(Utils::SHADER_STAGE_GEOMETRY, n_id);
8233         const std::string tc_body = getShaderBody(Utils::SHADER_STAGE_TESSELLATION_CONTROL, n_id);
8234         const std::string te_body = getShaderBody(Utils::SHADER_STAGE_TESSELLATION_EVALUATION, n_id);
8235         const std::string vs_body = getShaderBody(Utils::SHADER_STAGE_VERTEX, n_id);
8236 
8237         if (!Utils::buildProgram(gl, vs_body, tc_body, te_body, gs_body, fs_body, DE_NULL, /* xfb_varyings */
8238                                  DE_NULL,                                                  /* n_xfb_varyings */
8239                                  m_vs_ids + n_id, m_tc_ids + n_id, m_te_ids + n_id, m_gs_ids + n_id, m_fs_ids + n_id,
8240                                  m_po_ids + n_id))
8241         {
8242             m_testCtx.getLog() << tcu::TestLog::Message
8243                                << "Failed to build test program object, index:"
8244                                   "["
8245                                << n_id << "]" << tcu::TestLog::EndMessage;
8246 
8247             TCU_FAIL("Failed to build a test program");
8248         }
8249 
8250         if (m_are_pipeline_objects_supported)
8251         {
8252             /* Initialize shader program objects */
8253             const char *fs_body_raw_ptr = fs_body.c_str();
8254             const char *gs_body_raw_ptr = gs_body.c_str();
8255             glw::GLint link_status[5]   = {GL_FALSE};
8256             const char *tc_body_raw_ptr = tc_body.c_str();
8257             const char *te_body_raw_ptr = te_body.c_str();
8258             const char *vs_body_raw_ptr = vs_body.c_str();
8259 
8260             m_fs_po_ids[n_id] = gl.createShaderProgramv(GL_FRAGMENT_SHADER, 1 /* count */, &fs_body_raw_ptr);
8261             m_gs_po_ids[n_id] = gl.createShaderProgramv(GL_GEOMETRY_SHADER, 1 /* count */, &gs_body_raw_ptr);
8262             m_tc_po_ids[n_id] = gl.createShaderProgramv(GL_TESS_CONTROL_SHADER, 1 /* count */, &tc_body_raw_ptr);
8263             m_te_po_ids[n_id] = gl.createShaderProgramv(GL_TESS_EVALUATION_SHADER, 1 /* count */, &te_body_raw_ptr);
8264             m_vs_po_ids[n_id] = gl.createShaderProgramv(GL_VERTEX_SHADER, 1 /* count */, &vs_body_raw_ptr);
8265             GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
8266 
8267             gl.getProgramiv(m_fs_po_ids[n_id], GL_LINK_STATUS, link_status + 0);
8268             gl.getProgramiv(m_gs_po_ids[n_id], GL_LINK_STATUS, link_status + 1);
8269             gl.getProgramiv(m_tc_po_ids[n_id], GL_LINK_STATUS, link_status + 2);
8270             gl.getProgramiv(m_te_po_ids[n_id], GL_LINK_STATUS, link_status + 3);
8271             gl.getProgramiv(m_vs_po_ids[n_id], GL_LINK_STATUS, link_status + 4);
8272             GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
8273 
8274             if (link_status[0] == GL_FALSE)
8275                 TCU_FAIL("Fragment shader program failed to link");
8276             if (link_status[1] == GL_FALSE)
8277                 TCU_FAIL("Geometry shader program failed to link");
8278             if (link_status[2] == GL_FALSE)
8279                 TCU_FAIL("Tessellation control shader program failed to link");
8280             if (link_status[3] == GL_FALSE)
8281                 TCU_FAIL("Tessellation evaluation shader program failed to link");
8282             if (link_status[4] == GL_FALSE)
8283                 TCU_FAIL("Vertex shader program failed to link");
8284 
8285             /* Initialize pipeline program object */
8286             gl.genProgramPipelines(1 /* n */, m_pipeline_object_ids + n_id);
8287             GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() call failed.");
8288 
8289             gl.useProgramStages(m_pipeline_object_ids[n_id], GL_FRAGMENT_SHADER_BIT, m_fs_po_ids[n_id]);
8290             gl.useProgramStages(m_pipeline_object_ids[n_id], GL_GEOMETRY_SHADER_BIT, m_gs_po_ids[n_id]);
8291             gl.useProgramStages(m_pipeline_object_ids[n_id], GL_TESS_CONTROL_SHADER_BIT, m_tc_po_ids[n_id]);
8292             gl.useProgramStages(m_pipeline_object_ids[n_id], GL_TESS_EVALUATION_SHADER_BIT, m_te_po_ids[n_id]);
8293             gl.useProgramStages(m_pipeline_object_ids[n_id], GL_VERTEX_SHADER_BIT, m_vs_po_ids[n_id]);
8294             GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8295         }
8296 
8297         /* Retrieve subroutine locations */
8298         struct _item
8299         {
8300             glw::GLuint po_id;
8301             _shader_stage &stage;
8302             glw::GLuint so_id;
8303             glw::GLenum so_type;
8304         } items[] = {
8305             {m_po_ids[n_id], m_po_descriptors[n_id].fragment, m_fs_ids[n_id], GL_FRAGMENT_SHADER},
8306             {m_po_ids[n_id], m_po_descriptors[n_id].geometry, m_gs_ids[n_id], GL_GEOMETRY_SHADER},
8307             {m_po_ids[n_id], m_po_descriptors[n_id].tess_control, m_tc_ids[n_id], GL_TESS_CONTROL_SHADER},
8308             {m_po_ids[n_id], m_po_descriptors[n_id].tess_evaluation, m_te_ids[n_id], GL_TESS_EVALUATION_SHADER},
8309             {m_po_ids[n_id], m_po_descriptors[n_id].vertex, m_vs_ids[n_id], GL_VERTEX_SHADER},
8310 
8311             {m_fs_po_ids[n_id], m_fs_po_descriptors[n_id], m_fs_po_ids[n_id], GL_FRAGMENT_SHADER},
8312             {m_gs_po_ids[n_id], m_gs_po_descriptors[n_id], m_gs_po_ids[n_id], GL_GEOMETRY_SHADER},
8313             {m_tc_po_ids[n_id], m_tc_po_descriptors[n_id], m_tc_po_ids[n_id], GL_TESS_CONTROL_SHADER},
8314             {m_te_po_ids[n_id], m_te_po_descriptors[n_id], m_te_po_ids[n_id], GL_TESS_EVALUATION_SHADER},
8315             {m_vs_po_ids[n_id], m_vs_po_descriptors[n_id], m_vs_po_ids[n_id], GL_VERTEX_SHADER},
8316         };
8317         const unsigned int n_items = sizeof(items) / sizeof(items[0]);
8318 
8319         for (unsigned int n_item = 0; n_item < n_items; ++n_item)
8320         {
8321             _item &current_item = items[n_item];
8322 
8323             current_item.stage.function1_index =
8324                 gl.getSubroutineIndex(current_item.po_id, current_item.so_type, "function1");
8325             current_item.stage.function2_index =
8326                 gl.getSubroutineIndex(current_item.po_id, current_item.so_type, "function2");
8327             current_item.stage.function3_index =
8328                 gl.getSubroutineIndex(current_item.po_id, current_item.so_type, "function3");
8329             current_item.stage.function4_index =
8330                 gl.getSubroutineIndex(current_item.po_id, current_item.so_type, "function4");
8331             GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineIndex() call(s) failed.");
8332 
8333             if (current_item.stage.function1_index == GL_INVALID_INDEX ||
8334                 current_item.stage.function2_index == GL_INVALID_INDEX ||
8335                 current_item.stage.function3_index == GL_INVALID_INDEX ||
8336                 current_item.stage.function4_index == GL_INVALID_INDEX)
8337             {
8338                 TCU_FAIL("Subroutine name was not recognized.");
8339             }
8340 
8341             current_item.stage.subroutine1_uniform_location =
8342                 gl.getSubroutineUniformLocation(current_item.po_id, current_item.so_type, "subroutine1");
8343             current_item.stage.subroutine2_uniform_location =
8344                 gl.getSubroutineUniformLocation(current_item.po_id, current_item.so_type, "subroutine2");
8345             current_item.stage.subroutine3_uniform_location =
8346                 gl.getSubroutineUniformLocation(current_item.po_id, current_item.so_type, "subroutine3");
8347             current_item.stage.subroutine4_uniform_location =
8348                 gl.getSubroutineUniformLocation(current_item.po_id, current_item.so_type, "subroutine4");
8349             GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineUniformLocation() call(s) failed.");
8350 
8351             if (current_item.stage.subroutine1_uniform_location == -1 ||
8352                 current_item.stage.subroutine2_uniform_location == -1 ||
8353                 current_item.stage.subroutine3_uniform_location == -1 ||
8354                 current_item.stage.subroutine4_uniform_location == -1)
8355             {
8356                 TCU_FAIL("Subroutine uniform name was not recognized.");
8357             }
8358 
8359             if (m_po_ids[n_id] == current_item.po_id)
8360             {
8361                 gl.useProgram(current_item.po_id);
8362                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
8363             }
8364             else
8365             {
8366                 /* Temporarily bind the program pipeline. */
8367                 gl.bindProgramPipeline(m_pipeline_object_ids[n_id]);
8368                 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
8369             }
8370 
8371             gl.getUniformSubroutineuiv(current_item.so_type, current_item.stage.subroutine1_uniform_location,
8372                                        &current_item.stage.default_subroutine1_value);
8373             gl.getUniformSubroutineuiv(current_item.so_type, current_item.stage.subroutine2_uniform_location,
8374                                        &current_item.stage.default_subroutine2_value);
8375             gl.getUniformSubroutineuiv(current_item.so_type, current_item.stage.subroutine3_uniform_location,
8376                                        &current_item.stage.default_subroutine3_value);
8377             gl.getUniformSubroutineuiv(current_item.so_type, current_item.stage.subroutine4_uniform_location,
8378                                        &current_item.stage.default_subroutine4_value);
8379             GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformSubroutineuiv() call(s) failed.");
8380 
8381             current_item.stage.gl_stage = current_item.so_type;
8382 
8383             if (m_po_ids[n_id] != current_item.po_id)
8384             {
8385                 /* Unbind the program pipeline object */
8386                 gl.bindProgramPipeline(0);
8387                 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
8388             }
8389         } /* for (all items) */
8390 
8391         /* Make sure the default subroutine choices are valid. */
8392         verifySubroutineUniformValues(
8393             TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT, /* makes the verification routine use program object descriptor */
8394             n_id, SUBROUTINE_UNIFORMS_SET_TO_VALID_VALUES);
8395 
8396         if (m_are_pipeline_objects_supported)
8397         {
8398             gl.useProgram(0);
8399             GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
8400 
8401             gl.bindProgramPipeline(m_pipeline_object_ids[n_id]);
8402             GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
8403             {
8404                 verifySubroutineUniformValues(
8405                     TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_PIPELINE_OBJECT, /* makes the verification routine use pipeline object descriptor */
8406                     n_id, SUBROUTINE_UNIFORMS_SET_TO_VALID_VALUES);
8407             }
8408             gl.bindProgramPipeline(0);
8409             GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
8410         }
8411     } /* for (both program descriptors) */
8412 }
8413 
8414 /** Retrieves IDs of shaders OR shader program objects, depending on which of the two
8415  *  the caller requests for.
8416  *
8417  *  @param retrieve_program_object_shader_ids true if the caller wishes to retrieve shader object IDs,
8418  *                                            false to return shader program IDs.
8419  *  @param n_id                               Index of the program/pipeline object the shaders
8420  *                                            are a part of.
8421  *  @param out_shader_stages                  Deref will be used to store exactly five IDs. Must not
8422  *                                            be NULL.
8423  **/
getShaderStages(bool retrieve_program_object_shader_ids,const unsigned int & n_id,const _shader_stage ** out_shader_stages) const8424 void FunctionalTest16::getShaderStages(bool retrieve_program_object_shader_ids, const unsigned int &n_id,
8425                                        const _shader_stage **out_shader_stages) const
8426 {
8427     if (retrieve_program_object_shader_ids)
8428     {
8429         out_shader_stages[0] = &m_po_descriptors[n_id].vertex;
8430         out_shader_stages[1] = &m_po_descriptors[n_id].tess_control;
8431         out_shader_stages[2] = &m_po_descriptors[n_id].tess_evaluation;
8432         out_shader_stages[3] = &m_po_descriptors[n_id].geometry;
8433         out_shader_stages[4] = &m_po_descriptors[n_id].fragment;
8434     }
8435     else
8436     {
8437         out_shader_stages[0] = m_vs_po_descriptors + n_id;
8438         out_shader_stages[1] = m_tc_po_descriptors + n_id;
8439         out_shader_stages[2] = m_te_po_descriptors + n_id;
8440         out_shader_stages[3] = m_gs_po_descriptors + n_id;
8441         out_shader_stages[4] = m_fs_po_descriptors + n_id;
8442     }
8443 }
8444 
8445 /** Executes test iteration.
8446  *
8447  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
8448  */
iterate()8449 tcu::TestNode::IterateResult FunctionalTest16::iterate()
8450 {
8451     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
8452 
8453     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
8454     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
8455     {
8456         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
8457     }
8458 
8459     m_are_pipeline_objects_supported =
8460         m_context.getContextInfo().isExtensionSupported("GL_ARB_separate_shader_objects");
8461 
8462     /* Initialize GL objects required to run the test */
8463     initTest();
8464 
8465     /* Iterate over both pipelines/programs and verify that calling glUseProgram() /
8466      * glBindProgramPipeline() / glUseProgramStages() resets subroutine uniform configuration.
8467      */
8468     for (int test_case = static_cast<int>(TEST_CASE_FIRST); test_case != static_cast<int>(TEST_CASE_COUNT); ++test_case)
8469     {
8470         if (static_cast<_test_case>(test_case) != TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT &&
8471             !m_are_pipeline_objects_supported)
8472         {
8473             /* Current test case requires GL_ARB_separate_shader_objects support which is
8474              * unavaiable on the platform that we're testing
8475              */
8476             continue;
8477         }
8478 
8479         for (unsigned int n_object_id = 0; n_object_id < 2; /* pipeline/program objects allocated for the test */
8480              ++n_object_id)
8481         {
8482             /* Verify that currently reported subroutine uniform values are equal to default values */
8483             if (test_case == TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT)
8484             {
8485                 gl.useProgram(m_po_ids[n_object_id]);
8486                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
8487             }
8488             else
8489             {
8490                 gl.bindProgramPipeline(m_pipeline_object_ids[n_object_id]);
8491                 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed");
8492             }
8493 
8494             verifySubroutineUniformValues(static_cast<_test_case>(test_case), n_object_id,
8495                                           SUBROUTINE_UNIFORMS_SET_TO_DEFAULT_VALUES);
8496 
8497             /* Re-configure subroutine uniforms so that they point to different subroutines than
8498              * the default ones.
8499              */
8500             const _shader_stage *stages[5 /* fs+gs+tc+te+vs */] = {DE_NULL};
8501 
8502             getShaderStages(static_cast<_test_case>(test_case) == TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT,
8503                             n_object_id, stages);
8504 
8505             for (unsigned int n_stage = 0; n_stage < 5 /* fs+gs+tc+te+vs stages */; ++n_stage)
8506             {
8507                 const _shader_stage &current_stage      = *(stages[n_stage]);
8508                 glw::GLuint subroutine_configuration[4] = {GL_INVALID_INDEX};
8509 
8510                 subroutine_configuration[0] =
8511                     (current_stage.default_subroutine1_value == current_stage.function1_index) ?
8512                         current_stage.function2_index :
8513                         current_stage.function1_index;
8514                 subroutine_configuration[1] =
8515                     (current_stage.default_subroutine2_value == current_stage.function1_index) ?
8516                         current_stage.function2_index :
8517                         current_stage.function1_index;
8518                 subroutine_configuration[2] =
8519                     (current_stage.default_subroutine3_value == current_stage.function3_index) ?
8520                         current_stage.function4_index :
8521                         current_stage.function3_index;
8522                 subroutine_configuration[3] =
8523                     (current_stage.default_subroutine4_value == current_stage.function3_index) ?
8524                         current_stage.function4_index :
8525                         current_stage.function3_index;
8526 
8527                 gl.uniformSubroutinesuiv(current_stage.gl_stage, 4 /* count */, subroutine_configuration);
8528                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniformSubroutinesuiv() call failed.");
8529             } /* for (all stages) */
8530 
8531             verifySubroutineUniformValues(static_cast<_test_case>(test_case), n_object_id,
8532                                           SUBROUTINE_UNIFORMS_SET_TO_NONDEFAULT_VALUES);
8533 
8534             /* Execute test case-specific code */
8535             _shader_stage cached_shader_stage_data;
8536             bool stage_reset_status[Utils::SHADER_STAGE_COUNT] = {false, false, false, false, false};
8537             bool uses_stage_reset_status                       = false;
8538 
8539             switch (test_case)
8540             {
8541             case TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT:
8542             {
8543                 /* Switch to a different program object and then back to current PO.
8544                  * Subroutine uniforms should be back at their default settings, instead of
8545                  * the ones we've just set.
8546                  */
8547                 gl.useProgram(m_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8548                 gl.useProgram(m_po_ids[n_object_id]);
8549                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call(s) failed.");
8550 
8551                 break;
8552             }
8553 
8554             case TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_PIPELINE_OBJECT:
8555             {
8556                 /* Switch to a different pipeline object and then back to the current one.
8557                  * Subroutine uniforms should be back at their default settings, instead of
8558                  * the ones we've just set.
8559                  */
8560                 gl.bindProgramPipeline(
8561                     m_pipeline_object_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8562                 gl.bindProgramPipeline(m_pipeline_object_ids[n_object_id]);
8563                 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call(s) failed.");
8564 
8565                 break;
8566             }
8567 
8568             case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_FRAGMENT_STAGE:
8569             {
8570                 /* Change the fragment shader stage to a different one.
8571                  *
8572                  * Note: We also need to update internal descriptor since the subroutine/uniform
8573                  *       locations may be different between the two programs.
8574                  */
8575                 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_FRAGMENT_SHADER_BIT,
8576                                     m_fs_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8577                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8578 
8579                 cached_shader_stage_data         = m_fs_po_descriptors[n_object_id];
8580                 m_fs_po_descriptors[n_object_id] = m_fs_po_descriptors[(n_object_id + 1) % 2];
8581 
8582                 stage_reset_status[Utils::SHADER_STAGE_FRAGMENT] = true;
8583                 uses_stage_reset_status                          = true;
8584 
8585                 break;
8586             }
8587 
8588             case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_GEOMETRY_STAGE:
8589             {
8590                 /* Change the geometry shader stage to a different one.
8591                  *
8592                  * Note: We also need to update internal descriptor since the subroutine/uniform
8593                  *       locations may be different between the two programs.
8594                  */
8595                 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_GEOMETRY_SHADER_BIT,
8596                                     m_gs_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8597                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8598 
8599                 cached_shader_stage_data         = m_gs_po_descriptors[n_object_id];
8600                 m_gs_po_descriptors[n_object_id] = m_gs_po_descriptors[(n_object_id + 1) % 2];
8601 
8602                 stage_reset_status[Utils::SHADER_STAGE_GEOMETRY] = true;
8603                 uses_stage_reset_status                          = true;
8604 
8605                 break;
8606             }
8607 
8608             case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_TESS_CONTROL_STAGE:
8609             {
8610                 /* Change the tessellation control shader stage to a different one.
8611                  *
8612                  * Note: We also need to update internal descriptor since the subroutine/uniform
8613                  *       locations may be different between the two programs.
8614                  */
8615                 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_TESS_CONTROL_SHADER_BIT,
8616                                     m_tc_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8617                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8618 
8619                 cached_shader_stage_data         = m_tc_po_descriptors[n_object_id];
8620                 m_tc_po_descriptors[n_object_id] = m_tc_po_descriptors[(n_object_id + 1) % 2];
8621 
8622                 stage_reset_status[Utils::SHADER_STAGE_TESSELLATION_CONTROL] = true;
8623                 uses_stage_reset_status                                      = true;
8624 
8625                 break;
8626             }
8627 
8628             case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_TESS_EVALUATION_STAGE:
8629             {
8630                 /* Change the tessellation evaluation shader stage to a different one.
8631                  *
8632                  * Note: We also need to update internal descriptor since the subroutine/uniform
8633                  *       locations may be different between the two programs.
8634                  */
8635                 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_TESS_EVALUATION_SHADER_BIT,
8636                                     m_te_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8637                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8638 
8639                 cached_shader_stage_data         = m_te_po_descriptors[n_object_id];
8640                 m_te_po_descriptors[n_object_id] = m_te_po_descriptors[(n_object_id + 1) % 2];
8641 
8642                 stage_reset_status[Utils::SHADER_STAGE_TESSELLATION_EVALUATION] = true;
8643                 uses_stage_reset_status                                         = true;
8644 
8645                 break;
8646             }
8647 
8648             case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_VERTEX_STAGE:
8649             {
8650                 /* Change the vertex shader stage to a different one.
8651                  *
8652                  * Note: We also need to update internal descriptor since the subroutine/uniform
8653                  *       locations may be different between the two programs.
8654                  */
8655                 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_VERTEX_SHADER_BIT,
8656                                     m_vs_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8657                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8658 
8659                 cached_shader_stage_data         = m_vs_po_descriptors[n_object_id];
8660                 m_vs_po_descriptors[n_object_id] = m_vs_po_descriptors[(n_object_id + 1) % 2];
8661 
8662                 stage_reset_status[Utils::SHADER_STAGE_VERTEX] = true;
8663                 uses_stage_reset_status                        = true;
8664 
8665                 break;
8666             }
8667 
8668             default:
8669             {
8670                 TCU_FAIL("Unrecognized test case");
8671             }
8672             } /* switch (test_case) */
8673 
8674             /* Verify the subroutine uniform values are valid */
8675             if (!uses_stage_reset_status)
8676             {
8677                 verifySubroutineUniformValues(static_cast<_test_case>(test_case), n_object_id,
8678                                               SUBROUTINE_UNIFORMS_SET_TO_DEFAULT_VALUES);
8679             }
8680             else
8681             {
8682                 const _shader_stage *shader_stages[Utils::SHADER_STAGE_COUNT] = {DE_NULL};
8683 
8684                 getShaderStages(static_cast<_test_case>(test_case) == TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT,
8685                                 n_object_id, shader_stages);
8686 
8687                 for (unsigned int n_shader_stage = 0; n_shader_stage < Utils::SHADER_STAGE_COUNT; ++n_shader_stage)
8688                 {
8689                     const _shader_stage &current_shader_stage = *(shader_stages[n_shader_stage]);
8690 
8691                     if (stage_reset_status[n_shader_stage])
8692                     {
8693                         verifySubroutineUniformValuesForShaderStage(current_shader_stage,
8694                                                                     SUBROUTINE_UNIFORMS_SET_TO_DEFAULT_VALUES);
8695                     }
8696                     else
8697                     {
8698                         verifySubroutineUniformValuesForShaderStage(current_shader_stage,
8699                                                                     SUBROUTINE_UNIFORMS_SET_TO_NONDEFAULT_VALUES);
8700                     }
8701                 } /* for (all shader stages) */
8702             }
8703 
8704             /* Revert the changes some of the test cases appied */
8705             switch (test_case)
8706             {
8707             case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_FRAGMENT_STAGE:
8708             {
8709                 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_FRAGMENT_SHADER_BIT,
8710                                     m_fs_po_ids[n_object_id]);
8711                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8712 
8713                 m_fs_po_descriptors[n_object_id] = cached_shader_stage_data;
8714 
8715                 break;
8716             }
8717 
8718             case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_GEOMETRY_STAGE:
8719             {
8720                 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_GEOMETRY_SHADER_BIT,
8721                                     m_gs_po_ids[n_object_id]);
8722                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8723 
8724                 m_gs_po_descriptors[n_object_id] = cached_shader_stage_data;
8725 
8726                 break;
8727             }
8728 
8729             case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_TESS_CONTROL_STAGE:
8730             {
8731                 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_TESS_CONTROL_SHADER_BIT,
8732                                     m_tc_po_ids[n_object_id]);
8733                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8734 
8735                 m_tc_po_descriptors[n_object_id] = cached_shader_stage_data;
8736 
8737                 break;
8738             }
8739 
8740             case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_TESS_EVALUATION_STAGE:
8741             {
8742                 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_TESS_EVALUATION_SHADER_BIT,
8743                                     m_te_po_ids[n_object_id]);
8744                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8745 
8746                 m_te_po_descriptors[n_object_id] = cached_shader_stage_data;
8747 
8748                 break;
8749             }
8750 
8751             case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_VERTEX_STAGE:
8752             {
8753                 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_VERTEX_SHADER_BIT, m_vs_po_ids[n_object_id]);
8754                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8755 
8756                 m_vs_po_descriptors[n_object_id] = cached_shader_stage_data;
8757 
8758                 break;
8759             }
8760 
8761             default:
8762                 break;
8763             } /* switch (test_case) */
8764 
8765         } /* for (all program object descriptors) */
8766 
8767         /* Unbind the program object */
8768         gl.useProgram(0);
8769         GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
8770     } /* for (all test cases) */
8771 
8772     if (m_has_test_passed)
8773     {
8774         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
8775     }
8776     else
8777     {
8778         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
8779     }
8780 
8781     return STOP;
8782 }
8783 
8784 /** Verifies the subroutine uniform values reported by GL implementation. Depending on the test case,
8785  *  it will either query program object stages or separate shader objects.
8786  *
8787  *  @param test_case    Test case the verification is to be performed for.
8788  *  @param n_id         Index of the program/pipeline object to use for the verification
8789  *  @param verification Verification method.
8790  */
verifySubroutineUniformValues(const _test_case & test_case,const unsigned int & n_id,const _subroutine_uniform_value_verification & verification)8791 void FunctionalTest16::verifySubroutineUniformValues(const _test_case &test_case, const unsigned int &n_id,
8792                                                      const _subroutine_uniform_value_verification &verification)
8793 {
8794     const _shader_stage *stages[] = {
8795         DE_NULL, /* fragment shader     stage slot */
8796         DE_NULL, /* geometry shader     stage slot */
8797         DE_NULL, /* tess control shader stage slot */
8798         DE_NULL, /* tess eval shader    stage slot */
8799         DE_NULL  /* vertex shader       stage slot */
8800     };
8801     const unsigned int n_stages = sizeof(stages) / sizeof(stages[0]);
8802 
8803     /* Verify that currently reported subroutine uniform values are equal to default values */
8804     getShaderStages(test_case == TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT, n_id, stages);
8805 
8806     for (unsigned int n_stage = 0; n_stage < n_stages; ++n_stage)
8807     {
8808         const _shader_stage &current_stage = *(stages[n_stage]);
8809 
8810         verifySubroutineUniformValuesForShaderStage(current_stage, verification);
8811     } /* for (all items) */
8812 }
8813 
8814 /** Verifies the subroutine uniform values reported by GL implementation for user-specified
8815  *  shader stage. If the verification fails, m_has_test_passed will be set to false.
8816  *
8817  *  @param shader_stage Descriptor of a shader stage that should be used for the process.
8818  *  @param verification Type of verification that should be performed.
8819  *
8820  **/
verifySubroutineUniformValuesForShaderStage(const _shader_stage & shader_stage,const _subroutine_uniform_value_verification & verification)8821 void FunctionalTest16::verifySubroutineUniformValuesForShaderStage(
8822     const _shader_stage &shader_stage, const _subroutine_uniform_value_verification &verification)
8823 {
8824     const glw::Functions &gl     = m_context.getRenderContext().getFunctions();
8825     glw::GLuint result_values[4] = {0};
8826 
8827     gl.getUniformSubroutineuiv(shader_stage.gl_stage, shader_stage.subroutine1_uniform_location, result_values + 0);
8828     gl.getUniformSubroutineuiv(shader_stage.gl_stage, shader_stage.subroutine2_uniform_location, result_values + 1);
8829     gl.getUniformSubroutineuiv(shader_stage.gl_stage, shader_stage.subroutine3_uniform_location, result_values + 2);
8830     gl.getUniformSubroutineuiv(shader_stage.gl_stage, shader_stage.subroutine4_uniform_location, result_values + 3);
8831     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformSubroutineuiv() call(s) failed.");
8832 
8833     if (verification == SUBROUTINE_UNIFORMS_SET_TO_VALID_VALUES)
8834     {
8835         if (!((result_values[0] == (GLuint)shader_stage.subroutine1_uniform_location ||
8836                result_values[0] == (GLuint)shader_stage.subroutine2_uniform_location) &&
8837               (result_values[1] == (GLuint)shader_stage.subroutine1_uniform_location ||
8838                result_values[1] == (GLuint)shader_stage.subroutine2_uniform_location) &&
8839               (result_values[2] == (GLuint)shader_stage.subroutine3_uniform_location ||
8840                result_values[2] == (GLuint)shader_stage.subroutine4_uniform_location) &&
8841               (result_values[3] == (GLuint)shader_stage.subroutine3_uniform_location ||
8842                result_values[3] == (GLuint)shader_stage.subroutine4_uniform_location)))
8843         {
8844             m_testCtx.getLog() << tcu::TestLog::Message
8845                                << "SUBROUTINE_UNIFORMS_SET_TO_VALID_VALUES validation failed. "
8846                                   "Shader stage:["
8847                                << Utils::getShaderStageStringFromGLEnum(shader_stage.gl_stage)
8848                                << "], "
8849                                   "expected data:["
8850                                << shader_stage.subroutine1_uniform_location << " OR "
8851                                << shader_stage.subroutine2_uniform_location << " x 2, "
8852                                << shader_stage.subroutine3_uniform_location << " OR "
8853                                << shader_stage.subroutine4_uniform_location
8854                                << " x 2], "
8855                                   "found data:["
8856                                << result_values[0] << ", " << result_values[1] << ", " << result_values[2] << ", "
8857                                << result_values[3] << "]." << tcu::TestLog::EndMessage;
8858 
8859             m_has_test_passed = false;
8860         }
8861     }
8862     else if (verification == SUBROUTINE_UNIFORMS_SET_TO_DEFAULT_VALUES)
8863     {
8864         if (result_values[0] != shader_stage.default_subroutine1_value ||
8865             result_values[1] != shader_stage.default_subroutine2_value ||
8866             result_values[2] != shader_stage.default_subroutine3_value ||
8867             result_values[3] != shader_stage.default_subroutine4_value)
8868         {
8869             m_testCtx.getLog() << tcu::TestLog::Message
8870                                << "SUBROUTINE_UNIFORMS_SET_TO_DEFAULT_VALUES validation failed. "
8871                                   "Shader stage:["
8872                                << Utils::getShaderStageStringFromGLEnum(shader_stage.gl_stage)
8873                                << "], "
8874                                   "expected data:["
8875                                << shader_stage.default_subroutine1_value << ", "
8876                                << shader_stage.default_subroutine2_value << ", "
8877                                << shader_stage.default_subroutine3_value << ", "
8878                                << shader_stage.default_subroutine4_value
8879                                << "], "
8880                                   "found data:["
8881                                << result_values[0] << ", " << result_values[1] << ", " << result_values[2] << ", "
8882                                << result_values[3] << "]." << tcu::TestLog::EndMessage;
8883 
8884             m_has_test_passed = false;
8885         }
8886     }
8887     else
8888     {
8889         DE_ASSERT(verification == SUBROUTINE_UNIFORMS_SET_TO_NONDEFAULT_VALUES);
8890 
8891         if (result_values[0] == shader_stage.default_subroutine1_value ||
8892             result_values[1] == shader_stage.default_subroutine2_value ||
8893             result_values[2] == shader_stage.default_subroutine3_value ||
8894             result_values[3] == shader_stage.default_subroutine4_value)
8895         {
8896             m_testCtx.getLog() << tcu::TestLog::Message
8897                                << "SUBROUTINE_UNIFORMS_SET_TO_NONDEFAULT_VALUES validation failed. "
8898                                   "Shader stage:["
8899                                << Utils::getShaderStageStringFromGLEnum(shader_stage.gl_stage)
8900                                << "], "
8901                                   "expected data:!["
8902                                << shader_stage.default_subroutine1_value << ", "
8903                                << shader_stage.default_subroutine2_value << ", "
8904                                << shader_stage.default_subroutine3_value << ", "
8905                                << shader_stage.default_subroutine4_value
8906                                << "], "
8907                                   "found data:["
8908                                << result_values[0] << ", " << result_values[1] << ", " << result_values[2] << ", "
8909                                << result_values[3] << "]." << tcu::TestLog::EndMessage;
8910 
8911             m_has_test_passed = false;
8912         }
8913     }
8914 }
8915 
8916 /** Constructor.
8917  *
8918  *  @param context Rendering context.
8919  *
8920  **/
FunctionalTest17(deqp::Context & context)8921 FunctionalTest17::FunctionalTest17(deqp::Context &context)
8922     : TestCase(context, "same_subroutine_and_subroutine_uniform_but_different_type_used_in_all_stages",
8923                "Creates a program which uses the same subroutine and subroutine uniform "
8924                "names for every stage (types of subroutines are different in each stage) "
8925                "and then makes sure that such program compiles and works as expected.")
8926     , m_fbo_id(0)
8927     , m_fs_id(0)
8928     , m_gs_id(0)
8929     , m_has_test_passed(true)
8930     , m_po_id(0)
8931     , m_tc_id(0)
8932     , m_te_id(0)
8933     , m_to_data(DE_NULL)
8934     , m_to_height(4) /* arbitrary value */
8935     , m_to_id(0)
8936     , m_to_width(4) /* arbitrary value */
8937     , m_vao_id(0)
8938     , m_vs_id(0)
8939 {
8940     /* Left blank intentionally */
8941 }
8942 
8943 /** Deinitializes all GL objects that may have been created during test execution. */
deinit()8944 void FunctionalTest17::deinit()
8945 {
8946     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
8947 
8948     if (m_fbo_id != 0)
8949     {
8950         gl.deleteFramebuffers(1, &m_fbo_id);
8951 
8952         m_fbo_id = 0;
8953     }
8954 
8955     if (m_fs_id != 0)
8956     {
8957         gl.deleteShader(m_fs_id);
8958 
8959         m_fs_id = 0;
8960     }
8961 
8962     if (m_gs_id != 0)
8963     {
8964         gl.deleteShader(m_gs_id);
8965 
8966         m_gs_id = 0;
8967     }
8968 
8969     if (m_po_id != 0)
8970     {
8971         gl.deleteProgram(m_po_id);
8972 
8973         m_po_id = 0;
8974     }
8975 
8976     if (m_tc_id != 0)
8977     {
8978         gl.deleteShader(m_tc_id);
8979 
8980         m_tc_id = 0;
8981     }
8982 
8983     if (m_te_id != 0)
8984     {
8985         gl.deleteShader(m_te_id);
8986 
8987         m_te_id = 0;
8988     }
8989 
8990     if (m_to_data != DE_NULL)
8991     {
8992         delete[] m_to_data;
8993 
8994         m_to_data = DE_NULL;
8995     }
8996 
8997     if (m_to_id != 0)
8998     {
8999         gl.deleteTextures(1, &m_to_id);
9000 
9001         m_to_id = 0;
9002     }
9003 
9004     if (m_vao_id != 0)
9005     {
9006         gl.deleteVertexArrays(1, &m_vao_id);
9007 
9008         m_vao_id = 0;
9009     }
9010 
9011     if (m_vs_id != 0)
9012     {
9013         gl.deleteShader(m_vs_id);
9014 
9015         m_vs_id = 0;
9016     }
9017 
9018     /* Restore original GL configuration */
9019     gl.patchParameteri(GL_PATCH_VERTICES, 3);
9020     GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteri() call failed.");
9021 
9022     gl.pixelStorei(GL_PACK_ALIGNMENT, 4);
9023     GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call failed.");
9024 }
9025 
9026 /** Retrieves body of a fragment shader that should be used by the test program.
9027  *
9028  *  @return Requested string.
9029  **/
getFragmentShaderBody() const9030 std::string FunctionalTest17::getFragmentShaderBody() const
9031 {
9032     return "#version 400\n"
9033            "\n"
9034            "#extension GL_ARB_shader_subroutine : require\n"
9035            "\n"
9036            "in GS_DATA\n"
9037            "{\n"
9038            "    vec4 gs_data;\n"
9039            "    vec4 tc_data;\n"
9040            "    vec4 te_data;\n"
9041            "    vec4 vs_data;\n"
9042            "} gs;\n"
9043            "\n"
9044            "out vec4 result;\n"
9045            "\n"
9046            "subroutine void subroutineTypeFS(out vec4 result);\n"
9047            "\n"
9048            "subroutine(subroutineTypeFS) void subroutine1(out vec4 result)\n"
9049            "{\n"
9050            "    result = vec4(5, 6, 7, 8);\n"
9051            "}\n"
9052            "\n"
9053            "subroutine uniform subroutineTypeFS function;\n"
9054            "\n"
9055            "void main()\n"
9056            "{\n"
9057            "    vec4 fs_data;\n"
9058            "\n"
9059            "    function(fs_data);\n"
9060            "    result = gs.gs_data + gs.tc_data + gs.te_data + gs.vs_data + fs_data;\n"
9061            "}\n";
9062 }
9063 
9064 /** Retrieves body of a geometry shader that should be used by the test program.
9065  *
9066  *  @return Requested string.
9067  **/
getGeometryShaderBody() const9068 std::string FunctionalTest17::getGeometryShaderBody() const
9069 {
9070     return "#version 400\n"
9071            "\n"
9072            "#extension GL_ARB_shader_subroutine : require\n"
9073            "\n"
9074            "layout(points)                           in;\n"
9075            "layout(triangle_strip, max_vertices = 4) out;\n"
9076            "\n"
9077            "subroutine void subroutineTypeGS(out vec4 result);\n"
9078            "\n"
9079            "subroutine(subroutineTypeGS) void subroutine1(out vec4 result)\n"
9080            "{\n"
9081            "    result = vec4(4, 5, 6, 7);\n"
9082            "}\n"
9083            "\n"
9084            "subroutine uniform subroutineTypeGS function;\n"
9085            "\n"
9086            "in TE_DATA\n"
9087            "{\n"
9088            "    vec4 tc_data;\n"
9089            "    vec4 te_data;\n"
9090            "    vec4 vs_data;\n"
9091            "} te[];\n"
9092            "\n"
9093            "out GS_DATA\n"
9094            "{\n"
9095            "    vec4 gs_data;\n"
9096            "    vec4 tc_data;\n"
9097            "    vec4 te_data;\n"
9098            "    vec4 vs_data;\n"
9099            "} result;\n"
9100            "\n"
9101            "void main()\n"
9102            "{\n"
9103            "    function(result.gs_data);\n"
9104            "    gl_Position    = vec4(1, -1, 0, 1);\n"
9105            "    result.tc_data = te[0].tc_data;\n"
9106            "    result.te_data = te[0].te_data;\n"
9107            "    result.vs_data = te[0].vs_data;\n"
9108            "    EmitVertex();\n"
9109            "\n"
9110            "    function(result.gs_data);\n"
9111            "    gl_Position    = vec4(-1, -1, 0, 1);\n"
9112            "    result.tc_data = te[0].tc_data;\n"
9113            "    result.te_data = te[0].te_data;\n"
9114            "    result.vs_data = te[0].vs_data;\n"
9115            "    EmitVertex();\n"
9116            "\n"
9117            "    function(result.gs_data);\n"
9118            "    gl_Position    = vec4(1, 1, 0, 1);\n"
9119            "    result.tc_data = te[0].tc_data;\n"
9120            "    result.te_data = te[0].te_data;\n"
9121            "    result.vs_data = te[0].vs_data;\n"
9122            "    EmitVertex();\n"
9123            "\n"
9124            "    function(result.gs_data);\n"
9125            "    gl_Position    = vec4(-1, 1, 0, 1);\n"
9126            "    result.tc_data = te[0].tc_data;\n"
9127            "    result.te_data = te[0].te_data;\n"
9128            "    result.vs_data = te[0].vs_data;\n"
9129            "    EmitVertex();\n"
9130            "    EndPrimitive();\n"
9131            "}\n";
9132 }
9133 
9134 /** Retrieves body of a tessellation control shader that should be used by the test program.
9135  *
9136  *  @return Requested string.
9137  **/
getTessellationControlShaderBody() const9138 std::string FunctionalTest17::getTessellationControlShaderBody() const
9139 {
9140     return "#version 400\n"
9141            "\n"
9142            "#extension GL_ARB_shader_subroutine : require\n"
9143            "\n"
9144            "layout (vertices = 4) out;\n"
9145            "\n"
9146            "subroutine void subroutineTypeTC(out vec4 result);\n"
9147            "\n"
9148            "subroutine(subroutineTypeTC) void subroutine1(out vec4 result)\n"
9149            "{\n"
9150            "    result = vec4(2, 3, 4, 5);\n"
9151            "}\n"
9152            "\n"
9153            "subroutine uniform subroutineTypeTC function;\n"
9154            "\n"
9155            "in VS_DATA\n"
9156            "{\n"
9157            "    vec4 vs_data;\n"
9158            "} vs[];\n"
9159            "\n"
9160            "out TC_DATA\n"
9161            "{\n"
9162            "    vec4 tc_data;\n"
9163            "    vec4 vs_data;\n"
9164            "} result[];\n"
9165            "\n"
9166            "void main()\n"
9167            "{\n"
9168            "    gl_TessLevelInner[0] = 1.0;\n"
9169            "    gl_TessLevelInner[1] = 1.0;\n"
9170            "    gl_TessLevelOuter[0] = 1.0;\n"
9171            "    gl_TessLevelOuter[1] = 1.0;\n"
9172            "    gl_TessLevelOuter[2] = 1.0;\n"
9173            "    gl_TessLevelOuter[3] = 1.0;\n"
9174            "\n"
9175            "    function(result[gl_InvocationID].tc_data);\n"
9176            "    result[gl_InvocationID].vs_data = vs[gl_InvocationID].vs_data;\n"
9177            "}\n";
9178 }
9179 
9180 /** Retrieves body of a tessellation evaluation shader that should be used
9181  *  by the test program.
9182  *
9183  *  @return Requested string.
9184  **/
getTessellationEvaluationShaderBody() const9185 std::string FunctionalTest17::getTessellationEvaluationShaderBody() const
9186 {
9187     return "#version 400\n"
9188            "\n"
9189            "#extension GL_ARB_shader_subroutine : require\n"
9190            "\n"
9191            "layout (quads, point_mode) in;\n"
9192            "\n"
9193            "subroutine void subroutineTypeTE(out vec4 result);\n"
9194            "\n"
9195            "subroutine(subroutineTypeTE) void subroutine1(out vec4 result)\n"
9196            "{\n"
9197            "    result = vec4(3, 4, 5, 6);\n"
9198            "}\n"
9199            "\n"
9200            "subroutine uniform subroutineTypeTE function;\n"
9201            "\n"
9202            "in TC_DATA\n"
9203            "{\n"
9204            "    vec4 tc_data;\n"
9205            "    vec4 vs_data;\n"
9206            "} tc[];\n"
9207            "\n"
9208            "out TE_DATA\n"
9209            "{\n"
9210            "    vec4 tc_data;\n"
9211            "    vec4 te_data;\n"
9212            "    vec4 vs_data;\n"
9213            "} result;\n"
9214            "\n"
9215            "void main()\n"
9216            "{\n"
9217            "    result.vs_data = tc[0].vs_data;\n"
9218            "    result.tc_data = tc[0].tc_data;\n"
9219            "    function(result.te_data);\n"
9220            "}\n";
9221 }
9222 
9223 /** Retrieves body of a vertex shader that should be used by the test program.
9224  *
9225  *  @return Requested string.
9226  **/
getVertexShaderBody() const9227 std::string FunctionalTest17::getVertexShaderBody() const
9228 {
9229     return "#version 400\n"
9230            "\n"
9231            "#extension GL_ARB_shader_subroutine : require\n"
9232            "\n"
9233            "out VS_DATA\n"
9234            "{\n"
9235            "    vec4 vs_data;\n"
9236            "} result;\n"
9237            "\n"
9238            "subroutine void subroutineTypeVS(out vec4 result);\n"
9239            "\n"
9240            "subroutine(subroutineTypeVS) void subroutine1(out vec4 result)\n"
9241            "{\n"
9242            "    result = vec4(1, 2, 3, 4);\n"
9243            "}\n"
9244            "\n"
9245            "subroutine uniform subroutineTypeVS function;\n"
9246            "\n"
9247            "void main()\n"
9248            "{\n"
9249            "    function(result.vs_data);\n"
9250            "}\n";
9251 }
9252 
9253 /** Initializes all buffers and GL objects required to run the test. */
initTest()9254 void FunctionalTest17::initTest()
9255 {
9256     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
9257 
9258     /* Configure GL_PATCH_VERTICES so that TC only takes a single patch vertex */
9259     gl.patchParameteri(GL_PATCH_VERTICES, 1);
9260     GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteri() call failed.");
9261 
9262     /* Generate & bind a VAO */
9263     gl.genVertexArrays(1, &m_vao_id);
9264     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
9265 
9266     gl.bindVertexArray(m_vao_id);
9267     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
9268 
9269     /* Set up test program object */
9270     std::string fs_body = getFragmentShaderBody();
9271     std::string gs_body = getGeometryShaderBody();
9272     std::string tc_body = getTessellationControlShaderBody();
9273     std::string te_body = getTessellationEvaluationShaderBody();
9274     std::string vs_body = getVertexShaderBody();
9275 
9276     if (!Utils::buildProgram(gl, vs_body, tc_body, te_body, gs_body, fs_body, DE_NULL, /* xfb_varyings */
9277                              DE_NULL,                                                  /* n_xfb_varyings */
9278                              &m_vs_id, &m_tc_id, &m_te_id, &m_gs_id, &m_fs_id, &m_po_id))
9279     {
9280         TCU_FAIL("Failed to link test program object");
9281     }
9282 
9283     /* Set up a texture object that will be used as a color attachment */
9284     gl.genTextures(1, &m_to_id);
9285     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed.");
9286 
9287     gl.bindTexture(GL_TEXTURE_2D, m_to_id);
9288     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
9289 
9290     gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
9291                     GL_RGBA32F, m_to_width, m_to_height);
9292     GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed.");
9293 
9294     /* Set up FBO */
9295     gl.genFramebuffers(1, &m_fbo_id);
9296     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed.");
9297 
9298     gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
9299     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed.");
9300 
9301     gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0 /* level */);
9302     GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
9303 
9304     /* Make sure glReadPixels() does not return misaligned data */
9305     gl.pixelStorei(GL_PACK_ALIGNMENT, 1);
9306     GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call failed.");
9307 
9308     /* Initialize a buffer that will be used to store rendered data */
9309     m_to_data = new float[m_to_width * m_to_height * 4 /* rgba */];
9310 }
9311 
9312 /** Executes test iteration.
9313  *
9314  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
9315  */
iterate()9316 tcu::TestNode::IterateResult FunctionalTest17::iterate()
9317 {
9318     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
9319 
9320     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
9321     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
9322     {
9323         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
9324     }
9325 
9326     initTest();
9327 
9328     /* Use the test program to render a full-screen test quad */
9329     gl.useProgram(m_po_id);
9330     GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
9331 
9332     gl.drawArrays(GL_PATCHES, 0 /* first */, 1 /* count */);
9333     GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
9334 
9335     /* Read back the data that was rendered */
9336     gl.readPixels(0, /* x */
9337                   0, /* y */
9338                   m_to_width, m_to_height, GL_RGBA, GL_FLOAT, m_to_data);
9339     GLU_EXPECT_NO_ERROR(gl.getError(), "glReaDPixels() call failed.");
9340 
9341     /* Verify the data */
9342     verifyRenderedData();
9343 
9344     /** All done */
9345     if (m_has_test_passed)
9346     {
9347         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
9348     }
9349     else
9350     {
9351         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
9352     }
9353 
9354     return STOP;
9355 }
9356 
9357 /** Verifies the data that have been rendered by the test program.
9358  *
9359  *  It is assumed the rendered data have already been copied to
9360  *  m_to_data.
9361  *
9362  *  If the rendered data is found to be invalid, m_has_test_passed
9363  *  will be set to false.
9364  **/
verifyRenderedData()9365 void FunctionalTest17::verifyRenderedData()
9366 {
9367     const float epsilon          = 1e-5f;
9368     const float expected_data[4] = {15.0f, 20.0f, 25.0f, 30.0f};
9369 
9370     for (unsigned int y = 0; y < m_to_height && m_has_test_passed; ++y)
9371     {
9372         const float *row_ptr = m_to_data + y * 4 /* rgba */ * m_to_width;
9373 
9374         for (unsigned int x = 0; x < m_to_width && m_has_test_passed; ++x)
9375         {
9376             const float *pixel_ptr = row_ptr + 4 /* rgba */ * x;
9377 
9378             if (de::abs(pixel_ptr[0] - expected_data[0]) > epsilon ||
9379                 de::abs(pixel_ptr[1] - expected_data[1]) > epsilon ||
9380                 de::abs(pixel_ptr[2] - expected_data[2]) > epsilon ||
9381                 de::abs(pixel_ptr[3] - expected_data[3]) > epsilon)
9382             {
9383                 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid texel found at (" << x << ", " << y
9384                                    << "): "
9385                                       "expected:("
9386                                    << expected_data[0] << ", " << expected_data[1] << ", " << expected_data[2] << ", "
9387                                    << expected_data[3] << "), found:(" << pixel_ptr[0] << ", " << pixel_ptr[1] << ", "
9388                                    << pixel_ptr[2] << ", " << pixel_ptr[3] << ")." << tcu::TestLog::EndMessage;
9389 
9390                 m_has_test_passed = false;
9391             }
9392         } /* for (all columns) */
9393     }     /* for (all rows) */
9394 }
9395 
9396 /** Constructor.
9397  *
9398  *  @param context Rendering context.
9399  *
9400  **/
FunctionalTest18_19(deqp::Context & context)9401 FunctionalTest18_19::FunctionalTest18_19(deqp::Context &context)
9402     : TestCase(context, "control_flow_and_returned_subroutine_values_used_as_subroutine_input",
9403                "Makes sure that calling a subroutine with argument value returned by "
9404                "another subroutine works correctly. Also checks that subroutine and "
9405                "subroutine uniforms work as expected when used in connection with control "
9406                "flow functions.")
9407     , m_has_test_passed(true)
9408     , m_n_points_to_draw(16) /* arbitrary value */
9409     , m_po_id(0)
9410     , m_po_subroutine_divide_by_two_location(GL_INVALID_INDEX)
9411     , m_po_subroutine_multiply_by_four_location(GL_INVALID_INDEX)
9412     , m_po_subroutine_returns_false_location(GL_INVALID_INDEX)
9413     , m_po_subroutine_returns_true_location(GL_INVALID_INDEX)
9414     , m_po_subroutine_uniform_bool_operator1(-1)
9415     , m_po_subroutine_uniform_bool_operator2(-1)
9416     , m_po_subroutine_uniform_vec4_processor1(-1)
9417     , m_po_subroutine_uniform_vec4_processor2(-1)
9418     , m_xfb_bo_id(0)
9419     , m_vao_id(0)
9420     , m_vs_id(0)
9421 {
9422     /* Left blank intentionally */
9423 }
9424 
9425 /** De-initializes all GL objects that may have been created during test execution */
deinit()9426 void FunctionalTest18_19::deinit()
9427 {
9428     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
9429 
9430     if (m_po_id != 0)
9431     {
9432         gl.deleteProgram(m_po_id);
9433 
9434         m_po_id = 0;
9435     }
9436 
9437     if (m_vao_id != 0)
9438     {
9439         gl.deleteVertexArrays(1, &m_vao_id);
9440 
9441         m_vao_id = 0;
9442     }
9443 
9444     if (m_vs_id != 0)
9445     {
9446         gl.deleteShader(m_vs_id);
9447 
9448         m_vs_id = 0;
9449     }
9450 
9451     if (m_xfb_bo_id != 0)
9452     {
9453         gl.deleteBuffers(1, &m_xfb_bo_id);
9454 
9455         m_xfb_bo_id = 0;
9456     }
9457 }
9458 
9459 /** Executes a single test iteration using user-specified properties. If the
9460  *  iterations fails, m_has_test_passed is set to false.
9461  *
9462  *  @param bool_operator1_subroutine_location Location of a subroutine to be assigned to
9463  *                                            bool_operator1 subroutine uniform.
9464  *  @param bool_operator2_subroutine_location Location of a subroutine to be assigned to
9465  *                                            bool_operator2 subroutine uniform.
9466  *  @param vec4_operator1_subroutine_location Location of a subroutine to be assigned to
9467  *                                            vec4_operator1 subroutine uniform.
9468  *  @param vec4_operator2_subroutine_location Location of a subroutine to be assigned to
9469  *                                            vec4_operator2 subroutine uniform.
9470  &**/
executeTest(glw::GLuint bool_operator1_subroutine_location,glw::GLuint bool_operator2_subroutine_location,glw::GLuint vec4_operator1_subroutine_location,glw::GLuint vec4_operator2_subroutine_location)9471 void FunctionalTest18_19::executeTest(glw::GLuint bool_operator1_subroutine_location,
9472                                       glw::GLuint bool_operator2_subroutine_location,
9473                                       glw::GLuint vec4_operator1_subroutine_location,
9474                                       glw::GLuint vec4_operator2_subroutine_location)
9475 {
9476     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
9477 
9478     /* Set up subroutines */
9479     glw::GLuint subroutine_configuration[4 /* total number of subroutines */] = {0};
9480 
9481     subroutine_configuration[m_po_subroutine_uniform_bool_operator1]  = bool_operator1_subroutine_location;
9482     subroutine_configuration[m_po_subroutine_uniform_bool_operator2]  = bool_operator2_subroutine_location;
9483     subroutine_configuration[m_po_subroutine_uniform_vec4_processor1] = vec4_operator1_subroutine_location;
9484     subroutine_configuration[m_po_subroutine_uniform_vec4_processor2] = vec4_operator2_subroutine_location;
9485 
9486     gl.useProgram(m_po_id);
9487     GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
9488 
9489     gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, 4 /* count */, subroutine_configuration);
9490     GLU_EXPECT_NO_ERROR(gl.getError(), "glUniformSubroutinesuiv() call failed");
9491 
9492     /* Draw test-specific number of points */
9493     gl.beginTransformFeedback(GL_POINTS);
9494     GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed");
9495     {
9496         gl.drawArrays(GL_POINTS, 0 /* first */, m_n_points_to_draw);
9497         GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed");
9498     }
9499     gl.endTransformFeedback();
9500     GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed");
9501 
9502     /* Map the BO storage into process space */
9503     const glw::GLvoid *xfb_data_ptr = gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
9504     GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer() call failed.");
9505 
9506     verifyXFBData(xfb_data_ptr, bool_operator1_subroutine_location, bool_operator2_subroutine_location,
9507                   vec4_operator1_subroutine_location, vec4_operator2_subroutine_location);
9508 
9509     /* Unmap BO storage */
9510     gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
9511     GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
9512 }
9513 
9514 /** Retrieves body of a vertex shader to be used by the test. */
getVertexShaderBody() const9515 std::string FunctionalTest18_19::getVertexShaderBody() const
9516 {
9517     return "#version 400\n"
9518            "\n"
9519            "subroutine bool bool_processor();\n"
9520            "subroutine vec4 vec4_processor(in vec4 iparam);\n"
9521            "\n"
9522            "subroutine(bool_processor) bool returnsFalse()\n"
9523            "{\n"
9524            "    return false;\n"
9525            "}\n"
9526            "\n"
9527            "subroutine(bool_processor) bool returnsTrue()\n"
9528            "{\n"
9529            "    return true;\n"
9530            "}\n"
9531            "\n"
9532            "subroutine(vec4_processor) vec4 divideByTwo(in vec4 iparam)\n"
9533            "{\n"
9534            "    return iparam * vec4(0.5);\n"
9535            "}\n"
9536            "\n"
9537            "subroutine(vec4_processor) vec4 multiplyByFour(in vec4 iparam)\n"
9538            "{\n"
9539            "    return iparam * vec4(4.0);\n"
9540            "}\n"
9541            "\n"
9542            "subroutine uniform bool_processor bool_operator1;\n"
9543            "subroutine uniform bool_processor bool_operator2;\n"
9544            "subroutine uniform vec4_processor vec4_operator1;\n"
9545            "subroutine uniform vec4_processor vec4_operator2;\n"
9546            "\n"
9547            "out float result;\n"
9548            "\n"
9549            "void main()\n"
9550            "{\n"
9551            "    if (bool_operator1() )\n"
9552            "    {\n"
9553            "        float value = float( (3 * gl_VertexID + 1) * 2);\n"
9554            "\n"
9555            "        while (bool_operator1() )\n"
9556            "        {\n"
9557            "            value /= float(gl_VertexID + 2);\n"
9558            "\n"
9559            "            if (value <= 1.0f) break;\n"
9560            "        }\n"
9561            "\n"
9562            "        result = value;\n"
9563            "    }\n"
9564            "    else\n"
9565            "    {\n"
9566            "        vec4 value = vec4(gl_VertexID,     gl_VertexID + 1,\n"
9567            "                          gl_VertexID + 2, gl_VertexID + 3);\n"
9568            "\n"
9569            "        switch (gl_VertexID % 2)\n"
9570            "        {\n"
9571            "            case 0:\n"
9572            "            {\n"
9573            "                for (int iteration = 0; iteration < gl_VertexID && bool_operator2(); ++iteration)\n"
9574            "                {\n"
9575            "                    value = vec4_operator2(vec4_operator1(value));\n"
9576            "                }\n"
9577            "\n"
9578            "                break;\n"
9579            "            }\n"
9580            "\n"
9581            "            case 1:\n"
9582            "            {\n"
9583            "                for (int iteration = 0; iteration < gl_VertexID * 2; ++iteration)\n"
9584            "                {\n"
9585            "                    value = vec4_operator1(vec4_operator2(value));\n"
9586            "                }\n"
9587            "\n"
9588            "                break;\n"
9589            "            }\n"
9590            "        }\n"
9591            "\n"
9592            "        result = value.x + value.y + value.z + value.w;\n"
9593            "\n"
9594            "    }\n"
9595            "}\n";
9596 }
9597 
9598 /** Initializes all GL objects required to run the test. */
initTest()9599 void FunctionalTest18_19::initTest()
9600 {
9601     const glw::Functions &gl      = m_context.getRenderContext().getFunctions();
9602     const char *varyings[1]       = {"result"};
9603     std::string vs_body           = getVertexShaderBody();
9604     const unsigned int n_varyings = sizeof(varyings) / sizeof(varyings[0]);
9605 
9606     if (!Utils::buildProgram(gl, vs_body, "",                         /* tc_body */
9607                              "",                                      /* te_body */
9608                              "",                                      /* gs_body */
9609                              "",                                      /* fs_body */
9610                              varyings, n_varyings, &m_vs_id, DE_NULL, /* out_tc_id */
9611                              DE_NULL,                                 /* out_te_id */
9612                              DE_NULL,                                 /* out_gs_id */
9613                              DE_NULL,                                 /* out_fs_id */
9614                              &m_po_id))
9615     {
9616         TCU_FAIL("Failed to build test program object");
9617     }
9618 
9619     /* Retrieve subroutine & subroutine uniform locations */
9620     m_po_subroutine_divide_by_two_location    = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "divideByTwo");
9621     m_po_subroutine_multiply_by_four_location = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "multiplyByFour");
9622     m_po_subroutine_returns_false_location    = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "returnsFalse");
9623     m_po_subroutine_returns_true_location     = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "returnsTrue");
9624     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineIndex() call(s) failed");
9625 
9626     if (m_po_subroutine_divide_by_two_location == GL_INVALID_INDEX ||
9627         m_po_subroutine_multiply_by_four_location == GL_INVALID_INDEX ||
9628         m_po_subroutine_returns_false_location == GL_INVALID_INDEX ||
9629         m_po_subroutine_returns_true_location == GL_INVALID_INDEX)
9630     {
9631         TCU_FAIL("glGetSubroutineIndex() returned GL_INVALID_INDEX for a valid subroutine");
9632     }
9633 
9634     m_po_subroutine_uniform_bool_operator1 =
9635         gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "bool_operator1");
9636     m_po_subroutine_uniform_bool_operator2 =
9637         gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "bool_operator2");
9638     m_po_subroutine_uniform_vec4_processor1 =
9639         gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "vec4_operator1");
9640     m_po_subroutine_uniform_vec4_processor2 =
9641         gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "vec4_operator2");
9642     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineUniformLocation() call(s) failed");
9643 
9644     if (m_po_subroutine_uniform_bool_operator1 == -1 || m_po_subroutine_uniform_bool_operator2 == -1 ||
9645         m_po_subroutine_uniform_vec4_processor1 == -1 || m_po_subroutine_uniform_vec4_processor2 == -1)
9646     {
9647         TCU_FAIL("glGetSubroutineUniformLocation() returned -1 for an active subroutine uniform");
9648     }
9649 
9650     /* Set up XFB BO */
9651     const unsigned int bo_size = static_cast<unsigned int>(sizeof(float) * m_n_points_to_draw);
9652 
9653     gl.genBuffers(1, &m_xfb_bo_id);
9654     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
9655 
9656     gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_xfb_bo_id);
9657     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
9658 
9659     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_xfb_bo_id);
9660     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed.");
9661 
9662     gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, DE_NULL /* data */, GL_STATIC_COPY);
9663     GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
9664 
9665     /* Set up a VAO */
9666     gl.genVertexArrays(1, &m_vao_id);
9667     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
9668 
9669     gl.bindVertexArray(m_vao_id);
9670     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
9671 }
9672 
9673 /** Executes test iteration.
9674  *
9675  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
9676  */
iterate()9677 tcu::TestNode::IterateResult FunctionalTest18_19::iterate()
9678 {
9679     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
9680     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
9681     {
9682         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
9683     }
9684 
9685     /* Initialize all GL objects required to run the test */
9686     initTest();
9687 
9688     /* Iterate over all subroutine permutations */
9689     const glw::GLuint subroutine_bool_operators[] = {m_po_subroutine_returns_false_location,
9690                                                      m_po_subroutine_returns_true_location};
9691     const unsigned int n_subroutine_bool_operators =
9692         sizeof(subroutine_bool_operators) / sizeof(subroutine_bool_operators[0]);
9693 
9694     const glw::GLuint subroutine_vec4_operators[] = {m_po_subroutine_divide_by_two_location,
9695                                                      m_po_subroutine_multiply_by_four_location};
9696     const unsigned int n_subroutine_vec4_operators =
9697         sizeof(subroutine_vec4_operators) / sizeof(subroutine_vec4_operators[0]);
9698 
9699     for (unsigned int n_subroutine_uniform_bool_operator1 = 0;
9700          n_subroutine_uniform_bool_operator1 < n_subroutine_bool_operators; ++n_subroutine_uniform_bool_operator1)
9701     {
9702         for (unsigned int n_subroutine_uniform_bool_operator2 = 0;
9703              n_subroutine_uniform_bool_operator2 < n_subroutine_bool_operators; ++n_subroutine_uniform_bool_operator2)
9704         {
9705             for (unsigned int n_subroutine_uniform_vec4_operator1 = 0;
9706                  n_subroutine_uniform_vec4_operator1 < n_subroutine_vec4_operators;
9707                  ++n_subroutine_uniform_vec4_operator1)
9708             {
9709                 for (unsigned int n_subroutine_uniform_vec4_operator2 = 0;
9710                      n_subroutine_uniform_vec4_operator2 < n_subroutine_vec4_operators;
9711                      ++n_subroutine_uniform_vec4_operator2)
9712                 {
9713                     executeTest(subroutine_bool_operators[n_subroutine_uniform_bool_operator1],
9714                                 subroutine_bool_operators[n_subroutine_uniform_bool_operator2],
9715                                 subroutine_vec4_operators[n_subroutine_uniform_vec4_operator1],
9716                                 subroutine_vec4_operators[n_subroutine_uniform_vec4_operator2]);
9717                 } /* for (all subroutine vec4 operator subroutines used for processor2) */
9718             }     /* for (all subroutine vec4 operator subroutines used for processor1) */
9719         }         /* for (all subroutine bool operator subroutines used for operator2) */
9720     }             /* for (all subroutine bool operator subroutines used for operator1) */
9721 
9722     /* All done */
9723     if (m_has_test_passed)
9724     {
9725         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
9726     }
9727     else
9728     {
9729         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
9730     }
9731 
9732     return STOP;
9733 }
9734 
9735 /** Divides input argument by two. The result value is returned to the
9736  *  caller.
9737  *
9738  *  @param data Input value.
9739  *
9740  *  @return As per description.
9741  **/
vec4operator_div2(tcu::Vec4 data)9742 tcu::Vec4 FunctionalTest18_19::vec4operator_div2(tcu::Vec4 data)
9743 {
9744     return data * 0.5f;
9745 }
9746 
9747 /** Multiplies input argument by four. The result value is returned to the
9748  *  caller.
9749  *
9750  *  @param data Input value.
9751  *
9752  *  @return As per description.
9753  **/
vec4operator_mul4(tcu::Vec4 data)9754 tcu::Vec4 FunctionalTest18_19::vec4operator_mul4(tcu::Vec4 data)
9755 {
9756     return data * 4.0f;
9757 }
9758 
9759 /** Verifies data XFBed out by the vertex shader. It is assumed the subroutines were configured
9760  *  as per passed arguments, prior to the draw call.
9761  *
9762  *  If the result data is found to be invalid, m_has_test_passed is set to false.
9763  *
9764  *  @param data                               XFBed data.
9765  *  @param bool_operator1_subroutine_location Location of a subroutine to be assigned to
9766  *                                            bool_operator1 subroutine uniform.
9767  *  @param bool_operator2_subroutine_location Location of a subroutine to be assigned to
9768  *                                            bool_operator2 subroutine uniform.
9769  *  @param vec4_operator1_subroutine_location Location of a subroutine to be assigned to
9770  *                                            vec4_operator1 subroutine uniform.
9771  *  @param vec4_operator2_subroutine_location Location of a subroutine to be assigned to
9772  *                                            vec4_operator2 subroutine uniform.
9773  */
verifyXFBData(const glw::GLvoid * data,glw::GLuint bool_operator1_subroutine_location,glw::GLuint bool_operator2_subroutine_location,glw::GLuint vec4_operator1_subroutine_location,glw::GLuint vec4_operator2_subroutine_location)9774 void FunctionalTest18_19::verifyXFBData(const glw::GLvoid *data, glw::GLuint bool_operator1_subroutine_location,
9775                                         glw::GLuint bool_operator2_subroutine_location,
9776                                         glw::GLuint vec4_operator1_subroutine_location,
9777                                         glw::GLuint vec4_operator2_subroutine_location)
9778 {
9779     bool bool_operator1_result         = false;
9780     bool bool_operator2_result         = false;
9781     const float epsilon                = 1e-5f;
9782     PFNVEC4OPERATORPROC pVec4Operator1 = NULL;
9783     PFNVEC4OPERATORPROC pVec4Operator2 = NULL;
9784     const glw::GLfloat *traveller_ptr  = (const glw::GLfloat *)data;
9785 
9786     bool_operator1_result = (bool_operator1_subroutine_location == m_po_subroutine_returns_true_location);
9787     bool_operator2_result = (bool_operator2_subroutine_location == m_po_subroutine_returns_true_location);
9788     pVec4Operator1        = (vec4_operator1_subroutine_location == m_po_subroutine_divide_by_two_location) ?
9789                                 vec4operator_div2 :
9790                                 vec4operator_mul4;
9791     pVec4Operator2        = (vec4_operator2_subroutine_location == m_po_subroutine_divide_by_two_location) ?
9792                                 vec4operator_div2 :
9793                                 vec4operator_mul4;
9794 
9795     for (unsigned int n_vertex = 0; n_vertex < m_n_points_to_draw; ++n_vertex)
9796     {
9797         float expected_value = 0.0f;
9798 
9799         if (bool_operator1_result)
9800         {
9801             float value = float((3 * n_vertex + 1) * 2);
9802 
9803             while (bool_operator1_result)
9804             {
9805                 value /= float(n_vertex + 2);
9806 
9807                 if (value <= 1.0f)
9808                     break;
9809             }
9810 
9811             expected_value = value;
9812         }
9813         else
9814         {
9815             tcu::Vec4 value((float)n_vertex, (float)n_vertex + 1, (float)n_vertex + 2, (float)n_vertex + 3);
9816 
9817             switch (n_vertex % 2)
9818             {
9819             case 0:
9820             {
9821                 for (unsigned int iteration = 0; iteration < n_vertex && bool_operator2_result; ++iteration)
9822                 {
9823                     value = pVec4Operator2(pVec4Operator1(value));
9824                 }
9825 
9826                 break;
9827             }
9828 
9829             case 1:
9830             {
9831                 for (unsigned int iteration = 0; iteration < n_vertex * 2; ++iteration)
9832                 {
9833                     value = pVec4Operator1(pVec4Operator2(value));
9834                 }
9835 
9836                 break;
9837             }
9838             } /* switch (n_vertex % 2) */
9839 
9840             expected_value = value.x() + value.y() + value.z() + value.w();
9841         }
9842 
9843         if (de::abs(expected_value - *traveller_ptr) > epsilon)
9844         {
9845             m_testCtx.getLog() << tcu::TestLog::Message << "XFBed data was found to be invalid at index [" << n_vertex
9846                                << "]"
9847                                   "for the following subroutine location configuration:"
9848                                   " bool_operator1_subroutine_location:["
9849                                << bool_operator1_subroutine_location
9850                                << "]"
9851                                   " bool_operator2_subroutine_location:["
9852                                << bool_operator2_subroutine_location
9853                                << "]"
9854                                   " vec4_operator1_subroutine_location:["
9855                                << vec4_operator1_subroutine_location
9856                                << "]"
9857                                   " vec4_operator2_subroutine_location:["
9858                                << vec4_operator2_subroutine_location
9859                                << "];"
9860                                   " expected data:"
9861                                << expected_value << ", found:" << *traveller_ptr << tcu::TestLog::EndMessage;
9862 
9863             m_has_test_passed = false;
9864         }
9865 
9866         ++traveller_ptr;
9867     } /* for (all drawn points) */
9868 }
9869 
9870 /** Constructor.
9871  *
9872  *  @param context Rendering context.
9873  *
9874  **/
NegativeTest1(deqp::Context & context)9875 NegativeTest1::NegativeTest1(deqp::Context &context)
9876     : TestCase(context, "subroutine_errors",
9877                "Verifies all GL_INVALID_OPERATION, GL_INVALID_VALUE, GL_INVALID ENUM "
9878                "errors related to subroutine usage are properly generated.")
9879     , m_has_test_passed(true)
9880     , m_po_active_subroutine_uniform_locations(0)
9881     , m_po_active_subroutine_uniforms(0)
9882     , m_po_active_subroutines(0)
9883     , m_po_subroutine_uniform_function_index(-1)
9884     , m_po_subroutine_uniform_function2_index(-1)
9885     , m_po_subroutine_test1_index(GL_INVALID_INDEX)
9886     , m_po_subroutine_test2_index(GL_INVALID_INDEX)
9887     , m_po_subroutine_test3_index(GL_INVALID_INDEX)
9888     , m_po_not_linked_id(0)
9889     , m_po_id(0)
9890     , m_vs_id(0)
9891 {
9892     /* Left blank intentionally */
9893 }
9894 
9895 /** Deinitializes all GL objects that may have been created during
9896  *  test execution.
9897  **/
deinit()9898 void NegativeTest1::deinit()
9899 {
9900     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
9901 
9902     if (m_po_id != 0)
9903     {
9904         gl.deleteProgram(m_po_id);
9905 
9906         m_po_id = 0;
9907     }
9908 
9909     if (m_po_not_linked_id != 0)
9910     {
9911         gl.deleteProgram(m_po_not_linked_id);
9912 
9913         m_po_not_linked_id = 0;
9914     }
9915 
9916     if (m_vs_id != 0)
9917     {
9918         gl.deleteShader(m_vs_id);
9919 
9920         m_vs_id = 0;
9921     }
9922 }
9923 
9924 /** Initializes all GL objects required to run the test.  */
initTest()9925 void NegativeTest1::initTest()
9926 {
9927     glw::GLint compile_status = GL_FALSE;
9928     const glw::Functions &gl  = m_context.getRenderContext().getFunctions();
9929 
9930     /* Create program objects */
9931     m_po_not_linked_id = gl.createProgram();
9932     m_po_id            = gl.createProgram();
9933     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call(s) failed.");
9934 
9935     /* Create vertex shader object */
9936     m_vs_id = gl.createShader(GL_VERTEX_SHADER);
9937     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
9938 
9939     /* Set up vertex shader */
9940     const char *vs_body = "#version 400\n"
9941                           "\n"
9942                           "#extension GL_ARB_shader_subroutine : require\n"
9943                           "\n"
9944                           "subroutine void subroutineType (out ivec2 arg);\n"
9945                           "subroutine void subroutineType2(out ivec4 arg);\n"
9946                           "\n"
9947                           "subroutine(subroutineType) void test1(out ivec2 arg)\n"
9948                           "{\n"
9949                           "    arg = ivec2(1, 2);\n"
9950                           "}\n"
9951                           "subroutine(subroutineType) void test2(out ivec2 arg)\n"
9952                           "{\n"
9953                           "    arg = ivec2(3,4);\n"
9954                           "}\n"
9955                           "subroutine(subroutineType2) void test3(out ivec4 arg)\n"
9956                           "{\n"
9957                           "    arg = ivec4(1, 2, 3, 4);\n"
9958                           "}\n"
9959                           "\n"
9960                           "subroutine uniform subroutineType  function;\n"
9961                           "subroutine uniform subroutineType2 function2;\n"
9962                           "\n"
9963                           "void main()\n"
9964                           "{\n"
9965                           "    ivec2 test;\n"
9966                           "    ivec4 test2;\n"
9967                           "\n"
9968                           "    function(test);\n"
9969                           "\n"
9970                           "    if (test.x > 2)\n"
9971                           "    {\n"
9972                           "        gl_Position = vec4(1);\n"
9973                           "    }\n"
9974                           "    else\n"
9975                           "    {\n"
9976                           "        function2(test2);\n"
9977                           "\n"
9978                           "        gl_Position = vec4(float(test2.x) );\n"
9979                           "    }\n"
9980                           "}\n";
9981 
9982     gl.shaderSource(m_vs_id, 1 /* count */, &vs_body, DE_NULL /* length */);
9983     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed");
9984 
9985     gl.compileShader(m_vs_id);
9986     GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed");
9987 
9988     gl.getShaderiv(m_vs_id, GL_COMPILE_STATUS, &compile_status);
9989     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed");
9990 
9991     if (compile_status == GL_FALSE)
9992     {
9993         TCU_FAIL("Shader compilation failed");
9994     }
9995 
9996     /* Set up & link the test program object */
9997     glw::GLint link_status = GL_FALSE;
9998 
9999     gl.attachShader(m_po_id, m_vs_id);
10000     GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
10001 
10002     gl.linkProgram(m_po_id);
10003     GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
10004 
10005     gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
10006     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
10007 
10008     if (link_status == GL_FALSE)
10009     {
10010         TCU_FAIL("Program linking failed");
10011     }
10012 
10013     /* Query test program object's properties */
10014     gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS,
10015                          &m_po_active_subroutine_uniform_locations);
10016     gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORMS, &m_po_active_subroutine_uniforms);
10017     gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINES, &m_po_active_subroutines);
10018     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramStageiv() call(s) failed.");
10019 
10020     if (m_po_active_subroutine_uniform_locations != 2)
10021     {
10022         TCU_FAIL("Invalid GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS value returned");
10023     }
10024 
10025     m_po_subroutine_test1_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "test1");
10026     m_po_subroutine_test2_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "test2");
10027     m_po_subroutine_test3_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "test3");
10028     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineIndex() call(s) failed.");
10029 
10030     if (m_po_subroutine_test1_index == GL_INVALID_INDEX || m_po_subroutine_test2_index == GL_INVALID_INDEX ||
10031         m_po_subroutine_test3_index == GL_INVALID_INDEX)
10032     {
10033         TCU_FAIL("Invalid subroutine index returned");
10034     }
10035 
10036     m_po_subroutine_uniform_function_index  = gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "function");
10037     m_po_subroutine_uniform_function2_index = gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "function2");
10038     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineUniformLocation() call(s) failed.");
10039 
10040     if (m_po_subroutine_uniform_function_index == -1 || m_po_subroutine_uniform_function2_index == -1)
10041     {
10042         TCU_FAIL("Invalid subroutine uniform index returned");
10043     }
10044 }
10045 
10046 /** Executes test iteration.
10047  *
10048  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
10049  */
iterate()10050 tcu::TestNode::IterateResult NegativeTest1::iterate()
10051 {
10052     glw::GLenum error_code   = GL_NO_ERROR;
10053     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
10054 
10055     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
10056     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
10057     {
10058         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
10059     }
10060 
10061     /* Initialize GL objects required to run the test */
10062     initTest();
10063 
10064     /* The error INVALID_OPERATION is generated by GetSubroutineUniformLocation
10065      * if the program object identified by <program> has not been successfully
10066      * linked.
10067      */
10068     gl.getSubroutineUniformLocation(m_po_not_linked_id, GL_FRAGMENT_SHADER, "subroutine_uniform_name");
10069 
10070     error_code = gl.getError();
10071 
10072     if (error_code != GL_INVALID_OPERATION)
10073     {
10074         m_testCtx.getLog() << tcu::TestLog::Message
10075                            << "glGetSubroutineUniformLocation() does not generate GL_INVALID_OPERATION "
10076                               "error code when called for a non-linked program object."
10077                            << tcu::TestLog::EndMessage;
10078 
10079         m_has_test_passed = false;
10080     }
10081 
10082     /* The error INVALID_VALUE is generated by GetActiveSubroutineUniformiv or
10083      * GetActiveSubroutineUniformName if <index> is greater than or equal to the
10084      * value of ACTIVE_SUBROUTINE_UNIFORMS for the shader stage.
10085      */
10086     glw::GLint temp_length = 0;
10087     glw::GLint temp_values = 0;
10088 
10089     gl.getActiveSubroutineUniformiv(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutine_uniforms,
10090                                     GL_NUM_COMPATIBLE_SUBROUTINES, &temp_values);
10091     error_code = gl.getError();
10092 
10093     if (error_code == GL_INVALID_VALUE)
10094     {
10095         gl.getActiveSubroutineUniformiv(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutine_uniforms + 1,
10096                                         GL_NUM_COMPATIBLE_SUBROUTINES, &temp_values);
10097 
10098         error_code = gl.getError();
10099     }
10100 
10101     if (error_code != GL_INVALID_VALUE)
10102     {
10103         m_testCtx.getLog() << tcu::TestLog::Message
10104                            << "glGetActiveSubroutineUniformiv() does not generate GL_INVALID_VALUE "
10105                               "when passed <index> argument that is greater than or equal to "
10106                               "the value of GL_ACTIVE_SUBROUTINE_UNIFORMS."
10107                            << tcu::TestLog::EndMessage;
10108 
10109         m_has_test_passed = false;
10110     }
10111 
10112     gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutine_uniforms, 0, /* bufsize */
10113                                       &temp_length, DE_NULL);                                        /* name */
10114     error_code = gl.getError();
10115 
10116     if (error_code == GL_INVALID_VALUE)
10117     {
10118         gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutine_uniforms + 1,
10119                                           0,                      /* bufsize */
10120                                           &temp_length, DE_NULL); /* name */
10121 
10122         error_code = gl.getError();
10123     }
10124 
10125     if (error_code != GL_INVALID_VALUE)
10126     {
10127         m_testCtx.getLog() << tcu::TestLog::Message
10128                            << "glGetActiveSubroutineUniformName() does not generate GL_INVALID_VALUE "
10129                               "when passed <index> argument that is greater than or equal to "
10130                               "the value of GL_ACTIVE_SUBROUTINE_UNIFORMS."
10131                            << tcu::TestLog::EndMessage;
10132 
10133         m_has_test_passed = false;
10134     }
10135 
10136     /* The error INVALID_VALUE is generated by GetActiveSubroutineName if <index>
10137      * is greater than or equal to the value of ACTIVE_SUBROUTINES for the shader
10138      * stage.
10139      */
10140     gl.getActiveSubroutineName(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutines, 0, /* bufsize */
10141                                &temp_length, DE_NULL);                                /* name */
10142     error_code = gl.getError();
10143 
10144     if (error_code == GL_INVALID_VALUE)
10145     {
10146         gl.getActiveSubroutineName(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutines + 1, 0, /* bufsize */
10147                                    &temp_length, DE_NULL);                                    /* name */
10148 
10149         error_code = gl.getError();
10150     }
10151 
10152     if (error_code != GL_INVALID_VALUE)
10153     {
10154         m_testCtx.getLog() << tcu::TestLog::Message
10155                            << "glGetActiveSubroutineName() does not generate GL_INVALID_VALUE "
10156                               "when passed <index> argument that is greater than or equal to "
10157                               "the value of GL_ACTIVE_SUBROUTINES."
10158                            << tcu::TestLog::EndMessage;
10159 
10160         m_has_test_passed = false;
10161     }
10162 
10163     /* The error INVALID_VALUE is generated by UniformSubroutinesuiv if <count>
10164      * is not equal to the value of ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS for the
10165      * shader stage <shadertype>.
10166      */
10167     glw::GLuint index = 0;
10168 
10169     gl.useProgram(m_po_id);
10170     GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
10171 
10172     gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations - 1, &index);
10173     error_code = gl.getError();
10174 
10175     if (error_code == GL_INVALID_VALUE)
10176     {
10177         gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations + 1, &index);
10178 
10179         error_code = gl.getError();
10180     }
10181 
10182     if (error_code != GL_INVALID_VALUE)
10183     {
10184         m_testCtx.getLog() << tcu::TestLog::Message
10185                            << "glUniformSubroutinesiv() does not generate GL_INVALID_VALUE "
10186                               "when passed <count> argument that is not equal to the value of "
10187                               "GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS."
10188                            << tcu::TestLog::EndMessage;
10189 
10190         m_has_test_passed = false;
10191     }
10192 
10193     /* The error INVALID_VALUE is generated by UniformSubroutinesuiv if any value
10194      * in <indices> is greater than or equal to the value of ACTIVE_SUBROUTINES
10195      * for the shader stage.
10196      */
10197     glw::GLuint invalid_subroutine_indices[4] = {(GLuint)m_po_active_subroutines, (GLuint)m_po_active_subroutines,
10198                                                  (GLuint)m_po_active_subroutines + 1,
10199                                                  (GLuint)m_po_active_subroutines + 1};
10200 
10201     gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations, /* count */
10202                              invalid_subroutine_indices + 0);
10203     error_code = gl.getError();
10204 
10205     if (error_code == GL_INVALID_VALUE)
10206     {
10207         gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations,
10208                                  invalid_subroutine_indices + 2);
10209 
10210         error_code = gl.getError();
10211     }
10212 
10213     if (error_code != GL_INVALID_VALUE)
10214     {
10215         m_testCtx.getLog() << tcu::TestLog::Message
10216                            << "glUniformSubroutinesuiv() does not generate GL_INVALID_VALUE "
10217                               "when the value passed via <indices> argument is greater than "
10218                               "or equal to the value of GL_ACTIVE_SUBROUTINES."
10219                            << tcu::TestLog::EndMessage;
10220 
10221         m_has_test_passed = false;
10222     }
10223 
10224     /* The error INVALID_OPERATION is generated by UniformSubroutinesuiv() if any
10225      * subroutine index in <indices> identifies a subroutine not associated with
10226      * the type of the subroutine uniform variable assigned to the corresponding
10227      * location.
10228      */
10229     glw::GLuint invalid_subroutine_indices2[2] = {m_po_subroutine_test1_index, m_po_subroutine_test1_index};
10230 
10231     gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations, invalid_subroutine_indices2);
10232     error_code = gl.getError();
10233 
10234     if (error_code != GL_INVALID_OPERATION)
10235     {
10236         m_testCtx.getLog() << tcu::TestLog::Message
10237                            << "glUniformSubroutinesuiv() does not generate GL_INVALID_OPERATION "
10238                               "when the subroutine index passed via <indices> argument identifies"
10239                               "a subroutine not associated with the type of the subroutine uniform "
10240                               "assigned to the corresponding location."
10241                            << tcu::TestLog::EndMessage;
10242 
10243         m_has_test_passed = false;
10244     }
10245 
10246     /* The error INVALID_OPERATION is generated by UniformSubroutinesuiv if no
10247      * program is active.
10248      */
10249     glw::GLuint valid_subroutine_locations[2] = {0};
10250 
10251     valid_subroutine_locations[m_po_subroutine_uniform_function_index]  = m_po_subroutine_test1_index;
10252     valid_subroutine_locations[m_po_subroutine_uniform_function2_index] = m_po_subroutine_test3_index;
10253 
10254     gl.useProgram(0);
10255     GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
10256 
10257     gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations, valid_subroutine_locations);
10258     error_code = gl.getError();
10259 
10260     if (error_code != GL_INVALID_OPERATION)
10261     {
10262         m_testCtx.getLog() << tcu::TestLog::Message
10263                            << "glUniformSubroutinesuiv() does not generate GL_INVALID_OPERATION "
10264                               "when called without an active program object."
10265                            << tcu::TestLog::EndMessage;
10266 
10267         m_has_test_passed = false;
10268     }
10269 
10270     /* The error INVALID_VALUE is generated by GetUniformSubroutineuiv if
10271      * <location> is greater than or equal to the value of
10272      * ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS for the shader stage.
10273      */
10274     glw::GLuint temp_value = 0;
10275 
10276     gl.useProgram(m_po_id);
10277     GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
10278 
10279     gl.getUniformSubroutineuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations, &temp_value);
10280     error_code = gl.getError();
10281 
10282     if (error_code == GL_INVALID_VALUE)
10283     {
10284         gl.getUniformSubroutineuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations + 1, &temp_value);
10285         error_code = gl.getError();
10286     }
10287 
10288     if (error_code != GL_INVALID_VALUE)
10289     {
10290         m_testCtx.getLog() << tcu::TestLog::Message
10291                            << "glGetUniformSubroutineuiv() does not generate GL_INVALID_VALUE "
10292                               "when called for location that is greater than or equal to the value "
10293                               "of GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS."
10294                            << tcu::TestLog::EndMessage;
10295 
10296         m_has_test_passed = false;
10297     }
10298 
10299     /* The error INVALID_OPERATION is generated by GetUniformSubroutineuiv if no
10300      * program is active for the shader stage identified by <shadertype>.
10301      */
10302     const glw::GLenum undefined_shader_stages[]  = {GL_FRAGMENT_SHADER, GL_GEOMETRY_SHADER, GL_TESS_CONTROL_SHADER,
10303                                                     GL_TESS_EVALUATION_SHADER};
10304     const unsigned int n_undefined_shader_stages = sizeof(undefined_shader_stages) / sizeof(undefined_shader_stages[0]);
10305 
10306     for (unsigned int n_undefined_shader_stage = 0; n_undefined_shader_stage < n_undefined_shader_stages;
10307          ++n_undefined_shader_stage)
10308     {
10309         glw::GLenum shader_stage = undefined_shader_stages[n_undefined_shader_stage];
10310 
10311         gl.getUniformSubroutineuiv(shader_stage, 0, /* location */
10312                                    &temp_value);
10313         error_code = gl.getError();
10314 
10315         if (error_code != GL_INVALID_OPERATION)
10316         {
10317             m_testCtx.getLog() << tcu::TestLog::Message
10318                                << "glGetUniformSubroutineuiv() does not generate GL_INVALID_OPERATION "
10319                                   "when called for a shader stage that is not defined for active "
10320                                   "program object."
10321                                << tcu::TestLog::EndMessage;
10322 
10323             m_has_test_passed = false;
10324         }
10325     } /* for (all undefined shader stages) */
10326 
10327     /* All done */
10328     if (m_has_test_passed)
10329     {
10330         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
10331     }
10332     else
10333     {
10334         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
10335     }
10336 
10337     return STOP;
10338 }
10339 
10340 /** Constructor
10341  *
10342  *  @param context Rendering context.
10343  *
10344  **/
NegativeTest2(deqp::Context & context)10345 NegativeTest2::NegativeTest2(deqp::Context &context)
10346     : TestCase(context, "subroutine_uniform_scope",
10347                "Verifies subroutine uniforms declared in shader stage A"
10348                "cannot be accessed from a different stage.")
10349     , m_fs_id(0)
10350     , m_gs_id(0)
10351     , m_has_test_passed(true)
10352     , m_po_id(0)
10353     , m_tc_id(0)
10354     , m_te_id(0)
10355     , m_vs_id(0)
10356 {
10357     /* Left blank intentionally */
10358 }
10359 
10360 /** Deinitializes all GL objects that may have been created during test execution */
deinit()10361 void NegativeTest2::deinit()
10362 {
10363     deinitGLObjects();
10364 }
10365 
10366 /** Deinitializes all GL objects that may have been created during test execution */
deinitGLObjects()10367 void NegativeTest2::deinitGLObjects()
10368 {
10369     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
10370 
10371     if (m_fs_id != 0)
10372     {
10373         gl.deleteShader(m_fs_id);
10374 
10375         m_fs_id = 0;
10376     }
10377 
10378     if (m_gs_id != 0)
10379     {
10380         gl.deleteShader(m_gs_id);
10381 
10382         m_gs_id = 0;
10383     }
10384 
10385     if (m_tc_id != 0)
10386     {
10387         gl.deleteShader(m_tc_id);
10388 
10389         m_tc_id = 0;
10390     }
10391 
10392     if (m_te_id != 0)
10393     {
10394         gl.deleteShader(m_te_id);
10395 
10396         m_te_id = 0;
10397     }
10398 
10399     if (m_vs_id != 0)
10400     {
10401         gl.deleteShader(m_vs_id);
10402 
10403         m_vs_id = 0;
10404     }
10405 
10406     if (m_po_id != 0)
10407     {
10408         gl.deleteProgram(m_po_id);
10409 
10410         m_po_id = 0;
10411     }
10412 }
10413 
10414 /** Builds an offending program object and tries to link it. We're either expecting
10415  *  a compile-time or link-time error here.
10416  *
10417  *  If the program object builds successfully, the test has failed.
10418  *
10419  *  @param referencing_stage Shader stage which defines a subroutine uniform that
10420  *                           should be called from fragment/geometry/tess control/
10421  *                           tess evaluation/vertex shader stages.
10422  *
10423  **/
executeTestCase(const Utils::_shader_stage & referencing_stage)10424 void NegativeTest2::executeTestCase(const Utils::_shader_stage &referencing_stage)
10425 {
10426     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
10427 
10428     const std::string fs_body = getFragmentShaderBody(referencing_stage);
10429     const std::string gs_body = getGeometryShaderBody(referencing_stage);
10430     const std::string tc_body = getTessellationControlShaderBody(referencing_stage);
10431     const std::string te_body = getTessellationEvaluationShaderBody(referencing_stage);
10432     const std::string vs_body = getVertexShaderBody(referencing_stage);
10433 
10434     if (Utils::buildProgram(gl, vs_body, tc_body, te_body, gs_body, fs_body, NULL, /* xfb_varyings */
10435                             0,                                                     /* n_xfb_varyings */
10436                             &m_vs_id, &m_tc_id, &m_te_id, &m_gs_id, &m_fs_id, &m_po_id))
10437     {
10438         /* Test program should not have built correctly ! */
10439         m_testCtx.getLog() << tcu::TestLog::Message
10440                            << "In the following program, one of the stages references "
10441                               "a subroutine that is defined in another stage. This "
10442                               "is forbidden by the specification.\n"
10443                               "\n"
10444                               "Vertex shader:\n\n"
10445                            << vs_body.c_str() << "\n\nTessellation control shader:\n\n"
10446                            << tc_body.c_str() << "\n\nTessellation evaluation shader:\n\n"
10447                            << te_body.c_str() << "\n\nGeometry shader:\n\n"
10448                            << gs_body.c_str() << "\n\nFragment shader:\n\n"
10449                            << fs_body.c_str() << tcu::TestLog::EndMessage;
10450 
10451         m_has_test_passed = false;
10452     } /* if (test program was built successfully) */
10453 
10454     /* Release the shaders & the program object that buildProgram() created */
10455     deinitGLObjects();
10456 }
10457 
10458 /** Retrieves an offending fragment shader body.
10459  *
10460  *  @param referencing_stage Shader stage which defines the subroutine uniform that
10461  *                           will be called from fragment shader.
10462  *
10463  *  @return Requested string.
10464  **/
getFragmentShaderBody(const Utils::_shader_stage & referencing_stage) const10465 std::string NegativeTest2::getFragmentShaderBody(const Utils::_shader_stage &referencing_stage) const
10466 {
10467     std::stringstream result;
10468 
10469     /* Form the pre-amble */
10470     result << "#version 400\n"
10471               "\n"
10472               "#extension GL_ARB_shader_subroutine : require\n"
10473               "\n"
10474               "subroutine void testSubroutineType(out vec4 test_argument);\n"
10475               "\n"
10476               /* Define a subroutine */
10477               "subroutine(testSubroutineType) void fs_subroutine(out vec4 test_argument)\n"
10478               "{\n"
10479               "    test_argument = vec4(1, 0, 0, 0);\n"
10480               "}\n"
10481               "\n"
10482               /* Define output variables */
10483               "out vec4 result;\n"
10484               "\n"
10485               /* Define uniforms */
10486               "subroutine uniform testSubroutineType test_fs_subroutine;\n"
10487               "\n"
10488               /* Define main() */
10489               "void main()\n"
10490               "{\n"
10491               "    "
10492            << getSubroutineUniformName(referencing_stage)
10493            << "(result);\n"
10494               "}\n";
10495 
10496     return result.str();
10497 }
10498 
10499 /** Retrieves an offending geometry shader body.
10500  *
10501  *  @param referencing_stage Shader stage which defines the subroutine uniform that
10502  *                           will be called from geometry shader.
10503  *
10504  *  @return Requested string.
10505  **/
getGeometryShaderBody(const Utils::_shader_stage & referencing_stage) const10506 std::string NegativeTest2::getGeometryShaderBody(const Utils::_shader_stage &referencing_stage) const
10507 {
10508     std::stringstream result;
10509 
10510     /* Form the pre-amble */
10511     result << "#version 400\n"
10512               "\n"
10513               "#extension GL_ARB_shader_subroutine : require\n"
10514               "\n"
10515               "subroutine void testSubroutineType(out vec4 test_argument);\n"
10516               "\n"
10517               "layout(points)                   in;\n"
10518               "layout(points, max_vertices = 1) out;\n"
10519               "\n"
10520               /* Define a subroutine */
10521               "subroutine(testSubroutineType) void gs_subroutine(out vec4 test_argument)\n"
10522               "{\n"
10523               "    test_argument = vec4(0, 1, 1, 1);\n"
10524               "}\n"
10525               "\n"
10526               /* Define output variables */
10527               "out vec4 result;\n"
10528               "\n"
10529               /* Define uniforms */
10530               "subroutine uniform testSubroutineType test_gs_subroutine;\n"
10531               "\n"
10532               /* Define main() */
10533               "void main()\n"
10534               "{\n"
10535               "    "
10536            << getSubroutineUniformName(referencing_stage)
10537            << "(result);\n"
10538               "}\n";
10539 
10540     return result.str();
10541 }
10542 
10543 /** Retrieves name of the subroutine uniform that is defined in user-specified
10544  *  shader stage.
10545  *
10546  *  @param stage Shader stage to retrieve the subroutine uniform name for.
10547  *
10548  *  @return As per description.
10549  **/
getSubroutineUniformName(const Utils::_shader_stage & stage) const10550 std::string NegativeTest2::getSubroutineUniformName(const Utils::_shader_stage &stage) const
10551 {
10552     std::string result = "?";
10553 
10554     switch (stage)
10555     {
10556     case Utils::SHADER_STAGE_FRAGMENT:
10557     {
10558         result = "test_fs_subroutine";
10559 
10560         break;
10561     }
10562 
10563     case Utils::SHADER_STAGE_GEOMETRY:
10564     {
10565         result = "test_gs_subroutine";
10566 
10567         break;
10568     }
10569 
10570     case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
10571     {
10572         result = "test_tc_subroutine";
10573 
10574         break;
10575     }
10576 
10577     case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
10578     {
10579         result = "test_te_subroutine";
10580 
10581         break;
10582     }
10583 
10584     case Utils::SHADER_STAGE_VERTEX:
10585     {
10586         result = "test_vs_subroutine";
10587 
10588         break;
10589     }
10590 
10591     default:
10592     {
10593         TCU_FAIL("Unrecognized shader stage requested");
10594     }
10595     } /* switch (stage) */
10596 
10597     return result;
10598 }
10599 
10600 /** Retrieves an offending tessellation control shader body.
10601  *
10602  *  @param referencing_stage Shader stage which defines the subroutine uniform that
10603  *                           will be called from tessellation control shader.
10604  *
10605  *  @return Requested string.
10606  **/
getTessellationControlShaderBody(const Utils::_shader_stage & referencing_stage) const10607 std::string NegativeTest2::getTessellationControlShaderBody(const Utils::_shader_stage &referencing_stage) const
10608 {
10609     std::stringstream result;
10610 
10611     /* Form the pre-amble */
10612     result << "#version 400\n"
10613               "\n"
10614               "#extension GL_ARB_shader_subroutine : require\n"
10615               "\n"
10616               "layout(vertices = 4) out;\n"
10617               "\n"
10618               "subroutine void testSubroutineType(out vec4 test_argument);\n"
10619               "\n"
10620               /* Define a subroutine */
10621               "subroutine(testSubroutineType) void tc_subroutine(out vec4 test_argument)\n"
10622               "{\n"
10623               "    test_argument = vec4(0, 0, 1, 0);\n"
10624               "}\n"
10625               "\n"
10626               /* Define uniforms */
10627               "subroutine uniform testSubroutineType test_tc_subroutine;\n"
10628               "\n"
10629               /* Define main() */
10630               "void main()\n"
10631               "{\n"
10632               "    "
10633            << getSubroutineUniformName(referencing_stage)
10634            << "(gl_out[gl_InvocationID].gl_Position);\n"
10635               "}\n";
10636 
10637     return result.str();
10638 }
10639 
10640 /** Retrieves an offending tessellation evaluation shader body.
10641  *
10642  *  @param referencing_stage Shader stage which defines the subroutine uniform that
10643  *                           will be called from tessellation evaluation shader.
10644  *
10645  *  @return Requested string.
10646  **/
getTessellationEvaluationShaderBody(const Utils::_shader_stage & referencing_stage) const10647 std::string NegativeTest2::getTessellationEvaluationShaderBody(const Utils::_shader_stage &referencing_stage) const
10648 {
10649     std::stringstream result;
10650 
10651     /* Form the pre-amble */
10652     result << "#version 400\n"
10653               "\n"
10654               "#extension GL_ARB_shader_subroutine : require\n"
10655               "\n"
10656               "layout(quads) in;\n"
10657               "\n"
10658               "subroutine void testSubroutineType(out vec4 test_argument);\n"
10659               "\n"
10660               /* Define a subroutine */
10661               "subroutine(testSubroutineType) void te_subroutine(out vec4 test_argument)\n"
10662               "{\n"
10663               "    test_argument = vec4(1, 1, 1, 1);\n"
10664               "}\n"
10665               "\n"
10666               /* Define uniforms */
10667               "subroutine uniform testSubroutineType test_te_subroutine;\n"
10668               "\n"
10669               /* Define main() */
10670               "void main()\n"
10671               "{\n"
10672               "    "
10673            << getSubroutineUniformName(referencing_stage)
10674            << "(gl_Position);\n"
10675               "}\n";
10676 
10677     return result.str();
10678 }
10679 
10680 /** Retrieves an offending vertex shader body.
10681  *
10682  *  @param referencing_stage Shader stage which defines the subroutine uniform that
10683  *                           will be called from vertex shader.
10684  *
10685  *  @return Requested string.
10686  **/
getVertexShaderBody(const Utils::_shader_stage & referencing_stage) const10687 std::string NegativeTest2::getVertexShaderBody(const Utils::_shader_stage &referencing_stage) const
10688 {
10689     std::stringstream result;
10690 
10691     /* Form the pre-amble */
10692     result << "#version 400\n"
10693               "\n"
10694               "#extension GL_ARB_shader_subroutine : require\n"
10695               "\n"
10696               "subroutine void testSubroutineType(out vec4 test_argument);\n"
10697               "\n"
10698               /* Define a subroutine */
10699               "subroutine(testSubroutineType) void vs_subroutine(out vec4 test_argument)\n"
10700               "{\n"
10701               "    test_argument = vec4(0, 1, 0, 0);\n"
10702               "}\n"
10703               "\n"
10704               /* Define uniforms */
10705               "subroutine uniform testSubroutineType test_vs_subroutine;\n"
10706               "\n"
10707               /* Define main() */
10708               "void main()\n"
10709               "{\n"
10710               "    "
10711            << getSubroutineUniformName(referencing_stage)
10712            << "(gl_Position);\n"
10713               "}\n";
10714 
10715     return result.str();
10716 }
10717 
10718 /** Executes test iteration.
10719  *
10720  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
10721  */
iterate()10722 tcu::TestNode::IterateResult NegativeTest2::iterate()
10723 {
10724     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
10725     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
10726     {
10727         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
10728     }
10729 
10730     /* Iterate over all shader stages and execute the checks */
10731     for (int referencing_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
10732          referencing_stage < static_cast<int>(Utils::SHADER_STAGE_COUNT); ++referencing_stage)
10733     {
10734         executeTestCase(static_cast<Utils::_shader_stage>(referencing_stage));
10735     } /* for (all test cases) */
10736 
10737     /* All done */
10738     if (m_has_test_passed)
10739     {
10740         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
10741     }
10742     else
10743     {
10744         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
10745     }
10746 
10747     return STOP;
10748 }
10749 
10750 /** Constructor.
10751  *
10752  *  @param context Rendering context.
10753  *
10754  **/
NegativeTest3(deqp::Context & context)10755 NegativeTest3::NegativeTest3(deqp::Context &context)
10756     : TestCase(context, "missing_subroutine_keyword",
10757                "Verifies that subroutine keyword is necessary when declaring a "
10758                "subroutine uniforn and a compilation error occurs without it.")
10759     , m_has_test_passed(true)
10760     , m_so_id(0)
10761 {
10762     /* Left blank intentionally */
10763 }
10764 
10765 /** Deinitializes all GL objects that may have been created during test execution */
deinit()10766 void NegativeTest3::deinit()
10767 {
10768     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
10769 
10770     if (m_so_id != 0)
10771     {
10772         gl.deleteShader(m_so_id);
10773 
10774         m_so_id = 0;
10775     }
10776 }
10777 
10778 /** Verifies that broken shader (for user-specified shader stage) does not compile.
10779  *
10780  *  @param shader_stage Shader stage to use for the test.
10781  **/
executeTest(const Utils::_shader_stage & shader_stage)10782 void NegativeTest3::executeTest(const Utils::_shader_stage &shader_stage)
10783 {
10784     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
10785 
10786     /* Generate a new shader object */
10787     m_so_id = gl.createShader(Utils::getGLenumForShaderStage(shader_stage));
10788     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
10789 
10790     /* Assign body to the shader */
10791     std::string body;
10792     const char *body_raw_ptr = DE_NULL;
10793 
10794     switch (shader_stage)
10795     {
10796     case Utils::SHADER_STAGE_VERTEX:
10797         body = getVertexShaderBody();
10798         break;
10799     case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
10800         body = getTessellationControlShaderBody();
10801         break;
10802     case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
10803         body = getTessellationEvaluationShaderBody();
10804         break;
10805     case Utils::SHADER_STAGE_GEOMETRY:
10806         body = getGeometryShaderBody();
10807         break;
10808     case Utils::SHADER_STAGE_FRAGMENT:
10809         body = getFragmentShaderBody();
10810         break;
10811 
10812     default:
10813     {
10814         TCU_FAIL("Unrecognized shader stage requested");
10815     }
10816     } /* switch (shader_stage) */
10817 
10818     body_raw_ptr = body.c_str();
10819 
10820     gl.shaderSource(m_so_id, 1 /* count */, &body_raw_ptr, DE_NULL /* length */);
10821     GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
10822 
10823     /* Try to compile the shader */
10824     glw::GLint compile_status = 0;
10825 
10826     gl.compileShader(m_so_id);
10827     GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
10828 
10829     gl.getShaderiv(m_so_id, GL_COMPILE_STATUS, &compile_status);
10830     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
10831 
10832     if (compile_status == GL_TRUE)
10833     {
10834         m_testCtx.getLog() << tcu::TestLog::Message
10835                            << "The following shader was expected to fail to compile but was "
10836                               "accepted by the compiler:\n"
10837                               "\n"
10838                            << body.c_str() << tcu::TestLog::EndMessage;
10839 
10840         m_has_test_passed = false;
10841     }
10842 
10843     /* Good to release the shader at this point */
10844     gl.deleteShader(m_so_id);
10845     GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed.");
10846 }
10847 
10848 /** Retrieves body of a broken fragment shader.
10849  *
10850  *  @return Requested string.
10851  **/
getFragmentShaderBody() const10852 std::string NegativeTest3::getFragmentShaderBody() const
10853 {
10854     return "#version 400\n"
10855            "\n"
10856            "#extension GL_ARB_shader_subroutine : require\n"
10857            "\n"
10858            "subroutine void testSubroutineType(inout vec4 test);\n"
10859            "\n"
10860            "void testSubroutine1(inout vec4 test)\n"
10861            "{\n"
10862            "    test += vec4(3, 4, 5, 6);\n"
10863            "}\n"
10864            "\n"
10865            "uniform testSubroutineType subroutineFunction;\n"
10866            "out     vec4               result;\n"
10867            "\n"
10868            "void main()\n"
10869            "{\n"
10870            "    vec4 test = vec4(2, 3, 4, 5);\n"
10871            "\n"
10872            "    subroutineFunction(test);\n"
10873            "\n"
10874            "    result = test;\n"
10875            "}\n";
10876 }
10877 
10878 /** Retrieves body of a broken geometry shader.
10879  *
10880  *  @return Requested string.
10881  **/
getGeometryShaderBody() const10882 std::string NegativeTest3::getGeometryShaderBody() const
10883 {
10884     return "#version 400\n"
10885            "\n"
10886            "#extension GL_ARB_shader_subroutine : require\n"
10887            "\n"
10888            "layout(points)                   in;\n"
10889            "layout(points, max_vertices = 1) out;\n"
10890            "\n"
10891            "subroutine void testSubroutineType(inout vec4 test);\n"
10892            "\n"
10893            "void testSubroutine1(inout vec4 test)\n"
10894            "{\n"
10895            "    test += vec4(3, 4, 5, 6);\n"
10896            "}\n"
10897            "\n"
10898            "uniform testSubroutineType subroutineFunction;\n"
10899            "\n"
10900            "void main()\n"
10901            "{\n"
10902            "    vec4 test = vec4(2, 3, 4, 5);\n"
10903            "\n"
10904            "    subroutineFunction(test);\n"
10905            "\n"
10906            "    gl_Position = test;\n"
10907            "    EmitVertex();\n"
10908            "}\n";
10909 }
10910 
10911 /** Retrieves body of a broken tessellation control shader.
10912  *
10913  *  @return Requested string.
10914  **/
getTessellationControlShaderBody() const10915 std::string NegativeTest3::getTessellationControlShaderBody() const
10916 {
10917     return "#version 400\n"
10918            "\n"
10919            "#extension GL_ARB_shader_subroutine : require\n"
10920            "\n"
10921            "layout(vertices=4) out;\n"
10922            "\n"
10923            "subroutine void testSubroutineType(inout vec4 test);\n"
10924            "\n"
10925            "void testSubroutine1(inout vec4 test)\n"
10926            "{\n"
10927            "    test += vec4(1, 2, 3, 4);\n"
10928            "}\n"
10929            "\n"
10930            "uniform testSubroutineType subroutineFunction;\n"
10931            "\n"
10932            "void main()\n"
10933            "{\n"
10934            "    vec4 test = vec4(0, 1, 2, 3);\n"
10935            "\n"
10936            "    subroutineFunction(test);\n"
10937            "\n"
10938            "    gl_out[gl_InvocationID].gl_Position = test;\n"
10939            "}\n";
10940 }
10941 
10942 /** Retrieves body of a broken tessellation evaluation shader.
10943  *
10944  *  @return Requested string.
10945  **/
getTessellationEvaluationShaderBody() const10946 std::string NegativeTest3::getTessellationEvaluationShaderBody() const
10947 {
10948     return "#version 400\n"
10949            "\n"
10950            "#extension GL_ARB_shader_subroutine : require\n"
10951            "\n"
10952            "layout(quads) in;\n"
10953            "\n"
10954            "subroutine void testSubroutineType(inout vec4 test);\n"
10955            "\n"
10956            "void testSubroutine1(inout vec4 test)\n"
10957            "{\n"
10958            "    test += vec4(2, 3, 4, 5);\n"
10959            "}\n"
10960            "\n"
10961            "uniform testSubroutineType subroutineFunction;\n"
10962            "\n"
10963            "void main()\n"
10964            "{\n"
10965            "    vec4 test = vec4(1, 2, 3, 4);\n"
10966            "\n"
10967            "    subroutineFunction(test);\n"
10968            "\n"
10969            "    gl_Position = test;\n"
10970            "}\n";
10971 }
10972 
10973 /** Retrieves body of a broken vertex shader.
10974  *
10975  *  @return Requested string.
10976  **/
getVertexShaderBody() const10977 std::string NegativeTest3::getVertexShaderBody() const
10978 {
10979     return "#version 400\n"
10980            "\n"
10981            "#extension GL_ARB_shader_subroutine : require\n"
10982            "\n"
10983            "subroutine void testSubroutineType(inout vec4 test);\n"
10984            "\n"
10985            "void testSubroutine1(inout vec4 test)\n"
10986            "{\n"
10987            "    test += vec4(0, 1, 2, 3);\n"
10988            "}\n"
10989            "\n"
10990            "uniform testSubroutineType subroutineFunction;\n"
10991            "\n"
10992            "void main()\n"
10993            "{\n"
10994            "    subroutineFunction(gl_Position);\n"
10995            "}\n";
10996 }
10997 
10998 /** Executes test iteration.
10999  *
11000  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
11001  */
iterate()11002 tcu::TestNode::IterateResult NegativeTest3::iterate()
11003 {
11004     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
11005     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
11006     {
11007         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
11008     }
11009 
11010     /* Iterate over all shader stages */
11011     for (int shader_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
11012          shader_stage < static_cast<int>(Utils::SHADER_STAGE_COUNT); ++shader_stage)
11013     {
11014         executeTest(static_cast<Utils::_shader_stage>(shader_stage));
11015     } /* for (all shader stages) */
11016 
11017     /* Done */
11018     if (m_has_test_passed)
11019     {
11020         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
11021     }
11022     else
11023     {
11024         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
11025     }
11026 
11027     return STOP;
11028 }
11029 
11030 /** Constructor.
11031  *
11032  *  @param context Rendering context.
11033  *
11034  **/
NegativeTest4(deqp::Context & context)11035 NegativeTest4::NegativeTest4(deqp::Context &context)
11036     : TestCase(context, "subroutines_incompatible_with_subroutine_type",
11037                "Verifies that a compile-time error is generated when arguments and "
11038                "return type do not match beween the function and each associated "
11039                "subroutine type.")
11040     , m_has_test_passed(true)
11041     , m_so_id(0)
11042 {
11043     /* Left blank intentionally */
11044 }
11045 
11046 /** Deinitializes GL objects that may have been created during test
11047  *  execution.
11048  **/
deinit()11049 void NegativeTest4::deinit()
11050 {
11051     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
11052 
11053     if (m_so_id != 0)
11054     {
11055         gl.deleteShader(m_so_id);
11056 
11057         m_so_id = 0;
11058     }
11059 }
11060 
11061 /** Retrieves body of a shader of user-specified type that should be used
11062  *  for a single test iteration. The shader will define user-specified number
11063  *  of subroutine types, with the last type either defining an additional argument
11064  *  or using a different return type.
11065  *  A subroutine (claimed compatible with *all* subroutine types) will also be
11066  *  defined in the shader.
11067  *
11068  *  @param shader_stage       Shader stage to use for the query.
11069  *  @param n_subroutine_types Overall number of subroutine types that will be
11070  *                            declared & used in the shader. Please see description
11071  *                            for more details.
11072  *
11073  *  @return Requested string.
11074  **/
getShaderBody(const Utils::_shader_stage & shader_stage,const unsigned int & n_subroutine_types,const _test_case & test_case) const11075 std::string NegativeTest4::getShaderBody(const Utils::_shader_stage &shader_stage,
11076                                          const unsigned int &n_subroutine_types, const _test_case &test_case) const
11077 {
11078     std::stringstream result_sstream;
11079 
11080     /* Form the pre-amble */
11081     result_sstream << "#version 400\n"
11082                       "\n"
11083                       "#extension GL_ARB_shader_subroutine : require\n"
11084                       "\n";
11085 
11086     /* Inject stage-specific code */
11087     switch (shader_stage)
11088     {
11089     case Utils::SHADER_STAGE_GEOMETRY:
11090     {
11091         result_sstream << "layout (points) in;\n"
11092                           "layout (points, max_vertices = 1) out;\n"
11093                           "\n";
11094 
11095         break;
11096     }
11097 
11098     case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
11099     {
11100         result_sstream << "layout (vertices = 4) out;\n"
11101                           "\n";
11102 
11103         break;
11104     }
11105 
11106     case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
11107     {
11108         result_sstream << "layout (quads) in;\n"
11109                           "\n";
11110 
11111         break;
11112     }
11113 
11114     default:
11115         break;
11116     } /* switch (shader_stage) */
11117 
11118     /* Insert subroutine type declarations */
11119     for (unsigned int n_subroutine_type = 0; n_subroutine_type < n_subroutine_types - 1; ++n_subroutine_type)
11120     {
11121         result_sstream << "subroutine void subroutineType" << n_subroutine_type << "(inout vec3 argument);\n";
11122     } /* for (all subroutine types) */
11123 
11124     switch (test_case)
11125     {
11126     case TEST_CASE_INCOMPATIBLE_ARGUMENT_LIST:
11127     {
11128         result_sstream << "subroutine void subroutineType" << (n_subroutine_types - 1)
11129                        << "(inout vec3 argument, out vec4 argument2);\n";
11130 
11131         break;
11132     }
11133 
11134     case TEST_CASE_INCOMPATIBLE_RETURN_TYPE:
11135     {
11136         result_sstream << "subroutine int subroutineType" << (n_subroutine_types - 1) << "(inout vec3 argument);\n";
11137 
11138         break;
11139     }
11140 
11141     default:
11142     {
11143         TCU_FAIL("Unrecognized test case");
11144     }
11145     } /* switch (test_case) */
11146 
11147     /* Insert subroutine declarations */
11148     result_sstream << "subroutine(";
11149 
11150     for (unsigned int n_subroutine_type = 0; n_subroutine_type < n_subroutine_types; ++n_subroutine_type)
11151     {
11152         result_sstream << "subroutineType" << n_subroutine_type;
11153 
11154         if (n_subroutine_type != (n_subroutine_types - 1))
11155         {
11156             result_sstream << ", ";
11157         }
11158     } /* for (all subroutine types) */
11159 
11160     result_sstream << ") void function(inout vec3 argument)\n"
11161                       "{\n"
11162                       "    argument = vec3(1, 2, 3);\n"
11163                       "}\n"
11164                       "\n";
11165 
11166     /* Insert remaining required stage-specific bits */
11167     switch (shader_stage)
11168     {
11169     case Utils::SHADER_STAGE_FRAGMENT:
11170     {
11171         result_sstream << "out vec4 result;\n"
11172                           "\n"
11173                           "void main()\n"
11174                           "{\n"
11175                           "    result = vec4(1, 2, 3, 4);\n"
11176                           "}\n";
11177 
11178         break;
11179     }
11180 
11181     case Utils::SHADER_STAGE_GEOMETRY:
11182     {
11183         result_sstream << "void main()\n"
11184                           "{\n"
11185                           "    gl_Position = vec4(1, 2, 3, 4);\n"
11186                           "    EmitVertex();\n"
11187                           "}\n";
11188 
11189         break;
11190     }
11191 
11192     case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
11193     {
11194         result_sstream << "void main()\n"
11195                           "{\n"
11196                           "    gl_TessLevelInner[0]                = 1;\n"
11197                           "    gl_TessLevelInner[1]                = 1;\n"
11198                           "    gl_TessLevelOuter[0]                = 1;\n"
11199                           "    gl_TessLevelOuter[1]                = 1;\n"
11200                           "    gl_TessLevelOuter[2]                = 1;\n"
11201                           "    gl_TessLevelOuter[3]                = 1;\n"
11202                           "    gl_out[gl_InvocationID].gl_Position = vec4(2, 3, 4, 5);\n"
11203                           "}\n";
11204 
11205         break;
11206     }
11207 
11208     case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
11209     case Utils::SHADER_STAGE_VERTEX:
11210     {
11211         result_sstream << "void main()\n"
11212                           "{\n"
11213                           "    gl_Position = vec4(1, 2, 3, 4);\n"
11214                           "}\n";
11215 
11216         break;
11217     }
11218 
11219     default:
11220     {
11221         TCU_FAIL("Unrecognized shader stage");
11222     }
11223     } /* switch (shader_stage) */
11224 
11225     return result_sstream.str();
11226 }
11227 
11228 /** Executes test iteration.
11229  *
11230  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
11231  */
iterate()11232 tcu::TestNode::IterateResult NegativeTest4::iterate()
11233 {
11234     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
11235 
11236     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
11237     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
11238     {
11239         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
11240     }
11241 
11242     /* Iterate over all shader stages.. */
11243     for (int shader_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
11244          shader_stage != static_cast<int>(Utils::SHADER_STAGE_COUNT); ++shader_stage)
11245     {
11246         /* For each shader stage, we will be trying to compile a number of invalid shaders.
11247          * Each shader defines N different subroutine types. (N-1) of them are compatible
11248          * with a subroutine, but exactly 1 will be mismatched. The test passes if GLSL
11249          * compiler correctly detects that all shaders we will be trying to compile are
11250          * broken.
11251          */
11252         const glw::GLenum shader_type = Utils::getGLenumForShaderStage(static_cast<Utils::_shader_stage>(shader_stage));
11253 
11254         for (unsigned int n_subroutine_types = 1; n_subroutine_types < 6; /* arbitrary number */
11255              ++n_subroutine_types)
11256         {
11257             for (int test_case = static_cast<int>(TEST_CASE_FIRST); test_case != static_cast<int>(TEST_CASE_COUNT);
11258                  ++test_case)
11259             {
11260                 std::string body;
11261                 const char *body_raw_ptr  = NULL;
11262                 glw::GLint compile_status = GL_FALSE;
11263 
11264                 body         = getShaderBody(static_cast<Utils::_shader_stage>(shader_stage), n_subroutine_types,
11265                                              static_cast<_test_case>(test_case));
11266                 body_raw_ptr = body.c_str();
11267 
11268                 /* Try to compile the shader */
11269                 m_so_id = gl.createShader(shader_type);
11270                 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed");
11271 
11272                 gl.shaderSource(m_so_id, 1 /* count */, &body_raw_ptr, DE_NULL);
11273                 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed");
11274 
11275                 gl.compileShader(m_so_id);
11276                 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed");
11277 
11278                 gl.getShaderiv(m_so_id, GL_COMPILE_STATUS, &compile_status);
11279                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
11280 
11281                 if (compile_status == GL_TRUE)
11282                 {
11283                     m_testCtx.getLog() << tcu::TestLog::Message << "A malformed "
11284                                        << Utils::getShaderStageString(static_cast<Utils::_shader_stage>(shader_stage))
11285                                        << " compiled successfully "
11286                                           "("
11287                                        << n_subroutine_types
11288                                        << " subroutine types "
11289                                           "were defined)."
11290                                        << tcu::TestLog::EndMessage;
11291 
11292                     m_has_test_passed = false;
11293                 }
11294 
11295                 /* Release the object */
11296                 gl.deleteShader(m_so_id);
11297                 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed.");
11298             } /* for (all test cases) */
11299         }     /* for (a number of different subroutine type declarations) */
11300     }         /* for (all shader stages) */
11301 
11302     /* Done */
11303     if (m_has_test_passed)
11304     {
11305         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
11306     }
11307     else
11308     {
11309         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
11310     }
11311 
11312     return STOP;
11313 }
11314 
11315 /** Constructor.
11316  *
11317  *  @param context Rendering context.
11318  *
11319  **/
NegativeTest5(deqp::Context & context)11320 NegativeTest5::NegativeTest5(deqp::Context &context)
11321     : TestCase(context, "subroutine_uniform_wo_matching_subroutines",
11322                "Verifies that a link- or compile-time error occurs when "
11323                "trying to link a program with no subroutine for subroutine "
11324                "uniform variable.")
11325     , m_fs_id(0)
11326     , m_gs_id(0)
11327     , m_has_test_passed(true)
11328     , m_po_id(0)
11329     , m_tc_id(0)
11330     , m_te_id(0)
11331     , m_vs_id(0)
11332 {
11333     /* Left blank intentionally */
11334 }
11335 
11336 /** Deinitializes all GL objects that may have been created during test execution */
deinit()11337 void NegativeTest5::deinit()
11338 {
11339     deinitIteration();
11340 }
11341 
11342 /** Deinitializes all GL objects that may have been created during a single test
11343  *  iteration.
11344  ***/
deinitIteration()11345 void NegativeTest5::deinitIteration()
11346 {
11347     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
11348 
11349     if (m_fs_id != 0)
11350     {
11351         gl.deleteShader(m_fs_id);
11352 
11353         m_fs_id = 0;
11354     }
11355 
11356     if (m_gs_id != 0)
11357     {
11358         gl.deleteShader(m_gs_id);
11359 
11360         m_gs_id = 0;
11361     }
11362 
11363     if (m_po_id != 0)
11364     {
11365         gl.deleteProgram(m_po_id);
11366 
11367         m_po_id = 0;
11368     }
11369 
11370     if (m_tc_id != 0)
11371     {
11372         gl.deleteShader(m_tc_id);
11373 
11374         m_tc_id = 0;
11375     }
11376 
11377     if (m_te_id != 0)
11378     {
11379         gl.deleteShader(m_te_id);
11380 
11381         m_te_id = 0;
11382     }
11383 
11384     if (m_vs_id != 0)
11385     {
11386         gl.deleteShader(m_vs_id);
11387 
11388         m_vs_id = 0;
11389     }
11390 }
11391 
11392 /** Executes a single test iteration.
11393  *
11394  *  If the iteration fails, m_has_test_passed will be set to false.
11395  *
11396  *  @param shader_stage Shader stage, for which a subroutine uniform should be
11397  *                      declared in the shader without a matching subroutine.
11398  **/
executeIteration(const Utils::_shader_stage & shader_stage)11399 void NegativeTest5::executeIteration(const Utils::_shader_stage &shader_stage)
11400 {
11401     std::string fs_body = getFragmentShaderBody(shader_stage == Utils::SHADER_STAGE_FRAGMENT);
11402     std::string gs_body = getGeometryShaderBody(shader_stage == Utils::SHADER_STAGE_GEOMETRY);
11403     std::string tc_body = getTessellationControlShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_CONTROL);
11404     std::string te_body =
11405         getTessellationEvaluationShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_EVALUATION);
11406     std::string vs_body = getVertexShaderBody(shader_stage == Utils::SHADER_STAGE_VERTEX);
11407 
11408     if (Utils::buildProgram(m_context.getRenderContext().getFunctions(), vs_body, tc_body, te_body, gs_body, fs_body,
11409                             DE_NULL, /* xfb_varyings */
11410                             DE_NULL, /* n_xfb_varyings */
11411                             &m_vs_id, &m_tc_id, &m_te_id, &m_gs_id, &m_fs_id, &m_po_id))
11412     {
11413         /* None of the test programs should ever build successfully */
11414         m_testCtx.getLog() << tcu::TestLog::Message
11415                            << "A program object, consisting of the following shaders, has linked"
11416                               " correctly. One of the shaders defines a subroutine uniform but does "
11417                               "not implement any function that matches subroutine type of the uniform."
11418                               " This should have resulted in a compilation/link-time error.\n"
11419                               "\n"
11420                               "Vertex shader:\n"
11421                               "\n"
11422                            << vs_body
11423                            << "\n"
11424                               "Tessellation control shader:\n"
11425                               "\n"
11426                            << tc_body
11427                            << "\n"
11428                               "Tessellation evaluation shader:\n"
11429                               "\n"
11430                            << te_body
11431                            << "\n"
11432                               "Geometry shader:\n"
11433                               "\n"
11434                            << gs_body
11435                            << "\n"
11436                               "Fragment shader:\n"
11437                               "\n"
11438                            << fs_body << tcu::TestLog::EndMessage;
11439 
11440         m_has_test_passed = false;
11441     }
11442 }
11443 
11444 /** Retrieves fragment shader body.
11445  *
11446  *  @param include_invalid_subroutine_uniform_declaration true if the shader should declare
11447  *                                                        a subroutine uniform without
11448  *                                                        a matching subroutine, false otherwise.
11449  *
11450  *  @return Requested string.
11451  **/
getFragmentShaderBody(bool include_invalid_subroutine_uniform_declaration) const11452 std::string NegativeTest5::getFragmentShaderBody(bool include_invalid_subroutine_uniform_declaration) const
11453 {
11454     std::stringstream result_sstream;
11455 
11456     result_sstream << "#version 400\n"
11457                       "\n"
11458                       "#extension GL_ARB_shader_subroutine : require\n"
11459                       "\n";
11460 
11461     if (include_invalid_subroutine_uniform_declaration)
11462     {
11463         result_sstream << "subroutine void subroutineTestTypeFS(out vec4 test);\n"
11464                           "\n"
11465                           "subroutine uniform subroutineTestTypeFS test_subroutineFS;\n";
11466     }
11467 
11468     result_sstream << "\n"
11469                       "out vec4 result;\n"
11470                       "\n"
11471                       "void main()\n"
11472                       "{\n";
11473 
11474     if (include_invalid_subroutine_uniform_declaration)
11475     {
11476         result_sstream << "    test_subroutineFS(result);\n";
11477     }
11478     else
11479     {
11480         result_sstream << "    result = vec4(0, 1, 2, 3);\n";
11481     }
11482 
11483     result_sstream << "}\n";
11484 
11485     return result_sstream.str();
11486 }
11487 
11488 /** Retrieves geometry shader body.
11489  *
11490  *  @param include_invalid_subroutine_uniform_declaration true if the shader should declare
11491  *                                                        a subroutine uniform without
11492  *                                                        a matching subroutine, false otherwise.
11493  *
11494  *  @return Requested string.
11495  **/
getGeometryShaderBody(bool include_invalid_subroutine_uniform_declaration) const11496 std::string NegativeTest5::getGeometryShaderBody(bool include_invalid_subroutine_uniform_declaration) const
11497 {
11498     std::stringstream result_sstream;
11499 
11500     result_sstream << "#version 400\n"
11501                       "\n"
11502                       "#extension GL_ARB_shader_subroutine : require\n"
11503                       "\n"
11504                       "layout (points)                   in;\n"
11505                       "layout (points, max_vertices = 1) out;\n"
11506                       "\n";
11507 
11508     if (include_invalid_subroutine_uniform_declaration)
11509     {
11510         result_sstream << "subroutine void subroutineTestTypeGS(out vec4 test);\n"
11511                           "\n"
11512                           "subroutine uniform subroutineTestTypeGS test_subroutineGS;\n";
11513     }
11514 
11515     result_sstream << "\n"
11516                       "void main()\n"
11517                       "{\n";
11518 
11519     if (include_invalid_subroutine_uniform_declaration)
11520     {
11521         result_sstream << "    test_subroutineGS(gl_Position);\n";
11522     }
11523     else
11524     {
11525         result_sstream << "    gl_Position = vec4(0, 1, 2, 3);\n";
11526     }
11527 
11528     result_sstream << "EmitVertex();\n"
11529                       "}\n";
11530 
11531     return result_sstream.str();
11532 }
11533 
11534 /** Retrieves tessellation control shader body.
11535  *
11536  *  @param include_invalid_subroutine_uniform_declaration true if the shader should declare
11537  *                                                        a subroutine uniform without
11538  *                                                        a matching subroutine, false otherwise.
11539  *
11540  *  @return Requested string.
11541  **/
getTessellationControlShaderBody(bool include_invalid_subroutine_uniform_declaration) const11542 std::string NegativeTest5::getTessellationControlShaderBody(bool include_invalid_subroutine_uniform_declaration) const
11543 {
11544     std::stringstream result_sstream;
11545 
11546     result_sstream << "#version 400\n"
11547                       "\n"
11548                       "#extension GL_ARB_shader_subroutine : require\n"
11549                       "\n"
11550                       "layout (vertices = 4) out;\n"
11551                       "\n";
11552 
11553     if (include_invalid_subroutine_uniform_declaration)
11554     {
11555         result_sstream << "subroutine void subroutineTestTypeTC(out vec4 test);\n"
11556                           "\n"
11557                           "subroutine uniform subroutineTestTypeTC test_subroutineTC;\n";
11558     }
11559 
11560     result_sstream << "\n"
11561                       "void main()\n"
11562                       "{\n";
11563 
11564     if (include_invalid_subroutine_uniform_declaration)
11565     {
11566         result_sstream << "    test_subroutineTC(gl_out[gl_InvocationID].gl_Position);\n";
11567     }
11568     else
11569     {
11570         result_sstream << "    gl_out[gl_InvocationID].gl_Position = vec4(0, 1, 2, 3);\n";
11571     }
11572 
11573     result_sstream << "}\n";
11574 
11575     return result_sstream.str();
11576 }
11577 
11578 /** Retrieves tessellation evaluation body.
11579  *
11580  *  @param include_invalid_subroutine_uniform_declaration true if the shader should declare
11581  *                                                        a subroutine uniform without
11582  *                                                        a matching subroutine, false otherwise.
11583  *
11584  *  @return Requested string.
11585  **/
getTessellationEvaluationShaderBody(bool include_invalid_subroutine_uniform_declaration) const11586 std::string NegativeTest5::getTessellationEvaluationShaderBody(
11587     bool include_invalid_subroutine_uniform_declaration) const
11588 {
11589     std::stringstream result_sstream;
11590 
11591     result_sstream << "#version 400\n"
11592                       "\n"
11593                       "#extension GL_ARB_shader_subroutine : require\n"
11594                       "\n"
11595                       "layout (quads) in;\n"
11596                       "\n";
11597 
11598     if (include_invalid_subroutine_uniform_declaration)
11599     {
11600         result_sstream << "subroutine void subroutineTestTypeTE(out vec4 test);\n"
11601                           "\n"
11602                           "subroutine uniform subroutineTestTypeTE test_subroutineTE;\n";
11603     }
11604 
11605     result_sstream << "\n"
11606                       "void main()\n"
11607                       "{\n";
11608 
11609     if (include_invalid_subroutine_uniform_declaration)
11610     {
11611         result_sstream << "    test_subroutineTE(gl_Position);\n";
11612     }
11613     else
11614     {
11615         result_sstream << "    gl_Position = vec4(0, 1, 2, 3);\n";
11616     }
11617 
11618     result_sstream << "}\n";
11619 
11620     return result_sstream.str();
11621 }
11622 
11623 /** Retrieves vertex shader body.
11624  *
11625  *  @param include_invalid_subroutine_uniform_declaration true if the shader should declare
11626  *                                                        a subroutine uniform without
11627  *                                                        a matching subroutine, false otherwise.
11628  *
11629  *  @return Requested string.
11630  **/
getVertexShaderBody(bool include_invalid_subroutine_uniform_declaration) const11631 std::string NegativeTest5::getVertexShaderBody(bool include_invalid_subroutine_uniform_declaration) const
11632 {
11633     std::stringstream result_sstream;
11634 
11635     result_sstream << "#version 400\n"
11636                       "\n"
11637                       "#extension GL_ARB_shader_subroutine : require\n"
11638                       "\n";
11639 
11640     if (include_invalid_subroutine_uniform_declaration)
11641     {
11642         result_sstream << "subroutine void subroutineTestTypeVS(out vec4 test);\n"
11643                           "\n"
11644                           "subroutine uniform subroutineTestTypeVS test_subroutineVS;\n";
11645     }
11646 
11647     result_sstream << "\n"
11648                       "void main()\n"
11649                       "{\n";
11650 
11651     if (include_invalid_subroutine_uniform_declaration)
11652     {
11653         result_sstream << "    test_subroutineVS(gl_Position);\n";
11654     }
11655     else
11656     {
11657         result_sstream << "    gl_Position = vec4(0, 1, 2, 3);\n";
11658     }
11659 
11660     result_sstream << "}\n";
11661 
11662     return result_sstream.str();
11663 }
11664 
11665 /** Executes test iteration.
11666  *
11667  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
11668  */
iterate()11669 tcu::TestNode::IterateResult NegativeTest5::iterate()
11670 {
11671     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
11672     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
11673     {
11674         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
11675     }
11676 
11677     /* Iterate over all shader stages. Iteration-specific shader stage defines a subroutine type &
11678      * a corresponding subroutine uniform, for which no compatible subroutines are available. All
11679      * other shader stages are defined correctly.
11680      */
11681     for (int shader_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
11682          shader_stage < static_cast<int>(Utils::SHADER_STAGE_COUNT); ++shader_stage)
11683     {
11684         executeIteration(static_cast<Utils::_shader_stage>(shader_stage));
11685         deinitIteration();
11686     } /* for (all shader stages) */
11687 
11688     /* All done */
11689     if (m_has_test_passed)
11690     {
11691         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
11692     }
11693     else
11694     {
11695         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
11696     }
11697 
11698     return STOP;
11699 }
11700 
11701 /** Constructor.
11702  *
11703  *  @param context Rendering context.
11704  *
11705  **/
NegativeTest6(deqp::Context & context)11706 NegativeTest6::NegativeTest6(deqp::Context &context)
11707     : TestCase(context, "two_duplicate_functions_one_being_a_subroutine",
11708                "Verifies that a link- or compile-time error occurs if any shader in "
11709                "a program object includes two functions with the same name and one "
11710                "of which is associated with a subroutine type.")
11711     , m_fs_id(0)
11712     , m_gs_id(0)
11713     , m_has_test_passed(true)
11714     , m_po_id(0)
11715     , m_tc_id(0)
11716     , m_te_id(0)
11717     , m_vs_id(0)
11718 {
11719     /* Left blank intentionally */
11720 }
11721 
11722 /** Deinitializes all GL objects that may have been created during test execution */
deinit()11723 void NegativeTest6::deinit()
11724 {
11725     deinitIteration();
11726 }
11727 
11728 /** Deinitializes all GL objects that may have been created during a single test
11729  *  iteration.
11730  ***/
deinitIteration()11731 void NegativeTest6::deinitIteration()
11732 {
11733     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
11734 
11735     if (m_fs_id != 0)
11736     {
11737         gl.deleteShader(m_fs_id);
11738 
11739         m_fs_id = 0;
11740     }
11741 
11742     if (m_gs_id != 0)
11743     {
11744         gl.deleteShader(m_gs_id);
11745 
11746         m_gs_id = 0;
11747     }
11748 
11749     if (m_po_id != 0)
11750     {
11751         gl.deleteProgram(m_po_id);
11752 
11753         m_po_id = 0;
11754     }
11755 
11756     if (m_tc_id != 0)
11757     {
11758         gl.deleteShader(m_tc_id);
11759 
11760         m_tc_id = 0;
11761     }
11762 
11763     if (m_te_id != 0)
11764     {
11765         gl.deleteShader(m_te_id);
11766 
11767         m_te_id = 0;
11768     }
11769 
11770     if (m_vs_id != 0)
11771     {
11772         gl.deleteShader(m_vs_id);
11773 
11774         m_vs_id = 0;
11775     }
11776 }
11777 
11778 /** Executes a single test iteration.
11779  *
11780  *  If the iteration fails, m_has_test_passed will be set to false.
11781  *
11782  *  @param shader_stage Shader stage, for which two duplicate functions
11783  *                      (one additionally marked as subroutine) should
11784  *                      be defined.
11785  **/
executeIteration(const Utils::_shader_stage & shader_stage)11786 void NegativeTest6::executeIteration(const Utils::_shader_stage &shader_stage)
11787 {
11788     std::string fs_body = getFragmentShaderBody(shader_stage == Utils::SHADER_STAGE_FRAGMENT);
11789     std::string gs_body = getGeometryShaderBody(shader_stage == Utils::SHADER_STAGE_GEOMETRY);
11790     std::string tc_body = getTessellationControlShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_CONTROL);
11791     std::string te_body =
11792         getTessellationEvaluationShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_EVALUATION);
11793     std::string vs_body = getVertexShaderBody(shader_stage == Utils::SHADER_STAGE_VERTEX);
11794 
11795     if (Utils::buildProgram(m_context.getRenderContext().getFunctions(), vs_body, tc_body, te_body, gs_body, fs_body,
11796                             DE_NULL, /* xfb_varyings */
11797                             DE_NULL, /* n_xfb_varyings */
11798                             &m_vs_id, &m_tc_id, &m_te_id, &m_gs_id, &m_fs_id, &m_po_id))
11799     {
11800         /* None of the test programs should ever build successfully */
11801         m_testCtx.getLog() << tcu::TestLog::Message
11802                            << "A program object, consisting of the following shaders, has linked"
11803                               " correctly. This is invalid, because one of the shaders defines two"
11804                               " functions with the same name, with an exception that one of the"
11805                               " functions is marked as a subroutine.\n"
11806                               "\n"
11807                               "Vertex shader:\n"
11808                               "\n"
11809                            << vs_body
11810                            << "\n"
11811                               "Tessellation control shader:\n"
11812                               "\n"
11813                            << tc_body
11814                            << "\n"
11815                               "Tessellation evaluation shader:\n"
11816                               "\n"
11817                            << te_body
11818                            << "\n"
11819                               "Geometry shader:\n"
11820                               "\n"
11821                            << gs_body
11822                            << "\n"
11823                               "Fragment shader:\n"
11824                               "\n"
11825                            << fs_body << tcu::TestLog::EndMessage;
11826 
11827         m_has_test_passed = false;
11828     }
11829 }
11830 
11831 /** Retrieves fragment shader body.
11832  *
11833  *  @param include_invalid_declaration true if the shader should include duplicate function
11834  *                                     declaration.
11835  *
11836  *  @return Requested string.
11837  **/
getFragmentShaderBody(bool include_invalid_declaration) const11838 std::string NegativeTest6::getFragmentShaderBody(bool include_invalid_declaration) const
11839 {
11840     std::stringstream result_sstream;
11841 
11842     result_sstream << "#version 400\n"
11843                       "\n"
11844                       "#extension GL_ARB_shader_subroutine : require\n"
11845                       "\n";
11846 
11847     if (include_invalid_declaration)
11848     {
11849         result_sstream << "subroutine void subroutineTestTypeFS(out vec4 test);\n"
11850                           "\n"
11851                           "subroutine(subroutineTestTypeFS) void test_impl1(out vec4 test)\n"
11852                           "{\n"
11853                           "    test = vec4(1, 2, 3, 4);\n"
11854                           "}\n"
11855                           "\n"
11856                           "void test_impl1(out vec4 test)\n"
11857                           "{\n"
11858                           "    test = vec4(2, 3, 4, 5);\n"
11859                           "}\n"
11860                           "\n"
11861                           "subroutine uniform subroutineTestTypeFS test_subroutineFS;\n";
11862     }
11863 
11864     result_sstream << "\n"
11865                       "out vec4 result;\n"
11866                       "\n"
11867                       "void main()\n"
11868                       "{\n";
11869 
11870     if (include_invalid_declaration)
11871     {
11872         result_sstream << "    test_subroutineFS(result);\n";
11873     }
11874     else
11875     {
11876         result_sstream << "    result = vec4(0, 1, 2, 3);\n";
11877     }
11878 
11879     result_sstream << "}\n";
11880 
11881     return result_sstream.str();
11882 }
11883 
11884 /** Retrieves geometry shader body.
11885  *
11886  *  @param include_invalid_declaration true if the shader should include duplicate function
11887  *                                     declaration.
11888  *
11889  *  @return Requested string.
11890  **/
getGeometryShaderBody(bool include_invalid_declaration) const11891 std::string NegativeTest6::getGeometryShaderBody(bool include_invalid_declaration) const
11892 {
11893     std::stringstream result_sstream;
11894 
11895     result_sstream << "#version 400\n"
11896                       "\n"
11897                       "#extension GL_ARB_shader_subroutine : require\n"
11898                       "\n"
11899                       "layout (points)                   in;\n"
11900                       "layout (points, max_vertices = 1) out;\n"
11901                       "\n";
11902 
11903     if (include_invalid_declaration)
11904     {
11905         result_sstream << "subroutine void subroutineTestTypeGS(out vec4 test);\n"
11906                           "\n"
11907                           "subroutine(subroutineTestTypeGS) void test_impl1(out vec4 test)\n"
11908                           "{\n"
11909                           "    test = vec4(1, 2, 3, 4);\n"
11910                           "}\n"
11911                           "\n"
11912                           "void test_impl1(out vec4 test)\n"
11913                           "{\n"
11914                           "    test = vec4(2, 3, 4, 5);\n"
11915                           "}\n"
11916                           "\n"
11917                           "subroutine uniform subroutineTestTypeGS test_subroutineGS;\n";
11918     }
11919 
11920     result_sstream << "\n"
11921                       "void main()\n"
11922                       "{\n";
11923 
11924     if (include_invalid_declaration)
11925     {
11926         result_sstream << "    test_subroutineGS(gl_Position);\n";
11927     }
11928     else
11929     {
11930         result_sstream << "    gl_Position = vec4(0, 1, 2, 3);\n";
11931     }
11932 
11933     result_sstream << "EmitVertex();\n"
11934                       "}\n";
11935 
11936     return result_sstream.str();
11937 }
11938 
11939 /** Retrieves tessellation control shader body.
11940  *
11941  *  @param include_invalid_declaration true if the shader should include duplicate function
11942  *                                     declaration.
11943  *
11944  *  @return Requested string.
11945  **/
getTessellationControlShaderBody(bool include_invalid_declaration) const11946 std::string NegativeTest6::getTessellationControlShaderBody(bool include_invalid_declaration) const
11947 {
11948     std::stringstream result_sstream;
11949 
11950     result_sstream << "#version 400\n"
11951                       "\n"
11952                       "#extension GL_ARB_shader_subroutine : require\n"
11953                       "\n"
11954                       "layout (vertices = 4) out;\n"
11955                       "\n";
11956 
11957     if (include_invalid_declaration)
11958     {
11959         result_sstream << "subroutine void subroutineTestTypeTC(out vec4 test);\n"
11960                           "\n"
11961                           "subroutine(subroutineTestTypeTC) void test_impl1(out vec4 test)\n"
11962                           "{\n"
11963                           "    test = vec4(1, 2, 3, 4);\n"
11964                           "}\n"
11965                           "\n"
11966                           "void test_impl1(out vec4 test)\n"
11967                           "{\n"
11968                           "    test = vec4(2, 3, 4, 5);\n"
11969                           "}\n"
11970                           "\n"
11971                           "subroutine uniform subroutineTestTypeTC test_subroutineTC;\n";
11972     }
11973 
11974     result_sstream << "\n"
11975                       "void main()\n"
11976                       "{\n";
11977 
11978     if (include_invalid_declaration)
11979     {
11980         result_sstream << "    test_subroutineTC(gl_out[gl_InvocationID].gl_Position);\n";
11981     }
11982     else
11983     {
11984         result_sstream << "    gl_out[gl_InvocationID].gl_Position = vec4(0, 1, 2, 3);\n";
11985     }
11986 
11987     result_sstream << "}\n";
11988 
11989     return result_sstream.str();
11990 }
11991 
11992 /** Retrieves tessellation evaluation body.
11993  *
11994  *  @param include_invalid_declaration true if the shader should include duplicate function
11995  *                                     declaration.
11996  *
11997  *  @return Requested string.
11998  **/
getTessellationEvaluationShaderBody(bool include_invalid_declaration) const11999 std::string NegativeTest6::getTessellationEvaluationShaderBody(bool include_invalid_declaration) const
12000 {
12001     std::stringstream result_sstream;
12002 
12003     result_sstream << "#version 400\n"
12004                       "\n"
12005                       "#extension GL_ARB_shader_subroutine : require\n"
12006                       "\n"
12007                       "layout (quads) in;\n"
12008                       "\n";
12009 
12010     if (include_invalid_declaration)
12011     {
12012         result_sstream << "subroutine void subroutineTestTypeTE(out vec4 test);\n"
12013                           "\n"
12014                           "subroutine(subroutineTestTypeTE) void test_impl1(out vec4 test)\n"
12015                           "{\n"
12016                           "    test = vec4(1, 2, 3, 4);\n"
12017                           "}\n"
12018                           "\n"
12019                           "void test_impl1(out vec4 test)\n"
12020                           "{\n"
12021                           "    test = vec4(2, 3, 4, 5);\n"
12022                           "}\n"
12023                           "\n"
12024                           "subroutine uniform subroutineTestTypeTE test_subroutineTE;\n";
12025     }
12026 
12027     result_sstream << "\n"
12028                       "void main()\n"
12029                       "{\n";
12030 
12031     if (include_invalid_declaration)
12032     {
12033         result_sstream << "    test_subroutineTE(gl_Position);\n";
12034     }
12035     else
12036     {
12037         result_sstream << "    gl_Position = vec4(0, 1, 2, 3);\n";
12038     }
12039 
12040     result_sstream << "}\n";
12041 
12042     return result_sstream.str();
12043 }
12044 
12045 /** Retrieves vertex shader body.
12046  *
12047  *  @param include_invalid_declaration true if the shader should include duplicate function
12048  *                                     declaration.
12049  *
12050  *  @return Requested string.
12051  **/
getVertexShaderBody(bool include_invalid_declaration) const12052 std::string NegativeTest6::getVertexShaderBody(bool include_invalid_declaration) const
12053 {
12054     std::stringstream result_sstream;
12055 
12056     result_sstream << "#version 400\n"
12057                       "\n"
12058                       "#extension GL_ARB_shader_subroutine : require\n"
12059                       "\n";
12060 
12061     if (include_invalid_declaration)
12062     {
12063         result_sstream << "subroutine void subroutineTestTypeVS(out vec4 test);\n"
12064                           "\n"
12065                           "subroutine(subroutineTestTypeVS) void test_impl1(out vec4 test)\n"
12066                           "{\n"
12067                           "    test = vec4(1, 2, 3, 4);\n"
12068                           "}\n"
12069                           "\n"
12070                           "void test_impl1(out vec4 test)\n"
12071                           "{\n"
12072                           "    test = vec4(2, 3, 4, 5);\n"
12073                           "}\n"
12074                           "\n"
12075                           "subroutine uniform subroutineTestTypeVS test_subroutineVS;\n";
12076     }
12077 
12078     result_sstream << "\n"
12079                       "void main()\n"
12080                       "{\n";
12081 
12082     if (include_invalid_declaration)
12083     {
12084         result_sstream << "    test_subroutineVS(gl_Position);\n";
12085     }
12086     else
12087     {
12088         result_sstream << "    gl_Position = vec4(0, 1, 2, 3);\n";
12089     }
12090 
12091     result_sstream << "}\n";
12092 
12093     return result_sstream.str();
12094 }
12095 
12096 /** Executes test iteration.
12097  *
12098  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
12099  */
iterate()12100 tcu::TestNode::IterateResult NegativeTest6::iterate()
12101 {
12102     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
12103     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
12104     {
12105         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
12106     }
12107 
12108     /* Iterate over all shader stages. In each iteration, we will inject invalid
12109      * duplicate function declarations to iteration-specific shader stage. All other
12110      * shader stages will be assigned valid bodies. Test should fail if the program
12111      * links successfully.
12112      */
12113     for (int shader_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
12114          shader_stage < static_cast<int>(Utils::SHADER_STAGE_COUNT); ++shader_stage)
12115     {
12116         executeIteration(static_cast<Utils::_shader_stage>(shader_stage));
12117         deinitIteration();
12118     } /* for (all shader stages) */
12119 
12120     /* All done */
12121     if (m_has_test_passed)
12122     {
12123         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
12124     }
12125     else
12126     {
12127         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
12128     }
12129 
12130     return STOP;
12131 }
12132 
12133 /** Constructor
12134  *
12135  * @param context CTS context
12136  **/
NegativeTest7(deqp::Context & context)12137 NegativeTest7::NegativeTest7(deqp::Context &context)
12138     : TestCase(context, "recursion", "Verify that it is not possible to build program with recursing subroutines")
12139     , m_program_id(0)
12140     , m_vertex_shader_id(0)
12141 {
12142     /* Nothing to be done here */
12143 }
12144 
12145 /** Deinitializes all GL objects that may have been created during test execution
12146  *
12147  **/
deinit()12148 void NegativeTest7::deinit()
12149 {
12150     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
12151 
12152     if (m_program_id != 0)
12153     {
12154         gl.deleteProgram(m_program_id);
12155 
12156         m_program_id = 0;
12157     }
12158 
12159     if (m_vertex_shader_id != 0)
12160     {
12161         gl.deleteShader(m_vertex_shader_id);
12162 
12163         m_vertex_shader_id = 0;
12164     }
12165 }
12166 
12167 /** Executes test iteration.
12168  *
12169  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
12170  **/
iterate()12171 tcu::TestNode::IterateResult NegativeTest7::iterate()
12172 {
12173     static const GLchar *vertex_shader_with_static_recursion =
12174         "#version 400\n"
12175         "\n"
12176         "#extension GL_ARB_shader_subroutine : require\n"
12177         "\n"
12178         "precision highp float;\n"
12179         "\n"
12180         "subroutine vec4 routine_type(in vec4 data, in uint control);\n"
12181         "\n"
12182         "subroutine (routine_type) vec4 power_routine(in vec4 data, in uint control)\n"
12183         "{\n"
12184         "    if (0 != control)\n"
12185         "    {\n"
12186         "        return data * power_routine(data, control - 1);\n"
12187         "    }\n"
12188         "    else\n"
12189         "    {\n"
12190         "        return vec4(1, 1, 1, 1);\n"
12191         "    }\n"
12192         "}\n"
12193         "\n"
12194         "subroutine (routine_type) vec4 select_routine(in vec4 data, in uint control)\n"
12195         "{\n"
12196         "    if (0 == control)\n"
12197         "    {\n"
12198         "        return data.rrrr;\n"
12199         "    }\n"
12200         "    else if (1 == control)\n"
12201         "    {\n"
12202         "        return data.gggg;\n"
12203         "    }\n"
12204         "    else if (2 == control)\n"
12205         "    {\n"
12206         "        return data.bbbb;\n"
12207         "    }\n"
12208         "    else\n"
12209         "    {\n"
12210         "        return data.aaaa;\n"
12211         "    }\n"
12212         "}\n"
12213         "\n"
12214         "subroutine uniform routine_type routine;\n"
12215         "\n"
12216         "uniform vec4 uni_value;\n"
12217         "uniform uint uni_control;\n"
12218         "\n"
12219         "out vec4 out_result;\n"
12220         "\n"
12221         "void main()\n"
12222         "{\n"
12223         "    out_result = routine(uni_value, uni_control);\n"
12224         "}\n"
12225         "\n";
12226 
12227     static const GLchar *vertex_shader_with_dynamic_recursion =
12228         "#version 400\n"
12229         "\n"
12230         "#extension GL_ARB_shader_subroutine : require\n"
12231         "\n"
12232         "precision highp float;\n"
12233         "\n"
12234         "subroutine vec4 routine_type(in vec4 data);\n"
12235         "\n"
12236         "subroutine uniform routine_type routine;\n"
12237         "\n"
12238         "subroutine (routine_type) vec4 div_by_2(in vec4 data)\n"
12239         "{\n"
12240         "    return data / 2;\n"
12241         "}\n"
12242         "\n"
12243         "subroutine (routine_type) vec4 div_routine_result_by_2(in vec4 data)\n"
12244         "{\n"
12245         "    return routine(data) / 2;\n"
12246         "}\n"
12247         "\n"
12248         "uniform vec4 uni_value;\n"
12249         "\n"
12250         "out vec4 out_result;\n"
12251         "\n"
12252         "void main()\n"
12253         "{\n"
12254         "    out_result = routine(uni_value);\n"
12255         "}\n"
12256         "\n";
12257 
12258     static const GLchar *vertex_shader_with_subroutine_function_recursion =
12259         "#version 400\n"
12260         "\n"
12261         "#extension GL_ARB_shader_subroutine : require\n"
12262         "\n"
12263         "precision highp float;\n"
12264         "\n"
12265         "subroutine vec4 routine_type(in vec4 data);\n"
12266         "\n"
12267         "subroutine uniform routine_type routine;\n"
12268         "\n"
12269         "vec4 function(in vec4 data)\n"
12270         "{\n"
12271         "    return routine(data) + vec4(0.5, 0.5, 0.5, 0.5);\n"
12272         "}\n"
12273         "\n"
12274         "subroutine (routine_type) vec4 routine_a(in vec4 data)\n"
12275         "{\n"
12276         "    return function(data) / 2;\n"
12277         "}\n"
12278         "\n"
12279         "subroutine (routine_type) vec4 routine_b(in vec4 data)\n"
12280         "{\n"
12281         "    return routine_a(data) * 2;\n"
12282         "}\n"
12283         "\n"
12284         "uniform vec4 uni_value;\n"
12285         "\n"
12286         "out vec4 out_result;\n"
12287         "\n"
12288         "void main()\n"
12289         "{\n"
12290         "    out_result = routine(uni_value);\n"
12291         "}\n"
12292         "\n";
12293 
12294     bool result = true;
12295 
12296     if (false == test(vertex_shader_with_subroutine_function_recursion, "routine_a"))
12297     {
12298         result = false;
12299     }
12300 
12301     if (false == test(vertex_shader_with_dynamic_recursion, "div_routine_result_by_2"))
12302     {
12303         result = false;
12304     }
12305 
12306     if (false == test(vertex_shader_with_static_recursion, "power_routine"))
12307     {
12308         result = false;
12309     }
12310 
12311     /* Set result */
12312     if (true == result)
12313     {
12314         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
12315     }
12316     else
12317     {
12318         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
12319     }
12320 
12321     /* Done */
12322     return tcu::TestNode::STOP;
12323 }
12324 
12325 /** Try to build program from vertex shader code.
12326  *
12327  * @param vertex_shader_code        Source code of vertex shader
12328  * @param name_of_recursive_routine Name of subroutine that should cause link failure due to recursion
12329  *
12330  * @return true build process failed, false otherwise
12331  **/
test(const GLchar * vertex_shader_code,const GLchar * name_of_recursive_routine)12332 bool NegativeTest7::test(const GLchar *vertex_shader_code, const GLchar *name_of_recursive_routine)
12333 {
12334     const glw::Functions &gl          = m_context.getRenderContext().getFunctions();
12335     bool result                       = true;
12336     static const GLchar *varying_name = "out_result";
12337 
12338     /* Try to build program */
12339     if (true == Utils::buildProgram(gl, vertex_shader_code, "", "", "", "", &varying_name /* varying_names */,
12340                                     1 /* n_varyings */, &m_vertex_shader_id, 0, 0, 0, 0, &m_program_id))
12341     {
12342         /* Success is considered an error */
12343 
12344         Utils::program program(m_context);
12345         GLuint index = 0;
12346 
12347         program.build(0, 0, 0, 0, 0, vertex_shader_code, 0, 0);
12348 
12349         /* Verify that recursive subroutine is active */
12350         try
12351         {
12352             index = program.getSubroutineIndex(name_of_recursive_routine, GL_VERTEX_SHADER);
12353         }
12354         catch (const std::exception &exc)
12355         {
12356             /* Something wrong with shader or compilation */
12357             m_context.getTestContext().getLog()
12358                 << tcu::TestLog::Message << "It is expected that subroutine: \n"
12359                 << name_of_recursive_routine
12360                 << " is considered active. This subroutine is potentially recursive and should cause link failure."
12361                 << tcu::TestLog::EndMessage;
12362 
12363             throw exc;
12364         }
12365 
12366         /* Subsoutine is active, however linking should fail */
12367         m_context.getTestContext().getLog()
12368             << tcu::TestLog::Message << "Error. Program with potentially recursive subroutine, "
12369             << name_of_recursive_routine << ", which is active, index: " << index << ", has been built successfully.\n"
12370             << vertex_shader_code << tcu::TestLog::EndMessage;
12371 
12372         result = false;
12373     }
12374 
12375     /* Delete program and shader */
12376     deinit();
12377 
12378     /* Done */
12379     return result;
12380 }
12381 
12382 /** Constructor.
12383  *
12384  *  @param context Rendering context.
12385  *
12386  **/
NegativeTest8(deqp::Context & context)12387 NegativeTest8::NegativeTest8(deqp::Context &context)
12388     : TestCase(context, "subroutine_wo_body",
12389                "Verifies that a compile- or link-time error occurs if a function "
12390                "declared as a subroutine does not include a body.")
12391     , m_fs_id(0)
12392     , m_gs_id(0)
12393     , m_has_test_passed(true)
12394     , m_po_id(0)
12395     , m_tc_id(0)
12396     , m_te_id(0)
12397     , m_vs_id(0)
12398 {
12399     /* Left blank intentionally */
12400 }
12401 
12402 /** Deinitializes all GL objects that may have been created during test execution */
deinit()12403 void NegativeTest8::deinit()
12404 {
12405     deinitIteration();
12406 }
12407 
12408 /** Deinitializes all GL objects that may have been created during a single test
12409  *  iteration.
12410  ***/
deinitIteration()12411 void NegativeTest8::deinitIteration()
12412 {
12413     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
12414 
12415     if (m_fs_id != 0)
12416     {
12417         gl.deleteShader(m_fs_id);
12418 
12419         m_fs_id = 0;
12420     }
12421 
12422     if (m_gs_id != 0)
12423     {
12424         gl.deleteShader(m_gs_id);
12425 
12426         m_gs_id = 0;
12427     }
12428 
12429     if (m_po_id != 0)
12430     {
12431         gl.deleteProgram(m_po_id);
12432 
12433         m_po_id = 0;
12434     }
12435 
12436     if (m_tc_id != 0)
12437     {
12438         gl.deleteShader(m_tc_id);
12439 
12440         m_tc_id = 0;
12441     }
12442 
12443     if (m_te_id != 0)
12444     {
12445         gl.deleteShader(m_te_id);
12446 
12447         m_te_id = 0;
12448     }
12449 
12450     if (m_vs_id != 0)
12451     {
12452         gl.deleteShader(m_vs_id);
12453 
12454         m_vs_id = 0;
12455     }
12456 }
12457 
12458 /** Executes a single test iteration.
12459  *
12460  *  If the iteration fails, m_has_test_passed will be set to false.
12461  *
12462  *  @param shader_stage Shader stage, for which two duplicate functions
12463  *                      (one additionally marked as subroutine) should
12464  *                      be defined.
12465  **/
executeIteration(const Utils::_shader_stage & shader_stage)12466 void NegativeTest8::executeIteration(const Utils::_shader_stage &shader_stage)
12467 {
12468     std::string fs_body = getFragmentShaderBody(shader_stage == Utils::SHADER_STAGE_FRAGMENT);
12469     std::string gs_body = getGeometryShaderBody(shader_stage == Utils::SHADER_STAGE_GEOMETRY);
12470     std::string tc_body = getTessellationControlShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_CONTROL);
12471     std::string te_body =
12472         getTessellationEvaluationShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_EVALUATION);
12473     std::string vs_body = getVertexShaderBody(shader_stage == Utils::SHADER_STAGE_VERTEX);
12474 
12475     if (Utils::buildProgram(m_context.getRenderContext().getFunctions(), vs_body, tc_body, te_body, gs_body, fs_body,
12476                             DE_NULL, /* xfb_varyings */
12477                             DE_NULL, /* n_xfb_varyings */
12478                             &m_vs_id, &m_tc_id, &m_te_id, &m_gs_id, &m_fs_id, &m_po_id))
12479     {
12480         /* None of the test programs should ever build successfully */
12481         m_testCtx.getLog() << tcu::TestLog::Message
12482                            << "A program object consisting of FS+GS+TC+TE+VS stages has linked successfully, "
12483                               "even though one of the shaders only defines a subroutine that lacks any body."
12484                               "\n"
12485                               "Vertex shader:\n"
12486                               "\n"
12487                            << vs_body
12488                            << "\n"
12489                               "Tessellation control shader:\n"
12490                               "\n"
12491                            << tc_body
12492                            << "\n"
12493                               "Tessellation evaluation shader:\n"
12494                               "\n"
12495                            << te_body
12496                            << "\n"
12497                               "Geometry shader:\n"
12498                               "\n"
12499                            << gs_body
12500                            << "\n"
12501                               "Fragment shader:\n"
12502                               "\n"
12503                            << fs_body << tcu::TestLog::EndMessage;
12504 
12505         m_has_test_passed = false;
12506     }
12507 }
12508 
12509 /** Retrieves fragment shader body.
12510  *
12511  *  @param include_invalid_declaration true if a subroutine prototype should be included in
12512  *                                     the shader, false to skip it.
12513  *
12514  *  @return Requested string.
12515  **/
getFragmentShaderBody(bool include_invalid_declaration) const12516 std::string NegativeTest8::getFragmentShaderBody(bool include_invalid_declaration) const
12517 {
12518     std::stringstream result_sstream;
12519 
12520     result_sstream << "#version 400\n"
12521                       "\n"
12522                       "#extension GL_ARB_shader_subroutine : require\n"
12523                       "\n";
12524 
12525     if (include_invalid_declaration)
12526     {
12527         result_sstream << "subroutine void subroutineTestTypeFS(out vec4 test);\n"
12528                           "\n"
12529                           "subroutine(subroutineTestTypeFS) void test_impl1(out vec4 test);\n"
12530                           "\n"
12531                           "subroutine uniform subroutineTestTypeFS test_subroutineFS;\n";
12532     }
12533 
12534     result_sstream << "\n"
12535                       "out vec4 result;\n"
12536                       "\n"
12537                       "void main()\n"
12538                       "{\n";
12539 
12540     if (include_invalid_declaration)
12541     {
12542         result_sstream << "    test_subroutineFS(result);\n";
12543     }
12544     else
12545     {
12546         result_sstream << "    result = vec4(0, 1, 2, 3);\n";
12547     }
12548 
12549     result_sstream << "}\n";
12550 
12551     return result_sstream.str();
12552 }
12553 
12554 /** Retrieves geometry shader body.
12555  *
12556  *  @param include_invalid_declaration true if a subroutine prototype should be included in
12557  *                                     the shader, false to skip it.
12558  *
12559  *  @return Requested string.
12560  **/
getGeometryShaderBody(bool include_invalid_declaration) const12561 std::string NegativeTest8::getGeometryShaderBody(bool include_invalid_declaration) const
12562 {
12563     std::stringstream result_sstream;
12564 
12565     result_sstream << "#version 400\n"
12566                       "\n"
12567                       "#extension GL_ARB_shader_subroutine : require\n"
12568                       "\n"
12569                       "layout (points)                   in;\n"
12570                       "layout (points, max_vertices = 1) out;\n"
12571                       "\n";
12572 
12573     if (include_invalid_declaration)
12574     {
12575         result_sstream << "subroutine void subroutineTestTypeGS(out vec4 test);\n"
12576                           "\n"
12577                           "subroutine(subroutineTestTypeGS) void test_impl1(out vec4 test);\n"
12578                           "\n"
12579                           "subroutine uniform subroutineTestTypeGS test_subroutineGS;\n";
12580     }
12581 
12582     result_sstream << "\n"
12583                       "void main()\n"
12584                       "{\n";
12585 
12586     if (include_invalid_declaration)
12587     {
12588         result_sstream << "    test_subroutineGS(gl_Position);\n";
12589     }
12590     else
12591     {
12592         result_sstream << "    gl_Position = vec4(0, 1, 2, 3);\n";
12593     }
12594 
12595     result_sstream << "EmitVertex();\n"
12596                       "}\n";
12597 
12598     return result_sstream.str();
12599 }
12600 
12601 /** Retrieves tessellation control shader body.
12602  *
12603  *  @param include_invalid_declaration true if a subroutine prototype should be included in
12604  *                                     the shader, false to skip it.
12605  *
12606  *  @return Requested string.
12607  **/
getTessellationControlShaderBody(bool include_invalid_declaration) const12608 std::string NegativeTest8::getTessellationControlShaderBody(bool include_invalid_declaration) const
12609 {
12610     std::stringstream result_sstream;
12611 
12612     result_sstream << "#version 400\n"
12613                       "\n"
12614                       "#extension GL_ARB_shader_subroutine : require\n"
12615                       "\n"
12616                       "layout (vertices = 4) out;\n"
12617                       "\n";
12618 
12619     if (include_invalid_declaration)
12620     {
12621         result_sstream << "subroutine void subroutineTestTypeTC(out vec4 test);\n"
12622                           "\n"
12623                           "subroutine(subroutineTestTypeTC) void test_impl1(out vec4 test);\n"
12624                           "\n"
12625                           "subroutine uniform subroutineTestTypeTC test_subroutineTC;\n";
12626     }
12627 
12628     result_sstream << "\n"
12629                       "void main()\n"
12630                       "{\n";
12631 
12632     if (include_invalid_declaration)
12633     {
12634         result_sstream << "    test_subroutineTC(gl_out[gl_InvocationID].gl_Position);\n";
12635     }
12636     else
12637     {
12638         result_sstream << "    gl_out[gl_InvocationID].gl_Position = vec4(0, 1, 2, 3);\n";
12639     }
12640 
12641     result_sstream << "}\n";
12642 
12643     return result_sstream.str();
12644 }
12645 
12646 /** Retrieves tessellation evaluation body.
12647  *
12648  *  @param include_invalid_declaration true if a subroutine prototype should be included in
12649  *                                     the shader, false to skip it.
12650  *
12651  *  @return Requested string.
12652  **/
getTessellationEvaluationShaderBody(bool include_invalid_declaration) const12653 std::string NegativeTest8::getTessellationEvaluationShaderBody(bool include_invalid_declaration) const
12654 {
12655     std::stringstream result_sstream;
12656 
12657     result_sstream << "#version 400\n"
12658                       "\n"
12659                       "#extension GL_ARB_shader_subroutine : require\n"
12660                       "\n"
12661                       "layout (quads) in;\n"
12662                       "\n";
12663 
12664     if (include_invalid_declaration)
12665     {
12666         result_sstream << "subroutine void subroutineTestTypeTE(out vec4 test);\n"
12667                           "\n"
12668                           "subroutine(subroutineTestTypeTE) void test_impl1(out vec4 test);\n"
12669                           "\n"
12670                           "subroutine uniform subroutineTestTypeTE test_subroutineTE;\n";
12671     }
12672 
12673     result_sstream << "\n"
12674                       "void main()\n"
12675                       "{\n";
12676 
12677     if (include_invalid_declaration)
12678     {
12679         result_sstream << "    test_subroutineTE(gl_Position);\n";
12680     }
12681     else
12682     {
12683         result_sstream << "    gl_Position = vec4(0, 1, 2, 3);\n";
12684     }
12685 
12686     result_sstream << "}\n";
12687 
12688     return result_sstream.str();
12689 }
12690 
12691 /** Retrieves vertex shader body.
12692  *
12693  *  @param include_invalid_declaration true if a subroutine prototype should be included in
12694  *                                     the shader, false to skip it.
12695  *
12696  *  @return Requested string.
12697  **/
getVertexShaderBody(bool include_invalid_declaration) const12698 std::string NegativeTest8::getVertexShaderBody(bool include_invalid_declaration) const
12699 {
12700     std::stringstream result_sstream;
12701 
12702     result_sstream << "#version 400\n"
12703                       "\n"
12704                       "#extension GL_ARB_shader_subroutine : require\n"
12705                       "\n";
12706 
12707     if (include_invalid_declaration)
12708     {
12709         result_sstream << "subroutine void subroutineTestTypeVS(out vec4 test);\n"
12710                           "\n"
12711                           "subroutine(subroutineTestTypeVS) void test_impl1(out vec4 test);\n"
12712                           "\n"
12713                           "subroutine uniform subroutineTestTypeVS test_subroutineVS;\n";
12714     }
12715 
12716     result_sstream << "\n"
12717                       "void main()\n"
12718                       "{\n";
12719 
12720     if (include_invalid_declaration)
12721     {
12722         result_sstream << "    test_subroutineVS(gl_Position);\n";
12723     }
12724     else
12725     {
12726         result_sstream << "    gl_Position = vec4(0, 1, 2, 3);\n";
12727     }
12728 
12729     result_sstream << "}\n";
12730 
12731     return result_sstream.str();
12732 }
12733 
12734 /** Executes test iteration.
12735  *
12736  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
12737  */
iterate()12738 tcu::TestNode::IterateResult NegativeTest8::iterate()
12739 {
12740     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
12741     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
12742     {
12743         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
12744     }
12745 
12746     /* Iterate over all shader stages. For each iteration, iteration-specific shader stage
12747      * will feature an invalid subroutine definition. Other shader stages will be assigned
12748      * valid bodies. The test fails if a program built of such shaders links successfully.
12749      */
12750     for (int shader_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
12751          shader_stage < static_cast<int>(Utils::SHADER_STAGE_COUNT); ++shader_stage)
12752     {
12753         executeIteration(static_cast<Utils::_shader_stage>(shader_stage));
12754         deinitIteration();
12755     } /* for (all shader stages) */
12756 
12757     /* All done */
12758     if (m_has_test_passed)
12759     {
12760         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
12761     }
12762     else
12763     {
12764         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
12765     }
12766 
12767     return STOP;
12768 }
12769 
12770 /** Constructor.
12771  *
12772  *  @param context Rendering context.
12773  **/
NegativeTest9(deqp::Context & context)12774 NegativeTest9::NegativeTest9(deqp::Context &context)
12775     : TestCase(context, "subroutines_cannot_be_assigned_float_int_values_or_be_compared",
12776                "Make sure it is not possible to assign float/int to subroutine "
12777                "uniform and that subroutine uniform values cannot be compared.")
12778     , m_has_test_passed(true)
12779     , m_po_id(0)
12780     , m_vs_id(0)
12781 {
12782     /* Left blank intentionally */
12783 }
12784 
12785 /** Deinitializes any GL objects that may have been created during
12786  *  test execution.
12787  **/
deinit()12788 void NegativeTest9::deinit()
12789 {
12790     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
12791 
12792     if (m_po_id != 0)
12793     {
12794         gl.deleteProgram(m_po_id);
12795 
12796         m_po_id = 0;
12797     }
12798 
12799     if (m_vs_id != 0)
12800     {
12801         gl.deleteShader(m_vs_id);
12802 
12803         m_vs_id = 0;
12804     }
12805 }
12806 
12807 /** Returns a literal corresponding to user-specified test case enum.
12808  *
12809  *  @param test_case As per description.
12810  *
12811  *  @return Requested string.
12812  **/
getTestCaseString(const _test_case & test_case)12813 std::string NegativeTest9::getTestCaseString(const _test_case &test_case)
12814 {
12815     std::string result = "?";
12816 
12817     switch (test_case)
12818     {
12819     case TEST_CASE_INVALID_FLOAT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT:
12820         result = "TEST_CASE_INVALID_FLOAT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT";
12821         break;
12822     case TEST_CASE_INVALID_INT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT:
12823         result = "TEST_CASE_INVALID_INT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT";
12824         break;
12825     case TEST_CASE_INVALID_SUBROUTINE_UNIFORM_VALUE_COMPARISON:
12826         result = "TEST_CASE_INVALID_SUBROUTINE_UNIFORM_VALUE_COMPARISON";
12827         break;
12828     default:
12829         break;
12830     }
12831 
12832     return result;
12833 }
12834 
12835 /** Retrieves vertex shader body for user-specified test case.
12836  *
12837  *  @param test_case As per description.
12838  *
12839  *  @return Requested string.
12840  **/
getVertexShader(const _test_case & test_case)12841 std::string NegativeTest9::getVertexShader(const _test_case &test_case)
12842 {
12843     std::stringstream result_sstream;
12844 
12845     /* Form pre-amble */
12846     result_sstream << "#version 400\n"
12847                       "\n"
12848                       "#extension GL_ARB_shader_subroutine : require\n"
12849                       "\n"
12850                       /* Define a subroutine */
12851                       "subroutine void subroutineType(inout vec4 test);\n"
12852                       "\n"
12853                       "subroutine(subroutineType) void test_function(inout vec4 test)\n"
12854                       "{\n"
12855                       "    test += vec4(0, 1, 2, 3);\n"
12856                       "}\n"
12857                       "\n"
12858                       "subroutine uniform subroutineType function;\n"
12859                       "\n";
12860 
12861     /* Include case-specific implementation */
12862     switch (test_case)
12863     {
12864     case TEST_CASE_INVALID_FLOAT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT:
12865     {
12866         result_sstream << "void main()\n"
12867                           "{\n"
12868                           "    function = 1.0f;\n"
12869                           "\n"
12870                           "    function(gl_Position);\n"
12871                           "}\n";
12872 
12873         break;
12874     }
12875 
12876     case TEST_CASE_INVALID_INT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT:
12877     {
12878         result_sstream << "void main()\n"
12879                           "{\n"
12880                           "    function = 1;\n"
12881                           "\n"
12882                           "    function(gl_Position);\n"
12883                           "}\n";
12884 
12885         break;
12886     }
12887 
12888     case TEST_CASE_INVALID_SUBROUTINE_UNIFORM_VALUE_COMPARISON:
12889     {
12890         result_sstream << "subroutine uniform subroutineType function2;\n"
12891                           "\n"
12892                           "void main()\n"
12893                           "{\n"
12894                           "    if (function == function2)\n"
12895                           "    {\n"
12896                           "        function(gl_Position);\n"
12897                           "    }\n"
12898                           "    else\n"
12899                           "    {\n"
12900                           "        function2(gl_Position);\n"
12901                           "    }\n"
12902                           "}\n";
12903 
12904         break;
12905     }
12906 
12907     default:
12908         break;
12909     } /* switch (test_case) */
12910 
12911     /* Done */
12912     return result_sstream.str();
12913 }
12914 
12915 /** Executes test iteration.
12916  *
12917  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
12918  */
iterate()12919 tcu::TestNode::IterateResult NegativeTest9::iterate()
12920 {
12921     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
12922 
12923     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
12924     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
12925     {
12926         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
12927     }
12928 
12929     /* Iterate over all test cases */
12930     for (int test_case = static_cast<int>(TEST_CASE_FIRST); test_case != static_cast<int>(TEST_CASE_COUNT); ++test_case)
12931     {
12932         /* Try to build a program object using invalid vertex shader, specific to the
12933          * iteration we're currently in */
12934         std::string vs_body = getVertexShader(static_cast<_test_case>(test_case));
12935 
12936         if (ShaderSubroutine::Utils::buildProgram(gl, vs_body, "",   /* tc_body */
12937                                                   "",                /* te_body */
12938                                                   "",                /* gs_body */
12939                                                   "",                /* fs_body */
12940                                                   DE_NULL,           /* xfb_varyings */
12941                                                   0,                 /* n_xfb_varyings */
12942                                                   &m_vs_id, DE_NULL, /* out_tc_id */
12943                                                   DE_NULL,           /* out_te_id */
12944                                                   DE_NULL,           /* out_gs_id */
12945                                                   DE_NULL,           /* out_fs_id */
12946                                                   &m_po_id))
12947         {
12948             m_testCtx.getLog() << tcu::TestLog::Message << "A program object was successfully built for ["
12949                                << getTestCaseString(static_cast<_test_case>(test_case))
12950                                << "] test case, even though it was invalid." << tcu::TestLog::EndMessage;
12951 
12952             m_has_test_passed = false;
12953         }
12954 
12955         /* Delete any objects that may have been created */
12956         deinit();
12957     } /* for (all test cases) */
12958 
12959     /** All done */
12960     if (m_has_test_passed)
12961     {
12962         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
12963     }
12964     else
12965     {
12966         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
12967     }
12968 
12969     return STOP;
12970 }
12971 
12972 /** Constructor.
12973  *
12974  *  @param context Rendering context.
12975  **/
NegativeTest10(deqp::Context & context)12976 NegativeTest10::NegativeTest10(deqp::Context &context)
12977     : TestCase(context, "function_overloading_forbidden_for_subroutines",
12978                "Check that an overloaded function cannot be declared with subroutine and "
12979                "a program will fail to compile or link if any shader or stage contains"
12980                " two or more  functions with the same name if the name is associated with"
12981                " a subroutine type.")
12982     , m_has_test_passed(true)
12983     , m_fs_id(0)
12984     , m_gs_id(0)
12985     , m_po_id(0)
12986     , m_tc_id(0)
12987     , m_te_id(0)
12988     , m_vs_id(0)
12989 {
12990     /* Left blank intentionally */
12991 }
12992 
12993 /** Deinitializes any GL objects that may have been created during
12994  *  test execution.
12995  **/
deinit()12996 void NegativeTest10::deinit()
12997 {
12998     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
12999 
13000     if (m_fs_id != 0)
13001     {
13002         gl.deleteShader(m_fs_id);
13003 
13004         m_fs_id = 0;
13005     }
13006 
13007     if (m_gs_id != 0)
13008     {
13009         gl.deleteShader(m_gs_id);
13010 
13011         m_gs_id = 0;
13012     }
13013 
13014     if (m_po_id != 0)
13015     {
13016         gl.deleteProgram(m_po_id);
13017 
13018         m_po_id = 0;
13019     }
13020 
13021     if (m_tc_id != 0)
13022     {
13023         gl.deleteShader(m_tc_id);
13024 
13025         m_tc_id = 0;
13026     }
13027 
13028     if (m_te_id != 0)
13029     {
13030         gl.deleteShader(m_te_id);
13031 
13032         m_te_id = 0;
13033     }
13034 
13035     if (m_vs_id != 0)
13036     {
13037         gl.deleteShader(m_vs_id);
13038 
13039         m_vs_id = 0;
13040     }
13041 }
13042 
13043 /** Retrieves fragment shader that should be used for the purpose of the test.
13044  *  An overloaded version of a subroutine function is inserted if
13045  *  @param include_duplicate_function flag is set to true.
13046  *
13047  *  @param include_duplicate_function As per description.
13048  *
13049  *  @return Requested string.
13050  **/
getFragmentShader(bool include_duplicate_function)13051 std::string NegativeTest10::getFragmentShader(bool include_duplicate_function)
13052 {
13053     std::stringstream result_sstream;
13054 
13055     result_sstream << "#version 400\n"
13056                       "\n"
13057                       "#extension GL_ARB_shader_subroutine : require\n"
13058                       "\n"
13059                       "subroutine void subroutineType(inout vec4 test);\n"
13060                       "\n"
13061                       "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13062                       "{\n"
13063                       "    test = vec4(2, 3, 4, 5);\n"
13064                       "}\n"
13065                       "\n"
13066                       "subroutine uniform subroutineType function;\n"
13067                       "out vec4 result;\n"
13068                       "\n";
13069 
13070     if (include_duplicate_function)
13071     {
13072         result_sstream << "void test_function(inout vec4 test)\n"
13073                           "{\n"
13074                           "    test = vec4(3, 4, 5, 6);\n"
13075                           "}\n"
13076                           "\n";
13077     }
13078 
13079     result_sstream << "void main()\n"
13080                       "{\n"
13081                       "    test_function(result);\n"
13082                       "}\n";
13083 
13084     return result_sstream.str();
13085 }
13086 
13087 /** Retrieves geometry shader that should be used for the purpose of the test.
13088  *  An overloaded version of a subroutine function is inserted if
13089  *  @param include_duplicate_function flag is set to true.
13090  *
13091  *  @param include_duplicate_function As per description.
13092  *
13093  *  @return Requested string.
13094  **/
getGeometryShader(bool include_duplicate_function)13095 std::string NegativeTest10::getGeometryShader(bool include_duplicate_function)
13096 {
13097     std::stringstream result_sstream;
13098 
13099     result_sstream << "#version 400\n"
13100                       "\n"
13101                       "#extension GL_ARB_shader_subroutine : require\n"
13102                       "\n"
13103                       "layout (triangles)                        in;\n"
13104                       "layout (triangle_strip, max_vertices = 4) out;\n"
13105                       "\n"
13106                       "subroutine void subroutineType(inout vec4 test);\n"
13107                       "\n"
13108                       "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13109                       "{\n"
13110                       "    test = vec4(2, 3, 4, 5);\n"
13111                       "}\n"
13112                       "\n"
13113                       "subroutine uniform subroutineType function;\n"
13114                       "\n";
13115 
13116     if (include_duplicate_function)
13117     {
13118         result_sstream << "void test_function(inout vec4 test)\n"
13119                           "{\n"
13120                           "    test = vec4(3, 4, 5, 6);\n"
13121                           "}\n"
13122                           "\n";
13123     }
13124 
13125     result_sstream << "void main()\n"
13126                       "{\n"
13127                       "    function(gl_Position);\n"
13128                       "    EmitVertex();\n"
13129                       "    EndPrimitive();\n"
13130                       "}\n";
13131 
13132     return result_sstream.str();
13133 }
13134 
13135 /** Retrieves tess control shader that should be used for the purpose of the test.
13136  *  An overloaded version of a subroutine function is inserted if
13137  *  @param include_duplicate_function flag is set to true.
13138  *
13139  *  @param include_duplicate_function As per description.
13140  *
13141  *  @return Requested string.
13142  **/
getTessellationControlShader(bool include_duplicate_function)13143 std::string NegativeTest10::getTessellationControlShader(bool include_duplicate_function)
13144 {
13145     std::stringstream result_sstream;
13146 
13147     result_sstream << "#version 400\n"
13148                       "\n"
13149                       "#extension GL_ARB_shader_subroutine : require\n"
13150                       "\n"
13151                       "layout (vertices = 4) out;\n"
13152                       "\n"
13153                       "subroutine void subroutineType(inout vec4 test);\n"
13154                       "\n"
13155                       "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13156                       "{\n"
13157                       "    test = vec4(2, 3, 4, 5);\n"
13158                       "}\n"
13159                       "\n"
13160                       "subroutine uniform subroutineType function;\n"
13161                       "\n";
13162 
13163     if (include_duplicate_function)
13164     {
13165         result_sstream << "void test_function(inout vec4 test)\n"
13166                           "{\n"
13167                           "    test = vec4(3, 4, 5, 6);\n"
13168                           "}\n"
13169                           "\n";
13170     }
13171 
13172     result_sstream << "void main()\n"
13173                       "{\n"
13174                       "    vec4 temp;\n"
13175                       "\n"
13176                       "    function(temp);\n"
13177                       "\n"
13178                       "    gl_out[gl_InvocationID].gl_Position = temp;\n"
13179                       "    gl_TessLevelInner[0]                = temp.x;\n"
13180                       "    gl_TessLevelInner[1]                = temp.y;\n"
13181                       "    gl_TessLevelOuter[0]                = temp.z;\n"
13182                       "    gl_TessLevelOuter[1]                = temp.w;\n"
13183                       "    gl_TessLevelOuter[2]                = temp.x;\n"
13184                       "    gl_TessLevelOuter[3]                = temp.y;\n"
13185                       "}\n";
13186 
13187     return result_sstream.str();
13188 }
13189 
13190 /** Retrieves tess evaluation shader that should be used for the purpose of the test.
13191  *  An overloaded version of a subroutine function is inserted if
13192  *  @param include_duplicate_function flag is set to true.
13193  *
13194  *  @param include_duplicate_function As per description.
13195  *
13196  *  @return Requested string.
13197  **/
getTessellationEvaluationShader(bool include_duplicate_function)13198 std::string NegativeTest10::getTessellationEvaluationShader(bool include_duplicate_function)
13199 {
13200     std::stringstream result_sstream;
13201 
13202     result_sstream << "#version 400\n"
13203                       "\n"
13204                       "#extension GL_ARB_shader_subroutine : require\n"
13205                       "\n"
13206                       "layout (quads) in;\n"
13207                       "\n"
13208                       "subroutine void subroutineType(inout vec4 test);\n"
13209                       "\n"
13210                       "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13211                       "{\n"
13212                       "    test = vec4(2, 3, 4, 5);\n"
13213                       "}\n"
13214                       "\n"
13215                       "subroutine uniform subroutineType function;\n"
13216                       "\n";
13217 
13218     if (include_duplicate_function)
13219     {
13220         result_sstream << "void test_function(inout vec4 test)\n"
13221                           "{\n"
13222                           "    test = vec4(3, 4, 5, 6);\n"
13223                           "}\n"
13224                           "\n";
13225     }
13226 
13227     result_sstream << "void main()\n"
13228                       "{\n"
13229                       "    vec4 temp;\n"
13230                       "\n"
13231                       "    function(temp);\n"
13232                       "\n"
13233                       "    gl_Position = temp;\n"
13234                       "}\n";
13235 
13236     return result_sstream.str();
13237 }
13238 
13239 /** Retrieves vertex shader that should be used for the purpose of the test.
13240  *  An overloaded version of a subroutine function is inserted if
13241  *  @param include_duplicate_function flag is set to true.
13242  *
13243  *  @param include_duplicate_function As per description.
13244  *
13245  *  @return Requested string.
13246  **/
getVertexShader(bool include_duplicate_function)13247 std::string NegativeTest10::getVertexShader(bool include_duplicate_function)
13248 {
13249     std::stringstream result_sstream;
13250 
13251     result_sstream << "#version 400\n"
13252                       "\n"
13253                       "#extension GL_ARB_shader_subroutine : require\n"
13254                       "\n"
13255                       "subroutine void subroutineType(inout vec4 test);\n"
13256                       "\n"
13257                       "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13258                       "{\n"
13259                       "    test = vec4(2, 3, 4, 5);\n"
13260                       "}\n"
13261                       "\n"
13262                       "subroutine uniform subroutineType function;\n"
13263                       "\n";
13264 
13265     if (include_duplicate_function)
13266     {
13267         result_sstream << "void test_function(inout vec4 test)\n"
13268                           "{\n"
13269                           "    test = vec4(3, 4, 5, 6);\n"
13270                           "}\n"
13271                           "\n";
13272     }
13273 
13274     result_sstream << "void main()\n"
13275                       "{\n"
13276                       "    function(gl_Position);\n"
13277                       "}\n";
13278 
13279     return result_sstream.str();
13280 }
13281 
13282 /** Fills m_test_cases field with test case descriptors */
initTestCases()13283 void NegativeTest10::initTestCases()
13284 {
13285     /* For each test case, only one shader stage should define a function that
13286      * has already been defined as a subroutine. */
13287     for (int offending_shader_stage_it = static_cast<int>(Utils::SHADER_STAGE_FIRST);
13288          offending_shader_stage_it != static_cast<int>(Utils::SHADER_STAGE_COUNT); ++offending_shader_stage_it)
13289     {
13290         Utils::_shader_stage offending_shader_stage = static_cast<Utils::_shader_stage>(offending_shader_stage_it);
13291         /* Form the test case descriptor */
13292         std::stringstream name_sstream;
13293         _test_case test_case;
13294 
13295         name_sstream << "Broken shader stage:" << Utils::getShaderStageString(offending_shader_stage);
13296 
13297         test_case.fs_body = getFragmentShader(offending_shader_stage == Utils::SHADER_STAGE_FRAGMENT);
13298         test_case.gs_body = getGeometryShader(offending_shader_stage == Utils::SHADER_STAGE_GEOMETRY);
13299         test_case.name    = name_sstream.str();
13300         test_case.tc_body =
13301             getTessellationControlShader(offending_shader_stage == Utils::SHADER_STAGE_TESSELLATION_CONTROL);
13302         test_case.te_body =
13303             getTessellationEvaluationShader(offending_shader_stage == Utils::SHADER_STAGE_TESSELLATION_EVALUATION);
13304         test_case.vs_body = getVertexShader(offending_shader_stage == Utils::SHADER_STAGE_VERTEX);
13305 
13306         m_test_cases.push_back(test_case);
13307     }
13308 }
13309 
13310 /** Executes test iteration.
13311  *
13312  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
13313  */
iterate()13314 tcu::TestNode::IterateResult NegativeTest10::iterate()
13315 {
13316     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
13317 
13318     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
13319     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
13320     {
13321         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
13322     }
13323 
13324     /* Form test cases */
13325     initTestCases();
13326 
13327     /* Iterate over all test cases */
13328     for (_test_cases_const_iterator test_case_iterator = m_test_cases.begin(); test_case_iterator != m_test_cases.end();
13329          ++test_case_iterator)
13330     {
13331         const _test_case &test_case = *test_case_iterator;
13332 
13333         /* Try to build the program object */
13334         if (ShaderSubroutine::Utils::buildProgram(gl, test_case.vs_body, test_case.tc_body, test_case.te_body,
13335                                                   test_case.gs_body, test_case.fs_body, DE_NULL, /* xfb_varyings */
13336                                                   0,                                             /* n_xfb_varyings */
13337                                                   &m_vs_id, (test_case.tc_body.length() > 0) ? &m_tc_id : DE_NULL,
13338                                                   (test_case.te_body.length() > 0) ? &m_te_id : DE_NULL,
13339                                                   (test_case.gs_body.length() > 0) ? &m_gs_id : DE_NULL,
13340                                                   (test_case.fs_body.length() > 0) ? &m_fs_id : DE_NULL, &m_po_id))
13341         {
13342             m_testCtx.getLog() << tcu::TestLog::Message << "A program object was successfully built for ["
13343                                << test_case.name << "] test case, even though it was invalid."
13344                                << tcu::TestLog::EndMessage;
13345 
13346             m_has_test_passed = false;
13347         }
13348 
13349         /* Delete any objects that may have been created */
13350         deinit();
13351     } /* for (all test cases) */
13352 
13353     /** All done */
13354     if (m_has_test_passed)
13355     {
13356         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
13357     }
13358     else
13359     {
13360         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
13361     }
13362 
13363     return STOP;
13364 }
13365 
13366 /** Constructor.
13367  *
13368  *  @param context Rendering context.
13369  **/
NegativeTest11(deqp::Context & context)13370 NegativeTest11::NegativeTest11(deqp::Context &context)
13371     : TestCase(context, "subroutine_uniforms_used_for_sampling_atomic_image_functions",
13372                "Tries to use subroutine uniforms in invalid way in sampling, "
13373                "atomic and image functions. Verifies that compile- or link-time "
13374                "error occurs.")
13375     , m_has_test_passed(true)
13376     , m_po_id(0)
13377     , m_vs_id(0)
13378 {
13379     /* Left blank intentionally */
13380 }
13381 
13382 /** Deinitializes any GL objects that may have been created during
13383  *  test execution.
13384  **/
deinit()13385 void NegativeTest11::deinit()
13386 {
13387     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
13388 
13389     if (m_po_id != 0)
13390     {
13391         gl.deleteProgram(m_po_id);
13392 
13393         m_po_id = 0;
13394     }
13395 
13396     if (m_vs_id != 0)
13397     {
13398         gl.deleteShader(m_vs_id);
13399 
13400         m_vs_id = 0;
13401     }
13402 }
13403 
13404 /** Returns a literal corresponding to user-specified test case enum.
13405  *
13406  *  @param test_case As per description.
13407  *
13408  *  @return Requested string.
13409  **/
getTestCaseString(const _test_case & test_case)13410 std::string NegativeTest11::getTestCaseString(const _test_case &test_case)
13411 {
13412     std::string result = "?";
13413 
13414     switch (test_case)
13415     {
13416     case TEST_CASE_INVALID_TEXTURE_SAMPLING_ATTEMPT:
13417         result = "TEST_CASE_INVALID_TEXTURE_SAMPLING_ATTEMPT";
13418         break;
13419     case TEST_CASE_INVALID_ATOMIC_COUNTER_USAGE_ATTEMPT:
13420         result = "TEST_CASE_INVALID_ATOMIC_COUNTER_USAGE_ATTEMPT";
13421         break;
13422     case TEST_CASE_INVALID_IMAGE_FUNCTION_USAGE_ATTEMPT:
13423         result = "TEST_CASE_INVALID_IMAGE_FUNCTION_USAGE_ATTEMPT";
13424         break;
13425     default:
13426         break;
13427     }
13428 
13429     return result;
13430 }
13431 
13432 /** Retrieves vertex shader body for user-specified test case.
13433  *
13434  *  @param test_case As per description.
13435  *
13436  *  @return Requested string.
13437  **/
getVertexShader(const _test_case & test_case)13438 std::string NegativeTest11::getVertexShader(const _test_case &test_case)
13439 {
13440     std::stringstream result_sstream;
13441 
13442     /* Form pre-amble */
13443     result_sstream << "#version 400\n"
13444                       "\n"
13445                       "#extension GL_ARB_shader_subroutine : require\n";
13446 
13447     if (test_case == TEST_CASE_INVALID_ATOMIC_COUNTER_USAGE_ATTEMPT)
13448     {
13449         result_sstream << "#extension GL_ARB_shader_atomic_counters : require\n";
13450     }
13451 
13452     result_sstream << "\n"
13453                       /* Define a subroutine */
13454                       "subroutine void subroutineType(inout vec4 test);\n"
13455                       "\n"
13456                       "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13457                       "{\n"
13458                       "    test += vec4(0, 1, 2, 3);\n"
13459                       "}\n"
13460                       "\n"
13461                       "subroutine uniform subroutineType function;\n"
13462                       "\n"
13463 
13464                       /* Define main() body */
13465                       "void main()\n"
13466                       "{\n";
13467 
13468     /* Implement case-specific behavior */
13469     switch (test_case)
13470     {
13471     case TEST_CASE_INVALID_ATOMIC_COUNTER_USAGE_ATTEMPT:
13472     {
13473         result_sstream << "if (atomicCounter(function) > 2)\n"
13474                           "{\n"
13475                           "    gl_Position = vec4(1);\n"
13476                           "}\n";
13477 
13478         break;
13479     }
13480 
13481     case TEST_CASE_INVALID_IMAGE_FUNCTION_USAGE_ATTEMPT:
13482     {
13483         result_sstream << "imageStore(function, vec2(0.0, 1.0), vec4(1.0) );\n";
13484 
13485         break;
13486     }
13487 
13488     case TEST_CASE_INVALID_TEXTURE_SAMPLING_ATTEMPT:
13489     {
13490         result_sstream << "gl_Position = texture(function, vec2(1.0) );\n";
13491 
13492         break;
13493     }
13494 
13495     default:
13496         break;
13497     } /* switch (test_case) */
13498 
13499     /* Close main() body */
13500     result_sstream << "}\n";
13501 
13502     /* Done */
13503     return result_sstream.str();
13504 }
13505 
13506 /** Executes test iteration.
13507  *
13508  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
13509  */
iterate()13510 tcu::TestNode::IterateResult NegativeTest11::iterate()
13511 {
13512     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
13513 
13514     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
13515     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
13516     {
13517         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
13518     }
13519 
13520     /* Iterate over all test cases */
13521     for (int test_case = static_cast<int>(TEST_CASE_FIRST); test_case != static_cast<int>(TEST_CASE_COUNT); ++test_case)
13522     {
13523         if (static_cast<_test_case>(test_case) == TEST_CASE_INVALID_ATOMIC_COUNTER_USAGE_ATTEMPT &&
13524             !m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_atomic_counters"))
13525         {
13526             /* This iteration requires atomic counter support that this GL implementation
13527              * is not capable of. Skip the iteration
13528              */
13529             continue;
13530         }
13531 
13532         /* Try to build a program object using invalid vertex shader, specific to the
13533          * iteration we're currently in */
13534         std::string vs_body = getVertexShader(static_cast<_test_case>(test_case));
13535 
13536         if (ShaderSubroutine::Utils::buildProgram(gl, vs_body, "",   /* tc_body */
13537                                                   "",                /* te_body */
13538                                                   "",                /* gs_body */
13539                                                   "",                /* fs_body */
13540                                                   DE_NULL,           /* xfb_varyings */
13541                                                   0,                 /* n_xfb_varyings */
13542                                                   &m_vs_id, DE_NULL, /* out_tc_id */
13543                                                   DE_NULL,           /* out_te_id */
13544                                                   DE_NULL,           /* out_gs_id */
13545                                                   DE_NULL,           /* out_fs_id */
13546                                                   &m_po_id))
13547         {
13548             m_testCtx.getLog() << tcu::TestLog::Message << "A program object was successfully built for ["
13549                                << getTestCaseString(static_cast<_test_case>(test_case))
13550                                << "] test case, even though it was invalid." << tcu::TestLog::EndMessage;
13551 
13552             m_has_test_passed = false;
13553         }
13554 
13555         /* Delete any objects that may have been created */
13556         deinit();
13557     } /* for (all test cases) */
13558 
13559     /** All done */
13560     if (m_has_test_passed)
13561     {
13562         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
13563     }
13564     else
13565     {
13566         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
13567     }
13568 
13569     return STOP;
13570 }
13571 
13572 /** Constructor.
13573  *
13574  *  @param context Rendering context.
13575  **/
NegativeTest12(deqp::Context & context)13576 NegativeTest12::NegativeTest12(deqp::Context &context)
13577     : TestCase(context, "subroutines_not_allowed_as_variables_constructors_and_argument_or_return_types",
13578                "Verifies that it is not allowed to use subroutine type for "
13579                "local/global variables, constructors or argument/return type.")
13580     , m_has_test_passed(true)
13581     , m_po_id(0)
13582     , m_vs_id(0)
13583 {
13584     /* Left blank intentionally */
13585 }
13586 
13587 /** Deinitializes any GL objects that may have been created during
13588  *  test execution.
13589  **/
deinit()13590 void NegativeTest12::deinit()
13591 {
13592     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
13593 
13594     if (m_po_id != 0)
13595     {
13596         gl.deleteProgram(m_po_id);
13597 
13598         m_po_id = 0;
13599     }
13600 
13601     if (m_vs_id != 0)
13602     {
13603         gl.deleteShader(m_vs_id);
13604 
13605         m_vs_id = 0;
13606     }
13607 }
13608 
13609 /** Returns a literal corresponding to user-specified test case enum.
13610  *
13611  *  @param test_case As per description.
13612  *
13613  *  @return Requested string.
13614  **/
getTestCaseString(const _test_case & test_case)13615 std::string NegativeTest12::getTestCaseString(const _test_case &test_case)
13616 {
13617     std::string result = "?";
13618 
13619     switch (test_case)
13620     {
13621     case TEST_CASE_INVALID_LOCAL_SUBROUTINE_VARIABLE:
13622         result = "TEST_CASE_INVALID_LOCAL_SUBROUTINE_VARIABLE";
13623         break;
13624     case TEST_CASE_INVALID_GLOBAL_SUBROUTINE_VARIABLE:
13625         result = "TEST_CASE_INVALID_GLOBAL_SUBROUTINE_VARIABLE";
13626         break;
13627     case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR:
13628         result = "TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR";
13629         break;
13630     case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_ARGUMENT:
13631         result = "TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_ARGUMENT";
13632         break;
13633     case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_RETURN_TYPE:
13634         result = "TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_RETURN_TYPE";
13635         break;
13636     default:
13637         break;
13638     }
13639 
13640     return result;
13641 }
13642 
13643 /** Retrieves vertex shader body for user-specified test case.
13644  *
13645  *  @param test_case As per description.
13646  *
13647  *  @return Requested string.
13648  **/
getVertexShader(const _test_case & test_case)13649 std::string NegativeTest12::getVertexShader(const _test_case &test_case)
13650 {
13651     std::stringstream result_sstream;
13652 
13653     /* Form pre-amble */
13654     result_sstream << "#version 400\n"
13655                       "\n"
13656                       "#extension GL_ARB_shader_subroutine : require\n"
13657                       "\n"
13658                       /* Define a subroutine */
13659                       "subroutine void subroutineType(inout vec4 test);\n"
13660                       "\n"
13661                       "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13662                       "{\n"
13663                       "    test += vec4(0, 1, 2, 3);\n"
13664                       "}\n"
13665                       "\n"
13666                       "subroutine uniform subroutineType function;\n"
13667                       "\n";
13668 
13669     /* Include case-specific implementation */
13670     switch (test_case)
13671     {
13672     case TEST_CASE_INVALID_LOCAL_SUBROUTINE_VARIABLE:
13673     {
13674         result_sstream << "void main()\n"
13675                           "{\n"
13676                           "    subroutine subroutineType function2;\n"
13677                           "    vec4                      result;\n"
13678                           "\n"
13679                           "    function2(result);\n"
13680                           "    gl_Position = result;\n"
13681                           "}\n";
13682 
13683         break;
13684     }
13685 
13686     case TEST_CASE_INVALID_GLOBAL_SUBROUTINE_VARIABLE:
13687     {
13688         result_sstream << "subroutine subroutineType function2;\n"
13689                           "\n"
13690                           "void main()\n"
13691                           "{\n"
13692                           "    vec4 result;\n"
13693                           "\n"
13694                           "    function2(result);\n"
13695                           "    gl_Position = result;\n"
13696                           "}\n";
13697 
13698         break;
13699     }
13700 
13701     case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR:
13702     {
13703         result_sstream << "void main()\n"
13704                           "{\n"
13705                           "    subroutineType(function);\n"
13706                           "}\n";
13707 
13708         break;
13709     }
13710 
13711     case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_ARGUMENT:
13712     {
13713         result_sstream << "vec4 test_function(subroutineType argument)\n"
13714                           "{\n"
13715                           "    vec4 result = vec4(1, 2, 3, 4);\n"
13716                           "\n"
13717                           "    argument(result);\n"
13718                           "\n"
13719                           "    return result;\n"
13720                           "}\n"
13721                           "\n"
13722                           "void main()\n"
13723                           "{\n"
13724                           "    test_function(function);\n"
13725                           "}\n";
13726 
13727         break;
13728     }
13729 
13730     case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_RETURN_TYPE:
13731     {
13732         result_sstream << "subroutineType test_function()\n"
13733                           "{\n"
13734                           "    return function;\n"
13735                           "}\n"
13736                           "\n"
13737                           "void main()\n"
13738                           "{\n"
13739                           "    test_function()(gl_Position);\n"
13740                           "}\n";
13741 
13742         break;
13743     }
13744 
13745     default:
13746         break;
13747     } /* switch (test_case) */
13748 
13749     /* Done */
13750     return result_sstream.str();
13751 }
13752 
13753 /** Executes test iteration.
13754  *
13755  *  @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
13756  */
iterate()13757 tcu::TestNode::IterateResult NegativeTest12::iterate()
13758 {
13759     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
13760 
13761     /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
13762     if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
13763     {
13764         throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
13765     }
13766 
13767     /* Iterate over all test cases */
13768     for (int test_case = static_cast<int>(TEST_CASE_FIRST); test_case != static_cast<int>(TEST_CASE_COUNT); ++test_case)
13769     {
13770         /* Try to build a program object using invalid vertex shader, specific to the
13771          * iteration we're currently in */
13772         std::string vs_body = getVertexShader(static_cast<_test_case>(test_case));
13773 
13774         if (ShaderSubroutine::Utils::buildProgram(gl, vs_body, "",   /* tc_body */
13775                                                   "",                /* te_body */
13776                                                   "",                /* gs_body */
13777                                                   "",                /* fs_body */
13778                                                   DE_NULL,           /* xfb_varyings */
13779                                                   0,                 /* n_xfb_varyings */
13780                                                   &m_vs_id, DE_NULL, /* out_tc_id */
13781                                                   DE_NULL,           /* out_te_id */
13782                                                   DE_NULL,           /* out_gs_id */
13783                                                   DE_NULL,           /* out_fs_id */
13784                                                   &m_po_id))
13785         {
13786             m_testCtx.getLog() << tcu::TestLog::Message << "A program object was successfully built for ["
13787                                << getTestCaseString(static_cast<_test_case>(test_case))
13788                                << "] test case, even though it was invalid." << tcu::TestLog::EndMessage;
13789 
13790             m_has_test_passed = false;
13791         }
13792 
13793         /* Delete any objects that may have been created */
13794         deinit();
13795     } /* for (all test cases) */
13796 
13797     /** All done */
13798     if (m_has_test_passed)
13799     {
13800         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
13801     }
13802     else
13803     {
13804         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
13805     }
13806 
13807     return STOP;
13808 }
13809 
13810 } // namespace ShaderSubroutine
13811 
13812 /** Constructor.
13813  *
13814  *  @param context Rendering context.
13815  **/
ShaderSubroutineTests(deqp::Context & context)13816 ShaderSubroutineTests::ShaderSubroutineTests(deqp::Context &context)
13817     : TestCaseGroup(context, "shader_subroutine", "Verifies \"shader_subroutine\" functionality")
13818 {
13819     /* Left blank on purpose */
13820 }
13821 
13822 /** Initializes a texture_storage_multisample test group.
13823  *
13824  **/
init(void)13825 void ShaderSubroutineTests::init(void)
13826 {
13827     addChild(new ShaderSubroutine::APITest1(m_context));
13828     addChild(new ShaderSubroutine::APITest2(m_context));
13829     addChild(new ShaderSubroutine::FunctionalTest1_2(m_context));
13830     addChild(new ShaderSubroutine::FunctionalTest3_4(m_context));
13831     addChild(new ShaderSubroutine::FunctionalTest5(m_context));
13832     addChild(new ShaderSubroutine::FunctionalTest6(m_context));
13833     addChild(new ShaderSubroutine::FunctionalTest7_8(m_context));
13834     addChild(new ShaderSubroutine::FunctionalTest9(m_context));
13835     addChild(new ShaderSubroutine::FunctionalTest10(m_context));
13836     addChild(new ShaderSubroutine::FunctionalTest11(m_context));
13837     addChild(new ShaderSubroutine::FunctionalTest12(m_context));
13838     addChild(new ShaderSubroutine::FunctionalTest13(m_context));
13839     addChild(new ShaderSubroutine::FunctionalTest14_15(m_context));
13840     addChild(new ShaderSubroutine::FunctionalTest16(m_context));
13841     addChild(new ShaderSubroutine::FunctionalTest17(m_context));
13842     addChild(new ShaderSubroutine::FunctionalTest18_19(m_context));
13843     addChild(new ShaderSubroutine::NegativeTest1(m_context));
13844     addChild(new ShaderSubroutine::NegativeTest2(m_context));
13845     addChild(new ShaderSubroutine::NegativeTest3(m_context));
13846     addChild(new ShaderSubroutine::NegativeTest4(m_context));
13847     addChild(new ShaderSubroutine::NegativeTest5(m_context));
13848     addChild(new ShaderSubroutine::NegativeTest6(m_context));
13849     addChild(new ShaderSubroutine::NegativeTest7(m_context));
13850     addChild(new ShaderSubroutine::NegativeTest8(m_context));
13851     addChild(new ShaderSubroutine::NegativeTest9(m_context));
13852     addChild(new ShaderSubroutine::NegativeTest10(m_context));
13853     addChild(new ShaderSubroutine::NegativeTest11(m_context));
13854     addChild(new ShaderSubroutine::NegativeTest12(m_context));
13855 }
13856 
13857 } // namespace gl4cts
13858