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() << tcu::TestLog::Message << "Uniform: " << uniform_name
503 << " 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 break;
1323 };
1324
1325 return string;
1326 }
1327
1328 /** Returns string that represents pname's name
1329 *
1330 * @param pname pname
1331 *
1332 * @return String representation of known pnames
1333 **/
pnameToStr(glw::GLenum pname)1334 const GLchar* Utils::pnameToStr(glw::GLenum pname)
1335 {
1336 const GLchar* string = "Unknown pname";
1337
1338 switch (pname)
1339 {
1340 case GL_ACTIVE_SUBROUTINE_UNIFORMS:
1341 string = "GL_ACTIVE_SUBROUTINE_UNIFORMS";
1342 break;
1343 case GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS:
1344 string = "GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS";
1345 break;
1346 case GL_ACTIVE_SUBROUTINES:
1347 string = "GL_ACTIVE_SUBROUTINES";
1348 break;
1349 case GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH:
1350 string = "GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH";
1351 break;
1352 case GL_ACTIVE_SUBROUTINE_MAX_LENGTH:
1353 string = "GL_ACTIVE_SUBROUTINE_MAX_LENGTH";
1354 break;
1355 case GL_NUM_COMPATIBLE_SUBROUTINES:
1356 string = "GL_NUM_COMPATIBLE_SUBROUTINES";
1357 break;
1358 case GL_UNIFORM_SIZE:
1359 string = "GL_UNIFORM_SIZE";
1360 break;
1361 case GL_COMPATIBLE_SUBROUTINES:
1362 string = "GL_COMPATIBLE_SUBROUTINES";
1363 break;
1364 case GL_UNIFORM_NAME_LENGTH:
1365 string = "GL_UNIFORM_NAME_LENGTH";
1366 break;
1367 case GL_ACTIVE_RESOURCES:
1368 string = "GL_ACTIVE_RESOURCES";
1369 break;
1370 case GL_MAX_NAME_LENGTH:
1371 string = "GL_MAX_NAME_LENGTH";
1372 break;
1373 case GL_MAX_NUM_COMPATIBLE_SUBROUTINES:
1374 string = "GL_MAX_NUM_COMPATIBLE_SUBROUTINES";
1375 break;
1376 case GL_NAME_LENGTH:
1377 string = "GL_NAME_LENGTH";
1378 break;
1379 case GL_ARRAY_SIZE:
1380 string = "GL_ARRAY_SIZE";
1381 break;
1382 case GL_LOCATION:
1383 string = "GL_LOCATION";
1384 break;
1385 default:
1386 TCU_FAIL("Not implemented");
1387 break;
1388 };
1389
1390 return string;
1391 }
1392
compare(const glw::GLfloat & left,const glw::GLfloat & right)1393 bool Utils::compare(const glw::GLfloat& left, const glw::GLfloat& right)
1394 {
1395 static const glw::GLfloat m_epsilon = 0.00001f;
1396
1397 if (m_epsilon < std::abs(right - left))
1398 {
1399 return false;
1400 }
1401 else
1402 {
1403 return true;
1404 }
1405 }
1406
1407 /** Returns a variable type enum corresponding to user-specified base variable type
1408 * and the number of components it should support.
1409 *
1410 * @param base_variable_type Base variable type to use for the query.
1411 * @param n_components Number of components to consider for the query.
1412 *
1413 * @return As per description.
1414 **/
getVariableTypeFromProperties(const _variable_type & base_variable_type,const unsigned int & n_components)1415 Utils::_variable_type Utils::getVariableTypeFromProperties(const _variable_type& base_variable_type,
1416 const unsigned int& n_components)
1417 {
1418 _variable_type result = VARIABLE_TYPE_UNKNOWN;
1419
1420 switch (base_variable_type)
1421 {
1422 case VARIABLE_TYPE_BOOL:
1423 {
1424 switch (n_components)
1425 {
1426 case 1:
1427 result = VARIABLE_TYPE_BOOL;
1428 break;
1429 case 2:
1430 result = VARIABLE_TYPE_BVEC2;
1431 break;
1432 case 3:
1433 result = VARIABLE_TYPE_BVEC3;
1434 break;
1435 case 4:
1436 result = VARIABLE_TYPE_BVEC4;
1437 break;
1438
1439 default:
1440 {
1441 TCU_FAIL("Unsupported number of components requested");
1442 }
1443 } /* switch (n_components) */
1444
1445 break;
1446 }
1447
1448 case VARIABLE_TYPE_DOUBLE:
1449 {
1450 switch (n_components)
1451 {
1452 case 1:
1453 result = VARIABLE_TYPE_DOUBLE;
1454 break;
1455 case 2:
1456 result = VARIABLE_TYPE_DVEC2;
1457 break;
1458 case 3:
1459 result = VARIABLE_TYPE_DVEC3;
1460 break;
1461 case 4:
1462 result = VARIABLE_TYPE_DVEC4;
1463 break;
1464
1465 default:
1466 {
1467 TCU_FAIL("Unsupported number of components requested");
1468 }
1469 } /* switch (n_components) */
1470
1471 break;
1472 }
1473
1474 case VARIABLE_TYPE_FLOAT:
1475 {
1476 switch (n_components)
1477 {
1478 case 1:
1479 result = VARIABLE_TYPE_FLOAT;
1480 break;
1481 case 2:
1482 result = VARIABLE_TYPE_VEC2;
1483 break;
1484 case 3:
1485 result = VARIABLE_TYPE_VEC3;
1486 break;
1487 case 4:
1488 result = VARIABLE_TYPE_VEC4;
1489 break;
1490
1491 default:
1492 {
1493 TCU_FAIL("Unsupported number of components requested");
1494 }
1495 } /* switch (n_components) */
1496
1497 break;
1498 }
1499
1500 case VARIABLE_TYPE_INT:
1501 {
1502 switch (n_components)
1503 {
1504 case 1:
1505 result = VARIABLE_TYPE_INT;
1506 break;
1507 case 2:
1508 result = VARIABLE_TYPE_IVEC2;
1509 break;
1510 case 3:
1511 result = VARIABLE_TYPE_IVEC3;
1512 break;
1513 case 4:
1514 result = VARIABLE_TYPE_IVEC4;
1515 break;
1516
1517 default:
1518 {
1519 TCU_FAIL("Unsupported number of components requested");
1520 }
1521 } /* switch (n_components) */
1522
1523 break;
1524 }
1525
1526 case VARIABLE_TYPE_UINT:
1527 {
1528 switch (n_components)
1529 {
1530 case 1:
1531 result = VARIABLE_TYPE_UINT;
1532 break;
1533 case 2:
1534 result = VARIABLE_TYPE_UVEC2;
1535 break;
1536 case 3:
1537 result = VARIABLE_TYPE_UVEC3;
1538 break;
1539 case 4:
1540 result = VARIABLE_TYPE_UVEC4;
1541 break;
1542
1543 default:
1544 {
1545 TCU_FAIL("Unsupported number of components requested");
1546 }
1547 } /* switch (n_components) */
1548
1549 break;
1550 }
1551
1552 default:
1553 {
1554 TCU_FAIL("Unrecognized base variable type");
1555 }
1556 } /* switch (base_variable_type) */
1557
1558 return result;
1559 }
1560
1561 /** Returns a GLSL literal corresponding to user-specified variable type.
1562 *
1563 * @param variable_type Variable type to use for the query.
1564 *
1565 * @return As per description or [?] if @param variable_type was not
1566 * recognized.
1567 **/
getVariableTypeGLSLString(const _variable_type & variable_type)1568 std::string Utils::getVariableTypeGLSLString(const _variable_type& variable_type)
1569 {
1570 std::string result = "[?]";
1571
1572 switch (variable_type)
1573 {
1574 case VARIABLE_TYPE_BOOL:
1575 result = "bool";
1576 break;
1577 case VARIABLE_TYPE_BVEC2:
1578 result = "bvec2";
1579 break;
1580 case VARIABLE_TYPE_BVEC3:
1581 result = "bvec3";
1582 break;
1583 case VARIABLE_TYPE_BVEC4:
1584 result = "bvec4";
1585 break;
1586 case VARIABLE_TYPE_DOUBLE:
1587 result = "double";
1588 break;
1589 case VARIABLE_TYPE_DVEC2:
1590 result = "dvec2";
1591 break;
1592 case VARIABLE_TYPE_DVEC3:
1593 result = "dvec3";
1594 break;
1595 case VARIABLE_TYPE_DVEC4:
1596 result = "dvec4";
1597 break;
1598 case VARIABLE_TYPE_FLOAT:
1599 result = "float";
1600 break;
1601 case VARIABLE_TYPE_INT:
1602 result = "int";
1603 break;
1604 case VARIABLE_TYPE_IVEC2:
1605 result = "ivec2";
1606 break;
1607 case VARIABLE_TYPE_IVEC3:
1608 result = "ivec3";
1609 break;
1610 case VARIABLE_TYPE_IVEC4:
1611 result = "ivec4";
1612 break;
1613 case VARIABLE_TYPE_MAT2:
1614 result = "mat2";
1615 break;
1616 case VARIABLE_TYPE_MAT2X3:
1617 result = "mat2x3";
1618 break;
1619 case VARIABLE_TYPE_MAT2X4:
1620 result = "mat2x4";
1621 break;
1622 case VARIABLE_TYPE_MAT3:
1623 result = "mat3";
1624 break;
1625 case VARIABLE_TYPE_MAT3X2:
1626 result = "mat3x2";
1627 break;
1628 case VARIABLE_TYPE_MAT3X4:
1629 result = "mat3x4";
1630 break;
1631 case VARIABLE_TYPE_MAT4:
1632 result = "mat4";
1633 break;
1634 case VARIABLE_TYPE_MAT4X2:
1635 result = "mat4x2";
1636 break;
1637 case VARIABLE_TYPE_MAT4X3:
1638 result = "mat4x3";
1639 break;
1640 case VARIABLE_TYPE_UINT:
1641 result = "uint";
1642 break;
1643 case VARIABLE_TYPE_UVEC2:
1644 result = "uvec2";
1645 break;
1646 case VARIABLE_TYPE_UVEC3:
1647 result = "uvec3";
1648 break;
1649 case VARIABLE_TYPE_UVEC4:
1650 result = "uvec4";
1651 break;
1652 case VARIABLE_TYPE_VEC2:
1653 result = "vec2";
1654 break;
1655 case VARIABLE_TYPE_VEC3:
1656 result = "vec3";
1657 break;
1658 case VARIABLE_TYPE_VEC4:
1659 result = "vec4";
1660 break;
1661
1662 default:
1663 {
1664 TCU_FAIL("Unrecognized variable type");
1665 }
1666 } /* switch (variable_type) */
1667
1668 return result;
1669 }
1670
1671 /** Constructor.
1672 *
1673 * @param context Rendering context.
1674 *
1675 **/
APITest1(deqp::Context & context)1676 APITest1::APITest1(deqp::Context& context)
1677 : TestCase(context, "min_maxes", "Verifies the implementation returns valid GL_MAX_SUBROUTINE* pnames "
1678 "which meet the minimum maximum requirements enforced by the spec.")
1679 , m_has_test_passed(true)
1680 {
1681 /* Left blank intentionally */
1682 }
1683
1684 /** Executes test iteration.
1685 *
1686 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
1687 */
iterate()1688 tcu::TestNode::IterateResult APITest1::iterate()
1689 {
1690 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1691
1692 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
1693 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
1694 {
1695 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
1696 }
1697
1698 /* Iterate over all pnames */
1699 const struct
1700 {
1701 glw::GLenum pname;
1702 const char* pname_string;
1703 glw::GLint min_value;
1704 } pnames[] = { { GL_MAX_SUBROUTINES, "GL_MAX_SUBROUTINES", 256 },
1705 { GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS, "GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS", 1024 } };
1706 const unsigned int n_pnames = sizeof(pnames) / sizeof(pnames[0]);
1707
1708 for (unsigned int n_pname = 0; n_pname < n_pnames; ++n_pname)
1709 {
1710 glw::GLboolean bool_value = GL_FALSE;
1711 glw::GLdouble double_value = 0.0;
1712 glw::GLfloat float_value = 0.0f;
1713 glw::GLint int_value = 0;
1714 glw::GLint64 int64_value = 0;
1715 const glw::GLint min_value = pnames[n_pname].min_value;
1716 const glw::GLenum& pname = pnames[n_pname].pname;
1717 const char* pname_string = pnames[n_pname].pname_string;
1718
1719 /* Retrieve the pname values */
1720 gl.getBooleanv(pname, &bool_value);
1721 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetBooleanv() call failed.");
1722
1723 gl.getDoublev(pname, &double_value);
1724 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetDoublev() call failed.");
1725
1726 gl.getFloatv(pname, &float_value);
1727 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv() call failed.");
1728
1729 gl.getIntegerv(pname, &int_value);
1730 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed.");
1731
1732 gl.getInteger64v(pname, &int64_value);
1733 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInteger64v() call failed.");
1734
1735 /* Make sure the value reported meets the min max requirement */
1736 if (int_value < min_value)
1737 {
1738 m_testCtx.getLog() << tcu::TestLog::Message << "GL implementation reports a value of [" << int_value
1739 << "]"
1740 " for property ["
1741 << pname_string << "]"
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 " (int value:["
1758 << int_value << "])" << tcu::TestLog::EndMessage;
1759
1760 m_has_test_passed = false;
1761 }
1762
1763 if (de::abs(double_value - (double)int_value) > epsilon)
1764 {
1765 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid double value [" << double_value
1766 << "]"
1767 " reported for property ["
1768 << pname_string << "]"
1769 " (int value:["
1770 << int_value << "])" << tcu::TestLog::EndMessage;
1771
1772 m_has_test_passed = false;
1773 }
1774
1775 if (de::abs(float_value - (float)int_value) > epsilon)
1776 {
1777 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid float value [" << float_value
1778 << "]"
1779 " reported for property ["
1780 << pname_string << "]"
1781 " (int value:["
1782 << int_value << "])" << tcu::TestLog::EndMessage;
1783
1784 m_has_test_passed = false;
1785 }
1786
1787 if (int64_value != int_value)
1788 {
1789 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid 64-bit integer value [" << float_value
1790 << "]"
1791 " reported for property ["
1792 << pname_string << "]"
1793 " (int value:["
1794 << int_value << "])" << tcu::TestLog::EndMessage;
1795
1796 m_has_test_passed = false;
1797 }
1798 } /* for (all pnames) */
1799
1800 if (m_has_test_passed)
1801 {
1802 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1803 }
1804 else
1805 {
1806 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1807 }
1808
1809 return STOP;
1810 }
1811
1812 /** Constructor.
1813 *
1814 * @param context Rendering context.
1815 *
1816 **/
APITest2(deqp::Context & context)1817 APITest2::APITest2(deqp::Context& context)
1818 : TestCase(context, "name_getters", "Verifies glGetActiveSubroutineName() and glGetActiveSubroutineUniformName() "
1819 "functions work correctly.")
1820 , m_buffer(DE_NULL)
1821 , m_has_test_passed(true)
1822 , m_po_id(0)
1823 , m_subroutine_name1("subroutine1")
1824 , m_subroutine_name2("subroutine2")
1825 , m_subroutine_uniform_name("data_provider")
1826 , m_vs_id(0)
1827 {
1828 /* Left blank intentionally */
1829 }
1830
1831 /** Destroys all ES objects that may have been created during test initialization,
1832 * as well as releases any buffers that may have been allocated during the process.
1833 */
deinit()1834 void APITest2::deinit()
1835 {
1836 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1837
1838 if (m_buffer != DE_NULL)
1839 {
1840 delete[] m_buffer;
1841
1842 m_buffer = DE_NULL;
1843 }
1844
1845 if (m_po_id != 0)
1846 {
1847 gl.deleteProgram(m_po_id);
1848
1849 m_po_id = 0;
1850 }
1851
1852 if (m_vs_id != 0)
1853 {
1854 gl.deleteShader(m_vs_id);
1855
1856 m_vs_id = 0;
1857 }
1858 }
1859
1860 /** Returns body of a vertex shader that should be used for the test.
1861 *
1862 * @return As per description.
1863 **/
getVertexShaderBody()1864 std::string APITest2::getVertexShaderBody()
1865 {
1866 return "#version 400\n"
1867 "\n"
1868 "#extension GL_ARB_shader_subroutine : require\n"
1869 "\n"
1870 "subroutine int ExampleSubroutineType(int example_argument);\n"
1871 "\n"
1872 "subroutine(ExampleSubroutineType) int subroutine1(int example_argument)\n"
1873 "{\n"
1874 " return 1;\n"
1875 "}\n"
1876 "\n"
1877 "subroutine(ExampleSubroutineType) int subroutine2(int example_argument)\n"
1878 "{\n"
1879 " return 2;\n"
1880 "}\n"
1881 "\n"
1882 "subroutine uniform ExampleSubroutineType data_provider;\n"
1883 "\n"
1884 "void main()\n"
1885 "{\n"
1886 " gl_Position = vec4(float(data_provider(0)), vec3(1) );\n"
1887 "}\n";
1888 }
1889
1890 /** Initializes all ES objects required to run the test. */
initTest()1891 void APITest2::initTest()
1892 {
1893 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1894
1895 /* Generate program & shader objects */
1896 m_po_id = gl.createProgram();
1897 m_vs_id = gl.createShader(GL_VERTEX_SHADER);
1898
1899 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() or glCreateShader() call(s) failed.");
1900
1901 /* Attach the shader to the program object */
1902 gl.attachShader(m_po_id, m_vs_id);
1903 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
1904
1905 /* Compile the shader */
1906 glw::GLint compile_status = GL_FALSE;
1907 std::string vs_body = getVertexShaderBody();
1908 const char* vs_body_raw_ptr = vs_body.c_str();
1909
1910 gl.shaderSource(m_vs_id, 1 /* count */, &vs_body_raw_ptr, DE_NULL /* length */);
1911 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
1912
1913 gl.compileShader(m_vs_id);
1914 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
1915
1916 gl.getShaderiv(m_vs_id, GL_COMPILE_STATUS, &compile_status);
1917 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
1918
1919 if (compile_status != GL_TRUE)
1920 {
1921 TCU_FAIL("Shader compilation failed.");
1922 }
1923
1924 /* Try to link the program object */
1925 glw::GLint link_status = GL_FALSE;
1926
1927 gl.linkProgram(m_po_id);
1928 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
1929
1930 gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
1931 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
1932
1933 if (link_status != GL_TRUE)
1934 {
1935 TCU_FAIL("Program linking failed.");
1936 }
1937
1938 /* Perform a few sanity checks */
1939 glw::GLint n_active_subroutines = 0;
1940 glw::GLint n_active_subroutine_uniforms = 0;
1941
1942 gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINES, &n_active_subroutines);
1943 gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORMS, &n_active_subroutine_uniforms);
1944 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramStageiv() call failed.");
1945
1946 if (n_active_subroutines != 2 /* subroutines declared in vertex shader */)
1947 {
1948 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid amount of active subroutines reported; expected: 2,"
1949 " reported:"
1950 << n_active_subroutines << tcu::TestLog::EndMessage;
1951
1952 TCU_FAIL("Invalid GL_ACTIVE_SUBROUTINES property value.");
1953 }
1954
1955 if (n_active_subroutine_uniforms != 1)
1956 {
1957 m_testCtx.getLog() << tcu::TestLog::Message
1958 << "Invalid amount of active subroutine uniforms reported: expected: 1,"
1959 " reported: "
1960 << n_active_subroutine_uniforms << tcu::TestLog::EndMessage;
1961
1962 TCU_FAIL("Invalid GL_ACTIVE_SUBROUTINE_UNIFORMS property value.");
1963 }
1964 }
1965
1966 /** Executes test iteration.
1967 *
1968 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
1969 */
iterate()1970 tcu::TestNode::IterateResult APITest2::iterate()
1971 {
1972 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
1973 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
1974 {
1975 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
1976 }
1977
1978 /* Initialize a test program object */
1979 initTest();
1980
1981 /* Verify glGetActiveSubroutineName() works correctly */
1982 verifyGLGetActiveSubroutineNameFunctionality();
1983
1984 /* Verify glGetActiveSubroutineUniformName() works correctly */
1985 verifyGLGetActiveSubroutineUniformNameFunctionality();
1986
1987 /* Done */
1988 if (m_has_test_passed)
1989 {
1990 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1991 }
1992 else
1993 {
1994 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1995 }
1996
1997 return STOP;
1998 }
1999
2000 /** Verifies glGetActiveSubroutineName() behaves as per GL_ARB_shader_subroutine
2001 * specification.
2002 **/
verifyGLGetActiveSubroutineNameFunctionality()2003 void APITest2::verifyGLGetActiveSubroutineNameFunctionality()
2004 {
2005 GLsizei expected_length1 = (GLsizei)strlen(m_subroutine_name1) + 1;
2006 GLsizei expected_length2 = (GLsizei)strlen(m_subroutine_name1) + 1;
2007 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2008 GLsizei reported_length = 0;
2009
2010 gl.getActiveSubroutineName(m_po_id, GL_VERTEX_SHADER, 0, /* index */
2011 0, /* bufsize */
2012 DE_NULL, /* length */
2013 DE_NULL); /* name */
2014 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineName() call failed.");
2015
2016 gl.getProgramInterfaceiv(m_po_id, GL_VERTEX_SUBROUTINE, GL_MAX_NAME_LENGTH, &reported_length);
2017 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineName() call failed.");
2018
2019 if ((reported_length != expected_length1) && (reported_length != expected_length2))
2020 {
2021 m_testCtx.getLog() << tcu::TestLog::Message
2022 << "Invalid active subroutine name length reported:" << reported_length
2023 << ", instead of: " << expected_length1 << " or " << expected_length2
2024 << tcu::TestLog::EndMessage;
2025
2026 TCU_FAIL("Incorrect length of active subroutine name");
2027 }
2028
2029 m_buffer = new glw::GLchar[reported_length];
2030
2031 memset(m_buffer, 0, reported_length);
2032
2033 gl.getActiveSubroutineName(m_po_id, GL_VERTEX_SHADER, 0, reported_length, DE_NULL, /* length */
2034 m_buffer);
2035 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineName() call failed.");
2036
2037 if (strcmp(m_buffer, m_subroutine_name1) != 0 && strcmp(m_buffer, m_subroutine_name2) != 0)
2038 {
2039 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid active subroutine name reported:[" << m_buffer
2040 << "]"
2041 " instead of:["
2042 << m_subroutine_name1 << "]"
2043 " or:["
2044 << m_subroutine_name2 << "]." << tcu::TestLog::EndMessage;
2045
2046 TCU_FAIL("Invalid active subroutine name reported.");
2047 }
2048
2049 delete[] m_buffer;
2050 m_buffer = DE_NULL;
2051 }
2052
2053 /** Verifies glGetActiveSubroutineUniformName() behaves as per GL_ARB_shader_subroutine
2054 * specification.
2055 **/
verifyGLGetActiveSubroutineUniformNameFunctionality()2056 void APITest2::verifyGLGetActiveSubroutineUniformNameFunctionality()
2057 {
2058 GLsizei expected_length = (GLsizei)strlen(m_subroutine_uniform_name);
2059 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2060 GLsizei reported_length = 0;
2061
2062 gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, 0, /* index */
2063 0, /* bufsize */
2064 DE_NULL, /* length */
2065 DE_NULL); /* name */
2066 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineUniformName() call failed.");
2067
2068 gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, 0, /* index */
2069 0, /* bufsize */
2070 &reported_length, DE_NULL); /* name */
2071 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineUniformName() call failed.");
2072
2073 // reported_length is the actual number of characters written into <name>
2074 // If <bufSize> is 0, reported_length should be 0
2075 if (reported_length != 0)
2076 {
2077 m_testCtx.getLog() << tcu::TestLog::Message
2078 << "Invalid active subroutine uniform name length reported:" << reported_length
2079 << ", instead of: " << 0 << tcu::TestLog::EndMessage;
2080
2081 TCU_FAIL("Incorrect length of active subroutine uniform name");
2082 }
2083
2084 m_buffer = new glw::GLchar[expected_length + 1];
2085
2086 memset(m_buffer, 0, expected_length + 1);
2087
2088 gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, 0, expected_length + 1, &reported_length, m_buffer);
2089 GLU_EXPECT_NO_ERROR(gl.getError(), "getActiveSubroutineUniformName() call failed.");
2090
2091 if (reported_length != expected_length)
2092 {
2093 m_testCtx.getLog() << tcu::TestLog::Message
2094 << "Invalid active subroutine uniform name length reported:" << reported_length
2095 << ", instead of: " << expected_length << tcu::TestLog::EndMessage;
2096
2097 TCU_FAIL("Incorrect length of active subroutine uniform name");
2098 }
2099
2100 if (strcmp(m_buffer, m_subroutine_uniform_name) != 0)
2101 {
2102 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid active subroutine uniform name reported:[" << m_buffer
2103 << "]"
2104 " instead of:["
2105 << m_subroutine_uniform_name << "]" << tcu::TestLog::EndMessage;
2106
2107 TCU_FAIL("Invalid active subroutine uniform name reported.");
2108 }
2109
2110 delete[] m_buffer;
2111 m_buffer = DE_NULL;
2112 }
2113
2114 /** Constructor.
2115 *
2116 * @param context Rendering context.
2117 *
2118 **/
FunctionalTest1_2(deqp::Context & context)2119 FunctionalTest1_2::FunctionalTest1_2(deqp::Context& context)
2120 : TestCase(context, "two_subroutines_single_subroutine_uniform",
2121 "Verifies the subroutines work correctly in a vertex shader for"
2122 " bool/float/int/uint/double/*vec*/*mat* argument and return types")
2123 , m_has_test_passed(true)
2124 , m_po_id(0)
2125 , m_po_getter0_subroutine_index(GL_INVALID_INDEX)
2126 , m_po_getter1_subroutine_index(GL_INVALID_INDEX)
2127 , m_po_subroutine_uniform_index(-1)
2128 , m_xfb_bo_id(0)
2129 , m_vao_id(0)
2130 , m_vs_id(0)
2131 {
2132 /* Left blank intentionally */
2133 }
2134
2135 /** Destroys all ES objects that may have been created during test initialization,
2136 * as well as releases any buffers that may have been allocated during the process.
2137 */
deinit()2138 void FunctionalTest1_2::deinit()
2139 {
2140 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2141
2142 deinitTestIteration();
2143
2144 if (m_xfb_bo_id != 0)
2145 {
2146 gl.deleteBuffers(1, &m_xfb_bo_id);
2147
2148 m_xfb_bo_id = 0;
2149 }
2150
2151 if (m_vao_id != 0)
2152 {
2153 gl.deleteVertexArrays(1, &m_vao_id);
2154
2155 m_vao_id = 0;
2156 }
2157 }
2158
2159 /** Deinitializes GL objects that are iteration-specific */
deinitTestIteration()2160 void FunctionalTest1_2::deinitTestIteration()
2161 {
2162 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2163
2164 if (m_po_id != 0)
2165 {
2166 gl.deleteProgram(m_po_id);
2167
2168 m_po_id = 0;
2169 }
2170
2171 if (m_vs_id != 0)
2172 {
2173 gl.deleteShader(m_vs_id);
2174
2175 m_vs_id = 0;
2176 }
2177 }
2178
2179 /** Executes a single test iteration using user-specified test case propertiesz.
2180 *
2181 * @param test-case Test case descriptor.
2182 *
2183 * @return true if the test iteration passed, false otherwise.
2184 **/
executeTestIteration(const _test_case & test_case)2185 bool FunctionalTest1_2::executeTestIteration(const _test_case& test_case)
2186 {
2187 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2188 bool result = true;
2189
2190 /* Build the test program */
2191 std::string empty_body;
2192 std::string vs_body = getVertexShaderBody(test_case.variable_type, test_case.array_size);
2193 const glw::GLchar* xfb_varyings[] = { "result" };
2194 const unsigned int n_xfb_varyings = sizeof(xfb_varyings) / sizeof(xfb_varyings[0]);
2195
2196 if (!Utils::buildProgram(gl, vs_body, empty_body, empty_body, empty_body, empty_body, xfb_varyings, n_xfb_varyings,
2197 &m_vs_id, NULL, /* out_tc_id */
2198 NULL, /* out_te_id */
2199 NULL, /* out_gs_id */
2200 NULL, &m_po_id))
2201 {
2202 TCU_FAIL("Test program failed to build.");
2203 }
2204
2205 /* Retrieve subroutine locations */
2206 m_po_getter0_subroutine_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "getter0");
2207 m_po_getter1_subroutine_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "getter1");
2208
2209 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineIndex() call(s) failed.");
2210
2211 if (m_po_getter0_subroutine_index == GL_INVALID_INDEX || m_po_getter1_subroutine_index == GL_INVALID_INDEX)
2212 {
2213 TCU_FAIL("At least one subroutine is considered inactive which is invalid.");
2214 }
2215
2216 /* Retrieve subroutine uniform location */
2217 m_po_subroutine_uniform_index = gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "colorGetterUniform");
2218
2219 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineUniformLocation() call failed.");
2220
2221 if (m_po_subroutine_uniform_index == -1)
2222 {
2223 TCU_FAIL("Subroutine uniform is considered inactive which is invalid.");
2224 }
2225
2226 /* Set up XFB BO storage */
2227 const Utils::_variable_type base_variable_type = Utils::getBaseVariableType(test_case.variable_type);
2228 unsigned int iteration_xfb_bo_size = Utils::getComponentSizeForVariableType(base_variable_type) *
2229 Utils::getNumberOfComponentsForVariableType(test_case.variable_type);
2230 unsigned int total_xfb_bo_size = 0;
2231
2232 if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2233 {
2234 /* Boolean varyings are not supported by OpenGL. Instead, we use ints to output
2235 * boolean values. */
2236 iteration_xfb_bo_size = static_cast<unsigned int>(iteration_xfb_bo_size * sizeof(int));
2237 }
2238
2239 total_xfb_bo_size = iteration_xfb_bo_size * 2 /* subroutines we will be testing */;
2240
2241 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, total_xfb_bo_size, DE_NULL /* data */, GL_STATIC_DRAW);
2242 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
2243
2244 /* Activate test program object */
2245 gl.useProgram(m_po_id);
2246 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
2247
2248 /* Run two iterations. Each iteration should invoke different subroutine. */
2249 const glw::GLuint subroutine_indices[] = { m_po_getter0_subroutine_index, m_po_getter1_subroutine_index };
2250 const unsigned int n_subroutine_indices = sizeof(subroutine_indices) / sizeof(subroutine_indices[0]);
2251
2252 for (unsigned int n_subroutine_index = 0; n_subroutine_index < n_subroutine_indices; ++n_subroutine_index)
2253 {
2254 /* Configure which subroutine should be used for the draw call */
2255 glw::GLuint current_subroutine_index = subroutine_indices[n_subroutine_index];
2256
2257 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, 1 /* count */, ¤t_subroutine_index);
2258 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniformSubroutinesuiv() call failed.");
2259
2260 /* Update XFB binding so that we do not overwrite data XFBed in previous iterations */
2261 gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
2262 m_xfb_bo_id, iteration_xfb_bo_size * n_subroutine_index, iteration_xfb_bo_size);
2263 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange() call failed.");
2264
2265 /* Draw a single point */
2266 gl.beginTransformFeedback(GL_POINTS);
2267 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed.");
2268 {
2269 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
2270 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
2271 }
2272 gl.endTransformFeedback();
2273 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed.");
2274 } /* for (all subroutine indices) */
2275
2276 /* Map the BO storage into process space */
2277 const void* xfb_data_ptr = gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
2278 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer() call failed.");
2279
2280 result &= verifyXFBData(xfb_data_ptr, test_case.variable_type);
2281
2282 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
2283 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffeR() call failed.");
2284
2285 return result;
2286 }
2287
2288 /** Retrieves body of a vertex shader that should be used to verify
2289 * subroutine support, given user-specified test iteration properties.
2290 *
2291 * @param variable_type GLSL type that should be used for argument and
2292 * return type definition in a subroutine. This setting
2293 * also affects type of the only output variable in the shader.
2294 * @param array_size 1 if non-arrayed arguments/return types should be tested;
2295 * 2 if arrayed arguments/return types should be tested.
2296 *
2297 * @return Requested string.
2298 **/
getVertexShaderBody(const Utils::_variable_type & variable_type,unsigned int array_size)2299 std::string FunctionalTest1_2::getVertexShaderBody(const Utils::_variable_type& variable_type, unsigned int array_size)
2300 {
2301 Utils::_variable_type base_variable_type = Utils::getBaseVariableType(variable_type);
2302 unsigned int n_variable_type_components = Utils::getNumberOfComponentsForVariableType(variable_type);
2303 std::stringstream result_sstream;
2304 std::string variable_type_glsl = Utils::getVariableTypeGLSLString(variable_type);
2305 std::stringstream variable_type_glsl_array_sstream;
2306 std::stringstream variable_type_glsl_arrayed_sstream;
2307
2308 variable_type_glsl_arrayed_sstream << variable_type_glsl;
2309
2310 if (array_size > 1)
2311 {
2312 variable_type_glsl_array_sstream << "[" << array_size << "]";
2313 variable_type_glsl_arrayed_sstream << variable_type_glsl_array_sstream.str();
2314 }
2315
2316 /* Form pre-amble */
2317 result_sstream << "#version 400\n"
2318 "\n"
2319 "#extension GL_ARB_shader_subroutine : require\n";
2320
2321 if (variable_type == Utils::VARIABLE_TYPE_DOUBLE)
2322 {
2323 result_sstream << "#extension GL_ARB_gpu_shader_fp64 : require\n";
2324 }
2325
2326 /* Form subroutine type declaration */
2327 result_sstream << "\n"
2328 "subroutine "
2329 << variable_type_glsl_arrayed_sstream.str() << " colorGetter(in " << variable_type_glsl
2330 << " in_value" << variable_type_glsl_array_sstream.str() << ");\n"
2331 "\n";
2332
2333 /* Declare getter functions */
2334 for (int n_getter = 0; n_getter < 2; ++n_getter)
2335 {
2336 result_sstream << "subroutine(colorGetter) " << variable_type_glsl_arrayed_sstream.str() << " getter"
2337 << n_getter << "(in " << variable_type_glsl << " in_value"
2338 << variable_type_glsl_array_sstream.str() << ")\n"
2339 "{\n";
2340
2341 if (array_size > 1)
2342 {
2343 result_sstream << variable_type_glsl << " temp" << variable_type_glsl_array_sstream.str() << ";\n";
2344 }
2345
2346 if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2347 {
2348 if (array_size > 1)
2349 {
2350 for (unsigned int array_index = 0; array_index < array_size; ++array_index)
2351 {
2352 result_sstream << " temp[" << array_index << "]"
2353 " = "
2354 << ((n_getter == 0) ? ((variable_type_glsl == "bool") ? "!" : "not") : "")
2355 << "(in_value[" << array_index << "]);\n";
2356 }
2357
2358 result_sstream << " return temp;\n";
2359 }
2360 else
2361 {
2362 result_sstream << " return "
2363 << ((n_getter == 0) ? ((variable_type_glsl == "bool") ? "!" : "not") : "")
2364 << "(in_value);\n";
2365 }
2366 } /* if (base_variable_type == Utils::VARIABLE_TYPE_BOOL) */
2367 else
2368 {
2369 if (array_size > 1)
2370 {
2371 for (unsigned int array_index = 0; array_index < array_size; ++array_index)
2372 {
2373 result_sstream << " temp[" << array_index << "]"
2374 " = in_value["
2375 << array_index << "] + " << (n_getter + 1) << ";\n";
2376 }
2377
2378 result_sstream << " return temp;\n";
2379 }
2380 else
2381 {
2382 result_sstream << " return (in_value + " << (n_getter + 1) << ");\n";
2383 }
2384 }
2385
2386 result_sstream << "}\n";
2387 } /* for (both getter functions) */
2388
2389 /* Declare subroutine uniform */
2390 result_sstream << "subroutine uniform colorGetter colorGetterUniform;\n"
2391 "\n";
2392
2393 /* Declare output variable */
2394 result_sstream << "out ";
2395
2396 if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2397 {
2398 Utils::_variable_type result_as_int_variable_type =
2399 Utils::getVariableTypeFromProperties(Utils::VARIABLE_TYPE_INT, n_variable_type_components);
2400 std::string variable_type_glsl_as_int = Utils::getVariableTypeGLSLString(result_as_int_variable_type);
2401
2402 result_sstream << variable_type_glsl_as_int;
2403 }
2404 else
2405 {
2406 result_sstream << variable_type_glsl;
2407 }
2408
2409 result_sstream << " result;\n"
2410 "\n";
2411
2412 /* Declare main(): prepare input argument for the subroutine function */
2413 result_sstream << "void main()\n"
2414 "{\n"
2415 " "
2416 << variable_type_glsl << " temp";
2417
2418 if (array_size > 1)
2419 {
2420 result_sstream << "[" << array_size << "]";
2421 };
2422
2423 result_sstream << ";\n";
2424
2425 for (unsigned int array_index = 0; array_index < array_size; ++array_index)
2426 {
2427 result_sstream << " temp";
2428
2429 if (array_size > 1)
2430 {
2431 result_sstream << "[" << array_index << "]";
2432 }
2433
2434 result_sstream << " = " << variable_type_glsl << "(";
2435
2436 if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2437 {
2438 result_sstream << "true";
2439 }
2440 else
2441 {
2442 for (unsigned int n_component = 0; n_component < n_variable_type_components; ++n_component)
2443 {
2444 result_sstream << "3";
2445
2446 if (n_component != (n_variable_type_components - 1))
2447 {
2448 result_sstream << ", ";
2449 }
2450 } /* for (all components) */
2451 }
2452
2453 result_sstream << ");\n";
2454 } /* for (all array indices) */
2455
2456 /* Declare main(): call the subroutine. Verify the input and write the result
2457 * to the output variable.
2458 **/
2459 if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2460 {
2461 Utils::_variable_type result_as_int_variable_type =
2462 Utils::getVariableTypeFromProperties(Utils::VARIABLE_TYPE_INT, n_variable_type_components);
2463 std::string variable_type_glsl_as_int = Utils::getVariableTypeGLSLString(result_as_int_variable_type);
2464
2465 result_sstream << variable_type_glsl_arrayed_sstream.str() << " subroutine_result = colorGetterUniform(temp);\n"
2466 "result = ";
2467
2468 for (unsigned int array_index = 0; array_index < array_size; ++array_index)
2469 {
2470 if (variable_type_glsl == "bool")
2471 result_sstream << "bool(subroutine_result";
2472 else
2473 result_sstream << "all(subroutine_result";
2474
2475 if (array_size > 1)
2476 {
2477 result_sstream << "[" << array_index << "]";
2478 }
2479
2480 result_sstream << ")";
2481
2482 if (array_index != (array_size - 1))
2483 {
2484 result_sstream << "&& ";
2485 }
2486 }
2487
2488 result_sstream << " == true ? " << variable_type_glsl_as_int << "(1) : " << variable_type_glsl_as_int << "(0);";
2489 }
2490 else
2491 {
2492 if (array_size > 1)
2493 {
2494 DE_ASSERT(array_size == 2);
2495
2496 result_sstream << variable_type_glsl << " subroutine_result" << variable_type_glsl_array_sstream.str()
2497 << " = colorGetterUniform(temp);\n"
2498 "\n"
2499 "if (subroutine_result[0] == subroutine_result[1]) result = subroutine_result[0];\n"
2500 "else\n"
2501 "result = "
2502 << variable_type_glsl << "(-1);\n";
2503 }
2504 else
2505 {
2506 result_sstream << "result = colorGetterUniform(temp);\n";
2507 }
2508 }
2509
2510 /* All done */
2511 result_sstream << "}\n";
2512
2513 return result_sstream.str();
2514 }
2515
2516 /** Initializes all GL objects required to run the test. */
initTest()2517 void FunctionalTest1_2::initTest()
2518 {
2519 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2520
2521 /* Generate buffer object to hold result XFB data */
2522 gl.genBuffers(1, &m_xfb_bo_id);
2523 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
2524
2525 /* Set up XFB BO bindings */
2526 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_xfb_bo_id);
2527 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
2528
2529 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_xfb_bo_id);
2530 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed.");
2531
2532 /* Generate VAO to use for the draw calls */
2533 gl.genVertexArrays(1, &m_vao_id);
2534 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
2535
2536 gl.bindVertexArray(m_vao_id);
2537 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
2538 }
2539
2540 /** Executes test iteration.
2541 *
2542 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
2543 */
iterate()2544 tcu::TestNode::IterateResult FunctionalTest1_2::iterate()
2545 {
2546 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
2547 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
2548 {
2549 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
2550 }
2551
2552 /* Initialize a test program object */
2553 initTest();
2554
2555 /* Construct test case descriptors: first, iIerate over all
2556 * variable types we want to cover */
2557 const Utils::_variable_type variable_types[] = {
2558 Utils::VARIABLE_TYPE_BOOL, Utils::VARIABLE_TYPE_BVEC2, Utils::VARIABLE_TYPE_BVEC3,
2559 Utils::VARIABLE_TYPE_BVEC4, Utils::VARIABLE_TYPE_DOUBLE, Utils::VARIABLE_TYPE_FLOAT,
2560 Utils::VARIABLE_TYPE_INT, Utils::VARIABLE_TYPE_IVEC2, Utils::VARIABLE_TYPE_IVEC3,
2561 Utils::VARIABLE_TYPE_IVEC4, Utils::VARIABLE_TYPE_MAT2, Utils::VARIABLE_TYPE_MAT2X3,
2562 Utils::VARIABLE_TYPE_MAT2X4, Utils::VARIABLE_TYPE_MAT3, Utils::VARIABLE_TYPE_MAT3X2,
2563 Utils::VARIABLE_TYPE_MAT3X4, Utils::VARIABLE_TYPE_MAT4, Utils::VARIABLE_TYPE_MAT4X2,
2564 Utils::VARIABLE_TYPE_MAT4X3, Utils::VARIABLE_TYPE_UINT, Utils::VARIABLE_TYPE_UVEC2,
2565 Utils::VARIABLE_TYPE_UVEC3, Utils::VARIABLE_TYPE_UVEC4, Utils::VARIABLE_TYPE_VEC2,
2566 Utils::VARIABLE_TYPE_VEC3, Utils::VARIABLE_TYPE_VEC4
2567 };
2568 const unsigned int n_variable_types = sizeof(variable_types) / sizeof(variable_types[0]);
2569
2570 for (unsigned int n_variable_type = 0; n_variable_type < n_variable_types; ++n_variable_type)
2571 {
2572 Utils::_variable_type current_variable_type = variable_types[n_variable_type];
2573
2574 /* We need to test both arrayed and non-arrayed arguments */
2575 for (unsigned int array_size = 1; array_size < 3; ++array_size)
2576 {
2577 /* Exclude double variables if the relevant extension is unavailable */
2578 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gpu_shader_fp64") &&
2579 current_variable_type == Utils::VARIABLE_TYPE_DOUBLE)
2580 {
2581 continue;
2582 }
2583
2584 /* Form the descriptor */
2585 _test_case test_case;
2586
2587 test_case.array_size = array_size;
2588 test_case.variable_type = current_variable_type;
2589
2590 /* Store the test case descriptor */
2591 m_test_cases.push_back(test_case);
2592 } /* for (both arrayed and non-arrayed arguments) */
2593 } /* for (all variable types) */
2594
2595 /* Iterate over all test cases and execute the test */
2596 for (_test_cases_const_iterator test_case_iterator = m_test_cases.begin(); test_case_iterator != m_test_cases.end();
2597 ++test_case_iterator)
2598 {
2599 const _test_case& test_case = *test_case_iterator;
2600
2601 m_has_test_passed &= executeTestIteration(test_case);
2602
2603 /* Release GL objects that were created during the execution */
2604 deinitTestIteration();
2605 } /* for (all test cases) */
2606
2607 /* Done */
2608 if (m_has_test_passed)
2609 {
2610 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2611 }
2612 else
2613 {
2614 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2615 }
2616
2617 return STOP;
2618 }
2619
2620 /** Verifies data that has been XFBed out by the vertex shader.
2621 *
2622 * @param xfb_data Buffer holding the data.
2623 * @param variable_type GLSL type used for the test iteration
2624 * that generated the data at @param xfb_data.
2625 *
2626 * @return true if the data was found to be valid, false if it
2627 * was detected to be incorrect.
2628 **/
verifyXFBData(const void * xfb_data,const Utils::_variable_type & variable_type)2629 bool FunctionalTest1_2::verifyXFBData(const void* xfb_data, const Utils::_variable_type& variable_type)
2630 {
2631 const Utils::_variable_type base_variable_type = Utils::getBaseVariableType(variable_type);
2632 const float epsilon = 1e-5f;
2633 const unsigned int n_variable_type_components = Utils::getNumberOfComponentsForVariableType(variable_type);
2634 bool result = true;
2635 const unsigned char* traveller_ptr = (const unsigned char*)xfb_data;
2636
2637 /* Boolean arguments/return types are tested with a slightly different shader so we
2638 * need to test them in a separate code-path.
2639 */
2640 if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2641 {
2642 /* 0 should be returned when getter0 is used, 1 otherwise */
2643 const unsigned int ref_values[] = { 0, 1 };
2644 const unsigned int n_ref_values = sizeof(ref_values) / sizeof(ref_values[0]);
2645
2646 for (unsigned int n_ref_value = 0; n_ref_value < n_ref_values; ++n_ref_value)
2647 {
2648 const unsigned int ref_value = ref_values[n_ref_value];
2649
2650 for (unsigned int n_component = 0; n_component < n_variable_type_components; ++n_component)
2651 {
2652 int* result_value_ptr = (int*)(traveller_ptr);
2653
2654 if (*result_value_ptr != (int)ref_value)
2655 {
2656 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value reported by subroutine using "
2657 "["
2658 << Utils::getVariableTypeGLSLString(variable_type) << "]"
2659 << " argument/return types ("
2660 "expected:["
2661 << ref_value << "], found:[" << *result_value_ptr << "])"
2662 << tcu::TestLog::EndMessage;
2663
2664 result = false;
2665 break;
2666 }
2667
2668 traveller_ptr += sizeof(int);
2669 } /* for (all components) */
2670 } /* for (all reference values) */
2671 } /* if (base_variable_type == Utils::VARIABLE_TYPE_BOOL) */
2672 else
2673 {
2674 /* 4 should be returned when getter0 is used, 5 otherwise */
2675 const unsigned int ref_values[] = { 4, 5 };
2676 const unsigned int n_ref_values = sizeof(ref_values) / sizeof(ref_values[0]);
2677
2678 for (unsigned int n_ref_value = 0; n_ref_value < n_ref_values; ++n_ref_value)
2679 {
2680 const unsigned int ref_value = ref_values[n_ref_value];
2681
2682 DE_ASSERT(
2683 base_variable_type == Utils::VARIABLE_TYPE_DOUBLE || base_variable_type == Utils::VARIABLE_TYPE_FLOAT ||
2684 base_variable_type == Utils::VARIABLE_TYPE_INT || base_variable_type == Utils::VARIABLE_TYPE_UINT);
2685
2686 for (unsigned int n_component = 0; n_component < n_variable_type_components; ++n_component)
2687 {
2688 const double* double_value_ptr = (double*)traveller_ptr;
2689 const float* float_value_ptr = (float*)traveller_ptr;
2690 const int* int_value_ptr = (int*)traveller_ptr;
2691
2692 switch (base_variable_type)
2693 {
2694 case Utils::VARIABLE_TYPE_DOUBLE:
2695 {
2696 if (de::abs(*double_value_ptr - (double)ref_value) > epsilon)
2697 {
2698 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value reported by subroutine using "
2699 "["
2700 << Utils::getVariableTypeGLSLString(variable_type) << "]"
2701 << " argument/return types ("
2702 "expected:["
2703 << ref_value << "], found:[" << *double_value_ptr << "])"
2704 << tcu::TestLog::EndMessage;
2705
2706 result = false;
2707 }
2708
2709 traveller_ptr += sizeof(double);
2710 break;
2711 }
2712
2713 case Utils::VARIABLE_TYPE_FLOAT:
2714 {
2715 if (de::abs(*float_value_ptr - (float)ref_value) > epsilon)
2716 {
2717 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value reported by subroutine using "
2718 "["
2719 << Utils::getVariableTypeGLSLString(variable_type) << "]"
2720 << " argument/return types ("
2721 "expected:["
2722 << ref_value << "], found:[" << *float_value_ptr << "])"
2723 << tcu::TestLog::EndMessage;
2724
2725 result = false;
2726 }
2727
2728 traveller_ptr += sizeof(float);
2729 break;
2730 }
2731
2732 case Utils::VARIABLE_TYPE_INT:
2733 case Utils::VARIABLE_TYPE_UINT:
2734 {
2735 if (*int_value_ptr != (int)ref_value)
2736 {
2737 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value reported by subroutine using "
2738 "["
2739 << Utils::getVariableTypeGLSLString(variable_type) << "]"
2740 << " argument/return types ("
2741 "expected:["
2742 << ref_value << "], found:[" << *int_value_ptr << "])"
2743 << tcu::TestLog::EndMessage;
2744
2745 result = false;
2746 }
2747
2748 traveller_ptr += sizeof(int);
2749 break;
2750 }
2751
2752 default:
2753 break;
2754 } /* switch (base_variable_type) */
2755 } /* for (all components) */
2756 } /* for (all reference values) */
2757 }
2758
2759 return result;
2760 }
2761
2762 /** Constructor
2763 *
2764 * @param context CTS context
2765 **/
FunctionalTest3_4(deqp::Context & context)2766 FunctionalTest3_4::FunctionalTest3_4(deqp::Context& context)
2767 : TestCase(context, "four_subroutines_with_two_uniforms", "Verify Get* API and draw calls")
2768 , m_n_active_subroutine_uniforms(0)
2769 , m_n_active_subroutine_uniform_locations(0)
2770 , m_n_active_subroutines(0)
2771 , m_n_active_subroutine_uniform_name_length(0)
2772 , m_n_active_subroutine_name_length(0)
2773 , m_n_active_subroutine_uniform_size(0)
2774 {
2775 /* Nothing to be done here */
2776 }
2777
2778 /** Execute test
2779 *
2780 * @return tcu::TestNode::STOP
2781 **/
iterate()2782 tcu::TestNode::IterateResult FunctionalTest3_4::iterate()
2783 {
2784 static const glw::GLchar* vertex_shader_code =
2785 "#version 400 core\n"
2786 "#extension GL_ARB_shader_subroutine : require\n"
2787 "\n"
2788 "precision highp float;\n"
2789 "\n"
2790 "// Sub routine type declaration\n"
2791 "subroutine vec4 routine_type(in vec4 iparam);\n"
2792 "\n"
2793 "// Sub routine definitions\n"
2794 "subroutine(routine_type) vec4 inverse_order(in vec4 iparam)\n"
2795 "{\n"
2796 " return iparam.wzyx;\n"
2797 "}\n"
2798 "\n"
2799 "subroutine(routine_type) vec4 negate(in vec4 iparam)\n"
2800 "{\n"
2801 " return -iparam;\n"
2802 "}\n"
2803 "\n"
2804 "subroutine(routine_type) vec4 inverse(in vec4 iparam)\n"
2805 "{\n"
2806 " return 1 / iparam;\n"
2807 "}\n"
2808 "\n"
2809 "subroutine(routine_type) vec4 square(in vec4 iparam)\n"
2810 "{\n"
2811 " return iparam * iparam;\n"
2812 "}\n"
2813 "\n"
2814 "// Sub routine uniforms\n"
2815 "subroutine uniform routine_type first_routine;\n"
2816 "subroutine uniform routine_type second_routine;\n"
2817 "\n"
2818 "// Input data\n"
2819 "uniform vec4 input_data;\n"
2820 "\n"
2821 "// Output\n"
2822 "out vec4 out_input_data;\n"
2823 "out vec4 out_result_from_first_routine;\n"
2824 "out vec4 out_result_from_second_routine;\n"
2825 "out vec4 out_result_from_combined_routines;\n"
2826 "out vec4 out_result_from_routines_combined_in_reveresed_order;\n"
2827 "\n"
2828 "void main()\n"
2829 "{\n"
2830 " out_input_data = input_data;\n"
2831 " out_result_from_first_routine = first_routine(input_data);\n"
2832 " out_result_from_second_routine = second_routine(input_data);\n"
2833 " out_result_from_combined_routines = second_routine(first_routine(input_data));\n"
2834 " out_result_from_routines_combined_in_reveresed_order = first_routine(second_routine(input_data));\n"
2835 "}\n"
2836 "\n";
2837
2838 static const GLchar* varying_names[] = {
2839 "out_input_data",
2840 "out_result_from_first_routine",
2841 "out_result_from_second_routine",
2842 "out_result_from_combined_routines",
2843 "out_result_from_routines_combined_in_reveresed_order",
2844 };
2845
2846 static const GLchar* subroutine_uniform_names[] = { "first_routine", "second_routine" };
2847
2848 static const GLchar* subroutine_names[] = { "inverse_order", "negate", "inverse", "square" };
2849
2850 static const GLuint n_varyings = sizeof(varying_names) / sizeof(varying_names[0]);
2851 static const GLuint transform_feedback_buffer_size = n_varyings * sizeof(GLfloat) * 4 /* vec4 */;
2852
2853 static const GLuint inverse_order_routine_index = 0;
2854 static const GLuint negate_routine_index = 1;
2855 static const GLuint inverse_routine_index = 2;
2856 static const GLuint square_routine_index = 3;
2857
2858 /* Test data */
2859 static const Utils::vec4<GLfloat> inverse_order_negate_data[5] = {
2860 Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
2861 Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f), Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f),
2862 Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f),
2863 };
2864
2865 static const Utils::vec4<GLfloat> inverse_order_inverse_data[5] = {
2866 Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
2867 Utils::vec4<GLfloat>(-0.5f, -1.0f, 1.0f, 0.5f), Utils::vec4<GLfloat>(0.5f, 1.0f, -1.0f, -0.5f),
2868 Utils::vec4<GLfloat>(0.5f, 1.0f, -1.0f, -0.5f),
2869 };
2870
2871 static const Utils::vec4<GLfloat> inverse_order_square_data[5] = {
2872 Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
2873 Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f), Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f),
2874 Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f),
2875 };
2876
2877 static const Utils::vec4<GLfloat> negate_inverse_data[5] = {
2878 Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
2879 Utils::vec4<GLfloat>(-0.5f, -1.0f, 1.0f, 0.5f), Utils::vec4<GLfloat>(0.5f, 1.0f, -1.0f, -0.5f),
2880 Utils::vec4<GLfloat>(0.5f, 1.0f, -1.0f, -0.5f),
2881 };
2882
2883 static const Utils::vec4<GLfloat> negate_square_data[5] = {
2884 Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
2885 Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f), Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f),
2886 Utils::vec4<GLfloat>(-4.0f, -1.0f, -1.0f, -4.0f),
2887 };
2888
2889 static const Utils::vec4<GLfloat> inverse_square_data[5] = {
2890 Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(-0.5f, -1.0f, 1.0f, 0.5f),
2891 Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f), Utils::vec4<GLfloat>(0.25f, 1.0f, 1.0f, 0.25f),
2892 Utils::vec4<GLfloat>(0.25f, 1.0f, 1.0f, 0.25f),
2893 };
2894
2895 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
2896 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
2897 {
2898 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
2899 }
2900
2901 m_n_active_subroutine_uniforms = 2;
2902 m_n_active_subroutine_uniform_locations = 2;
2903 m_n_active_subroutines = 4;
2904 m_n_active_subroutine_uniform_name_length = 0;
2905 m_n_active_subroutine_name_length = 0;
2906 m_n_active_subroutine_uniform_size = 1;
2907
2908 /* GL objects */
2909 Utils::program program(m_context);
2910 Utils::buffer transform_feedback_buffer(m_context);
2911 Utils::vertexArray vao(m_context);
2912
2913 bool result = true;
2914
2915 /* Calculate max name lengths for subroutines and subroutine uniforms */
2916 for (GLint i = 0; i < m_n_active_subroutine_uniforms; ++i)
2917 {
2918 const GLsizei length = (GLsizei)strlen(subroutine_uniform_names[i]);
2919
2920 if (length > m_n_active_subroutine_uniform_name_length)
2921 {
2922 m_n_active_subroutine_uniform_name_length = length;
2923 }
2924 }
2925
2926 for (GLint i = 0; i < m_n_active_subroutines; ++i)
2927 {
2928 const GLsizei length = (GLsizei)strlen(subroutine_names[i]);
2929
2930 if (length > m_n_active_subroutine_name_length)
2931 {
2932 m_n_active_subroutine_name_length = length;
2933 }
2934 }
2935
2936 /* Init */
2937 program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code, varying_names,
2938 n_varyings);
2939
2940 vao.generate();
2941 vao.bind();
2942
2943 transform_feedback_buffer.generate();
2944 transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
2945 GL_DYNAMIC_COPY);
2946 transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
2947
2948 program.use();
2949
2950 /* Inspect Get* API */
2951 if ((false == inspectProgramStageiv(program.m_program_object_id)) ||
2952 (false == inspectActiveSubroutineUniformiv(program.m_program_object_id, subroutine_uniform_names)) ||
2953 (false == inspectActiveSubroutineUniformName(program.m_program_object_id, subroutine_uniform_names)) ||
2954 (false == inspectActiveSubroutineName(program.m_program_object_id, subroutine_names)) ||
2955 (false ==
2956 inspectSubroutineBinding(program.m_program_object_id, subroutine_names, subroutine_uniform_names, false)))
2957 {
2958 result = false;
2959 }
2960
2961 /* Inspect GetProgram* API */
2962 if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_program_interface_query"))
2963 {
2964 if ((false == inspectProgramInterfaceiv(program.m_program_object_id)) ||
2965 (false ==
2966 inspectProgramResourceiv(program.m_program_object_id, subroutine_names, subroutine_uniform_names)) ||
2967 (false ==
2968 inspectSubroutineBinding(program.m_program_object_id, subroutine_names, subroutine_uniform_names, true)))
2969 {
2970 result = false;
2971 }
2972 }
2973
2974 /* Test shader execution */
2975 if ((false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
2976 subroutine_names[negate_routine_index], subroutine_uniform_names, inverse_order_negate_data,
2977 false)) ||
2978 (false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
2979 subroutine_names[inverse_routine_index], subroutine_uniform_names,
2980 inverse_order_inverse_data, false)) ||
2981 (false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
2982 subroutine_names[square_routine_index], subroutine_uniform_names, inverse_order_square_data,
2983 false)) ||
2984 (false == testDraw(program.m_program_object_id, subroutine_names[negate_routine_index],
2985 subroutine_names[inverse_routine_index], subroutine_uniform_names, negate_inverse_data,
2986 false)) ||
2987 (false == testDraw(program.m_program_object_id, subroutine_names[negate_routine_index],
2988 subroutine_names[square_routine_index], subroutine_uniform_names, negate_square_data,
2989 false)) ||
2990 (false == testDraw(program.m_program_object_id, subroutine_names[inverse_routine_index],
2991 subroutine_names[square_routine_index], subroutine_uniform_names, inverse_square_data,
2992 false)))
2993 {
2994 result = false;
2995 }
2996
2997 if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_program_interface_query"))
2998 {
2999 if ((false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
3000 subroutine_names[negate_routine_index], subroutine_uniform_names,
3001 inverse_order_negate_data, true)) ||
3002 (false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
3003 subroutine_names[inverse_routine_index], subroutine_uniform_names,
3004 inverse_order_inverse_data, true)) ||
3005 (false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
3006 subroutine_names[square_routine_index], subroutine_uniform_names,
3007 inverse_order_square_data, true)) ||
3008 (false == testDraw(program.m_program_object_id, subroutine_names[negate_routine_index],
3009 subroutine_names[inverse_routine_index], subroutine_uniform_names, negate_inverse_data,
3010 true)) ||
3011 (false == testDraw(program.m_program_object_id, subroutine_names[negate_routine_index],
3012 subroutine_names[square_routine_index], subroutine_uniform_names, negate_square_data,
3013 true)) ||
3014 (false == testDraw(program.m_program_object_id, subroutine_names[inverse_routine_index],
3015 subroutine_names[square_routine_index], subroutine_uniform_names, inverse_square_data,
3016 true)))
3017 {
3018 result = false;
3019 }
3020 }
3021
3022 /* Done */
3023 if (true == result)
3024 {
3025 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3026 }
3027 else
3028 {
3029 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
3030 }
3031
3032 return tcu::TestNode::STOP;
3033 }
3034
3035 /** Verify result of getProgramStageiv
3036 *
3037 * @param program_id Program object id
3038 * @param pname <pname> parameter for getProgramStageiv
3039 * @param expected Expected value
3040 *
3041 * @return true if result is equal to expected value, flase otherwise
3042 **/
checkProgramStageiv(glw::GLuint program_id,glw::GLenum pname,glw::GLint expected) const3043 bool FunctionalTest3_4::checkProgramStageiv(glw::GLuint program_id, glw::GLenum pname, glw::GLint expected) const
3044 {
3045 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3046 GLint value = 0;
3047
3048 gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, pname, &value);
3049 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3050
3051 if (expected != value)
3052 {
3053 m_context.getTestContext().getLog() << tcu::TestLog::Message
3054 << "Error. Invalid result. Function: getProgramStageiv. "
3055 << "pname: " << Utils::pnameToStr(pname) << ". "
3056 << "Result: " << value << ". "
3057 << "Expected: " << expected << "." << tcu::TestLog::EndMessage;
3058
3059 return false;
3060 }
3061 else
3062 {
3063 return true;
3064 }
3065 }
3066
3067 /** Verify result of getProgramResourceiv
3068 *
3069 * @param program_id Program object id
3070 * @param program_interface Program interface
3071 * @param pname <pname> parameter for getProgramStageiv
3072 * @param resource_name Resource name
3073 * @param expected Expected value
3074 *
3075 * @return true if result is equal to expected value, false otherwise
3076 **/
checkProgramResourceiv(GLuint program_id,GLenum program_interface,GLenum pname,const glw::GLchar * resource_name,GLint expected) const3077 bool FunctionalTest3_4::checkProgramResourceiv(GLuint program_id, GLenum program_interface, GLenum pname,
3078 const glw::GLchar* resource_name, GLint expected) const
3079 {
3080 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3081 GLuint index = gl.getProgramResourceIndex(program_id, program_interface, resource_name);
3082 GLint value = 0;
3083
3084 if (GL_INVALID_INDEX == index)
3085 {
3086 return false;
3087 }
3088
3089 gl.getProgramResourceiv(program_id, program_interface, index, 1, &pname, 1, 0, &value);
3090 GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramResourceiv");
3091
3092 if (expected != value)
3093 {
3094 m_context.getTestContext().getLog()
3095 << tcu::TestLog::Message << "Error. Invalid result. Function: getProgramResourceiv. "
3096 << "Program interface: " << Utils::programInterfaceToStr(program_interface) << ". "
3097 << "Resource name: " << resource_name << ". "
3098 << "Property: " << Utils::pnameToStr(pname) << ". "
3099 << "Result: " << value << ". "
3100 << "Expected: " << expected << "." << tcu::TestLog::EndMessage;
3101
3102 return false;
3103 }
3104 else
3105 {
3106 return true;
3107 }
3108 }
3109
3110 /** Verify result of getProgramInterfaceiv
3111 *
3112 * @param program_id Program object id
3113 * @param program_interface Program interface
3114 * @param pname <pname> parameter for getProgramStageiv
3115 * @param expected Expected value
3116 *
3117 * @return true if result is equal to expected value, flase otherwise
3118 **/
checkProgramInterfaceiv(GLuint program_id,GLenum program_interface,GLenum pname,GLint expected) const3119 bool FunctionalTest3_4::checkProgramInterfaceiv(GLuint program_id, GLenum program_interface, GLenum pname,
3120 GLint expected) const
3121 {
3122 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3123 GLint value = 0;
3124
3125 gl.getProgramInterfaceiv(program_id, program_interface, pname, &value);
3126 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramInterfaceiv");
3127
3128 if (expected != value)
3129 {
3130 m_context.getTestContext().getLog()
3131 << tcu::TestLog::Message << "Error. Invalid result. Function: getProgramInterfaceiv. "
3132 << "Program interface: " << Utils::programInterfaceToStr(program_interface) << ". "
3133 << "pname: " << Utils::pnameToStr(pname) << ". "
3134 << "Result: " << value << ". "
3135 << "Expected: " << expected << "." << tcu::TestLog::EndMessage;
3136
3137 return false;
3138 }
3139 else
3140 {
3141 return true;
3142 }
3143 }
3144
3145 /** Verify result of getActiveSubroutineUniformiv
3146 *
3147 * @param program_id Program object id
3148 * @param index <index> parameter for getActiveSubroutineUniformiv
3149 * @param pname <pname> parameter for getActiveSubroutineUniformiv
3150 * @param expected Expected value
3151 *
3152 * @return true if result is equal to expected value, flase otherwise
3153 **/
checkActiveSubroutineUniformiv(GLuint program_id,GLuint index,GLenum pname,GLint expected) const3154 bool FunctionalTest3_4::checkActiveSubroutineUniformiv(GLuint program_id, GLuint index, GLenum pname,
3155 GLint expected) const
3156 {
3157 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3158 GLint value = 0;
3159
3160 gl.getActiveSubroutineUniformiv(program_id, GL_VERTEX_SHADER, index, pname, &value);
3161 GLU_EXPECT_NO_ERROR(gl.getError(), "getActiveSubroutineUniformiv");
3162
3163 if (expected != value)
3164 {
3165 m_context.getTestContext().getLog() << tcu::TestLog::Message
3166 << "Error. Invalid result. Function: getActiveSubroutineUniformiv. "
3167 << "idnex: " << index << ". "
3168 << "pname: " << Utils::pnameToStr(pname) << ". "
3169 << "Result: " << value << ". "
3170 << "Expected: " << expected << "." << tcu::TestLog::EndMessage;
3171
3172 return false;
3173 }
3174 else
3175 {
3176 return true;
3177 }
3178 }
3179
3180 /** Returns index of program resource
3181 *
3182 * @param program_id Program object id
3183 * @param program_interface Program interface
3184 * @param resource_name Name of resource
3185 *
3186 * @return Index of specified resource
3187 **/
getProgramResourceIndex(GLuint program_id,GLenum program_interface,const glw::GLchar * resource_name) const3188 GLuint FunctionalTest3_4::getProgramResourceIndex(GLuint program_id, GLenum program_interface,
3189 const glw::GLchar* resource_name) const
3190 {
3191 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3192 GLuint index = gl.getProgramResourceIndex(program_id, program_interface, resource_name);
3193
3194 GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramResourceIndex");
3195
3196 if (GL_INVALID_INDEX == index)
3197 {
3198 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error. Program resource is not available. "
3199 << "Program interface: " << Utils::programInterfaceToStr(program_interface)
3200 << ". "
3201 << "Resource name: " << resource_name << "." << tcu::TestLog::EndMessage;
3202 }
3203
3204 return index;
3205 }
3206
3207 /** Get subroutine index
3208 *
3209 * @param program_id Program object id
3210 * @param subroutine_name Subroutine name
3211 * @param use_program_query If true getProgramResourceIndex is used, otherwise getSubroutineIndex
3212 *
3213 * @return Index of subroutine
3214 **/
getSubroutineIndex(GLuint program_id,const glw::GLchar * subroutine_name,bool use_program_query) const3215 GLuint FunctionalTest3_4::getSubroutineIndex(GLuint program_id, const glw::GLchar* subroutine_name,
3216 bool use_program_query) const
3217 {
3218 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3219 GLuint index = -1;
3220
3221 if (false == use_program_query)
3222 {
3223 index = gl.getSubroutineIndex(program_id, GL_VERTEX_SHADER, subroutine_name);
3224 GLU_EXPECT_NO_ERROR(gl.getError(), "GetSubroutineIndex");
3225 }
3226 else
3227 {
3228 index = gl.getProgramResourceIndex(program_id, GL_VERTEX_SUBROUTINE, subroutine_name);
3229 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramResourceIndex");
3230 }
3231
3232 if (GL_INVALID_INDEX == index)
3233 {
3234 TCU_FAIL("Subroutine is not available");
3235 }
3236
3237 return index;
3238 }
3239
3240 /** Get subroutine uniform location
3241 *
3242 * @param program_id Program object id
3243 * @param uniform_name Subroutine uniform name
3244 * @param use_program_query If true getProgramResourceLocation is used, otherwise getSubroutineUniformLocation
3245 *
3246 * @return Location of subroutine uniform
3247 **/
getSubroutineUniformLocation(GLuint program_id,const glw::GLchar * uniform_name,bool use_program_query) const3248 GLint FunctionalTest3_4::getSubroutineUniformLocation(GLuint program_id, const glw::GLchar* uniform_name,
3249 bool use_program_query) const
3250 {
3251 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3252 GLint location = -1;
3253
3254 if (false == use_program_query)
3255 {
3256 location = gl.getSubroutineUniformLocation(program_id, GL_VERTEX_SHADER, uniform_name);
3257 GLU_EXPECT_NO_ERROR(gl.getError(), "GetSubroutineUniformLocation");
3258 }
3259 else
3260 {
3261 location = gl.getProgramResourceLocation(program_id, GL_VERTEX_SUBROUTINE_UNIFORM, uniform_name);
3262 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramResourceLocation");
3263 }
3264
3265 if (-1 == location)
3266 {
3267 TCU_FAIL("Subroutine uniform is not available");
3268 }
3269
3270 return location;
3271 }
3272
3273 /** Test if getProgramStageiv results are as expected
3274 *
3275 * @param program_id Program object id
3276 *
3277 * @result false in case of invalid result for any pname, true otherwise
3278 **/
inspectProgramStageiv(glw::GLuint program_id) const3279 bool FunctionalTest3_4::inspectProgramStageiv(glw::GLuint program_id) const
3280 {
3281 bool result = true;
3282
3283 const inspectionDetails details[] = {
3284 { GL_ACTIVE_SUBROUTINE_UNIFORMS, m_n_active_subroutine_uniforms },
3285 { GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS, m_n_active_subroutine_uniform_locations },
3286 { GL_ACTIVE_SUBROUTINES, m_n_active_subroutines },
3287 { GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH, m_n_active_subroutine_uniform_name_length + 1 },
3288 { GL_ACTIVE_SUBROUTINE_MAX_LENGTH, m_n_active_subroutine_name_length + 1 }
3289 };
3290 const GLuint n_details = sizeof(details) / sizeof(details[0]);
3291
3292 for (GLuint i = 0; i < n_details; ++i)
3293 {
3294 if (false == checkProgramStageiv(program_id, details[i].pname, details[i].expected_value))
3295 {
3296 result = false;
3297 }
3298 }
3299
3300 return result;
3301 }
3302
3303 /** Test if checkProgramInterfaceiv results are as expected
3304 *
3305 * @param program_id Program object id
3306 *
3307 * @result false in case of invalid result for any pname, true otherwise
3308 **/
inspectProgramInterfaceiv(glw::GLuint program_id) const3309 bool FunctionalTest3_4::inspectProgramInterfaceiv(glw::GLuint program_id) const
3310 {
3311 bool result = true;
3312
3313 const inspectionDetailsForProgramInterface details[] = {
3314 { GL_VERTEX_SUBROUTINE_UNIFORM, GL_ACTIVE_RESOURCES, m_n_active_subroutine_uniforms },
3315 { GL_VERTEX_SUBROUTINE_UNIFORM, GL_MAX_NAME_LENGTH, m_n_active_subroutine_uniform_name_length + 1 },
3316 { GL_VERTEX_SUBROUTINE_UNIFORM, GL_MAX_NUM_COMPATIBLE_SUBROUTINES, m_n_active_subroutines },
3317 { GL_VERTEX_SUBROUTINE, GL_ACTIVE_RESOURCES, m_n_active_subroutines },
3318 { GL_VERTEX_SUBROUTINE, GL_MAX_NAME_LENGTH, m_n_active_subroutine_name_length + 1 }
3319 };
3320 const GLuint n_details = sizeof(details) / sizeof(details[0]);
3321
3322 for (GLuint i = 0; i < n_details; ++i)
3323 {
3324 if (false == checkProgramInterfaceiv(program_id, details[i].program_interface, details[i].pname,
3325 details[i].expected_value))
3326 {
3327 result = false;
3328 }
3329 }
3330
3331 return result;
3332 }
3333
3334 /** Test if checkProgramResourceiv results are as expected
3335 *
3336 * @param program_id Program object id
3337 * @param subroutine_names Array of subroutine names
3338 * @param uniform_names Array of uniform names
3339 *
3340 * @result false in case of invalid result for any pname, true otherwise
3341 **/
inspectProgramResourceiv(GLuint program_id,const GLchar ** subroutine_names,const GLchar ** uniform_names) const3342 bool FunctionalTest3_4::inspectProgramResourceiv(GLuint program_id, const GLchar** subroutine_names,
3343 const GLchar** uniform_names) const
3344 {
3345 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3346 bool result = true;
3347
3348 for (GLint subroutine = 0; subroutine < m_n_active_subroutines; ++subroutine)
3349 {
3350 const GLchar* subroutine_name = subroutine_names[subroutine];
3351 const GLint length = (GLint)strlen(subroutine_name) + 1;
3352
3353 if (false == checkProgramResourceiv(program_id, GL_VERTEX_SUBROUTINE, GL_NAME_LENGTH, subroutine_name, length))
3354 {
3355 result = false;
3356 }
3357 }
3358
3359 inspectionDetails details[] = {
3360 { GL_NAME_LENGTH, 0 },
3361 { GL_ARRAY_SIZE, 1 },
3362 { GL_NUM_COMPATIBLE_SUBROUTINES, m_n_active_subroutines },
3363 { GL_LOCATION, 0 },
3364 };
3365 const GLuint n_details = sizeof(details) / sizeof(details[0]);
3366
3367 for (GLint uniform = 0; uniform < m_n_active_subroutine_uniforms; ++uniform)
3368 {
3369 const GLchar* uniform_name = uniform_names[uniform];
3370 const GLint length = (GLint)strlen(uniform_name) + 1;
3371 const GLint location = getSubroutineUniformLocation(program_id, uniform_name, true);
3372
3373 details[0].expected_value = length;
3374 details[3].expected_value = location;
3375
3376 for (GLuint i = 0; i < n_details; ++i)
3377 {
3378 if (false == checkProgramResourceiv(program_id, GL_VERTEX_SUBROUTINE_UNIFORM, details[i].pname,
3379 uniform_name, details[i].expected_value))
3380 {
3381 result = false;
3382 }
3383 }
3384
3385 /* Check compatible subroutines */
3386 GLuint index = getProgramResourceIndex(program_id, GL_VERTEX_SUBROUTINE_UNIFORM, uniform_name);
3387
3388 if (GL_INVALID_INDEX != index)
3389 {
3390 std::vector<GLint> compatible_subroutines;
3391 GLint index_sum = 0;
3392 GLenum prop = GL_COMPATIBLE_SUBROUTINES;
3393
3394 compatible_subroutines.resize(m_n_active_subroutines);
3395
3396 gl.getProgramResourceiv(program_id, GL_VERTEX_SUBROUTINE_UNIFORM, index, 1, &prop, m_n_active_subroutines,
3397 0, &compatible_subroutines[0]);
3398
3399 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramResourceiv");
3400
3401 /* Expected indices are 0, 1, 2, ... N */
3402 for (GLint i = 0; i < m_n_active_subroutines; ++i)
3403 {
3404 index_sum += compatible_subroutines[i];
3405 }
3406
3407 /* Sum of E1, ..., EN = (E1 + EN) * N / 2 */
3408 if (((m_n_active_subroutines - 1) * m_n_active_subroutines) / 2 != index_sum)
3409 {
3410 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
3411
3412 message << "Error. Invalid result. Function: getProgramResourceiv. "
3413 << "Program interface: GL_VERTEX_SUBROUTINE_UNIFORM. "
3414 << "Resource name: " << uniform_name << ". "
3415 << "Property: GL_COMPATIBLE_SUBROUTINES. "
3416 << "Results: ";
3417
3418 for (GLint i = 1; i < m_n_active_subroutines; ++i)
3419 {
3420 message << compatible_subroutines[i];
3421 }
3422
3423 message << tcu::TestLog::EndMessage;
3424
3425 result = false;
3426 }
3427 }
3428 }
3429
3430 return result;
3431 }
3432
3433 /** Test if getActiveSubroutineUniformiv results are as expected
3434 *
3435 * @param program_id Program object id
3436 * @param uniform_names Array of subroutine uniform names available in program
3437 *
3438 * @result false in case of invalid result for any pname, true otherwise
3439 **/
inspectActiveSubroutineUniformiv(GLuint program_id,const GLchar ** uniform_names) const3440 bool FunctionalTest3_4::inspectActiveSubroutineUniformiv(GLuint program_id, const GLchar** uniform_names) const
3441 {
3442 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3443 bool result = true;
3444 GLint n_active_subroutine_uniforms = 0;
3445
3446 inspectionDetails details[] = {
3447 { GL_NUM_COMPATIBLE_SUBROUTINES, m_n_active_subroutines },
3448 { GL_UNIFORM_SIZE, m_n_active_subroutine_uniform_size },
3449 { GL_UNIFORM_NAME_LENGTH, 0 },
3450 };
3451 const GLuint n_details = sizeof(details) / sizeof(details[0]);
3452
3453 /* Get amount of active subroutine uniforms */
3454 gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORMS, &n_active_subroutine_uniforms);
3455 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3456
3457 for (GLint uniform = 0; uniform < n_active_subroutine_uniforms; ++uniform)
3458 {
3459 GLint name_length = (GLint)strlen(uniform_names[uniform]);
3460
3461 details[2].expected_value = name_length + 1;
3462
3463 /* Checks from "details" */
3464 for (GLuint i = 0; i < n_details; ++i)
3465 {
3466 if (false ==
3467 checkActiveSubroutineUniformiv(program_id, uniform, details[i].pname, details[i].expected_value))
3468 {
3469 result = false;
3470 }
3471 }
3472
3473 /* Check compatible subroutines */
3474 std::vector<GLint> compatible_subroutines;
3475 compatible_subroutines.resize(m_n_active_subroutines);
3476 GLint index_sum = 0;
3477
3478 gl.getActiveSubroutineUniformiv(program_id, GL_VERTEX_SHADER, uniform, GL_COMPATIBLE_SUBROUTINES,
3479 &compatible_subroutines[0]);
3480 GLU_EXPECT_NO_ERROR(gl.getError(), "getActiveSubroutineUniformiv");
3481
3482 /* Expected indices are 0, 1, 2, ... N */
3483 for (GLint i = 0; i < m_n_active_subroutines; ++i)
3484 {
3485 index_sum += compatible_subroutines[i];
3486 }
3487
3488 /* Sum of E1, ..., EN = (E1 + EN) * N / 2 */
3489 if (((m_n_active_subroutines - 1) * m_n_active_subroutines) / 2 != index_sum)
3490 {
3491 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
3492
3493 message << "Error. Invalid result. Function: getActiveSubroutineUniformiv. idnex: " << uniform
3494 << ". pname: " << Utils::pnameToStr(GL_COMPATIBLE_SUBROUTINES) << ". Results: ";
3495
3496 for (GLint i = 1; i < m_n_active_subroutines; ++i)
3497 {
3498 message << compatible_subroutines[i];
3499 }
3500
3501 message << tcu::TestLog::EndMessage;
3502
3503 result = false;
3504 }
3505 }
3506
3507 return result;
3508 }
3509
3510 /** Test if getActiveSubroutineUniformName results are as expected
3511 *
3512 * @param program_id Program object id
3513 * @param uniform_names Array of subroutine uniform names available in program
3514 *
3515 * @result false in case of invalid result, true otherwise
3516 **/
inspectActiveSubroutineUniformName(GLuint program_id,const GLchar ** uniform_names) const3517 bool FunctionalTest3_4::inspectActiveSubroutineUniformName(GLuint program_id, const GLchar** uniform_names) const
3518 {
3519 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3520 bool result = true;
3521 GLint n_active_subroutine_uniforms = 0;
3522 std::vector<GLchar> active_uniform_name;
3523
3524 gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORMS, &n_active_subroutine_uniforms);
3525 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3526
3527 active_uniform_name.resize(m_n_active_subroutine_uniform_name_length + 1);
3528
3529 for (GLint uniform = 0; uniform < n_active_subroutine_uniforms; ++uniform)
3530 {
3531 bool is_name_ok = false;
3532
3533 gl.getActiveSubroutineUniformName(program_id, GL_VERTEX_SHADER, uniform, (GLsizei)active_uniform_name.size(),
3534 0 /* length */, &active_uniform_name[0]);
3535 GLU_EXPECT_NO_ERROR(gl.getError(), "GetActiveSubroutineUniformName");
3536
3537 for (GLint name = 0; name < n_active_subroutine_uniforms; ++name)
3538 {
3539 if (0 == strcmp(uniform_names[name], &active_uniform_name[0]))
3540 {
3541 is_name_ok = true;
3542 break;
3543 }
3544 }
3545
3546 if (false == is_name_ok)
3547 {
3548 m_context.getTestContext().getLog()
3549 << tcu::TestLog::Message
3550 << "Error. Invalid result. Function: getActiveSubroutineUniformName. idnex: " << uniform
3551 << ". Result: " << &active_uniform_name[0] << tcu::TestLog::EndMessage;
3552
3553 result = false;
3554 break;
3555 }
3556 }
3557
3558 return result;
3559 }
3560
3561 /** Test if getActiveSubroutineUniformName results are as expected
3562 *
3563 * @param program_id Program object id
3564 * @param subroutine_names Array of subroutine names available in program
3565 *
3566 * @result false in case of invalid result, true otherwise
3567 **/
inspectActiveSubroutineName(GLuint program_id,const GLchar ** subroutine_names) const3568 bool FunctionalTest3_4::inspectActiveSubroutineName(GLuint program_id, const GLchar** subroutine_names) const
3569 {
3570 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3571 bool result = true;
3572 GLint n_active_subroutines = 0;
3573 std::vector<GLchar> active_subroutine_name;
3574
3575 gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINES, &n_active_subroutines);
3576 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3577
3578 active_subroutine_name.resize(m_n_active_subroutine_name_length + 1);
3579
3580 for (GLint uniform = 0; uniform < n_active_subroutines; ++uniform)
3581 {
3582 bool is_name_ok = false;
3583
3584 gl.getActiveSubroutineName(program_id, GL_VERTEX_SHADER, uniform, (GLsizei)active_subroutine_name.size(),
3585 0 /* length */, &active_subroutine_name[0]);
3586 GLU_EXPECT_NO_ERROR(gl.getError(), "getActiveSubroutineName");
3587
3588 for (GLint name = 0; name < n_active_subroutines; ++name)
3589 {
3590 if (0 == strcmp(subroutine_names[name], &active_subroutine_name[0]))
3591 {
3592 is_name_ok = true;
3593 break;
3594 }
3595 }
3596
3597 if (false == is_name_ok)
3598 {
3599 m_context.getTestContext().getLog()
3600 << tcu::TestLog::Message
3601 << "Error. Invalid result. Function: getActiveSubroutineName. idnex: " << uniform
3602 << ". Result: " << &active_subroutine_name[0] << tcu::TestLog::EndMessage;
3603
3604 result = false;
3605 break;
3606 }
3607 }
3608
3609 return result;
3610 }
3611
3612 /** Test if it is possible to "bind" all subroutines uniforms with all subroutines
3613 *
3614 * @param program_id Program object id
3615 * @param subroutine_names Array of subroutine names available in program
3616 * @param uniform_names Array of subroutine uniform names available in program
3617 *
3618 * @result false in case of invalid result, true otherwise
3619 **/
inspectSubroutineBinding(GLuint program_id,const GLchar ** subroutine_names,const GLchar ** uniform_names,bool use_program_query) const3620 bool FunctionalTest3_4::inspectSubroutineBinding(GLuint program_id, const GLchar** subroutine_names,
3621 const GLchar** uniform_names, bool use_program_query) const
3622 {
3623 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3624 bool result = true;
3625 GLint n_active_subroutines = 0;
3626 GLint n_active_subroutine_uniforms = 0;
3627 std::vector<GLuint> subroutine_uniforms;
3628 GLuint queried_subroutine_index = 0;
3629
3630 gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINES, &n_active_subroutines);
3631 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3632
3633 gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORMS, &n_active_subroutine_uniforms);
3634 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3635
3636 subroutine_uniforms.resize(n_active_subroutine_uniforms);
3637
3638 for (GLint uniform = 0; uniform < n_active_subroutine_uniforms; ++uniform)
3639 {
3640 GLuint uniform_location = getSubroutineUniformLocation(program_id, uniform_names[uniform], use_program_query);
3641
3642 for (GLint routine = 0; routine < n_active_subroutines; ++routine)
3643 {
3644 GLuint routine_index = getSubroutineIndex(program_id, subroutine_names[routine], use_program_query);
3645
3646 subroutine_uniforms[uniform] = routine_index;
3647
3648 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, n_active_subroutine_uniforms, &subroutine_uniforms[0]);
3649 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
3650
3651 gl.getUniformSubroutineuiv(GL_VERTEX_SHADER, uniform_location, &queried_subroutine_index);
3652 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv");
3653
3654 if (queried_subroutine_index != routine_index)
3655 {
3656 m_context.getTestContext().getLog()
3657 << tcu::TestLog::Message << "Error. Invalid result. Function: gl.getUniformSubroutineuiv."
3658 << " Subroutine uniform: " << uniform << ", name: " << uniform_names[uniform]
3659 << ", location: " << uniform_location << ". Subroutine: " << routine
3660 << ", name: " << subroutine_names[routine] << ", index: " << routine_index
3661 << ". Result: " << queried_subroutine_index << tcu::TestLog::EndMessage;
3662
3663 result = false;
3664 }
3665 }
3666 }
3667
3668 return result;
3669 }
3670
3671 /** Execute draw call and verify results
3672 *
3673 * @param program_id Program object id
3674 * @param first_routine_name Name of subroutine that shall be used aas first_routine
3675 * @param second_routine_name Name of subroutine that shall be used aas second_routine
3676 * @param uniform_names Name of uniforms
3677 * @param expected_results Test data. [0] is used as input data. All are used as expected_results
3678 * @param use_program_query If true GetProgram* API will be used
3679 *
3680 * @return false in case of invalid result, true otherwise
3681 **/
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) const3682 bool FunctionalTest3_4::testDraw(GLuint program_id, const GLchar* first_routine_name, const GLchar* second_routine_name,
3683 const GLchar** uniform_names, const Utils::vec4<GLfloat> expected_results[5],
3684 bool use_program_query) const
3685 {
3686 static const GLuint n_varyings = 5;
3687 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3688 bool result = true;
3689 GLuint subroutine_uniforms[2] = { 0 };
3690
3691 /* Get subroutine uniform locations */
3692 GLint first_routine_location = getSubroutineUniformLocation(program_id, uniform_names[0], use_program_query);
3693
3694 GLint second_routine_location = getSubroutineUniformLocation(program_id, uniform_names[1], use_program_query);
3695
3696 /* Get subroutine indices */
3697 GLuint first_routine_index = getSubroutineIndex(program_id, first_routine_name, use_program_query);
3698
3699 GLuint second_routine_index = getSubroutineIndex(program_id, second_routine_name, use_program_query);
3700
3701 /* Map uniforms with subroutines */
3702 subroutine_uniforms[first_routine_location] = first_routine_index;
3703 subroutine_uniforms[second_routine_location] = second_routine_index;
3704
3705 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, 2 /* number of uniforms */, &subroutine_uniforms[0]);
3706 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
3707
3708 /* Get location of input_data */
3709 GLint input_data_location = gl.getUniformLocation(program_id, "input_data");
3710 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation");
3711
3712 if (-1 == input_data_location)
3713 {
3714 TCU_FAIL("Uniform is not available");
3715 }
3716
3717 /* Set up input_data */
3718 gl.uniform4f(input_data_location, expected_results[0].m_x, expected_results[0].m_y, expected_results[0].m_z,
3719 expected_results[0].m_w);
3720 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
3721
3722 /* Execute draw call with transform feedback */
3723 gl.beginTransformFeedback(GL_POINTS);
3724 GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
3725
3726 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
3727 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
3728
3729 gl.endTransformFeedback();
3730 GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
3731
3732 /* Verify results */
3733 GLfloat* feedback_data = (GLfloat*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
3734 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
3735
3736 Utils::vec4<GLfloat> results[5];
3737
3738 results[0].m_x = feedback_data[0];
3739 results[0].m_y = feedback_data[1];
3740 results[0].m_z = feedback_data[2];
3741 results[0].m_w = feedback_data[3];
3742
3743 results[1].m_x = feedback_data[4];
3744 results[1].m_y = feedback_data[5];
3745 results[1].m_z = feedback_data[6];
3746 results[1].m_w = feedback_data[7];
3747
3748 results[2].m_x = feedback_data[8];
3749 results[2].m_y = feedback_data[9];
3750 results[2].m_z = feedback_data[10];
3751 results[2].m_w = feedback_data[11];
3752
3753 results[3].m_x = feedback_data[12];
3754 results[3].m_y = feedback_data[13];
3755 results[3].m_z = feedback_data[14];
3756 results[3].m_w = feedback_data[15];
3757
3758 results[4].m_x = feedback_data[16];
3759 results[4].m_y = feedback_data[17];
3760 results[4].m_z = feedback_data[18];
3761 results[4].m_w = feedback_data[19];
3762
3763 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
3764 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
3765
3766 for (GLuint i = 0; i < n_varyings; ++i)
3767 {
3768 result = result && (results[i] == expected_results[i]);
3769 }
3770
3771 if (false == result)
3772 {
3773 m_context.getTestContext().getLog() << tcu::TestLog::Message
3774 << "Error. Invalid result. First routine: " << first_routine_name
3775 << ". Second routine: " << second_routine_name << tcu::TestLog::EndMessage;
3776
3777 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
3778
3779 message << "Results:";
3780
3781 for (GLuint i = 0; i < n_varyings; ++i)
3782 {
3783 results[i].log(message);
3784 }
3785
3786 message << tcu::TestLog::EndMessage;
3787
3788 message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
3789
3790 message << "Expected:";
3791
3792 for (GLuint i = 0; i < n_varyings; ++i)
3793 {
3794 expected_results[i].log(message);
3795 }
3796
3797 message << tcu::TestLog::EndMessage;
3798 }
3799
3800 return result;
3801 }
3802
3803 /** Constructor
3804 *
3805 * @param context CTS context
3806 **/
FunctionalTest5(deqp::Context & context)3807 FunctionalTest5::FunctionalTest5(deqp::Context& context)
3808 : TestCase(context, "eight_subroutines_four_uniforms", "Verify multiple subroutine sets")
3809 {
3810 }
3811
3812 /** Execute test
3813 *
3814 * @return tcu::TestNode::STOP
3815 **/
iterate()3816 tcu::TestNode::IterateResult FunctionalTest5::iterate()
3817 {
3818 static const GLchar* vertex_shader_code =
3819 "#version 400 core\n"
3820 "#extension GL_ARB_shader_subroutine : require\n"
3821 "\n"
3822 "precision highp float;\n"
3823 "\n"
3824 "// Subroutine types\n"
3825 "subroutine vec4 routine_type_1(in vec4 left, in vec4 right);\n"
3826 "subroutine vec4 routine_type_2(in vec4 iparam);\n"
3827 "subroutine vec4 routine_type_3(in vec4 a, in vec4 b, in vec4 c);\n"
3828 "subroutine bvec4 routine_type_4(in vec4 left, in vec4 right);\n"
3829 "\n"
3830 "// Subroutine definitions\n"
3831 "// 1st type\n"
3832 "subroutine(routine_type_1) vec4 add(in vec4 left, in vec4 right)\n"
3833 "{\n"
3834 " return left + right;\n"
3835 "}\n"
3836 "\n"
3837 "subroutine(routine_type_1) vec4 subtract(in vec4 left, in vec4 right)\n"
3838 "{\n"
3839 " return left - right;\n"
3840 "}\n"
3841 "\n"
3842 "// 2nd type\n"
3843 "subroutine(routine_type_2) vec4 square(in vec4 iparam)\n"
3844 "{\n"
3845 " return iparam * iparam;\n"
3846 "}\n"
3847 "\n"
3848 "subroutine(routine_type_2) vec4 square_root(in vec4 iparam)\n"
3849 "{\n"
3850 " return sqrt(iparam);\n"
3851 "}\n"
3852 "\n"
3853 "// 3rd type\n"
3854 "subroutine(routine_type_3) vec4 do_fma(in vec4 a, in vec4 b, in vec4 c)\n"
3855 "{\n"
3856 " return fma(a, b, c);\n"
3857 "}\n"
3858 "\n"
3859 "subroutine(routine_type_3) vec4 blend(in vec4 a, in vec4 b, in vec4 c)\n"
3860 "{\n"
3861 " return c * a + (vec4(1) - c) * b;\n"
3862 "}\n"
3863 "\n"
3864 "// 4th type\n"
3865 "subroutine(routine_type_4) bvec4 are_equal(in vec4 left, in vec4 right)\n"
3866 "{\n"
3867 " return equal(left, right);\n"
3868 "}\n"
3869 "\n"
3870 "subroutine(routine_type_4) bvec4 are_greater(in vec4 left, in vec4 right)\n"
3871 "{\n"
3872 " return greaterThan(left, right);\n"
3873 "}\n"
3874 "\n"
3875 "// Sub routine uniforms\n"
3876 "subroutine uniform routine_type_1 first_routine;\n"
3877 "subroutine uniform routine_type_2 second_routine;\n"
3878 "subroutine uniform routine_type_3 third_routine;\n"
3879 "subroutine uniform routine_type_4 fourth_routine;\n"
3880 "\n"
3881 "// Input data\n"
3882 "uniform vec4 first_input;\n"
3883 "uniform vec4 second_input;\n"
3884 "uniform vec4 third_input;\n"
3885 "\n"
3886 "// Output\n"
3887 "out vec4 out_result_from_first_routine;\n"
3888 "out vec4 out_result_from_second_routine;\n"
3889 "out vec4 out_result_from_third_routine;\n"
3890 "out uvec4 out_result_from_fourth_routine;\n"
3891 "\n"
3892 "void main()\n"
3893 "{\n"
3894 " out_result_from_first_routine = first_routine (first_input, second_input);\n"
3895 " out_result_from_second_routine = second_routine(first_input);\n"
3896 " out_result_from_third_routine = third_routine (first_input, second_input, third_input);\n"
3897 " out_result_from_fourth_routine = uvec4(fourth_routine(first_input, second_input));\n"
3898 "}\n"
3899 "\n";
3900
3901 static const GLchar* subroutine_names[4][2] = {
3902 { "add", "subtract" }, { "square", "square_root" }, { "do_fma", "blend" }, { "are_equal", "are_greater" }
3903 };
3904
3905 static const GLchar* subroutine_uniform_names[4][1] = {
3906 { "first_routine" }, { "second_routine" }, { "third_routine" }, { "fourth_routine" }
3907 };
3908
3909 static const GLuint n_subroutine_types = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
3910 static const GLuint n_subroutines_per_type = sizeof(subroutine_names[0]) / sizeof(subroutine_names[0][0]);
3911 static const GLuint n_subroutine_uniforms_per_type =
3912 sizeof(subroutine_uniform_names[0]) / sizeof(subroutine_uniform_names[0][0]);
3913
3914 static const GLchar* uniform_names[] = { "first_input", "second_input", "third_input" };
3915 static const GLuint n_uniform_names = sizeof(uniform_names) / sizeof(uniform_names[0]);
3916
3917 static const GLchar* varying_names[] = { "out_result_from_first_routine", "out_result_from_second_routine",
3918 "out_result_from_third_routine", "out_result_from_fourth_routine" };
3919 static const GLuint n_varyings = sizeof(varying_names) / sizeof(varying_names[0]);
3920 static const GLuint transform_feedback_buffer_size = n_varyings * sizeof(GLfloat) * 4 /* vec4 */;
3921
3922 /* Test data */
3923 static const Utils::vec4<GLfloat> input_data[3] = { Utils::vec4<GLfloat>(1.0f, 4.0f, 9.0f, 16.0f),
3924 Utils::vec4<GLfloat>(16.0f, 9.0f, 4.0f, 1.0f),
3925 Utils::vec4<GLfloat>(0.25f, 0.5f, 0.75f, 1.0f) };
3926
3927 static const Utils::vec4<GLfloat> expected_result_from_first_routine[2] = {
3928 Utils::vec4<GLfloat>(17.0f, 13.0f, 13.0f, 17.0f), Utils::vec4<GLfloat>(-15.0f, -5.0f, 5.0f, 15.0f)
3929 };
3930
3931 static const Utils::vec4<GLfloat> expected_result_from_second_routine[2] = {
3932 Utils::vec4<GLfloat>(1.0f, 16.0f, 81.0f, 256.0f), Utils::vec4<GLfloat>(1.0f, 2.0f, 3.0f, 4.0f)
3933 };
3934
3935 static const Utils::vec4<GLfloat> expected_result_from_third_routine[2] = {
3936 Utils::vec4<GLfloat>(16.25f, 36.5f, 36.75f, 17.0f), Utils::vec4<GLfloat>(12.25f, 6.5f, 7.75f, 16.0f)
3937 };
3938
3939 static const Utils::vec4<GLuint> expected_result_from_fourth_routine[2] = { Utils::vec4<GLuint>(0, 0, 0, 0),
3940 Utils::vec4<GLuint>(0, 0, 1, 1) };
3941
3942 /* All combinations of subroutines */
3943 static const GLuint subroutine_combinations[][4] = {
3944 { 0, 0, 0, 0 }, { 0, 0, 0, 1 }, { 0, 0, 1, 0 }, { 0, 0, 1, 1 }, { 0, 1, 0, 0 }, { 0, 1, 0, 1 },
3945 { 0, 1, 1, 0 }, { 0, 1, 1, 1 }, { 1, 0, 0, 0 }, { 1, 0, 0, 1 }, { 1, 0, 1, 0 }, { 1, 0, 1, 1 },
3946 { 1, 1, 0, 0 }, { 1, 1, 0, 1 }, { 1, 1, 1, 0 }, { 1, 1, 1, 1 }
3947 };
3948 static const GLuint n_subroutine_combinations =
3949 sizeof(subroutine_combinations) / sizeof(subroutine_combinations[0]);
3950
3951 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
3952 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
3953 {
3954 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
3955 }
3956
3957 /* Result */
3958 bool result = true;
3959
3960 /* GL objects */
3961 Utils::program program(m_context);
3962 Utils::buffer transform_feedback_buffer(m_context);
3963 Utils::vertexArray vao(m_context);
3964
3965 /* Init GL objects */
3966 program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code, varying_names,
3967 n_varyings);
3968
3969 program.use();
3970
3971 vao.generate();
3972 vao.bind();
3973
3974 transform_feedback_buffer.generate();
3975 transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
3976 GL_DYNAMIC_COPY);
3977 transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
3978
3979 /* Get subroutine uniform locations and subroutine indices */
3980 for (GLuint type = 0; type < n_subroutine_types; ++type)
3981 {
3982 for (GLuint uniform = 0; uniform < n_subroutine_uniforms_per_type; ++uniform)
3983 {
3984 m_subroutine_uniform_locations[type][uniform] =
3985 program.getSubroutineUniformLocation(subroutine_uniform_names[type][uniform], GL_VERTEX_SHADER);
3986 }
3987
3988 for (GLuint routine = 0; routine < n_subroutines_per_type; ++routine)
3989 {
3990 m_subroutine_indices[type][routine] =
3991 program.getSubroutineIndex(subroutine_names[type][routine], GL_VERTEX_SHADER);
3992 }
3993 }
3994
3995 /* Get uniform locations */
3996 for (GLuint i = 0; i < n_uniform_names; ++i)
3997 {
3998 m_uniform_locations[i] = program.getUniformLocation(uniform_names[i]);
3999 }
4000
4001 /* Draw with each routine combination */
4002 for (GLuint i = 0; i < n_subroutine_combinations; ++i)
4003 {
4004 Utils::vec4<GLfloat> first_routine_result;
4005 Utils::vec4<GLfloat> second_routine_result;
4006 Utils::vec4<GLfloat> third_routine_result;
4007 Utils::vec4<GLuint> fourth_routine_result;
4008
4009 testDraw(subroutine_combinations[i], input_data, first_routine_result, second_routine_result,
4010 third_routine_result, fourth_routine_result);
4011
4012 if (false == verify(first_routine_result, second_routine_result, third_routine_result, fourth_routine_result,
4013 expected_result_from_first_routine[subroutine_combinations[i][0]],
4014 expected_result_from_second_routine[subroutine_combinations[i][1]],
4015 expected_result_from_third_routine[subroutine_combinations[i][2]],
4016 expected_result_from_fourth_routine[subroutine_combinations[i][3]]))
4017 {
4018 logError(subroutine_names, subroutine_combinations[i], input_data, first_routine_result,
4019 second_routine_result, third_routine_result, fourth_routine_result,
4020 expected_result_from_first_routine[subroutine_combinations[i][0]],
4021 expected_result_from_second_routine[subroutine_combinations[i][1]],
4022 expected_result_from_third_routine[subroutine_combinations[i][2]],
4023 expected_result_from_fourth_routine[subroutine_combinations[i][3]]);
4024
4025 result = false;
4026 }
4027 }
4028
4029 /* Done */
4030 if (true == result)
4031 {
4032 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4033 }
4034 else
4035 {
4036 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
4037 }
4038
4039 return tcu::TestNode::STOP;
4040 }
4041
4042 /** Log error message
4043 *
4044 * @param subroutine_names Array of subroutine names
4045 * @param subroutine_combination Combination of subroutines
4046 * @param input_data Input data
4047 * @param first_routine_result Result of first routine
4048 * @param second_routine_result Result of second routine
4049 * @param third_routine_result Result of third routine
4050 * @param fourth_routine_result Result of fourth routine
4051 * @param first_routine_expected_result Expected result of first routine
4052 * @param second_routine_expected_result Expected result of second routine
4053 * @param third_routine_expected_result Expected result of third routine
4054 * @param fourth_routine_expected_result Expected result of fourth routine
4055 **/
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) const4056 void FunctionalTest5::logError(const glw::GLchar* subroutine_names[4][2], const glw::GLuint subroutine_combination[4],
4057 const Utils::vec4<glw::GLfloat> input_data[3],
4058 const Utils::vec4<glw::GLfloat>& first_routine_result,
4059 const Utils::vec4<glw::GLfloat>& second_routine_result,
4060 const Utils::vec4<glw::GLfloat>& third_routine_result,
4061 const Utils::vec4<glw::GLuint>& fourth_routine_result,
4062 const Utils::vec4<glw::GLfloat>& first_routine_expected_result,
4063 const Utils::vec4<glw::GLfloat>& second_routine_expected_result,
4064 const Utils::vec4<glw::GLfloat>& third_routine_expected_result,
4065 const Utils::vec4<glw::GLuint>& fourth_routine_expected_result) const
4066 {
4067 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error. Invalid result."
4068 << tcu::TestLog::EndMessage;
4069
4070 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4071
4072 message << "Function: " << subroutine_names[0][subroutine_combination[0]] << "( ";
4073 input_data[0].log(message);
4074 message << ", ";
4075 input_data[1].log(message);
4076 message << " ). Result: ";
4077 first_routine_result.log(message);
4078 message << ". Expected: ";
4079 first_routine_expected_result.log(message);
4080
4081 message << tcu::TestLog::EndMessage;
4082
4083 message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4084
4085 message << "Function: " << subroutine_names[1][subroutine_combination[1]] << "( ";
4086 input_data[0].log(message);
4087 message << " ). Result: ";
4088 second_routine_result.log(message);
4089 message << ". Expected: ";
4090 second_routine_expected_result.log(message);
4091
4092 message << tcu::TestLog::EndMessage;
4093
4094 message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4095
4096 message << "Function: " << subroutine_names[2][subroutine_combination[2]] << "( ";
4097 input_data[0].log(message);
4098 message << ", ";
4099 input_data[1].log(message);
4100 message << ", ";
4101 input_data[2].log(message);
4102 message << "). Result: ";
4103 third_routine_result.log(message);
4104 message << ". Expected: ";
4105 third_routine_expected_result.log(message);
4106
4107 message << tcu::TestLog::EndMessage;
4108
4109 message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4110
4111 message << "Function: " << subroutine_names[3][subroutine_combination[3]] << "( ";
4112 input_data[0].log(message);
4113 message << ", ";
4114 input_data[1].log(message);
4115 message << ", ";
4116 message << " ). Result: ";
4117 fourth_routine_result.log(message);
4118 message << ". Expected: ";
4119 fourth_routine_expected_result.log(message);
4120
4121 message << tcu::TestLog::EndMessage;
4122 }
4123
4124 /** Execute draw call and capture results
4125 *
4126 * @param subroutine_combination Combination of subroutines
4127 * @param input_data Input data
4128 * @param out_first_routine_result Result of first routine
4129 * @param out_second_routine_result Result of second routine
4130 * @param out_third_routine_result Result of third routine
4131 * @param out_fourth_routine_result Result of fourth routine
4132 **/
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) const4133 void FunctionalTest5::testDraw(const glw::GLuint subroutine_combination[4],
4134 const Utils::vec4<glw::GLfloat> input_data[3],
4135 Utils::vec4<glw::GLfloat>& out_first_routine_result,
4136 Utils::vec4<glw::GLfloat>& out_second_routine_result,
4137 Utils::vec4<glw::GLfloat>& out_third_routine_result,
4138 Utils::vec4<glw::GLuint>& out_fourth_routine_result) const
4139 {
4140 static const GLuint n_uniforms = sizeof(m_uniform_locations) / sizeof(m_uniform_locations[0]);
4141 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
4142 GLuint subroutine_indices[4];
4143 static const GLuint n_subroutine_uniforms = sizeof(subroutine_indices) / sizeof(subroutine_indices[0]);
4144
4145 /* Prepare subroutine uniform data */
4146 for (GLuint i = 0; i < n_subroutine_uniforms; ++i)
4147 {
4148 const GLuint location = m_subroutine_uniform_locations[i][0];
4149
4150 subroutine_indices[location] = m_subroutine_indices[i][subroutine_combination[i]];
4151 }
4152
4153 /* Set up subroutine uniforms */
4154 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, n_subroutine_uniforms, &subroutine_indices[0]);
4155 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
4156
4157 /* Set up input data uniforms */
4158 for (GLuint i = 0; i < n_uniforms; ++i)
4159 {
4160 gl.uniform4f(m_uniform_locations[i], input_data[i].m_x, input_data[i].m_y, input_data[i].m_z,
4161 input_data[i].m_w);
4162 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
4163 }
4164
4165 /* Execute draw call with transform feedback */
4166 gl.beginTransformFeedback(GL_POINTS);
4167 GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
4168
4169 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
4170 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
4171
4172 gl.endTransformFeedback();
4173 GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
4174
4175 /* Capture results */
4176 GLvoid* feedback_data = gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
4177 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
4178
4179 GLfloat* float_ptr = (GLfloat*)feedback_data;
4180
4181 /* First result */
4182 out_first_routine_result.m_x = float_ptr[0];
4183 out_first_routine_result.m_y = float_ptr[1];
4184 out_first_routine_result.m_z = float_ptr[2];
4185 out_first_routine_result.m_w = float_ptr[3];
4186
4187 /* Second result */
4188 out_second_routine_result.m_x = float_ptr[4];
4189 out_second_routine_result.m_y = float_ptr[5];
4190 out_second_routine_result.m_z = float_ptr[6];
4191 out_second_routine_result.m_w = float_ptr[7];
4192
4193 /* Third result */
4194 out_third_routine_result.m_x = float_ptr[8];
4195 out_third_routine_result.m_y = float_ptr[9];
4196 out_third_routine_result.m_z = float_ptr[10];
4197 out_third_routine_result.m_w = float_ptr[11];
4198
4199 /* Fourth result */
4200 GLuint* uint_ptr = (GLuint*)(float_ptr + 12);
4201 out_fourth_routine_result.m_x = uint_ptr[0];
4202 out_fourth_routine_result.m_y = uint_ptr[1];
4203 out_fourth_routine_result.m_z = uint_ptr[2];
4204 out_fourth_routine_result.m_w = uint_ptr[3];
4205
4206 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
4207 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
4208 }
4209
4210 /** Verify if results match expected results
4211 *
4212 * @param first_routine_result Result of first routine
4213 * @param second_routine_result Result of second routine
4214 * @param third_routine_result Result of third routine
4215 * @param fourth_routine_result Result of fourth routine
4216 * @param first_routine_expected_result Expected result of first routine
4217 * @param second_routine_expected_result Expected result of second routine
4218 * @param third_routine_expected_result Expected result of third routine
4219 * @param fourth_routine_expected_result Expected result of fourth routine
4220 **/
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) const4221 bool FunctionalTest5::verify(const Utils::vec4<glw::GLfloat>& first_routine_result,
4222 const Utils::vec4<glw::GLfloat>& second_routine_result,
4223 const Utils::vec4<glw::GLfloat>& third_routine_result,
4224 const Utils::vec4<glw::GLuint>& fourth_routine_result,
4225 const Utils::vec4<glw::GLfloat>& first_routine_expected_result,
4226 const Utils::vec4<glw::GLfloat>& second_routine_expected_result,
4227 const Utils::vec4<glw::GLfloat>& third_routine_expected_result,
4228 const Utils::vec4<glw::GLuint>& fourth_routine_expected_result) const
4229 {
4230 bool result = true;
4231
4232 result = result && (first_routine_result == first_routine_expected_result);
4233 result = result && (second_routine_result == second_routine_expected_result);
4234 result = result && (third_routine_result == third_routine_expected_result);
4235 result = result && (fourth_routine_result == fourth_routine_expected_result);
4236
4237 return result;
4238 }
4239
4240 /** Constructor
4241 *
4242 * @param context CTS context
4243 **/
FunctionalTest6(deqp::Context & context)4244 FunctionalTest6::FunctionalTest6(deqp::Context& context)
4245 : TestCase(context, "static_subroutine_call", "Verify that subroutine can be called in a static manner")
4246 {
4247 }
4248
4249 /** Execute test
4250 *
4251 * @return tcu::TestNode::STOP
4252 **/
iterate()4253 tcu::TestNode::IterateResult FunctionalTest6::iterate()
4254 {
4255 static const GLchar* vertex_shader_code = "#version 400 core\n"
4256 "#extension GL_ARB_shader_subroutine : require\n"
4257 "\n"
4258 "precision highp float;\n"
4259 "\n"
4260 "// Subroutine type\n"
4261 "subroutine vec4 routine_type(in vec4 iparam);\n"
4262 "\n"
4263 "// Subroutine definition\n"
4264 "subroutine(routine_type) vec4 square(in vec4 iparam)\n"
4265 "{\n"
4266 " return iparam * iparam;\n"
4267 "}\n"
4268 "\n"
4269 "// Sub routine uniform\n"
4270 "subroutine uniform routine_type routine;\n"
4271 "\n"
4272 "// Input data\n"
4273 "uniform vec4 input_data;\n"
4274 "\n"
4275 "// Output\n"
4276 "out vec4 out_result;\n"
4277 "\n"
4278 "void main()\n"
4279 "{\n"
4280 " out_result = square(input_data);\n"
4281 "}\n"
4282 "\n";
4283
4284 static const GLchar* varying_name = "out_result";
4285
4286 /* Test data */
4287 static const Utils::vec4<GLfloat> input_data(1.0f, 4.0f, 9.0f, 16.0f);
4288
4289 static const Utils::vec4<GLfloat> expected_result(1.0f, 16.0f, 81.0f, 256.0f);
4290
4291 static const GLuint transform_feedback_buffer_size = 4 * sizeof(GLfloat);
4292
4293 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
4294 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
4295 {
4296 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
4297 }
4298
4299 /* GL objects */
4300 Utils::program program(m_context);
4301 Utils::buffer transform_feedback_buffer(m_context);
4302 Utils::vertexArray vao(m_context);
4303
4304 /* Init GL objects */
4305 program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code, &varying_name,
4306 1 /* n_varyings */);
4307
4308 program.use();
4309
4310 vao.generate();
4311 vao.bind();
4312
4313 transform_feedback_buffer.generate();
4314 transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
4315 GL_DYNAMIC_COPY);
4316 transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
4317
4318 /* Test */
4319 {
4320 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
4321 const GLint uniform_location = gl.getUniformLocation(program.m_program_object_id, "input_data");
4322
4323 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation");
4324
4325 if (-1 == uniform_location)
4326 {
4327 TCU_FAIL("Uniform is not available");
4328 }
4329
4330 /* Set up input data uniforms */
4331 gl.uniform4f(uniform_location, input_data.m_x, input_data.m_y, input_data.m_z, input_data.m_w);
4332 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
4333
4334 /* Execute draw call with transform feedback */
4335 gl.beginTransformFeedback(GL_POINTS);
4336 GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
4337
4338 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
4339 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
4340
4341 gl.endTransformFeedback();
4342 GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
4343
4344 /* Capture results */
4345 GLfloat* feedback_data = (GLfloat*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
4346 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
4347
4348 Utils::vec4<GLfloat> result(feedback_data[0], feedback_data[1], feedback_data[2], feedback_data[3]);
4349
4350 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
4351 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
4352
4353 /* Verify */
4354 if (expected_result == result)
4355 {
4356 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4357 }
4358 else
4359 {
4360 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error. Invalid result."
4361 << tcu::TestLog::EndMessage;
4362
4363 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4364
4365 message << "Function: square( ";
4366 input_data.log(message);
4367 message << " ). Result: ";
4368 result.log(message);
4369 message << ". Expected: ";
4370 expected_result.log(message);
4371
4372 message << tcu::TestLog::EndMessage;
4373
4374 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
4375 }
4376 }
4377
4378 /* Done */
4379 return tcu::TestNode::STOP;
4380 }
4381
4382 /** Constructor
4383 *
4384 * @param context CTS context
4385 **/
FunctionalTest7_8(deqp::Context & context)4386 FunctionalTest7_8::FunctionalTest7_8(deqp::Context& context)
4387 : TestCase(context, "arrayed_subroutine_uniforms", "Verify that subroutine can be called in a static manner")
4388 {
4389 }
4390
4391 /** Execute test
4392 *
4393 * @return tcu::TestNode::STOP
4394 **/
iterate()4395 tcu::TestNode::IterateResult FunctionalTest7_8::iterate()
4396 {
4397 static const GLchar* vertex_shader_code =
4398 "#version 400 core\n"
4399 "#extension GL_ARB_shader_subroutine : require\n"
4400 "\n"
4401 "precision highp float;\n"
4402 "\n"
4403 "// Subroutine type\n"
4404 "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n"
4405 "\n"
4406 "// Subroutine definitions\n"
4407 "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n"
4408 "{\n"
4409 " return left + right;\n"
4410 "}\n"
4411 "\n"
4412 "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n"
4413 "{\n"
4414 " return left * right;\n"
4415 "}\n"
4416 "\n"
4417 "// Sub routine uniform\n"
4418 "subroutine uniform routine_type routine[4];\n"
4419 "\n"
4420 "// Input data\n"
4421 "uniform vec4 uni_left;\n"
4422 "uniform vec4 uni_right;\n"
4423 "uniform uvec4 uni_indices;\n"
4424 "\n"
4425 "// Output\n"
4426 "out vec4 out_combined;\n"
4427 "out vec4 out_combined_inverted;\n"
4428 "out vec4 out_constant;\n"
4429 "out vec4 out_constant_inverted;\n"
4430 "out vec4 out_dynamic;\n"
4431 "out vec4 out_dynamic_inverted;\n"
4432 "out vec4 out_loop;\n"
4433 "out uint out_array_length;\n"
4434 "\n"
4435 "void main()\n"
4436 "{\n"
4437 " out_combined = routine[3](routine[2](routine[1](routine[0](uni_left, uni_right), uni_right), "
4438 "uni_right), uni_right);\n"
4439 " out_combined_inverted = routine[0](routine[1](routine[2](routine[3](uni_left, uni_right), uni_right), "
4440 "uni_right), uni_right);\n"
4441 " \n"
4442 " out_constant = routine[3](routine[2](routine[1](routine[0](vec4(1, 2, 3, 4), vec4(-5, -6, -7, "
4443 "-8)), vec4(-1, -2, -3, -4)), vec4(5, 6, 7, 8)), vec4(1, 2, 3, 4));\n"
4444 " out_constant_inverted = routine[0](routine[1](routine[2](routine[3](vec4(1, 2, 3, 4), vec4(-5, -6, -7, "
4445 "-8)), vec4(-1, -2, -3, -4)), vec4(5, 6, 7, 8)), vec4(1, 2, 3, 4));\n"
4446 " \n"
4447 " out_dynamic = "
4448 "routine[uni_indices.w](routine[uni_indices.z](routine[uni_indices.y](routine[uni_indices.x](uni_left, "
4449 "uni_right), uni_right), uni_right), uni_right);\n"
4450 " out_dynamic_inverted = "
4451 "routine[uni_indices.x](routine[uni_indices.y](routine[uni_indices.z](routine[uni_indices.w](uni_left, "
4452 "uni_right), uni_right), uni_right), uni_right);\n"
4453 " \n"
4454 " out_loop = uni_left;\n"
4455 " for (uint i = 0u; i < routine.length(); ++i)\n"
4456 " {\n"
4457 " out_loop = routine[i](out_loop, uni_right);\n"
4458 " }\n"
4459 " \n"
4460 " out_array_length = routine.length() + 6 - (uni_indices.x + uni_indices.y + uni_indices.z + "
4461 "uni_indices.w);\n"
4462 "}\n"
4463 "\n";
4464
4465 static const GLchar* subroutine_names[] = {
4466 "add", "multiply",
4467 };
4468 static const GLuint n_subroutine_names = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
4469
4470 static const GLchar* subroutine_uniform_names[] = { "routine[0]", "routine[1]", "routine[2]", "routine[3]" };
4471 static const GLuint n_subroutine_uniform_names =
4472 sizeof(subroutine_uniform_names) / sizeof(subroutine_uniform_names[0]);
4473
4474 static const GLchar* uniform_names[] = {
4475 "uni_left", "uni_right", "uni_indices",
4476 };
4477 static const GLuint n_uniform_names = sizeof(uniform_names) / sizeof(uniform_names[0]);
4478
4479 static const GLchar* varying_names[] = { "out_combined", "out_combined_inverted",
4480 "out_constant", "out_constant_inverted",
4481 "out_dynamic", "out_dynamic_inverted",
4482 "out_loop", "out_array_length" };
4483
4484 static const GLuint n_varyings = sizeof(varying_names) / sizeof(varying_names[0]);
4485 static const GLuint transform_feedback_buffer_size = n_varyings * 4 * sizeof(GLfloat);
4486
4487 /* Test data */
4488 static const Utils::vec4<GLfloat> uni_left(-1.0f, 0.75f, -0.5f, 0.25f);
4489 static const Utils::vec4<GLfloat> uni_right(1.0f, -0.75f, 0.5f, -0.25f);
4490 static const Utils::vec4<GLuint> uni_indices(1, 2, 0, 3);
4491
4492 static const GLuint subroutine_combinations[][4] = {
4493 { 0, 0, 0, 0 }, /* + + + + */
4494 { 0, 0, 0, 1 }, /* + + + * */
4495 { 0, 0, 1, 0 }, /* + + * + */
4496 { 0, 0, 1, 1 }, /* + + * * */
4497 { 0, 1, 0, 0 }, /* + * + + */
4498 { 0, 1, 0, 1 }, /* + * + * */
4499 { 0, 1, 1, 0 }, /* + * * + */
4500 { 0, 1, 1, 1 }, /* + * * * */
4501 { 1, 0, 0, 0 }, /* * + + + */
4502 { 1, 0, 0, 1 }, /* * + + * */
4503 { 1, 0, 1, 0 }, /* * + * + */
4504 { 1, 0, 1, 1 }, /* * + * * */
4505 { 1, 1, 0, 0 }, /* * * + + */
4506 { 1, 1, 0, 1 }, /* * * + * */
4507 { 1, 1, 1, 0 }, /* * * * + */
4508 { 1, 1, 1, 1 } /* * * * * */
4509 };
4510 static const GLuint n_subroutine_combinations =
4511 sizeof(subroutine_combinations) / sizeof(subroutine_combinations[0]);
4512
4513 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
4514 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
4515 {
4516 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
4517 }
4518
4519 /* GL objects */
4520 Utils::program program(m_context);
4521 Utils::buffer transform_feedback_buffer(m_context);
4522 Utils::vertexArray vao(m_context);
4523
4524 bool result = true;
4525
4526 /* Init GL objects */
4527 program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code, varying_names,
4528 n_varyings);
4529
4530 program.use();
4531
4532 vao.generate();
4533 vao.bind();
4534
4535 transform_feedback_buffer.generate();
4536
4537 /* Get subroutine indices */
4538 for (GLuint routine = 0; routine < n_subroutine_names; ++routine)
4539 {
4540 m_subroutine_indices[routine] = program.getSubroutineIndex(subroutine_names[routine], GL_VERTEX_SHADER);
4541 }
4542
4543 /* Get subroutine uniform locations */
4544 for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
4545 {
4546 m_subroutine_uniform_locations[uniform] =
4547 program.getSubroutineUniformLocation(subroutine_uniform_names[uniform], GL_VERTEX_SHADER);
4548 }
4549
4550 /* Get uniform locations */
4551 for (GLuint i = 0; i < n_uniform_names; ++i)
4552 {
4553 m_uniform_locations[i] = program.getUniformLocation(uniform_names[i]);
4554 }
4555
4556 /* Test */
4557 for (GLuint i = 0; i < n_subroutine_combinations; ++i)
4558 {
4559 /* Clean */
4560 transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
4561 GL_DYNAMIC_COPY);
4562 transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
4563
4564 /* Verify */
4565 if (false == testDraw(subroutine_combinations[i], uni_left, uni_right, uni_indices))
4566 {
4567 result = false;
4568 }
4569 }
4570
4571 if (true == result)
4572 {
4573 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4574 }
4575 else
4576 {
4577 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
4578 }
4579
4580 /* Done */
4581 return tcu::TestNode::STOP;
4582 }
4583
4584 /* Calculate result of function applied to operands
4585 *
4586 * @param function Function id, 0 is sum, 1 is multiplication
4587 * @param left Left operand
4588 * @param right Right operand
4589 * @param out Function result
4590 **/
calculate(glw::GLuint function,const Utils::vec4<glw::GLfloat> & left,const Utils::vec4<glw::GLfloat> & right,Utils::vec4<glw::GLfloat> & out) const4591 void FunctionalTest7_8::calculate(glw::GLuint function, const Utils::vec4<glw::GLfloat>& left,
4592 const Utils::vec4<glw::GLfloat>& right, Utils::vec4<glw::GLfloat>& out) const
4593 {
4594 if (0 == function)
4595 {
4596 out.m_x = left.m_x + right.m_x;
4597 out.m_y = left.m_y + right.m_y;
4598 out.m_z = left.m_z + right.m_z;
4599 out.m_w = left.m_w + right.m_w;
4600 }
4601 else
4602 {
4603 out.m_x = left.m_x * right.m_x;
4604 out.m_y = left.m_y * right.m_y;
4605 out.m_z = left.m_z * right.m_z;
4606 out.m_w = left.m_w * right.m_w;
4607 }
4608 }
4609
4610 /** Calculate expected values for all operations
4611 *
4612 * @param combination Function combination, first applied function is at index [0]
4613 * @param left Left operand
4614 * @param right Right operand
4615 * @param indices Indices used by dynamic calls
4616 * @param out_combined Expected result of "combined" operation
4617 * @param out_combined_inverted Expected result of "combined_inverted" operation
4618 * @param out_constant Expected result of "constant" operation
4619 * @param out_constant_inverted Expected result of "constant_inverted" operation
4620 * @param out_dynamic Expected result of "dynamic" operation
4621 * @param out_dynamic_inverted Expected result of "out_dynamic_inverted" operation
4622 * @param out_loop Expected result of "loop" operation
4623 **/
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) const4624 void FunctionalTest7_8::calculate(
4625 const glw::GLuint combination[4], const Utils::vec4<glw::GLfloat>& left, const Utils::vec4<glw::GLfloat>& right,
4626 const Utils::vec4<glw::GLuint>& indices, Utils::vec4<glw::GLfloat>& out_combined,
4627 Utils::vec4<glw::GLfloat>& out_combined_inverted, Utils::vec4<glw::GLfloat>& out_constant,
4628 Utils::vec4<glw::GLfloat>& out_constant_inverted, Utils::vec4<glw::GLfloat>& out_dynamic,
4629 Utils::vec4<glw::GLfloat>& out_dynamic_inverted, Utils::vec4<glw::GLfloat>& out_loop) const
4630 {
4631 /* Indices used by "dynamic" operations, range <0..4> */
4632 const GLuint dynamic_combination[4] = { combination[indices.m_x], combination[indices.m_y],
4633 combination[indices.m_z], combination[indices.m_w] };
4634
4635 /* Values used by "constant" operations, come from shader code */
4636 const Utils::vec4<glw::GLfloat> constant_values[] = { Utils::vec4<glw::GLfloat>(1, 2, 3, 4),
4637 Utils::vec4<glw::GLfloat>(-5, -6, -7, -8),
4638 Utils::vec4<glw::GLfloat>(-1, -2, -3, -4),
4639 Utils::vec4<glw::GLfloat>(5, 6, 7, 8),
4640 Utils::vec4<glw::GLfloat>(1, 2, 3, 4) };
4641
4642 /* Start values */
4643 Utils::vec4<glw::GLfloat> combined = left;
4644 Utils::vec4<glw::GLfloat> combined_inverted = left;
4645 Utils::vec4<glw::GLfloat> constant = constant_values[0];
4646 Utils::vec4<glw::GLfloat> constant_inverted = constant_values[0];
4647 Utils::vec4<glw::GLfloat> dynamic = left;
4648 Utils::vec4<glw::GLfloat> dynamic_inverted = left;
4649
4650 /* Calculate expected results */
4651 for (GLuint i = 0; i < 4; ++i)
4652 {
4653 GLuint function = combination[i];
4654 GLuint function_inverted = combination[3 - i];
4655 GLuint dynamic_function = dynamic_combination[i];
4656 GLuint dynamic_function_inverted = dynamic_combination[3 - i];
4657
4658 calculate(function, combined, right, combined);
4659 calculate(function_inverted, combined_inverted, right, combined_inverted);
4660 calculate(function, constant, constant_values[i + 1], constant);
4661 calculate(function_inverted, constant_inverted, constant_values[i + 1], constant_inverted);
4662 calculate(dynamic_function, dynamic, right, dynamic);
4663 calculate(dynamic_function_inverted, dynamic_inverted, right, dynamic_inverted);
4664 }
4665
4666 /* Store results */
4667 out_combined = combined;
4668 out_combined_inverted = combined_inverted;
4669 out_constant = constant;
4670 out_constant_inverted = constant_inverted;
4671 out_dynamic = dynamic;
4672 out_dynamic_inverted = dynamic_inverted;
4673 out_loop = combined;
4674 }
4675
4676 /** Log error
4677 *
4678 * @param combination Operations combination
4679 * @param left Left operand
4680 * @param right Right operand
4681 * @param indices Inidices used by "dynamic" calls
4682 * @param vec4_expected Expected results
4683 * @param vec4_result Results
4684 * @param array_length Length of array
4685 * @param result Comparison results
4686 **/
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]) const4687 void FunctionalTest7_8::logError(const glw::GLuint combination[4], const Utils::vec4<glw::GLfloat>& left,
4688 const Utils::vec4<glw::GLfloat>& right, const Utils::vec4<glw::GLuint>& indices,
4689 const Utils::vec4<glw::GLfloat> vec4_expected[7],
4690 const Utils::vec4<glw::GLfloat> vec4_result[7], glw::GLuint array_length,
4691 bool result[7]) const
4692 {
4693 static const GLuint n_functions = 4;
4694 static const GLuint n_operations = 7;
4695
4696 /* Indices used by "dynamic" operations, range <0..4> */
4697 const GLuint dynamic_combination[4] = { combination[indices.m_x], combination[indices.m_y],
4698 combination[indices.m_z], combination[indices.m_w] };
4699
4700 /* Function symbols */
4701 GLchar functions[4];
4702 GLchar functions_inverted[4];
4703 GLchar functions_dynamic[4];
4704 GLchar functions_dynamic_inverted[4];
4705
4706 for (GLuint i = 0; i < n_functions; ++i)
4707 {
4708 GLchar function = (0 == combination[i]) ? '+' : '*';
4709 GLchar dynamic_function = (0 == dynamic_combination[i]) ? '+' : '*';
4710
4711 functions[i] = function;
4712 functions_inverted[n_functions - i - 1] = function;
4713 functions_dynamic[i] = dynamic_function;
4714 functions_dynamic_inverted[n_functions - i - 1] = dynamic_function;
4715 }
4716
4717 /* Values used by "constant" operations, come from shader code */
4718 const Utils::vec4<glw::GLfloat> constant_values[] = { Utils::vec4<glw::GLfloat>(1, 2, 3, 4),
4719 Utils::vec4<glw::GLfloat>(-5, -6, -7, -8),
4720 Utils::vec4<glw::GLfloat>(-1, -2, -3, -4),
4721 Utils::vec4<glw::GLfloat>(5, 6, 7, 8),
4722 Utils::vec4<glw::GLfloat>(1, 2, 3, 4) };
4723
4724 /* Values used by non-"constant" operations */
4725 Utils::vec4<glw::GLfloat> dynamic_values[5];
4726 dynamic_values[0] = left;
4727 dynamic_values[1] = right;
4728 dynamic_values[2] = right;
4729 dynamic_values[3] = right;
4730 dynamic_values[4] = right;
4731
4732 /* For each operation */
4733 for (GLuint i = 0; i < n_operations; ++i)
4734 {
4735 /* If result is failure */
4736 if (false == result[i])
4737 {
4738 const GLchar* description = 0;
4739 const Utils::vec4<glw::GLfloat>* input = 0;
4740 const GLchar* operation = 0;
4741
4742 switch (i)
4743 {
4744 case 0:
4745 description = "Call made with predefined array indices";
4746 input = dynamic_values;
4747 operation = functions;
4748 break;
4749 case 1:
4750 description = "Call made with predefined array indices in inverted order";
4751 input = dynamic_values;
4752 operation = functions_inverted;
4753 break;
4754 case 2:
4755 description = "Call made with predefined array indices, for constant values";
4756 input = constant_values;
4757 operation = functions;
4758 break;
4759 case 3:
4760 description = "Call made with predefined array indices in inverted order, for constant values";
4761 input = constant_values;
4762 operation = functions_inverted;
4763 break;
4764 case 4:
4765 description = "Call made with dynamic array indices";
4766 input = dynamic_values;
4767 operation = functions_dynamic;
4768 break;
4769 case 5:
4770 description = "Call made with dynamic array indices in inverted order";
4771 input = dynamic_values;
4772 operation = functions_dynamic_inverted;
4773 break;
4774 case 6:
4775 description = "Call made with loop";
4776 input = dynamic_values;
4777 operation = functions;
4778 break;
4779 }
4780
4781 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error. Invalid result."
4782 << tcu::TestLog::EndMessage;
4783
4784 m_context.getTestContext().getLog() << tcu::TestLog::Message << description << tcu::TestLog::EndMessage;
4785
4786 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4787
4788 message << "Operation: ((((";
4789 input[0].log(message);
4790 for (GLuint function = 0; function < n_functions; ++function)
4791 {
4792 message << " " << operation[function] << " ";
4793
4794 input[function + 1].log(message);
4795
4796 message << ")";
4797 }
4798
4799 message << tcu::TestLog::EndMessage;
4800
4801 message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4802
4803 message << "Result: ";
4804 vec4_result[i].log(message);
4805
4806 message << tcu::TestLog::EndMessage;
4807
4808 message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4809
4810 message << "Expected: ";
4811 vec4_expected[i].log(message);
4812
4813 message << tcu::TestLog::EndMessage;
4814 }
4815
4816 /* Check array length, it should be 4 */
4817 if (4 != array_length)
4818 {
4819 m_context.getTestContext().getLog() << tcu::TestLog::Message
4820 << "Error. Invalid array length: " << array_length << ". Expected 4."
4821 << tcu::TestLog::EndMessage;
4822 }
4823 }
4824 }
4825
4826 /** Execute draw call and verifies captrued varyings
4827 *
4828 * @param combination Function combination, first applied function is at index [0]
4829 * @param left Left operand
4830 * @param right Right operand
4831 * @param indices Indices used by dynamic calls
4832 *
4833 * @return true if all results match expected values, false otherwise
4834 **/
testDraw(const glw::GLuint combination[4],const Utils::vec4<glw::GLfloat> & left,const Utils::vec4<glw::GLfloat> & right,const Utils::vec4<glw::GLuint> & indices) const4835 bool FunctionalTest7_8::testDraw(const glw::GLuint combination[4], const Utils::vec4<glw::GLfloat>& left,
4836 const Utils::vec4<glw::GLfloat>& right, const Utils::vec4<glw::GLuint>& indices) const
4837 {
4838 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
4839 static const GLuint n_vec4_varyings = 7;
4840 bool result = true;
4841 GLuint subroutine_indices[4];
4842 static const GLuint n_subroutine_uniforms = sizeof(subroutine_indices) / sizeof(subroutine_indices[0]);
4843
4844 /* Prepare expected results */
4845 Utils::vec4<glw::GLfloat> expected_results[7];
4846 calculate(combination, left, right, indices, expected_results[0], expected_results[1], expected_results[2],
4847 expected_results[3], expected_results[4], expected_results[5], expected_results[6]);
4848
4849 /* Set up input data uniforms */
4850 gl.uniform4f(m_uniform_locations[0], left.m_x, left.m_y, left.m_z, left.m_w);
4851 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
4852
4853 gl.uniform4f(m_uniform_locations[1], right.m_x, right.m_y, right.m_z, right.m_w);
4854 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
4855
4856 gl.uniform4ui(m_uniform_locations[2], indices.m_x, indices.m_y, indices.m_z, indices.m_w);
4857 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4ui");
4858
4859 /* Prepare subroutine uniform data */
4860 for (GLuint i = 0; i < n_subroutine_uniforms; ++i)
4861 {
4862 const GLuint location = m_subroutine_uniform_locations[i];
4863
4864 subroutine_indices[location] = m_subroutine_indices[combination[i]];
4865 }
4866
4867 /* Set up subroutine uniforms */
4868 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, n_subroutine_uniforms, &subroutine_indices[0]);
4869 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
4870
4871 /* Execute draw call with transform feedback */
4872 gl.beginTransformFeedback(GL_POINTS);
4873 GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
4874
4875 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
4876 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
4877
4878 gl.endTransformFeedback();
4879 GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
4880
4881 /* Capture results */
4882 GLvoid* feedback_data = (GLvoid*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
4883 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
4884
4885 Utils::vec4<GLfloat> vec4_results[7];
4886 bool results[7];
4887 GLfloat* float_data = (GLfloat*)feedback_data;
4888 for (GLuint i = 0; i < n_vec4_varyings; ++i)
4889 {
4890 vec4_results[i].m_x = float_data[i * 4 + 0];
4891 vec4_results[i].m_y = float_data[i * 4 + 1];
4892 vec4_results[i].m_z = float_data[i * 4 + 2];
4893 vec4_results[i].m_w = float_data[i * 4 + 3];
4894 }
4895
4896 GLuint* uint_data = (GLuint*)(float_data + (n_vec4_varyings)*4);
4897 GLuint array_length = uint_data[0];
4898
4899 /* Unmap buffer */
4900 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
4901 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
4902
4903 /* Verification */
4904 for (GLuint i = 0; i < n_vec4_varyings; ++i)
4905 {
4906 results[i] = (vec4_results[i] == expected_results[i]);
4907 result = result && results[i];
4908 }
4909
4910 result = result && (4 == array_length);
4911
4912 /* Log error if any */
4913 if (false == result)
4914 {
4915 logError(combination, left, right, indices, expected_results, vec4_results, array_length, results);
4916 }
4917
4918 /* Done */
4919 return result;
4920 }
4921
4922 /** Constructor.
4923 *
4924 * @param context Rendering context.
4925 *
4926 **/
FunctionalTest9(deqp::Context & context)4927 FunctionalTest9::FunctionalTest9(deqp::Context& context)
4928 : TestCase(context, "subroutines_3_subroutine_types_and_subroutine_uniforms_one_function",
4929 "Makes sure that program with one function associated with 3 different "
4930 "subroutine types and 3 subroutine uniforms using that function compiles "
4931 "and works as expected")
4932 , m_has_test_passed(true)
4933 , m_n_points_to_draw(16) /* arbitrary value */
4934 , m_po_id(0)
4935 , m_vao_id(0)
4936 , m_vs_id(0)
4937 , m_xfb_bo_id(0)
4938 {
4939 /* Left blank intentionally */
4940 }
4941
4942 /** De-initializes GL objects that may have been created during test execution. */
deinit()4943 void FunctionalTest9::deinit()
4944 {
4945 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
4946
4947 if (m_po_id != 0)
4948 {
4949 gl.deleteProgram(m_po_id);
4950
4951 m_po_id = 0;
4952 }
4953
4954 if (m_vao_id != 0)
4955 {
4956 gl.deleteVertexArrays(1, &m_vao_id);
4957
4958 m_vao_id = 0;
4959 }
4960
4961 if (m_vs_id != 0)
4962 {
4963 gl.deleteShader(m_vs_id);
4964
4965 m_vs_id = 0;
4966 }
4967
4968 if (m_xfb_bo_id != 0)
4969 {
4970 gl.deleteBuffers(1, &m_xfb_bo_id);
4971
4972 m_xfb_bo_id = 0;
4973 }
4974 }
4975
4976 /** Retrieves body of a vertex shader that should be used
4977 * for the testing purposes.
4978 **/
getVertexShaderBody() const4979 std::string FunctionalTest9::getVertexShaderBody() const
4980 {
4981 return "#version 400\n"
4982 "\n"
4983 "#extension GL_ARB_shader_subroutine : require\n"
4984 "\n"
4985 "subroutine void subroutineType1(inout float);\n"
4986 "subroutine void subroutineType2(inout float);\n"
4987 "subroutine void subroutineType3(inout float);\n"
4988 "\n"
4989 "subroutine(subroutineType1, subroutineType2, subroutineType3) void function(inout float result)\n"
4990 "{\n"
4991 " result += float(0.123) + float(gl_VertexID);\n"
4992 "}\n"
4993 "\n"
4994 "subroutine uniform subroutineType1 subroutine_uniform1;\n"
4995 "subroutine uniform subroutineType2 subroutine_uniform2;\n"
4996 "subroutine uniform subroutineType3 subroutine_uniform3;\n"
4997 "\n"
4998 "out vec4 result;\n"
4999 "\n"
5000 "void main()\n"
5001 "{\n"
5002 " result = vec4(0, 1, 2, 3);\n"
5003 "\n"
5004 " subroutine_uniform1(result.x);\n"
5005 " subroutine_uniform2(result.y);\n"
5006 " subroutine_uniform3(result.z);\n"
5007 "\n"
5008 " result.w += result.x + result.y + result.z;\n"
5009 "}\n";
5010 }
5011
5012 /** Initializes all GL objects required to run the test. */
initTest()5013 void FunctionalTest9::initTest()
5014 {
5015 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
5016
5017 /* Set up program object */
5018 const char* xfb_varyings[] = { "result" };
5019
5020 const unsigned int n_xfb_varyings = sizeof(xfb_varyings) / sizeof(xfb_varyings[0]);
5021 if (!Utils::buildProgram(gl, getVertexShaderBody(), "", /* tc_body */
5022 "", /* te_body */
5023 "", /* gs_body */
5024 "", /* fs_body */
5025 xfb_varyings, n_xfb_varyings, &m_vs_id, DE_NULL, /* out_tc_id */
5026 DE_NULL, /* out_te_id */
5027 DE_NULL, /* out_gs_id */
5028 DE_NULL, /* out_fs_id */
5029 &m_po_id))
5030 {
5031 TCU_FAIL("Program failed to link successfully");
5032 }
5033
5034 /* Set up a buffer object we will use to hold XFB data */
5035 const unsigned int xfb_bo_size = static_cast<unsigned int>(sizeof(float) * 4 /* components */ * m_n_points_to_draw);
5036
5037 gl.genBuffers(1, &m_xfb_bo_id);
5038 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
5039
5040 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_xfb_bo_id);
5041 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
5042
5043 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_xfb_bo_id);
5044 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed.");
5045
5046 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_bo_size, DE_NULL, /* data */
5047 GL_STATIC_COPY);
5048 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
5049
5050 /* Generate & bind a VAO */
5051 gl.genVertexArrays(1, &m_vao_id);
5052 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
5053
5054 gl.bindVertexArray(m_vao_id);
5055 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
5056 }
5057
5058 /** Executes test iteration.
5059 *
5060 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
5061 */
iterate()5062 tcu::TestNode::IterateResult FunctionalTest9::iterate()
5063 {
5064 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
5065
5066 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
5067 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
5068 {
5069 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
5070 }
5071 initTest();
5072
5073 /* Issue a draw call to make use of the three subroutine uniforms that we've defined */
5074 gl.useProgram(m_po_id);
5075 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
5076
5077 gl.beginTransformFeedback(GL_POINTS);
5078 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed.");
5079 {
5080 gl.drawArrays(GL_POINTS, 0 /* first */, m_n_points_to_draw);
5081 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
5082 }
5083 gl.endTransformFeedback();
5084 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed.");
5085
5086 /* Map the XFB BO storage into process space */
5087 const glw::GLvoid* xfb_data_ptr = gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
5088 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer() call failed.");
5089
5090 verifyXFBData(xfb_data_ptr);
5091
5092 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
5093 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
5094
5095 /* All done */
5096 if (m_has_test_passed)
5097 {
5098 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5099 }
5100 else
5101 {
5102 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
5103 }
5104
5105 return STOP;
5106 }
5107
5108 /** Verifies the data XFBed out by the vertex shader. Should the data
5109 * be found invalid, m_has_test_passed will be set to false.
5110 *
5111 * @param data_ptr XFB data.
5112 **/
verifyXFBData(const glw::GLvoid * data_ptr)5113 void FunctionalTest9::verifyXFBData(const glw::GLvoid* data_ptr)
5114 {
5115 const float epsilon = 1e-5f;
5116 bool should_continue = true;
5117 const glw::GLfloat* traveller_ptr = (const glw::GLfloat*)data_ptr;
5118
5119 for (unsigned int n_point = 0; n_point < m_n_points_to_draw && should_continue; ++n_point)
5120 {
5121 tcu::Vec4 expected_result(0, 1, 2, 3);
5122
5123 for (unsigned int n_component = 0; n_component < 3 /* xyz */; ++n_component)
5124 {
5125 expected_result[n_component] += 0.123f + float(n_point);
5126 }
5127
5128 expected_result[3 /* w */] += expected_result[0] + expected_result[1] + expected_result[2];
5129
5130 if (de::abs(expected_result[0] - traveller_ptr[0]) > epsilon ||
5131 de::abs(expected_result[1] - traveller_ptr[1]) > epsilon ||
5132 de::abs(expected_result[2] - traveller_ptr[2]) > epsilon ||
5133 de::abs(expected_result[3] - traveller_ptr[3]) > epsilon)
5134 {
5135 m_testCtx.getLog() << tcu::TestLog::Message << "XFBed data is invalid. Expected:"
5136 "("
5137 << expected_result[0] << ", " << expected_result[1] << ", " << expected_result[2] << ", "
5138 << expected_result[3] << "), found:(" << traveller_ptr[0] << ", " << traveller_ptr[1]
5139 << ", " << traveller_ptr[2] << ", " << traveller_ptr[3] << ")."
5140 << tcu::TestLog::EndMessage;
5141
5142 m_has_test_passed = false;
5143 should_continue = false;
5144 }
5145
5146 traveller_ptr += 4; /* xyzw */
5147 } /* for (all rendered points) */
5148 }
5149
5150 /** Constructor
5151 *
5152 * @param context CTS context
5153 **/
FunctionalTest10(deqp::Context & context)5154 FunctionalTest10::FunctionalTest10(deqp::Context& context)
5155 : TestCase(context, "arrays_of_arrays_of_uniforms", "Verify that arrays of arrays of uniforms works as expected")
5156 {
5157 }
5158
5159 /** Execute test
5160 *
5161 * @return tcu::TestNode::STOP
5162 **/
iterate()5163 tcu::TestNode::IterateResult FunctionalTest10::iterate()
5164 {
5165 static const GLchar* vertex_shader_code = "#version 400 core\n"
5166 "#extension GL_ARB_arrays_of_arrays : require\n"
5167 "#extension GL_ARB_shader_subroutine : require\n"
5168 "\n"
5169 "precision highp float;\n"
5170 "\n"
5171 "// Subroutine type\n"
5172 "subroutine int routine_type(in int iparam);\n"
5173 "\n"
5174 "// Subroutine definitions\n"
5175 "subroutine(routine_type) int increment(in int iparam)\n"
5176 "{\n"
5177 " return iparam + 1;\n"
5178 "}\n"
5179 "\n"
5180 "subroutine(routine_type) int decrement(in int iparam)\n"
5181 "{\n"
5182 " return iparam - 1;\n"
5183 "}\n"
5184 "\n"
5185 "// Sub routine uniform\n"
5186 "subroutine uniform routine_type routine[4][4];\n"
5187 "\n"
5188 "// Output\n"
5189 "out int out_result;\n"
5190 "\n"
5191 "void main()\n"
5192 "{\n"
5193 " int result = 0;\n"
5194 " \n"
5195 " for (uint j = 0; j < routine.length(); ++j)\n"
5196 " {\n"
5197 " for (uint i = 0; i < routine[j].length(); ++i)\n"
5198 " {\n"
5199 " result = routine[j][i](result);\n"
5200 " }\n"
5201 " }\n"
5202 " \n"
5203 " out_result = result;\n"
5204 "}\n"
5205 "\n";
5206
5207 static const GLchar* subroutine_names[] = {
5208 "increment", "decrement",
5209 };
5210 static const GLuint n_subroutine_names = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
5211
5212 static const GLchar* subroutine_uniform_names[] = {
5213 "routine[0][0]", "routine[1][0]", "routine[2][0]", "routine[3][0]", "routine[0][1]", "routine[1][1]",
5214 "routine[2][1]", "routine[3][1]", "routine[0][2]", "routine[1][2]", "routine[2][2]", "routine[3][2]",
5215 "routine[0][3]", "routine[1][3]", "routine[2][3]", "routine[3][3]"
5216 };
5217 static const GLuint n_subroutine_uniform_names =
5218 sizeof(subroutine_uniform_names) / sizeof(subroutine_uniform_names[0]);
5219
5220 static const GLchar* varying_name = "out_result";
5221 static const GLuint transform_feedback_buffer_size = sizeof(GLint);
5222
5223 static const GLuint configuration_increment[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
5224
5225 static const GLuint configuration_decrement[16] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
5226
5227 static const GLuint configuration_mix[16] = { 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1 };
5228
5229 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
5230 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
5231 {
5232 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
5233 }
5234
5235 /* Do not execute the test if GL_ARB_arrays_of_arrays is not supported */
5236 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_arrays_of_arrays"))
5237 {
5238 throw tcu::NotSupportedError("GL_ARB_arrays_of_arrays is not supported.");
5239 }
5240
5241 bool result = true;
5242
5243 /* GL objects */
5244 Utils::program program(m_context);
5245 Utils::buffer transform_feedback_buffer(m_context);
5246 Utils::vertexArray vao(m_context);
5247
5248 /* Init GL objects */
5249 program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code, &varying_name,
5250 1 /* n_varyings */);
5251
5252 program.use();
5253
5254 vao.generate();
5255 vao.bind();
5256
5257 transform_feedback_buffer.generate();
5258 transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
5259 GL_DYNAMIC_COPY);
5260 transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
5261
5262 /* Get subroutine indices */
5263 for (GLuint routine = 0; routine < n_subroutine_names; ++routine)
5264 {
5265 m_subroutine_indices[routine] = program.getSubroutineIndex(subroutine_names[routine], GL_VERTEX_SHADER);
5266 }
5267
5268 /* Get subroutine uniform locations */
5269 for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
5270 {
5271 m_subroutine_uniform_locations[uniform] =
5272 program.getSubroutineUniformLocation(subroutine_uniform_names[uniform], GL_VERTEX_SHADER);
5273 }
5274
5275 /* Test */
5276 GLint increment_result = testDraw(configuration_increment);
5277 GLint decrement_result = testDraw(configuration_decrement);
5278 GLint mix_result = testDraw(configuration_mix);
5279
5280 /* Verify */
5281 if (16 != increment_result)
5282 {
5283 result = false;
5284 }
5285
5286 if (-16 != decrement_result)
5287 {
5288 result = false;
5289 }
5290 if (0 != mix_result)
5291 {
5292 result = false;
5293 }
5294
5295 /* Set test result */
5296 if (true == result)
5297 {
5298 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5299 }
5300 else
5301 {
5302 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error. Invalid result."
5303 << " Incrementation applied 16 times: " << increment_result
5304 << ". Decrementation applied 16 times: " << decrement_result
5305 << ". Incrementation and decrementation applied 8 times: " << mix_result
5306 << tcu::TestLog::EndMessage;
5307
5308 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
5309 }
5310
5311 /* Done */
5312 return tcu::TestNode::STOP;
5313 }
5314
5315 /** Execute draw call and return captured varying
5316 *
5317 * @param routine_indices Configuration of subroutine uniforms
5318 *
5319 * @return Value of varying captured with transform feedback
5320 **/
testDraw(const GLuint routine_indices[16]) const5321 GLint FunctionalTest10::testDraw(const GLuint routine_indices[16]) const
5322 {
5323 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
5324 GLuint subroutine_indices[16];
5325 static const GLuint n_subroutine_uniforms = sizeof(subroutine_indices) / sizeof(subroutine_indices[0]);
5326
5327 /* Prepare subroutine uniform data */
5328 for (GLuint i = 0; i < n_subroutine_uniforms; ++i)
5329 {
5330 const GLuint location = m_subroutine_uniform_locations[i];
5331
5332 subroutine_indices[location] = m_subroutine_indices[routine_indices[i]];
5333 }
5334
5335 /* Set up subroutine uniforms */
5336 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, n_subroutine_uniforms, &subroutine_indices[0]);
5337 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
5338
5339 /* Execute draw call with transform feedback */
5340 gl.beginTransformFeedback(GL_POINTS);
5341 GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
5342
5343 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
5344 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
5345
5346 gl.endTransformFeedback();
5347 GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
5348
5349 /* Capture results */
5350 GLint* feedback_data = (GLint*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
5351 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
5352
5353 GLint result = feedback_data[0];
5354
5355 /* Unmap buffer */
5356 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
5357 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
5358
5359 return result;
5360 }
5361
5362 /* Definitions of constants used by FunctionalTest11 */
5363 const GLuint FunctionalTest11::m_texture_height = 32;
5364 const GLuint FunctionalTest11::m_texture_width = 32;
5365
5366 /** Constructor
5367 *
5368 * @param context CTS context
5369 **/
FunctionalTest11(deqp::Context & context)5370 FunctionalTest11::FunctionalTest11(deqp::Context& context)
5371 : TestCase(context, "globals_sampling_output_discard_function_calls", "Verify that global variables, texture "
5372 "sampling, fragment output, fragment discard "
5373 "and function calls work as expected")
5374 {
5375 }
5376
5377 /** Execute test
5378 *
5379 * @return tcu::TestNode::STOP
5380 **/
iterate()5381 tcu::TestNode::IterateResult FunctionalTest11::iterate()
5382 {
5383 static const GLchar* fragment_shader_code =
5384 "#version 400 core\n"
5385 "#extension GL_ARB_shader_subroutine : require\n"
5386 "\n"
5387 "precision highp float;\n"
5388 "\n"
5389 "// Output\n"
5390 "layout(location = 0) out vec4 out_color;\n"
5391 "\n"
5392 "// Global variables\n"
5393 "vec4 success_color;\n"
5394 "vec4 failure_color;\n"
5395 "\n"
5396 "// Samplers\n"
5397 "uniform sampler2D sampler_1;\n"
5398 "uniform sampler2D sampler_2;\n"
5399 "\n"
5400 "// Functions\n"
5401 "bool are_same(in vec4 left, in vec4 right)\n"
5402 "{\n"
5403 " bvec4 result;\n"
5404 "\n"
5405 " result.x = (left.x == right.x);\n"
5406 " result.y = (left.y == right.y);\n"
5407 " result.z = (left.z == right.z);\n"
5408 " result.w = (left.w == right.w);\n"
5409 "\n"
5410 " return all(result);\n"
5411 "}\n"
5412 "\n"
5413 "bool are_different(in vec4 left, in vec4 right)\n"
5414 "{\n"
5415 " bvec4 result;\n"
5416 "\n"
5417 " result.x = (left.x != right.x);\n"
5418 " result.y = (left.y != right.y);\n"
5419 " result.z = (left.z != right.z);\n"
5420 " result.w = (left.w != right.w);\n"
5421 "\n"
5422 " return any(result);\n"
5423 "}\n"
5424 "\n"
5425 "// Subroutine types\n"
5426 "subroutine void discard_fragment_type(void);\n"
5427 "subroutine void set_global_colors_type(void);\n"
5428 "subroutine vec4 sample_texture_type(in vec2);\n"
5429 "subroutine bool comparison_type(in vec4 left, in vec4 right);\n"
5430 "subroutine void test_type(void);\n"
5431 "\n"
5432 "// Subroutine definitions\n"
5433 "// discard_fragment_type\n"
5434 "subroutine(discard_fragment_type) void discard_yes(void)\n"
5435 "{\n"
5436 " discard;\n"
5437 "}\n"
5438 "\n"
5439 "subroutine(discard_fragment_type) void discard_no(void)\n"
5440 "{\n"
5441 "}\n"
5442 "\n"
5443 "// set_global_colors_type\n"
5444 "subroutine(set_global_colors_type) void red_pass_blue_fail(void)\n"
5445 "{\n"
5446 " success_color = vec4(1, 0, 0, 1);\n"
5447 " failure_color = vec4(0, 0, 1, 1);\n"
5448 "}\n"
5449 "\n"
5450 "subroutine(set_global_colors_type) void blue_pass_red_fail(void)\n"
5451 "{\n"
5452 " success_color = vec4(0, 0, 1, 1);\n"
5453 " failure_color = vec4(1, 0, 0, 1);\n"
5454 "}\n"
5455 "\n"
5456 "// sample_texture_type\n"
5457 "subroutine(sample_texture_type) vec4 first_sampler(in vec2 coord)\n"
5458 "{\n"
5459 " return texture(sampler_1, coord);\n"
5460 "}\n"
5461 "\n"
5462 "subroutine(sample_texture_type) vec4 second_sampler(in vec2 coord)\n"
5463 "{\n"
5464 " return texture(sampler_2, coord);\n"
5465 "}\n"
5466 "\n"
5467 "// comparison_type\n"
5468 "subroutine(comparison_type) bool check_equal(in vec4 left, in vec4 right)\n"
5469 "{\n"
5470 " return are_same(left, right);\n"
5471 "}\n"
5472 "\n"
5473 "subroutine(comparison_type) bool check_not_equal(in vec4 left, in vec4 right)\n"
5474 "{\n"
5475 " return are_different(left, right);\n"
5476 "}\n"
5477 "\n"
5478 "// Subroutine uniforms\n"
5479 "subroutine uniform discard_fragment_type discard_fragment;\n"
5480 "subroutine uniform set_global_colors_type set_global_colors;\n"
5481 "subroutine uniform sample_texture_type sample_texture;\n"
5482 "subroutine uniform comparison_type compare;\n"
5483 "\n"
5484 "// Subroutine definitions\n"
5485 "// test_type\n"
5486 "subroutine(test_type) void test_with_discard(void)\n"
5487 "{\n"
5488 " discard_fragment();"
5489 "\n"
5490 " out_color = failure_color;\n"
5491 "\n"
5492 " set_global_colors();\n"
5493 "\n"
5494 " vec4 sampled_color = sample_texture(gl_PointCoord);\n"
5495 "\n"
5496 " bool comparison_result = compare(success_color, sampled_color);\n"
5497 "\n"
5498 " if (true == comparison_result)\n"
5499 " {\n"
5500 " out_color = success_color;\n"
5501 " }\n"
5502 " else\n"
5503 " {\n"
5504 " out_color = failure_color;\n"
5505 " }\n"
5506 "}\n"
5507 "\n"
5508 "subroutine(test_type) void test_without_discard(void)\n"
5509 "{\n"
5510 " set_global_colors();\n"
5511 "\n"
5512 " vec4 sampled_color = sample_texture(gl_PointCoord);\n"
5513 "\n"
5514 " bool comparison_result = compare(success_color, sampled_color);\n"
5515 "\n"
5516 " if (true == comparison_result)\n"
5517 " {\n"
5518 " out_color = success_color;\n"
5519 " }\n"
5520 " else\n"
5521 " {\n"
5522 " out_color = failure_color;\n"
5523 " }\n"
5524 "}\n"
5525 "\n"
5526 "// Subroutine uniforms\n"
5527 "subroutine uniform test_type test;\n"
5528 "\n"
5529 "void main()\n"
5530 "{\n"
5531 " // Set colors\n"
5532 " success_color = vec4(0.5, 0.5, 0.5, 0.5);\n"
5533 " failure_color = vec4(0.5, 0.5, 0.5, 0.5);\n"
5534 "\n"
5535 " test();\n"
5536 "}\n"
5537 "\n";
5538
5539 static const GLchar* geometry_shader_code = "#version 400 core\n"
5540 "#extension GL_ARB_shader_subroutine : require\n"
5541 "\n"
5542 "precision highp float;\n"
5543 "\n"
5544 "layout(points) in;\n"
5545 "layout(triangle_strip, max_vertices = 4) out;\n"
5546 "\n"
5547 "void main()\n"
5548 "{\n"
5549 " gl_Position = vec4(-1, -1, 0, 1);\n"
5550 " EmitVertex();\n"
5551 " \n"
5552 " gl_Position = vec4(-1, 1, 0, 1);\n"
5553 " EmitVertex();\n"
5554 " \n"
5555 " gl_Position = vec4( 1, -1, 0, 1);\n"
5556 " EmitVertex();\n"
5557 " \n"
5558 " gl_Position = vec4( 1, 1, 0, 1);\n"
5559 " EmitVertex();\n"
5560 " \n"
5561 " EndPrimitive();\n"
5562 "}\n"
5563 "\n";
5564
5565 static const GLchar* vertex_shader_code = "#version 400 core\n"
5566 "#extension GL_ARB_shader_subroutine : require\n"
5567 "\n"
5568 "precision highp float;\n"
5569 "\n"
5570 "void main()\n"
5571 "{\n"
5572 "}\n"
5573 "\n";
5574
5575 static const GLchar* subroutine_names[][2] = { { "discard_yes", "discard_no" },
5576 { "red_pass_blue_fail", "blue_pass_red_fail" },
5577 { "first_sampler", "second_sampler" },
5578 { "check_equal", "check_not_equal" },
5579 { "test_with_discard", "test_without_discard" } };
5580 static const GLuint n_subroutine_types = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
5581
5582 static const GLchar* subroutine_uniform_names[] = { "discard_fragment", "set_global_colors", "sample_texture",
5583 "compare", "test" };
5584 static const GLuint n_subroutine_uniform_names =
5585 sizeof(subroutine_uniform_names) / sizeof(subroutine_uniform_names[0]);
5586
5587 static const GLchar* uniform_names[] = {
5588 "sampler_1", "sampler_2",
5589 };
5590 static const GLuint n_uniform_names = sizeof(uniform_names) / sizeof(uniform_names[0]);
5591
5592 /* Colors */
5593 static const GLubyte blue_color[4] = { 0, 0, 255, 255 };
5594 static const GLubyte clean_color[4] = { 0, 0, 0, 0 };
5595 static const GLubyte red_color[4] = { 255, 0, 0, 255 };
5596
5597 /* Configurations */
5598 static const testConfiguration test_configurations[] = {
5599 testConfiguration(
5600 "Expect red color from 1st sampler", red_color, 1 /* discard_fragment : discard_no */,
5601 0 /* set_global_colors : red_pass_blue_fail */, 0 /* sample_texture : first_sampler */,
5602 0 /* compare : check_equal */, 0 /* test : test_with_discard */, 1 /* red */,
5603 0 /* blue */),
5604
5605 testConfiguration(
5606 "Test \"without discard\" option, expect no blue color from 2nd sampler", blue_color,
5607 0 /* discard_fragment : discard_yes */, 1 /* set_global_colors : blue_pass_red_fail */,
5608 1 /* sample_texture : second_sampler */, 1 /* compare : check_not_equal */,
5609 1 /* test : test_without_discard */, 0 /* blue */, 1 /* red */),
5610
5611 testConfiguration("Fragment shoud be discarded", clean_color, 0 /* discard_fragment : discard_yes */,
5612 0 /* set_global_colors : red_pass_blue_fail */,
5613 0 /* sample_texture : first_sampler */,
5614 0 /* compare : check_equal */,
5615 0 /* test : test_with_discard */, 1 /* red */, 0 /* blue */),
5616
5617 testConfiguration(
5618 "Expect blue color from 1st sampler", blue_color, 1 /* discard_fragment : discard_no */,
5619 1 /* set_global_colors : blue_pass_red_fail */, 0 /* sample_texture : first_sampler */,
5620 0 /* compare : check_equal */, 0 /* test : test_with_discard */,
5621 0 /* blue */, 1 /* red */),
5622
5623 testConfiguration(
5624 "Expect red color from 2nd sampler", red_color, 1 /* discard_fragment : discard_no */,
5625 0 /* set_global_colors : red_pass_blue_fail */, 1 /* sample_texture : second_sampler */,
5626 0 /* compare : check_equal */, 0 /* test : test_with_discard */,
5627 0 /* blue */, 1 /* red */),
5628
5629 testConfiguration(
5630 "Expect no blue color from 2nd sampler", blue_color, 1 /* discard_fragment : discard_no */,
5631 1 /* set_global_colors : blue_pass_red_fail */, 1 /* sample_texture : second_sampler */,
5632 1 /* compare : check_not_equal */, 0 /* test : test_with_discard */,
5633 0 /* blue */, 1 /* red */),
5634 };
5635 static const GLuint n_test_cases = sizeof(test_configurations) / sizeof(test_configurations[0]);
5636
5637 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
5638 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
5639 {
5640 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
5641 }
5642
5643 /* GL objects */
5644 Utils::texture blue_texture(m_context);
5645 Utils::texture color_texture(m_context);
5646 Utils::framebuffer framebuffer(m_context);
5647 Utils::program program(m_context);
5648 Utils::texture red_texture(m_context);
5649 Utils::vertexArray vao(m_context);
5650
5651 /* Init GL objects */
5652 program.build(0 /* cs */, fragment_shader_code /* fs */, geometry_shader_code /* gs */, 0 /* tcs */, 0 /* test */,
5653 vertex_shader_code, 0 /* varying_names */, 0 /* n_varyings */);
5654
5655 program.use();
5656
5657 vao.generate();
5658 vao.bind();
5659
5660 blue_texture.create(m_texture_width, m_texture_height, GL_RGBA8);
5661 color_texture.create(m_texture_width, m_texture_height, GL_RGBA8);
5662 red_texture.create(m_texture_width, m_texture_height, GL_RGBA8);
5663
5664 framebuffer.generate();
5665 framebuffer.bind();
5666 framebuffer.attachTexture(GL_COLOR_ATTACHMENT0, color_texture.m_id, m_texture_width, m_texture_height);
5667
5668 /* Get subroutine indices */
5669 for (GLuint type = 0; type < n_subroutine_types; ++type)
5670 {
5671 m_subroutine_indices[type][0] = program.getSubroutineIndex(subroutine_names[type][0], GL_FRAGMENT_SHADER);
5672 m_subroutine_indices[type][1] = program.getSubroutineIndex(subroutine_names[type][1], GL_FRAGMENT_SHADER);
5673 }
5674
5675 /* Get subroutine uniform locations */
5676 for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
5677 {
5678 m_subroutine_uniform_locations[uniform] =
5679 program.getSubroutineUniformLocation(subroutine_uniform_names[uniform], GL_FRAGMENT_SHADER);
5680 }
5681
5682 /* Get uniform locations */
5683 for (GLuint i = 0; i < n_uniform_names; ++i)
5684 {
5685 m_uniform_locations[i] = program.getUniformLocation(uniform_names[i]);
5686 }
5687
5688 /* Prepare textures */
5689 fillTexture(blue_texture, blue_color);
5690 fillTexture(color_texture, clean_color);
5691 fillTexture(red_texture, red_color);
5692
5693 m_source_textures[0] = blue_texture.m_id;
5694 m_source_textures[1] = red_texture.m_id;
5695
5696 framebuffer.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
5697
5698 /* Test */
5699 bool result = true;
5700 for (GLuint i = 0; i < n_test_cases; ++i)
5701 {
5702 /* Clean output texture */
5703 framebuffer.clear(GL_COLOR_BUFFER_BIT);
5704
5705 /* Execute test */
5706 if (false == testDraw(test_configurations[i].m_routines, test_configurations[i].m_samplers,
5707 test_configurations[i].m_expected_color, color_texture))
5708 {
5709 m_context.getTestContext().getLog()
5710 << tcu::TestLog::Message << "Error. Failure for configuration: " << test_configurations[i].m_description
5711 << tcu::TestLog::EndMessage;
5712
5713 result = false;
5714 }
5715 }
5716
5717 /* Set result */
5718 if (true == result)
5719 {
5720 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5721 }
5722 else
5723 {
5724 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
5725 }
5726
5727 /* Done */
5728 return tcu::TestNode::STOP;
5729 }
5730
5731 /** Fill texture with specified color
5732 *
5733 * @param texture Texture instance
5734 * @param color Color
5735 **/
fillTexture(Utils::texture & texture,const glw::GLubyte color[4]) const5736 void FunctionalTest11::fillTexture(Utils::texture& texture, const glw::GLubyte color[4]) const
5737 {
5738 std::vector<GLubyte> texture_data;
5739
5740 /* Prepare texture data */
5741 texture_data.resize(m_texture_width * m_texture_height * 4);
5742
5743 for (GLuint y = 0; y < m_texture_height; ++y)
5744 {
5745 const GLuint line_offset = y * m_texture_width * 4;
5746
5747 for (GLuint x = 0; x < m_texture_width; ++x)
5748 {
5749 const GLuint point_offset = x * 4 + line_offset;
5750
5751 texture_data[point_offset + 0] = color[0]; /* red */
5752 texture_data[point_offset + 1] = color[1]; /* green */
5753 texture_data[point_offset + 2] = color[2]; /* blue */
5754 texture_data[point_offset + 3] = color[3]; /* alpha */
5755 }
5756 }
5757
5758 texture.update(m_texture_width, m_texture_height, GL_RGBA, GL_UNSIGNED_BYTE, &texture_data[0]);
5759 }
5760
5761 /** Execute draw call and verify results
5762 *
5763 * @param routine_configuration Configurations of routines to be used
5764 * @param sampler_configuration Configuration of textures to be bound to samplers
5765 * @param expected_color Expected color of result image
5766 *
5767 * @return true if result image is filled with expected color, false otherwise
5768 **/
testDraw(const glw::GLuint routine_configuration[5],const glw::GLuint sampler_configuration[2],const glw::GLubyte expected_color[4],Utils::texture & color_texture) const5769 bool FunctionalTest11::testDraw(const glw::GLuint routine_configuration[5], const glw::GLuint sampler_configuration[2],
5770 const glw::GLubyte expected_color[4], Utils::texture& color_texture) const
5771 {
5772 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
5773 static const GLint n_samplers = 2;
5774 static const GLint n_subroutine_uniforms = 5;
5775 GLuint subroutine_indices[5];
5776
5777 /* Set samplers */
5778 for (GLuint i = 0; i < n_samplers; ++i)
5779 {
5780 const GLuint location = m_uniform_locations[i];
5781 const GLuint texture = m_source_textures[sampler_configuration[i]];
5782
5783 gl.activeTexture(GL_TEXTURE0 + i);
5784 GLU_EXPECT_NO_ERROR(gl.getError(), "ActiveTexture");
5785
5786 gl.bindTexture(GL_TEXTURE_2D, texture);
5787 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
5788
5789 gl.uniform1i(location, i);
5790 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
5791 }
5792
5793 gl.activeTexture(GL_TEXTURE0 + 0);
5794
5795 /* Set subroutine uniforms */
5796 for (GLuint i = 0; i < n_subroutine_uniforms; ++i)
5797 {
5798 const GLuint location = m_subroutine_uniform_locations[i];
5799 const GLuint routine = routine_configuration[i];
5800
5801 subroutine_indices[location] = m_subroutine_indices[i][routine];
5802 }
5803
5804 gl.uniformSubroutinesuiv(GL_FRAGMENT_SHADER, 5, subroutine_indices);
5805 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
5806
5807 /* Draw */
5808 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
5809 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
5810
5811 /* Capture result */
5812 std::vector<GLubyte> captured_data;
5813 captured_data.resize(m_texture_width * m_texture_height * 4);
5814
5815 color_texture.get(GL_RGBA, GL_UNSIGNED_BYTE, &captured_data[0]);
5816
5817 /* Verify result */
5818 for (GLuint y = 0; y < m_texture_height; ++y)
5819 {
5820 const GLuint line_offset = y * m_texture_width * 4;
5821
5822 for (GLuint x = 0; x < m_texture_width; ++x)
5823 {
5824 const GLuint point_offset = x * 4 + line_offset;
5825 bool is_as_expected = true;
5826
5827 is_as_expected = is_as_expected && (expected_color[0] == captured_data[point_offset + 0]); /* red */
5828 is_as_expected = is_as_expected && (expected_color[1] == captured_data[point_offset + 1]); /* green */
5829 is_as_expected = is_as_expected && (expected_color[2] == captured_data[point_offset + 2]); /* blue */
5830 is_as_expected = is_as_expected && (expected_color[3] == captured_data[point_offset + 3]); /* alpha */
5831
5832 if (false == is_as_expected)
5833 {
5834 return false;
5835 }
5836 }
5837 }
5838
5839 /* Done */
5840 return true;
5841 }
5842
5843 /* Constatns used by FunctionalTest12 */
5844 const glw::GLuint FunctionalTest12::m_texture_height = 16;
5845 const glw::GLuint FunctionalTest12::m_texture_width = 16;
5846
5847 /** Constructor
5848 *
5849 * @param context CTS context
5850 **/
FunctionalTest12(deqp::Context & context)5851 FunctionalTest12::FunctionalTest12(deqp::Context& context)
5852 : TestCase(context, "ssbo_atomic_image_load_store",
5853 "Verify that SSBO, atomic counters and image load store work as expected")
5854 , m_left_image(0)
5855 , m_right_image(0)
5856 {
5857 }
5858
5859 /** Execute test
5860 *
5861 * @return tcu::TestNode::STOP
5862 **/
iterate()5863 tcu::TestNode::IterateResult FunctionalTest12::iterate()
5864 {
5865 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
5866 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
5867 {
5868 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
5869 }
5870
5871 bool result = true;
5872
5873 /* Test atomic counters */
5874 if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_atomic_counters"))
5875 {
5876 if (false == testAtomic())
5877 {
5878 result = false;
5879 }
5880 }
5881
5882 /* Test shader storage buffer */
5883 if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_storage_buffer_object"))
5884 {
5885 if (false == testSSBO())
5886 {
5887 result = false;
5888 }
5889 }
5890
5891 /* Test image load store */
5892 if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_image_load_store"))
5893 {
5894 if (false == testImage())
5895 {
5896 result = false;
5897 }
5898 }
5899
5900 /* Set result */
5901 if (true == result)
5902 {
5903 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5904 }
5905 else
5906 {
5907 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
5908 }
5909
5910 /* Done */
5911 return tcu::TestNode::STOP;
5912 }
5913
5914 /** Fill texture with specified color
5915 *
5916 * @param texture Texture instance
5917 * @param color Color
5918 **/
fillTexture(Utils::texture & texture,const glw::GLuint color[4]) const5919 void FunctionalTest12::fillTexture(Utils::texture& texture, const glw::GLuint color[4]) const
5920 {
5921 std::vector<GLuint> texture_data;
5922
5923 /* Prepare texture data */
5924 texture_data.resize(m_texture_width * m_texture_height * 4);
5925
5926 for (GLuint y = 0; y < m_texture_height; ++y)
5927 {
5928 const GLuint line_offset = y * m_texture_width * 4;
5929
5930 for (GLuint x = 0; x < m_texture_width; ++x)
5931 {
5932 const GLuint point_offset = x * 4 + line_offset;
5933
5934 texture_data[point_offset + 0] = color[0]; /* red */
5935 texture_data[point_offset + 1] = color[1]; /* green */
5936 texture_data[point_offset + 2] = color[2]; /* blue */
5937 texture_data[point_offset + 3] = color[3]; /* alpha */
5938 }
5939 }
5940
5941 texture.update(m_texture_width, m_texture_height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &texture_data[0]);
5942 }
5943
5944 /** Test atomic counters
5945 *
5946 * @return true if test pass, false otherwise
5947 **/
testAtomic()5948 bool FunctionalTest12::testAtomic()
5949 {
5950 static const GLchar* fragment_shader_code = "#version 400 core\n"
5951 "#extension GL_ARB_shader_atomic_counters : require\n"
5952 "#extension GL_ARB_shader_subroutine : require\n"
5953 "\n"
5954 "precision highp float;\n"
5955 "\n"
5956 "layout(location = 0) out uint out_color;\n"
5957 "\n"
5958 "layout(binding = 0, offset = 8) uniform atomic_uint one;\n"
5959 "layout(binding = 0, offset = 4) uniform atomic_uint two;\n"
5960 "layout(binding = 0, offset = 0) uniform atomic_uint three;\n"
5961 "\n"
5962 "subroutine void atomic_routine(void)\n;"
5963 "\n"
5964 "subroutine(atomic_routine) void increment_two(void)\n"
5965 "{\n"
5966 " out_color = atomicCounterIncrement(two);\n"
5967 "}\n"
5968 "\n"
5969 "subroutine(atomic_routine) void decrement_three(void)\n"
5970 "{\n"
5971 " out_color = atomicCounterDecrement(three);\n"
5972 "}\n"
5973 "\n"
5974 "subroutine(atomic_routine) void read_one(void)\n"
5975 "{\n"
5976 " out_color = atomicCounter(one);\n"
5977 "}\n"
5978 "\n"
5979 "subroutine uniform atomic_routine routine;\n"
5980 "\n"
5981 "void main()\n"
5982 "{\n"
5983 " routine();\n"
5984 "}\n"
5985 "\n";
5986
5987 static const GLchar* geometry_shader_code = "#version 400 core\n"
5988 "#extension GL_ARB_shader_subroutine : require\n"
5989 "\n"
5990 "precision highp float;\n"
5991 "\n"
5992 "layout(points) in;\n"
5993 "layout(triangle_strip, max_vertices = 4) out;\n"
5994 "\n"
5995 "void main()\n"
5996 "{\n"
5997 " gl_Position = vec4(-1, -1, 0, 1);\n"
5998 " EmitVertex();\n"
5999 " \n"
6000 " gl_Position = vec4(-1, 1, 0, 1);\n"
6001 " EmitVertex();\n"
6002 " \n"
6003 " gl_Position = vec4( 1, -1, 0, 1);\n"
6004 " EmitVertex();\n"
6005 " \n"
6006 " gl_Position = vec4( 1, 1, 0, 1);\n"
6007 " EmitVertex();\n"
6008 " \n"
6009 " EndPrimitive();\n"
6010 "}\n"
6011 "\n";
6012
6013 static const GLchar* vertex_shader_code = "#version 400 core\n"
6014 "#extension GL_ARB_shader_subroutine : require\n"
6015 "\n"
6016 "precision highp float;\n"
6017 "\n"
6018 "void main()\n"
6019 "{\n"
6020 "}\n"
6021 "\n";
6022
6023 static const GLchar* subroutine_names[] = { "increment_two", "decrement_three", "read_one" };
6024
6025 /* Test data */
6026 static const glw::GLuint atomic_buffer_data[] = { m_texture_width * m_texture_height,
6027 m_texture_width * m_texture_height,
6028 m_texture_width * m_texture_height };
6029
6030 static const glw::GLuint expected_incremented_two[] = { atomic_buffer_data[0], 2 * atomic_buffer_data[1],
6031 atomic_buffer_data[2] };
6032
6033 static const glw::GLuint expected_decremented_three[] = { 0, expected_incremented_two[1],
6034 expected_incremented_two[2] };
6035
6036 static const glw::GLuint expected_read_one[] = { expected_decremented_three[0], expected_decremented_three[1],
6037 expected_decremented_three[2] };
6038
6039 /* GL objects */
6040 Utils::buffer atomic_buffer(m_context);
6041 Utils::texture color_texture(m_context);
6042 Utils::framebuffer framebuffer(m_context);
6043 Utils::program program(m_context);
6044 Utils::vertexArray vao(m_context);
6045
6046 /* Init GL objects */
6047 program.build(0 /* cs */, fragment_shader_code /* fs */, geometry_shader_code /* gs */, 0 /* tcs */, 0 /* test */,
6048 vertex_shader_code, 0 /* varying_names */, 0 /* n_varyings */);
6049
6050 program.use();
6051
6052 vao.generate();
6053 vao.bind();
6054
6055 color_texture.create(m_texture_width, m_texture_height, GL_R32UI);
6056
6057 atomic_buffer.generate();
6058 atomic_buffer.update(GL_ATOMIC_COUNTER_BUFFER, sizeof(atomic_buffer_data), (GLvoid*)atomic_buffer_data,
6059 GL_STATIC_DRAW);
6060 atomic_buffer.bindRange(GL_ATOMIC_COUNTER_BUFFER, 0 /* index */, 0 /* offset */, sizeof(atomic_buffer_data));
6061
6062 framebuffer.generate();
6063 framebuffer.bind();
6064 framebuffer.attachTexture(GL_COLOR_ATTACHMENT0, color_texture.m_id, m_texture_width, m_texture_height);
6065 framebuffer.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
6066 framebuffer.clear(GL_COLOR_BUFFER_BIT);
6067
6068 /* Subroutine indices */
6069 GLuint increment_two = program.getSubroutineIndex(subroutine_names[0], GL_FRAGMENT_SHADER);
6070 GLuint decrement_three = program.getSubroutineIndex(subroutine_names[1], GL_FRAGMENT_SHADER);
6071 GLuint read_one = program.getSubroutineIndex(subroutine_names[2], GL_FRAGMENT_SHADER);
6072
6073 /* Test */
6074 bool result = true;
6075
6076 if (false == testAtomicDraw(increment_two, expected_incremented_two))
6077 {
6078 result = false;
6079 }
6080
6081 if (false == testAtomicDraw(decrement_three, expected_decremented_three))
6082 {
6083 result = false;
6084 }
6085
6086 if (false == testAtomicDraw(read_one, expected_read_one))
6087 {
6088 result = false;
6089 }
6090
6091 /* Done */
6092 return result;
6093 }
6094
6095 /** Execture draw call and verify results
6096 *
6097 * @param subroutine_index Index of subroutine that shall be used during draw call
6098 * @param expected_results Expected results
6099 *
6100 * @return true if results are as expected, false otherwise
6101 **/
testAtomicDraw(GLuint subroutine_index,const GLuint expected_results[3]) const6102 bool FunctionalTest12::testAtomicDraw(GLuint subroutine_index, const GLuint expected_results[3]) const
6103 {
6104 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
6105
6106 /* Set subroutine uniforms */
6107 gl.uniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &subroutine_index);
6108 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
6109
6110 /* Draw */
6111 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
6112 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
6113
6114 /* Capture results */
6115 GLuint* atomic_results = (GLuint*)gl.mapBuffer(GL_ATOMIC_COUNTER_BUFFER, GL_READ_ONLY);
6116 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
6117
6118 /* Verify */
6119 bool result = (0 == memcmp(expected_results, atomic_results, 3 * sizeof(GLuint)));
6120
6121 if (false == result)
6122 {
6123 m_context.getTestContext().getLog()
6124 << tcu::TestLog::Message << "Error. Invalid result. "
6125 << "Result: [ " << atomic_results[0] << ", " << atomic_results[1] << ", " << atomic_results[2] << " ] "
6126 << "Expected: [ " << expected_results[0] << ", " << expected_results[1] << ", " << expected_results[2]
6127 << " ]" << tcu::TestLog::EndMessage;
6128 }
6129
6130 /* Unmap buffer */
6131 gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
6132 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
6133
6134 /* Done */
6135 return result;
6136 }
6137
6138 /** Test image load store
6139 *
6140 * @return true if test pass, false otherwise
6141 **/
testImage()6142 bool FunctionalTest12::testImage()
6143 {
6144 static const GLchar* fragment_shader_code =
6145 "#version 400 core\n"
6146 "#extension GL_ARB_shader_image_load_store : require\n"
6147 "#extension GL_ARB_shader_subroutine : require\n"
6148 "\n"
6149 "precision highp float;\n"
6150 "\n"
6151 "layout(location = 0) out uvec4 out_color;\n"
6152 "\n"
6153 "layout(rgba32ui) uniform uimage2D left_image;\n"
6154 "layout(rgba32ui) uniform uimage2D right_image;\n"
6155 "\n"
6156 "subroutine void image_routine(void);\n"
6157 "\n"
6158 "subroutine(image_routine) void left_to_right(void)\n"
6159 "{\n"
6160 " out_color = imageLoad (left_image, ivec2(gl_FragCoord.xy));\n"
6161 " imageStore(right_image, ivec2(gl_FragCoord.xy), out_color);\n"
6162 "}\n"
6163 "\n"
6164 "subroutine(image_routine) void right_to_left(void)\n"
6165 "{\n"
6166 " out_color = imageLoad (right_image, ivec2(gl_FragCoord.xy));\n"
6167 " imageStore(left_image, ivec2(gl_FragCoord.xy), out_color);\n"
6168 "}\n"
6169 "\n"
6170 "subroutine uniform image_routine routine;\n"
6171 "\n"
6172 "void main()\n"
6173 "{\n"
6174 " routine();\n"
6175 "}\n"
6176 "\n";
6177
6178 static const GLchar* geometry_shader_code = "#version 400 core\n"
6179 "#extension GL_ARB_shader_subroutine : require\n"
6180 "\n"
6181 "precision highp float;\n"
6182 "\n"
6183 "layout(points) in;\n"
6184 "layout(triangle_strip, max_vertices = 4) out;\n"
6185 "\n"
6186 "void main()\n"
6187 "{\n"
6188 " gl_Position = vec4(-1, -1, 0, 1);\n"
6189 " EmitVertex();\n"
6190 " \n"
6191 " gl_Position = vec4(-1, 1, 0, 1);\n"
6192 " EmitVertex();\n"
6193 " \n"
6194 " gl_Position = vec4( 1, -1, 0, 1);\n"
6195 " EmitVertex();\n"
6196 " \n"
6197 " gl_Position = vec4( 1, 1, 0, 1);\n"
6198 " EmitVertex();\n"
6199 " \n"
6200 " EndPrimitive();\n"
6201 "}\n"
6202 "\n";
6203
6204 static const GLchar* vertex_shader_code = "#version 400 core\n"
6205 "#extension GL_ARB_shader_subroutine : require\n"
6206 "\n"
6207 "precision highp float;\n"
6208 "\n"
6209 "void main()\n"
6210 "{\n"
6211 "}\n"
6212 "\n";
6213
6214 static const GLchar* subroutine_names[] = { "left_to_right", "right_to_left" };
6215
6216 static const GLchar* uniform_names[] = { "left_image", "right_image" };
6217
6218 /* Test data */
6219 static const GLuint blue_color[4] = { 0, 0, 255, 255 };
6220 static const GLuint clean_color[4] = { 16, 32, 64, 128 };
6221 static const GLuint red_color[4] = { 255, 0, 0, 255 };
6222
6223 /* GL objects */
6224 Utils::texture blue_texture(m_context);
6225 Utils::texture destination_texture(m_context);
6226 Utils::texture color_texture(m_context);
6227 Utils::framebuffer framebuffer(m_context);
6228 Utils::program program(m_context);
6229 Utils::texture red_texture(m_context);
6230 Utils::vertexArray vao(m_context);
6231
6232 /* Init GL objects */
6233 program.build(0 /* cs */, fragment_shader_code /* fs */, geometry_shader_code /* gs */, 0 /* tcs */, 0 /* test */,
6234 vertex_shader_code, 0 /* varying_names */, 0 /* n_varyings */);
6235
6236 program.use();
6237
6238 vao.generate();
6239 vao.bind();
6240
6241 blue_texture.create(m_texture_width, m_texture_height, GL_RGBA32UI);
6242 destination_texture.create(m_texture_width, m_texture_height, GL_RGBA32UI);
6243 color_texture.create(m_texture_width, m_texture_height, GL_RGBA32UI);
6244 red_texture.create(m_texture_width, m_texture_height, GL_RGBA32UI);
6245
6246 fillTexture(blue_texture, blue_color);
6247 fillTexture(destination_texture, clean_color);
6248 fillTexture(red_texture, red_color);
6249
6250 framebuffer.generate();
6251 framebuffer.bind();
6252 framebuffer.attachTexture(GL_COLOR_ATTACHMENT0, color_texture.m_id, m_texture_width, m_texture_height);
6253 framebuffer.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
6254 framebuffer.clear(GL_COLOR_BUFFER_BIT);
6255
6256 /* Subroutine indices */
6257 GLuint left_to_right = program.getSubroutineIndex(subroutine_names[0], GL_FRAGMENT_SHADER);
6258 GLuint right_to_left = program.getSubroutineIndex(subroutine_names[1], GL_FRAGMENT_SHADER);
6259
6260 /* Uniform locations */
6261 m_left_image = program.getUniformLocation(uniform_names[0]);
6262 m_right_image = program.getUniformLocation(uniform_names[1]);
6263
6264 /* Test */
6265 bool result = true;
6266
6267 if (false == testImageDraw(left_to_right, blue_texture, destination_texture, blue_color, blue_color))
6268 {
6269 result = false;
6270 }
6271
6272 if (false == testImageDraw(left_to_right, red_texture, destination_texture, red_color, red_color))
6273 {
6274 result = false;
6275 }
6276
6277 if (false == testImageDraw(right_to_left, destination_texture, blue_texture, blue_color, blue_color))
6278 {
6279 result = false;
6280 }
6281
6282 if (false == testImageDraw(right_to_left, destination_texture, red_texture, red_color, red_color))
6283 {
6284 result = false;
6285 }
6286
6287 if (false == testImageDraw(left_to_right, blue_texture, red_texture, blue_color, blue_color))
6288 {
6289 result = false;
6290 }
6291
6292 /* Done */
6293 return result;
6294 }
6295
6296 /** Execute draw call and verifies results
6297 *
6298 * @param subroutine_index Index of subroutine that shall be used during draw call
6299 * @param left "Left" texture
6300 * @param right "Right" texture
6301 * @param expected_left_color Expected color of "left" texture
6302 * @param expected_right_color Expected color of "right" texture
6303 *
6304 * @return true if verification result is positive, false otherwise
6305 **/
testImageDraw(GLuint subroutine_index,Utils::texture & left,Utils::texture & right,const GLuint expected_left_color[4],const GLuint expected_right_color[4]) const6306 bool FunctionalTest12::testImageDraw(GLuint subroutine_index, Utils::texture& left, Utils::texture& right,
6307 const GLuint expected_left_color[4], const GLuint expected_right_color[4]) const
6308 {
6309 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
6310
6311 /* Set subroutine uniforms */
6312 gl.uniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &subroutine_index);
6313 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
6314
6315 /* Set up image units */
6316 gl.uniform1i(m_left_image, 0);
6317 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
6318
6319 gl.uniform1i(m_right_image, 1);
6320 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
6321
6322 gl.bindImageTexture(0, left.m_id, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32UI);
6323 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
6324
6325 gl.bindImageTexture(1, right.m_id, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32UI);
6326 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
6327
6328 /* Draw */
6329 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
6330 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
6331
6332 /* Verify results */
6333 bool result = true;
6334
6335 if (false == verifyTexture(left, expected_left_color))
6336 {
6337 m_context.getTestContext().getLog() << tcu::TestLog::Message
6338 << "Error. Invalid result. Left texture is filled with wrong color."
6339 << tcu::TestLog::EndMessage;
6340 result = false;
6341 }
6342
6343 if (false == verifyTexture(right, expected_right_color))
6344 {
6345 m_context.getTestContext().getLog() << tcu::TestLog::Message
6346 << "Error. Invalid result. Right texture is filled with wrong color."
6347 << tcu::TestLog::EndMessage;
6348 result = false;
6349 }
6350
6351 /* Done */
6352 return result;
6353 }
6354
6355 /** Test shader storage buffer
6356 *
6357 * @return true if test pass, false otherwise
6358 **/
testSSBO()6359 bool FunctionalTest12::testSSBO()
6360 {
6361 static const GLchar* fragment_shader_code = "#version 400 core\n"
6362 "#extension GL_ARB_shader_storage_buffer_object : require\n"
6363 "#extension GL_ARB_shader_subroutine : require\n"
6364 "\n"
6365 "precision highp float;\n"
6366 "\n"
6367 "layout(location = 0) out uvec4 out_color;\n"
6368 "\n"
6369 "layout(std140, binding = 0) buffer Buffer\n"
6370 "{\n"
6371 " uvec4 entry;\n"
6372 "};\n"
6373 "\n"
6374 "subroutine void ssbo_routine(void)\n;"
6375 "\n"
6376 "subroutine(ssbo_routine) void increment(void)\n"
6377 "{\n"
6378 " out_color.x = atomicAdd(entry.x, 1);\n"
6379 " out_color.y = atomicAdd(entry.y, 1);\n"
6380 " out_color.z = atomicAdd(entry.z, 1);\n"
6381 " out_color.w = atomicAdd(entry.w, 1);\n"
6382 "}\n"
6383 "\n"
6384 "subroutine(ssbo_routine) void decrement(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 uniform ssbo_routine routine;\n"
6393 "\n"
6394 "void main()\n"
6395 "{\n"
6396 " routine();\n"
6397 "}\n"
6398 "\n";
6399
6400 static const GLchar* geometry_shader_code = "#version 400 core\n"
6401 "#extension GL_ARB_shader_subroutine : require\n"
6402 "\n"
6403 "precision highp float;\n"
6404 "\n"
6405 "layout(points) in;\n"
6406 "layout(triangle_strip, max_vertices = 4) out;\n"
6407 "\n"
6408 "void main()\n"
6409 "{\n"
6410 " gl_Position = vec4(-1, -1, 0, 1);\n"
6411 " EmitVertex();\n"
6412 " \n"
6413 " gl_Position = vec4(-1, 1, 0, 1);\n"
6414 " EmitVertex();\n"
6415 " \n"
6416 " gl_Position = vec4( 1, -1, 0, 1);\n"
6417 " EmitVertex();\n"
6418 " \n"
6419 " gl_Position = vec4( 1, 1, 0, 1);\n"
6420 " EmitVertex();\n"
6421 " \n"
6422 " EndPrimitive();\n"
6423 "}\n"
6424 "\n";
6425
6426 static const GLchar* vertex_shader_code = "#version 400 core\n"
6427 "#extension GL_ARB_shader_subroutine : require\n"
6428 "\n"
6429 "precision highp float;\n"
6430 "\n"
6431 "void main()\n"
6432 "{\n"
6433 "}\n"
6434 "\n";
6435
6436 static const GLchar* subroutine_names[] = { "increment", "decrement" };
6437
6438 /* Test data */
6439 static const glw::GLuint buffer_data[] = { m_texture_width * m_texture_height + 1,
6440 m_texture_width * m_texture_height + 2,
6441 m_texture_width * m_texture_height + 3,
6442 m_texture_width * m_texture_height + 4 };
6443
6444 static const glw::GLuint expected_incremented[] = { m_texture_width * m_texture_height + buffer_data[0],
6445 m_texture_width * m_texture_height + buffer_data[1],
6446 m_texture_width * m_texture_height + buffer_data[2],
6447 m_texture_width * m_texture_height + buffer_data[3] };
6448
6449 static const glw::GLuint expected_decremented[] = { buffer_data[0], buffer_data[1], buffer_data[2],
6450 buffer_data[3] };
6451
6452 /* GL objects */
6453 Utils::buffer buffer(m_context);
6454 Utils::texture color_texture(m_context);
6455 Utils::framebuffer framebuffer(m_context);
6456 Utils::program program(m_context);
6457 Utils::vertexArray vao(m_context);
6458
6459 /* Init GL objects */
6460 program.build(0 /* cs */, fragment_shader_code /* fs */, geometry_shader_code /* gs */, 0 /* tcs */, 0 /* test */,
6461 vertex_shader_code, 0 /* varying_names */, 0 /* n_varyings */);
6462
6463 program.use();
6464
6465 vao.generate();
6466 vao.bind();
6467
6468 color_texture.create(m_texture_width, m_texture_height, GL_RGBA32UI);
6469
6470 buffer.generate();
6471 buffer.update(GL_SHADER_STORAGE_BUFFER, sizeof(buffer_data), (GLvoid*)buffer_data, GL_STATIC_DRAW);
6472 buffer.bindRange(GL_SHADER_STORAGE_BUFFER, 0 /* index */, 0 /* offset */, sizeof(buffer_data));
6473
6474 framebuffer.generate();
6475 framebuffer.bind();
6476 framebuffer.attachTexture(GL_COLOR_ATTACHMENT0, color_texture.m_id, m_texture_width, m_texture_height);
6477 framebuffer.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
6478 framebuffer.clear(GL_COLOR_BUFFER_BIT);
6479
6480 /* Subroutine indices */
6481 GLuint increment = program.getSubroutineIndex(subroutine_names[0], GL_FRAGMENT_SHADER);
6482 GLuint decrement = program.getSubroutineIndex(subroutine_names[1], GL_FRAGMENT_SHADER);
6483
6484 /* Test */
6485 bool result = true;
6486
6487 if (false == testSSBODraw(increment, expected_incremented))
6488 {
6489 result = false;
6490 }
6491
6492 if (false == testSSBODraw(decrement, expected_decremented))
6493 {
6494 result = false;
6495 }
6496
6497 /* Done */
6498 return result;
6499 }
6500
6501 /** Execute draw call and verify results
6502 *
6503 * @param subroutine_index Index of subroutine that shall be used by draw call
6504 * @param expected_results Expected results
6505 *
6506 *
6507 **/
testSSBODraw(GLuint subroutine_index,const GLuint expected_results[4]) const6508 bool FunctionalTest12::testSSBODraw(GLuint subroutine_index, const GLuint expected_results[4]) const
6509 {
6510 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
6511
6512 /* Set subroutine uniforms */
6513 gl.uniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &subroutine_index);
6514 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
6515
6516 /* Draw */
6517 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
6518 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
6519
6520 /* Capture results */
6521 GLuint* ssbo_results = (GLuint*)gl.mapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
6522 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
6523
6524 /* Verify */
6525 bool result = (0 == memcmp(expected_results, ssbo_results, 4 * sizeof(GLuint)));
6526
6527 if (false == result)
6528 {
6529 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error. Invalid result. "
6530 << "Result: [ " << ssbo_results[0] << ", " << ssbo_results[1] << ", "
6531 << ssbo_results[2] << ", " << ssbo_results[3] << " ] "
6532 << "Expected: [ " << expected_results[0] << ", " << expected_results[1]
6533 << ", " << expected_results[2] << ", " << expected_results[3] << " ]"
6534 << tcu::TestLog::EndMessage;
6535 }
6536
6537 /* Unmap buffer */
6538 gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
6539 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
6540
6541 /* Done */
6542 return result;
6543 }
6544
6545 /** Check if texture is filled with expected color
6546 *
6547 * @param texture Texture instance
6548 * @param expected_color Expected color
6549 *
6550 * @return true if texture is filled with specified color, false otherwise
6551 **/
verifyTexture(Utils::texture & texture,const GLuint expected_color[4]) const6552 bool FunctionalTest12::verifyTexture(Utils::texture& texture, const GLuint expected_color[4]) const
6553 {
6554 std::vector<GLuint> results;
6555 results.resize(m_texture_width * m_texture_height * 4);
6556
6557 texture.get(GL_RGBA_INTEGER, GL_UNSIGNED_INT, &results[0]);
6558
6559 for (GLuint y = 0; y < m_texture_height; ++y)
6560 {
6561 const GLuint line_offset = y * m_texture_width * 4;
6562
6563 for (GLuint x = 0; x < m_texture_width; ++x)
6564 {
6565 const GLuint point_offset = line_offset + x * 4;
6566 bool result = true;
6567
6568 result = result && (results[point_offset + 0] == expected_color[0]);
6569 result = result && (results[point_offset + 1] == expected_color[1]);
6570 result = result && (results[point_offset + 2] == expected_color[2]);
6571 result = result && (results[point_offset + 3] == expected_color[3]);
6572
6573 if (false == result)
6574 {
6575 return false;
6576 }
6577 }
6578 }
6579
6580 return true;
6581 }
6582
6583 /** Constructor.
6584 *
6585 * @param context Rendering context.
6586 *
6587 **/
FunctionalTest13(deqp::Context & context)6588 FunctionalTest13::FunctionalTest13(deqp::Context& context)
6589 : TestCase(context, "subroutines_with_separate_shader_objects",
6590 "Verifies that subroutines work correctly when used in separate "
6591 "shader objects")
6592 , m_fbo_id(0)
6593 , m_pipeline_id(0)
6594 , m_read_buffer(DE_NULL)
6595 , m_to_height(4)
6596 , m_to_id(0)
6597 , m_to_width(4)
6598 , m_vao_id(0)
6599 , m_has_test_passed(true)
6600 {
6601 memset(m_fs_po_ids, 0, sizeof(m_fs_po_ids));
6602 memset(m_gs_po_ids, 0, sizeof(m_gs_po_ids));
6603 memset(m_tc_po_ids, 0, sizeof(m_tc_po_ids));
6604 memset(m_te_po_ids, 0, sizeof(m_te_po_ids));
6605 memset(m_vs_po_ids, 0, sizeof(m_vs_po_ids));
6606 }
6607
6608 /** Deinitializes all GL objects that may have been created during test
6609 * execution, as well as releases all process-side buffers that may have
6610 * been allocated during the process.
6611 * The function also restores default GL state configuration.
6612 **/
deinit()6613 void FunctionalTest13::deinit()
6614 {
6615 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
6616
6617 if (m_fbo_id != 0)
6618 {
6619 gl.deleteFramebuffers(1, &m_fbo_id);
6620
6621 m_fbo_id = 0;
6622 }
6623
6624 if (m_pipeline_id != 0)
6625 {
6626 gl.deleteProgramPipelines(1, &m_pipeline_id);
6627
6628 m_pipeline_id = 0;
6629 }
6630
6631 if (m_read_buffer != DE_NULL)
6632 {
6633 delete[] m_read_buffer;
6634
6635 m_read_buffer = DE_NULL;
6636 }
6637
6638 for (unsigned int n_id = 0; n_id < 2 /* po id variants */; ++n_id)
6639 {
6640 if (m_fs_po_ids[n_id] != 0)
6641 {
6642 gl.deleteProgram(m_fs_po_ids[n_id]);
6643
6644 m_fs_po_ids[n_id] = 0;
6645 }
6646
6647 if (m_gs_po_ids[n_id] != 0)
6648 {
6649 gl.deleteProgram(m_gs_po_ids[n_id]);
6650
6651 m_gs_po_ids[n_id] = 0;
6652 }
6653
6654 if (m_tc_po_ids[n_id] != 0)
6655 {
6656 gl.deleteProgram(m_tc_po_ids[n_id]);
6657
6658 m_tc_po_ids[n_id] = 0;
6659 }
6660
6661 if (m_te_po_ids[n_id] != 0)
6662 {
6663 gl.deleteProgram(m_te_po_ids[n_id]);
6664
6665 m_te_po_ids[n_id] = 0;
6666 }
6667
6668 if (m_vs_po_ids[n_id] != 0)
6669 {
6670 gl.deleteProgram(m_vs_po_ids[n_id]);
6671
6672 m_vs_po_ids[n_id] = 0;
6673 }
6674 } /* for (both shader program object variants) */
6675
6676 if (m_to_id != 0)
6677 {
6678 gl.deleteTextures(1, &m_to_id);
6679
6680 m_to_id = 0;
6681 }
6682
6683 if (m_vao_id != 0)
6684 {
6685 gl.deleteVertexArrays(1, &m_vao_id);
6686
6687 m_vao_id = 0;
6688 }
6689
6690 /* Restore default GL_PATCH_VERTICES setting value */
6691 gl.patchParameteri(GL_PATCH_VERTICES, 3);
6692
6693 /* Restore default GL_PACK_ALIGNMENT setting value */
6694 gl.pixelStorei(GL_PACK_ALIGNMENT, 4);
6695 }
6696
6697 /** Retrieves body of a fragment shader that should be used for the test.
6698 * The subroutine implementations are slightly changed, depending on the
6699 * index of the shader, as specified by the caller.
6700 *
6701 * @param n_id Index of the shader.
6702 *
6703 * @return Requested string.
6704 **/
getFragmentShaderBody(unsigned int n_id)6705 std::string FunctionalTest13::getFragmentShaderBody(unsigned int n_id)
6706 {
6707 std::stringstream result_sstream;
6708
6709 /* Pre-amble */
6710 result_sstream << "#version 400\n"
6711 "\n"
6712 "#extension GL_ARB_shader_subroutine : require\n"
6713 "\n"
6714 /* Sub-routine */
6715 "subroutine void SubroutineFSType(inout vec4 result);\n"
6716 "\n"
6717 "subroutine(SubroutineFSType) void SubroutineFS1(inout vec4 result)\n"
6718 "{\n"
6719 " result += vec4("
6720 << float(n_id + 1) / 10.0f << ", " << float(n_id + 2) / 10.0f << ", " << float(n_id + 3) / 10.0f
6721 << ", " << float(n_id + 4) / 10.0f
6722 << ");\n"
6723 "}\n"
6724 "subroutine(SubroutineFSType) void SubroutineFS2(inout vec4 result)\n"
6725 "{\n"
6726 " result += vec4("
6727 << float(n_id + 1) / 20.0f << ", " << float(n_id + 2) / 20.0f << ", " << float(n_id + 3) / 20.0f
6728 << ", " << float(n_id + 4) / 20.0f << ");\n"
6729 "}\n"
6730 "\n"
6731 "subroutine uniform SubroutineFSType function;\n"
6732 "\n"
6733 /* Input block */
6734 "in GS_DATA\n"
6735 "{\n"
6736 " vec4 data;\n"
6737 "} in_gs;\n"
6738 "\n"
6739 "out vec4 result;\n"
6740 /* main() declaration */
6741 "void main()\n"
6742 "{\n"
6743 " vec4 data = in_gs.data;\n"
6744 " function(data);\n"
6745 "\n"
6746 " result = data;\n"
6747 "}\n";
6748
6749 return result_sstream.str();
6750 }
6751
6752 /** Retrieves body of a geometry shader that should be used for the test.
6753 * The subroutine implementations are slightly changed, depending on the
6754 * index of the shader, as specified by the caller.
6755 *
6756 * @param n_id Index of the shader.
6757 *
6758 * @return Requested string.
6759 **/
getGeometryShaderBody(unsigned int n_id)6760 std::string FunctionalTest13::getGeometryShaderBody(unsigned int n_id)
6761 {
6762 std::stringstream result_sstream;
6763
6764 /* Pre-amble */
6765 result_sstream << "#version 400\n"
6766 "\n"
6767 "#extension GL_ARB_shader_subroutine : require\n"
6768 "\n"
6769 "layout(points) in;\n"
6770 "layout(triangle_strip, max_vertices = 4) out;\n"
6771 /* Sub-routine */
6772 "subroutine void SubroutineGSType(inout vec4 result);\n"
6773 "\n"
6774 "subroutine(SubroutineGSType) void SubroutineGS1(inout vec4 result)\n"
6775 "{\n"
6776 " result += vec4(0, 0, 0, "
6777 << float(n_id + 1) * 0.425f << ");\n"
6778 "}\n"
6779 "subroutine(SubroutineGSType) void SubroutineGS2(inout vec4 result)\n"
6780 "{\n"
6781 " result += vec4(0, 0, 0, "
6782 << float(n_id + 1) * 0.0425f << ");\n"
6783 "}\n"
6784 "\n"
6785 "subroutine uniform SubroutineGSType function;\n"
6786 "\n"
6787 /* Input block */
6788 "in TE_DATA\n"
6789 "{\n"
6790 " vec4 data;\n"
6791 "} in_te[];\n"
6792 "\n"
6793 /* Output block */
6794 "out GS_DATA\n"
6795 "{\n"
6796 " vec4 data;\n"
6797 "} out_gs;\n"
6798 "\n"
6799 "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n"
6800 "out gl_PerVertex { vec4 gl_Position; };\n"
6801 /* main() declaration */
6802 "void main()\n"
6803 "{\n"
6804 " vec4 data = in_te[0].data;\n"
6805 "\n"
6806 " function(data);\n"
6807 "\n"
6808 " gl_Position = vec4(1, -1, 0, 1);\n"
6809 " out_gs.data = data;\n"
6810 " EmitVertex();\n"
6811 "\n"
6812 " gl_Position = vec4(-1, -1, 0, 1);\n"
6813 " out_gs.data = data;\n"
6814 " EmitVertex();\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 " EndPrimitive();\n"
6824 "}\n";
6825
6826 return result_sstream.str();
6827 }
6828
6829 /** Retrieves body of a tessellation control shader that should be used for the test.
6830 * The subroutine implementations are slightly changed, depending on the
6831 * index of the shader, as specified by the caller.
6832 *
6833 * @param n_id Index of the shader.
6834 *
6835 * @return Requested string.
6836 **/
getTessellationControlShaderBody(unsigned int n_id)6837 std::string FunctionalTest13::getTessellationControlShaderBody(unsigned int n_id)
6838 {
6839 std::stringstream result_sstream;
6840
6841 /* Pre-amble */
6842 result_sstream << "#version 400\n"
6843 "\n"
6844 "#extension GL_ARB_shader_subroutine : require\n"
6845 "\n"
6846 "layout(vertices = 4) out;\n"
6847 /* Sub-routine */
6848 "subroutine void SubroutineTCType(inout vec4 result);\n"
6849 "\n"
6850 "subroutine(SubroutineTCType) void SubroutineTC1(inout vec4 result)\n"
6851 "{\n"
6852 " result += vec4(0, "
6853 << float(n_id + 1) * 0.25f << ", 0, 0);\n"
6854 "}\n"
6855 "subroutine(SubroutineTCType) void SubroutineTC2(inout vec4 result)\n"
6856 "{\n"
6857 " result += vec4(0, "
6858 << float(n_id + 1) * 0.025f
6859 << ", 0, 0);\n"
6860 "}\n"
6861 "\n"
6862 "subroutine uniform SubroutineTCType function;\n"
6863 "\n"
6864 /* Input block */
6865 "in VS_DATA\n"
6866 "{\n"
6867 " vec4 data;\n"
6868 "} in_vs[];\n"
6869 "\n"
6870 /* Output block */
6871 "out TC_DATA\n"
6872 "{\n"
6873 " vec4 data;\n"
6874 "} out_tc[];\n"
6875 "\n"
6876 "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n"
6877 "out gl_PerVertex { vec4 gl_Position; } gl_out[];\n"
6878 /* main() declaration */
6879 "void main()\n"
6880 "{\n"
6881 " gl_TessLevelOuter[0] = 1.0;\n"
6882 " gl_TessLevelOuter[1] = 1.0;\n"
6883 " gl_TessLevelOuter[2] = 1.0;\n"
6884 " gl_TessLevelOuter[3] = 1.0;\n"
6885 " gl_TessLevelInner[0] = 1.0;\n"
6886 " gl_TessLevelInner[1] = 1.0;\n"
6887 " gl_out[gl_InvocationID].gl_Position = gl_in[0].gl_Position;\n"
6888 " out_tc[gl_InvocationID].data = in_vs[0].data;\n"
6889 "\n"
6890 " function(out_tc[gl_InvocationID].data);\n"
6891 "}\n";
6892
6893 return result_sstream.str();
6894 }
6895
6896 /** Retrieves body of a tessellation evaluation shader that should be used for the test.
6897 * The subroutine implementations are slightly changed, depending on the
6898 * index of the shader, as specified by the caller.
6899 *
6900 * @param n_id Index of the shader.
6901 *
6902 * @return Requested string.
6903 **/
getTessellationEvaluationShaderBody(unsigned int n_id)6904 std::string FunctionalTest13::getTessellationEvaluationShaderBody(unsigned int n_id)
6905 {
6906 std::stringstream result_sstream;
6907
6908 /* Pre-amble */
6909 result_sstream << "#version 400\n"
6910 "\n"
6911 "#extension GL_ARB_shader_subroutine : require\n"
6912 "\n"
6913 "layout(quads, point_mode) in;\n"
6914 /* Sub-routine */
6915 "subroutine void SubroutineTEType(inout vec4 result);\n"
6916 "\n"
6917 "subroutine(SubroutineTEType) void SubroutineTE1(inout vec4 result)\n"
6918 "{\n"
6919 " result += vec4(0, 0, "
6920 << float(n_id + 1) * 0.325f << ", 0);\n"
6921 "}\n"
6922 "subroutine(SubroutineTEType) void SubroutineTE2(inout vec4 result)\n"
6923 "{\n"
6924 " result += vec4(0, 0, "
6925 << float(n_id + 1) * 0.0325f << ", 0);\n"
6926 "}\n"
6927 "\n"
6928 "subroutine uniform SubroutineTEType function;\n"
6929 "\n"
6930 /* Input block */
6931 "in TC_DATA\n"
6932 "{\n"
6933 " vec4 data;\n"
6934 "} in_tc[];\n"
6935 "\n"
6936 /* Output block */
6937 "out TE_DATA\n"
6938 "{\n"
6939 " vec4 data;\n"
6940 "} out_te;\n"
6941 "\n"
6942 "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n"
6943 "out gl_PerVertex { vec4 gl_Position; };\n"
6944 /* main() declaration */
6945 "void main()\n"
6946 "{\n"
6947 " gl_Position = gl_in[0].gl_Position;\n"
6948 " out_te.data = in_tc[0].data;\n"
6949 "\n"
6950 " function(out_te.data);\n"
6951 "}\n";
6952
6953 return result_sstream.str();
6954 }
6955
6956 /** Retrieves body of a vertex shader that should be used for the test.
6957 * The subroutine implementations are slightly changed, depending on the
6958 * index of the shader, as specified by the caller.
6959 *
6960 * @param n_id Index of the shader.
6961 *
6962 * @return Requested string.
6963 **/
getVertexShaderBody(unsigned int n_id)6964 std::string FunctionalTest13::getVertexShaderBody(unsigned int n_id)
6965 {
6966 std::stringstream result_sstream;
6967
6968 /* Pre-amble */
6969 result_sstream << "#version 400\n"
6970 "\n"
6971 "#extension GL_ARB_shader_subroutine : require\n"
6972 "\n"
6973 /* Sub-routine */
6974 "subroutine void SubroutineVSType(inout vec4 result);\n"
6975 "\n"
6976 "subroutine(SubroutineVSType) void SubroutineVS1(inout vec4 result)\n"
6977 "{\n"
6978 " result += vec4("
6979 << float(n_id + 1) * 0.125f << ", 0, 0, 0);\n"
6980 "}\n"
6981 "subroutine(SubroutineVSType) void SubroutineVS2(inout vec4 result)\n"
6982 "{\n"
6983 " result += vec4("
6984 << float(n_id + 1) * 0.0125f << ", 0, 0, 0);\n"
6985 "}\n"
6986 "\n"
6987 "subroutine uniform SubroutineVSType function;\n"
6988 "\n"
6989 /* Output block */
6990 "out VS_DATA\n"
6991 "{\n"
6992 " vec4 data;\n"
6993 "} out_vs;\n"
6994 "\n"
6995 "out gl_PerVertex { vec4 gl_Position; };\n"
6996 /* main() declaration */
6997 "void main()\n"
6998 "{\n"
6999 " gl_Position = vec4(0, 0, 0, 1);\n"
7000 " out_vs.data = vec4(0);\n"
7001 "\n"
7002 " function(out_vs.data);\n"
7003 "\n"
7004 "}\n";
7005
7006 return result_sstream.str();
7007 }
7008
7009 /** Initializes all GL objects required to run the test. Also modifies a few
7010 * GL states in order for the test to run correctly.
7011 **/
initTest()7012 void FunctionalTest13::initTest()
7013 {
7014 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
7015
7016 /* Set up viewport */
7017 gl.viewport(0 /* x */, 0 /* y */, m_to_width, m_to_height);
7018 GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed.");
7019
7020 /* Make sure no program is used */
7021 gl.useProgram(0);
7022 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
7023
7024 /* Generate a pipeline object */
7025 gl.genProgramPipelines(1, &m_pipeline_id);
7026 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() call failed.");
7027
7028 gl.bindProgramPipeline(m_pipeline_id);
7029 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
7030
7031 /* Initialize all shader programs */
7032 for (unsigned int n_id = 0; n_id < 2 /* variants for each shader type */; ++n_id)
7033 {
7034 std::string fs_body = getFragmentShaderBody(n_id);
7035 const char* fs_body_raw_ptr = fs_body.c_str();
7036 std::string gs_body = getGeometryShaderBody(n_id);
7037 const char* gs_body_raw_ptr = gs_body.c_str();
7038 std::string tc_body = getTessellationControlShaderBody(n_id);
7039 const char* tc_body_raw_ptr = tc_body.c_str();
7040 std::string te_body = getTessellationEvaluationShaderBody(n_id);
7041 const char* te_body_raw_ptr = te_body.c_str();
7042 std::string vs_body = getVertexShaderBody(n_id);
7043 const char* vs_body_raw_ptr = vs_body.c_str();
7044
7045 m_fs_po_ids[n_id] = gl.createShaderProgramv(GL_FRAGMENT_SHADER, 1 /* count */, &fs_body_raw_ptr);
7046 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
7047
7048 m_gs_po_ids[n_id] = gl.createShaderProgramv(GL_GEOMETRY_SHADER, 1 /* count */, &gs_body_raw_ptr);
7049 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
7050
7051 m_tc_po_ids[n_id] = gl.createShaderProgramv(GL_TESS_CONTROL_SHADER, 1 /* count */, &tc_body_raw_ptr);
7052 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
7053
7054 m_te_po_ids[n_id] = gl.createShaderProgramv(GL_TESS_EVALUATION_SHADER, 1 /* count */, &te_body_raw_ptr);
7055 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
7056
7057 m_vs_po_ids[n_id] = gl.createShaderProgramv(GL_VERTEX_SHADER, 1 /* count */, &vs_body_raw_ptr);
7058 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
7059
7060 /* Verify that all shader program objects have been linked successfully */
7061 const glw::GLuint po_ids[] = {
7062 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],
7063 };
7064 const unsigned int n_po_ids = sizeof(po_ids) / sizeof(po_ids[0]);
7065
7066 for (unsigned int n_po_id = 0; n_po_id < n_po_ids; ++n_po_id)
7067 {
7068 glw::GLint link_status = GL_FALSE;
7069 glw::GLuint po_id = po_ids[n_po_id];
7070
7071 gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status);
7072 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
7073
7074 if (link_status != GL_TRUE)
7075 {
7076 TCU_FAIL("Shader program object linking failed.");
7077 }
7078 } /* for (all shader program objects) */
7079 } /* for (both shader program object variants) */
7080
7081 /* Generate a texture object. We will use the base mip-map as a render-target */
7082 gl.genTextures(1, &m_to_id);
7083 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed.");
7084
7085 gl.bindTexture(GL_TEXTURE_2D, m_to_id);
7086 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
7087
7088 gl.texStorage2D(GL_TEXTURE_2D, 1 /* levels */, GL_RGBA32F, m_to_width, m_to_height);
7089 GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed");
7090
7091 /* Generate and configure a FBO we will use for the draw call */
7092 gl.genFramebuffers(1, &m_fbo_id);
7093 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed.");
7094
7095 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
7096 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed.");
7097
7098 gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0 /* level */);
7099 GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
7100
7101 /* Generate & bind a VAO */
7102 gl.genVertexArrays(1, &m_vao_id);
7103 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
7104
7105 gl.bindVertexArray(m_vao_id);
7106 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
7107
7108 /* Set up tessellation */
7109 gl.patchParameteri(GL_PATCH_VERTICES, 1);
7110 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteri() call failed.");
7111
7112 /* Set up pixel storage alignment */
7113 gl.pixelStorei(GL_PACK_ALIGNMENT, 1);
7114 GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call failed.");
7115
7116 /* Allocate enough space to hold color attachment data */
7117 m_read_buffer = (unsigned char*)new float[m_to_width * m_to_height * 4 /* rgba */];
7118 }
7119
7120 /** Executes test iteration.
7121 *
7122 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
7123 */
iterate()7124 tcu::TestNode::IterateResult FunctionalTest13::iterate()
7125 {
7126 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
7127
7128 /* Do not execute the test if GL_ARB_shader_subroutine and GL_ARB_separate_shader_objects
7129 * are not supported */
7130 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
7131 {
7132 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
7133 }
7134
7135 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_separate_shader_objects"))
7136 {
7137 throw tcu::NotSupportedError("GL_ARB_separate_shader_objects is not supported");
7138 }
7139
7140 /* Initialize all GL objects before we continue */
7141 initTest();
7142
7143 /* Iterate over all possible FS/GS/TC/TE/VS permutations */
7144 for (int n_shader_permutation = 0; n_shader_permutation < 32 /* 2^5 */; ++n_shader_permutation)
7145 {
7146 const unsigned int n_fs_idx = ((n_shader_permutation & (1 << 0)) != 0) ? 1 : 0;
7147 const unsigned int n_gs_idx = ((n_shader_permutation & (1 << 1)) != 0) ? 1 : 0;
7148 const unsigned int n_tc_idx = ((n_shader_permutation & (1 << 2)) != 0) ? 1 : 0;
7149 const unsigned int n_te_idx = ((n_shader_permutation & (1 << 3)) != 0) ? 1 : 0;
7150 const unsigned int n_vs_idx = ((n_shader_permutation & (1 << 4)) != 0) ? 1 : 0;
7151 const unsigned int fs_po_id = m_fs_po_ids[n_fs_idx];
7152 const unsigned int gs_po_id = m_gs_po_ids[n_gs_idx];
7153 const unsigned int tc_po_id = m_tc_po_ids[n_tc_idx];
7154 const unsigned int te_po_id = m_te_po_ids[n_te_idx];
7155 const unsigned int vs_po_id = m_vs_po_ids[n_vs_idx];
7156
7157 /* Configure fragment shader stage */
7158 gl.useProgramStages(m_pipeline_id, GL_FRAGMENT_SHADER_BIT, fs_po_id);
7159 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed for GL_FRAGMENT_SHADER_BIT bit");
7160
7161 /* Configure geometry shader stage */
7162 gl.useProgramStages(m_pipeline_id, GL_GEOMETRY_SHADER_BIT, gs_po_id);
7163 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed for GL_GEOMETRY_SHADER_BIT bit");
7164
7165 /* Configure tessellation control shader stage */
7166 gl.useProgramStages(m_pipeline_id, GL_TESS_CONTROL_SHADER_BIT, tc_po_id);
7167 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed for GL_TESS_CONTROL_SHADER_BIT bit");
7168
7169 /* Configure tessellation evaluation shader stage */
7170 gl.useProgramStages(m_pipeline_id, GL_TESS_EVALUATION_SHADER_BIT, te_po_id);
7171 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed for GL_TESS_EVALUATION_SHADER_BIT bit");
7172
7173 /* Configure vertex shader stage */
7174 gl.useProgramStages(m_pipeline_id, GL_VERTEX_SHADER_BIT, vs_po_id);
7175 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed for GL_VERTEX_SHADER_BIT bit");
7176
7177 /* Validate the pipeline */
7178 glw::GLint validate_status = GL_FALSE;
7179
7180 gl.validateProgramPipeline(m_pipeline_id);
7181 GLU_EXPECT_NO_ERROR(gl.getError(), "glValidateProgramPipeline() call failed.");
7182
7183 gl.getProgramPipelineiv(m_pipeline_id, GL_VALIDATE_STATUS, &validate_status);
7184 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramPipelineiv() call failed.");
7185
7186 if (validate_status != GL_TRUE)
7187 {
7188 TCU_FAIL("Program pipeline has not been validated successfully.");
7189 }
7190
7191 /* Retrieve subroutine indices */
7192 GLuint fs_subroutine_indices[2] = { (GLuint)-1 };
7193 GLint fs_subroutine_uniform_index = 0;
7194 GLuint gs_subroutine_indices[2] = { (GLuint)-1 };
7195 GLint gs_subroutine_uniform_index = 0;
7196 GLuint tc_subroutine_indices[2] = { (GLuint)-1 };
7197 GLint tc_subroutine_uniform_index = 0;
7198 GLuint te_subroutine_indices[2] = { (GLuint)-1 };
7199 GLint te_subroutine_uniform_index = 0;
7200 GLuint vs_subroutine_indices[2] = { (GLuint)-1 };
7201 GLint vs_subroutine_uniform_index = 0;
7202
7203 for (unsigned int n_subroutine = 0; n_subroutine < 2; ++n_subroutine)
7204 {
7205 std::stringstream fs_subroutine_name_sstream;
7206 std::stringstream gs_subroutine_name_sstream;
7207 std::stringstream tc_subroutine_name_sstream;
7208 std::stringstream te_subroutine_name_sstream;
7209 std::stringstream vs_subroutine_name_sstream;
7210
7211 fs_subroutine_name_sstream << "SubroutineFS" << (n_subroutine + 1);
7212 gs_subroutine_name_sstream << "SubroutineGS" << (n_subroutine + 1);
7213 tc_subroutine_name_sstream << "SubroutineTC" << (n_subroutine + 1);
7214 te_subroutine_name_sstream << "SubroutineTE" << (n_subroutine + 1);
7215 vs_subroutine_name_sstream << "SubroutineVS" << (n_subroutine + 1);
7216
7217 fs_subroutine_indices[n_subroutine] =
7218 gl.getSubroutineIndex(fs_po_id, GL_FRAGMENT_SHADER, fs_subroutine_name_sstream.str().c_str());
7219 gs_subroutine_indices[n_subroutine] =
7220 gl.getSubroutineIndex(gs_po_id, GL_GEOMETRY_SHADER, gs_subroutine_name_sstream.str().c_str());
7221 tc_subroutine_indices[n_subroutine] =
7222 gl.getSubroutineIndex(tc_po_id, GL_TESS_CONTROL_SHADER, tc_subroutine_name_sstream.str().c_str());
7223 te_subroutine_indices[n_subroutine] =
7224 gl.getSubroutineIndex(te_po_id, GL_TESS_EVALUATION_SHADER, te_subroutine_name_sstream.str().c_str());
7225 vs_subroutine_indices[n_subroutine] =
7226 gl.getSubroutineIndex(vs_po_id, GL_VERTEX_SHADER, vs_subroutine_name_sstream.str().c_str());
7227 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineIndex() call(s) failed.");
7228
7229 if (fs_subroutine_indices[n_subroutine] == (GLuint)-1 ||
7230 gs_subroutine_indices[n_subroutine] == (GLuint)-1 ||
7231 tc_subroutine_indices[n_subroutine] == (GLuint)-1 ||
7232 te_subroutine_indices[n_subroutine] == (GLuint)-1 || vs_subroutine_indices[n_subroutine] == (GLuint)-1)
7233 {
7234 m_testCtx.getLog() << tcu::TestLog::Message
7235 << "At least one subroutine was not recognized by glGetSubroutineIndex() call. "
7236 "(fs:"
7237 << fs_subroutine_indices[n_subroutine]
7238 << ", gs:" << gs_subroutine_indices[n_subroutine]
7239 << ", tc:" << tc_subroutine_indices[n_subroutine]
7240 << ", te:" << te_subroutine_indices[n_subroutine]
7241 << ", vs:" << vs_subroutine_indices[n_subroutine] << ")."
7242 << tcu::TestLog::EndMessage;
7243
7244 TCU_FAIL("At least one subroutine was not recognized");
7245 }
7246 } /* for (both subroutines) */
7247
7248 /* Retrieve subroutine uniform indices */
7249 fs_subroutine_uniform_index = gl.getSubroutineUniformLocation(fs_po_id, GL_FRAGMENT_SHADER, "function");
7250 gs_subroutine_uniform_index = gl.getSubroutineUniformLocation(gs_po_id, GL_GEOMETRY_SHADER, "function");
7251 tc_subroutine_uniform_index = gl.getSubroutineUniformLocation(tc_po_id, GL_TESS_CONTROL_SHADER, "function");
7252 te_subroutine_uniform_index = gl.getSubroutineUniformLocation(te_po_id, GL_TESS_EVALUATION_SHADER, "function");
7253 vs_subroutine_uniform_index = gl.getSubroutineUniformLocation(vs_po_id, GL_VERTEX_SHADER, "function");
7254
7255 if (fs_subroutine_uniform_index == -1 || gs_subroutine_uniform_index == -1 ||
7256 tc_subroutine_uniform_index == -1 || te_subroutine_uniform_index == -1 || vs_subroutine_uniform_index == -1)
7257 {
7258 m_testCtx.getLog() << tcu::TestLog::Message << "At least one subroutine uniform is considered inactive by "
7259 "glGetSubroutineUniformLocation ("
7260 "fs:"
7261 << fs_subroutine_uniform_index << ", gs:" << gs_subroutine_uniform_index
7262 << ", tc:" << tc_subroutine_uniform_index << ", te:" << te_subroutine_uniform_index
7263 << ", vs:" << vs_subroutine_uniform_index << ")." << tcu::TestLog::EndMessage;
7264
7265 TCU_FAIL("At least one subroutine uniform is considered inactive");
7266 }
7267
7268 /* Check if both subroutines work correctly in each stage */
7269 for (int n_subroutine_permutation = 0; n_subroutine_permutation < 32; /* 2^5 */
7270 ++n_subroutine_permutation)
7271 {
7272 unsigned int n_fs_subroutine = ((n_subroutine_permutation & (1 << 0)) != 0) ? 1 : 0;
7273 unsigned int n_gs_subroutine = ((n_subroutine_permutation & (1 << 1)) != 0) ? 1 : 0;
7274 unsigned int n_tc_subroutine = ((n_subroutine_permutation & (1 << 2)) != 0) ? 1 : 0;
7275 unsigned int n_te_subroutine = ((n_subroutine_permutation & (1 << 3)) != 0) ? 1 : 0;
7276 unsigned int n_vs_subroutine = ((n_subroutine_permutation & (1 << 4)) != 0) ? 1 : 0;
7277
7278 /* Configure subroutine uniforms */
7279 struct
7280 {
7281 glw::GLenum stage;
7282 glw::GLuint po_id;
7283 glw::GLuint* indices;
7284 } configurations[] = {
7285 { GL_FRAGMENT_SHADER, fs_po_id, fs_subroutine_indices + n_fs_subroutine },
7286 { GL_GEOMETRY_SHADER, gs_po_id, gs_subroutine_indices + n_gs_subroutine },
7287 { GL_TESS_CONTROL_SHADER, tc_po_id, tc_subroutine_indices + n_tc_subroutine },
7288 { GL_TESS_EVALUATION_SHADER, te_po_id, te_subroutine_indices + n_te_subroutine },
7289 { GL_VERTEX_SHADER, vs_po_id, vs_subroutine_indices + n_vs_subroutine },
7290 };
7291
7292 for (int i = 0; i < 5; ++i)
7293 {
7294 gl.activeShaderProgram(m_pipeline_id, configurations[i].po_id);
7295 GLU_EXPECT_NO_ERROR(gl.getError(), "glActiveShaderProgram() call failed.");
7296
7297 gl.uniformSubroutinesuiv(configurations[i].stage, 1 /* count */, configurations[i].indices);
7298 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniformSubroutinesuiv() call failed.");
7299 }
7300
7301 /* Render a full-screen quad with the pipeline */
7302 gl.clear(GL_COLOR_BUFFER_BIT);
7303 GLU_EXPECT_NO_ERROR(gl.getError(), "glClear() call failed.");
7304
7305 gl.drawArrays(GL_PATCHES, 0 /* first */, 1 /* count */);
7306 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
7307
7308 /* Read color attachment's contents */
7309 gl.readPixels(0, /* x */
7310 0, /* y */
7311 m_to_width, m_to_height, GL_RGBA, GL_FLOAT, m_read_buffer);
7312 GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed.");
7313
7314 /* Verify the contents */
7315 verifyReadBuffer(n_fs_idx, n_fs_subroutine, n_gs_idx, n_gs_subroutine, n_tc_idx, n_tc_subroutine, n_te_idx,
7316 n_te_subroutine, n_vs_idx, n_vs_subroutine);
7317 } /* for (all subroutine permutations) */
7318 } /* for (all program shader object permutations) */
7319
7320 /** All done */
7321 if (m_has_test_passed)
7322 {
7323 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
7324 }
7325 else
7326 {
7327 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
7328 }
7329
7330 return STOP;
7331 }
7332
7333 /** Verifies the data that have been rendered using a pipeline object.
7334 * Contents of the data depends on indices of the shaders, as well as
7335 * on the subroutines that have been activated for particular iteration.
7336 *
7337 * @param n_fs_id Index of the fragment shader used for the iteration;
7338 * @param n_fs_subroutine Index of the subroutine used in the fragment shader
7339 * for the iteration;
7340 * @param n_gs_id Index of the geometry shader used for the iteration;
7341 * @param n_gs_subroutine Index of the subroutine used in the geometry shader
7342 * for the iteration;
7343 * @param n_tc_id Index of the tessellation control shader used for the iteration;
7344 * @param n_tc_subroutine Index of the subroutine used in the tessellation control
7345 * shader for the iteration;
7346 * @param n_te_id Index of the tessellation evaluation shader used for the iteration;
7347 * @param n_te_subroutine Index of the subroutine used in the tessellation evaluation
7348 * shader for the iteration;
7349 * @param n_vs_id Index of the vertex shader used for the iteration;
7350 * @param n_vs_subroutine Index of the subroutine used in the vertex shader for
7351 * the iteration.
7352 */
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)7353 void FunctionalTest13::verifyReadBuffer(unsigned int n_fs_id, unsigned int n_fs_subroutine, unsigned int n_gs_id,
7354 unsigned int n_gs_subroutine, unsigned int n_tc_id,
7355 unsigned int n_tc_subroutine, unsigned int n_te_id,
7356 unsigned int n_te_subroutine, unsigned int n_vs_id,
7357 unsigned int n_vs_subroutine)
7358 {
7359 float expected_color[4] = { 0 };
7360 float fs_modifier[4] = { 0 };
7361 float gs_modifier[4] = { 0 };
7362 float tc_modifier[4] = { 0 };
7363 float te_modifier[4] = { 0 };
7364 float vs_modifier[4] = { 0 };
7365
7366 if (n_fs_subroutine == 0)
7367 {
7368 for (unsigned int n_component = 0; n_component < 4; ++n_component)
7369 {
7370 fs_modifier[n_component] = float(n_fs_id + n_component + 1) / 10.0f;
7371 }
7372 }
7373 else
7374 {
7375 for (unsigned int n_component = 0; n_component < 4; ++n_component)
7376 {
7377 fs_modifier[n_component] = float(n_fs_id + n_component + 1) / 20.0f;
7378 }
7379 }
7380
7381 if (n_gs_subroutine == 0)
7382 {
7383 gs_modifier[3] = float(n_gs_id + 1) * 0.425f;
7384 }
7385 else
7386 {
7387 gs_modifier[3] = float(n_gs_id + 1) * 0.0425f;
7388 }
7389
7390 if (n_tc_subroutine == 0)
7391 {
7392 tc_modifier[1] = float(n_tc_id + 1) * 0.25f;
7393 }
7394 else
7395 {
7396 tc_modifier[1] = float(n_tc_id + 1) * 0.025f;
7397 }
7398
7399 if (n_te_subroutine == 0)
7400 {
7401 te_modifier[2] = float(n_te_id + 1) * 0.325f;
7402 }
7403 else
7404 {
7405 te_modifier[2] = float(n_te_id + 1) * 0.0325f;
7406 }
7407
7408 if (n_vs_subroutine == 0)
7409 {
7410 vs_modifier[0] = float(n_vs_id + 1) * 0.125f;
7411 }
7412 else
7413 {
7414 vs_modifier[0] = float(n_vs_id + 1) * 0.0125f;
7415 }
7416
7417 /* Determine the expected color */
7418 for (unsigned int n_component = 0; n_component < 4 /* rgba */; ++n_component)
7419 {
7420 expected_color[n_component] = fs_modifier[n_component] + gs_modifier[n_component] + tc_modifier[n_component] +
7421 te_modifier[n_component] + vs_modifier[n_component];
7422 }
7423
7424 /* Verify all read texels are valid */
7425 const float epsilon = 1e-5f;
7426 bool should_continue = true;
7427
7428 for (unsigned int y = 0; y < m_to_height && should_continue; ++y)
7429 {
7430 const float* row_ptr = (const float*)m_read_buffer + y * m_to_width * 4; /* rgba */
7431
7432 for (unsigned int x = 0; x < m_to_width && should_continue; ++x)
7433 {
7434 const float* texel_ptr = row_ptr + x * 4; /* rgba */
7435
7436 if (de::abs(texel_ptr[0] - expected_color[0]) > epsilon ||
7437 de::abs(texel_ptr[1] - expected_color[1]) > epsilon ||
7438 de::abs(texel_ptr[2] - expected_color[2]) > epsilon ||
7439 de::abs(texel_ptr[3] - expected_color[3]) > epsilon)
7440 {
7441 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid texel rendered at (" << x << ", " << y
7442 << ") for "
7443 "the following configuration: "
7444 "n_fs_id:"
7445 << n_fs_id << " n_fs_subroutine:" << n_fs_subroutine << " n_gs_id:" << n_gs_id
7446 << " n_gs_subroutine:" << n_gs_subroutine << " n_tc_id:" << n_tc_id
7447 << " n_tc_subroutine:" << n_tc_subroutine << " n_te_id:" << n_te_id
7448 << " n_te_subroutine:" << n_te_subroutine << " n_vs_id:" << n_vs_id
7449 << " n_vs_subroutine:" << n_vs_subroutine << "; expected:"
7450 "("
7451 << expected_color[0] << ", " << expected_color[1] << ", " << expected_color[2]
7452 << ", " << expected_color[3] << "), found:"
7453 "("
7454 << texel_ptr[0] << ", " << texel_ptr[1] << ", " << texel_ptr[2] << ", "
7455 << texel_ptr[3] << ")." << tcu::TestLog::EndMessage;
7456
7457 m_has_test_passed = false;
7458 should_continue = false;
7459 }
7460 } /* for (all columns) */
7461 } /* for (all rows) */
7462 }
7463
7464 /** Constructor
7465 *
7466 * @param context CTS context
7467 **/
FunctionalTest14_15(deqp::Context & context)7468 FunctionalTest14_15::FunctionalTest14_15(deqp::Context& context)
7469 : TestCase(context, "structure_parameters_program_binary", "Verify structures can be used as parameters")
7470 , m_uniform_location(0)
7471 {
7472 }
7473
7474 /** Execute test
7475 *
7476 * @return tcu::TestNode::STOP
7477 **/
iterate()7478 tcu::TestNode::IterateResult FunctionalTest14_15::iterate()
7479 {
7480 static const GLchar* vertex_shader_code =
7481 "#version 400 core\n"
7482 "#extension GL_ARB_shader_subroutine : require\n"
7483 "\n"
7484 "precision highp float;\n"
7485 "\n"
7486 "struct data\n"
7487 "{\n"
7488 " uint r;\n"
7489 " uint g;\n"
7490 " uint b;\n"
7491 " uint a;\n"
7492 "};\n"
7493 "\n"
7494 "subroutine void routine_type_1(in data iparam, out data oparam);\n"
7495 "subroutine void routine_type_2(inout data arg);\n"
7496 "\n"
7497 "subroutine (routine_type_1) void invert(in data iparam, out data oparam)\n"
7498 "{\n"
7499 " oparam.r = iparam.a;\n"
7500 " oparam.g = iparam.b;\n"
7501 " oparam.b = iparam.g;\n"
7502 " oparam.a = iparam.r;\n"
7503 "}\n"
7504 "\n"
7505 "subroutine (routine_type_1) void increment(in data iparam, out data oparam)\n"
7506 "{\n"
7507 " oparam.r = 1 + iparam.r;\n"
7508 " oparam.g = 1 + iparam.g;\n"
7509 " oparam.b = 1 + iparam.b;\n"
7510 " oparam.a = 1 + iparam.a;\n"
7511 "}\n"
7512 "\n"
7513 "subroutine (routine_type_2) void div_by_2(inout data arg)\n"
7514 "{\n"
7515 " arg.r = arg.r / 2;\n"
7516 " arg.g = arg.g / 2;\n"
7517 " arg.b = arg.b / 2;\n"
7518 " arg.a = arg.a / 2;\n"
7519 "}\n"
7520 "\n"
7521 "subroutine (routine_type_2) void decrement(inout data arg)\n"
7522 "{\n"
7523 " arg.r = arg.r - 1;\n"
7524 " arg.g = arg.g - 1;\n"
7525 " arg.b = arg.b - 1;\n"
7526 " arg.a = arg.a - 1;\n"
7527 "}\n"
7528 "\n"
7529 "subroutine uniform routine_type_1 routine_1;\n"
7530 "subroutine uniform routine_type_2 routine_2;\n"
7531 "\n"
7532 "uniform uvec4 uni_input;\n"
7533 "\n"
7534 "out uvec4 out_routine_1;\n"
7535 "out uvec4 out_routine_2;\n"
7536 "\n"
7537 "\n"
7538 "void main()\n"
7539 "{\n"
7540 " data routine_1_input;\n"
7541 " data routine_1_output;\n"
7542 " data routine_2_arg;\n"
7543 "\n"
7544 " routine_1_input.r = uni_input.r;\n"
7545 " routine_1_input.g = uni_input.g;\n"
7546 " routine_1_input.b = uni_input.b;\n"
7547 " routine_1_input.a = uni_input.a;\n"
7548 "\n"
7549 " routine_2_arg.r = uni_input.r;\n"
7550 " routine_2_arg.g = uni_input.g;\n"
7551 " routine_2_arg.b = uni_input.b;\n"
7552 " routine_2_arg.a = uni_input.a;\n"
7553 "\n"
7554 " routine_1(routine_1_input, routine_1_output);\n"
7555 " routine_2(routine_2_arg);\n"
7556 "\n"
7557 " out_routine_1.r = routine_1_output.r;\n"
7558 " out_routine_1.g = routine_1_output.g;\n"
7559 " out_routine_1.b = routine_1_output.b;\n"
7560 " out_routine_1.a = routine_1_output.a;\n"
7561 "\n"
7562 " out_routine_2.r = routine_2_arg.r;\n"
7563 " out_routine_2.g = routine_2_arg.g;\n"
7564 " out_routine_2.b = routine_2_arg.b;\n"
7565 " out_routine_2.a = routine_2_arg.a;\n"
7566 "}\n"
7567 "\n";
7568
7569 static const GLchar* subroutine_names[][2] = { { "invert", "increment" }, { "div_by_2", "decrement" } };
7570 static const GLuint n_subroutine_types = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
7571
7572 static const GLchar* subroutine_uniform_names[] = { "routine_1", "routine_2" };
7573 static const GLuint n_subroutine_uniform_names =
7574 sizeof(subroutine_uniform_names) / sizeof(subroutine_uniform_names[0]);
7575
7576 static const GLchar* uniform_name = "uni_input";
7577 static const GLchar* varying_names[] = { "out_routine_1", "out_routine_2" };
7578
7579 static const GLuint n_varying_names = sizeof(varying_names) / sizeof(varying_names[0]);
7580 static const GLuint transform_feedback_buffer_size = n_varying_names * 4 * sizeof(GLuint);
7581
7582 /* Test data */
7583 static const Utils::vec4<GLuint> uni_input[] = { Utils::vec4<GLuint>(8, 64, 4096, 16777216),
7584 Utils::vec4<GLuint>(8, 64, 4096, 16777216) };
7585
7586 static const Utils::vec4<GLuint> out_routine_1[] = { Utils::vec4<GLuint>(16777216, 4096, 64, 8),
7587 Utils::vec4<GLuint>(9, 65, 4097, 16777217) };
7588
7589 static const Utils::vec4<GLuint> out_routine_2[] = { Utils::vec4<GLuint>(4, 32, 2048, 8388608),
7590 Utils::vec4<GLuint>(7, 63, 4095, 16777215) };
7591
7592 static const GLuint n_test_cases = 2;
7593
7594 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
7595 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
7596 {
7597 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
7598 }
7599
7600 /* GL objects */
7601 Utils::program program(m_context);
7602 Utils::buffer transform_feedback_buffer(m_context);
7603 Utils::vertexArray vao(m_context);
7604
7605 bool is_program_binary_supported = program.isProgramBinarySupported();
7606
7607 /* Init GL objects */
7608 program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code,
7609 varying_names /* varying_names */, n_varying_names /* n_varyings */);
7610
7611 /* Do not execute the test if GL_ARB_get_program_binary is not supported */
7612 if (true == is_program_binary_supported)
7613 {
7614 /* Get subroutine indices */
7615 for (GLuint type = 0; type < n_subroutine_types; ++type)
7616 {
7617 m_initial_subroutine_indices[type][0] =
7618 program.getSubroutineIndex(subroutine_names[type][0], GL_VERTEX_SHADER);
7619
7620 m_initial_subroutine_indices[type][1] =
7621 program.getSubroutineIndex(subroutine_names[type][1], GL_VERTEX_SHADER);
7622 }
7623
7624 /* Get subroutine uniform locations */
7625 for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
7626 {
7627 m_initial_subroutine_uniform_locations[uniform] =
7628 program.getSubroutineUniformLocation(subroutine_uniform_names[uniform], GL_VERTEX_SHADER);
7629 }
7630
7631 /* Delete program and recreate it from binary */
7632 std::vector<GLubyte> program_binary;
7633 GLenum binary_format;
7634
7635 program.getBinary(program_binary, binary_format);
7636 program.remove();
7637 program.createFromBinary(program_binary, binary_format);
7638 }
7639
7640 program.use();
7641
7642 vao.generate();
7643 vao.bind();
7644
7645 transform_feedback_buffer.generate();
7646 transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
7647 GL_DYNAMIC_COPY);
7648 transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
7649
7650 /* Get subroutine indices */
7651 for (GLuint type = 0; type < n_subroutine_types; ++type)
7652 {
7653 m_subroutine_indices[type][0] = program.getSubroutineIndex(subroutine_names[type][0], GL_VERTEX_SHADER);
7654 m_subroutine_indices[type][1] = program.getSubroutineIndex(subroutine_names[type][1], GL_VERTEX_SHADER);
7655 }
7656
7657 /* Get subroutine uniform locations */
7658 for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
7659 {
7660 m_subroutine_uniform_locations[uniform] =
7661 program.getSubroutineUniformLocation(subroutine_uniform_names[uniform], GL_VERTEX_SHADER);
7662 }
7663
7664 /* Get uniform locations */
7665 m_uniform_location = program.getUniformLocation(uniform_name);
7666
7667 /* Test */
7668 bool result = true;
7669
7670 /* Test program binary */
7671 if (true == is_program_binary_supported)
7672 {
7673 /* Test indices and locations */
7674 if (false == testIndicesAndLocations())
7675 {
7676 static const GLuint n_subroutines_per_type = 2;
7677
7678 m_context.getTestContext().getLog() << tcu::TestLog::Message
7679 << "Error. Subroutine indices or subroutine uniform location changed."
7680 << tcu::TestLog::EndMessage;
7681
7682 for (GLuint type = 0; type < n_subroutine_types; ++type)
7683 {
7684 for (GLuint i = 0; i < n_subroutines_per_type; ++i)
7685 {
7686 m_context.getTestContext().getLog()
7687 << tcu::TestLog::Message << "Subroutine: " << subroutine_names[type][i]
7688 << " index: " << m_subroutine_indices[type][i]
7689 << " initial index: " << m_initial_subroutine_indices[type][i] << tcu::TestLog::EndMessage;
7690 }
7691 }
7692
7693 for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
7694 {
7695 m_context.getTestContext().getLog()
7696 << tcu::TestLog::Message << "Subroutine uniform: " << subroutine_uniform_names[uniform]
7697 << " location: " << m_subroutine_uniform_locations[uniform]
7698 << " initial location: " << m_initial_subroutine_uniform_locations[uniform]
7699 << tcu::TestLog::EndMessage;
7700 }
7701
7702 result = false;
7703 }
7704
7705 /* Test draw with deafult set of subroutines */
7706 if (false == testDefaultSubroutineSet(uni_input[0], out_routine_1, out_routine_2))
7707 {
7708 result = false;
7709 }
7710 }
7711
7712 for (GLuint i = 0; i < n_test_cases; ++i)
7713 {
7714 if (false == testDraw(i, uni_input[i], out_routine_1[i], out_routine_2[i]))
7715 {
7716 result = false;
7717 }
7718 }
7719
7720 /* Set result */
7721 if (true == result)
7722 {
7723 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
7724 }
7725 else
7726 {
7727 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
7728 }
7729
7730 /* Done */
7731 return tcu::TestNode::STOP;
7732 }
7733
7734 /** Execute draw call and verify results
7735 *
7736 * @param uni_input Input data
7737 * @param expected_routine_1_result Set of expected results of "routine_1"
7738 * @param expected_routine_2_result Set of expected results of "routine_2"
7739 *
7740 * @return true if test pass, false otherwise
7741 **/
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]) const7742 bool FunctionalTest14_15::testDefaultSubroutineSet(const Utils::vec4<glw::GLuint>& uni_input,
7743 const Utils::vec4<glw::GLuint> expected_routine_1_result[2],
7744 const Utils::vec4<glw::GLuint> expected_routine_2_result[2]) const
7745 {
7746 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
7747 bool result = true;
7748
7749 /* Set up input data uniforms */
7750 gl.uniform4ui(m_uniform_location, uni_input.m_x, uni_input.m_y, uni_input.m_z, uni_input.m_w);
7751 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
7752
7753 /* Execute draw call with transform feedback */
7754 gl.beginTransformFeedback(GL_POINTS);
7755 GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
7756
7757 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
7758 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
7759
7760 gl.endTransformFeedback();
7761 GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
7762
7763 /* Capture results */
7764 GLuint* feedback_data = (GLuint*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
7765 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
7766
7767 Utils::vec4<GLuint> routine_1_result;
7768 Utils::vec4<GLuint> routine_2_result;
7769
7770 routine_1_result.m_x = feedback_data[0 + 0];
7771 routine_1_result.m_y = feedback_data[0 + 1];
7772 routine_1_result.m_z = feedback_data[0 + 2];
7773 routine_1_result.m_w = feedback_data[0 + 3];
7774
7775 routine_2_result.m_x = feedback_data[4 + 0];
7776 routine_2_result.m_y = feedback_data[4 + 1];
7777 routine_2_result.m_z = feedback_data[4 + 2];
7778 routine_2_result.m_w = feedback_data[4 + 3];
7779
7780 /* Unmap buffer */
7781 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
7782 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
7783
7784 /* Verifiy */
7785 result = result &&
7786 ((routine_1_result == expected_routine_1_result[0]) || (routine_1_result == expected_routine_1_result[1]));
7787
7788 result = result &&
7789 ((routine_2_result == expected_routine_2_result[0]) || (routine_2_result == expected_routine_2_result[1]));
7790
7791 /* Log error if any */
7792 if (false == result)
7793 {
7794 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error. Invalid result."
7795 << tcu::TestLog::EndMessage;
7796
7797 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
7798
7799 message << "Routine_1, result: ";
7800
7801 routine_1_result.log(message);
7802
7803 message << "Routine_2, result: ";
7804
7805 routine_2_result.log(message);
7806
7807 message << tcu::TestLog::EndMessage;
7808 }
7809
7810 /* Done */
7811 return result;
7812 }
7813
7814 /** Execute draw call and verify results
7815 *
7816 * @param routine_configuration Subroutine "type" ordinal
7817 * @param uni_input Input data
7818 * @param expected_routine_1_result Expected results of "routine_1"
7819 * @param expected_routine_2_result Expected results of "routine_2"
7820 *
7821 * @return true if test pass, false otherwise
7822 **/
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) const7823 bool FunctionalTest14_15::testDraw(glw::GLuint routine_configuration, const Utils::vec4<glw::GLuint>& uni_input,
7824 const Utils::vec4<glw::GLuint>& expected_routine_1_result,
7825 const Utils::vec4<glw::GLuint>& expected_routine_2_result) const
7826 {
7827 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
7828 bool result = true;
7829 GLuint subroutine_indices[2];
7830 static const GLuint n_subroutine_uniforms = sizeof(subroutine_indices) / sizeof(subroutine_indices[0]);
7831
7832 /* Set up input data uniforms */
7833 gl.uniform4ui(m_uniform_location, uni_input.m_x, uni_input.m_y, uni_input.m_z, uni_input.m_w);
7834 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
7835
7836 /* Prepare subroutine uniform data */
7837 for (GLuint i = 0; i < n_subroutine_uniforms; ++i)
7838 {
7839 const GLuint location = m_subroutine_uniform_locations[i];
7840
7841 subroutine_indices[location] = m_subroutine_indices[i][routine_configuration];
7842 }
7843
7844 /* Set up subroutine uniforms */
7845 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, n_subroutine_uniforms, &subroutine_indices[0]);
7846 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
7847
7848 /* Execute draw call with transform feedback */
7849 gl.beginTransformFeedback(GL_POINTS);
7850 GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
7851
7852 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
7853 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
7854
7855 gl.endTransformFeedback();
7856 GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
7857
7858 /* Capture results */
7859 GLuint* feedback_data = (GLuint*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
7860 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
7861
7862 Utils::vec4<GLuint> routine_1_result;
7863 Utils::vec4<GLuint> routine_2_result;
7864
7865 routine_1_result.m_x = feedback_data[0 + 0];
7866 routine_1_result.m_y = feedback_data[0 + 1];
7867 routine_1_result.m_z = feedback_data[0 + 2];
7868 routine_1_result.m_w = feedback_data[0 + 3];
7869
7870 routine_2_result.m_x = feedback_data[4 + 0];
7871 routine_2_result.m_y = feedback_data[4 + 1];
7872 routine_2_result.m_z = feedback_data[4 + 2];
7873 routine_2_result.m_w = feedback_data[4 + 3];
7874
7875 /* Unmap buffer */
7876 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
7877 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
7878
7879 /* Verifiy */
7880 result = result && (routine_1_result == expected_routine_1_result);
7881 result = result && (routine_2_result == expected_routine_2_result);
7882
7883 /* Log error if any */
7884 if (false == result)
7885 {
7886 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error. Invalid result."
7887 << tcu::TestLog::EndMessage;
7888
7889 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
7890
7891 message << "Routine_1, result: ";
7892
7893 routine_1_result.log(message);
7894
7895 message << ", expected: ";
7896
7897 expected_routine_1_result.log(message);
7898
7899 message << "Routine_2, result: ";
7900
7901 routine_2_result.log(message);
7902
7903 message << ", expected: ";
7904
7905 expected_routine_2_result.log(message);
7906
7907 message << tcu::TestLog::EndMessage;
7908 }
7909
7910 /* Done */
7911 return result;
7912 }
7913
7914 /** Verify initial and current values of subroutine indices and subroutines uniform locations
7915 *
7916 * @return true if test pass, false otherwise
7917 **/
testIndicesAndLocations() const7918 bool FunctionalTest14_15::testIndicesAndLocations() const
7919 {
7920 static const GLuint n_subroutine_types = 2;
7921 bool result = true;
7922
7923 /* Verify subroutine indices */
7924 for (GLuint type = 0; type < n_subroutine_types; ++type)
7925 {
7926 result = result && (m_subroutine_indices[type][0] == m_initial_subroutine_indices[type][0]);
7927 result = result && (m_subroutine_indices[type][1] == m_initial_subroutine_indices[type][1]);
7928 }
7929
7930 /* Verify subroutine uniform locations */
7931 for (GLuint uniform = 0; uniform < n_subroutine_types; ++uniform)
7932 {
7933 result = result && (m_subroutine_uniform_locations[uniform] == m_initial_subroutine_uniform_locations[uniform]);
7934 }
7935
7936 return result;
7937 }
7938
7939 /** Constructor.
7940 *
7941 * @param context Rendering context.
7942 *
7943 **/
FunctionalTest16(deqp::Context & context)7944 FunctionalTest16::FunctionalTest16(deqp::Context& context)
7945 : TestCase(context, "subroutine_uniform_reset",
7946 "Checks that when the active program for a shader stage is re-linke or "
7947 "changed by a call to UseProgram, BindProgramPipeline, or UseProgramStages,"
7948 " subroutine uniforms for that stage are reset to arbitrarily chosen default "
7949 "functions with compatible subroutine types.")
7950 , m_are_pipeline_objects_supported(false)
7951 , m_has_test_passed(true)
7952 {
7953 memset(m_fs_ids, 0, sizeof(m_fs_ids));
7954 memset(m_gs_ids, 0, sizeof(m_gs_ids));
7955 memset(m_po_ids, 0, sizeof(m_po_ids));
7956 memset(m_tc_ids, 0, sizeof(m_tc_ids));
7957 memset(m_te_ids, 0, sizeof(m_te_ids));
7958 memset(m_vs_ids, 0, sizeof(m_vs_ids));
7959
7960 memset(m_fs_po_ids, 0, sizeof(m_fs_po_ids));
7961 memset(m_gs_po_ids, 0, sizeof(m_gs_po_ids));
7962 memset(m_pipeline_object_ids, 0, sizeof(m_pipeline_object_ids));
7963 memset(m_tc_po_ids, 0, sizeof(m_tc_po_ids));
7964 memset(m_te_po_ids, 0, sizeof(m_te_po_ids));
7965 memset(m_vs_po_ids, 0, sizeof(m_vs_po_ids));
7966 }
7967
7968 /** Deinitializes all GL objects that may have been created during test execution. */
deinit()7969 void FunctionalTest16::deinit()
7970 {
7971 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
7972
7973 for (unsigned int n_id = 0; n_id < 2; ++n_id)
7974 {
7975 if (m_fs_ids[n_id] != 0)
7976 {
7977 gl.deleteShader(m_fs_ids[n_id]);
7978
7979 m_fs_ids[n_id] = 0;
7980 }
7981
7982 if (m_fs_po_ids[n_id] != 0)
7983 {
7984 gl.deleteProgram(m_fs_po_ids[n_id]);
7985
7986 m_fs_po_ids[n_id] = 0;
7987 }
7988
7989 if (m_gs_ids[n_id] != 0)
7990 {
7991 gl.deleteShader(m_gs_ids[n_id]);
7992
7993 m_gs_ids[n_id] = 0;
7994 }
7995
7996 if (m_gs_po_ids[n_id] != 0)
7997 {
7998 gl.deleteProgram(m_gs_po_ids[n_id]);
7999
8000 m_gs_po_ids[n_id] = 0;
8001 }
8002
8003 if (m_pipeline_object_ids[n_id] != 0)
8004 {
8005 gl.deleteProgramPipelines(1 /* n */, m_pipeline_object_ids + n_id);
8006 }
8007
8008 if (m_po_ids[n_id] != 0)
8009 {
8010 gl.deleteProgram(m_po_ids[n_id]);
8011
8012 m_po_ids[n_id] = 0;
8013 }
8014
8015 if (m_tc_ids[n_id] != 0)
8016 {
8017 gl.deleteShader(m_tc_ids[n_id]);
8018
8019 m_tc_ids[n_id] = 0;
8020 }
8021
8022 if (m_tc_po_ids[n_id] != 0)
8023 {
8024 gl.deleteProgram(m_tc_po_ids[n_id]);
8025
8026 m_tc_po_ids[n_id] = 0;
8027 }
8028
8029 if (m_te_ids[n_id] != 0)
8030 {
8031 gl.deleteShader(m_te_ids[n_id]);
8032
8033 m_te_ids[n_id] = 0;
8034 }
8035
8036 if (m_te_po_ids[n_id] != 0)
8037 {
8038 gl.deleteProgram(m_te_po_ids[n_id]);
8039
8040 m_te_po_ids[n_id] = 0;
8041 }
8042
8043 if (m_vs_ids[n_id] != 0)
8044 {
8045 gl.deleteShader(m_vs_ids[n_id]);
8046
8047 m_vs_ids[n_id] = 0;
8048 }
8049
8050 if (m_vs_po_ids[n_id] != 0)
8051 {
8052 gl.deleteProgram(m_vs_po_ids[n_id]);
8053
8054 m_vs_po_ids[n_id] = 0;
8055 }
8056 } /* for (both IDs) */
8057 }
8058
8059 /** Retrieves body of a shader that should be used for user-specified shader stage.
8060 * This function returns slightly different implementations, depending on index of
8061 * the program/pipeline object the shader will be used for.
8062 *
8063 * @param shader_stage Stage the shader body is to be returned for.
8064 * @param n_id Index of the shader (as per description).
8065 *
8066 * @return Requested string.
8067 **/
getShaderBody(const Utils::_shader_stage & shader_stage,const unsigned int & n_id) const8068 std::string FunctionalTest16::getShaderBody(const Utils::_shader_stage& shader_stage, const unsigned int& n_id) const
8069 {
8070 std::stringstream result_sstream;
8071
8072 result_sstream << "#version 400\n"
8073 "\n"
8074 "#extension GL_ARB_shader_subroutine : require\n"
8075 "\n";
8076
8077 switch (shader_stage)
8078 {
8079 case Utils::SHADER_STAGE_VERTEX:
8080 {
8081 result_sstream << "out gl_PerVertex { vec4 gl_Position; } ;\n";
8082 break;
8083 }
8084 case Utils::SHADER_STAGE_GEOMETRY:
8085 {
8086 result_sstream << "layout(points) in;\n"
8087 "layout(points, max_vertices = 1) out;\n";
8088 result_sstream << "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n";
8089 result_sstream << "out gl_PerVertex { vec4 gl_Position; } ;\n";
8090 break;
8091 }
8092
8093 case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
8094 {
8095 result_sstream << "layout(vertices = 4) out;\n";
8096 result_sstream << "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n";
8097 result_sstream << "out gl_PerVertex { vec4 gl_Position; } gl_out[];\n";
8098 break;
8099 }
8100
8101 case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
8102 {
8103 result_sstream << "layout(quads) in;\n";
8104 result_sstream << "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n";
8105 result_sstream << "out gl_PerVertex { vec4 gl_Position; };\n";
8106 break;
8107 }
8108
8109 default:
8110 break;
8111 } /* switch (shader_stage) */
8112
8113 result_sstream << "\n"
8114 "subroutine void subroutineType (inout vec4 result);\n"
8115 "subroutine vec4 subroutineType2(in vec4 data);\n"
8116 "\n"
8117 "subroutine(subroutineType) void function1(inout vec4 result)\n"
8118 "{\n"
8119 " result += vec4("
8120 << (n_id + 1) << ", " << (n_id + 2) << ", " << (n_id + 3) << ", " << (n_id + 4)
8121 << ");\n"
8122 "}\n"
8123 "subroutine(subroutineType) void function2(inout vec4 result)\n"
8124 "{\n"
8125 " result += vec4("
8126 << (n_id + 2) << ", " << (n_id + 3) << ", " << (n_id + 4) << ", " << (n_id + 5)
8127 << ");\n"
8128 "}\n"
8129 "\n"
8130 "subroutine(subroutineType2) vec4 function3(in vec4 data)\n"
8131 "{\n"
8132 " return data * data;\n"
8133 "}\n"
8134 "subroutine(subroutineType2) vec4 function4(in vec4 data)\n"
8135 "{\n"
8136 " return data + data;\n"
8137 "}\n"
8138 "\n"
8139 "subroutine uniform subroutineType subroutine1;\n"
8140 "subroutine uniform subroutineType subroutine2;\n"
8141 "subroutine uniform subroutineType2 subroutine3;\n"
8142 "subroutine uniform subroutineType2 subroutine4;\n"
8143 "\n";
8144
8145 if (shader_stage == Utils::SHADER_STAGE_FRAGMENT)
8146 {
8147 result_sstream << "out vec4 result;\n";
8148 }
8149
8150 result_sstream << "void main()\n"
8151 "{\n";
8152
8153 switch (shader_stage)
8154 {
8155 case Utils::SHADER_STAGE_FRAGMENT:
8156 {
8157 result_sstream << " result = vec4(0);\n"
8158 << " subroutine1(result);\n"
8159 " subroutine2(result);\n"
8160 " result = subroutine3(result) + subroutine4(result);\n";
8161
8162 break;
8163 }
8164
8165 case Utils::SHADER_STAGE_GEOMETRY:
8166 {
8167 result_sstream << " gl_Position = vec4(0);\n"
8168 " subroutine1(gl_Position);\n"
8169 " subroutine2(gl_Position);\n"
8170 " gl_Position = subroutine3(gl_Position) + subroutine4(gl_Position);\n"
8171 " EmitVertex();\n";
8172
8173 break;
8174 }
8175
8176 case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
8177 {
8178 result_sstream << " gl_out[gl_InvocationID].gl_Position = vec4(0);\n"
8179 " subroutine1(gl_out[gl_InvocationID].gl_Position);\n"
8180 " subroutine2(gl_out[gl_InvocationID].gl_Position);\n"
8181 " gl_out[gl_InvocationID].gl_Position = subroutine3(gl_in[0].gl_Position) + "
8182 "subroutine4(gl_in[0].gl_Position);\n";
8183
8184 break;
8185 }
8186
8187 case Utils::SHADER_STAGE_VERTEX:
8188 case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
8189 {
8190 result_sstream << " gl_Position = vec4(0);\n"
8191 " subroutine1(gl_Position);\n"
8192 " subroutine2(gl_Position);\n"
8193 " gl_Position = subroutine3(gl_Position) + subroutine4(gl_Position);\n";
8194
8195 break;
8196 }
8197
8198 default:
8199 break;
8200 } /* switch (shader_stage) */
8201
8202 result_sstream << "}\n";
8203
8204 return result_sstream.str();
8205 }
8206
8207 /** Initializes all objects required to run the test. */
initTest()8208 void FunctionalTest16::initTest()
8209 {
8210 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
8211
8212 for (unsigned int n_id = 0; n_id < 2 /* test program/shader objects */; ++n_id)
8213 {
8214 const std::string fs_body = getShaderBody(Utils::SHADER_STAGE_FRAGMENT, n_id);
8215 const std::string gs_body = getShaderBody(Utils::SHADER_STAGE_GEOMETRY, n_id);
8216 const std::string tc_body = getShaderBody(Utils::SHADER_STAGE_TESSELLATION_CONTROL, n_id);
8217 const std::string te_body = getShaderBody(Utils::SHADER_STAGE_TESSELLATION_EVALUATION, n_id);
8218 const std::string vs_body = getShaderBody(Utils::SHADER_STAGE_VERTEX, n_id);
8219
8220 if (!Utils::buildProgram(gl, vs_body, tc_body, te_body, gs_body, fs_body, DE_NULL, /* xfb_varyings */
8221 DE_NULL, /* n_xfb_varyings */
8222 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,
8223 m_po_ids + n_id))
8224 {
8225 m_testCtx.getLog() << tcu::TestLog::Message << "Failed to build test program object, index:"
8226 "["
8227 << n_id << "]" << tcu::TestLog::EndMessage;
8228
8229 TCU_FAIL("Failed to build a test program");
8230 }
8231
8232 if (m_are_pipeline_objects_supported)
8233 {
8234 /* Initialize shader program objects */
8235 const char* fs_body_raw_ptr = fs_body.c_str();
8236 const char* gs_body_raw_ptr = gs_body.c_str();
8237 glw::GLint link_status[5] = { GL_FALSE };
8238 const char* tc_body_raw_ptr = tc_body.c_str();
8239 const char* te_body_raw_ptr = te_body.c_str();
8240 const char* vs_body_raw_ptr = vs_body.c_str();
8241
8242 m_fs_po_ids[n_id] = gl.createShaderProgramv(GL_FRAGMENT_SHADER, 1 /* count */, &fs_body_raw_ptr);
8243 m_gs_po_ids[n_id] = gl.createShaderProgramv(GL_GEOMETRY_SHADER, 1 /* count */, &gs_body_raw_ptr);
8244 m_tc_po_ids[n_id] = gl.createShaderProgramv(GL_TESS_CONTROL_SHADER, 1 /* count */, &tc_body_raw_ptr);
8245 m_te_po_ids[n_id] = gl.createShaderProgramv(GL_TESS_EVALUATION_SHADER, 1 /* count */, &te_body_raw_ptr);
8246 m_vs_po_ids[n_id] = gl.createShaderProgramv(GL_VERTEX_SHADER, 1 /* count */, &vs_body_raw_ptr);
8247 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
8248
8249 gl.getProgramiv(m_fs_po_ids[n_id], GL_LINK_STATUS, link_status + 0);
8250 gl.getProgramiv(m_gs_po_ids[n_id], GL_LINK_STATUS, link_status + 1);
8251 gl.getProgramiv(m_tc_po_ids[n_id], GL_LINK_STATUS, link_status + 2);
8252 gl.getProgramiv(m_te_po_ids[n_id], GL_LINK_STATUS, link_status + 3);
8253 gl.getProgramiv(m_vs_po_ids[n_id], GL_LINK_STATUS, link_status + 4);
8254 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
8255
8256 if (link_status[0] == GL_FALSE)
8257 TCU_FAIL("Fragment shader program failed to link");
8258 if (link_status[1] == GL_FALSE)
8259 TCU_FAIL("Geometry shader program failed to link");
8260 if (link_status[2] == GL_FALSE)
8261 TCU_FAIL("Tessellation control shader program failed to link");
8262 if (link_status[3] == GL_FALSE)
8263 TCU_FAIL("Tessellation evaluation shader program failed to link");
8264 if (link_status[4] == GL_FALSE)
8265 TCU_FAIL("Vertex shader program failed to link");
8266
8267 /* Initialize pipeline program object */
8268 gl.genProgramPipelines(1 /* n */, m_pipeline_object_ids + n_id);
8269 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() call failed.");
8270
8271 gl.useProgramStages(m_pipeline_object_ids[n_id], GL_FRAGMENT_SHADER_BIT, m_fs_po_ids[n_id]);
8272 gl.useProgramStages(m_pipeline_object_ids[n_id], GL_GEOMETRY_SHADER_BIT, m_gs_po_ids[n_id]);
8273 gl.useProgramStages(m_pipeline_object_ids[n_id], GL_TESS_CONTROL_SHADER_BIT, m_tc_po_ids[n_id]);
8274 gl.useProgramStages(m_pipeline_object_ids[n_id], GL_TESS_EVALUATION_SHADER_BIT, m_te_po_ids[n_id]);
8275 gl.useProgramStages(m_pipeline_object_ids[n_id], GL_VERTEX_SHADER_BIT, m_vs_po_ids[n_id]);
8276 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8277 }
8278
8279 /* Retrieve subroutine locations */
8280 struct _item
8281 {
8282 glw::GLuint po_id;
8283 _shader_stage& stage;
8284 glw::GLuint so_id;
8285 glw::GLenum so_type;
8286 } items[] = {
8287 { m_po_ids[n_id], m_po_descriptors[n_id].fragment, m_fs_ids[n_id], GL_FRAGMENT_SHADER },
8288 { m_po_ids[n_id], m_po_descriptors[n_id].geometry, m_gs_ids[n_id], GL_GEOMETRY_SHADER },
8289 { m_po_ids[n_id], m_po_descriptors[n_id].tess_control, m_tc_ids[n_id], GL_TESS_CONTROL_SHADER },
8290 { m_po_ids[n_id], m_po_descriptors[n_id].tess_evaluation, m_te_ids[n_id], GL_TESS_EVALUATION_SHADER },
8291 { m_po_ids[n_id], m_po_descriptors[n_id].vertex, m_vs_ids[n_id], GL_VERTEX_SHADER },
8292
8293 { m_fs_po_ids[n_id], m_fs_po_descriptors[n_id], m_fs_po_ids[n_id], GL_FRAGMENT_SHADER },
8294 { m_gs_po_ids[n_id], m_gs_po_descriptors[n_id], m_gs_po_ids[n_id], GL_GEOMETRY_SHADER },
8295 { m_tc_po_ids[n_id], m_tc_po_descriptors[n_id], m_tc_po_ids[n_id], GL_TESS_CONTROL_SHADER },
8296 { m_te_po_ids[n_id], m_te_po_descriptors[n_id], m_te_po_ids[n_id], GL_TESS_EVALUATION_SHADER },
8297 { m_vs_po_ids[n_id], m_vs_po_descriptors[n_id], m_vs_po_ids[n_id], GL_VERTEX_SHADER },
8298 };
8299 const unsigned int n_items = sizeof(items) / sizeof(items[0]);
8300
8301 for (unsigned int n_item = 0; n_item < n_items; ++n_item)
8302 {
8303 _item& current_item = items[n_item];
8304
8305 current_item.stage.function1_index =
8306 gl.getSubroutineIndex(current_item.po_id, current_item.so_type, "function1");
8307 current_item.stage.function2_index =
8308 gl.getSubroutineIndex(current_item.po_id, current_item.so_type, "function2");
8309 current_item.stage.function3_index =
8310 gl.getSubroutineIndex(current_item.po_id, current_item.so_type, "function3");
8311 current_item.stage.function4_index =
8312 gl.getSubroutineIndex(current_item.po_id, current_item.so_type, "function4");
8313 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineIndex() call(s) failed.");
8314
8315 if (current_item.stage.function1_index == GL_INVALID_INDEX ||
8316 current_item.stage.function2_index == GL_INVALID_INDEX ||
8317 current_item.stage.function3_index == GL_INVALID_INDEX ||
8318 current_item.stage.function4_index == GL_INVALID_INDEX)
8319 {
8320 TCU_FAIL("Subroutine name was not recognized.");
8321 }
8322
8323 current_item.stage.subroutine1_uniform_location =
8324 gl.getSubroutineUniformLocation(current_item.po_id, current_item.so_type, "subroutine1");
8325 current_item.stage.subroutine2_uniform_location =
8326 gl.getSubroutineUniformLocation(current_item.po_id, current_item.so_type, "subroutine2");
8327 current_item.stage.subroutine3_uniform_location =
8328 gl.getSubroutineUniformLocation(current_item.po_id, current_item.so_type, "subroutine3");
8329 current_item.stage.subroutine4_uniform_location =
8330 gl.getSubroutineUniformLocation(current_item.po_id, current_item.so_type, "subroutine4");
8331 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineUniformLocation() call(s) failed.");
8332
8333 if (current_item.stage.subroutine1_uniform_location == -1 ||
8334 current_item.stage.subroutine2_uniform_location == -1 ||
8335 current_item.stage.subroutine3_uniform_location == -1 ||
8336 current_item.stage.subroutine4_uniform_location == -1)
8337 {
8338 TCU_FAIL("Subroutine uniform name was not recognized.");
8339 }
8340
8341 if (m_po_ids[n_id] == current_item.po_id)
8342 {
8343 gl.useProgram(current_item.po_id);
8344 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
8345 }
8346 else
8347 {
8348 /* Temporarily bind the program pipeline. */
8349 gl.bindProgramPipeline(m_pipeline_object_ids[n_id]);
8350 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
8351 }
8352
8353 gl.getUniformSubroutineuiv(current_item.so_type, current_item.stage.subroutine1_uniform_location,
8354 ¤t_item.stage.default_subroutine1_value);
8355 gl.getUniformSubroutineuiv(current_item.so_type, current_item.stage.subroutine2_uniform_location,
8356 ¤t_item.stage.default_subroutine2_value);
8357 gl.getUniformSubroutineuiv(current_item.so_type, current_item.stage.subroutine3_uniform_location,
8358 ¤t_item.stage.default_subroutine3_value);
8359 gl.getUniformSubroutineuiv(current_item.so_type, current_item.stage.subroutine4_uniform_location,
8360 ¤t_item.stage.default_subroutine4_value);
8361 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformSubroutineuiv() call(s) failed.");
8362
8363 current_item.stage.gl_stage = current_item.so_type;
8364
8365 if (m_po_ids[n_id] != current_item.po_id)
8366 {
8367 /* Unbind the program pipeline object */
8368 gl.bindProgramPipeline(0);
8369 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
8370 }
8371 } /* for (all items) */
8372
8373 /* Make sure the default subroutine choices are valid. */
8374 verifySubroutineUniformValues(
8375 TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT, /* makes the verification routine use program object descriptor */
8376 n_id, SUBROUTINE_UNIFORMS_SET_TO_VALID_VALUES);
8377
8378 if (m_are_pipeline_objects_supported)
8379 {
8380 gl.useProgram(0);
8381 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
8382
8383 gl.bindProgramPipeline(m_pipeline_object_ids[n_id]);
8384 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
8385 {
8386 verifySubroutineUniformValues(
8387 TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_PIPELINE_OBJECT, /* makes the verification routine use pipeline object descriptor */
8388 n_id, SUBROUTINE_UNIFORMS_SET_TO_VALID_VALUES);
8389 }
8390 gl.bindProgramPipeline(0);
8391 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
8392 }
8393 } /* for (both program descriptors) */
8394 }
8395
8396 /** Retrieves IDs of shaders OR shader program objects, depending on which of the two
8397 * the caller requests for.
8398 *
8399 * @param retrieve_program_object_shader_ids true if the caller wishes to retrieve shader object IDs,
8400 * false to return shader program IDs.
8401 * @param n_id Index of the program/pipeline object the shaders
8402 * are a part of.
8403 * @param out_shader_stages Deref will be used to store exactly five IDs. Must not
8404 * be NULL.
8405 **/
getShaderStages(bool retrieve_program_object_shader_ids,const unsigned int & n_id,const _shader_stage ** out_shader_stages) const8406 void FunctionalTest16::getShaderStages(bool retrieve_program_object_shader_ids, const unsigned int& n_id,
8407 const _shader_stage** out_shader_stages) const
8408 {
8409 if (retrieve_program_object_shader_ids)
8410 {
8411 out_shader_stages[0] = &m_po_descriptors[n_id].vertex;
8412 out_shader_stages[1] = &m_po_descriptors[n_id].tess_control;
8413 out_shader_stages[2] = &m_po_descriptors[n_id].tess_evaluation;
8414 out_shader_stages[3] = &m_po_descriptors[n_id].geometry;
8415 out_shader_stages[4] = &m_po_descriptors[n_id].fragment;
8416 }
8417 else
8418 {
8419 out_shader_stages[0] = m_vs_po_descriptors + n_id;
8420 out_shader_stages[1] = m_tc_po_descriptors + n_id;
8421 out_shader_stages[2] = m_te_po_descriptors + n_id;
8422 out_shader_stages[3] = m_gs_po_descriptors + n_id;
8423 out_shader_stages[4] = m_fs_po_descriptors + n_id;
8424 }
8425 }
8426
8427 /** Executes test iteration.
8428 *
8429 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
8430 */
iterate()8431 tcu::TestNode::IterateResult FunctionalTest16::iterate()
8432 {
8433 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
8434
8435 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
8436 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
8437 {
8438 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
8439 }
8440
8441 m_are_pipeline_objects_supported =
8442 m_context.getContextInfo().isExtensionSupported("GL_ARB_separate_shader_objects");
8443
8444 /* Initialize GL objects required to run the test */
8445 initTest();
8446
8447 /* Iterate over both pipelines/programs and verify that calling glUseProgram() /
8448 * glBindProgramPipeline() / glUseProgramStages() resets subroutine uniform configuration.
8449 */
8450 for (int test_case = static_cast<int>(TEST_CASE_FIRST); test_case != static_cast<int>(TEST_CASE_COUNT); ++test_case)
8451 {
8452 if (static_cast<_test_case>(test_case) != TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT &&
8453 !m_are_pipeline_objects_supported)
8454 {
8455 /* Current test case requires GL_ARB_separate_shader_objects support which is
8456 * unavaiable on the platform that we're testing
8457 */
8458 continue;
8459 }
8460
8461 for (unsigned int n_object_id = 0; n_object_id < 2; /* pipeline/program objects allocated for the test */
8462 ++n_object_id)
8463 {
8464 /* Verify that currently reported subroutine uniform values are equal to default values */
8465 if (test_case == TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT)
8466 {
8467 gl.useProgram(m_po_ids[n_object_id]);
8468 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
8469 }
8470 else
8471 {
8472 gl.bindProgramPipeline(m_pipeline_object_ids[n_object_id]);
8473 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed");
8474 }
8475
8476 verifySubroutineUniformValues(static_cast<_test_case>(test_case), n_object_id,
8477 SUBROUTINE_UNIFORMS_SET_TO_DEFAULT_VALUES);
8478
8479 /* Re-configure subroutine uniforms so that they point to different subroutines than
8480 * the default ones.
8481 */
8482 const _shader_stage* stages[5 /* fs+gs+tc+te+vs */] = { DE_NULL };
8483
8484 getShaderStages(static_cast<_test_case>(test_case) == TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT,
8485 n_object_id, stages);
8486
8487 for (unsigned int n_stage = 0; n_stage < 5 /* fs+gs+tc+te+vs stages */; ++n_stage)
8488 {
8489 const _shader_stage& current_stage = *(stages[n_stage]);
8490 glw::GLuint subroutine_configuration[4] = { GL_INVALID_INDEX };
8491
8492 subroutine_configuration[0] =
8493 (current_stage.default_subroutine1_value == current_stage.function1_index) ?
8494 current_stage.function2_index :
8495 current_stage.function1_index;
8496 subroutine_configuration[1] =
8497 (current_stage.default_subroutine2_value == current_stage.function1_index) ?
8498 current_stage.function2_index :
8499 current_stage.function1_index;
8500 subroutine_configuration[2] =
8501 (current_stage.default_subroutine3_value == current_stage.function3_index) ?
8502 current_stage.function4_index :
8503 current_stage.function3_index;
8504 subroutine_configuration[3] =
8505 (current_stage.default_subroutine4_value == current_stage.function3_index) ?
8506 current_stage.function4_index :
8507 current_stage.function3_index;
8508
8509 gl.uniformSubroutinesuiv(current_stage.gl_stage, 4 /* count */, subroutine_configuration);
8510 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniformSubroutinesuiv() call failed.");
8511 } /* for (all stages) */
8512
8513 verifySubroutineUniformValues(static_cast<_test_case>(test_case), n_object_id,
8514 SUBROUTINE_UNIFORMS_SET_TO_NONDEFAULT_VALUES);
8515
8516 /* Execute test case-specific code */
8517 _shader_stage cached_shader_stage_data;
8518 bool stage_reset_status[Utils::SHADER_STAGE_COUNT] = { false, false, false, false, false };
8519 bool uses_stage_reset_status = false;
8520
8521 switch (test_case)
8522 {
8523 case TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT:
8524 {
8525 /* Switch to a different program object and then back to current PO.
8526 * Subroutine uniforms should be back at their default settings, instead of
8527 * the ones we've just set.
8528 */
8529 gl.useProgram(m_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8530 gl.useProgram(m_po_ids[n_object_id]);
8531 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call(s) failed.");
8532
8533 break;
8534 }
8535
8536 case TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_PIPELINE_OBJECT:
8537 {
8538 /* Switch to a different pipeline object and then back to the current one.
8539 * Subroutine uniforms should be back at their default settings, instead of
8540 * the ones we've just set.
8541 */
8542 gl.bindProgramPipeline(
8543 m_pipeline_object_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8544 gl.bindProgramPipeline(m_pipeline_object_ids[n_object_id]);
8545 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call(s) failed.");
8546
8547 break;
8548 }
8549
8550 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_FRAGMENT_STAGE:
8551 {
8552 /* Change the fragment shader stage to a different one.
8553 *
8554 * Note: We also need to update internal descriptor since the subroutine/uniform
8555 * locations may be different between the two programs.
8556 */
8557 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_FRAGMENT_SHADER_BIT,
8558 m_fs_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8559 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8560
8561 cached_shader_stage_data = m_fs_po_descriptors[n_object_id];
8562 m_fs_po_descriptors[n_object_id] = m_fs_po_descriptors[(n_object_id + 1) % 2];
8563
8564 stage_reset_status[Utils::SHADER_STAGE_FRAGMENT] = true;
8565 uses_stage_reset_status = true;
8566
8567 break;
8568 }
8569
8570 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_GEOMETRY_STAGE:
8571 {
8572 /* Change the geometry shader stage to a different one.
8573 *
8574 * Note: We also need to update internal descriptor since the subroutine/uniform
8575 * locations may be different between the two programs.
8576 */
8577 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_GEOMETRY_SHADER_BIT,
8578 m_gs_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8579 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8580
8581 cached_shader_stage_data = m_gs_po_descriptors[n_object_id];
8582 m_gs_po_descriptors[n_object_id] = m_gs_po_descriptors[(n_object_id + 1) % 2];
8583
8584 stage_reset_status[Utils::SHADER_STAGE_GEOMETRY] = true;
8585 uses_stage_reset_status = true;
8586
8587 break;
8588 }
8589
8590 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_TESS_CONTROL_STAGE:
8591 {
8592 /* Change the tessellation control shader stage to a different one.
8593 *
8594 * Note: We also need to update internal descriptor since the subroutine/uniform
8595 * locations may be different between the two programs.
8596 */
8597 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_TESS_CONTROL_SHADER_BIT,
8598 m_tc_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8599 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8600
8601 cached_shader_stage_data = m_tc_po_descriptors[n_object_id];
8602 m_tc_po_descriptors[n_object_id] = m_tc_po_descriptors[(n_object_id + 1) % 2];
8603
8604 stage_reset_status[Utils::SHADER_STAGE_TESSELLATION_CONTROL] = true;
8605 uses_stage_reset_status = true;
8606
8607 break;
8608 }
8609
8610 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_TESS_EVALUATION_STAGE:
8611 {
8612 /* Change the tessellation evaluation shader stage to a different one.
8613 *
8614 * Note: We also need to update internal descriptor since the subroutine/uniform
8615 * locations may be different between the two programs.
8616 */
8617 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_TESS_EVALUATION_SHADER_BIT,
8618 m_te_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8619 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8620
8621 cached_shader_stage_data = m_te_po_descriptors[n_object_id];
8622 m_te_po_descriptors[n_object_id] = m_te_po_descriptors[(n_object_id + 1) % 2];
8623
8624 stage_reset_status[Utils::SHADER_STAGE_TESSELLATION_EVALUATION] = true;
8625 uses_stage_reset_status = true;
8626
8627 break;
8628 }
8629
8630 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_VERTEX_STAGE:
8631 {
8632 /* Change the vertex shader stage to a different one.
8633 *
8634 * Note: We also need to update internal descriptor since the subroutine/uniform
8635 * locations may be different between the two programs.
8636 */
8637 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_VERTEX_SHADER_BIT,
8638 m_vs_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8639 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8640
8641 cached_shader_stage_data = m_vs_po_descriptors[n_object_id];
8642 m_vs_po_descriptors[n_object_id] = m_vs_po_descriptors[(n_object_id + 1) % 2];
8643
8644 stage_reset_status[Utils::SHADER_STAGE_VERTEX] = true;
8645 uses_stage_reset_status = true;
8646
8647 break;
8648 }
8649
8650 default:
8651 {
8652 TCU_FAIL("Unrecognized test case");
8653 }
8654 } /* switch (test_case) */
8655
8656 /* Verify the subroutine uniform values are valid */
8657 if (!uses_stage_reset_status)
8658 {
8659 verifySubroutineUniformValues(static_cast<_test_case>(test_case), n_object_id,
8660 SUBROUTINE_UNIFORMS_SET_TO_DEFAULT_VALUES);
8661 }
8662 else
8663 {
8664 const _shader_stage* shader_stages[Utils::SHADER_STAGE_COUNT] = { DE_NULL };
8665
8666 getShaderStages(static_cast<_test_case>(test_case) == TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT,
8667 n_object_id, shader_stages);
8668
8669 for (unsigned int n_shader_stage = 0; n_shader_stage < Utils::SHADER_STAGE_COUNT; ++n_shader_stage)
8670 {
8671 const _shader_stage& current_shader_stage = *(shader_stages[n_shader_stage]);
8672
8673 if (stage_reset_status[n_shader_stage])
8674 {
8675 verifySubroutineUniformValuesForShaderStage(current_shader_stage,
8676 SUBROUTINE_UNIFORMS_SET_TO_DEFAULT_VALUES);
8677 }
8678 else
8679 {
8680 verifySubroutineUniformValuesForShaderStage(current_shader_stage,
8681 SUBROUTINE_UNIFORMS_SET_TO_NONDEFAULT_VALUES);
8682 }
8683 } /* for (all shader stages) */
8684 }
8685
8686 /* Revert the changes some of the test cases appied */
8687 switch (test_case)
8688 {
8689 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_FRAGMENT_STAGE:
8690 {
8691 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_FRAGMENT_SHADER_BIT,
8692 m_fs_po_ids[n_object_id]);
8693 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8694
8695 m_fs_po_descriptors[n_object_id] = cached_shader_stage_data;
8696
8697 break;
8698 }
8699
8700 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_GEOMETRY_STAGE:
8701 {
8702 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_GEOMETRY_SHADER_BIT,
8703 m_gs_po_ids[n_object_id]);
8704 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8705
8706 m_gs_po_descriptors[n_object_id] = cached_shader_stage_data;
8707
8708 break;
8709 }
8710
8711 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_TESS_CONTROL_STAGE:
8712 {
8713 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_TESS_CONTROL_SHADER_BIT,
8714 m_tc_po_ids[n_object_id]);
8715 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8716
8717 m_tc_po_descriptors[n_object_id] = cached_shader_stage_data;
8718
8719 break;
8720 }
8721
8722 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_TESS_EVALUATION_STAGE:
8723 {
8724 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_TESS_EVALUATION_SHADER_BIT,
8725 m_te_po_ids[n_object_id]);
8726 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8727
8728 m_te_po_descriptors[n_object_id] = cached_shader_stage_data;
8729
8730 break;
8731 }
8732
8733 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_VERTEX_STAGE:
8734 {
8735 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_VERTEX_SHADER_BIT, m_vs_po_ids[n_object_id]);
8736 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8737
8738 m_vs_po_descriptors[n_object_id] = cached_shader_stage_data;
8739
8740 break;
8741 }
8742
8743 default:
8744 break;
8745 } /* switch (test_case) */
8746
8747 } /* for (all program object descriptors) */
8748
8749 /* Unbind the program object */
8750 gl.useProgram(0);
8751 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
8752 } /* for (all test cases) */
8753
8754 if (m_has_test_passed)
8755 {
8756 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
8757 }
8758 else
8759 {
8760 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
8761 }
8762
8763 return STOP;
8764 }
8765
8766 /** Verifies the subroutine uniform values reported by GL implementation. Depending on the test case,
8767 * it will either query program object stages or separate shader objects.
8768 *
8769 * @param test_case Test case the verification is to be performed for.
8770 * @param n_id Index of the program/pipeline object to use for the verification
8771 * @param verification Verification method.
8772 */
verifySubroutineUniformValues(const _test_case & test_case,const unsigned int & n_id,const _subroutine_uniform_value_verification & verification)8773 void FunctionalTest16::verifySubroutineUniformValues(const _test_case& test_case, const unsigned int& n_id,
8774 const _subroutine_uniform_value_verification& verification)
8775 {
8776 const _shader_stage* stages[] = {
8777 DE_NULL, /* fragment shader stage slot */
8778 DE_NULL, /* geometry shader stage slot */
8779 DE_NULL, /* tess control shader stage slot */
8780 DE_NULL, /* tess eval shader stage slot */
8781 DE_NULL /* vertex shader stage slot */
8782 };
8783 const unsigned int n_stages = sizeof(stages) / sizeof(stages[0]);
8784
8785 /* Verify that currently reported subroutine uniform values are equal to default values */
8786 getShaderStages(test_case == TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT, n_id, stages);
8787
8788 for (unsigned int n_stage = 0; n_stage < n_stages; ++n_stage)
8789 {
8790 const _shader_stage& current_stage = *(stages[n_stage]);
8791
8792 verifySubroutineUniformValuesForShaderStage(current_stage, verification);
8793 } /* for (all items) */
8794 }
8795
8796 /** Verifies the subroutine uniform values reported by GL implementation for user-specified
8797 * shader stage. If the verification fails, m_has_test_passed will be set to false.
8798 *
8799 * @param shader_stage Descriptor of a shader stage that should be used for the process.
8800 * @param verification Type of verification that should be performed.
8801 *
8802 **/
verifySubroutineUniformValuesForShaderStage(const _shader_stage & shader_stage,const _subroutine_uniform_value_verification & verification)8803 void FunctionalTest16::verifySubroutineUniformValuesForShaderStage(
8804 const _shader_stage& shader_stage, const _subroutine_uniform_value_verification& verification)
8805 {
8806 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
8807 glw::GLuint result_values[4] = { 0 };
8808
8809 gl.getUniformSubroutineuiv(shader_stage.gl_stage, shader_stage.subroutine1_uniform_location, result_values + 0);
8810 gl.getUniformSubroutineuiv(shader_stage.gl_stage, shader_stage.subroutine2_uniform_location, result_values + 1);
8811 gl.getUniformSubroutineuiv(shader_stage.gl_stage, shader_stage.subroutine3_uniform_location, result_values + 2);
8812 gl.getUniformSubroutineuiv(shader_stage.gl_stage, shader_stage.subroutine4_uniform_location, result_values + 3);
8813 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformSubroutineuiv() call(s) failed.");
8814
8815 if (verification == SUBROUTINE_UNIFORMS_SET_TO_VALID_VALUES)
8816 {
8817 if (!((result_values[0] == (GLuint)shader_stage.subroutine1_uniform_location ||
8818 result_values[0] == (GLuint)shader_stage.subroutine2_uniform_location) &&
8819 (result_values[1] == (GLuint)shader_stage.subroutine1_uniform_location ||
8820 result_values[1] == (GLuint)shader_stage.subroutine2_uniform_location) &&
8821 (result_values[2] == (GLuint)shader_stage.subroutine3_uniform_location ||
8822 result_values[2] == (GLuint)shader_stage.subroutine4_uniform_location) &&
8823 (result_values[3] == (GLuint)shader_stage.subroutine3_uniform_location ||
8824 result_values[3] == (GLuint)shader_stage.subroutine4_uniform_location)))
8825 {
8826 m_testCtx.getLog() << tcu::TestLog::Message << "SUBROUTINE_UNIFORMS_SET_TO_VALID_VALUES validation failed. "
8827 "Shader stage:["
8828 << Utils::getShaderStageStringFromGLEnum(shader_stage.gl_stage) << "], "
8829 "expected data:["
8830 << shader_stage.subroutine1_uniform_location << " OR "
8831 << shader_stage.subroutine2_uniform_location << " x 2, "
8832 << shader_stage.subroutine3_uniform_location << " OR "
8833 << shader_stage.subroutine4_uniform_location << " x 2], "
8834 "found data:["
8835 << result_values[0] << ", " << result_values[1] << ", " << result_values[2] << ", "
8836 << result_values[3] << "]." << tcu::TestLog::EndMessage;
8837
8838 m_has_test_passed = false;
8839 }
8840 }
8841 else if (verification == SUBROUTINE_UNIFORMS_SET_TO_DEFAULT_VALUES)
8842 {
8843 if (result_values[0] != shader_stage.default_subroutine1_value ||
8844 result_values[1] != shader_stage.default_subroutine2_value ||
8845 result_values[2] != shader_stage.default_subroutine3_value ||
8846 result_values[3] != shader_stage.default_subroutine4_value)
8847 {
8848 m_testCtx.getLog() << tcu::TestLog::Message
8849 << "SUBROUTINE_UNIFORMS_SET_TO_DEFAULT_VALUES validation failed. "
8850 "Shader stage:["
8851 << Utils::getShaderStageStringFromGLEnum(shader_stage.gl_stage) << "], "
8852 "expected data:["
8853 << shader_stage.default_subroutine1_value << ", "
8854 << shader_stage.default_subroutine2_value << ", "
8855 << shader_stage.default_subroutine3_value << ", "
8856 << shader_stage.default_subroutine4_value << "], "
8857 "found data:["
8858 << result_values[0] << ", " << result_values[1] << ", " << result_values[2] << ", "
8859 << result_values[3] << "]." << tcu::TestLog::EndMessage;
8860
8861 m_has_test_passed = false;
8862 }
8863 }
8864 else
8865 {
8866 DE_ASSERT(verification == SUBROUTINE_UNIFORMS_SET_TO_NONDEFAULT_VALUES);
8867
8868 if (result_values[0] == shader_stage.default_subroutine1_value ||
8869 result_values[1] == shader_stage.default_subroutine2_value ||
8870 result_values[2] == shader_stage.default_subroutine3_value ||
8871 result_values[3] == shader_stage.default_subroutine4_value)
8872 {
8873 m_testCtx.getLog() << tcu::TestLog::Message
8874 << "SUBROUTINE_UNIFORMS_SET_TO_NONDEFAULT_VALUES validation failed. "
8875 "Shader stage:["
8876 << Utils::getShaderStageStringFromGLEnum(shader_stage.gl_stage) << "], "
8877 "expected data:!["
8878 << shader_stage.default_subroutine1_value << ", "
8879 << shader_stage.default_subroutine2_value << ", "
8880 << shader_stage.default_subroutine3_value << ", "
8881 << shader_stage.default_subroutine4_value << "], "
8882 "found data:["
8883 << result_values[0] << ", " << result_values[1] << ", " << result_values[2] << ", "
8884 << result_values[3] << "]." << tcu::TestLog::EndMessage;
8885
8886 m_has_test_passed = false;
8887 }
8888 }
8889 }
8890
8891 /** Constructor.
8892 *
8893 * @param context Rendering context.
8894 *
8895 **/
FunctionalTest17(deqp::Context & context)8896 FunctionalTest17::FunctionalTest17(deqp::Context& context)
8897 : TestCase(context, "same_subroutine_and_subroutine_uniform_but_different_type_used_in_all_stages",
8898 "Creates a program which uses the same subroutine and subroutine uniform "
8899 "names for every stage (types of subroutines are different in each stage) "
8900 "and then makes sure that such program compiles and works as expected.")
8901 , m_fbo_id(0)
8902 , m_fs_id(0)
8903 , m_gs_id(0)
8904 , m_has_test_passed(true)
8905 , m_po_id(0)
8906 , m_tc_id(0)
8907 , m_te_id(0)
8908 , m_to_data(DE_NULL)
8909 , m_to_height(4) /* arbitrary value */
8910 , m_to_id(0)
8911 , m_to_width(4) /* arbitrary value */
8912 , m_vao_id(0)
8913 , m_vs_id(0)
8914 {
8915 /* Left blank intentionally */
8916 }
8917
8918 /** Deinitializes all GL objects that may have been created during test execution. */
deinit()8919 void FunctionalTest17::deinit()
8920 {
8921 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
8922
8923 if (m_fbo_id != 0)
8924 {
8925 gl.deleteFramebuffers(1, &m_fbo_id);
8926
8927 m_fbo_id = 0;
8928 }
8929
8930 if (m_fs_id != 0)
8931 {
8932 gl.deleteShader(m_fs_id);
8933
8934 m_fs_id = 0;
8935 }
8936
8937 if (m_gs_id != 0)
8938 {
8939 gl.deleteShader(m_gs_id);
8940
8941 m_gs_id = 0;
8942 }
8943
8944 if (m_po_id != 0)
8945 {
8946 gl.deleteProgram(m_po_id);
8947
8948 m_po_id = 0;
8949 }
8950
8951 if (m_tc_id != 0)
8952 {
8953 gl.deleteShader(m_tc_id);
8954
8955 m_tc_id = 0;
8956 }
8957
8958 if (m_te_id != 0)
8959 {
8960 gl.deleteShader(m_te_id);
8961
8962 m_te_id = 0;
8963 }
8964
8965 if (m_to_data != DE_NULL)
8966 {
8967 delete[] m_to_data;
8968
8969 m_to_data = DE_NULL;
8970 }
8971
8972 if (m_to_id != 0)
8973 {
8974 gl.deleteTextures(1, &m_to_id);
8975
8976 m_to_id = 0;
8977 }
8978
8979 if (m_vao_id != 0)
8980 {
8981 gl.deleteVertexArrays(1, &m_vao_id);
8982
8983 m_vao_id = 0;
8984 }
8985
8986 if (m_vs_id != 0)
8987 {
8988 gl.deleteShader(m_vs_id);
8989
8990 m_vs_id = 0;
8991 }
8992
8993 /* Restore original GL configuration */
8994 gl.patchParameteri(GL_PATCH_VERTICES, 3);
8995 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteri() call failed.");
8996
8997 gl.pixelStorei(GL_PACK_ALIGNMENT, 4);
8998 GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call failed.");
8999 }
9000
9001 /** Retrieves body of a fragment shader that should be used by the test program.
9002 *
9003 * @return Requested string.
9004 **/
getFragmentShaderBody() const9005 std::string FunctionalTest17::getFragmentShaderBody() const
9006 {
9007 return "#version 400\n"
9008 "\n"
9009 "#extension GL_ARB_shader_subroutine : require\n"
9010 "\n"
9011 "in GS_DATA\n"
9012 "{\n"
9013 " vec4 gs_data;\n"
9014 " vec4 tc_data;\n"
9015 " vec4 te_data;\n"
9016 " vec4 vs_data;\n"
9017 "} gs;\n"
9018 "\n"
9019 "out vec4 result;\n"
9020 "\n"
9021 "subroutine void subroutineTypeFS(out vec4 result);\n"
9022 "\n"
9023 "subroutine(subroutineTypeFS) void subroutine1(out vec4 result)\n"
9024 "{\n"
9025 " result = vec4(5, 6, 7, 8);\n"
9026 "}\n"
9027 "\n"
9028 "subroutine uniform subroutineTypeFS function;\n"
9029 "\n"
9030 "void main()\n"
9031 "{\n"
9032 " vec4 fs_data;\n"
9033 "\n"
9034 " function(fs_data);\n"
9035 " result = gs.gs_data + gs.tc_data + gs.te_data + gs.vs_data + fs_data;\n"
9036 "}\n";
9037 }
9038
9039 /** Retrieves body of a geometry shader that should be used by the test program.
9040 *
9041 * @return Requested string.
9042 **/
getGeometryShaderBody() const9043 std::string FunctionalTest17::getGeometryShaderBody() const
9044 {
9045 return "#version 400\n"
9046 "\n"
9047 "#extension GL_ARB_shader_subroutine : require\n"
9048 "\n"
9049 "layout(points) in;\n"
9050 "layout(triangle_strip, max_vertices = 4) out;\n"
9051 "\n"
9052 "subroutine void subroutineTypeGS(out vec4 result);\n"
9053 "\n"
9054 "subroutine(subroutineTypeGS) void subroutine1(out vec4 result)\n"
9055 "{\n"
9056 " result = vec4(4, 5, 6, 7);\n"
9057 "}\n"
9058 "\n"
9059 "subroutine uniform subroutineTypeGS function;\n"
9060 "\n"
9061 "in TE_DATA\n"
9062 "{\n"
9063 " vec4 tc_data;\n"
9064 " vec4 te_data;\n"
9065 " vec4 vs_data;\n"
9066 "} te[];\n"
9067 "\n"
9068 "out GS_DATA\n"
9069 "{\n"
9070 " vec4 gs_data;\n"
9071 " vec4 tc_data;\n"
9072 " vec4 te_data;\n"
9073 " vec4 vs_data;\n"
9074 "} result;\n"
9075 "\n"
9076 "void main()\n"
9077 "{\n"
9078 " function(result.gs_data);\n"
9079 " gl_Position = vec4(1, -1, 0, 1);\n"
9080 " result.tc_data = te[0].tc_data;\n"
9081 " result.te_data = te[0].te_data;\n"
9082 " result.vs_data = te[0].vs_data;\n"
9083 " EmitVertex();\n"
9084 "\n"
9085 " function(result.gs_data);\n"
9086 " gl_Position = vec4(-1, -1, 0, 1);\n"
9087 " result.tc_data = te[0].tc_data;\n"
9088 " result.te_data = te[0].te_data;\n"
9089 " result.vs_data = te[0].vs_data;\n"
9090 " EmitVertex();\n"
9091 "\n"
9092 " function(result.gs_data);\n"
9093 " gl_Position = vec4(1, 1, 0, 1);\n"
9094 " result.tc_data = te[0].tc_data;\n"
9095 " result.te_data = te[0].te_data;\n"
9096 " result.vs_data = te[0].vs_data;\n"
9097 " EmitVertex();\n"
9098 "\n"
9099 " function(result.gs_data);\n"
9100 " gl_Position = vec4(-1, 1, 0, 1);\n"
9101 " result.tc_data = te[0].tc_data;\n"
9102 " result.te_data = te[0].te_data;\n"
9103 " result.vs_data = te[0].vs_data;\n"
9104 " EmitVertex();\n"
9105 " EndPrimitive();\n"
9106 "}\n";
9107 }
9108
9109 /** Retrieves body of a tessellation control shader that should be used by the test program.
9110 *
9111 * @return Requested string.
9112 **/
getTessellationControlShaderBody() const9113 std::string FunctionalTest17::getTessellationControlShaderBody() const
9114 {
9115 return "#version 400\n"
9116 "\n"
9117 "#extension GL_ARB_shader_subroutine : require\n"
9118 "\n"
9119 "layout (vertices = 4) out;\n"
9120 "\n"
9121 "subroutine void subroutineTypeTC(out vec4 result);\n"
9122 "\n"
9123 "subroutine(subroutineTypeTC) void subroutine1(out vec4 result)\n"
9124 "{\n"
9125 " result = vec4(2, 3, 4, 5);\n"
9126 "}\n"
9127 "\n"
9128 "subroutine uniform subroutineTypeTC function;\n"
9129 "\n"
9130 "in VS_DATA\n"
9131 "{\n"
9132 " vec4 vs_data;\n"
9133 "} vs[];\n"
9134 "\n"
9135 "out TC_DATA\n"
9136 "{\n"
9137 " vec4 tc_data;\n"
9138 " vec4 vs_data;\n"
9139 "} result[];\n"
9140 "\n"
9141 "void main()\n"
9142 "{\n"
9143 " gl_TessLevelInner[0] = 1.0;\n"
9144 " gl_TessLevelInner[1] = 1.0;\n"
9145 " gl_TessLevelOuter[0] = 1.0;\n"
9146 " gl_TessLevelOuter[1] = 1.0;\n"
9147 " gl_TessLevelOuter[2] = 1.0;\n"
9148 " gl_TessLevelOuter[3] = 1.0;\n"
9149 "\n"
9150 " function(result[gl_InvocationID].tc_data);\n"
9151 " result[gl_InvocationID].vs_data = vs[gl_InvocationID].vs_data;\n"
9152 "}\n";
9153 }
9154
9155 /** Retrieves body of a tessellation evaluation shader that should be used
9156 * by the test program.
9157 *
9158 * @return Requested string.
9159 **/
getTessellationEvaluationShaderBody() const9160 std::string FunctionalTest17::getTessellationEvaluationShaderBody() const
9161 {
9162 return "#version 400\n"
9163 "\n"
9164 "#extension GL_ARB_shader_subroutine : require\n"
9165 "\n"
9166 "layout (quads, point_mode) in;\n"
9167 "\n"
9168 "subroutine void subroutineTypeTE(out vec4 result);\n"
9169 "\n"
9170 "subroutine(subroutineTypeTE) void subroutine1(out vec4 result)\n"
9171 "{\n"
9172 " result = vec4(3, 4, 5, 6);\n"
9173 "}\n"
9174 "\n"
9175 "subroutine uniform subroutineTypeTE function;\n"
9176 "\n"
9177 "in TC_DATA\n"
9178 "{\n"
9179 " vec4 tc_data;\n"
9180 " vec4 vs_data;\n"
9181 "} tc[];\n"
9182 "\n"
9183 "out TE_DATA\n"
9184 "{\n"
9185 " vec4 tc_data;\n"
9186 " vec4 te_data;\n"
9187 " vec4 vs_data;\n"
9188 "} result;\n"
9189 "\n"
9190 "void main()\n"
9191 "{\n"
9192 " result.vs_data = tc[0].vs_data;\n"
9193 " result.tc_data = tc[0].tc_data;\n"
9194 " function(result.te_data);\n"
9195 "}\n";
9196 }
9197
9198 /** Retrieves body of a vertex shader that should be used by the test program.
9199 *
9200 * @return Requested string.
9201 **/
getVertexShaderBody() const9202 std::string FunctionalTest17::getVertexShaderBody() const
9203 {
9204 return "#version 400\n"
9205 "\n"
9206 "#extension GL_ARB_shader_subroutine : require\n"
9207 "\n"
9208 "out VS_DATA\n"
9209 "{\n"
9210 " vec4 vs_data;\n"
9211 "} result;\n"
9212 "\n"
9213 "subroutine void subroutineTypeVS(out vec4 result);\n"
9214 "\n"
9215 "subroutine(subroutineTypeVS) void subroutine1(out vec4 result)\n"
9216 "{\n"
9217 " result = vec4(1, 2, 3, 4);\n"
9218 "}\n"
9219 "\n"
9220 "subroutine uniform subroutineTypeVS function;\n"
9221 "\n"
9222 "void main()\n"
9223 "{\n"
9224 " function(result.vs_data);\n"
9225 "}\n";
9226 }
9227
9228 /** Initializes all buffers and GL objects required to run the test. */
initTest()9229 void FunctionalTest17::initTest()
9230 {
9231 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
9232
9233 /* Configure GL_PATCH_VERTICES so that TC only takes a single patch vertex */
9234 gl.patchParameteri(GL_PATCH_VERTICES, 1);
9235 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteri() call failed.");
9236
9237 /* Generate & bind a VAO */
9238 gl.genVertexArrays(1, &m_vao_id);
9239 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
9240
9241 gl.bindVertexArray(m_vao_id);
9242 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
9243
9244 /* Set up test program object */
9245 std::string fs_body = getFragmentShaderBody();
9246 std::string gs_body = getGeometryShaderBody();
9247 std::string tc_body = getTessellationControlShaderBody();
9248 std::string te_body = getTessellationEvaluationShaderBody();
9249 std::string vs_body = getVertexShaderBody();
9250
9251 if (!Utils::buildProgram(gl, vs_body, tc_body, te_body, gs_body, fs_body, DE_NULL, /* xfb_varyings */
9252 DE_NULL, /* n_xfb_varyings */
9253 &m_vs_id, &m_tc_id, &m_te_id, &m_gs_id, &m_fs_id, &m_po_id))
9254 {
9255 TCU_FAIL("Failed to link test program object");
9256 }
9257
9258 /* Set up a texture object that will be used as a color attachment */
9259 gl.genTextures(1, &m_to_id);
9260 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed.");
9261
9262 gl.bindTexture(GL_TEXTURE_2D, m_to_id);
9263 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
9264
9265 gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
9266 GL_RGBA32F, m_to_width, m_to_height);
9267 GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed.");
9268
9269 /* Set up FBO */
9270 gl.genFramebuffers(1, &m_fbo_id);
9271 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed.");
9272
9273 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
9274 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed.");
9275
9276 gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0 /* level */);
9277 GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
9278
9279 /* Make sure glReadPixels() does not return misaligned data */
9280 gl.pixelStorei(GL_PACK_ALIGNMENT, 1);
9281 GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call failed.");
9282
9283 /* Initialize a buffer that will be used to store rendered data */
9284 m_to_data = new float[m_to_width * m_to_height * 4 /* rgba */];
9285 }
9286
9287 /** Executes test iteration.
9288 *
9289 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
9290 */
iterate()9291 tcu::TestNode::IterateResult FunctionalTest17::iterate()
9292 {
9293 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
9294
9295 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
9296 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
9297 {
9298 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
9299 }
9300
9301 initTest();
9302
9303 /* Use the test program to render a full-screen test quad */
9304 gl.useProgram(m_po_id);
9305 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
9306
9307 gl.drawArrays(GL_PATCHES, 0 /* first */, 1 /* count */);
9308 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
9309
9310 /* Read back the data that was rendered */
9311 gl.readPixels(0, /* x */
9312 0, /* y */
9313 m_to_width, m_to_height, GL_RGBA, GL_FLOAT, m_to_data);
9314 GLU_EXPECT_NO_ERROR(gl.getError(), "glReaDPixels() call failed.");
9315
9316 /* Verify the data */
9317 verifyRenderedData();
9318
9319 /** All done */
9320 if (m_has_test_passed)
9321 {
9322 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
9323 }
9324 else
9325 {
9326 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
9327 }
9328
9329 return STOP;
9330 }
9331
9332 /** Verifies the data that have been rendered by the test program.
9333 *
9334 * It is assumed the rendered data have already been copied to
9335 * m_to_data.
9336 *
9337 * If the rendered data is found to be invalid, m_has_test_passed
9338 * will be set to false.
9339 **/
verifyRenderedData()9340 void FunctionalTest17::verifyRenderedData()
9341 {
9342 const float epsilon = 1e-5f;
9343 const float expected_data[4] = { 15.0f, 20.0f, 25.0f, 30.0f };
9344
9345 for (unsigned int y = 0; y < m_to_height && m_has_test_passed; ++y)
9346 {
9347 const float* row_ptr = m_to_data + y * 4 /* rgba */ * m_to_width;
9348
9349 for (unsigned int x = 0; x < m_to_width && m_has_test_passed; ++x)
9350 {
9351 const float* pixel_ptr = row_ptr + 4 /* rgba */ * x;
9352
9353 if (de::abs(pixel_ptr[0] - expected_data[0]) > epsilon ||
9354 de::abs(pixel_ptr[1] - expected_data[1]) > epsilon ||
9355 de::abs(pixel_ptr[2] - expected_data[2]) > epsilon ||
9356 de::abs(pixel_ptr[3] - expected_data[3]) > epsilon)
9357 {
9358 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid texel found at (" << x << ", " << y
9359 << "): "
9360 "expected:("
9361 << expected_data[0] << ", " << expected_data[1] << ", " << expected_data[2] << ", "
9362 << expected_data[3] << "), found:(" << pixel_ptr[0] << ", " << pixel_ptr[1] << ", "
9363 << pixel_ptr[2] << ", " << pixel_ptr[3] << ")." << tcu::TestLog::EndMessage;
9364
9365 m_has_test_passed = false;
9366 }
9367 } /* for (all columns) */
9368 } /* for (all rows) */
9369 }
9370
9371 /** Constructor.
9372 *
9373 * @param context Rendering context.
9374 *
9375 **/
FunctionalTest18_19(deqp::Context & context)9376 FunctionalTest18_19::FunctionalTest18_19(deqp::Context& context)
9377 : TestCase(context, "control_flow_and_returned_subroutine_values_used_as_subroutine_input",
9378 "Makes sure that calling a subroutine with argument value returned by "
9379 "another subroutine works correctly. Also checks that subroutine and "
9380 "subroutine uniforms work as expected when used in connection with control "
9381 "flow functions.")
9382 , m_has_test_passed(true)
9383 , m_n_points_to_draw(16) /* arbitrary value */
9384 , m_po_id(0)
9385 , m_po_subroutine_divide_by_two_location(GL_INVALID_INDEX)
9386 , m_po_subroutine_multiply_by_four_location(GL_INVALID_INDEX)
9387 , m_po_subroutine_returns_false_location(GL_INVALID_INDEX)
9388 , m_po_subroutine_returns_true_location(GL_INVALID_INDEX)
9389 , m_po_subroutine_uniform_bool_operator1(-1)
9390 , m_po_subroutine_uniform_bool_operator2(-1)
9391 , m_po_subroutine_uniform_vec4_processor1(-1)
9392 , m_po_subroutine_uniform_vec4_processor2(-1)
9393 , m_xfb_bo_id(0)
9394 , m_vao_id(0)
9395 , m_vs_id(0)
9396 {
9397 /* Left blank intentionally */
9398 }
9399
9400 /** De-initializes all GL objects that may have been created during test execution */
deinit()9401 void FunctionalTest18_19::deinit()
9402 {
9403 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
9404
9405 if (m_po_id != 0)
9406 {
9407 gl.deleteProgram(m_po_id);
9408
9409 m_po_id = 0;
9410 }
9411
9412 if (m_vao_id != 0)
9413 {
9414 gl.deleteVertexArrays(1, &m_vao_id);
9415
9416 m_vao_id = 0;
9417 }
9418
9419 if (m_vs_id != 0)
9420 {
9421 gl.deleteShader(m_vs_id);
9422
9423 m_vs_id = 0;
9424 }
9425
9426 if (m_xfb_bo_id != 0)
9427 {
9428 gl.deleteBuffers(1, &m_xfb_bo_id);
9429
9430 m_xfb_bo_id = 0;
9431 }
9432 }
9433
9434 /** Executes a single test iteration using user-specified properties. If the
9435 * iterations fails, m_has_test_passed is set to false.
9436 *
9437 * @param bool_operator1_subroutine_location Location of a subroutine to be assigned to
9438 * bool_operator1 subroutine uniform.
9439 * @param bool_operator2_subroutine_location Location of a subroutine to be assigned to
9440 * bool_operator2 subroutine uniform.
9441 * @param vec4_operator1_subroutine_location Location of a subroutine to be assigned to
9442 * vec4_operator1 subroutine uniform.
9443 * @param vec4_operator2_subroutine_location Location of a subroutine to be assigned to
9444 * vec4_operator2 subroutine uniform.
9445 &**/
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)9446 void FunctionalTest18_19::executeTest(glw::GLuint bool_operator1_subroutine_location,
9447 glw::GLuint bool_operator2_subroutine_location,
9448 glw::GLuint vec4_operator1_subroutine_location,
9449 glw::GLuint vec4_operator2_subroutine_location)
9450 {
9451 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
9452
9453 /* Set up subroutines */
9454 glw::GLuint subroutine_configuration[4 /* total number of subroutines */] = { 0 };
9455
9456 subroutine_configuration[m_po_subroutine_uniform_bool_operator1] = bool_operator1_subroutine_location;
9457 subroutine_configuration[m_po_subroutine_uniform_bool_operator2] = bool_operator2_subroutine_location;
9458 subroutine_configuration[m_po_subroutine_uniform_vec4_processor1] = vec4_operator1_subroutine_location;
9459 subroutine_configuration[m_po_subroutine_uniform_vec4_processor2] = vec4_operator2_subroutine_location;
9460
9461 gl.useProgram(m_po_id);
9462 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
9463
9464 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, 4 /* count */, subroutine_configuration);
9465 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniformSubroutinesuiv() call failed");
9466
9467 /* Draw test-specific number of points */
9468 gl.beginTransformFeedback(GL_POINTS);
9469 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed");
9470 {
9471 gl.drawArrays(GL_POINTS, 0 /* first */, m_n_points_to_draw);
9472 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed");
9473 }
9474 gl.endTransformFeedback();
9475 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed");
9476
9477 /* Map the BO storage into process space */
9478 const glw::GLvoid* xfb_data_ptr = gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
9479 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer() call failed.");
9480
9481 verifyXFBData(xfb_data_ptr, bool_operator1_subroutine_location, bool_operator2_subroutine_location,
9482 vec4_operator1_subroutine_location, vec4_operator2_subroutine_location);
9483
9484 /* Unmap BO storage */
9485 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
9486 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
9487 }
9488
9489 /** Retrieves body of a vertex shader to be used by the test. */
getVertexShaderBody() const9490 std::string FunctionalTest18_19::getVertexShaderBody() const
9491 {
9492 return "#version 400\n"
9493 "\n"
9494 "subroutine bool bool_processor();\n"
9495 "subroutine vec4 vec4_processor(in vec4 iparam);\n"
9496 "\n"
9497 "subroutine(bool_processor) bool returnsFalse()\n"
9498 "{\n"
9499 " return false;\n"
9500 "}\n"
9501 "\n"
9502 "subroutine(bool_processor) bool returnsTrue()\n"
9503 "{\n"
9504 " return true;\n"
9505 "}\n"
9506 "\n"
9507 "subroutine(vec4_processor) vec4 divideByTwo(in vec4 iparam)\n"
9508 "{\n"
9509 " return iparam * vec4(0.5);\n"
9510 "}\n"
9511 "\n"
9512 "subroutine(vec4_processor) vec4 multiplyByFour(in vec4 iparam)\n"
9513 "{\n"
9514 " return iparam * vec4(4.0);\n"
9515 "}\n"
9516 "\n"
9517 "subroutine uniform bool_processor bool_operator1;\n"
9518 "subroutine uniform bool_processor bool_operator2;\n"
9519 "subroutine uniform vec4_processor vec4_operator1;\n"
9520 "subroutine uniform vec4_processor vec4_operator2;\n"
9521 "\n"
9522 "out float result;\n"
9523 "\n"
9524 "void main()\n"
9525 "{\n"
9526 " if (bool_operator1() )\n"
9527 " {\n"
9528 " float value = float( (3 * gl_VertexID + 1) * 2);\n"
9529 "\n"
9530 " while (bool_operator1() )\n"
9531 " {\n"
9532 " value /= float(gl_VertexID + 2);\n"
9533 "\n"
9534 " if (value <= 1.0f) break;\n"
9535 " }\n"
9536 "\n"
9537 " result = value;\n"
9538 " }\n"
9539 " else\n"
9540 " {\n"
9541 " vec4 value = vec4(gl_VertexID, gl_VertexID + 1,\n"
9542 " gl_VertexID + 2, gl_VertexID + 3);\n"
9543 "\n"
9544 " switch (gl_VertexID % 2)\n"
9545 " {\n"
9546 " case 0:\n"
9547 " {\n"
9548 " for (int iteration = 0; iteration < gl_VertexID && bool_operator2(); ++iteration)\n"
9549 " {\n"
9550 " value = vec4_operator2(vec4_operator1(value));\n"
9551 " }\n"
9552 "\n"
9553 " break;\n"
9554 " }\n"
9555 "\n"
9556 " case 1:\n"
9557 " {\n"
9558 " for (int iteration = 0; iteration < gl_VertexID * 2; ++iteration)\n"
9559 " {\n"
9560 " value = vec4_operator1(vec4_operator2(value));\n"
9561 " }\n"
9562 "\n"
9563 " break;\n"
9564 " }\n"
9565 " }\n"
9566 "\n"
9567 " result = value.x + value.y + value.z + value.w;\n"
9568 "\n"
9569 " }\n"
9570 "}\n";
9571 }
9572
9573 /** Initializes all GL objects required to run the test. */
initTest()9574 void FunctionalTest18_19::initTest()
9575 {
9576 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
9577 const char* varyings[1] = { "result" };
9578 std::string vs_body = getVertexShaderBody();
9579 const unsigned int n_varyings = sizeof(varyings) / sizeof(varyings[0]);
9580
9581 if (!Utils::buildProgram(gl, vs_body, "", /* tc_body */
9582 "", /* te_body */
9583 "", /* gs_body */
9584 "", /* fs_body */
9585 varyings, n_varyings, &m_vs_id, DE_NULL, /* out_tc_id */
9586 DE_NULL, /* out_te_id */
9587 DE_NULL, /* out_gs_id */
9588 DE_NULL, /* out_fs_id */
9589 &m_po_id))
9590 {
9591 TCU_FAIL("Failed to build test program object");
9592 }
9593
9594 /* Retrieve subroutine & subroutine uniform locations */
9595 m_po_subroutine_divide_by_two_location = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "divideByTwo");
9596 m_po_subroutine_multiply_by_four_location = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "multiplyByFour");
9597 m_po_subroutine_returns_false_location = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "returnsFalse");
9598 m_po_subroutine_returns_true_location = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "returnsTrue");
9599 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineIndex() call(s) failed");
9600
9601 if (m_po_subroutine_divide_by_two_location == GL_INVALID_INDEX ||
9602 m_po_subroutine_multiply_by_four_location == GL_INVALID_INDEX ||
9603 m_po_subroutine_returns_false_location == GL_INVALID_INDEX ||
9604 m_po_subroutine_returns_true_location == GL_INVALID_INDEX)
9605 {
9606 TCU_FAIL("glGetSubroutineIndex() returned GL_INVALID_INDEX for a valid subroutine");
9607 }
9608
9609 m_po_subroutine_uniform_bool_operator1 =
9610 gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "bool_operator1");
9611 m_po_subroutine_uniform_bool_operator2 =
9612 gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "bool_operator2");
9613 m_po_subroutine_uniform_vec4_processor1 =
9614 gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "vec4_operator1");
9615 m_po_subroutine_uniform_vec4_processor2 =
9616 gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "vec4_operator2");
9617 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineUniformLocation() call(s) failed");
9618
9619 if (m_po_subroutine_uniform_bool_operator1 == -1 || m_po_subroutine_uniform_bool_operator2 == -1 ||
9620 m_po_subroutine_uniform_vec4_processor1 == -1 || m_po_subroutine_uniform_vec4_processor2 == -1)
9621 {
9622 TCU_FAIL("glGetSubroutineUniformLocation() returned -1 for an active subroutine uniform");
9623 }
9624
9625 /* Set up XFB BO */
9626 const unsigned int bo_size = static_cast<unsigned int>(sizeof(float) * m_n_points_to_draw);
9627
9628 gl.genBuffers(1, &m_xfb_bo_id);
9629 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
9630
9631 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_xfb_bo_id);
9632 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
9633
9634 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_xfb_bo_id);
9635 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed.");
9636
9637 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, DE_NULL /* data */, GL_STATIC_COPY);
9638 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
9639
9640 /* Set up a VAO */
9641 gl.genVertexArrays(1, &m_vao_id);
9642 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
9643
9644 gl.bindVertexArray(m_vao_id);
9645 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
9646 }
9647
9648 /** Executes test iteration.
9649 *
9650 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
9651 */
iterate()9652 tcu::TestNode::IterateResult FunctionalTest18_19::iterate()
9653 {
9654 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
9655 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
9656 {
9657 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
9658 }
9659
9660 /* Initialize all GL objects required to run the test */
9661 initTest();
9662
9663 /* Iterate over all subroutine permutations */
9664 const glw::GLuint subroutine_bool_operators[] = { m_po_subroutine_returns_false_location,
9665 m_po_subroutine_returns_true_location };
9666 const unsigned int n_subroutine_bool_operators =
9667 sizeof(subroutine_bool_operators) / sizeof(subroutine_bool_operators[0]);
9668
9669 const glw::GLuint subroutine_vec4_operators[] = { m_po_subroutine_divide_by_two_location,
9670 m_po_subroutine_multiply_by_four_location };
9671 const unsigned int n_subroutine_vec4_operators =
9672 sizeof(subroutine_vec4_operators) / sizeof(subroutine_vec4_operators[0]);
9673
9674 for (unsigned int n_subroutine_uniform_bool_operator1 = 0;
9675 n_subroutine_uniform_bool_operator1 < n_subroutine_bool_operators; ++n_subroutine_uniform_bool_operator1)
9676 {
9677 for (unsigned int n_subroutine_uniform_bool_operator2 = 0;
9678 n_subroutine_uniform_bool_operator2 < n_subroutine_bool_operators; ++n_subroutine_uniform_bool_operator2)
9679 {
9680 for (unsigned int n_subroutine_uniform_vec4_operator1 = 0;
9681 n_subroutine_uniform_vec4_operator1 < n_subroutine_vec4_operators;
9682 ++n_subroutine_uniform_vec4_operator1)
9683 {
9684 for (unsigned int n_subroutine_uniform_vec4_operator2 = 0;
9685 n_subroutine_uniform_vec4_operator2 < n_subroutine_vec4_operators;
9686 ++n_subroutine_uniform_vec4_operator2)
9687 {
9688 executeTest(subroutine_bool_operators[n_subroutine_uniform_bool_operator1],
9689 subroutine_bool_operators[n_subroutine_uniform_bool_operator2],
9690 subroutine_vec4_operators[n_subroutine_uniform_vec4_operator1],
9691 subroutine_vec4_operators[n_subroutine_uniform_vec4_operator2]);
9692 } /* for (all subroutine vec4 operator subroutines used for processor2) */
9693 } /* for (all subroutine vec4 operator subroutines used for processor1) */
9694 } /* for (all subroutine bool operator subroutines used for operator2) */
9695 } /* for (all subroutine bool operator subroutines used for operator1) */
9696
9697 /* All done */
9698 if (m_has_test_passed)
9699 {
9700 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
9701 }
9702 else
9703 {
9704 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
9705 }
9706
9707 return STOP;
9708 }
9709
9710 /** Divides input argument by two. The result value is returned to the
9711 * caller.
9712 *
9713 * @param data Input value.
9714 *
9715 * @return As per description.
9716 **/
vec4operator_div2(tcu::Vec4 data)9717 tcu::Vec4 FunctionalTest18_19::vec4operator_div2(tcu::Vec4 data)
9718 {
9719 return data * 0.5f;
9720 }
9721
9722 /** Multiplies input argument by four. The result value is returned to the
9723 * caller.
9724 *
9725 * @param data Input value.
9726 *
9727 * @return As per description.
9728 **/
vec4operator_mul4(tcu::Vec4 data)9729 tcu::Vec4 FunctionalTest18_19::vec4operator_mul4(tcu::Vec4 data)
9730 {
9731 return data * 4.0f;
9732 }
9733
9734 /** Verifies data XFBed out by the vertex shader. It is assumed the subroutines were configured
9735 * as per passed arguments, prior to the draw call.
9736 *
9737 * If the result data is found to be invalid, m_has_test_passed is set to false.
9738 *
9739 * @param data XFBed data.
9740 * @param bool_operator1_subroutine_location Location of a subroutine to be assigned to
9741 * bool_operator1 subroutine uniform.
9742 * @param bool_operator2_subroutine_location Location of a subroutine to be assigned to
9743 * bool_operator2 subroutine uniform.
9744 * @param vec4_operator1_subroutine_location Location of a subroutine to be assigned to
9745 * vec4_operator1 subroutine uniform.
9746 * @param vec4_operator2_subroutine_location Location of a subroutine to be assigned to
9747 * vec4_operator2 subroutine uniform.
9748 */
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)9749 void FunctionalTest18_19::verifyXFBData(const glw::GLvoid* data, glw::GLuint bool_operator1_subroutine_location,
9750 glw::GLuint bool_operator2_subroutine_location,
9751 glw::GLuint vec4_operator1_subroutine_location,
9752 glw::GLuint vec4_operator2_subroutine_location)
9753 {
9754 bool bool_operator1_result = false;
9755 bool bool_operator2_result = false;
9756 const float epsilon = 1e-5f;
9757 PFNVEC4OPERATORPROC pVec4Operator1 = NULL;
9758 PFNVEC4OPERATORPROC pVec4Operator2 = NULL;
9759 const glw::GLfloat* traveller_ptr = (const glw::GLfloat*)data;
9760
9761 bool_operator1_result = (bool_operator1_subroutine_location == m_po_subroutine_returns_true_location);
9762 bool_operator2_result = (bool_operator2_subroutine_location == m_po_subroutine_returns_true_location);
9763 pVec4Operator1 = (vec4_operator1_subroutine_location == m_po_subroutine_divide_by_two_location) ?
9764 vec4operator_div2 :
9765 vec4operator_mul4;
9766 pVec4Operator2 = (vec4_operator2_subroutine_location == m_po_subroutine_divide_by_two_location) ?
9767 vec4operator_div2 :
9768 vec4operator_mul4;
9769
9770 for (unsigned int n_vertex = 0; n_vertex < m_n_points_to_draw; ++n_vertex)
9771 {
9772 float expected_value = 0.0f;
9773
9774 if (bool_operator1_result)
9775 {
9776 float value = float((3 * n_vertex + 1) * 2);
9777
9778 while (bool_operator1_result)
9779 {
9780 value /= float(n_vertex + 2);
9781
9782 if (value <= 1.0f)
9783 break;
9784 }
9785
9786 expected_value = value;
9787 }
9788 else
9789 {
9790 tcu::Vec4 value((float)n_vertex, (float)n_vertex + 1, (float)n_vertex + 2, (float)n_vertex + 3);
9791
9792 switch (n_vertex % 2)
9793 {
9794 case 0:
9795 {
9796 for (unsigned int iteration = 0; iteration < n_vertex && bool_operator2_result; ++iteration)
9797 {
9798 value = pVec4Operator2(pVec4Operator1(value));
9799 }
9800
9801 break;
9802 }
9803
9804 case 1:
9805 {
9806 for (unsigned int iteration = 0; iteration < n_vertex * 2; ++iteration)
9807 {
9808 value = pVec4Operator1(pVec4Operator2(value));
9809 }
9810
9811 break;
9812 }
9813 } /* switch (n_vertex % 2) */
9814
9815 expected_value = value.x() + value.y() + value.z() + value.w();
9816 }
9817
9818 if (de::abs(expected_value - *traveller_ptr) > epsilon)
9819 {
9820 m_testCtx.getLog() << tcu::TestLog::Message << "XFBed data was found to be invalid at index [" << n_vertex
9821 << "]"
9822 "for the following subroutine location configuration:"
9823 " bool_operator1_subroutine_location:["
9824 << bool_operator1_subroutine_location << "]"
9825 " bool_operator2_subroutine_location:["
9826 << bool_operator2_subroutine_location << "]"
9827 " vec4_operator1_subroutine_location:["
9828 << vec4_operator1_subroutine_location << "]"
9829 " vec4_operator2_subroutine_location:["
9830 << vec4_operator2_subroutine_location << "];"
9831 " expected data:"
9832 << expected_value << ", found:" << *traveller_ptr << tcu::TestLog::EndMessage;
9833
9834 m_has_test_passed = false;
9835 }
9836
9837 ++traveller_ptr;
9838 } /* for (all drawn points) */
9839 }
9840
9841 /** Constructor.
9842 *
9843 * @param context Rendering context.
9844 *
9845 **/
NegativeTest1(deqp::Context & context)9846 NegativeTest1::NegativeTest1(deqp::Context& context)
9847 : TestCase(context, "subroutine_errors", "Verifies all GL_INVALID_OPERATION, GL_INVALID_VALUE, GL_INVALID ENUM "
9848 "errors related to subroutine usage are properly generated.")
9849 , m_has_test_passed(true)
9850 , m_po_active_subroutine_uniform_locations(0)
9851 , m_po_active_subroutine_uniforms(0)
9852 , m_po_active_subroutines(0)
9853 , m_po_subroutine_uniform_function_index(-1)
9854 , m_po_subroutine_uniform_function2_index(-1)
9855 , m_po_subroutine_test1_index(GL_INVALID_INDEX)
9856 , m_po_subroutine_test2_index(GL_INVALID_INDEX)
9857 , m_po_subroutine_test3_index(GL_INVALID_INDEX)
9858 , m_po_not_linked_id(0)
9859 , m_po_id(0)
9860 , m_vs_id(0)
9861 {
9862 /* Left blank intentionally */
9863 }
9864
9865 /** Deinitializes all GL objects that may have been created during
9866 * test execution.
9867 **/
deinit()9868 void NegativeTest1::deinit()
9869 {
9870 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
9871
9872 if (m_po_id != 0)
9873 {
9874 gl.deleteProgram(m_po_id);
9875
9876 m_po_id = 0;
9877 }
9878
9879 if (m_po_not_linked_id != 0)
9880 {
9881 gl.deleteProgram(m_po_not_linked_id);
9882
9883 m_po_not_linked_id = 0;
9884 }
9885
9886 if (m_vs_id != 0)
9887 {
9888 gl.deleteShader(m_vs_id);
9889
9890 m_vs_id = 0;
9891 }
9892 }
9893
9894 /** Initializes all GL objects required to run the test. */
initTest()9895 void NegativeTest1::initTest()
9896 {
9897 glw::GLint compile_status = GL_FALSE;
9898 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
9899
9900 /* Create program objects */
9901 m_po_not_linked_id = gl.createProgram();
9902 m_po_id = gl.createProgram();
9903 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call(s) failed.");
9904
9905 /* Create vertex shader object */
9906 m_vs_id = gl.createShader(GL_VERTEX_SHADER);
9907 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
9908
9909 /* Set up vertex shader */
9910 const char* vs_body = "#version 400\n"
9911 "\n"
9912 "#extension GL_ARB_shader_subroutine : require\n"
9913 "\n"
9914 "subroutine void subroutineType (out ivec2 arg);\n"
9915 "subroutine void subroutineType2(out ivec4 arg);\n"
9916 "\n"
9917 "subroutine(subroutineType) void test1(out ivec2 arg)\n"
9918 "{\n"
9919 " arg = ivec2(1, 2);\n"
9920 "}\n"
9921 "subroutine(subroutineType) void test2(out ivec2 arg)\n"
9922 "{\n"
9923 " arg = ivec2(3,4);\n"
9924 "}\n"
9925 "subroutine(subroutineType2) void test3(out ivec4 arg)\n"
9926 "{\n"
9927 " arg = ivec4(1, 2, 3, 4);\n"
9928 "}\n"
9929 "\n"
9930 "subroutine uniform subroutineType function;\n"
9931 "subroutine uniform subroutineType2 function2;\n"
9932 "\n"
9933 "void main()\n"
9934 "{\n"
9935 " ivec2 test;\n"
9936 " ivec4 test2;\n"
9937 "\n"
9938 " function(test);\n"
9939 "\n"
9940 " if (test.x > 2)\n"
9941 " {\n"
9942 " gl_Position = vec4(1);\n"
9943 " }\n"
9944 " else\n"
9945 " {\n"
9946 " function2(test2);\n"
9947 "\n"
9948 " gl_Position = vec4(float(test2.x) );\n"
9949 " }\n"
9950 "}\n";
9951
9952 gl.shaderSource(m_vs_id, 1 /* count */, &vs_body, DE_NULL /* length */);
9953 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed");
9954
9955 gl.compileShader(m_vs_id);
9956 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed");
9957
9958 gl.getShaderiv(m_vs_id, GL_COMPILE_STATUS, &compile_status);
9959 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed");
9960
9961 if (compile_status == GL_FALSE)
9962 {
9963 TCU_FAIL("Shader compilation failed");
9964 }
9965
9966 /* Set up & link the test program object */
9967 glw::GLint link_status = GL_FALSE;
9968
9969 gl.attachShader(m_po_id, m_vs_id);
9970 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
9971
9972 gl.linkProgram(m_po_id);
9973 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
9974
9975 gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
9976 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
9977
9978 if (link_status == GL_FALSE)
9979 {
9980 TCU_FAIL("Program linking failed");
9981 }
9982
9983 /* Query test program object's properties */
9984 gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS,
9985 &m_po_active_subroutine_uniform_locations);
9986 gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORMS, &m_po_active_subroutine_uniforms);
9987 gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINES, &m_po_active_subroutines);
9988 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramStageiv() call(s) failed.");
9989
9990 if (m_po_active_subroutine_uniform_locations != 2)
9991 {
9992 TCU_FAIL("Invalid GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS value returned");
9993 }
9994
9995 m_po_subroutine_test1_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "test1");
9996 m_po_subroutine_test2_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "test2");
9997 m_po_subroutine_test3_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "test3");
9998 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineIndex() call(s) failed.");
9999
10000 if (m_po_subroutine_test1_index == GL_INVALID_INDEX || m_po_subroutine_test2_index == GL_INVALID_INDEX ||
10001 m_po_subroutine_test3_index == GL_INVALID_INDEX)
10002 {
10003 TCU_FAIL("Invalid subroutine index returned");
10004 }
10005
10006 m_po_subroutine_uniform_function_index = gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "function");
10007 m_po_subroutine_uniform_function2_index = gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "function2");
10008 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineUniformLocation() call(s) failed.");
10009
10010 if (m_po_subroutine_uniform_function_index == -1 || m_po_subroutine_uniform_function2_index == -1)
10011 {
10012 TCU_FAIL("Invalid subroutine uniform index returned");
10013 }
10014 }
10015
10016 /** Executes test iteration.
10017 *
10018 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
10019 */
iterate()10020 tcu::TestNode::IterateResult NegativeTest1::iterate()
10021 {
10022 glw::GLenum error_code = GL_NO_ERROR;
10023 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
10024
10025 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
10026 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
10027 {
10028 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
10029 }
10030
10031 /* Initialize GL objects required to run the test */
10032 initTest();
10033
10034 /* The error INVALID_OPERATION is generated by GetSubroutineUniformLocation
10035 * if the program object identified by <program> has not been successfully
10036 * linked.
10037 */
10038 gl.getSubroutineUniformLocation(m_po_not_linked_id, GL_FRAGMENT_SHADER, "subroutine_uniform_name");
10039
10040 error_code = gl.getError();
10041
10042 if (error_code != GL_INVALID_OPERATION)
10043 {
10044 m_testCtx.getLog() << tcu::TestLog::Message
10045 << "glGetSubroutineUniformLocation() does not generate GL_INVALID_OPERATION "
10046 "error code when called for a non-linked program object."
10047 << tcu::TestLog::EndMessage;
10048
10049 m_has_test_passed = false;
10050 }
10051
10052 /* The error INVALID_VALUE is generated by GetActiveSubroutineUniformiv or
10053 * GetActiveSubroutineUniformName if <index> is greater than or equal to the
10054 * value of ACTIVE_SUBROUTINE_UNIFORMS for the shader stage.
10055 */
10056 glw::GLint temp_length = 0;
10057 glw::GLint temp_values = 0;
10058
10059 gl.getActiveSubroutineUniformiv(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutine_uniforms,
10060 GL_NUM_COMPATIBLE_SUBROUTINES, &temp_values);
10061 error_code = gl.getError();
10062
10063 if (error_code == GL_INVALID_VALUE)
10064 {
10065 gl.getActiveSubroutineUniformiv(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutine_uniforms + 1,
10066 GL_NUM_COMPATIBLE_SUBROUTINES, &temp_values);
10067
10068 error_code = gl.getError();
10069 }
10070
10071 if (error_code != GL_INVALID_VALUE)
10072 {
10073 m_testCtx.getLog() << tcu::TestLog::Message
10074 << "glGetActiveSubroutineUniformiv() does not generate GL_INVALID_VALUE "
10075 "when passed <index> argument that is greater than or equal to "
10076 "the value of GL_ACTIVE_SUBROUTINE_UNIFORMS."
10077 << tcu::TestLog::EndMessage;
10078
10079 m_has_test_passed = false;
10080 }
10081
10082 gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutine_uniforms, 0, /* bufsize */
10083 &temp_length, DE_NULL); /* name */
10084 error_code = gl.getError();
10085
10086 if (error_code == GL_INVALID_VALUE)
10087 {
10088 gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutine_uniforms + 1,
10089 0, /* bufsize */
10090 &temp_length, DE_NULL); /* name */
10091
10092 error_code = gl.getError();
10093 }
10094
10095 if (error_code != GL_INVALID_VALUE)
10096 {
10097 m_testCtx.getLog() << tcu::TestLog::Message
10098 << "glGetActiveSubroutineUniformName() does not generate GL_INVALID_VALUE "
10099 "when passed <index> argument that is greater than or equal to "
10100 "the value of GL_ACTIVE_SUBROUTINE_UNIFORMS."
10101 << tcu::TestLog::EndMessage;
10102
10103 m_has_test_passed = false;
10104 }
10105
10106 /* The error INVALID_VALUE is generated by GetActiveSubroutineName if <index>
10107 * is greater than or equal to the value of ACTIVE_SUBROUTINES for the shader
10108 * stage.
10109 */
10110 gl.getActiveSubroutineName(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutines, 0, /* bufsize */
10111 &temp_length, DE_NULL); /* name */
10112 error_code = gl.getError();
10113
10114 if (error_code == GL_INVALID_VALUE)
10115 {
10116 gl.getActiveSubroutineName(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutines + 1, 0, /* bufsize */
10117 &temp_length, DE_NULL); /* name */
10118
10119 error_code = gl.getError();
10120 }
10121
10122 if (error_code != GL_INVALID_VALUE)
10123 {
10124 m_testCtx.getLog() << tcu::TestLog::Message << "glGetActiveSubroutineName() does not generate GL_INVALID_VALUE "
10125 "when passed <index> argument that is greater than or equal to "
10126 "the value of GL_ACTIVE_SUBROUTINES."
10127 << tcu::TestLog::EndMessage;
10128
10129 m_has_test_passed = false;
10130 }
10131
10132 /* The error INVALID_VALUE is generated by UniformSubroutinesuiv if <count>
10133 * is not equal to the value of ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS for the
10134 * shader stage <shadertype>.
10135 */
10136 glw::GLuint index = 0;
10137
10138 gl.useProgram(m_po_id);
10139 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
10140
10141 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations - 1, &index);
10142 error_code = gl.getError();
10143
10144 if (error_code == GL_INVALID_VALUE)
10145 {
10146 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations + 1, &index);
10147
10148 error_code = gl.getError();
10149 }
10150
10151 if (error_code != GL_INVALID_VALUE)
10152 {
10153 m_testCtx.getLog() << tcu::TestLog::Message << "glUniformSubroutinesiv() does not generate GL_INVALID_VALUE "
10154 "when passed <count> argument that is not equal to the value of "
10155 "GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS."
10156 << tcu::TestLog::EndMessage;
10157
10158 m_has_test_passed = false;
10159 }
10160
10161 /* The error INVALID_VALUE is generated by UniformSubroutinesuiv if any value
10162 * in <indices> is greater than or equal to the value of ACTIVE_SUBROUTINES
10163 * for the shader stage.
10164 */
10165 glw::GLuint invalid_subroutine_indices[4] = { (GLuint)m_po_active_subroutines, (GLuint)m_po_active_subroutines,
10166 (GLuint)m_po_active_subroutines + 1,
10167 (GLuint)m_po_active_subroutines + 1 };
10168
10169 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations, /* count */
10170 invalid_subroutine_indices + 0);
10171 error_code = gl.getError();
10172
10173 if (error_code == GL_INVALID_VALUE)
10174 {
10175 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations,
10176 invalid_subroutine_indices + 2);
10177
10178 error_code = gl.getError();
10179 }
10180
10181 if (error_code != GL_INVALID_VALUE)
10182 {
10183 m_testCtx.getLog() << tcu::TestLog::Message << "glUniformSubroutinesuiv() does not generate GL_INVALID_VALUE "
10184 "when the value passed via <indices> argument is greater than "
10185 "or equal to the value of GL_ACTIVE_SUBROUTINES."
10186 << tcu::TestLog::EndMessage;
10187
10188 m_has_test_passed = false;
10189 }
10190
10191 /* The error INVALID_OPERATION is generated by UniformSubroutinesuiv() if any
10192 * subroutine index in <indices> identifies a subroutine not associated with
10193 * the type of the subroutine uniform variable assigned to the corresponding
10194 * location.
10195 */
10196 glw::GLuint invalid_subroutine_indices2[2] = { m_po_subroutine_test1_index, m_po_subroutine_test1_index };
10197
10198 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations, invalid_subroutine_indices2);
10199 error_code = gl.getError();
10200
10201 if (error_code != GL_INVALID_OPERATION)
10202 {
10203 m_testCtx.getLog() << tcu::TestLog::Message
10204 << "glUniformSubroutinesuiv() does not generate GL_INVALID_OPERATION "
10205 "when the subroutine index passed via <indices> argument identifies"
10206 "a subroutine not associated with the type of the subroutine uniform "
10207 "assigned to the corresponding location."
10208 << tcu::TestLog::EndMessage;
10209
10210 m_has_test_passed = false;
10211 }
10212
10213 /* The error INVALID_OPERATION is generated by UniformSubroutinesuiv if no
10214 * program is active.
10215 */
10216 glw::GLuint valid_subroutine_locations[2] = { 0 };
10217
10218 valid_subroutine_locations[m_po_subroutine_uniform_function_index] = m_po_subroutine_test1_index;
10219 valid_subroutine_locations[m_po_subroutine_uniform_function2_index] = m_po_subroutine_test3_index;
10220
10221 gl.useProgram(0);
10222 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
10223
10224 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations, valid_subroutine_locations);
10225 error_code = gl.getError();
10226
10227 if (error_code != GL_INVALID_OPERATION)
10228 {
10229 m_testCtx.getLog() << tcu::TestLog::Message
10230 << "glUniformSubroutinesuiv() does not generate GL_INVALID_OPERATION "
10231 "when called without an active program object."
10232 << tcu::TestLog::EndMessage;
10233
10234 m_has_test_passed = false;
10235 }
10236
10237 /* The error INVALID_VALUE is generated by GetUniformSubroutineuiv if
10238 * <location> is greater than or equal to the value of
10239 * ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS for the shader stage.
10240 */
10241 glw::GLuint temp_value = 0;
10242
10243 gl.useProgram(m_po_id);
10244 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
10245
10246 gl.getUniformSubroutineuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations, &temp_value);
10247 error_code = gl.getError();
10248
10249 if (error_code == GL_INVALID_VALUE)
10250 {
10251 gl.getUniformSubroutineuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations + 1, &temp_value);
10252 error_code = gl.getError();
10253 }
10254
10255 if (error_code != GL_INVALID_VALUE)
10256 {
10257 m_testCtx.getLog() << tcu::TestLog::Message
10258 << "glGetUniformSubroutineuiv() does not generate GL_INVALID_VALUE "
10259 "when called for location that is greater than or equal to the value "
10260 "of GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS."
10261 << tcu::TestLog::EndMessage;
10262
10263 m_has_test_passed = false;
10264 }
10265
10266 /* The error INVALID_OPERATION is generated by GetUniformSubroutineuiv if no
10267 * program is active for the shader stage identified by <shadertype>.
10268 */
10269 const glw::GLenum undefined_shader_stages[] = { GL_FRAGMENT_SHADER, GL_GEOMETRY_SHADER, GL_TESS_CONTROL_SHADER,
10270 GL_TESS_EVALUATION_SHADER };
10271 const unsigned int n_undefined_shader_stages = sizeof(undefined_shader_stages) / sizeof(undefined_shader_stages[0]);
10272
10273 for (unsigned int n_undefined_shader_stage = 0; n_undefined_shader_stage < n_undefined_shader_stages;
10274 ++n_undefined_shader_stage)
10275 {
10276 glw::GLenum shader_stage = undefined_shader_stages[n_undefined_shader_stage];
10277
10278 gl.getUniformSubroutineuiv(shader_stage, 0, /* location */
10279 &temp_value);
10280 error_code = gl.getError();
10281
10282 if (error_code != GL_INVALID_OPERATION)
10283 {
10284 m_testCtx.getLog() << tcu::TestLog::Message
10285 << "glGetUniformSubroutineuiv() does not generate GL_INVALID_OPERATION "
10286 "when called for a shader stage that is not defined for active "
10287 "program object."
10288 << tcu::TestLog::EndMessage;
10289
10290 m_has_test_passed = false;
10291 }
10292 } /* for (all undefined shader stages) */
10293
10294 /* All done */
10295 if (m_has_test_passed)
10296 {
10297 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
10298 }
10299 else
10300 {
10301 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
10302 }
10303
10304 return STOP;
10305 }
10306
10307 /** Constructor
10308 *
10309 * @param context Rendering context.
10310 *
10311 **/
NegativeTest2(deqp::Context & context)10312 NegativeTest2::NegativeTest2(deqp::Context& context)
10313 : TestCase(context, "subroutine_uniform_scope", "Verifies subroutine uniforms declared in shader stage A"
10314 "cannot be accessed from a different stage.")
10315 , m_fs_id(0)
10316 , m_gs_id(0)
10317 , m_has_test_passed(true)
10318 , m_po_id(0)
10319 , m_tc_id(0)
10320 , m_te_id(0)
10321 , m_vs_id(0)
10322 {
10323 /* Left blank intentionally */
10324 }
10325
10326 /** Deinitializes all GL objects that may have been created during test execution */
deinit()10327 void NegativeTest2::deinit()
10328 {
10329 deinitGLObjects();
10330 }
10331
10332 /** Deinitializes all GL objects that may have been created during test execution */
deinitGLObjects()10333 void NegativeTest2::deinitGLObjects()
10334 {
10335 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
10336
10337 if (m_fs_id != 0)
10338 {
10339 gl.deleteShader(m_fs_id);
10340
10341 m_fs_id = 0;
10342 }
10343
10344 if (m_gs_id != 0)
10345 {
10346 gl.deleteShader(m_gs_id);
10347
10348 m_gs_id = 0;
10349 }
10350
10351 if (m_tc_id != 0)
10352 {
10353 gl.deleteShader(m_tc_id);
10354
10355 m_tc_id = 0;
10356 }
10357
10358 if (m_te_id != 0)
10359 {
10360 gl.deleteShader(m_te_id);
10361
10362 m_te_id = 0;
10363 }
10364
10365 if (m_vs_id != 0)
10366 {
10367 gl.deleteShader(m_vs_id);
10368
10369 m_vs_id = 0;
10370 }
10371
10372 if (m_po_id != 0)
10373 {
10374 gl.deleteProgram(m_po_id);
10375
10376 m_po_id = 0;
10377 }
10378 }
10379
10380 /** Builds an offending program object and tries to link it. We're either expecting
10381 * a compile-time or link-time error here.
10382 *
10383 * If the program object builds successfully, the test has failed.
10384 *
10385 * @param referencing_stage Shader stage which defines a subroutine uniform that
10386 * should be called from fragment/geometry/tess control/
10387 * tess evaluation/vertex shader stages.
10388 *
10389 **/
executeTestCase(const Utils::_shader_stage & referencing_stage)10390 void NegativeTest2::executeTestCase(const Utils::_shader_stage& referencing_stage)
10391 {
10392 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
10393
10394 const std::string fs_body = getFragmentShaderBody(referencing_stage);
10395 const std::string gs_body = getGeometryShaderBody(referencing_stage);
10396 const std::string tc_body = getTessellationControlShaderBody(referencing_stage);
10397 const std::string te_body = getTessellationEvaluationShaderBody(referencing_stage);
10398 const std::string vs_body = getVertexShaderBody(referencing_stage);
10399
10400 if (Utils::buildProgram(gl, vs_body, tc_body, te_body, gs_body, fs_body, NULL, /* xfb_varyings */
10401 0, /* n_xfb_varyings */
10402 &m_vs_id, &m_tc_id, &m_te_id, &m_gs_id, &m_fs_id, &m_po_id))
10403 {
10404 /* Test program should not have built correctly ! */
10405 m_testCtx.getLog() << tcu::TestLog::Message << "In the following program, one of the stages references "
10406 "a subroutine that is defined in another stage. This "
10407 "is forbidden by the specification.\n"
10408 "\n"
10409 "Vertex shader:\n\n"
10410 << vs_body.c_str() << "\n\nTessellation control shader:\n\n"
10411 << tc_body.c_str() << "\n\nTessellation evaluation shader:\n\n"
10412 << te_body.c_str() << "\n\nGeometry shader:\n\n"
10413 << gs_body.c_str() << "\n\nFragment shader:\n\n"
10414 << fs_body.c_str() << tcu::TestLog::EndMessage;
10415
10416 m_has_test_passed = false;
10417 } /* if (test program was built successfully) */
10418
10419 /* Release the shaders & the program object that buildProgram() created */
10420 deinitGLObjects();
10421 }
10422
10423 /** Retrieves an offending fragment shader body.
10424 *
10425 * @param referencing_stage Shader stage which defines the subroutine uniform that
10426 * will be called from fragment shader.
10427 *
10428 * @return Requested string.
10429 **/
getFragmentShaderBody(const Utils::_shader_stage & referencing_stage) const10430 std::string NegativeTest2::getFragmentShaderBody(const Utils::_shader_stage& referencing_stage) const
10431 {
10432 std::stringstream result;
10433
10434 /* Form the pre-amble */
10435 result << "#version 400\n"
10436 "\n"
10437 "#extension GL_ARB_shader_subroutine : require\n"
10438 "\n"
10439 "subroutine void testSubroutineType(out vec4 test_argument);\n"
10440 "\n"
10441 /* Define a subroutine */
10442 "subroutine(testSubroutineType) void fs_subroutine(out vec4 test_argument)\n"
10443 "{\n"
10444 " test_argument = vec4(1, 0, 0, 0);\n"
10445 "}\n"
10446 "\n"
10447 /* Define output variables */
10448 "out vec4 result;\n"
10449 "\n"
10450 /* Define uniforms */
10451 "subroutine uniform testSubroutineType test_fs_subroutine;\n"
10452 "\n"
10453 /* Define main() */
10454 "void main()\n"
10455 "{\n"
10456 " "
10457 << getSubroutineUniformName(referencing_stage) << "(result);\n"
10458 "}\n";
10459
10460 return result.str();
10461 }
10462
10463 /** Retrieves an offending geometry shader body.
10464 *
10465 * @param referencing_stage Shader stage which defines the subroutine uniform that
10466 * will be called from geometry shader.
10467 *
10468 * @return Requested string.
10469 **/
getGeometryShaderBody(const Utils::_shader_stage & referencing_stage) const10470 std::string NegativeTest2::getGeometryShaderBody(const Utils::_shader_stage& referencing_stage) const
10471 {
10472 std::stringstream result;
10473
10474 /* Form the pre-amble */
10475 result << "#version 400\n"
10476 "\n"
10477 "#extension GL_ARB_shader_subroutine : require\n"
10478 "\n"
10479 "subroutine void testSubroutineType(out vec4 test_argument);\n"
10480 "\n"
10481 "layout(points) in;\n"
10482 "layout(points, max_vertices = 1) out;\n"
10483 "\n"
10484 /* Define a subroutine */
10485 "subroutine(testSubroutineType) void gs_subroutine(out vec4 test_argument)\n"
10486 "{\n"
10487 " test_argument = vec4(0, 1, 1, 1);\n"
10488 "}\n"
10489 "\n"
10490 /* Define output variables */
10491 "out vec4 result;\n"
10492 "\n"
10493 /* Define uniforms */
10494 "subroutine uniform testSubroutineType test_gs_subroutine;\n"
10495 "\n"
10496 /* Define main() */
10497 "void main()\n"
10498 "{\n"
10499 " "
10500 << getSubroutineUniformName(referencing_stage) << "(result);\n"
10501 "}\n";
10502
10503 return result.str();
10504 }
10505
10506 /** Retrieves name of the subroutine uniform that is defined in user-specified
10507 * shader stage.
10508 *
10509 * @param stage Shader stage to retrieve the subroutine uniform name for.
10510 *
10511 * @return As per description.
10512 **/
getSubroutineUniformName(const Utils::_shader_stage & stage) const10513 std::string NegativeTest2::getSubroutineUniformName(const Utils::_shader_stage& stage) const
10514 {
10515 std::string result = "?";
10516
10517 switch (stage)
10518 {
10519 case Utils::SHADER_STAGE_FRAGMENT:
10520 {
10521 result = "test_fs_subroutine";
10522
10523 break;
10524 }
10525
10526 case Utils::SHADER_STAGE_GEOMETRY:
10527 {
10528 result = "test_gs_subroutine";
10529
10530 break;
10531 }
10532
10533 case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
10534 {
10535 result = "test_tc_subroutine";
10536
10537 break;
10538 }
10539
10540 case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
10541 {
10542 result = "test_te_subroutine";
10543
10544 break;
10545 }
10546
10547 case Utils::SHADER_STAGE_VERTEX:
10548 {
10549 result = "test_vs_subroutine";
10550
10551 break;
10552 }
10553
10554 default:
10555 {
10556 TCU_FAIL("Unrecognized shader stage requested");
10557 }
10558 } /* switch (stage) */
10559
10560 return result;
10561 }
10562
10563 /** Retrieves an offending tessellation control shader body.
10564 *
10565 * @param referencing_stage Shader stage which defines the subroutine uniform that
10566 * will be called from tessellation control shader.
10567 *
10568 * @return Requested string.
10569 **/
getTessellationControlShaderBody(const Utils::_shader_stage & referencing_stage) const10570 std::string NegativeTest2::getTessellationControlShaderBody(const Utils::_shader_stage& referencing_stage) const
10571 {
10572 std::stringstream result;
10573
10574 /* Form the pre-amble */
10575 result << "#version 400\n"
10576 "\n"
10577 "#extension GL_ARB_shader_subroutine : require\n"
10578 "\n"
10579 "layout(vertices = 4) out;\n"
10580 "\n"
10581 "subroutine void testSubroutineType(out vec4 test_argument);\n"
10582 "\n"
10583 /* Define a subroutine */
10584 "subroutine(testSubroutineType) void tc_subroutine(out vec4 test_argument)\n"
10585 "{\n"
10586 " test_argument = vec4(0, 0, 1, 0);\n"
10587 "}\n"
10588 "\n"
10589 /* Define uniforms */
10590 "subroutine uniform testSubroutineType test_tc_subroutine;\n"
10591 "\n"
10592 /* Define main() */
10593 "void main()\n"
10594 "{\n"
10595 " "
10596 << getSubroutineUniformName(referencing_stage) << "(gl_out[gl_InvocationID].gl_Position);\n"
10597 "}\n";
10598
10599 return result.str();
10600 }
10601
10602 /** Retrieves an offending tessellation evaluation shader body.
10603 *
10604 * @param referencing_stage Shader stage which defines the subroutine uniform that
10605 * will be called from tessellation evaluation shader.
10606 *
10607 * @return Requested string.
10608 **/
getTessellationEvaluationShaderBody(const Utils::_shader_stage & referencing_stage) const10609 std::string NegativeTest2::getTessellationEvaluationShaderBody(const Utils::_shader_stage& referencing_stage) const
10610 {
10611 std::stringstream result;
10612
10613 /* Form the pre-amble */
10614 result << "#version 400\n"
10615 "\n"
10616 "#extension GL_ARB_shader_subroutine : require\n"
10617 "\n"
10618 "layout(quads) in;\n"
10619 "\n"
10620 "subroutine void testSubroutineType(out vec4 test_argument);\n"
10621 "\n"
10622 /* Define a subroutine */
10623 "subroutine(testSubroutineType) void te_subroutine(out vec4 test_argument)\n"
10624 "{\n"
10625 " test_argument = vec4(1, 1, 1, 1);\n"
10626 "}\n"
10627 "\n"
10628 /* Define uniforms */
10629 "subroutine uniform testSubroutineType test_te_subroutine;\n"
10630 "\n"
10631 /* Define main() */
10632 "void main()\n"
10633 "{\n"
10634 " "
10635 << getSubroutineUniformName(referencing_stage) << "(gl_Position);\n"
10636 "}\n";
10637
10638 return result.str();
10639 }
10640
10641 /** Retrieves an offending vertex shader body.
10642 *
10643 * @param referencing_stage Shader stage which defines the subroutine uniform that
10644 * will be called from vertex shader.
10645 *
10646 * @return Requested string.
10647 **/
getVertexShaderBody(const Utils::_shader_stage & referencing_stage) const10648 std::string NegativeTest2::getVertexShaderBody(const Utils::_shader_stage& referencing_stage) const
10649 {
10650 std::stringstream result;
10651
10652 /* Form the pre-amble */
10653 result << "#version 400\n"
10654 "\n"
10655 "#extension GL_ARB_shader_subroutine : require\n"
10656 "\n"
10657 "subroutine void testSubroutineType(out vec4 test_argument);\n"
10658 "\n"
10659 /* Define a subroutine */
10660 "subroutine(testSubroutineType) void vs_subroutine(out vec4 test_argument)\n"
10661 "{\n"
10662 " test_argument = vec4(0, 1, 0, 0);\n"
10663 "}\n"
10664 "\n"
10665 /* Define uniforms */
10666 "subroutine uniform testSubroutineType test_vs_subroutine;\n"
10667 "\n"
10668 /* Define main() */
10669 "void main()\n"
10670 "{\n"
10671 " "
10672 << getSubroutineUniformName(referencing_stage) << "(gl_Position);\n"
10673 "}\n";
10674
10675 return result.str();
10676 }
10677
10678 /** Executes test iteration.
10679 *
10680 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
10681 */
iterate()10682 tcu::TestNode::IterateResult NegativeTest2::iterate()
10683 {
10684 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
10685 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
10686 {
10687 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
10688 }
10689
10690 /* Iterate over all shader stages and execute the checks */
10691 for (int referencing_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
10692 referencing_stage < static_cast<int>(Utils::SHADER_STAGE_COUNT); ++referencing_stage)
10693 {
10694 executeTestCase(static_cast<Utils::_shader_stage>(referencing_stage));
10695 } /* for (all test cases) */
10696
10697 /* All done */
10698 if (m_has_test_passed)
10699 {
10700 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
10701 }
10702 else
10703 {
10704 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
10705 }
10706
10707 return STOP;
10708 }
10709
10710 /** Constructor.
10711 *
10712 * @param context Rendering context.
10713 *
10714 **/
NegativeTest3(deqp::Context & context)10715 NegativeTest3::NegativeTest3(deqp::Context& context)
10716 : TestCase(context, "missing_subroutine_keyword", "Verifies that subroutine keyword is necessary when declaring a "
10717 "subroutine uniforn and a compilation error occurs without it.")
10718 , m_has_test_passed(true)
10719 , m_so_id(0)
10720 {
10721 /* Left blank intentionally */
10722 }
10723
10724 /** Deinitializes all GL objects that may have been created during test execution */
deinit()10725 void NegativeTest3::deinit()
10726 {
10727 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
10728
10729 if (m_so_id != 0)
10730 {
10731 gl.deleteShader(m_so_id);
10732
10733 m_so_id = 0;
10734 }
10735 }
10736
10737 /** Verifies that broken shader (for user-specified shader stage) does not compile.
10738 *
10739 * @param shader_stage Shader stage to use for the test.
10740 **/
executeTest(const Utils::_shader_stage & shader_stage)10741 void NegativeTest3::executeTest(const Utils::_shader_stage& shader_stage)
10742 {
10743 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
10744
10745 /* Generate a new shader object */
10746 m_so_id = gl.createShader(Utils::getGLenumForShaderStage(shader_stage));
10747 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
10748
10749 /* Assign body to the shader */
10750 std::string body;
10751 const char* body_raw_ptr = DE_NULL;
10752
10753 switch (shader_stage)
10754 {
10755 case Utils::SHADER_STAGE_VERTEX:
10756 body = getVertexShaderBody();
10757 break;
10758 case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
10759 body = getTessellationControlShaderBody();
10760 break;
10761 case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
10762 body = getTessellationEvaluationShaderBody();
10763 break;
10764 case Utils::SHADER_STAGE_GEOMETRY:
10765 body = getGeometryShaderBody();
10766 break;
10767 case Utils::SHADER_STAGE_FRAGMENT:
10768 body = getFragmentShaderBody();
10769 break;
10770
10771 default:
10772 {
10773 TCU_FAIL("Unrecognized shader stage requested");
10774 }
10775 } /* switch (shader_stage) */
10776
10777 body_raw_ptr = body.c_str();
10778
10779 gl.shaderSource(m_so_id, 1 /* count */, &body_raw_ptr, DE_NULL /* length */);
10780 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
10781
10782 /* Try to compile the shader */
10783 glw::GLint compile_status = 0;
10784
10785 gl.compileShader(m_so_id);
10786 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
10787
10788 gl.getShaderiv(m_so_id, GL_COMPILE_STATUS, &compile_status);
10789 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
10790
10791 if (compile_status == GL_TRUE)
10792 {
10793 m_testCtx.getLog() << tcu::TestLog::Message << "The following shader was expected to fail to compile but was "
10794 "accepted by the compiler:\n"
10795 "\n"
10796 << body.c_str() << tcu::TestLog::EndMessage;
10797
10798 m_has_test_passed = false;
10799 }
10800
10801 /* Good to release the shader at this point */
10802 gl.deleteShader(m_so_id);
10803 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed.");
10804 }
10805
10806 /** Retrieves body of a broken fragment shader.
10807 *
10808 * @return Requested string.
10809 **/
getFragmentShaderBody() const10810 std::string NegativeTest3::getFragmentShaderBody() const
10811 {
10812 return "#version 400\n"
10813 "\n"
10814 "#extension GL_ARB_shader_subroutine : require\n"
10815 "\n"
10816 "subroutine void testSubroutineType(inout vec4 test);\n"
10817 "\n"
10818 "void testSubroutine1(inout vec4 test)\n"
10819 "{\n"
10820 " test += vec4(3, 4, 5, 6);\n"
10821 "}\n"
10822 "\n"
10823 "uniform testSubroutineType subroutineFunction;\n"
10824 "out vec4 result;\n"
10825 "\n"
10826 "void main()\n"
10827 "{\n"
10828 " vec4 test = vec4(2, 3, 4, 5);\n"
10829 "\n"
10830 " subroutineFunction(test);\n"
10831 "\n"
10832 " result = test;\n"
10833 "}\n";
10834 }
10835
10836 /** Retrieves body of a broken geometry shader.
10837 *
10838 * @return Requested string.
10839 **/
getGeometryShaderBody() const10840 std::string NegativeTest3::getGeometryShaderBody() const
10841 {
10842 return "#version 400\n"
10843 "\n"
10844 "#extension GL_ARB_shader_subroutine : require\n"
10845 "\n"
10846 "layout(points) in;\n"
10847 "layout(points, max_vertices = 1) out;\n"
10848 "\n"
10849 "subroutine void testSubroutineType(inout vec4 test);\n"
10850 "\n"
10851 "void testSubroutine1(inout vec4 test)\n"
10852 "{\n"
10853 " test += vec4(3, 4, 5, 6);\n"
10854 "}\n"
10855 "\n"
10856 "uniform testSubroutineType subroutineFunction;\n"
10857 "\n"
10858 "void main()\n"
10859 "{\n"
10860 " vec4 test = vec4(2, 3, 4, 5);\n"
10861 "\n"
10862 " subroutineFunction(test);\n"
10863 "\n"
10864 " gl_Position = test;\n"
10865 " EmitVertex();\n"
10866 "}\n";
10867 }
10868
10869 /** Retrieves body of a broken tessellation control shader.
10870 *
10871 * @return Requested string.
10872 **/
getTessellationControlShaderBody() const10873 std::string NegativeTest3::getTessellationControlShaderBody() const
10874 {
10875 return "#version 400\n"
10876 "\n"
10877 "#extension GL_ARB_shader_subroutine : require\n"
10878 "\n"
10879 "layout(vertices=4) out;\n"
10880 "\n"
10881 "subroutine void testSubroutineType(inout vec4 test);\n"
10882 "\n"
10883 "void testSubroutine1(inout vec4 test)\n"
10884 "{\n"
10885 " test += vec4(1, 2, 3, 4);\n"
10886 "}\n"
10887 "\n"
10888 "uniform testSubroutineType subroutineFunction;\n"
10889 "\n"
10890 "void main()\n"
10891 "{\n"
10892 " vec4 test = vec4(0, 1, 2, 3);\n"
10893 "\n"
10894 " subroutineFunction(test);\n"
10895 "\n"
10896 " gl_out[gl_InvocationID].gl_Position = test;\n"
10897 "}\n";
10898 }
10899
10900 /** Retrieves body of a broken tessellation evaluation shader.
10901 *
10902 * @return Requested string.
10903 **/
getTessellationEvaluationShaderBody() const10904 std::string NegativeTest3::getTessellationEvaluationShaderBody() const
10905 {
10906 return "#version 400\n"
10907 "\n"
10908 "#extension GL_ARB_shader_subroutine : require\n"
10909 "\n"
10910 "layout(quads) in;\n"
10911 "\n"
10912 "subroutine void testSubroutineType(inout vec4 test);\n"
10913 "\n"
10914 "void testSubroutine1(inout vec4 test)\n"
10915 "{\n"
10916 " test += vec4(2, 3, 4, 5);\n"
10917 "}\n"
10918 "\n"
10919 "uniform testSubroutineType subroutineFunction;\n"
10920 "\n"
10921 "void main()\n"
10922 "{\n"
10923 " vec4 test = vec4(1, 2, 3, 4);\n"
10924 "\n"
10925 " subroutineFunction(test);\n"
10926 "\n"
10927 " gl_Position = test;\n"
10928 "}\n";
10929 }
10930
10931 /** Retrieves body of a broken vertex shader.
10932 *
10933 * @return Requested string.
10934 **/
getVertexShaderBody() const10935 std::string NegativeTest3::getVertexShaderBody() const
10936 {
10937 return "#version 400\n"
10938 "\n"
10939 "#extension GL_ARB_shader_subroutine : require\n"
10940 "\n"
10941 "subroutine void testSubroutineType(inout vec4 test);\n"
10942 "\n"
10943 "void testSubroutine1(inout vec4 test)\n"
10944 "{\n"
10945 " test += vec4(0, 1, 2, 3);\n"
10946 "}\n"
10947 "\n"
10948 "uniform testSubroutineType subroutineFunction;\n"
10949 "\n"
10950 "void main()\n"
10951 "{\n"
10952 " subroutineFunction(gl_Position);\n"
10953 "}\n";
10954 }
10955
10956 /** Executes test iteration.
10957 *
10958 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
10959 */
iterate()10960 tcu::TestNode::IterateResult NegativeTest3::iterate()
10961 {
10962 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
10963 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
10964 {
10965 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
10966 }
10967
10968 /* Iterate over all shader stages */
10969 for (int shader_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
10970 shader_stage < static_cast<int>(Utils::SHADER_STAGE_COUNT); ++shader_stage)
10971 {
10972 executeTest(static_cast<Utils::_shader_stage>(shader_stage));
10973 } /* for (all shader stages) */
10974
10975 /* Done */
10976 if (m_has_test_passed)
10977 {
10978 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
10979 }
10980 else
10981 {
10982 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
10983 }
10984
10985 return STOP;
10986 }
10987
10988 /** Constructor.
10989 *
10990 * @param context Rendering context.
10991 *
10992 **/
NegativeTest4(deqp::Context & context)10993 NegativeTest4::NegativeTest4(deqp::Context& context)
10994 : TestCase(context, "subroutines_incompatible_with_subroutine_type",
10995 "Verifies that a compile-time error is generated when arguments and "
10996 "return type do not match beween the function and each associated "
10997 "subroutine type.")
10998 , m_has_test_passed(true)
10999 , m_so_id(0)
11000 {
11001 /* Left blank intentionally */
11002 }
11003
11004 /** Deinitializes GL objects that may have been created during test
11005 * execution.
11006 **/
deinit()11007 void NegativeTest4::deinit()
11008 {
11009 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
11010
11011 if (m_so_id != 0)
11012 {
11013 gl.deleteShader(m_so_id);
11014
11015 m_so_id = 0;
11016 }
11017 }
11018
11019 /** Retrieves body of a shader of user-specified type that should be used
11020 * for a single test iteration. The shader will define user-specified number
11021 * of subroutine types, with the last type either defining an additional argument
11022 * or using a different return type.
11023 * A subroutine (claimed compatible with *all* subroutine types) will also be
11024 * defined in the shader.
11025 *
11026 * @param shader_stage Shader stage to use for the query.
11027 * @param n_subroutine_types Overall number of subroutine types that will be
11028 * declared & used in the shader. Please see description
11029 * for more details.
11030 *
11031 * @return Requested string.
11032 **/
getShaderBody(const Utils::_shader_stage & shader_stage,const unsigned int & n_subroutine_types,const _test_case & test_case) const11033 std::string NegativeTest4::getShaderBody(const Utils::_shader_stage& shader_stage,
11034 const unsigned int& n_subroutine_types, const _test_case& test_case) const
11035 {
11036 std::stringstream result_sstream;
11037
11038 /* Form the pre-amble */
11039 result_sstream << "#version 400\n"
11040 "\n"
11041 "#extension GL_ARB_shader_subroutine : require\n"
11042 "\n";
11043
11044 /* Inject stage-specific code */
11045 switch (shader_stage)
11046 {
11047 case Utils::SHADER_STAGE_GEOMETRY:
11048 {
11049 result_sstream << "layout (points) in;\n"
11050 "layout (points, max_vertices = 1) out;\n"
11051 "\n";
11052
11053 break;
11054 }
11055
11056 case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
11057 {
11058 result_sstream << "layout (vertices = 4) out;\n"
11059 "\n";
11060
11061 break;
11062 }
11063
11064 case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
11065 {
11066 result_sstream << "layout (quads) in;\n"
11067 "\n";
11068
11069 break;
11070 }
11071
11072 default:
11073 break;
11074 } /* switch (shader_stage) */
11075
11076 /* Insert subroutine type declarations */
11077 for (unsigned int n_subroutine_type = 0; n_subroutine_type < n_subroutine_types - 1; ++n_subroutine_type)
11078 {
11079 result_sstream << "subroutine void subroutineType" << n_subroutine_type << "(inout vec3 argument);\n";
11080 } /* for (all subroutine types) */
11081
11082 switch (test_case)
11083 {
11084 case TEST_CASE_INCOMPATIBLE_ARGUMENT_LIST:
11085 {
11086 result_sstream << "subroutine void subroutineType" << (n_subroutine_types - 1)
11087 << "(inout vec3 argument, out vec4 argument2);\n";
11088
11089 break;
11090 }
11091
11092 case TEST_CASE_INCOMPATIBLE_RETURN_TYPE:
11093 {
11094 result_sstream << "subroutine int subroutineType" << (n_subroutine_types - 1) << "(inout vec3 argument);\n";
11095
11096 break;
11097 }
11098
11099 default:
11100 {
11101 TCU_FAIL("Unrecognized test case");
11102 }
11103 } /* switch (test_case) */
11104
11105 /* Insert subroutine declarations */
11106 result_sstream << "subroutine(";
11107
11108 for (unsigned int n_subroutine_type = 0; n_subroutine_type < n_subroutine_types; ++n_subroutine_type)
11109 {
11110 result_sstream << "subroutineType" << n_subroutine_type;
11111
11112 if (n_subroutine_type != (n_subroutine_types - 1))
11113 {
11114 result_sstream << ", ";
11115 }
11116 } /* for (all subroutine types) */
11117
11118 result_sstream << ") void function(inout vec3 argument)\n"
11119 "{\n"
11120 " argument = vec3(1, 2, 3);\n"
11121 "}\n"
11122 "\n";
11123
11124 /* Insert remaining required stage-specific bits */
11125 switch (shader_stage)
11126 {
11127 case Utils::SHADER_STAGE_FRAGMENT:
11128 {
11129 result_sstream << "out vec4 result;\n"
11130 "\n"
11131 "void main()\n"
11132 "{\n"
11133 " result = vec4(1, 2, 3, 4);\n"
11134 "}\n";
11135
11136 break;
11137 }
11138
11139 case Utils::SHADER_STAGE_GEOMETRY:
11140 {
11141 result_sstream << "void main()\n"
11142 "{\n"
11143 " gl_Position = vec4(1, 2, 3, 4);\n"
11144 " EmitVertex();\n"
11145 "}\n";
11146
11147 break;
11148 }
11149
11150 case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
11151 {
11152 result_sstream << "void main()\n"
11153 "{\n"
11154 " gl_TessLevelInner[0] = 1;\n"
11155 " gl_TessLevelInner[1] = 1;\n"
11156 " gl_TessLevelOuter[0] = 1;\n"
11157 " gl_TessLevelOuter[1] = 1;\n"
11158 " gl_TessLevelOuter[2] = 1;\n"
11159 " gl_TessLevelOuter[3] = 1;\n"
11160 " gl_out[gl_InvocationID].gl_Position = vec4(2, 3, 4, 5);\n"
11161 "}\n";
11162
11163 break;
11164 }
11165
11166 case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
11167 case Utils::SHADER_STAGE_VERTEX:
11168 {
11169 result_sstream << "void main()\n"
11170 "{\n"
11171 " gl_Position = vec4(1, 2, 3, 4);\n"
11172 "}\n";
11173
11174 break;
11175 }
11176
11177 default:
11178 {
11179 TCU_FAIL("Unrecognized shader stage");
11180 }
11181 } /* switch (shader_stage) */
11182
11183 return result_sstream.str();
11184 }
11185
11186 /** Executes test iteration.
11187 *
11188 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
11189 */
iterate()11190 tcu::TestNode::IterateResult NegativeTest4::iterate()
11191 {
11192 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
11193
11194 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
11195 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
11196 {
11197 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
11198 }
11199
11200 /* Iterate over all shader stages.. */
11201 for (int shader_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
11202 shader_stage != static_cast<int>(Utils::SHADER_STAGE_COUNT); ++shader_stage)
11203 {
11204 /* For each shader stage, we will be trying to compile a number of invalid shaders.
11205 * Each shader defines N different subroutine types. (N-1) of them are compatible
11206 * with a subroutine, but exactly 1 will be mismatched. The test passes if GLSL
11207 * compiler correctly detects that all shaders we will be trying to compile are
11208 * broken.
11209 */
11210 const glw::GLenum shader_type = Utils::getGLenumForShaderStage(static_cast<Utils::_shader_stage>(shader_stage));
11211
11212 for (unsigned int n_subroutine_types = 1; n_subroutine_types < 6; /* arbitrary number */
11213 ++n_subroutine_types)
11214 {
11215 for (int test_case = static_cast<int>(TEST_CASE_FIRST); test_case != static_cast<int>(TEST_CASE_COUNT);
11216 ++test_case)
11217 {
11218 std::string body;
11219 const char* body_raw_ptr = NULL;
11220 glw::GLint compile_status = GL_FALSE;
11221
11222 body = getShaderBody(static_cast<Utils::_shader_stage>(shader_stage), n_subroutine_types,
11223 static_cast<_test_case>(test_case));
11224 body_raw_ptr = body.c_str();
11225
11226 /* Try to compile the shader */
11227 m_so_id = gl.createShader(shader_type);
11228 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed");
11229
11230 gl.shaderSource(m_so_id, 1 /* count */, &body_raw_ptr, DE_NULL);
11231 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed");
11232
11233 gl.compileShader(m_so_id);
11234 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed");
11235
11236 gl.getShaderiv(m_so_id, GL_COMPILE_STATUS, &compile_status);
11237 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
11238
11239 if (compile_status == GL_TRUE)
11240 {
11241 m_testCtx.getLog() << tcu::TestLog::Message << "A malformed "
11242 << Utils::getShaderStageString(static_cast<Utils::_shader_stage>(shader_stage))
11243 << " compiled successfully "
11244 "("
11245 << n_subroutine_types << " subroutine types "
11246 "were defined)."
11247 << tcu::TestLog::EndMessage;
11248
11249 m_has_test_passed = false;
11250 }
11251
11252 /* Release the object */
11253 gl.deleteShader(m_so_id);
11254 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed.");
11255 } /* for (all test cases) */
11256 } /* for (a number of different subroutine type declarations) */
11257 } /* for (all shader stages) */
11258
11259 /* Done */
11260 if (m_has_test_passed)
11261 {
11262 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
11263 }
11264 else
11265 {
11266 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
11267 }
11268
11269 return STOP;
11270 }
11271
11272 /** Constructor.
11273 *
11274 * @param context Rendering context.
11275 *
11276 **/
NegativeTest5(deqp::Context & context)11277 NegativeTest5::NegativeTest5(deqp::Context& context)
11278 : TestCase(context, "subroutine_uniform_wo_matching_subroutines",
11279 "Verifies that a link- or compile-time error occurs when "
11280 "trying to link a program with no subroutine for subroutine "
11281 "uniform variable.")
11282 , m_fs_id(0)
11283 , m_gs_id(0)
11284 , m_has_test_passed(true)
11285 , m_po_id(0)
11286 , m_tc_id(0)
11287 , m_te_id(0)
11288 , m_vs_id(0)
11289 {
11290 /* Left blank intentionally */
11291 }
11292
11293 /** Deinitializes all GL objects that may have been created during test execution */
deinit()11294 void NegativeTest5::deinit()
11295 {
11296 deinitIteration();
11297 }
11298
11299 /** Deinitializes all GL objects that may have been created during a single test
11300 * iteration.
11301 ***/
deinitIteration()11302 void NegativeTest5::deinitIteration()
11303 {
11304 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
11305
11306 if (m_fs_id != 0)
11307 {
11308 gl.deleteShader(m_fs_id);
11309
11310 m_fs_id = 0;
11311 }
11312
11313 if (m_gs_id != 0)
11314 {
11315 gl.deleteShader(m_gs_id);
11316
11317 m_gs_id = 0;
11318 }
11319
11320 if (m_po_id != 0)
11321 {
11322 gl.deleteProgram(m_po_id);
11323
11324 m_po_id = 0;
11325 }
11326
11327 if (m_tc_id != 0)
11328 {
11329 gl.deleteShader(m_tc_id);
11330
11331 m_tc_id = 0;
11332 }
11333
11334 if (m_te_id != 0)
11335 {
11336 gl.deleteShader(m_te_id);
11337
11338 m_te_id = 0;
11339 }
11340
11341 if (m_vs_id != 0)
11342 {
11343 gl.deleteShader(m_vs_id);
11344
11345 m_vs_id = 0;
11346 }
11347 }
11348
11349 /** Executes a single test iteration.
11350 *
11351 * If the iteration fails, m_has_test_passed will be set to false.
11352 *
11353 * @param shader_stage Shader stage, for which a subroutine uniform should be
11354 * declared in the shader without a matching subroutine.
11355 **/
executeIteration(const Utils::_shader_stage & shader_stage)11356 void NegativeTest5::executeIteration(const Utils::_shader_stage& shader_stage)
11357 {
11358 std::string fs_body = getFragmentShaderBody(shader_stage == Utils::SHADER_STAGE_FRAGMENT);
11359 std::string gs_body = getGeometryShaderBody(shader_stage == Utils::SHADER_STAGE_GEOMETRY);
11360 std::string tc_body = getTessellationControlShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_CONTROL);
11361 std::string te_body =
11362 getTessellationEvaluationShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_EVALUATION);
11363 std::string vs_body = getVertexShaderBody(shader_stage == Utils::SHADER_STAGE_VERTEX);
11364
11365 if (Utils::buildProgram(m_context.getRenderContext().getFunctions(), vs_body, tc_body, te_body, gs_body, fs_body,
11366 DE_NULL, /* xfb_varyings */
11367 DE_NULL, /* n_xfb_varyings */
11368 &m_vs_id, &m_tc_id, &m_te_id, &m_gs_id, &m_fs_id, &m_po_id))
11369 {
11370 /* None of the test programs should ever build successfully */
11371 m_testCtx.getLog() << tcu::TestLog::Message
11372 << "A program object, consisting of the following shaders, has linked"
11373 " correctly. One of the shaders defines a subroutine uniform but does "
11374 "not implement any function that matches subroutine type of the uniform."
11375 " This should have resulted in a compilation/link-time error.\n"
11376 "\n"
11377 "Vertex shader:\n"
11378 "\n"
11379 << vs_body << "\n"
11380 "Tessellation control shader:\n"
11381 "\n"
11382 << tc_body << "\n"
11383 "Tessellation evaluation shader:\n"
11384 "\n"
11385 << te_body << "\n"
11386 "Geometry shader:\n"
11387 "\n"
11388 << gs_body << "\n"
11389 "Fragment shader:\n"
11390 "\n"
11391 << fs_body << tcu::TestLog::EndMessage;
11392
11393 m_has_test_passed = false;
11394 }
11395 }
11396
11397 /** Retrieves fragment shader body.
11398 *
11399 * @param include_invalid_subroutine_uniform_declaration true if the shader should declare
11400 * a subroutine uniform without
11401 * a matching subroutine, false otherwise.
11402 *
11403 * @return Requested string.
11404 **/
getFragmentShaderBody(bool include_invalid_subroutine_uniform_declaration) const11405 std::string NegativeTest5::getFragmentShaderBody(bool include_invalid_subroutine_uniform_declaration) const
11406 {
11407 std::stringstream result_sstream;
11408
11409 result_sstream << "#version 400\n"
11410 "\n"
11411 "#extension GL_ARB_shader_subroutine : require\n"
11412 "\n";
11413
11414 if (include_invalid_subroutine_uniform_declaration)
11415 {
11416 result_sstream << "subroutine void subroutineTestTypeFS(out vec4 test);\n"
11417 "\n"
11418 "subroutine uniform subroutineTestTypeFS test_subroutineFS;\n";
11419 };
11420
11421 result_sstream << "\n"
11422 "out vec4 result;\n"
11423 "\n"
11424 "void main()\n"
11425 "{\n";
11426
11427 if (include_invalid_subroutine_uniform_declaration)
11428 {
11429 result_sstream << " test_subroutineFS(result);\n";
11430 }
11431 else
11432 {
11433 result_sstream << " result = vec4(0, 1, 2, 3);\n";
11434 }
11435
11436 result_sstream << "}\n";
11437
11438 return result_sstream.str();
11439 }
11440
11441 /** Retrieves geometry shader body.
11442 *
11443 * @param include_invalid_subroutine_uniform_declaration true if the shader should declare
11444 * a subroutine uniform without
11445 * a matching subroutine, false otherwise.
11446 *
11447 * @return Requested string.
11448 **/
getGeometryShaderBody(bool include_invalid_subroutine_uniform_declaration) const11449 std::string NegativeTest5::getGeometryShaderBody(bool include_invalid_subroutine_uniform_declaration) const
11450 {
11451 std::stringstream result_sstream;
11452
11453 result_sstream << "#version 400\n"
11454 "\n"
11455 "#extension GL_ARB_shader_subroutine : require\n"
11456 "\n"
11457 "layout (points) in;\n"
11458 "layout (points, max_vertices = 1) out;\n"
11459 "\n";
11460
11461 if (include_invalid_subroutine_uniform_declaration)
11462 {
11463 result_sstream << "subroutine void subroutineTestTypeGS(out vec4 test);\n"
11464 "\n"
11465 "subroutine uniform subroutineTestTypeGS test_subroutineGS;\n";
11466 };
11467
11468 result_sstream << "\n"
11469 "void main()\n"
11470 "{\n";
11471
11472 if (include_invalid_subroutine_uniform_declaration)
11473 {
11474 result_sstream << " test_subroutineGS(gl_Position);\n";
11475 }
11476 else
11477 {
11478 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
11479 }
11480
11481 result_sstream << "EmitVertex();\n"
11482 "}\n";
11483
11484 return result_sstream.str();
11485 }
11486
11487 /** Retrieves tessellation control shader body.
11488 *
11489 * @param include_invalid_subroutine_uniform_declaration true if the shader should declare
11490 * a subroutine uniform without
11491 * a matching subroutine, false otherwise.
11492 *
11493 * @return Requested string.
11494 **/
getTessellationControlShaderBody(bool include_invalid_subroutine_uniform_declaration) const11495 std::string NegativeTest5::getTessellationControlShaderBody(bool include_invalid_subroutine_uniform_declaration) const
11496 {
11497 std::stringstream result_sstream;
11498
11499 result_sstream << "#version 400\n"
11500 "\n"
11501 "#extension GL_ARB_shader_subroutine : require\n"
11502 "\n"
11503 "layout (vertices = 4) out;\n"
11504 "\n";
11505
11506 if (include_invalid_subroutine_uniform_declaration)
11507 {
11508 result_sstream << "subroutine void subroutineTestTypeTC(out vec4 test);\n"
11509 "\n"
11510 "subroutine uniform subroutineTestTypeTC test_subroutineTC;\n";
11511 };
11512
11513 result_sstream << "\n"
11514 "void main()\n"
11515 "{\n";
11516
11517 if (include_invalid_subroutine_uniform_declaration)
11518 {
11519 result_sstream << " test_subroutineTC(gl_out[gl_InvocationID].gl_Position);\n";
11520 }
11521 else
11522 {
11523 result_sstream << " gl_out[gl_InvocationID].gl_Position = vec4(0, 1, 2, 3);\n";
11524 }
11525
11526 result_sstream << "}\n";
11527
11528 return result_sstream.str();
11529 }
11530
11531 /** Retrieves tessellation evaluation body.
11532 *
11533 * @param include_invalid_subroutine_uniform_declaration true if the shader should declare
11534 * a subroutine uniform without
11535 * a matching subroutine, false otherwise.
11536 *
11537 * @return Requested string.
11538 **/
getTessellationEvaluationShaderBody(bool include_invalid_subroutine_uniform_declaration) const11539 std::string NegativeTest5::getTessellationEvaluationShaderBody(
11540 bool include_invalid_subroutine_uniform_declaration) const
11541 {
11542 std::stringstream result_sstream;
11543
11544 result_sstream << "#version 400\n"
11545 "\n"
11546 "#extension GL_ARB_shader_subroutine : require\n"
11547 "\n"
11548 "layout (quads) in;\n"
11549 "\n";
11550
11551 if (include_invalid_subroutine_uniform_declaration)
11552 {
11553 result_sstream << "subroutine void subroutineTestTypeTE(out vec4 test);\n"
11554 "\n"
11555 "subroutine uniform subroutineTestTypeTE test_subroutineTE;\n";
11556 };
11557
11558 result_sstream << "\n"
11559 "void main()\n"
11560 "{\n";
11561
11562 if (include_invalid_subroutine_uniform_declaration)
11563 {
11564 result_sstream << " test_subroutineTE(gl_Position);\n";
11565 }
11566 else
11567 {
11568 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
11569 }
11570
11571 result_sstream << "}\n";
11572
11573 return result_sstream.str();
11574 }
11575
11576 /** Retrieves vertex shader body.
11577 *
11578 * @param include_invalid_subroutine_uniform_declaration true if the shader should declare
11579 * a subroutine uniform without
11580 * a matching subroutine, false otherwise.
11581 *
11582 * @return Requested string.
11583 **/
getVertexShaderBody(bool include_invalid_subroutine_uniform_declaration) const11584 std::string NegativeTest5::getVertexShaderBody(bool include_invalid_subroutine_uniform_declaration) const
11585 {
11586 std::stringstream result_sstream;
11587
11588 result_sstream << "#version 400\n"
11589 "\n"
11590 "#extension GL_ARB_shader_subroutine : require\n"
11591 "\n";
11592
11593 if (include_invalid_subroutine_uniform_declaration)
11594 {
11595 result_sstream << "subroutine void subroutineTestTypeVS(out vec4 test);\n"
11596 "\n"
11597 "subroutine uniform subroutineTestTypeVS test_subroutineVS;\n";
11598 };
11599
11600 result_sstream << "\n"
11601 "void main()\n"
11602 "{\n";
11603
11604 if (include_invalid_subroutine_uniform_declaration)
11605 {
11606 result_sstream << " test_subroutineVS(gl_Position);\n";
11607 }
11608 else
11609 {
11610 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
11611 }
11612
11613 result_sstream << "}\n";
11614
11615 return result_sstream.str();
11616 }
11617
11618 /** Executes test iteration.
11619 *
11620 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
11621 */
iterate()11622 tcu::TestNode::IterateResult NegativeTest5::iterate()
11623 {
11624 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
11625 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
11626 {
11627 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
11628 }
11629
11630 /* Iterate over all shader stages. Iteration-specific shader stage defines a subroutine type &
11631 * a corresponding subroutine uniform, for which no compatible subroutines are available. All
11632 * other shader stages are defined correctly.
11633 */
11634 for (int shader_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
11635 shader_stage < static_cast<int>(Utils::SHADER_STAGE_COUNT); ++shader_stage)
11636 {
11637 executeIteration(static_cast<Utils::_shader_stage>(shader_stage));
11638 deinitIteration();
11639 } /* for (all shader stages) */
11640
11641 /* All done */
11642 if (m_has_test_passed)
11643 {
11644 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
11645 }
11646 else
11647 {
11648 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
11649 }
11650
11651 return STOP;
11652 }
11653
11654 /** Constructor.
11655 *
11656 * @param context Rendering context.
11657 *
11658 **/
NegativeTest6(deqp::Context & context)11659 NegativeTest6::NegativeTest6(deqp::Context& context)
11660 : TestCase(context, "two_duplicate_functions_one_being_a_subroutine",
11661 "Verifies that a link- or compile-time error occurs if any shader in "
11662 "a program object includes two functions with the same name and one "
11663 "of which is associated with a subroutine type.")
11664 , m_fs_id(0)
11665 , m_gs_id(0)
11666 , m_has_test_passed(true)
11667 , m_po_id(0)
11668 , m_tc_id(0)
11669 , m_te_id(0)
11670 , m_vs_id(0)
11671 {
11672 /* Left blank intentionally */
11673 }
11674
11675 /** Deinitializes all GL objects that may have been created during test execution */
deinit()11676 void NegativeTest6::deinit()
11677 {
11678 deinitIteration();
11679 }
11680
11681 /** Deinitializes all GL objects that may have been created during a single test
11682 * iteration.
11683 ***/
deinitIteration()11684 void NegativeTest6::deinitIteration()
11685 {
11686 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
11687
11688 if (m_fs_id != 0)
11689 {
11690 gl.deleteShader(m_fs_id);
11691
11692 m_fs_id = 0;
11693 }
11694
11695 if (m_gs_id != 0)
11696 {
11697 gl.deleteShader(m_gs_id);
11698
11699 m_gs_id = 0;
11700 }
11701
11702 if (m_po_id != 0)
11703 {
11704 gl.deleteProgram(m_po_id);
11705
11706 m_po_id = 0;
11707 }
11708
11709 if (m_tc_id != 0)
11710 {
11711 gl.deleteShader(m_tc_id);
11712
11713 m_tc_id = 0;
11714 }
11715
11716 if (m_te_id != 0)
11717 {
11718 gl.deleteShader(m_te_id);
11719
11720 m_te_id = 0;
11721 }
11722
11723 if (m_vs_id != 0)
11724 {
11725 gl.deleteShader(m_vs_id);
11726
11727 m_vs_id = 0;
11728 }
11729 }
11730
11731 /** Executes a single test iteration.
11732 *
11733 * If the iteration fails, m_has_test_passed will be set to false.
11734 *
11735 * @param shader_stage Shader stage, for which two duplicate functions
11736 * (one additionally marked as subroutine) should
11737 * be defined.
11738 **/
executeIteration(const Utils::_shader_stage & shader_stage)11739 void NegativeTest6::executeIteration(const Utils::_shader_stage& shader_stage)
11740 {
11741 std::string fs_body = getFragmentShaderBody(shader_stage == Utils::SHADER_STAGE_FRAGMENT);
11742 std::string gs_body = getGeometryShaderBody(shader_stage == Utils::SHADER_STAGE_GEOMETRY);
11743 std::string tc_body = getTessellationControlShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_CONTROL);
11744 std::string te_body =
11745 getTessellationEvaluationShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_EVALUATION);
11746 std::string vs_body = getVertexShaderBody(shader_stage == Utils::SHADER_STAGE_VERTEX);
11747
11748 if (Utils::buildProgram(m_context.getRenderContext().getFunctions(), vs_body, tc_body, te_body, gs_body, fs_body,
11749 DE_NULL, /* xfb_varyings */
11750 DE_NULL, /* n_xfb_varyings */
11751 &m_vs_id, &m_tc_id, &m_te_id, &m_gs_id, &m_fs_id, &m_po_id))
11752 {
11753 /* None of the test programs should ever build successfully */
11754 m_testCtx.getLog() << tcu::TestLog::Message
11755 << "A program object, consisting of the following shaders, has linked"
11756 " correctly. This is invalid, because one of the shaders defines two"
11757 " functions with the same name, with an exception that one of the"
11758 " functions is marked as a subroutine.\n"
11759 "\n"
11760 "Vertex shader:\n"
11761 "\n"
11762 << vs_body << "\n"
11763 "Tessellation control shader:\n"
11764 "\n"
11765 << tc_body << "\n"
11766 "Tessellation evaluation shader:\n"
11767 "\n"
11768 << te_body << "\n"
11769 "Geometry shader:\n"
11770 "\n"
11771 << gs_body << "\n"
11772 "Fragment shader:\n"
11773 "\n"
11774 << fs_body << tcu::TestLog::EndMessage;
11775
11776 m_has_test_passed = false;
11777 }
11778 }
11779
11780 /** Retrieves fragment shader body.
11781 *
11782 * @param include_invalid_declaration true if the shader should include duplicate function
11783 * declaration.
11784 *
11785 * @return Requested string.
11786 **/
getFragmentShaderBody(bool include_invalid_declaration) const11787 std::string NegativeTest6::getFragmentShaderBody(bool include_invalid_declaration) const
11788 {
11789 std::stringstream result_sstream;
11790
11791 result_sstream << "#version 400\n"
11792 "\n"
11793 "#extension GL_ARB_shader_subroutine : require\n"
11794 "\n";
11795
11796 if (include_invalid_declaration)
11797 {
11798 result_sstream << "subroutine void subroutineTestTypeFS(out vec4 test);\n"
11799 "\n"
11800 "subroutine(subroutineTestTypeFS) void test_impl1(out vec4 test)\n"
11801 "{\n"
11802 " test = vec4(1, 2, 3, 4);\n"
11803 "}\n"
11804 "\n"
11805 "void test_impl1(out vec4 test)\n"
11806 "{\n"
11807 " test = vec4(2, 3, 4, 5);\n"
11808 "}\n"
11809 "\n"
11810 "subroutine uniform subroutineTestTypeFS test_subroutineFS;\n";
11811 };
11812
11813 result_sstream << "\n"
11814 "out vec4 result;\n"
11815 "\n"
11816 "void main()\n"
11817 "{\n";
11818
11819 if (include_invalid_declaration)
11820 {
11821 result_sstream << " test_subroutineFS(result);\n";
11822 }
11823 else
11824 {
11825 result_sstream << " result = vec4(0, 1, 2, 3);\n";
11826 }
11827
11828 result_sstream << "}\n";
11829
11830 return result_sstream.str();
11831 }
11832
11833 /** Retrieves geometry shader body.
11834 *
11835 * @param include_invalid_declaration true if the shader should include duplicate function
11836 * declaration.
11837 *
11838 * @return Requested string.
11839 **/
getGeometryShaderBody(bool include_invalid_declaration) const11840 std::string NegativeTest6::getGeometryShaderBody(bool include_invalid_declaration) const
11841 {
11842 std::stringstream result_sstream;
11843
11844 result_sstream << "#version 400\n"
11845 "\n"
11846 "#extension GL_ARB_shader_subroutine : require\n"
11847 "\n"
11848 "layout (points) in;\n"
11849 "layout (points, max_vertices = 1) out;\n"
11850 "\n";
11851
11852 if (include_invalid_declaration)
11853 {
11854 result_sstream << "subroutine void subroutineTestTypeGS(out vec4 test);\n"
11855 "\n"
11856 "subroutine(subroutineTestTypeGS) void test_impl1(out vec4 test)\n"
11857 "{\n"
11858 " test = vec4(1, 2, 3, 4);\n"
11859 "}\n"
11860 "\n"
11861 "void test_impl1(out vec4 test)\n"
11862 "{\n"
11863 " test = vec4(2, 3, 4, 5);\n"
11864 "}\n"
11865 "\n"
11866 "subroutine uniform subroutineTestTypeGS test_subroutineGS;\n";
11867 };
11868
11869 result_sstream << "\n"
11870 "void main()\n"
11871 "{\n";
11872
11873 if (include_invalid_declaration)
11874 {
11875 result_sstream << " test_subroutineGS(gl_Position);\n";
11876 }
11877 else
11878 {
11879 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
11880 }
11881
11882 result_sstream << "EmitVertex();\n"
11883 "}\n";
11884
11885 return result_sstream.str();
11886 }
11887
11888 /** Retrieves tessellation control shader body.
11889 *
11890 * @param include_invalid_declaration true if the shader should include duplicate function
11891 * declaration.
11892 *
11893 * @return Requested string.
11894 **/
getTessellationControlShaderBody(bool include_invalid_declaration) const11895 std::string NegativeTest6::getTessellationControlShaderBody(bool include_invalid_declaration) const
11896 {
11897 std::stringstream result_sstream;
11898
11899 result_sstream << "#version 400\n"
11900 "\n"
11901 "#extension GL_ARB_shader_subroutine : require\n"
11902 "\n"
11903 "layout (vertices = 4) out;\n"
11904 "\n";
11905
11906 if (include_invalid_declaration)
11907 {
11908 result_sstream << "subroutine void subroutineTestTypeTC(out vec4 test);\n"
11909 "\n"
11910 "subroutine(subroutineTestTypeTC) void test_impl1(out vec4 test)\n"
11911 "{\n"
11912 " test = vec4(1, 2, 3, 4);\n"
11913 "}\n"
11914 "\n"
11915 "void test_impl1(out vec4 test)\n"
11916 "{\n"
11917 " test = vec4(2, 3, 4, 5);\n"
11918 "}\n"
11919 "\n"
11920 "subroutine uniform subroutineTestTypeTC test_subroutineTC;\n";
11921 };
11922
11923 result_sstream << "\n"
11924 "void main()\n"
11925 "{\n";
11926
11927 if (include_invalid_declaration)
11928 {
11929 result_sstream << " test_subroutineTC(gl_out[gl_InvocationID].gl_Position);\n";
11930 }
11931 else
11932 {
11933 result_sstream << " gl_out[gl_InvocationID].gl_Position = vec4(0, 1, 2, 3);\n";
11934 }
11935
11936 result_sstream << "}\n";
11937
11938 return result_sstream.str();
11939 }
11940
11941 /** Retrieves tessellation evaluation body.
11942 *
11943 * @param include_invalid_declaration true if the shader should include duplicate function
11944 * declaration.
11945 *
11946 * @return Requested string.
11947 **/
getTessellationEvaluationShaderBody(bool include_invalid_declaration) const11948 std::string NegativeTest6::getTessellationEvaluationShaderBody(bool include_invalid_declaration) const
11949 {
11950 std::stringstream result_sstream;
11951
11952 result_sstream << "#version 400\n"
11953 "\n"
11954 "#extension GL_ARB_shader_subroutine : require\n"
11955 "\n"
11956 "layout (quads) in;\n"
11957 "\n";
11958
11959 if (include_invalid_declaration)
11960 {
11961 result_sstream << "subroutine void subroutineTestTypeTE(out vec4 test);\n"
11962 "\n"
11963 "subroutine(subroutineTestTypeTE) void test_impl1(out vec4 test)\n"
11964 "{\n"
11965 " test = vec4(1, 2, 3, 4);\n"
11966 "}\n"
11967 "\n"
11968 "void test_impl1(out vec4 test)\n"
11969 "{\n"
11970 " test = vec4(2, 3, 4, 5);\n"
11971 "}\n"
11972 "\n"
11973 "subroutine uniform subroutineTestTypeTE test_subroutineTE;\n";
11974 };
11975
11976 result_sstream << "\n"
11977 "void main()\n"
11978 "{\n";
11979
11980 if (include_invalid_declaration)
11981 {
11982 result_sstream << " test_subroutineTE(gl_Position);\n";
11983 }
11984 else
11985 {
11986 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
11987 }
11988
11989 result_sstream << "}\n";
11990
11991 return result_sstream.str();
11992 }
11993
11994 /** Retrieves vertex shader body.
11995 *
11996 * @param include_invalid_declaration true if the shader should include duplicate function
11997 * declaration.
11998 *
11999 * @return Requested string.
12000 **/
getVertexShaderBody(bool include_invalid_declaration) const12001 std::string NegativeTest6::getVertexShaderBody(bool include_invalid_declaration) const
12002 {
12003 std::stringstream result_sstream;
12004
12005 result_sstream << "#version 400\n"
12006 "\n"
12007 "#extension GL_ARB_shader_subroutine : require\n"
12008 "\n";
12009
12010 if (include_invalid_declaration)
12011 {
12012 result_sstream << "subroutine void subroutineTestTypeVS(out vec4 test);\n"
12013 "\n"
12014 "subroutine(subroutineTestTypeVS) 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 subroutineTestTypeVS test_subroutineVS;\n";
12025 };
12026
12027 result_sstream << "\n"
12028 "void main()\n"
12029 "{\n";
12030
12031 if (include_invalid_declaration)
12032 {
12033 result_sstream << " test_subroutineVS(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 /** Executes test iteration.
12046 *
12047 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
12048 */
iterate()12049 tcu::TestNode::IterateResult NegativeTest6::iterate()
12050 {
12051 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
12052 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
12053 {
12054 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
12055 }
12056
12057 /* Iterate over all shader stages. In each iteration, we will inject invalid
12058 * duplicate function declarations to iteration-specific shader stage. All other
12059 * shader stages will be assigned valid bodies. Test should fail if the program
12060 * links successfully.
12061 */
12062 for (int shader_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
12063 shader_stage < static_cast<int>(Utils::SHADER_STAGE_COUNT); ++shader_stage)
12064 {
12065 executeIteration(static_cast<Utils::_shader_stage>(shader_stage));
12066 deinitIteration();
12067 } /* for (all shader stages) */
12068
12069 /* All done */
12070 if (m_has_test_passed)
12071 {
12072 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
12073 }
12074 else
12075 {
12076 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
12077 }
12078
12079 return STOP;
12080 }
12081
12082 /** Constructor
12083 *
12084 * @param context CTS context
12085 **/
NegativeTest7(deqp::Context & context)12086 NegativeTest7::NegativeTest7(deqp::Context& context)
12087 : TestCase(context, "recursion", "Verify that it is not possible to build program with recursing subroutines")
12088 , m_program_id(0)
12089 , m_vertex_shader_id(0)
12090 {
12091 /* Nothing to be done here */
12092 }
12093
12094 /** Deinitializes all GL objects that may have been created during test execution
12095 *
12096 **/
deinit()12097 void NegativeTest7::deinit()
12098 {
12099 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
12100
12101 if (m_program_id != 0)
12102 {
12103 gl.deleteProgram(m_program_id);
12104
12105 m_program_id = 0;
12106 }
12107
12108 if (m_vertex_shader_id != 0)
12109 {
12110 gl.deleteShader(m_vertex_shader_id);
12111
12112 m_vertex_shader_id = 0;
12113 }
12114 }
12115
12116 /** Executes test iteration.
12117 *
12118 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
12119 **/
iterate()12120 tcu::TestNode::IterateResult NegativeTest7::iterate()
12121 {
12122 static const GLchar* vertex_shader_with_static_recursion =
12123 "#version 400\n"
12124 "\n"
12125 "#extension GL_ARB_shader_subroutine : require\n"
12126 "\n"
12127 "precision highp float;\n"
12128 "\n"
12129 "subroutine vec4 routine_type(in vec4 data, in uint control);\n"
12130 "\n"
12131 "subroutine (routine_type) vec4 power_routine(in vec4 data, in uint control)\n"
12132 "{\n"
12133 " if (0 != control)\n"
12134 " {\n"
12135 " return data * power_routine(data, control - 1);\n"
12136 " }\n"
12137 " else\n"
12138 " {\n"
12139 " return vec4(1, 1, 1, 1);\n"
12140 " }\n"
12141 "}\n"
12142 "\n"
12143 "subroutine (routine_type) vec4 select_routine(in vec4 data, in uint control)\n"
12144 "{\n"
12145 " if (0 == control)\n"
12146 " {\n"
12147 " return data.rrrr;\n"
12148 " }\n"
12149 " else if (1 == control)\n"
12150 " {\n"
12151 " return data.gggg;\n"
12152 " }\n"
12153 " else if (2 == control)\n"
12154 " {\n"
12155 " return data.bbbb;\n"
12156 " }\n"
12157 " else\n"
12158 " {\n"
12159 " return data.aaaa;\n"
12160 " }\n"
12161 "}\n"
12162 "\n"
12163 "subroutine uniform routine_type routine;\n"
12164 "\n"
12165 "uniform vec4 uni_value;\n"
12166 "uniform uint uni_control;\n"
12167 "\n"
12168 "out vec4 out_result;\n"
12169 "\n"
12170 "void main()\n"
12171 "{\n"
12172 " out_result = routine(uni_value, uni_control);\n"
12173 "}\n"
12174 "\n";
12175
12176 static const GLchar* vertex_shader_with_dynamic_recursion =
12177 "#version 400\n"
12178 "\n"
12179 "#extension GL_ARB_shader_subroutine : require\n"
12180 "\n"
12181 "precision highp float;\n"
12182 "\n"
12183 "subroutine vec4 routine_type(in vec4 data);\n"
12184 "\n"
12185 "subroutine uniform routine_type routine;\n"
12186 "\n"
12187 "subroutine (routine_type) vec4 div_by_2(in vec4 data)\n"
12188 "{\n"
12189 " return data / 2;\n"
12190 "}\n"
12191 "\n"
12192 "subroutine (routine_type) vec4 div_routine_result_by_2(in vec4 data)\n"
12193 "{\n"
12194 " return routine(data) / 2;\n"
12195 "}\n"
12196 "\n"
12197 "uniform vec4 uni_value;\n"
12198 "\n"
12199 "out vec4 out_result;\n"
12200 "\n"
12201 "void main()\n"
12202 "{\n"
12203 " out_result = routine(uni_value);\n"
12204 "}\n"
12205 "\n";
12206
12207 static const GLchar* vertex_shader_with_subroutine_function_recursion =
12208 "#version 400\n"
12209 "\n"
12210 "#extension GL_ARB_shader_subroutine : require\n"
12211 "\n"
12212 "precision highp float;\n"
12213 "\n"
12214 "subroutine vec4 routine_type(in vec4 data);\n"
12215 "\n"
12216 "subroutine uniform routine_type routine;\n"
12217 "\n"
12218 "vec4 function(in vec4 data)\n"
12219 "{\n"
12220 " return routine(data) + vec4(0.5, 0.5, 0.5, 0.5);\n"
12221 "}\n"
12222 "\n"
12223 "subroutine (routine_type) vec4 routine_a(in vec4 data)\n"
12224 "{\n"
12225 " return function(data) / 2;\n"
12226 "}\n"
12227 "\n"
12228 "subroutine (routine_type) vec4 routine_b(in vec4 data)\n"
12229 "{\n"
12230 " return routine_a(data) * 2;\n"
12231 "}\n"
12232 "\n"
12233 "uniform vec4 uni_value;\n"
12234 "\n"
12235 "out vec4 out_result;\n"
12236 "\n"
12237 "void main()\n"
12238 "{\n"
12239 " out_result = routine(uni_value);\n"
12240 "}\n"
12241 "\n";
12242
12243 bool result = true;
12244
12245 if (false == test(vertex_shader_with_subroutine_function_recursion, "routine_a"))
12246 {
12247 result = false;
12248 }
12249
12250 if (false == test(vertex_shader_with_dynamic_recursion, "div_routine_result_by_2"))
12251 {
12252 result = false;
12253 }
12254
12255 if (false == test(vertex_shader_with_static_recursion, "power_routine"))
12256 {
12257 result = false;
12258 }
12259
12260 /* Set result */
12261 if (true == result)
12262 {
12263 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
12264 }
12265 else
12266 {
12267 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
12268 }
12269
12270 /* Done */
12271 return tcu::TestNode::STOP;
12272 }
12273
12274 /** Try to build program from vertex shader code.
12275 *
12276 * @param vertex_shader_code Source code of vertex shader
12277 * @param name_of_recursive_routine Name of subroutine that should cause link failure due to recursion
12278 *
12279 * @return true build process failed, false otherwise
12280 **/
test(const GLchar * vertex_shader_code,const GLchar * name_of_recursive_routine)12281 bool NegativeTest7::test(const GLchar* vertex_shader_code, const GLchar* name_of_recursive_routine)
12282 {
12283 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
12284 bool result = true;
12285 static const GLchar* varying_name = "out_result";
12286
12287 /* Try to build program */
12288 if (true == Utils::buildProgram(gl, vertex_shader_code, "", "", "", "", &varying_name /* varying_names */,
12289 1 /* n_varyings */, &m_vertex_shader_id, 0, 0, 0, 0, &m_program_id))
12290 {
12291 /* Success is considered an error */
12292
12293 Utils::program program(m_context);
12294 GLuint index = 0;
12295
12296 program.build(0, 0, 0, 0, 0, vertex_shader_code, 0, 0);
12297
12298 /* Verify that recursive subroutine is active */
12299 try
12300 {
12301 index = program.getSubroutineIndex(name_of_recursive_routine, GL_VERTEX_SHADER);
12302 }
12303 catch (const std::exception& exc)
12304 {
12305 /* Something wrong with shader or compilation */
12306 m_context.getTestContext().getLog()
12307 << tcu::TestLog::Message << "It is expected that subroutine: \n"
12308 << name_of_recursive_routine
12309 << " is considered active. This subroutine is potentially recursive and should cause link failure."
12310 << tcu::TestLog::EndMessage;
12311
12312 throw exc;
12313 }
12314
12315 /* Subsoutine is active, however linking should fail */
12316 m_context.getTestContext().getLog()
12317 << tcu::TestLog::Message << "Error. Program with potentially recursive subroutine, "
12318 << name_of_recursive_routine << ", which is active, index: " << index << ", has been built successfully.\n"
12319 << vertex_shader_code << tcu::TestLog::EndMessage;
12320
12321 result = false;
12322 }
12323
12324 /* Delete program and shader */
12325 deinit();
12326
12327 /* Done */
12328 return result;
12329 }
12330
12331 /** Constructor.
12332 *
12333 * @param context Rendering context.
12334 *
12335 **/
NegativeTest8(deqp::Context & context)12336 NegativeTest8::NegativeTest8(deqp::Context& context)
12337 : TestCase(context, "subroutine_wo_body", "Verifies that a compile- or link-time error occurs if a function "
12338 "declared as a subroutine does not include a body.")
12339 , m_fs_id(0)
12340 , m_gs_id(0)
12341 , m_has_test_passed(true)
12342 , m_po_id(0)
12343 , m_tc_id(0)
12344 , m_te_id(0)
12345 , m_vs_id(0)
12346 {
12347 /* Left blank intentionally */
12348 }
12349
12350 /** Deinitializes all GL objects that may have been created during test execution */
deinit()12351 void NegativeTest8::deinit()
12352 {
12353 deinitIteration();
12354 }
12355
12356 /** Deinitializes all GL objects that may have been created during a single test
12357 * iteration.
12358 ***/
deinitIteration()12359 void NegativeTest8::deinitIteration()
12360 {
12361 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
12362
12363 if (m_fs_id != 0)
12364 {
12365 gl.deleteShader(m_fs_id);
12366
12367 m_fs_id = 0;
12368 }
12369
12370 if (m_gs_id != 0)
12371 {
12372 gl.deleteShader(m_gs_id);
12373
12374 m_gs_id = 0;
12375 }
12376
12377 if (m_po_id != 0)
12378 {
12379 gl.deleteProgram(m_po_id);
12380
12381 m_po_id = 0;
12382 }
12383
12384 if (m_tc_id != 0)
12385 {
12386 gl.deleteShader(m_tc_id);
12387
12388 m_tc_id = 0;
12389 }
12390
12391 if (m_te_id != 0)
12392 {
12393 gl.deleteShader(m_te_id);
12394
12395 m_te_id = 0;
12396 }
12397
12398 if (m_vs_id != 0)
12399 {
12400 gl.deleteShader(m_vs_id);
12401
12402 m_vs_id = 0;
12403 }
12404 }
12405
12406 /** Executes a single test iteration.
12407 *
12408 * If the iteration fails, m_has_test_passed will be set to false.
12409 *
12410 * @param shader_stage Shader stage, for which two duplicate functions
12411 * (one additionally marked as subroutine) should
12412 * be defined.
12413 **/
executeIteration(const Utils::_shader_stage & shader_stage)12414 void NegativeTest8::executeIteration(const Utils::_shader_stage& shader_stage)
12415 {
12416 std::string fs_body = getFragmentShaderBody(shader_stage == Utils::SHADER_STAGE_FRAGMENT);
12417 std::string gs_body = getGeometryShaderBody(shader_stage == Utils::SHADER_STAGE_GEOMETRY);
12418 std::string tc_body = getTessellationControlShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_CONTROL);
12419 std::string te_body =
12420 getTessellationEvaluationShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_EVALUATION);
12421 std::string vs_body = getVertexShaderBody(shader_stage == Utils::SHADER_STAGE_VERTEX);
12422
12423 if (Utils::buildProgram(m_context.getRenderContext().getFunctions(), vs_body, tc_body, te_body, gs_body, fs_body,
12424 DE_NULL, /* xfb_varyings */
12425 DE_NULL, /* n_xfb_varyings */
12426 &m_vs_id, &m_tc_id, &m_te_id, &m_gs_id, &m_fs_id, &m_po_id))
12427 {
12428 /* None of the test programs should ever build successfully */
12429 m_testCtx.getLog() << tcu::TestLog::Message
12430 << "A program object consisting of FS+GS+TC+TE+VS stages has linked successfully, "
12431 "even though one of the shaders only defines a subroutine that lacks any body."
12432 "\n"
12433 "Vertex shader:\n"
12434 "\n"
12435 << vs_body << "\n"
12436 "Tessellation control shader:\n"
12437 "\n"
12438 << tc_body << "\n"
12439 "Tessellation evaluation shader:\n"
12440 "\n"
12441 << te_body << "\n"
12442 "Geometry shader:\n"
12443 "\n"
12444 << gs_body << "\n"
12445 "Fragment shader:\n"
12446 "\n"
12447 << fs_body << tcu::TestLog::EndMessage;
12448
12449 m_has_test_passed = false;
12450 }
12451 }
12452
12453 /** Retrieves fragment shader body.
12454 *
12455 * @param include_invalid_declaration true if a subroutine prototype should be included in
12456 * the shader, false to skip it.
12457 *
12458 * @return Requested string.
12459 **/
getFragmentShaderBody(bool include_invalid_declaration) const12460 std::string NegativeTest8::getFragmentShaderBody(bool include_invalid_declaration) const
12461 {
12462 std::stringstream result_sstream;
12463
12464 result_sstream << "#version 400\n"
12465 "\n"
12466 "#extension GL_ARB_shader_subroutine : require\n"
12467 "\n";
12468
12469 if (include_invalid_declaration)
12470 {
12471 result_sstream << "subroutine void subroutineTestTypeFS(out vec4 test);\n"
12472 "\n"
12473 "subroutine(subroutineTestTypeFS) void test_impl1(out vec4 test);\n"
12474 "\n"
12475 "subroutine uniform subroutineTestTypeFS test_subroutineFS;\n";
12476 };
12477
12478 result_sstream << "\n"
12479 "out vec4 result;\n"
12480 "\n"
12481 "void main()\n"
12482 "{\n";
12483
12484 if (include_invalid_declaration)
12485 {
12486 result_sstream << " test_subroutineFS(result);\n";
12487 }
12488 else
12489 {
12490 result_sstream << " result = vec4(0, 1, 2, 3);\n";
12491 }
12492
12493 result_sstream << "}\n";
12494
12495 return result_sstream.str();
12496 }
12497
12498 /** Retrieves geometry shader body.
12499 *
12500 * @param include_invalid_declaration true if a subroutine prototype should be included in
12501 * the shader, false to skip it.
12502 *
12503 * @return Requested string.
12504 **/
getGeometryShaderBody(bool include_invalid_declaration) const12505 std::string NegativeTest8::getGeometryShaderBody(bool include_invalid_declaration) const
12506 {
12507 std::stringstream result_sstream;
12508
12509 result_sstream << "#version 400\n"
12510 "\n"
12511 "#extension GL_ARB_shader_subroutine : require\n"
12512 "\n"
12513 "layout (points) in;\n"
12514 "layout (points, max_vertices = 1) out;\n"
12515 "\n";
12516
12517 if (include_invalid_declaration)
12518 {
12519 result_sstream << "subroutine void subroutineTestTypeGS(out vec4 test);\n"
12520 "\n"
12521 "subroutine(subroutineTestTypeGS) void test_impl1(out vec4 test);\n"
12522 "\n"
12523 "subroutine uniform subroutineTestTypeGS test_subroutineGS;\n";
12524 };
12525
12526 result_sstream << "\n"
12527 "void main()\n"
12528 "{\n";
12529
12530 if (include_invalid_declaration)
12531 {
12532 result_sstream << " test_subroutineGS(gl_Position);\n";
12533 }
12534 else
12535 {
12536 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
12537 }
12538
12539 result_sstream << "EmitVertex();\n"
12540 "}\n";
12541
12542 return result_sstream.str();
12543 }
12544
12545 /** Retrieves tessellation control shader body.
12546 *
12547 * @param include_invalid_declaration true if a subroutine prototype should be included in
12548 * the shader, false to skip it.
12549 *
12550 * @return Requested string.
12551 **/
getTessellationControlShaderBody(bool include_invalid_declaration) const12552 std::string NegativeTest8::getTessellationControlShaderBody(bool include_invalid_declaration) const
12553 {
12554 std::stringstream result_sstream;
12555
12556 result_sstream << "#version 400\n"
12557 "\n"
12558 "#extension GL_ARB_shader_subroutine : require\n"
12559 "\n"
12560 "layout (vertices = 4) out;\n"
12561 "\n";
12562
12563 if (include_invalid_declaration)
12564 {
12565 result_sstream << "subroutine void subroutineTestTypeTC(out vec4 test);\n"
12566 "\n"
12567 "subroutine(subroutineTestTypeTC) void test_impl1(out vec4 test);\n"
12568 "\n"
12569 "subroutine uniform subroutineTestTypeTC test_subroutineTC;\n";
12570 };
12571
12572 result_sstream << "\n"
12573 "void main()\n"
12574 "{\n";
12575
12576 if (include_invalid_declaration)
12577 {
12578 result_sstream << " test_subroutineTC(gl_out[gl_InvocationID].gl_Position);\n";
12579 }
12580 else
12581 {
12582 result_sstream << " gl_out[gl_InvocationID].gl_Position = vec4(0, 1, 2, 3);\n";
12583 }
12584
12585 result_sstream << "}\n";
12586
12587 return result_sstream.str();
12588 }
12589
12590 /** Retrieves tessellation evaluation body.
12591 *
12592 * @param include_invalid_declaration true if a subroutine prototype should be included in
12593 * the shader, false to skip it.
12594 *
12595 * @return Requested string.
12596 **/
getTessellationEvaluationShaderBody(bool include_invalid_declaration) const12597 std::string NegativeTest8::getTessellationEvaluationShaderBody(bool include_invalid_declaration) const
12598 {
12599 std::stringstream result_sstream;
12600
12601 result_sstream << "#version 400\n"
12602 "\n"
12603 "#extension GL_ARB_shader_subroutine : require\n"
12604 "\n"
12605 "layout (quads) in;\n"
12606 "\n";
12607
12608 if (include_invalid_declaration)
12609 {
12610 result_sstream << "subroutine void subroutineTestTypeTE(out vec4 test);\n"
12611 "\n"
12612 "subroutine(subroutineTestTypeTE) void test_impl1(out vec4 test);\n"
12613 "\n"
12614 "subroutine uniform subroutineTestTypeTE test_subroutineTE;\n";
12615 };
12616
12617 result_sstream << "\n"
12618 "void main()\n"
12619 "{\n";
12620
12621 if (include_invalid_declaration)
12622 {
12623 result_sstream << " test_subroutineTE(gl_Position);\n";
12624 }
12625 else
12626 {
12627 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
12628 }
12629
12630 result_sstream << "}\n";
12631
12632 return result_sstream.str();
12633 }
12634
12635 /** Retrieves vertex shader body.
12636 *
12637 * @param include_invalid_declaration true if a subroutine prototype should be included in
12638 * the shader, false to skip it.
12639 *
12640 * @return Requested string.
12641 **/
getVertexShaderBody(bool include_invalid_declaration) const12642 std::string NegativeTest8::getVertexShaderBody(bool include_invalid_declaration) const
12643 {
12644 std::stringstream result_sstream;
12645
12646 result_sstream << "#version 400\n"
12647 "\n"
12648 "#extension GL_ARB_shader_subroutine : require\n"
12649 "\n";
12650
12651 if (include_invalid_declaration)
12652 {
12653 result_sstream << "subroutine void subroutineTestTypeVS(out vec4 test);\n"
12654 "\n"
12655 "subroutine(subroutineTestTypeVS) void test_impl1(out vec4 test);\n"
12656 "\n"
12657 "subroutine uniform subroutineTestTypeVS test_subroutineVS;\n";
12658 };
12659
12660 result_sstream << "\n"
12661 "void main()\n"
12662 "{\n";
12663
12664 if (include_invalid_declaration)
12665 {
12666 result_sstream << " test_subroutineVS(gl_Position);\n";
12667 }
12668 else
12669 {
12670 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
12671 }
12672
12673 result_sstream << "}\n";
12674
12675 return result_sstream.str();
12676 }
12677
12678 /** Executes test iteration.
12679 *
12680 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
12681 */
iterate()12682 tcu::TestNode::IterateResult NegativeTest8::iterate()
12683 {
12684 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
12685 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
12686 {
12687 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
12688 }
12689
12690 /* Iterate over all shader stages. For each iteration, iteration-specific shader stage
12691 * will feature an invalid subroutine definition. Other shader stages will be assigned
12692 * valid bodies. The test fails if a program built of such shaders links successfully.
12693 */
12694 for (int shader_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
12695 shader_stage < static_cast<int>(Utils::SHADER_STAGE_COUNT); ++shader_stage)
12696 {
12697 executeIteration(static_cast<Utils::_shader_stage>(shader_stage));
12698 deinitIteration();
12699 } /* for (all shader stages) */
12700
12701 /* All done */
12702 if (m_has_test_passed)
12703 {
12704 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
12705 }
12706 else
12707 {
12708 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
12709 }
12710
12711 return STOP;
12712 }
12713
12714 /** Constructor.
12715 *
12716 * @param context Rendering context.
12717 **/
NegativeTest9(deqp::Context & context)12718 NegativeTest9::NegativeTest9(deqp::Context& context)
12719 : TestCase(context, "subroutines_cannot_be_assigned_float_int_values_or_be_compared",
12720 "Make sure it is not possible to assign float/int to subroutine "
12721 "uniform and that subroutine uniform values cannot be compared.")
12722 , m_has_test_passed(true)
12723 , m_po_id(0)
12724 , m_vs_id(0)
12725 {
12726 /* Left blank intentionally */
12727 }
12728
12729 /** Deinitializes any GL objects that may have been created during
12730 * test execution.
12731 **/
deinit()12732 void NegativeTest9::deinit()
12733 {
12734 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
12735
12736 if (m_po_id != 0)
12737 {
12738 gl.deleteProgram(m_po_id);
12739
12740 m_po_id = 0;
12741 }
12742
12743 if (m_vs_id != 0)
12744 {
12745 gl.deleteShader(m_vs_id);
12746
12747 m_vs_id = 0;
12748 }
12749 }
12750
12751 /** Returns a literal corresponding to user-specified test case enum.
12752 *
12753 * @param test_case As per description.
12754 *
12755 * @return Requested string.
12756 **/
getTestCaseString(const _test_case & test_case)12757 std::string NegativeTest9::getTestCaseString(const _test_case& test_case)
12758 {
12759 std::string result = "?";
12760
12761 switch (test_case)
12762 {
12763 case TEST_CASE_INVALID_FLOAT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT:
12764 result = "TEST_CASE_INVALID_FLOAT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT";
12765 break;
12766 case TEST_CASE_INVALID_INT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT:
12767 result = "TEST_CASE_INVALID_INT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT";
12768 break;
12769 case TEST_CASE_INVALID_SUBROUTINE_UNIFORM_VALUE_COMPARISON:
12770 result = "TEST_CASE_INVALID_SUBROUTINE_UNIFORM_VALUE_COMPARISON";
12771 break;
12772 default:
12773 break;
12774 }
12775
12776 return result;
12777 }
12778
12779 /** Retrieves vertex shader body for user-specified test case.
12780 *
12781 * @param test_case As per description.
12782 *
12783 * @return Requested string.
12784 **/
getVertexShader(const _test_case & test_case)12785 std::string NegativeTest9::getVertexShader(const _test_case& test_case)
12786 {
12787 std::stringstream result_sstream;
12788
12789 /* Form pre-amble */
12790 result_sstream << "#version 400\n"
12791 "\n"
12792 "#extension GL_ARB_shader_subroutine : require\n"
12793 "\n"
12794 /* Define a subroutine */
12795 "subroutine void subroutineType(inout vec4 test);\n"
12796 "\n"
12797 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
12798 "{\n"
12799 " test += vec4(0, 1, 2, 3);\n"
12800 "}\n"
12801 "\n"
12802 "subroutine uniform subroutineType function;\n"
12803 "\n";
12804
12805 /* Include case-specific implementation */
12806 switch (test_case)
12807 {
12808 case TEST_CASE_INVALID_FLOAT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT:
12809 {
12810 result_sstream << "void main()\n"
12811 "{\n"
12812 " function = 1.0f;\n"
12813 "\n"
12814 " function(gl_Position);\n"
12815 "}\n";
12816
12817 break;
12818 }
12819
12820 case TEST_CASE_INVALID_INT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT:
12821 {
12822 result_sstream << "void main()\n"
12823 "{\n"
12824 " function = 1;\n"
12825 "\n"
12826 " function(gl_Position);\n"
12827 "}\n";
12828
12829 break;
12830 }
12831
12832 case TEST_CASE_INVALID_SUBROUTINE_UNIFORM_VALUE_COMPARISON:
12833 {
12834 result_sstream << "subroutine uniform subroutineType function2;\n"
12835 "\n"
12836 "void main()\n"
12837 "{\n"
12838 " if (function == function2)\n"
12839 " {\n"
12840 " function(gl_Position);\n"
12841 " }\n"
12842 " else\n"
12843 " {\n"
12844 " function2(gl_Position);\n"
12845 " }\n"
12846 "}\n";
12847
12848 break;
12849 }
12850
12851 default:
12852 break;
12853 } /* switch (test_case) */
12854
12855 /* Done */
12856 return result_sstream.str();
12857 }
12858
12859 /** Executes test iteration.
12860 *
12861 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
12862 */
iterate()12863 tcu::TestNode::IterateResult NegativeTest9::iterate()
12864 {
12865 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
12866
12867 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
12868 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
12869 {
12870 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
12871 }
12872
12873 /* Iterate over all test cases */
12874 for (int test_case = static_cast<int>(TEST_CASE_FIRST); test_case != static_cast<int>(TEST_CASE_COUNT); ++test_case)
12875 {
12876 /* Try to build a program object using invalid vertex shader, specific to the
12877 * iteration we're currently in */
12878 std::string vs_body = getVertexShader(static_cast<_test_case>(test_case));
12879
12880 if (ShaderSubroutine::Utils::buildProgram(gl, vs_body, "", /* tc_body */
12881 "", /* te_body */
12882 "", /* gs_body */
12883 "", /* fs_body */
12884 DE_NULL, /* xfb_varyings */
12885 0, /* n_xfb_varyings */
12886 &m_vs_id, DE_NULL, /* out_tc_id */
12887 DE_NULL, /* out_te_id */
12888 DE_NULL, /* out_gs_id */
12889 DE_NULL, /* out_fs_id */
12890 &m_po_id))
12891 {
12892 m_testCtx.getLog() << tcu::TestLog::Message << "A program object was successfully built for ["
12893 << getTestCaseString(static_cast<_test_case>(test_case))
12894 << "] test case, even though it was invalid." << tcu::TestLog::EndMessage;
12895
12896 m_has_test_passed = false;
12897 }
12898
12899 /* Delete any objects that may have been created */
12900 deinit();
12901 } /* for (all test cases) */
12902
12903 /** All done */
12904 if (m_has_test_passed)
12905 {
12906 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
12907 }
12908 else
12909 {
12910 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
12911 }
12912
12913 return STOP;
12914 }
12915
12916 /** Constructor.
12917 *
12918 * @param context Rendering context.
12919 **/
NegativeTest10(deqp::Context & context)12920 NegativeTest10::NegativeTest10(deqp::Context& context)
12921 : TestCase(context, "function_overloading_forbidden_for_subroutines",
12922 "Check that an overloaded function cannot be declared with subroutine and "
12923 "a program will fail to compile or link if any shader or stage contains"
12924 " two or more functions with the same name if the name is associated with"
12925 " a subroutine type.")
12926 , m_has_test_passed(true)
12927 , m_fs_id(0)
12928 , m_gs_id(0)
12929 , m_po_id(0)
12930 , m_tc_id(0)
12931 , m_te_id(0)
12932 , m_vs_id(0)
12933 {
12934 /* Left blank intentionally */
12935 }
12936
12937 /** Deinitializes any GL objects that may have been created during
12938 * test execution.
12939 **/
deinit()12940 void NegativeTest10::deinit()
12941 {
12942 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
12943
12944 if (m_fs_id != 0)
12945 {
12946 gl.deleteShader(m_fs_id);
12947
12948 m_fs_id = 0;
12949 }
12950
12951 if (m_gs_id != 0)
12952 {
12953 gl.deleteShader(m_gs_id);
12954
12955 m_gs_id = 0;
12956 }
12957
12958 if (m_po_id != 0)
12959 {
12960 gl.deleteProgram(m_po_id);
12961
12962 m_po_id = 0;
12963 }
12964
12965 if (m_tc_id != 0)
12966 {
12967 gl.deleteShader(m_tc_id);
12968
12969 m_tc_id = 0;
12970 }
12971
12972 if (m_te_id != 0)
12973 {
12974 gl.deleteShader(m_te_id);
12975
12976 m_te_id = 0;
12977 }
12978
12979 if (m_vs_id != 0)
12980 {
12981 gl.deleteShader(m_vs_id);
12982
12983 m_vs_id = 0;
12984 }
12985 }
12986
12987 /** Retrieves fragment shader that should be used for the purpose of the test.
12988 * An overloaded version of a subroutine function is inserted if
12989 * @param include_duplicate_function flag is set to true.
12990 *
12991 * @param include_duplicate_function As per description.
12992 *
12993 * @return Requested string.
12994 **/
getFragmentShader(bool include_duplicate_function)12995 std::string NegativeTest10::getFragmentShader(bool include_duplicate_function)
12996 {
12997 std::stringstream result_sstream;
12998
12999 result_sstream << "#version 400\n"
13000 "\n"
13001 "#extension GL_ARB_shader_subroutine : require\n"
13002 "\n"
13003 "subroutine void subroutineType(inout vec4 test);\n"
13004 "\n"
13005 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13006 "{\n"
13007 " test = vec4(2, 3, 4, 5);\n"
13008 "}\n"
13009 "\n"
13010 "subroutine uniform subroutineType function;\n"
13011 "out vec4 result;\n"
13012 "\n";
13013
13014 if (include_duplicate_function)
13015 {
13016 result_sstream << "void test_function(inout vec4 test)\n"
13017 "{\n"
13018 " test = vec4(3, 4, 5, 6);\n"
13019 "}\n"
13020 "\n";
13021 }
13022
13023 result_sstream << "void main()\n"
13024 "{\n"
13025 " test_function(result);\n"
13026 "}\n";
13027
13028 return result_sstream.str();
13029 }
13030
13031 /** Retrieves geometry shader that should be used for the purpose of the test.
13032 * An overloaded version of a subroutine function is inserted if
13033 * @param include_duplicate_function flag is set to true.
13034 *
13035 * @param include_duplicate_function As per description.
13036 *
13037 * @return Requested string.
13038 **/
getGeometryShader(bool include_duplicate_function)13039 std::string NegativeTest10::getGeometryShader(bool include_duplicate_function)
13040 {
13041 std::stringstream result_sstream;
13042
13043 result_sstream << "#version 400\n"
13044 "\n"
13045 "#extension GL_ARB_shader_subroutine : require\n"
13046 "\n"
13047 "layout (triangles) in;\n"
13048 "layout (triangle_strip, max_vertices = 4) out;\n"
13049 "\n"
13050 "subroutine void subroutineType(inout vec4 test);\n"
13051 "\n"
13052 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13053 "{\n"
13054 " test = vec4(2, 3, 4, 5);\n"
13055 "}\n"
13056 "\n"
13057 "subroutine uniform subroutineType function;\n"
13058 "\n";
13059
13060 if (include_duplicate_function)
13061 {
13062 result_sstream << "void test_function(inout vec4 test)\n"
13063 "{\n"
13064 " test = vec4(3, 4, 5, 6);\n"
13065 "}\n"
13066 "\n";
13067 }
13068
13069 result_sstream << "void main()\n"
13070 "{\n"
13071 " function(gl_Position);\n"
13072 " EmitVertex();\n"
13073 " EndPrimitive();\n"
13074 "}\n";
13075
13076 return result_sstream.str();
13077 }
13078
13079 /** Retrieves tess control shader that should be used for the purpose of the test.
13080 * An overloaded version of a subroutine function is inserted if
13081 * @param include_duplicate_function flag is set to true.
13082 *
13083 * @param include_duplicate_function As per description.
13084 *
13085 * @return Requested string.
13086 **/
getTessellationControlShader(bool include_duplicate_function)13087 std::string NegativeTest10::getTessellationControlShader(bool include_duplicate_function)
13088 {
13089 std::stringstream result_sstream;
13090
13091 result_sstream << "#version 400\n"
13092 "\n"
13093 "#extension GL_ARB_shader_subroutine : require\n"
13094 "\n"
13095 "layout (vertices = 4) out;\n"
13096 "\n"
13097 "subroutine void subroutineType(inout vec4 test);\n"
13098 "\n"
13099 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13100 "{\n"
13101 " test = vec4(2, 3, 4, 5);\n"
13102 "}\n"
13103 "\n"
13104 "subroutine uniform subroutineType function;\n"
13105 "\n";
13106
13107 if (include_duplicate_function)
13108 {
13109 result_sstream << "void test_function(inout vec4 test)\n"
13110 "{\n"
13111 " test = vec4(3, 4, 5, 6);\n"
13112 "}\n"
13113 "\n";
13114 }
13115
13116 result_sstream << "void main()\n"
13117 "{\n"
13118 " vec4 temp;\n"
13119 "\n"
13120 " function(temp);\n"
13121 "\n"
13122 " gl_out[gl_InvocationID].gl_Position = temp;\n"
13123 " gl_TessLevelInner[0] = temp.x;\n"
13124 " gl_TessLevelInner[1] = temp.y;\n"
13125 " gl_TessLevelOuter[0] = temp.z;\n"
13126 " gl_TessLevelOuter[1] = temp.w;\n"
13127 " gl_TessLevelOuter[2] = temp.x;\n"
13128 " gl_TessLevelOuter[3] = temp.y;\n"
13129 "}\n";
13130
13131 return result_sstream.str();
13132 }
13133
13134 /** Retrieves tess evaluation shader that should be used for the purpose of the test.
13135 * An overloaded version of a subroutine function is inserted if
13136 * @param include_duplicate_function flag is set to true.
13137 *
13138 * @param include_duplicate_function As per description.
13139 *
13140 * @return Requested string.
13141 **/
getTessellationEvaluationShader(bool include_duplicate_function)13142 std::string NegativeTest10::getTessellationEvaluationShader(bool include_duplicate_function)
13143 {
13144 std::stringstream result_sstream;
13145
13146 result_sstream << "#version 400\n"
13147 "\n"
13148 "#extension GL_ARB_shader_subroutine : require\n"
13149 "\n"
13150 "layout (quads) in;\n"
13151 "\n"
13152 "subroutine void subroutineType(inout vec4 test);\n"
13153 "\n"
13154 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13155 "{\n"
13156 " test = vec4(2, 3, 4, 5);\n"
13157 "}\n"
13158 "\n"
13159 "subroutine uniform subroutineType function;\n"
13160 "\n";
13161
13162 if (include_duplicate_function)
13163 {
13164 result_sstream << "void test_function(inout vec4 test)\n"
13165 "{\n"
13166 " test = vec4(3, 4, 5, 6);\n"
13167 "}\n"
13168 "\n";
13169 }
13170
13171 result_sstream << "void main()\n"
13172 "{\n"
13173 " vec4 temp;\n"
13174 "\n"
13175 " function(temp);\n"
13176 "\n"
13177 " gl_Position = temp;\n"
13178 "}\n";
13179
13180 return result_sstream.str();
13181 }
13182
13183 /** Retrieves vertex shader that should be used for the purpose of the test.
13184 * An overloaded version of a subroutine function is inserted if
13185 * @param include_duplicate_function flag is set to true.
13186 *
13187 * @param include_duplicate_function As per description.
13188 *
13189 * @return Requested string.
13190 **/
getVertexShader(bool include_duplicate_function)13191 std::string NegativeTest10::getVertexShader(bool include_duplicate_function)
13192 {
13193 std::stringstream result_sstream;
13194
13195 result_sstream << "#version 400\n"
13196 "\n"
13197 "#extension GL_ARB_shader_subroutine : require\n"
13198 "\n"
13199 "subroutine void subroutineType(inout vec4 test);\n"
13200 "\n"
13201 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13202 "{\n"
13203 " test = vec4(2, 3, 4, 5);\n"
13204 "}\n"
13205 "\n"
13206 "subroutine uniform subroutineType function;\n"
13207 "\n";
13208
13209 if (include_duplicate_function)
13210 {
13211 result_sstream << "void test_function(inout vec4 test)\n"
13212 "{\n"
13213 " test = vec4(3, 4, 5, 6);\n"
13214 "}\n"
13215 "\n";
13216 }
13217
13218 result_sstream << "void main()\n"
13219 "{\n"
13220 " function(gl_Position);\n"
13221 "}\n";
13222
13223 return result_sstream.str();
13224 }
13225
13226 /** Fills m_test_cases field with test case descriptors */
initTestCases()13227 void NegativeTest10::initTestCases()
13228 {
13229 /* For each test case, only one shader stage should define a function that
13230 * has already been defined as a subroutine. */
13231 for (int offending_shader_stage_it = static_cast<int>(Utils::SHADER_STAGE_FIRST);
13232 offending_shader_stage_it != static_cast<int>(Utils::SHADER_STAGE_COUNT); ++offending_shader_stage_it)
13233 {
13234 Utils::_shader_stage offending_shader_stage = static_cast<Utils::_shader_stage>(offending_shader_stage_it);
13235 /* Form the test case descriptor */
13236 std::stringstream name_sstream;
13237 _test_case test_case;
13238
13239 name_sstream << "Broken shader stage:" << Utils::getShaderStageString(offending_shader_stage);
13240
13241 test_case.fs_body = getFragmentShader(offending_shader_stage == Utils::SHADER_STAGE_FRAGMENT);
13242 test_case.gs_body = getGeometryShader(offending_shader_stage == Utils::SHADER_STAGE_GEOMETRY);
13243 test_case.name = name_sstream.str();
13244 test_case.tc_body =
13245 getTessellationControlShader(offending_shader_stage == Utils::SHADER_STAGE_TESSELLATION_CONTROL);
13246 test_case.te_body =
13247 getTessellationEvaluationShader(offending_shader_stage == Utils::SHADER_STAGE_TESSELLATION_EVALUATION);
13248 test_case.vs_body = getVertexShader(offending_shader_stage == Utils::SHADER_STAGE_VERTEX);
13249
13250 m_test_cases.push_back(test_case);
13251 }
13252 }
13253
13254 /** Executes test iteration.
13255 *
13256 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
13257 */
iterate()13258 tcu::TestNode::IterateResult NegativeTest10::iterate()
13259 {
13260 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
13261
13262 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
13263 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
13264 {
13265 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
13266 }
13267
13268 /* Form test cases */
13269 initTestCases();
13270
13271 /* Iterate over all test cases */
13272 for (_test_cases_const_iterator test_case_iterator = m_test_cases.begin(); test_case_iterator != m_test_cases.end();
13273 ++test_case_iterator)
13274 {
13275 const _test_case& test_case = *test_case_iterator;
13276
13277 /* Try to build the program object */
13278 if (ShaderSubroutine::Utils::buildProgram(gl, test_case.vs_body, test_case.tc_body, test_case.te_body,
13279 test_case.gs_body, test_case.fs_body, DE_NULL, /* xfb_varyings */
13280 0, /* n_xfb_varyings */
13281 &m_vs_id, (test_case.tc_body.length() > 0) ? &m_tc_id : DE_NULL,
13282 (test_case.te_body.length() > 0) ? &m_te_id : DE_NULL,
13283 (test_case.gs_body.length() > 0) ? &m_gs_id : DE_NULL,
13284 (test_case.fs_body.length() > 0) ? &m_fs_id : DE_NULL, &m_po_id))
13285 {
13286 m_testCtx.getLog() << tcu::TestLog::Message << "A program object was successfully built for ["
13287 << test_case.name << "] test case, even though it was invalid."
13288 << tcu::TestLog::EndMessage;
13289
13290 m_has_test_passed = false;
13291 }
13292
13293 /* Delete any objects that may have been created */
13294 deinit();
13295 } /* for (all test cases) */
13296
13297 /** All done */
13298 if (m_has_test_passed)
13299 {
13300 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
13301 }
13302 else
13303 {
13304 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
13305 }
13306
13307 return STOP;
13308 }
13309
13310 /** Constructor.
13311 *
13312 * @param context Rendering context.
13313 **/
NegativeTest11(deqp::Context & context)13314 NegativeTest11::NegativeTest11(deqp::Context& context)
13315 : TestCase(context, "subroutine_uniforms_used_for_sampling_atomic_image_functions",
13316 "Tries to use subroutine uniforms in invalid way in sampling, "
13317 "atomic and image functions. Verifies that compile- or link-time "
13318 "error occurs.")
13319 , m_has_test_passed(true)
13320 , m_po_id(0)
13321 , m_vs_id(0)
13322 {
13323 /* Left blank intentionally */
13324 }
13325
13326 /** Deinitializes any GL objects that may have been created during
13327 * test execution.
13328 **/
deinit()13329 void NegativeTest11::deinit()
13330 {
13331 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
13332
13333 if (m_po_id != 0)
13334 {
13335 gl.deleteProgram(m_po_id);
13336
13337 m_po_id = 0;
13338 }
13339
13340 if (m_vs_id != 0)
13341 {
13342 gl.deleteShader(m_vs_id);
13343
13344 m_vs_id = 0;
13345 }
13346 }
13347
13348 /** Returns a literal corresponding to user-specified test case enum.
13349 *
13350 * @param test_case As per description.
13351 *
13352 * @return Requested string.
13353 **/
getTestCaseString(const _test_case & test_case)13354 std::string NegativeTest11::getTestCaseString(const _test_case& test_case)
13355 {
13356 std::string result = "?";
13357
13358 switch (test_case)
13359 {
13360 case TEST_CASE_INVALID_TEXTURE_SAMPLING_ATTEMPT:
13361 result = "TEST_CASE_INVALID_TEXTURE_SAMPLING_ATTEMPT";
13362 break;
13363 case TEST_CASE_INVALID_ATOMIC_COUNTER_USAGE_ATTEMPT:
13364 result = "TEST_CASE_INVALID_ATOMIC_COUNTER_USAGE_ATTEMPT";
13365 break;
13366 case TEST_CASE_INVALID_IMAGE_FUNCTION_USAGE_ATTEMPT:
13367 result = "TEST_CASE_INVALID_IMAGE_FUNCTION_USAGE_ATTEMPT";
13368 break;
13369 default:
13370 break;
13371 }
13372
13373 return result;
13374 }
13375
13376 /** Retrieves vertex shader body for user-specified test case.
13377 *
13378 * @param test_case As per description.
13379 *
13380 * @return Requested string.
13381 **/
getVertexShader(const _test_case & test_case)13382 std::string NegativeTest11::getVertexShader(const _test_case& test_case)
13383 {
13384 std::stringstream result_sstream;
13385
13386 /* Form pre-amble */
13387 result_sstream << "#version 400\n"
13388 "\n"
13389 "#extension GL_ARB_shader_subroutine : require\n";
13390
13391 if (test_case == TEST_CASE_INVALID_ATOMIC_COUNTER_USAGE_ATTEMPT)
13392 {
13393 result_sstream << "#extension GL_ARB_shader_atomic_counters : require\n";
13394 }
13395
13396 result_sstream << "\n"
13397 /* Define a subroutine */
13398 "subroutine void subroutineType(inout vec4 test);\n"
13399 "\n"
13400 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13401 "{\n"
13402 " test += vec4(0, 1, 2, 3);\n"
13403 "}\n"
13404 "\n"
13405 "subroutine uniform subroutineType function;\n"
13406 "\n"
13407
13408 /* Define main() body */
13409 "void main()\n"
13410 "{\n";
13411
13412 /* Implement case-specific behavior */
13413 switch (test_case)
13414 {
13415 case TEST_CASE_INVALID_ATOMIC_COUNTER_USAGE_ATTEMPT:
13416 {
13417 result_sstream << "if (atomicCounter(function) > 2)\n"
13418 "{\n"
13419 " gl_Position = vec4(1);\n"
13420 "}\n";
13421
13422 break;
13423 }
13424
13425 case TEST_CASE_INVALID_IMAGE_FUNCTION_USAGE_ATTEMPT:
13426 {
13427 result_sstream << "imageStore(function, vec2(0.0, 1.0), vec4(1.0) );\n";
13428
13429 break;
13430 }
13431
13432 case TEST_CASE_INVALID_TEXTURE_SAMPLING_ATTEMPT:
13433 {
13434 result_sstream << "gl_Position = texture(function, vec2(1.0) );\n";
13435
13436 break;
13437 }
13438
13439 default:
13440 break;
13441 } /* switch (test_case) */
13442
13443 /* Close main() body */
13444 result_sstream << "}\n";
13445
13446 /* Done */
13447 return result_sstream.str();
13448 }
13449
13450 /** Executes test iteration.
13451 *
13452 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
13453 */
iterate()13454 tcu::TestNode::IterateResult NegativeTest11::iterate()
13455 {
13456 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
13457
13458 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
13459 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
13460 {
13461 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
13462 }
13463
13464 /* Iterate over all test cases */
13465 for (int test_case = static_cast<int>(TEST_CASE_FIRST); test_case != static_cast<int>(TEST_CASE_COUNT); ++test_case)
13466 {
13467 if (static_cast<_test_case>(test_case) == TEST_CASE_INVALID_ATOMIC_COUNTER_USAGE_ATTEMPT &&
13468 !m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_atomic_counters"))
13469 {
13470 /* This iteration requires atomic counter support that this GL implementation
13471 * is not capable of. Skip the iteration
13472 */
13473 continue;
13474 }
13475
13476 /* Try to build a program object using invalid vertex shader, specific to the
13477 * iteration we're currently in */
13478 std::string vs_body = getVertexShader(static_cast<_test_case>(test_case));
13479
13480 if (ShaderSubroutine::Utils::buildProgram(gl, vs_body, "", /* tc_body */
13481 "", /* te_body */
13482 "", /* gs_body */
13483 "", /* fs_body */
13484 DE_NULL, /* xfb_varyings */
13485 0, /* n_xfb_varyings */
13486 &m_vs_id, DE_NULL, /* out_tc_id */
13487 DE_NULL, /* out_te_id */
13488 DE_NULL, /* out_gs_id */
13489 DE_NULL, /* out_fs_id */
13490 &m_po_id))
13491 {
13492 m_testCtx.getLog() << tcu::TestLog::Message << "A program object was successfully built for ["
13493 << getTestCaseString(static_cast<_test_case>(test_case))
13494 << "] test case, even though it was invalid." << tcu::TestLog::EndMessage;
13495
13496 m_has_test_passed = false;
13497 }
13498
13499 /* Delete any objects that may have been created */
13500 deinit();
13501 } /* for (all test cases) */
13502
13503 /** All done */
13504 if (m_has_test_passed)
13505 {
13506 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
13507 }
13508 else
13509 {
13510 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
13511 }
13512
13513 return STOP;
13514 }
13515
13516 /** Constructor.
13517 *
13518 * @param context Rendering context.
13519 **/
NegativeTest12(deqp::Context & context)13520 NegativeTest12::NegativeTest12(deqp::Context& context)
13521 : TestCase(context, "subroutines_not_allowed_as_variables_constructors_and_argument_or_return_types",
13522 "Verifies that it is not allowed to use subroutine type for "
13523 "local/global variables, constructors or argument/return type.")
13524 , m_has_test_passed(true)
13525 , m_po_id(0)
13526 , m_vs_id(0)
13527 {
13528 /* Left blank intentionally */
13529 }
13530
13531 /** Deinitializes any GL objects that may have been created during
13532 * test execution.
13533 **/
deinit()13534 void NegativeTest12::deinit()
13535 {
13536 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
13537
13538 if (m_po_id != 0)
13539 {
13540 gl.deleteProgram(m_po_id);
13541
13542 m_po_id = 0;
13543 }
13544
13545 if (m_vs_id != 0)
13546 {
13547 gl.deleteShader(m_vs_id);
13548
13549 m_vs_id = 0;
13550 }
13551 }
13552
13553 /** Returns a literal corresponding to user-specified test case enum.
13554 *
13555 * @param test_case As per description.
13556 *
13557 * @return Requested string.
13558 **/
getTestCaseString(const _test_case & test_case)13559 std::string NegativeTest12::getTestCaseString(const _test_case& test_case)
13560 {
13561 std::string result = "?";
13562
13563 switch (test_case)
13564 {
13565 case TEST_CASE_INVALID_LOCAL_SUBROUTINE_VARIABLE:
13566 result = "TEST_CASE_INVALID_LOCAL_SUBROUTINE_VARIABLE";
13567 break;
13568 case TEST_CASE_INVALID_GLOBAL_SUBROUTINE_VARIABLE:
13569 result = "TEST_CASE_INVALID_GLOBAL_SUBROUTINE_VARIABLE";
13570 break;
13571 case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR:
13572 result = "TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR";
13573 break;
13574 case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_ARGUMENT:
13575 result = "TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_ARGUMENT";
13576 break;
13577 case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_RETURN_TYPE:
13578 result = "TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_RETURN_TYPE";
13579 break;
13580 default:
13581 break;
13582 }
13583
13584 return result;
13585 }
13586
13587 /** Retrieves vertex shader body for user-specified test case.
13588 *
13589 * @param test_case As per description.
13590 *
13591 * @return Requested string.
13592 **/
getVertexShader(const _test_case & test_case)13593 std::string NegativeTest12::getVertexShader(const _test_case& test_case)
13594 {
13595 std::stringstream result_sstream;
13596
13597 /* Form pre-amble */
13598 result_sstream << "#version 400\n"
13599 "\n"
13600 "#extension GL_ARB_shader_subroutine : require\n"
13601 "\n"
13602 /* Define a subroutine */
13603 "subroutine void subroutineType(inout vec4 test);\n"
13604 "\n"
13605 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13606 "{\n"
13607 " test += vec4(0, 1, 2, 3);\n"
13608 "}\n"
13609 "\n"
13610 "subroutine uniform subroutineType function;\n"
13611 "\n";
13612
13613 /* Include case-specific implementation */
13614 switch (test_case)
13615 {
13616 case TEST_CASE_INVALID_LOCAL_SUBROUTINE_VARIABLE:
13617 {
13618 result_sstream << "void main()\n"
13619 "{\n"
13620 " subroutine subroutineType function2;\n"
13621 " vec4 result;\n"
13622 "\n"
13623 " function2(result);\n"
13624 " gl_Position = result;\n"
13625 "}\n";
13626
13627 break;
13628 }
13629
13630 case TEST_CASE_INVALID_GLOBAL_SUBROUTINE_VARIABLE:
13631 {
13632 result_sstream << "subroutine subroutineType function2;\n"
13633 "\n"
13634 "void main()\n"
13635 "{\n"
13636 " vec4 result;\n"
13637 "\n"
13638 " function2(result);\n"
13639 " gl_Position = result;\n"
13640 "}\n";
13641
13642 break;
13643 }
13644
13645 case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR:
13646 {
13647 result_sstream << "void main()\n"
13648 "{\n"
13649 " subroutineType(function);\n"
13650 "}\n";
13651
13652 break;
13653 }
13654
13655 case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_ARGUMENT:
13656 {
13657 result_sstream << "vec4 test_function(subroutineType argument)\n"
13658 "{\n"
13659 " vec4 result = vec4(1, 2, 3, 4);\n"
13660 "\n"
13661 " argument(result);\n"
13662 "\n"
13663 " return result;\n"
13664 "}\n"
13665 "\n"
13666 "void main()\n"
13667 "{\n"
13668 " test_function(function);\n"
13669 "}\n";
13670
13671 break;
13672 }
13673
13674 case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_RETURN_TYPE:
13675 {
13676 result_sstream << "subroutineType test_function()\n"
13677 "{\n"
13678 " return function;\n"
13679 "}\n"
13680 "\n"
13681 "void main()\n"
13682 "{\n"
13683 " test_function()(gl_Position);\n"
13684 "}\n";
13685
13686 break;
13687 }
13688
13689 default:
13690 break;
13691 } /* switch (test_case) */
13692
13693 /* Done */
13694 return result_sstream.str();
13695 }
13696
13697 /** Executes test iteration.
13698 *
13699 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
13700 */
iterate()13701 tcu::TestNode::IterateResult NegativeTest12::iterate()
13702 {
13703 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
13704
13705 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
13706 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
13707 {
13708 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
13709 }
13710
13711 /* Iterate over all test cases */
13712 for (int test_case = static_cast<int>(TEST_CASE_FIRST); test_case != static_cast<int>(TEST_CASE_COUNT); ++test_case)
13713 {
13714 /* Try to build a program object using invalid vertex shader, specific to the
13715 * iteration we're currently in */
13716 std::string vs_body = getVertexShader(static_cast<_test_case>(test_case));
13717
13718 if (ShaderSubroutine::Utils::buildProgram(gl, vs_body, "", /* tc_body */
13719 "", /* te_body */
13720 "", /* gs_body */
13721 "", /* fs_body */
13722 DE_NULL, /* xfb_varyings */
13723 0, /* n_xfb_varyings */
13724 &m_vs_id, DE_NULL, /* out_tc_id */
13725 DE_NULL, /* out_te_id */
13726 DE_NULL, /* out_gs_id */
13727 DE_NULL, /* out_fs_id */
13728 &m_po_id))
13729 {
13730 m_testCtx.getLog() << tcu::TestLog::Message << "A program object was successfully built for ["
13731 << getTestCaseString(static_cast<_test_case>(test_case))
13732 << "] test case, even though it was invalid." << tcu::TestLog::EndMessage;
13733
13734 m_has_test_passed = false;
13735 }
13736
13737 /* Delete any objects that may have been created */
13738 deinit();
13739 } /* for (all test cases) */
13740
13741 /** All done */
13742 if (m_has_test_passed)
13743 {
13744 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
13745 }
13746 else
13747 {
13748 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
13749 }
13750
13751 return STOP;
13752 }
13753
13754 } /* ShaderSubroutine */
13755
13756 /** Constructor.
13757 *
13758 * @param context Rendering context.
13759 **/
ShaderSubroutineTests(deqp::Context & context)13760 ShaderSubroutineTests::ShaderSubroutineTests(deqp::Context& context)
13761 : TestCaseGroup(context, "shader_subroutine", "Verifies \"shader_subroutine\" functionality")
13762 {
13763 /* Left blank on purpose */
13764 }
13765
13766 /** Initializes a texture_storage_multisample test group.
13767 *
13768 **/
init(void)13769 void ShaderSubroutineTests::init(void)
13770 {
13771 addChild(new ShaderSubroutine::APITest1(m_context));
13772 addChild(new ShaderSubroutine::APITest2(m_context));
13773 addChild(new ShaderSubroutine::FunctionalTest1_2(m_context));
13774 addChild(new ShaderSubroutine::FunctionalTest3_4(m_context));
13775 addChild(new ShaderSubroutine::FunctionalTest5(m_context));
13776 addChild(new ShaderSubroutine::FunctionalTest6(m_context));
13777 addChild(new ShaderSubroutine::FunctionalTest7_8(m_context));
13778 addChild(new ShaderSubroutine::FunctionalTest9(m_context));
13779 addChild(new ShaderSubroutine::FunctionalTest10(m_context));
13780 addChild(new ShaderSubroutine::FunctionalTest11(m_context));
13781 addChild(new ShaderSubroutine::FunctionalTest12(m_context));
13782 addChild(new ShaderSubroutine::FunctionalTest13(m_context));
13783 addChild(new ShaderSubroutine::FunctionalTest14_15(m_context));
13784 addChild(new ShaderSubroutine::FunctionalTest16(m_context));
13785 addChild(new ShaderSubroutine::FunctionalTest17(m_context));
13786 addChild(new ShaderSubroutine::FunctionalTest18_19(m_context));
13787 addChild(new ShaderSubroutine::NegativeTest1(m_context));
13788 addChild(new ShaderSubroutine::NegativeTest2(m_context));
13789 addChild(new ShaderSubroutine::NegativeTest3(m_context));
13790 addChild(new ShaderSubroutine::NegativeTest4(m_context));
13791 addChild(new ShaderSubroutine::NegativeTest5(m_context));
13792 addChild(new ShaderSubroutine::NegativeTest6(m_context));
13793 addChild(new ShaderSubroutine::NegativeTest7(m_context));
13794 addChild(new ShaderSubroutine::NegativeTest8(m_context));
13795 addChild(new ShaderSubroutine::NegativeTest9(m_context));
13796 addChild(new ShaderSubroutine::NegativeTest10(m_context));
13797 addChild(new ShaderSubroutine::NegativeTest11(m_context));
13798 addChild(new ShaderSubroutine::NegativeTest12(m_context));
13799 }
13800
13801 } /* glcts namespace */
13802