1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2014-2016 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 */ /*!
20 * \file
21 * \brief
22 */ /*-------------------------------------------------------------------*/
23
24 /**
25 * \file gl4cShaderSubroutineTests.cpp
26 * \brief Implements conformance tests for "Shader Subroutine" functionality.
27 */ /*-------------------------------------------------------------------*/
28
29 #include "gl4cShaderSubroutineTests.hpp"
30 #include "gluContextInfo.hpp"
31 #include "glwEnums.hpp"
32 #include "glwFunctions.hpp"
33 #include "tcuMatrix.hpp"
34 #include <cmath>
35 #include <cstring>
36 #include <deMath.h>
37
38 using namespace glw;
39
40 namespace gl4cts
41 {
42 namespace ShaderSubroutine
43 {
44 /** Constructor.
45 *
46 * @param context CTS context.
47 **/
buffer(deqp::Context & context)48 Utils::buffer::buffer(deqp::Context &context) : m_id(0), m_context(context)
49 {
50 }
51
52 /** Destructor
53 *
54 **/
~buffer()55 Utils::buffer::~buffer()
56 {
57 if (0 != m_id)
58 {
59 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
60
61 gl.deleteBuffers(1, &m_id);
62 m_id = 0;
63 }
64 }
65
66 /** Execute BindBufferRange
67 *
68 * @param target <target> parameter
69 * @param index <index> parameter
70 * @param offset <offset> parameter
71 * @param size <size> parameter
72 **/
bindRange(glw::GLenum target,glw::GLuint index,glw::GLintptr offset,glw::GLsizeiptr size)73 void Utils::buffer::bindRange(glw::GLenum target, glw::GLuint index, glw::GLintptr offset, glw::GLsizeiptr size)
74 {
75 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
76
77 gl.bindBufferRange(target, index, m_id, offset, size);
78 GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferRange");
79 }
80
81 /** Execute GenBuffer
82 *
83 **/
generate()84 void Utils::buffer::generate()
85 {
86 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
87
88 gl.genBuffers(1, &m_id);
89 GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers");
90 }
91
92 /** Execute BufferData
93 *
94 * @param target <target> parameter
95 * @param size <size> parameter
96 * @param data <data> parameter
97 * @param usage <usage> parameter
98 **/
update(glw::GLenum target,glw::GLsizeiptr size,glw::GLvoid * data,glw::GLenum usage)99 void Utils::buffer::update(glw::GLenum target, glw::GLsizeiptr size, glw::GLvoid *data, glw::GLenum usage)
100 {
101 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
102
103 gl.bindBuffer(target, m_id);
104 GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer");
105
106 gl.bufferData(target, size, data, usage);
107 GLU_EXPECT_NO_ERROR(gl.getError(), "bufferData");
108 }
109
110 /** Constructor
111 *
112 * @param context CTS context
113 **/
framebuffer(deqp::Context & context)114 Utils::framebuffer::framebuffer(deqp::Context &context) : m_id(0), m_context(context)
115 {
116 /* Nothing to be done here */
117 }
118
119 /** Destructor
120 *
121 **/
~framebuffer()122 Utils::framebuffer::~framebuffer()
123 {
124 if (0 != m_id)
125 {
126 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
127
128 gl.deleteFramebuffers(1, &m_id);
129 m_id = 0;
130 }
131 }
132
133 /** Attach texture to specified attachment
134 *
135 * @param attachment Attachment
136 * @param texture_id Texture id
137 * @param width Texture width
138 * @param height Texture height
139 **/
attachTexture(glw::GLenum attachment,glw::GLuint texture_id,glw::GLuint width,glw::GLuint height)140 void Utils::framebuffer::attachTexture(glw::GLenum attachment, glw::GLuint texture_id, glw::GLuint width,
141 glw::GLuint height)
142 {
143 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
144
145 bind();
146
147 gl.bindTexture(GL_TEXTURE_2D, texture_id);
148 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
149
150 gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, GL_TEXTURE_2D, texture_id, 0 /* level */);
151
152 GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture2D");
153
154 gl.viewport(0 /* x */, 0 /* y */, width, height);
155 GLU_EXPECT_NO_ERROR(gl.getError(), "Viewport");
156 }
157
158 /** Binds framebuffer to DRAW_FRAMEBUFFER
159 *
160 **/
bind()161 void Utils::framebuffer::bind()
162 {
163 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
164
165 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_id);
166 GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
167 }
168
169 /** Clear framebuffer
170 *
171 * @param mask <mask> parameter of glClear. Decides which shall be cleared
172 **/
clear(glw::GLenum mask)173 void Utils::framebuffer::clear(glw::GLenum mask)
174 {
175 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
176
177 gl.clear(mask);
178 GLU_EXPECT_NO_ERROR(gl.getError(), "Clear");
179 }
180
181 /** Specifie clear color
182 *
183 * @param red Red channel
184 * @param green Green channel
185 * @param blue Blue channel
186 * @param alpha Alpha channel
187 **/
clearColor(GLfloat red,GLfloat green,GLfloat blue,GLfloat alpha)188 void Utils::framebuffer::clearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
189 {
190 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
191
192 gl.clearColor(red, green, blue, alpha);
193 GLU_EXPECT_NO_ERROR(gl.getError(), "ClearColor");
194 }
195
196 /** Generate framebuffer
197 *
198 **/
generate()199 void Utils::framebuffer::generate()
200 {
201 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
202
203 gl.genFramebuffers(1, &m_id);
204 GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers");
205 }
206
207 const glw::GLenum Utils::program::ARB_COMPUTE_SHADER = 0x91B9;
208
209 /** Constructor.
210 *
211 * @param context CTS context.
212 **/
program(deqp::Context & context)213 Utils::program::program(deqp::Context &context)
214 : m_compute_shader_id(0)
215 , m_fragment_shader_id(0)
216 , m_geometry_shader_id(0)
217 , m_program_object_id(0)
218 , m_tesselation_control_shader_id(0)
219 , m_tesselation_evaluation_shader_id(0)
220 , m_vertex_shader_id(0)
221 , m_context(context)
222 {
223 /* Nothing to be done here */
224 }
225
226 /** Destructor
227 *
228 **/
~program()229 Utils::program::~program()
230 {
231 remove();
232 }
233
234 /** Build program
235 *
236 * @param compute_shader_code Compute shader source code
237 * @param fragment_shader_code Fragment shader source code
238 * @param geometry_shader_code Geometry shader source code
239 * @param tesselation_control_shader_code Tesselation control shader source code
240 * @param tesselation_evaluation_shader_code Tesselation evaluation shader source code
241 * @param vertex_shader_code Vertex shader source code
242 * @param varying_names Array of strings containing names of varyings to be captured with transfrom feedback
243 * @param n_varying_names Number of varyings to be captured with transfrom feedback
244 * @param is_separable Selects if monolithis or separable program should be built. Defaults to false
245 **/
build(const glw::GLchar * compute_shader_code,const glw::GLchar * fragment_shader_code,const glw::GLchar * geometry_shader_code,const glw::GLchar * tesselation_control_shader_code,const glw::GLchar * tesselation_evaluation_shader_code,const glw::GLchar * vertex_shader_code,const glw::GLchar * const * varying_names,glw::GLuint n_varying_names,bool is_separable)246 void Utils::program::build(const glw::GLchar *compute_shader_code, const glw::GLchar *fragment_shader_code,
247 const glw::GLchar *geometry_shader_code, const glw::GLchar *tesselation_control_shader_code,
248 const glw::GLchar *tesselation_evaluation_shader_code, const glw::GLchar *vertex_shader_code,
249 const glw::GLchar *const *varying_names, glw::GLuint n_varying_names, bool is_separable)
250 {
251 /* GL entry points */
252 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
253
254 /* Create shader objects and compile */
255 if (0 != compute_shader_code)
256 {
257 m_compute_shader_id = gl.createShader(ARB_COMPUTE_SHADER);
258 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
259
260 compile(m_compute_shader_id, compute_shader_code);
261 }
262
263 if (0 != fragment_shader_code)
264 {
265 m_fragment_shader_id = gl.createShader(GL_FRAGMENT_SHADER);
266 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
267
268 compile(m_fragment_shader_id, fragment_shader_code);
269 }
270
271 if (0 != geometry_shader_code)
272 {
273 m_geometry_shader_id = gl.createShader(GL_GEOMETRY_SHADER);
274 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
275
276 compile(m_geometry_shader_id, geometry_shader_code);
277 }
278
279 if (0 != tesselation_control_shader_code)
280 {
281 m_tesselation_control_shader_id = gl.createShader(GL_TESS_CONTROL_SHADER);
282 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
283
284 compile(m_tesselation_control_shader_id, tesselation_control_shader_code);
285 }
286
287 if (0 != tesselation_evaluation_shader_code)
288 {
289 m_tesselation_evaluation_shader_id = gl.createShader(GL_TESS_EVALUATION_SHADER);
290 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
291
292 compile(m_tesselation_evaluation_shader_id, tesselation_evaluation_shader_code);
293 }
294
295 if (0 != vertex_shader_code)
296 {
297 m_vertex_shader_id = gl.createShader(GL_VERTEX_SHADER);
298 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
299
300 compile(m_vertex_shader_id, vertex_shader_code);
301 }
302
303 /* Create program object */
304 m_program_object_id = gl.createProgram();
305 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateProgram");
306
307 /* Set up captyured varyings' names */
308 if (0 != n_varying_names)
309 {
310 gl.transformFeedbackVaryings(m_program_object_id, n_varying_names, varying_names, GL_INTERLEAVED_ATTRIBS);
311 GLU_EXPECT_NO_ERROR(gl.getError(), "TransformFeedbackVaryings");
312 }
313
314 /* Set separable parameter */
315 if (true == is_separable)
316 {
317 gl.programParameteri(m_program_object_id, GL_PROGRAM_SEPARABLE, GL_TRUE);
318 GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramParameteri");
319 }
320
321 /* Link program */
322 link();
323 }
324
325 /** Compile shader
326 *
327 * @param shader_id Shader object id
328 * @param shader_code Shader source code
329 **/
compile(glw::GLuint shader_id,const glw::GLchar * shader_code) const330 void Utils::program::compile(glw::GLuint shader_id, const glw::GLchar *shader_code) const
331 {
332 /* GL entry points */
333 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
334
335 /* Compilation status */
336 glw::GLint status = GL_FALSE;
337
338 /* Set source code */
339 gl.shaderSource(shader_id, 1 /* count */, &shader_code, 0);
340 GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderSource");
341
342 /* Compile */
343 gl.compileShader(shader_id);
344 GLU_EXPECT_NO_ERROR(gl.getError(), "CompileShader");
345
346 /* Get compilation status */
347 gl.getShaderiv(shader_id, GL_COMPILE_STATUS, &status);
348 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
349
350 /* Log compilation error */
351 if (GL_TRUE != status)
352 {
353 glw::GLint length = 0;
354 std::vector<glw::GLchar> message;
355
356 /* Error log length */
357 gl.getShaderiv(shader_id, GL_INFO_LOG_LENGTH, &length);
358 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
359
360 /* Prepare storage */
361 message.resize(length);
362
363 /* Get error log */
364 gl.getShaderInfoLog(shader_id, length, 0, &message[0]);
365 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderInfoLog");
366
367 /* Log */
368 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Failed to compile shader:\n"
369 << &message[0] << "\nShader source\n"
370 << shader_code << tcu::TestLog::EndMessage;
371
372 TCU_FAIL("Failed to compile shader");
373 }
374 }
375
376 /** Checks whether the tested driver supports GL_ARB_get_program_binary
377 *
378 * @return true if the extension is supported and, also, at least one binary format.
379 **/
isProgramBinarySupported() const380 bool Utils::program::isProgramBinarySupported() const
381 {
382 glw::GLint n_program_binary_formats = 0;
383
384 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
385
386 if (m_context.getContextInfo().isExtensionSupported("GL_ARB_get_program_binary"))
387 {
388 gl.getIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &n_program_binary_formats);
389 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed.");
390 }
391
392 return n_program_binary_formats > 0;
393 }
394
395 /** Create program from provided binary
396 *
397 * @param binary Buffer with binary form of program
398 * @param binary_format Format of <binary> data
399 **/
createFromBinary(const std::vector<GLubyte> & binary,GLenum binary_format)400 void Utils::program::createFromBinary(const std::vector<GLubyte> &binary, GLenum binary_format)
401 {
402 /* GL entry points */
403 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
404
405 /* Create program object */
406 m_program_object_id = gl.createProgram();
407 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateProgram");
408
409 gl.programBinary(m_program_object_id, binary_format, &binary[0], (GLsizei)binary.size());
410 GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramBinary");
411 }
412
413 /** Get binary form of program
414 *
415 * @param binary Buffer for binary data
416 * @param binary_format Format of binary data
417 **/
getBinary(std::vector<GLubyte> & binary,GLenum & binary_format) const418 void Utils::program::getBinary(std::vector<GLubyte> &binary, GLenum &binary_format) const
419 {
420 /* GL entry points */
421 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
422
423 /* Get binary size */
424 GLint length = 0;
425 gl.getProgramiv(m_program_object_id, GL_PROGRAM_BINARY_LENGTH, &length);
426 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
427
428 /* Allocate storage */
429 binary.resize(length);
430
431 /* Get binary */
432 gl.getProgramBinary(m_program_object_id, (GLsizei)binary.size(), &length, &binary_format, &binary[0]);
433 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramBinary");
434 }
435
436 /** Get subroutine index
437 *
438 * @param subroutine_name Subroutine name
439 *
440 * @return Index of subroutine
441 **/
getSubroutineIndex(const glw::GLchar * subroutine_name,glw::GLenum shader_stage) const442 GLuint Utils::program::getSubroutineIndex(const glw::GLchar *subroutine_name, glw::GLenum shader_stage) const
443 {
444 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
445 GLuint index = -1;
446
447 index = gl.getSubroutineIndex(m_program_object_id, shader_stage, subroutine_name);
448 GLU_EXPECT_NO_ERROR(gl.getError(), "GetSubroutineIndex");
449
450 if (GL_INVALID_INDEX == index)
451 {
452 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Subroutine: " << subroutine_name
453 << " is not available" << tcu::TestLog::EndMessage;
454
455 TCU_FAIL("Subroutine is not available");
456 }
457
458 return index;
459 }
460
461 /** Get subroutine uniform location
462 *
463 * @param uniform_name Subroutine uniform name
464 *
465 * @return Location of subroutine uniform
466 **/
getSubroutineUniformLocation(const glw::GLchar * uniform_name,glw::GLenum shader_stage) const467 GLint Utils::program::getSubroutineUniformLocation(const glw::GLchar *uniform_name, glw::GLenum shader_stage) const
468 {
469 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
470 GLint location = -1;
471
472 location = gl.getSubroutineUniformLocation(m_program_object_id, shader_stage, uniform_name);
473 GLU_EXPECT_NO_ERROR(gl.getError(), "GetSubroutineUniformLocation");
474
475 if (-1 == location)
476 {
477 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Subroutine uniform: " << uniform_name
478 << " is not available" << tcu::TestLog::EndMessage;
479
480 TCU_FAIL("Subroutine uniform is not available");
481 }
482
483 return location;
484 }
485
486 /** Get uniform location
487 *
488 * @param uniform_name Subroutine uniform name
489 *
490 * @return Location of uniform
491 **/
getUniformLocation(const glw::GLchar * uniform_name) const492 GLint Utils::program::getUniformLocation(const glw::GLchar *uniform_name) const
493 {
494 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
495 GLint location = -1;
496
497 location = gl.getUniformLocation(m_program_object_id, uniform_name);
498 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation");
499
500 if (-1 == location)
501 {
502 m_context.getTestContext().getLog()
503 << tcu::TestLog::Message << "Uniform: " << uniform_name << " is not available" << tcu::TestLog::EndMessage;
504
505 TCU_FAIL("Uniform is not available");
506 }
507
508 return location;
509 }
510
511 /** Attach shaders and link program
512 *
513 **/
link() const514 void Utils::program::link() const
515 {
516 /* GL entry points */
517 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
518
519 /* Link status */
520 glw::GLint status = GL_FALSE;
521
522 /* Attach shaders */
523 if (0 != m_compute_shader_id)
524 {
525 gl.attachShader(m_program_object_id, m_compute_shader_id);
526 GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
527 }
528
529 if (0 != m_fragment_shader_id)
530 {
531 gl.attachShader(m_program_object_id, m_fragment_shader_id);
532 GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
533 }
534
535 if (0 != m_geometry_shader_id)
536 {
537 gl.attachShader(m_program_object_id, m_geometry_shader_id);
538 GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
539 }
540
541 if (0 != m_tesselation_control_shader_id)
542 {
543 gl.attachShader(m_program_object_id, m_tesselation_control_shader_id);
544 GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
545 }
546
547 if (0 != m_tesselation_evaluation_shader_id)
548 {
549 gl.attachShader(m_program_object_id, m_tesselation_evaluation_shader_id);
550 GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
551 }
552
553 if (0 != m_vertex_shader_id)
554 {
555 gl.attachShader(m_program_object_id, m_vertex_shader_id);
556 GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
557 }
558
559 /* Link */
560 gl.linkProgram(m_program_object_id);
561 GLU_EXPECT_NO_ERROR(gl.getError(), "LinkProgram");
562
563 /* Get link status */
564 gl.getProgramiv(m_program_object_id, GL_LINK_STATUS, &status);
565 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
566
567 /* Log link error */
568 if (GL_TRUE != status)
569 {
570 glw::GLint length = 0;
571 std::vector<glw::GLchar> message;
572
573 /* Get error log length */
574 gl.getProgramiv(m_program_object_id, GL_INFO_LOG_LENGTH, &length);
575 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
576
577 message.resize(length);
578
579 /* Get error log */
580 gl.getProgramInfoLog(m_program_object_id, length, 0, &message[0]);
581 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramInfoLog");
582
583 /* Log */
584 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Failed to link program:\n"
585 << &message[0] << tcu::TestLog::EndMessage;
586
587 TCU_FAIL("Failed to link program");
588 }
589 }
590
591 /** Delete program object and all attached shaders
592 *
593 **/
remove()594 void Utils::program::remove()
595 {
596 /* GL entry points */
597 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
598
599 /* Make sure program object is no longer used by GL */
600 gl.useProgram(0);
601
602 /* Clean program object */
603 if (0 != m_program_object_id)
604 {
605 gl.deleteProgram(m_program_object_id);
606 m_program_object_id = 0;
607 }
608
609 /* Clean shaders */
610 if (0 != m_compute_shader_id)
611 {
612 gl.deleteShader(m_compute_shader_id);
613 m_compute_shader_id = 0;
614 }
615
616 if (0 != m_fragment_shader_id)
617 {
618 gl.deleteShader(m_fragment_shader_id);
619 m_fragment_shader_id = 0;
620 }
621
622 if (0 != m_geometry_shader_id)
623 {
624 gl.deleteShader(m_geometry_shader_id);
625 m_geometry_shader_id = 0;
626 }
627
628 if (0 != m_tesselation_control_shader_id)
629 {
630 gl.deleteShader(m_tesselation_control_shader_id);
631 m_tesselation_control_shader_id = 0;
632 }
633
634 if (0 != m_tesselation_evaluation_shader_id)
635 {
636 gl.deleteShader(m_tesselation_evaluation_shader_id);
637 m_tesselation_evaluation_shader_id = 0;
638 }
639
640 if (0 != m_vertex_shader_id)
641 {
642 gl.deleteShader(m_vertex_shader_id);
643 m_vertex_shader_id = 0;
644 }
645 }
646
647 /** Execute UseProgram
648 *
649 **/
use() const650 void Utils::program::use() const
651 {
652 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
653
654 gl.useProgram(m_program_object_id);
655 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
656 }
657
658 /** Constructor.
659 *
660 * @param context CTS context.
661 **/
texture(deqp::Context & context)662 Utils::texture::texture(deqp::Context &context) : m_id(0), m_context(context)
663 {
664 /* Nothing to done here */
665 }
666
667 /** Destructor
668 *
669 **/
~texture()670 Utils::texture::~texture()
671 {
672 if (0 != m_id)
673 {
674 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
675
676 gl.deleteTextures(1, &m_id);
677 m_id = 0;
678 }
679 }
680
681 /** Bind texture to GL_TEXTURE_2D
682 *
683 **/
bind()684 void Utils::texture::bind()
685 {
686 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
687
688 gl.bindTexture(GL_TEXTURE_2D, m_id);
689 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
690 }
691
692 /** Create 2d texture
693 *
694 * @param width Width of texture
695 * @param height Height of texture
696 * @param internal_format Internal format of texture
697 **/
create(glw::GLuint width,glw::GLuint height,glw::GLenum internal_format)698 void Utils::texture::create(glw::GLuint width, glw::GLuint height, glw::GLenum internal_format)
699 {
700 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
701
702 gl.genTextures(1, &m_id);
703 GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures");
704
705 bind();
706
707 gl.texStorage2D(GL_TEXTURE_2D, 1 /* levels */, internal_format, width, height);
708 GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D");
709 }
710
711 /** Get contents of texture
712 *
713 * @param format Format of image
714 * @param type Type of image
715 * @param out_data Buffer for image
716 **/
get(glw::GLenum format,glw::GLenum type,glw::GLvoid * out_data)717 void Utils::texture::get(glw::GLenum format, glw::GLenum type, glw::GLvoid *out_data)
718 {
719 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
720
721 bind();
722
723 gl.getTexImage(GL_TEXTURE_2D, 0, format, type, out_data);
724 GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexImage");
725 }
726
727 /** Update contents of texture
728 *
729 * @param width Width of texture
730 * @param height Height of texture
731 * @param format Format of data
732 * @param type Type of data
733 * @param data Buffer with image
734 **/
update(glw::GLuint width,glw::GLuint height,glw::GLenum format,glw::GLenum type,glw::GLvoid * data)735 void Utils::texture::update(glw::GLuint width, glw::GLuint height, glw::GLenum format, glw::GLenum type,
736 glw::GLvoid *data)
737 {
738 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
739
740 bind();
741
742 gl.texSubImage2D(GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, width, height, format, type, data);
743 GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D");
744 }
745
746 /** Constructor.
747 *
748 * @param context CTS context.
749 **/
vertexArray(deqp::Context & context)750 Utils::vertexArray::vertexArray(deqp::Context &context) : m_id(0), m_context(context)
751 {
752 }
753
754 /** Destructor
755 *
756 **/
~vertexArray()757 Utils::vertexArray::~vertexArray()
758 {
759 if (0 != m_id)
760 {
761 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
762
763 gl.deleteVertexArrays(1, &m_id);
764
765 m_id = 0;
766 }
767 }
768
769 /** Execute BindVertexArray
770 *
771 **/
bind()772 void Utils::vertexArray::bind()
773 {
774 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
775
776 gl.bindVertexArray(m_id);
777 GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArray");
778 }
779
780 /** Execute GenVertexArrays
781 *
782 **/
generate()783 void Utils::vertexArray::generate()
784 {
785 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
786
787 gl.genVertexArrays(1, &m_id);
788 GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays");
789 }
790
791 /** Builds a program object consisting of up to 5 shader stages
792 * (vertex/tessellation control/tessellation evaluation/geometry/fragment).
793 * The shaders are attached to the program object, then compiled. Finally,
794 * the program object is linked.
795 *
796 * XFB can be optionally configured for the program object.
797 *
798 * Should an error be reported by GL implementation, a TestError
799 * exception will be thrown.
800 *
801 * @param gl OpenGL functions from the active rendering context.
802 * @param vs_body Body to use for the vertex shader. Can be an empty string.
803 * @param tc_body Body to use for the tessellation control shader. Can be
804 * an empty string.
805 * @param te_body Body to use for the tessellation evaluation shader. Can be
806 * an empty string.
807 * @param gs_body Body to use for the geometry shader. Can be an empty string.
808 * @param fs_body Body to use for the fragment shader. Can be an empty string.
809 * @param xfb_varyings An array of names of varyings to use for XFB. Can be NULL.
810 * @param n_xfb_varyings Amount of XFB varyings defined in @param xfb_varyings.Can be 0.
811 * @param out_vs_id Deref will be used to store GL id of a generated vertex shader.
812 * Can be NULL in which case no vertex shader will be used for the
813 * program object.
814 * @param out_tc_id Deref will be used to store GL id of a generated tess control shader.
815 * Can be NULL in which case no tess control shader will be used for the
816 * program object.
817 * @param out_te_id Deref will be used to store GL id of a generated tess evaluation shader.
818 * Can be NULL in which case no tess evaluation shader will be used for the
819 * program object.
820 * @param out_gs_id Deref will be used to store GL id of a generated geometry shader.
821 * Can be NULL in which case no geometry shader will be used for the
822 * program object.
823 * @param out_fs_id Deref will be used to store GL id of a generated fragment shader.
824 * Can be NULL in which case no fragment shader will be used for the
825 * program object.
826 * @param out_po_id Deref will be used to store GL id of a generated program object.
827 * Must not be NULL.
828 *
829 * @return true if the program was built successfully, false otherwise.
830 * */
buildProgram(const glw::Functions & gl,const std::string & vs_body,const std::string & tc_body,const std::string & te_body,const std::string & gs_body,const std::string & fs_body,const glw::GLchar ** xfb_varyings,const unsigned int & n_xfb_varyings,glw::GLuint * out_vs_id,glw::GLuint * out_tc_id,glw::GLuint * out_te_id,glw::GLuint * out_gs_id,glw::GLuint * out_fs_id,glw::GLuint * out_po_id)831 bool Utils::buildProgram(const glw::Functions &gl, const std::string &vs_body, const std::string &tc_body,
832 const std::string &te_body, const std::string &gs_body, const std::string &fs_body,
833 const glw::GLchar **xfb_varyings, const unsigned int &n_xfb_varyings, glw::GLuint *out_vs_id,
834 glw::GLuint *out_tc_id, glw::GLuint *out_te_id, glw::GLuint *out_gs_id, glw::GLuint *out_fs_id,
835 glw::GLuint *out_po_id)
836 {
837 bool result = false;
838
839 /* Link the program object */
840 glw::GLint link_status = GL_FALSE;
841
842 /* Create objects, set up shader bodies and attach all requested shaders to the program object */
843 *out_po_id = gl.createProgram();
844 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
845
846 if (out_vs_id != DE_NULL)
847 {
848 const char *vs_body_raw_ptr = vs_body.c_str();
849
850 *out_vs_id = gl.createShader(GL_VERTEX_SHADER);
851 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
852
853 gl.attachShader(*out_po_id, *out_vs_id);
854 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
855
856 gl.shaderSource(*out_vs_id, 1 /* count */, &vs_body_raw_ptr, DE_NULL /* length */);
857 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
858 }
859
860 if (out_tc_id != DE_NULL)
861 {
862 const char *tc_body_raw_ptr = tc_body.c_str();
863
864 *out_tc_id = gl.createShader(GL_TESS_CONTROL_SHADER);
865 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
866
867 gl.attachShader(*out_po_id, *out_tc_id);
868 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
869
870 gl.shaderSource(*out_tc_id, 1 /* count */, &tc_body_raw_ptr, DE_NULL /* length */);
871 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
872 }
873
874 if (out_te_id != DE_NULL)
875 {
876 const char *te_body_raw_ptr = te_body.c_str();
877
878 *out_te_id = gl.createShader(GL_TESS_EVALUATION_SHADER);
879 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
880
881 gl.attachShader(*out_po_id, *out_te_id);
882 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
883
884 gl.shaderSource(*out_te_id, 1 /* count */, &te_body_raw_ptr, DE_NULL /* length */);
885 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
886 }
887
888 if (out_gs_id != DE_NULL)
889 {
890 const char *gs_body_raw_ptr = gs_body.c_str();
891
892 *out_gs_id = gl.createShader(GL_GEOMETRY_SHADER);
893 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
894
895 gl.attachShader(*out_po_id, *out_gs_id);
896 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
897
898 gl.shaderSource(*out_gs_id, 1 /* count */, &gs_body_raw_ptr, DE_NULL /* length */);
899 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
900 }
901
902 if (out_fs_id != DE_NULL)
903 {
904 const char *fs_body_raw_ptr = fs_body.c_str();
905
906 *out_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
907 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
908
909 gl.attachShader(*out_po_id, *out_fs_id);
910 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
911
912 gl.shaderSource(*out_fs_id, 1 /* count */, &fs_body_raw_ptr, DE_NULL /* length */);
913 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
914 }
915
916 /* Compile all shaders */
917 const glw::GLuint so_ids[] = {(out_vs_id != DE_NULL) ? *out_vs_id : 0, (out_tc_id != DE_NULL) ? *out_tc_id : 0,
918 (out_te_id != DE_NULL) ? *out_te_id : 0, (out_gs_id != DE_NULL) ? *out_gs_id : 0,
919 (out_fs_id != DE_NULL) ? *out_fs_id : 0};
920 const unsigned int n_so_ids = sizeof(so_ids) / sizeof(so_ids[0]);
921
922 for (unsigned int n_so_id = 0; n_so_id < n_so_ids; ++n_so_id)
923 {
924 glw::GLuint so_id = so_ids[n_so_id];
925
926 if (so_id != 0)
927 {
928 glw::GLint compile_status = GL_FALSE;
929
930 gl.compileShader(so_id);
931 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
932
933 gl.getShaderiv(so_id, GL_COMPILE_STATUS, &compile_status);
934 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
935
936 if (compile_status != GL_TRUE)
937 {
938 goto end;
939 }
940 } /* if (so_id != 0) */
941 } /* for (all shader objects) */
942
943 /* Set up XFB */
944 if (xfb_varyings != NULL)
945 {
946 gl.transformFeedbackVaryings(*out_po_id, n_xfb_varyings, xfb_varyings, GL_INTERLEAVED_ATTRIBS);
947 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed.");
948 }
949
950 gl.linkProgram(*out_po_id);
951 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
952
953 gl.getProgramiv(*out_po_id, GL_LINK_STATUS, &link_status);
954 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
955
956 if (link_status != GL_TRUE)
957 {
958 goto end;
959 }
960
961 /* All done */
962 result = true;
963
964 end:
965 return result;
966 }
967
968 /** Retrieves base variable type for user-specified variable type
969 * (eg. float for vec4)
970 *
971 * @param variable_type Variable type to use for the query.
972 *
973 * @return As per description.
974 **/
getBaseVariableType(const _variable_type & variable_type)975 Utils::_variable_type Utils::getBaseVariableType(const _variable_type &variable_type)
976 {
977 _variable_type result = VARIABLE_TYPE_UNKNOWN;
978
979 switch (variable_type)
980 {
981 case VARIABLE_TYPE_BOOL:
982 case VARIABLE_TYPE_BVEC2:
983 case VARIABLE_TYPE_BVEC3:
984 case VARIABLE_TYPE_BVEC4:
985 {
986 result = VARIABLE_TYPE_BOOL;
987
988 break;
989 }
990
991 case VARIABLE_TYPE_DOUBLE:
992 case VARIABLE_TYPE_DVEC2:
993 case VARIABLE_TYPE_DVEC3:
994 case VARIABLE_TYPE_DVEC4:
995 {
996 result = VARIABLE_TYPE_DOUBLE;
997
998 break;
999 }
1000
1001 case VARIABLE_TYPE_FLOAT:
1002 case VARIABLE_TYPE_MAT2:
1003 case VARIABLE_TYPE_MAT2X3:
1004 case VARIABLE_TYPE_MAT2X4:
1005 case VARIABLE_TYPE_MAT3:
1006 case VARIABLE_TYPE_MAT3X2:
1007 case VARIABLE_TYPE_MAT3X4:
1008 case VARIABLE_TYPE_MAT4:
1009 case VARIABLE_TYPE_MAT4X2:
1010 case VARIABLE_TYPE_MAT4X3:
1011 case VARIABLE_TYPE_VEC2:
1012 case VARIABLE_TYPE_VEC3:
1013 case VARIABLE_TYPE_VEC4:
1014 {
1015 result = VARIABLE_TYPE_FLOAT;
1016
1017 break;
1018 }
1019
1020 case VARIABLE_TYPE_INT:
1021 case VARIABLE_TYPE_IVEC2:
1022 case VARIABLE_TYPE_IVEC3:
1023 case VARIABLE_TYPE_IVEC4:
1024 {
1025 result = VARIABLE_TYPE_INT;
1026
1027 break;
1028 }
1029
1030 case VARIABLE_TYPE_UINT:
1031 case VARIABLE_TYPE_UVEC2:
1032 case VARIABLE_TYPE_UVEC3:
1033 case VARIABLE_TYPE_UVEC4:
1034 {
1035 result = VARIABLE_TYPE_UINT;
1036
1037 break;
1038 }
1039
1040 default:
1041 {
1042 TCU_FAIL("Unrecognized variable type");
1043 }
1044 } /* switch (variable_type) */
1045
1046 return result;
1047 }
1048
1049 /** Retrieves size of a single component (in bytes) for user-specified
1050 * variable type.
1051 *
1052 * @param variable_type Variable type to use for the query.
1053 *
1054 * @return As per description.
1055 **/
getComponentSizeForVariableType(const _variable_type & variable_type)1056 unsigned int Utils::getComponentSizeForVariableType(const _variable_type &variable_type)
1057 {
1058 _variable_type base_variable_type = getBaseVariableType(variable_type);
1059 unsigned int result = 0;
1060
1061 switch (base_variable_type)
1062 {
1063 case VARIABLE_TYPE_BOOL:
1064 result = sizeof(bool);
1065 break;
1066 case VARIABLE_TYPE_DOUBLE:
1067 result = sizeof(double);
1068 break;
1069 case VARIABLE_TYPE_FLOAT:
1070 result = sizeof(float);
1071 break;
1072 case VARIABLE_TYPE_INT:
1073 result = sizeof(int);
1074 break;
1075 case VARIABLE_TYPE_UINT:
1076 result = sizeof(unsigned int);
1077 break;
1078
1079 default:
1080 {
1081 TCU_FAIL("Unrecognized base variable type");
1082 }
1083 } /* switch (variable_type) */
1084
1085 return result;
1086 }
1087
1088 /** Retrieves a GLenum value corresponding to internal shader stage
1089 * representation.
1090 *
1091 * @param shader_stage Shader stage to user for the query.
1092 *
1093 * @return Requested value or GL_NONE if the stage was not recognized.
1094 **/
getGLenumForShaderStage(const _shader_stage & shader_stage)1095 glw::GLenum Utils::getGLenumForShaderStage(const _shader_stage &shader_stage)
1096 {
1097 glw::GLenum result = GL_NONE;
1098
1099 switch (shader_stage)
1100 {
1101 case SHADER_STAGE_VERTEX:
1102 result = GL_VERTEX_SHADER;
1103 break;
1104 case SHADER_STAGE_TESSELLATION_CONTROL:
1105 result = GL_TESS_CONTROL_SHADER;
1106 break;
1107 case SHADER_STAGE_TESSELLATION_EVALUATION:
1108 result = GL_TESS_EVALUATION_SHADER;
1109 break;
1110 case SHADER_STAGE_GEOMETRY:
1111 result = GL_GEOMETRY_SHADER;
1112 break;
1113 case SHADER_STAGE_FRAGMENT:
1114 result = GL_FRAGMENT_SHADER;
1115 break;
1116
1117 default:
1118 {
1119 TCU_FAIL("Unrecognized shader stage requested");
1120 }
1121 } /* switch (shader_stage) */
1122
1123 return result;
1124 }
1125
1126 /** Retrieves number of components that user-specified variable type supports.
1127 *
1128 * @param variable_type GLSL variable type to use for the query.
1129 *
1130 * @return As per description.
1131 **/
getNumberOfComponentsForVariableType(const _variable_type & variable_type)1132 unsigned int Utils::getNumberOfComponentsForVariableType(const _variable_type &variable_type)
1133 {
1134 unsigned int result = 0;
1135
1136 switch (variable_type)
1137 {
1138 case VARIABLE_TYPE_BOOL:
1139 case VARIABLE_TYPE_DOUBLE:
1140 case VARIABLE_TYPE_FLOAT:
1141 case VARIABLE_TYPE_INT:
1142 case VARIABLE_TYPE_UINT:
1143 {
1144 result = 1;
1145
1146 break;
1147 }
1148
1149 case VARIABLE_TYPE_BVEC2:
1150 case VARIABLE_TYPE_DVEC2:
1151 case VARIABLE_TYPE_IVEC2:
1152 case VARIABLE_TYPE_UVEC2:
1153 case VARIABLE_TYPE_VEC2:
1154 {
1155 result = 2;
1156
1157 break;
1158 }
1159
1160 case VARIABLE_TYPE_BVEC3:
1161 case VARIABLE_TYPE_DVEC3:
1162 case VARIABLE_TYPE_IVEC3:
1163 case VARIABLE_TYPE_UVEC3:
1164 case VARIABLE_TYPE_VEC3:
1165 {
1166 result = 3;
1167
1168 break;
1169 }
1170
1171 case VARIABLE_TYPE_BVEC4:
1172 case VARIABLE_TYPE_DVEC4:
1173 case VARIABLE_TYPE_IVEC4:
1174 case VARIABLE_TYPE_MAT2:
1175 case VARIABLE_TYPE_UVEC4:
1176 case VARIABLE_TYPE_VEC4:
1177 {
1178 result = 4;
1179
1180 break;
1181 }
1182
1183 case VARIABLE_TYPE_MAT2X3:
1184 case VARIABLE_TYPE_MAT3X2:
1185 {
1186 result = 6;
1187
1188 break;
1189 }
1190
1191 case VARIABLE_TYPE_MAT2X4:
1192 case VARIABLE_TYPE_MAT4X2:
1193 {
1194 result = 8;
1195
1196 break;
1197 }
1198
1199 case VARIABLE_TYPE_MAT3:
1200 {
1201 result = 9;
1202
1203 break;
1204 }
1205
1206 case VARIABLE_TYPE_MAT3X4:
1207 case VARIABLE_TYPE_MAT4X3:
1208 {
1209 result = 12;
1210
1211 break;
1212 }
1213
1214 case VARIABLE_TYPE_MAT4:
1215 {
1216 result = 16;
1217
1218 break;
1219 }
1220
1221 default:
1222 break;
1223 } /* switch (variable_type) */
1224
1225 return result;
1226 }
1227
1228 /** Retrieves a literal defining user-specified shader stage enum.
1229 *
1230 * @param shader_stage Shader stage to use for the query.
1231 *
1232 * @return Requested string or "?" if the stage was not recognized.
1233 **/
getShaderStageString(const _shader_stage & shader_stage)1234 std::string Utils::getShaderStageString(const _shader_stage &shader_stage)
1235 {
1236 std::string result = "?";
1237
1238 switch (shader_stage)
1239 {
1240 case SHADER_STAGE_FRAGMENT:
1241 result = "Fragment Shader";
1242 break;
1243 case SHADER_STAGE_GEOMETRY:
1244 result = "Geometry Shader";
1245 break;
1246 case SHADER_STAGE_TESSELLATION_CONTROL:
1247 result = "Tessellation Control Shader";
1248 break;
1249 case SHADER_STAGE_TESSELLATION_EVALUATION:
1250 result = "Tessellation Evaluation Shader";
1251 break;
1252 case SHADER_STAGE_VERTEX:
1253 result = "Vertex Shader";
1254 break;
1255
1256 default:
1257 {
1258 TCU_FAIL("Unrecognized shader stage");
1259 }
1260 } /* switch (shader_stage) */
1261
1262 return result;
1263 }
1264
1265 /** Retrieves a literal defining user-specified shader stage enum.
1266 *
1267 * @param shader_stage_glenum Shader stage to use for the query.
1268 *
1269 * @return Requested string or "?" if the stage was not recognized.
1270 **/
getShaderStageStringFromGLEnum(const glw::GLenum shader_stage_glenum)1271 std::string Utils::getShaderStageStringFromGLEnum(const glw::GLenum shader_stage_glenum)
1272 {
1273 std::string result = "?";
1274
1275 switch (shader_stage_glenum)
1276 {
1277 case GL_FRAGMENT_SHADER:
1278 result = "Fragment Shader";
1279 break;
1280 case GL_GEOMETRY_SHADER:
1281 result = "Geometry Shader";
1282 break;
1283 case GL_TESS_CONTROL_SHADER:
1284 result = "Tessellation Control Shader";
1285 break;
1286 case GL_TESS_EVALUATION_SHADER:
1287 result = "Tessellation Evaluation Shader";
1288 break;
1289 case GL_VERTEX_SHADER:
1290 result = "Vertex Shader";
1291 break;
1292
1293 default:
1294 {
1295 TCU_FAIL("Unrecognized shader string");
1296 }
1297 } /* switch (shader_stage_glenum) */
1298
1299 return result;
1300 }
1301
1302 /** Returns string that represents program interface name
1303 *
1304 * @param program_interface Program interface
1305 *
1306 * @return String representation of known program interface
1307 **/
programInterfaceToStr(glw::GLenum program_interface)1308 const GLchar *Utils::programInterfaceToStr(glw::GLenum program_interface)
1309 {
1310 const GLchar *string = "Unknown program interface";
1311
1312 switch (program_interface)
1313 {
1314 case GL_VERTEX_SUBROUTINE:
1315 string = "GL_VERTEX_SUBROUTINE";
1316 break;
1317 case GL_VERTEX_SUBROUTINE_UNIFORM:
1318 string = "GL_VERTEX_SUBROUTINE_UNIFORM";
1319 break;
1320 default:
1321 TCU_FAIL("Not implemented");
1322 }
1323
1324 return string;
1325 }
1326
1327 /** Returns string that represents pname's name
1328 *
1329 * @param pname pname
1330 *
1331 * @return String representation of known pnames
1332 **/
pnameToStr(glw::GLenum pname)1333 const GLchar *Utils::pnameToStr(glw::GLenum pname)
1334 {
1335 const GLchar *string = "Unknown pname";
1336
1337 switch (pname)
1338 {
1339 case GL_ACTIVE_SUBROUTINE_UNIFORMS:
1340 string = "GL_ACTIVE_SUBROUTINE_UNIFORMS";
1341 break;
1342 case GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS:
1343 string = "GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS";
1344 break;
1345 case GL_ACTIVE_SUBROUTINES:
1346 string = "GL_ACTIVE_SUBROUTINES";
1347 break;
1348 case GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH:
1349 string = "GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH";
1350 break;
1351 case GL_ACTIVE_SUBROUTINE_MAX_LENGTH:
1352 string = "GL_ACTIVE_SUBROUTINE_MAX_LENGTH";
1353 break;
1354 case GL_NUM_COMPATIBLE_SUBROUTINES:
1355 string = "GL_NUM_COMPATIBLE_SUBROUTINES";
1356 break;
1357 case GL_UNIFORM_SIZE:
1358 string = "GL_UNIFORM_SIZE";
1359 break;
1360 case GL_COMPATIBLE_SUBROUTINES:
1361 string = "GL_COMPATIBLE_SUBROUTINES";
1362 break;
1363 case GL_UNIFORM_NAME_LENGTH:
1364 string = "GL_UNIFORM_NAME_LENGTH";
1365 break;
1366 case GL_ACTIVE_RESOURCES:
1367 string = "GL_ACTIVE_RESOURCES";
1368 break;
1369 case GL_MAX_NAME_LENGTH:
1370 string = "GL_MAX_NAME_LENGTH";
1371 break;
1372 case GL_MAX_NUM_COMPATIBLE_SUBROUTINES:
1373 string = "GL_MAX_NUM_COMPATIBLE_SUBROUTINES";
1374 break;
1375 case GL_NAME_LENGTH:
1376 string = "GL_NAME_LENGTH";
1377 break;
1378 case GL_ARRAY_SIZE:
1379 string = "GL_ARRAY_SIZE";
1380 break;
1381 case GL_LOCATION:
1382 string = "GL_LOCATION";
1383 break;
1384 default:
1385 TCU_FAIL("Not implemented");
1386 }
1387
1388 return string;
1389 }
1390
compare(const glw::GLfloat & left,const glw::GLfloat & right)1391 bool Utils::compare(const glw::GLfloat &left, const glw::GLfloat &right)
1392 {
1393 static const glw::GLfloat m_epsilon = 0.00001f;
1394
1395 if (m_epsilon < std::abs(right - left))
1396 {
1397 return false;
1398 }
1399 else
1400 {
1401 return true;
1402 }
1403 }
1404
1405 /** Returns a variable type enum corresponding to user-specified base variable type
1406 * and the number of components it should support.
1407 *
1408 * @param base_variable_type Base variable type to use for the query.
1409 * @param n_components Number of components to consider for the query.
1410 *
1411 * @return As per description.
1412 **/
getVariableTypeFromProperties(const _variable_type & base_variable_type,const unsigned int & n_components)1413 Utils::_variable_type Utils::getVariableTypeFromProperties(const _variable_type &base_variable_type,
1414 const unsigned int &n_components)
1415 {
1416 _variable_type result = VARIABLE_TYPE_UNKNOWN;
1417
1418 switch (base_variable_type)
1419 {
1420 case VARIABLE_TYPE_BOOL:
1421 {
1422 switch (n_components)
1423 {
1424 case 1:
1425 result = VARIABLE_TYPE_BOOL;
1426 break;
1427 case 2:
1428 result = VARIABLE_TYPE_BVEC2;
1429 break;
1430 case 3:
1431 result = VARIABLE_TYPE_BVEC3;
1432 break;
1433 case 4:
1434 result = VARIABLE_TYPE_BVEC4;
1435 break;
1436
1437 default:
1438 {
1439 TCU_FAIL("Unsupported number of components requested");
1440 }
1441 } /* switch (n_components) */
1442
1443 break;
1444 }
1445
1446 case VARIABLE_TYPE_DOUBLE:
1447 {
1448 switch (n_components)
1449 {
1450 case 1:
1451 result = VARIABLE_TYPE_DOUBLE;
1452 break;
1453 case 2:
1454 result = VARIABLE_TYPE_DVEC2;
1455 break;
1456 case 3:
1457 result = VARIABLE_TYPE_DVEC3;
1458 break;
1459 case 4:
1460 result = VARIABLE_TYPE_DVEC4;
1461 break;
1462
1463 default:
1464 {
1465 TCU_FAIL("Unsupported number of components requested");
1466 }
1467 } /* switch (n_components) */
1468
1469 break;
1470 }
1471
1472 case VARIABLE_TYPE_FLOAT:
1473 {
1474 switch (n_components)
1475 {
1476 case 1:
1477 result = VARIABLE_TYPE_FLOAT;
1478 break;
1479 case 2:
1480 result = VARIABLE_TYPE_VEC2;
1481 break;
1482 case 3:
1483 result = VARIABLE_TYPE_VEC3;
1484 break;
1485 case 4:
1486 result = VARIABLE_TYPE_VEC4;
1487 break;
1488
1489 default:
1490 {
1491 TCU_FAIL("Unsupported number of components requested");
1492 }
1493 } /* switch (n_components) */
1494
1495 break;
1496 }
1497
1498 case VARIABLE_TYPE_INT:
1499 {
1500 switch (n_components)
1501 {
1502 case 1:
1503 result = VARIABLE_TYPE_INT;
1504 break;
1505 case 2:
1506 result = VARIABLE_TYPE_IVEC2;
1507 break;
1508 case 3:
1509 result = VARIABLE_TYPE_IVEC3;
1510 break;
1511 case 4:
1512 result = VARIABLE_TYPE_IVEC4;
1513 break;
1514
1515 default:
1516 {
1517 TCU_FAIL("Unsupported number of components requested");
1518 }
1519 } /* switch (n_components) */
1520
1521 break;
1522 }
1523
1524 case VARIABLE_TYPE_UINT:
1525 {
1526 switch (n_components)
1527 {
1528 case 1:
1529 result = VARIABLE_TYPE_UINT;
1530 break;
1531 case 2:
1532 result = VARIABLE_TYPE_UVEC2;
1533 break;
1534 case 3:
1535 result = VARIABLE_TYPE_UVEC3;
1536 break;
1537 case 4:
1538 result = VARIABLE_TYPE_UVEC4;
1539 break;
1540
1541 default:
1542 {
1543 TCU_FAIL("Unsupported number of components requested");
1544 }
1545 } /* switch (n_components) */
1546
1547 break;
1548 }
1549
1550 default:
1551 {
1552 TCU_FAIL("Unrecognized base variable type");
1553 }
1554 } /* switch (base_variable_type) */
1555
1556 return result;
1557 }
1558
1559 /** Returns a GLSL literal corresponding to user-specified variable type.
1560 *
1561 * @param variable_type Variable type to use for the query.
1562 *
1563 * @return As per description or [?] if @param variable_type was not
1564 * recognized.
1565 **/
getVariableTypeGLSLString(const _variable_type & variable_type)1566 std::string Utils::getVariableTypeGLSLString(const _variable_type &variable_type)
1567 {
1568 std::string result = "[?]";
1569
1570 switch (variable_type)
1571 {
1572 case VARIABLE_TYPE_BOOL:
1573 result = "bool";
1574 break;
1575 case VARIABLE_TYPE_BVEC2:
1576 result = "bvec2";
1577 break;
1578 case VARIABLE_TYPE_BVEC3:
1579 result = "bvec3";
1580 break;
1581 case VARIABLE_TYPE_BVEC4:
1582 result = "bvec4";
1583 break;
1584 case VARIABLE_TYPE_DOUBLE:
1585 result = "double";
1586 break;
1587 case VARIABLE_TYPE_DVEC2:
1588 result = "dvec2";
1589 break;
1590 case VARIABLE_TYPE_DVEC3:
1591 result = "dvec3";
1592 break;
1593 case VARIABLE_TYPE_DVEC4:
1594 result = "dvec4";
1595 break;
1596 case VARIABLE_TYPE_FLOAT:
1597 result = "float";
1598 break;
1599 case VARIABLE_TYPE_INT:
1600 result = "int";
1601 break;
1602 case VARIABLE_TYPE_IVEC2:
1603 result = "ivec2";
1604 break;
1605 case VARIABLE_TYPE_IVEC3:
1606 result = "ivec3";
1607 break;
1608 case VARIABLE_TYPE_IVEC4:
1609 result = "ivec4";
1610 break;
1611 case VARIABLE_TYPE_MAT2:
1612 result = "mat2";
1613 break;
1614 case VARIABLE_TYPE_MAT2X3:
1615 result = "mat2x3";
1616 break;
1617 case VARIABLE_TYPE_MAT2X4:
1618 result = "mat2x4";
1619 break;
1620 case VARIABLE_TYPE_MAT3:
1621 result = "mat3";
1622 break;
1623 case VARIABLE_TYPE_MAT3X2:
1624 result = "mat3x2";
1625 break;
1626 case VARIABLE_TYPE_MAT3X4:
1627 result = "mat3x4";
1628 break;
1629 case VARIABLE_TYPE_MAT4:
1630 result = "mat4";
1631 break;
1632 case VARIABLE_TYPE_MAT4X2:
1633 result = "mat4x2";
1634 break;
1635 case VARIABLE_TYPE_MAT4X3:
1636 result = "mat4x3";
1637 break;
1638 case VARIABLE_TYPE_UINT:
1639 result = "uint";
1640 break;
1641 case VARIABLE_TYPE_UVEC2:
1642 result = "uvec2";
1643 break;
1644 case VARIABLE_TYPE_UVEC3:
1645 result = "uvec3";
1646 break;
1647 case VARIABLE_TYPE_UVEC4:
1648 result = "uvec4";
1649 break;
1650 case VARIABLE_TYPE_VEC2:
1651 result = "vec2";
1652 break;
1653 case VARIABLE_TYPE_VEC3:
1654 result = "vec3";
1655 break;
1656 case VARIABLE_TYPE_VEC4:
1657 result = "vec4";
1658 break;
1659
1660 default:
1661 {
1662 TCU_FAIL("Unrecognized variable type");
1663 }
1664 } /* switch (variable_type) */
1665
1666 return result;
1667 }
1668
1669 /** Constructor.
1670 *
1671 * @param context Rendering context.
1672 *
1673 **/
APITest1(deqp::Context & context)1674 APITest1::APITest1(deqp::Context &context)
1675 : TestCase(context, "min_maxes",
1676 "Verifies the implementation returns valid GL_MAX_SUBROUTINE* pnames "
1677 "which meet the minimum maximum requirements enforced by the spec.")
1678 , m_has_test_passed(true)
1679 {
1680 /* Left blank intentionally */
1681 }
1682
1683 /** Executes test iteration.
1684 *
1685 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
1686 */
iterate()1687 tcu::TestNode::IterateResult APITest1::iterate()
1688 {
1689 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1690
1691 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
1692 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
1693 {
1694 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
1695 }
1696
1697 /* Iterate over all pnames */
1698 const struct
1699 {
1700 glw::GLenum pname;
1701 const char *pname_string;
1702 glw::GLint min_value;
1703 } pnames[] = {{GL_MAX_SUBROUTINES, "GL_MAX_SUBROUTINES", 256},
1704 {GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS, "GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS", 1024}};
1705 const unsigned int n_pnames = sizeof(pnames) / sizeof(pnames[0]);
1706
1707 for (unsigned int n_pname = 0; n_pname < n_pnames; ++n_pname)
1708 {
1709 glw::GLboolean bool_value = GL_FALSE;
1710 glw::GLdouble double_value = 0.0;
1711 glw::GLfloat float_value = 0.0f;
1712 glw::GLint int_value = 0;
1713 glw::GLint64 int64_value = 0;
1714 const glw::GLint min_value = pnames[n_pname].min_value;
1715 const glw::GLenum &pname = pnames[n_pname].pname;
1716 const char *pname_string = pnames[n_pname].pname_string;
1717
1718 /* Retrieve the pname values */
1719 gl.getBooleanv(pname, &bool_value);
1720 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetBooleanv() call failed.");
1721
1722 gl.getDoublev(pname, &double_value);
1723 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetDoublev() call failed.");
1724
1725 gl.getFloatv(pname, &float_value);
1726 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv() call failed.");
1727
1728 gl.getIntegerv(pname, &int_value);
1729 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed.");
1730
1731 gl.getInteger64v(pname, &int64_value);
1732 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInteger64v() call failed.");
1733
1734 /* Make sure the value reported meets the min max requirement */
1735 if (int_value < min_value)
1736 {
1737 m_testCtx.getLog() << tcu::TestLog::Message << "GL implementation reports a value of [" << int_value
1738 << "]"
1739 " for property ["
1740 << pname_string
1741 << "]"
1742 ", whereas the min max for the property is ["
1743 << min_value << "]." << tcu::TestLog::EndMessage;
1744
1745 m_has_test_passed = false;
1746 }
1747
1748 /* Verify the other getters reported valid values */
1749 const float epsilon = 1e-5f;
1750
1751 if (((int_value == 0) && (bool_value == GL_TRUE)) || ((int_value != 0) && (bool_value != GL_TRUE)))
1752 {
1753 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid boolean value [" << bool_value
1754 << "]"
1755 " reported for property ["
1756 << pname_string
1757 << "]"
1758 " (int value:["
1759 << int_value << "])" << tcu::TestLog::EndMessage;
1760
1761 m_has_test_passed = false;
1762 }
1763
1764 if (de::abs(double_value - (double)int_value) > epsilon)
1765 {
1766 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid double value [" << double_value
1767 << "]"
1768 " reported for property ["
1769 << pname_string
1770 << "]"
1771 " (int value:["
1772 << int_value << "])" << tcu::TestLog::EndMessage;
1773
1774 m_has_test_passed = false;
1775 }
1776
1777 if (de::abs(float_value - (float)int_value) > epsilon)
1778 {
1779 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid float value [" << float_value
1780 << "]"
1781 " reported for property ["
1782 << pname_string
1783 << "]"
1784 " (int value:["
1785 << int_value << "])" << tcu::TestLog::EndMessage;
1786
1787 m_has_test_passed = false;
1788 }
1789
1790 if (int64_value != int_value)
1791 {
1792 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid 64-bit integer value [" << float_value
1793 << "]"
1794 " reported for property ["
1795 << pname_string
1796 << "]"
1797 " (int value:["
1798 << int_value << "])" << tcu::TestLog::EndMessage;
1799
1800 m_has_test_passed = false;
1801 }
1802 } /* for (all pnames) */
1803
1804 if (m_has_test_passed)
1805 {
1806 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1807 }
1808 else
1809 {
1810 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1811 }
1812
1813 return STOP;
1814 }
1815
1816 /** Constructor.
1817 *
1818 * @param context Rendering context.
1819 *
1820 **/
APITest2(deqp::Context & context)1821 APITest2::APITest2(deqp::Context &context)
1822 : TestCase(context, "name_getters",
1823 "Verifies glGetActiveSubroutineName() and glGetActiveSubroutineUniformName() "
1824 "functions work correctly.")
1825 , m_buffer(DE_NULL)
1826 , m_has_test_passed(true)
1827 , m_po_id(0)
1828 , m_subroutine_name1("subroutine1")
1829 , m_subroutine_name2("subroutine2")
1830 , m_subroutine_uniform_name("data_provider")
1831 , m_vs_id(0)
1832 {
1833 /* Left blank intentionally */
1834 }
1835
1836 /** Destroys all ES objects that may have been created during test initialization,
1837 * as well as releases any buffers that may have been allocated during the process.
1838 */
deinit()1839 void APITest2::deinit()
1840 {
1841 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1842
1843 if (m_buffer != DE_NULL)
1844 {
1845 delete[] m_buffer;
1846
1847 m_buffer = DE_NULL;
1848 }
1849
1850 if (m_po_id != 0)
1851 {
1852 gl.deleteProgram(m_po_id);
1853
1854 m_po_id = 0;
1855 }
1856
1857 if (m_vs_id != 0)
1858 {
1859 gl.deleteShader(m_vs_id);
1860
1861 m_vs_id = 0;
1862 }
1863 }
1864
1865 /** Returns body of a vertex shader that should be used for the test.
1866 *
1867 * @return As per description.
1868 **/
getVertexShaderBody()1869 std::string APITest2::getVertexShaderBody()
1870 {
1871 return "#version 400\n"
1872 "\n"
1873 "#extension GL_ARB_shader_subroutine : require\n"
1874 "\n"
1875 "subroutine int ExampleSubroutineType(int example_argument);\n"
1876 "\n"
1877 "subroutine(ExampleSubroutineType) int subroutine1(int example_argument)\n"
1878 "{\n"
1879 " return 1;\n"
1880 "}\n"
1881 "\n"
1882 "subroutine(ExampleSubroutineType) int subroutine2(int example_argument)\n"
1883 "{\n"
1884 " return 2;\n"
1885 "}\n"
1886 "\n"
1887 "subroutine uniform ExampleSubroutineType data_provider;\n"
1888 "\n"
1889 "void main()\n"
1890 "{\n"
1891 " gl_Position = vec4(float(data_provider(0)), vec3(1) );\n"
1892 "}\n";
1893 }
1894
1895 /** Initializes all ES objects required to run the test. */
initTest()1896 void APITest2::initTest()
1897 {
1898 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1899
1900 /* Generate program & shader objects */
1901 m_po_id = gl.createProgram();
1902 m_vs_id = gl.createShader(GL_VERTEX_SHADER);
1903
1904 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() or glCreateShader() call(s) failed.");
1905
1906 /* Attach the shader to the program object */
1907 gl.attachShader(m_po_id, m_vs_id);
1908 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
1909
1910 /* Compile the shader */
1911 glw::GLint compile_status = GL_FALSE;
1912 std::string vs_body = getVertexShaderBody();
1913 const char *vs_body_raw_ptr = vs_body.c_str();
1914
1915 gl.shaderSource(m_vs_id, 1 /* count */, &vs_body_raw_ptr, DE_NULL /* length */);
1916 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
1917
1918 gl.compileShader(m_vs_id);
1919 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
1920
1921 gl.getShaderiv(m_vs_id, GL_COMPILE_STATUS, &compile_status);
1922 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
1923
1924 if (compile_status != GL_TRUE)
1925 {
1926 TCU_FAIL("Shader compilation failed.");
1927 }
1928
1929 /* Try to link the program object */
1930 glw::GLint link_status = GL_FALSE;
1931
1932 gl.linkProgram(m_po_id);
1933 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
1934
1935 gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
1936 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
1937
1938 if (link_status != GL_TRUE)
1939 {
1940 TCU_FAIL("Program linking failed.");
1941 }
1942
1943 /* Perform a few quick checks */
1944 glw::GLint n_active_subroutines = 0;
1945 glw::GLint n_active_subroutine_uniforms = 0;
1946
1947 gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINES, &n_active_subroutines);
1948 gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORMS, &n_active_subroutine_uniforms);
1949 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramStageiv() call failed.");
1950
1951 if (n_active_subroutines != 2 /* subroutines declared in vertex shader */)
1952 {
1953 m_testCtx.getLog() << tcu::TestLog::Message
1954 << "Invalid amount of active subroutines reported; expected: 2,"
1955 " reported:"
1956 << n_active_subroutines << tcu::TestLog::EndMessage;
1957
1958 TCU_FAIL("Invalid GL_ACTIVE_SUBROUTINES property value.");
1959 }
1960
1961 if (n_active_subroutine_uniforms != 1)
1962 {
1963 m_testCtx.getLog() << tcu::TestLog::Message
1964 << "Invalid amount of active subroutine uniforms reported: expected: 1,"
1965 " reported: "
1966 << n_active_subroutine_uniforms << tcu::TestLog::EndMessage;
1967
1968 TCU_FAIL("Invalid GL_ACTIVE_SUBROUTINE_UNIFORMS property value.");
1969 }
1970 }
1971
1972 /** Executes test iteration.
1973 *
1974 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
1975 */
iterate()1976 tcu::TestNode::IterateResult APITest2::iterate()
1977 {
1978 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
1979 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
1980 {
1981 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
1982 }
1983
1984 /* Initialize a test program object */
1985 initTest();
1986
1987 /* Verify glGetActiveSubroutineName() works correctly */
1988 verifyGLGetActiveSubroutineNameFunctionality();
1989
1990 /* Verify glGetActiveSubroutineUniformName() works correctly */
1991 verifyGLGetActiveSubroutineUniformNameFunctionality();
1992
1993 /* Done */
1994 if (m_has_test_passed)
1995 {
1996 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1997 }
1998 else
1999 {
2000 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2001 }
2002
2003 return STOP;
2004 }
2005
2006 /** Verifies glGetActiveSubroutineName() behaves as per GL_ARB_shader_subroutine
2007 * specification.
2008 **/
verifyGLGetActiveSubroutineNameFunctionality()2009 void APITest2::verifyGLGetActiveSubroutineNameFunctionality()
2010 {
2011 GLsizei expected_length1 = (GLsizei)strlen(m_subroutine_name1) + 1;
2012 GLsizei expected_length2 = (GLsizei)strlen(m_subroutine_name1) + 1;
2013 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2014 GLsizei reported_length = 0;
2015
2016 gl.getActiveSubroutineName(m_po_id, GL_VERTEX_SHADER, 0, /* index */
2017 0, /* bufsize */
2018 DE_NULL, /* length */
2019 DE_NULL); /* name */
2020 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineName() call failed.");
2021
2022 gl.getProgramInterfaceiv(m_po_id, GL_VERTEX_SUBROUTINE, GL_MAX_NAME_LENGTH, &reported_length);
2023 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineName() call failed.");
2024
2025 if ((reported_length != expected_length1) && (reported_length != expected_length2))
2026 {
2027 m_testCtx.getLog() << tcu::TestLog::Message
2028 << "Invalid active subroutine name length reported:" << reported_length
2029 << ", instead of: " << expected_length1 << " or " << expected_length2
2030 << tcu::TestLog::EndMessage;
2031
2032 TCU_FAIL("Incorrect length of active subroutine name");
2033 }
2034
2035 m_buffer = new glw::GLchar[reported_length];
2036
2037 memset(m_buffer, 0, reported_length);
2038
2039 gl.getActiveSubroutineName(m_po_id, GL_VERTEX_SHADER, 0, reported_length, DE_NULL, /* length */
2040 m_buffer);
2041 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineName() call failed.");
2042
2043 if (strcmp(m_buffer, m_subroutine_name1) != 0 && strcmp(m_buffer, m_subroutine_name2) != 0)
2044 {
2045 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid active subroutine name reported:[" << m_buffer
2046 << "]"
2047 " instead of:["
2048 << m_subroutine_name1
2049 << "]"
2050 " or:["
2051 << m_subroutine_name2 << "]." << tcu::TestLog::EndMessage;
2052
2053 TCU_FAIL("Invalid active subroutine name reported.");
2054 }
2055
2056 delete[] m_buffer;
2057 m_buffer = DE_NULL;
2058 }
2059
2060 /** Verifies glGetActiveSubroutineUniformName() behaves as per GL_ARB_shader_subroutine
2061 * specification.
2062 **/
verifyGLGetActiveSubroutineUniformNameFunctionality()2063 void APITest2::verifyGLGetActiveSubroutineUniformNameFunctionality()
2064 {
2065 GLsizei expected_length = (GLsizei)strlen(m_subroutine_uniform_name);
2066 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2067 GLsizei reported_length = 0;
2068
2069 gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, 0, /* index */
2070 0, /* bufsize */
2071 DE_NULL, /* length */
2072 DE_NULL); /* name */
2073 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineUniformName() call failed.");
2074
2075 gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, 0, /* index */
2076 0, /* bufsize */
2077 &reported_length, DE_NULL); /* name */
2078 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineUniformName() call failed.");
2079
2080 // reported_length is the actual number of characters written into <name>
2081 // If <bufSize> is 0, reported_length should be 0
2082 if (reported_length != 0)
2083 {
2084 m_testCtx.getLog() << tcu::TestLog::Message
2085 << "Invalid active subroutine uniform name length reported:" << reported_length
2086 << ", instead of: " << 0 << tcu::TestLog::EndMessage;
2087
2088 TCU_FAIL("Incorrect length of active subroutine uniform name");
2089 }
2090
2091 m_buffer = new glw::GLchar[expected_length + 1];
2092
2093 memset(m_buffer, 0, expected_length + 1);
2094
2095 gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, 0, expected_length + 1, &reported_length, m_buffer);
2096 GLU_EXPECT_NO_ERROR(gl.getError(), "getActiveSubroutineUniformName() call failed.");
2097
2098 if (reported_length != expected_length)
2099 {
2100 m_testCtx.getLog() << tcu::TestLog::Message
2101 << "Invalid active subroutine uniform name length reported:" << reported_length
2102 << ", instead of: " << expected_length << tcu::TestLog::EndMessage;
2103
2104 TCU_FAIL("Incorrect length of active subroutine uniform name");
2105 }
2106
2107 if (strcmp(m_buffer, m_subroutine_uniform_name) != 0)
2108 {
2109 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid active subroutine uniform name reported:[" << m_buffer
2110 << "]"
2111 " instead of:["
2112 << m_subroutine_uniform_name << "]" << tcu::TestLog::EndMessage;
2113
2114 TCU_FAIL("Invalid active subroutine uniform name reported.");
2115 }
2116
2117 delete[] m_buffer;
2118 m_buffer = DE_NULL;
2119 }
2120
2121 /** Constructor.
2122 *
2123 * @param context Rendering context.
2124 *
2125 **/
FunctionalTest1_2(deqp::Context & context)2126 FunctionalTest1_2::FunctionalTest1_2(deqp::Context &context)
2127 : TestCase(context, "two_subroutines_single_subroutine_uniform",
2128 "Verifies the subroutines work correctly in a vertex shader for"
2129 " bool/float/int/uint/double/*vec*/*mat* argument and return types")
2130 , m_has_test_passed(true)
2131 , m_po_id(0)
2132 , m_po_getter0_subroutine_index(GL_INVALID_INDEX)
2133 , m_po_getter1_subroutine_index(GL_INVALID_INDEX)
2134 , m_po_subroutine_uniform_index(-1)
2135 , m_xfb_bo_id(0)
2136 , m_vao_id(0)
2137 , m_vs_id(0)
2138 {
2139 /* Left blank intentionally */
2140 }
2141
2142 /** Destroys all ES objects that may have been created during test initialization,
2143 * as well as releases any buffers that may have been allocated during the process.
2144 */
deinit()2145 void FunctionalTest1_2::deinit()
2146 {
2147 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2148
2149 deinitTestIteration();
2150
2151 if (m_xfb_bo_id != 0)
2152 {
2153 gl.deleteBuffers(1, &m_xfb_bo_id);
2154
2155 m_xfb_bo_id = 0;
2156 }
2157
2158 if (m_vao_id != 0)
2159 {
2160 gl.deleteVertexArrays(1, &m_vao_id);
2161
2162 m_vao_id = 0;
2163 }
2164 }
2165
2166 /** Deinitializes GL objects that are iteration-specific */
deinitTestIteration()2167 void FunctionalTest1_2::deinitTestIteration()
2168 {
2169 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2170
2171 if (m_po_id != 0)
2172 {
2173 gl.deleteProgram(m_po_id);
2174
2175 m_po_id = 0;
2176 }
2177
2178 if (m_vs_id != 0)
2179 {
2180 gl.deleteShader(m_vs_id);
2181
2182 m_vs_id = 0;
2183 }
2184 }
2185
2186 /** Executes a single test iteration using user-specified test case propertiesz.
2187 *
2188 * @param test-case Test case descriptor.
2189 *
2190 * @return true if the test iteration passed, false otherwise.
2191 **/
executeTestIteration(const _test_case & test_case)2192 bool FunctionalTest1_2::executeTestIteration(const _test_case &test_case)
2193 {
2194 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2195 bool result = true;
2196
2197 /* Build the test program */
2198 std::string empty_body;
2199 std::string vs_body = getVertexShaderBody(test_case.variable_type, test_case.array_size);
2200 const glw::GLchar *xfb_varyings[] = {"result"};
2201 const unsigned int n_xfb_varyings = sizeof(xfb_varyings) / sizeof(xfb_varyings[0]);
2202
2203 if (!Utils::buildProgram(gl, vs_body, empty_body, empty_body, empty_body, empty_body, xfb_varyings, n_xfb_varyings,
2204 &m_vs_id, NULL, /* out_tc_id */
2205 NULL, /* out_te_id */
2206 NULL, /* out_gs_id */
2207 NULL, &m_po_id))
2208 {
2209 TCU_FAIL("Test program failed to build.");
2210 }
2211
2212 /* Retrieve subroutine locations */
2213 m_po_getter0_subroutine_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "getter0");
2214 m_po_getter1_subroutine_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "getter1");
2215
2216 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineIndex() call(s) failed.");
2217
2218 if (m_po_getter0_subroutine_index == GL_INVALID_INDEX || m_po_getter1_subroutine_index == GL_INVALID_INDEX)
2219 {
2220 TCU_FAIL("At least one subroutine is considered inactive which is invalid.");
2221 }
2222
2223 /* Retrieve subroutine uniform location */
2224 m_po_subroutine_uniform_index = gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "colorGetterUniform");
2225
2226 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineUniformLocation() call failed.");
2227
2228 if (m_po_subroutine_uniform_index == -1)
2229 {
2230 TCU_FAIL("Subroutine uniform is considered inactive which is invalid.");
2231 }
2232
2233 /* Set up XFB BO storage */
2234 const Utils::_variable_type base_variable_type = Utils::getBaseVariableType(test_case.variable_type);
2235 unsigned int iteration_xfb_bo_size = Utils::getComponentSizeForVariableType(base_variable_type) *
2236 Utils::getNumberOfComponentsForVariableType(test_case.variable_type);
2237 unsigned int total_xfb_bo_size = 0;
2238
2239 if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2240 {
2241 /* Boolean varyings are not supported by OpenGL. Instead, we use ints to output
2242 * boolean values. */
2243 iteration_xfb_bo_size = static_cast<unsigned int>(iteration_xfb_bo_size * sizeof(int));
2244 }
2245
2246 total_xfb_bo_size = iteration_xfb_bo_size * 2 /* subroutines we will be testing */;
2247
2248 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, total_xfb_bo_size, DE_NULL /* data */, GL_STATIC_DRAW);
2249 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
2250
2251 /* Activate test program object */
2252 gl.useProgram(m_po_id);
2253 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
2254
2255 /* Run two iterations. Each iteration should invoke different subroutine. */
2256 const glw::GLuint subroutine_indices[] = {m_po_getter0_subroutine_index, m_po_getter1_subroutine_index};
2257 const unsigned int n_subroutine_indices = sizeof(subroutine_indices) / sizeof(subroutine_indices[0]);
2258
2259 for (unsigned int n_subroutine_index = 0; n_subroutine_index < n_subroutine_indices; ++n_subroutine_index)
2260 {
2261 /* Configure which subroutine should be used for the draw call */
2262 glw::GLuint current_subroutine_index = subroutine_indices[n_subroutine_index];
2263
2264 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, 1 /* count */, ¤t_subroutine_index);
2265 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniformSubroutinesuiv() call failed.");
2266
2267 /* Update XFB binding so that we do not overwrite data XFBed in previous iterations */
2268 gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
2269 m_xfb_bo_id, iteration_xfb_bo_size * n_subroutine_index, iteration_xfb_bo_size);
2270 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange() call failed.");
2271
2272 /* Draw a single point */
2273 gl.beginTransformFeedback(GL_POINTS);
2274 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed.");
2275 {
2276 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
2277 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
2278 }
2279 gl.endTransformFeedback();
2280 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed.");
2281 } /* for (all subroutine indices) */
2282
2283 /* Map the BO storage into process space */
2284 const void *xfb_data_ptr = gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
2285 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer() call failed.");
2286
2287 result &= verifyXFBData(xfb_data_ptr, test_case.variable_type);
2288
2289 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
2290 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffeR() call failed.");
2291
2292 return result;
2293 }
2294
2295 /** Retrieves body of a vertex shader that should be used to verify
2296 * subroutine support, given user-specified test iteration properties.
2297 *
2298 * @param variable_type GLSL type that should be used for argument and
2299 * return type definition in a subroutine. This setting
2300 * also affects type of the only output variable in the shader.
2301 * @param array_size 1 if non-arrayed arguments/return types should be tested;
2302 * 2 if arrayed arguments/return types should be tested.
2303 *
2304 * @return Requested string.
2305 **/
getVertexShaderBody(const Utils::_variable_type & variable_type,unsigned int array_size)2306 std::string FunctionalTest1_2::getVertexShaderBody(const Utils::_variable_type &variable_type, unsigned int array_size)
2307 {
2308 Utils::_variable_type base_variable_type = Utils::getBaseVariableType(variable_type);
2309 unsigned int n_variable_type_components = Utils::getNumberOfComponentsForVariableType(variable_type);
2310 std::stringstream result_sstream;
2311 std::string variable_type_glsl = Utils::getVariableTypeGLSLString(variable_type);
2312 std::stringstream variable_type_glsl_array_sstream;
2313 std::stringstream variable_type_glsl_arrayed_sstream;
2314
2315 variable_type_glsl_arrayed_sstream << variable_type_glsl;
2316
2317 if (array_size > 1)
2318 {
2319 variable_type_glsl_array_sstream << "[" << array_size << "]";
2320 variable_type_glsl_arrayed_sstream << variable_type_glsl_array_sstream.str();
2321 }
2322
2323 /* Form pre-amble */
2324 result_sstream << "#version 400\n"
2325 "\n"
2326 "#extension GL_ARB_shader_subroutine : require\n";
2327
2328 if (variable_type == Utils::VARIABLE_TYPE_DOUBLE)
2329 {
2330 result_sstream << "#extension GL_ARB_gpu_shader_fp64 : require\n";
2331 }
2332
2333 /* Form subroutine type declaration */
2334 result_sstream << "\n"
2335 "subroutine "
2336 << variable_type_glsl_arrayed_sstream.str() << " colorGetter(in " << variable_type_glsl
2337 << " in_value" << variable_type_glsl_array_sstream.str()
2338 << ");\n"
2339 "\n";
2340
2341 /* Declare getter functions */
2342 for (int n_getter = 0; n_getter < 2; ++n_getter)
2343 {
2344 result_sstream << "subroutine(colorGetter) " << variable_type_glsl_arrayed_sstream.str() << " getter"
2345 << n_getter << "(in " << variable_type_glsl << " in_value"
2346 << variable_type_glsl_array_sstream.str()
2347 << ")\n"
2348 "{\n";
2349
2350 if (array_size > 1)
2351 {
2352 result_sstream << variable_type_glsl << " temp" << variable_type_glsl_array_sstream.str() << ";\n";
2353 }
2354
2355 if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2356 {
2357 if (array_size > 1)
2358 {
2359 for (unsigned int array_index = 0; array_index < array_size; ++array_index)
2360 {
2361 result_sstream << " temp[" << array_index
2362 << "]"
2363 " = "
2364 << ((n_getter == 0) ? ((variable_type_glsl == "bool") ? "!" : "not") : "")
2365 << "(in_value[" << array_index << "]);\n";
2366 }
2367
2368 result_sstream << " return temp;\n";
2369 }
2370 else
2371 {
2372 result_sstream << " return "
2373 << ((n_getter == 0) ? ((variable_type_glsl == "bool") ? "!" : "not") : "")
2374 << "(in_value);\n";
2375 }
2376 } /* if (base_variable_type == Utils::VARIABLE_TYPE_BOOL) */
2377 else
2378 {
2379 if (array_size > 1)
2380 {
2381 for (unsigned int array_index = 0; array_index < array_size; ++array_index)
2382 {
2383 result_sstream << " temp[" << array_index
2384 << "]"
2385 " = in_value["
2386 << array_index << "] + " << (n_getter + 1) << ";\n";
2387 }
2388
2389 result_sstream << " return temp;\n";
2390 }
2391 else
2392 {
2393 result_sstream << " return (in_value + " << (n_getter + 1) << ");\n";
2394 }
2395 }
2396
2397 result_sstream << "}\n";
2398 } /* for (both getter functions) */
2399
2400 /* Declare subroutine uniform */
2401 result_sstream << "subroutine uniform colorGetter colorGetterUniform;\n"
2402 "\n";
2403
2404 /* Declare output variable */
2405 result_sstream << "out ";
2406
2407 if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2408 {
2409 Utils::_variable_type result_as_int_variable_type =
2410 Utils::getVariableTypeFromProperties(Utils::VARIABLE_TYPE_INT, n_variable_type_components);
2411 std::string variable_type_glsl_as_int = Utils::getVariableTypeGLSLString(result_as_int_variable_type);
2412
2413 result_sstream << variable_type_glsl_as_int;
2414 }
2415 else
2416 {
2417 result_sstream << variable_type_glsl;
2418 }
2419
2420 result_sstream << " result;\n"
2421 "\n";
2422
2423 /* Declare main(): prepare input argument for the subroutine function */
2424 result_sstream << "void main()\n"
2425 "{\n"
2426 " "
2427 << variable_type_glsl << " temp";
2428
2429 if (array_size > 1)
2430 {
2431 result_sstream << "[" << array_size << "]";
2432 }
2433
2434 result_sstream << ";\n";
2435
2436 for (unsigned int array_index = 0; array_index < array_size; ++array_index)
2437 {
2438 result_sstream << " temp";
2439
2440 if (array_size > 1)
2441 {
2442 result_sstream << "[" << array_index << "]";
2443 }
2444
2445 result_sstream << " = " << variable_type_glsl << "(";
2446
2447 if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2448 {
2449 result_sstream << "true";
2450 }
2451 else
2452 {
2453 for (unsigned int n_component = 0; n_component < n_variable_type_components; ++n_component)
2454 {
2455 result_sstream << "3";
2456
2457 if (n_component != (n_variable_type_components - 1))
2458 {
2459 result_sstream << ", ";
2460 }
2461 } /* for (all components) */
2462 }
2463
2464 result_sstream << ");\n";
2465 } /* for (all array indices) */
2466
2467 /* Declare main(): call the subroutine. Verify the input and write the result
2468 * to the output variable.
2469 **/
2470 if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2471 {
2472 Utils::_variable_type result_as_int_variable_type =
2473 Utils::getVariableTypeFromProperties(Utils::VARIABLE_TYPE_INT, n_variable_type_components);
2474 std::string variable_type_glsl_as_int = Utils::getVariableTypeGLSLString(result_as_int_variable_type);
2475
2476 result_sstream << variable_type_glsl_arrayed_sstream.str()
2477 << " subroutine_result = colorGetterUniform(temp);\n"
2478 "result = ";
2479
2480 for (unsigned int array_index = 0; array_index < array_size; ++array_index)
2481 {
2482 if (variable_type_glsl == "bool")
2483 result_sstream << "bool(subroutine_result";
2484 else
2485 result_sstream << "all(subroutine_result";
2486
2487 if (array_size > 1)
2488 {
2489 result_sstream << "[" << array_index << "]";
2490 }
2491
2492 result_sstream << ")";
2493
2494 if (array_index != (array_size - 1))
2495 {
2496 result_sstream << "&& ";
2497 }
2498 }
2499
2500 result_sstream << " == true ? " << variable_type_glsl_as_int << "(1) : " << variable_type_glsl_as_int << "(0);";
2501 }
2502 else
2503 {
2504 if (array_size > 1)
2505 {
2506 DE_ASSERT(array_size == 2);
2507
2508 result_sstream << variable_type_glsl << " subroutine_result" << variable_type_glsl_array_sstream.str()
2509 << " = colorGetterUniform(temp);\n"
2510 "\n"
2511 "if (subroutine_result[0] == subroutine_result[1]) result = subroutine_result[0];\n"
2512 "else\n"
2513 "result = "
2514 << variable_type_glsl << "(-1);\n";
2515 }
2516 else
2517 {
2518 result_sstream << "result = colorGetterUniform(temp);\n";
2519 }
2520 }
2521
2522 /* All done */
2523 result_sstream << "}\n";
2524
2525 return result_sstream.str();
2526 }
2527
2528 /** Initializes all GL objects required to run the test. */
initTest()2529 void FunctionalTest1_2::initTest()
2530 {
2531 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2532
2533 /* Generate buffer object to hold result XFB data */
2534 gl.genBuffers(1, &m_xfb_bo_id);
2535 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
2536
2537 /* Set up XFB BO bindings */
2538 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_xfb_bo_id);
2539 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
2540
2541 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_xfb_bo_id);
2542 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed.");
2543
2544 /* Generate VAO to use for the draw calls */
2545 gl.genVertexArrays(1, &m_vao_id);
2546 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
2547
2548 gl.bindVertexArray(m_vao_id);
2549 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
2550 }
2551
2552 /** Executes test iteration.
2553 *
2554 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
2555 */
iterate()2556 tcu::TestNode::IterateResult FunctionalTest1_2::iterate()
2557 {
2558 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
2559 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
2560 {
2561 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
2562 }
2563
2564 /* Initialize a test program object */
2565 initTest();
2566
2567 /* Construct test case descriptors: first, iIerate over all
2568 * variable types we want to cover */
2569 const Utils::_variable_type variable_types[] = {
2570 Utils::VARIABLE_TYPE_BOOL, Utils::VARIABLE_TYPE_BVEC2, Utils::VARIABLE_TYPE_BVEC3,
2571 Utils::VARIABLE_TYPE_BVEC4, Utils::VARIABLE_TYPE_DOUBLE, Utils::VARIABLE_TYPE_FLOAT,
2572 Utils::VARIABLE_TYPE_INT, Utils::VARIABLE_TYPE_IVEC2, Utils::VARIABLE_TYPE_IVEC3,
2573 Utils::VARIABLE_TYPE_IVEC4, Utils::VARIABLE_TYPE_MAT2, Utils::VARIABLE_TYPE_MAT2X3,
2574 Utils::VARIABLE_TYPE_MAT2X4, Utils::VARIABLE_TYPE_MAT3, Utils::VARIABLE_TYPE_MAT3X2,
2575 Utils::VARIABLE_TYPE_MAT3X4, Utils::VARIABLE_TYPE_MAT4, Utils::VARIABLE_TYPE_MAT4X2,
2576 Utils::VARIABLE_TYPE_MAT4X3, Utils::VARIABLE_TYPE_UINT, Utils::VARIABLE_TYPE_UVEC2,
2577 Utils::VARIABLE_TYPE_UVEC3, Utils::VARIABLE_TYPE_UVEC4, Utils::VARIABLE_TYPE_VEC2,
2578 Utils::VARIABLE_TYPE_VEC3, Utils::VARIABLE_TYPE_VEC4};
2579 const unsigned int n_variable_types = sizeof(variable_types) / sizeof(variable_types[0]);
2580
2581 for (unsigned int n_variable_type = 0; n_variable_type < n_variable_types; ++n_variable_type)
2582 {
2583 Utils::_variable_type current_variable_type = variable_types[n_variable_type];
2584
2585 /* We need to test both arrayed and non-arrayed arguments */
2586 for (unsigned int array_size = 1; array_size < 3; ++array_size)
2587 {
2588 /* Exclude double variables if the relevant extension is unavailable */
2589 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gpu_shader_fp64") &&
2590 current_variable_type == Utils::VARIABLE_TYPE_DOUBLE)
2591 {
2592 continue;
2593 }
2594
2595 /* Form the descriptor */
2596 _test_case test_case;
2597
2598 test_case.array_size = array_size;
2599 test_case.variable_type = current_variable_type;
2600
2601 /* Store the test case descriptor */
2602 m_test_cases.push_back(test_case);
2603 } /* for (both arrayed and non-arrayed arguments) */
2604 } /* for (all variable types) */
2605
2606 /* Iterate over all test cases and execute the test */
2607 for (_test_cases_const_iterator test_case_iterator = m_test_cases.begin(); test_case_iterator != m_test_cases.end();
2608 ++test_case_iterator)
2609 {
2610 const _test_case &test_case = *test_case_iterator;
2611
2612 m_has_test_passed &= executeTestIteration(test_case);
2613
2614 /* Release GL objects that were created during the execution */
2615 deinitTestIteration();
2616 } /* for (all test cases) */
2617
2618 /* Done */
2619 if (m_has_test_passed)
2620 {
2621 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2622 }
2623 else
2624 {
2625 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2626 }
2627
2628 return STOP;
2629 }
2630
2631 /** Verifies data that has been XFBed out by the vertex shader.
2632 *
2633 * @param xfb_data Buffer holding the data.
2634 * @param variable_type GLSL type used for the test iteration
2635 * that generated the data at @param xfb_data.
2636 *
2637 * @return true if the data was found to be valid, false if it
2638 * was detected to be incorrect.
2639 **/
verifyXFBData(const void * xfb_data,const Utils::_variable_type & variable_type)2640 bool FunctionalTest1_2::verifyXFBData(const void *xfb_data, const Utils::_variable_type &variable_type)
2641 {
2642 const Utils::_variable_type base_variable_type = Utils::getBaseVariableType(variable_type);
2643 const float epsilon = 1e-5f;
2644 const unsigned int n_variable_type_components = Utils::getNumberOfComponentsForVariableType(variable_type);
2645 bool result = true;
2646 const unsigned char *traveller_ptr = (const unsigned char *)xfb_data;
2647
2648 /* Boolean arguments/return types are tested with a slightly different shader so we
2649 * need to test them in a separate code-path.
2650 */
2651 if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2652 {
2653 /* 0 should be returned when getter0 is used, 1 otherwise */
2654 const unsigned int ref_values[] = {0, 1};
2655 const unsigned int n_ref_values = sizeof(ref_values) / sizeof(ref_values[0]);
2656
2657 for (unsigned int n_ref_value = 0; n_ref_value < n_ref_values; ++n_ref_value)
2658 {
2659 const unsigned int ref_value = ref_values[n_ref_value];
2660
2661 for (unsigned int n_component = 0; n_component < n_variable_type_components; ++n_component)
2662 {
2663 int *result_value_ptr = (int *)(traveller_ptr);
2664
2665 if (*result_value_ptr != (int)ref_value)
2666 {
2667 m_testCtx.getLog() << tcu::TestLog::Message
2668 << "Invalid value reported by subroutine using "
2669 "["
2670 << Utils::getVariableTypeGLSLString(variable_type) << "]"
2671 << " argument/return types ("
2672 "expected:["
2673 << ref_value << "], found:[" << *result_value_ptr << "])"
2674 << tcu::TestLog::EndMessage;
2675
2676 result = false;
2677 break;
2678 }
2679
2680 traveller_ptr += sizeof(int);
2681 } /* for (all components) */
2682 } /* for (all reference values) */
2683 } /* if (base_variable_type == Utils::VARIABLE_TYPE_BOOL) */
2684 else
2685 {
2686 /* 4 should be returned when getter0 is used, 5 otherwise */
2687 const unsigned int ref_values[] = {4, 5};
2688 const unsigned int n_ref_values = sizeof(ref_values) / sizeof(ref_values[0]);
2689
2690 for (unsigned int n_ref_value = 0; n_ref_value < n_ref_values; ++n_ref_value)
2691 {
2692 const unsigned int ref_value = ref_values[n_ref_value];
2693
2694 DE_ASSERT(
2695 base_variable_type == Utils::VARIABLE_TYPE_DOUBLE || base_variable_type == Utils::VARIABLE_TYPE_FLOAT ||
2696 base_variable_type == Utils::VARIABLE_TYPE_INT || base_variable_type == Utils::VARIABLE_TYPE_UINT);
2697
2698 for (unsigned int n_component = 0; n_component < n_variable_type_components; ++n_component)
2699 {
2700 const double *double_value_ptr = (double *)traveller_ptr;
2701 const float *float_value_ptr = (float *)traveller_ptr;
2702 const int *int_value_ptr = (int *)traveller_ptr;
2703
2704 switch (base_variable_type)
2705 {
2706 case Utils::VARIABLE_TYPE_DOUBLE:
2707 {
2708 if (de::abs(*double_value_ptr - (double)ref_value) > epsilon)
2709 {
2710 m_testCtx.getLog()
2711 << tcu::TestLog::Message
2712 << "Invalid value reported by subroutine using "
2713 "["
2714 << Utils::getVariableTypeGLSLString(variable_type) << "]"
2715 << " argument/return types ("
2716 "expected:["
2717 << ref_value << "], found:[" << *double_value_ptr << "])" << tcu::TestLog::EndMessage;
2718
2719 result = false;
2720 }
2721
2722 traveller_ptr += sizeof(double);
2723 break;
2724 }
2725
2726 case Utils::VARIABLE_TYPE_FLOAT:
2727 {
2728 if (de::abs(*float_value_ptr - (float)ref_value) > epsilon)
2729 {
2730 m_testCtx.getLog()
2731 << tcu::TestLog::Message
2732 << "Invalid value reported by subroutine using "
2733 "["
2734 << Utils::getVariableTypeGLSLString(variable_type) << "]"
2735 << " argument/return types ("
2736 "expected:["
2737 << ref_value << "], found:[" << *float_value_ptr << "])" << tcu::TestLog::EndMessage;
2738
2739 result = false;
2740 }
2741
2742 traveller_ptr += sizeof(float);
2743 break;
2744 }
2745
2746 case Utils::VARIABLE_TYPE_INT:
2747 case Utils::VARIABLE_TYPE_UINT:
2748 {
2749 if (*int_value_ptr != (int)ref_value)
2750 {
2751 m_testCtx.getLog()
2752 << tcu::TestLog::Message
2753 << "Invalid value reported by subroutine using "
2754 "["
2755 << Utils::getVariableTypeGLSLString(variable_type) << "]"
2756 << " argument/return types ("
2757 "expected:["
2758 << ref_value << "], found:[" << *int_value_ptr << "])" << tcu::TestLog::EndMessage;
2759
2760 result = false;
2761 }
2762
2763 traveller_ptr += sizeof(int);
2764 break;
2765 }
2766
2767 default:
2768 break;
2769 } /* switch (base_variable_type) */
2770 } /* for (all components) */
2771 } /* for (all reference values) */
2772 }
2773
2774 return result;
2775 }
2776
2777 /** Constructor
2778 *
2779 * @param context CTS context
2780 **/
FunctionalTest3_4(deqp::Context & context)2781 FunctionalTest3_4::FunctionalTest3_4(deqp::Context &context)
2782 : TestCase(context, "four_subroutines_with_two_uniforms", "Verify Get* API and draw calls")
2783 , m_n_active_subroutine_uniforms(0)
2784 , m_n_active_subroutine_uniform_locations(0)
2785 , m_n_active_subroutines(0)
2786 , m_n_active_subroutine_uniform_name_length(0)
2787 , m_n_active_subroutine_name_length(0)
2788 , m_n_active_subroutine_uniform_size(0)
2789 {
2790 /* Nothing to be done here */
2791 }
2792
2793 /** Execute test
2794 *
2795 * @return tcu::TestNode::STOP
2796 **/
iterate()2797 tcu::TestNode::IterateResult FunctionalTest3_4::iterate()
2798 {
2799 static const glw::GLchar *vertex_shader_code =
2800 "#version 400 core\n"
2801 "#extension GL_ARB_shader_subroutine : require\n"
2802 "\n"
2803 "precision highp float;\n"
2804 "\n"
2805 "// Sub routine type declaration\n"
2806 "subroutine vec4 routine_type(in vec4 iparam);\n"
2807 "\n"
2808 "// Sub routine definitions\n"
2809 "subroutine(routine_type) vec4 inverse_order(in vec4 iparam)\n"
2810 "{\n"
2811 " return iparam.wzyx;\n"
2812 "}\n"
2813 "\n"
2814 "subroutine(routine_type) vec4 negate(in vec4 iparam)\n"
2815 "{\n"
2816 " return -iparam;\n"
2817 "}\n"
2818 "\n"
2819 "subroutine(routine_type) vec4 inverse(in vec4 iparam)\n"
2820 "{\n"
2821 " return 1 / iparam;\n"
2822 "}\n"
2823 "\n"
2824 "subroutine(routine_type) vec4 square(in vec4 iparam)\n"
2825 "{\n"
2826 " return iparam * iparam;\n"
2827 "}\n"
2828 "\n"
2829 "// Sub routine uniforms\n"
2830 "subroutine uniform routine_type first_routine;\n"
2831 "subroutine uniform routine_type second_routine;\n"
2832 "\n"
2833 "// Input data\n"
2834 "uniform vec4 input_data;\n"
2835 "\n"
2836 "// Output\n"
2837 "out vec4 out_input_data;\n"
2838 "out vec4 out_result_from_first_routine;\n"
2839 "out vec4 out_result_from_second_routine;\n"
2840 "out vec4 out_result_from_combined_routines;\n"
2841 "out vec4 out_result_from_routines_combined_in_reveresed_order;\n"
2842 "\n"
2843 "void main()\n"
2844 "{\n"
2845 " out_input_data = input_data;\n"
2846 " out_result_from_first_routine = first_routine(input_data);\n"
2847 " out_result_from_second_routine = second_routine(input_data);\n"
2848 " out_result_from_combined_routines = second_routine(first_routine(input_data));\n"
2849 " out_result_from_routines_combined_in_reveresed_order = first_routine(second_routine(input_data));\n"
2850 "}\n"
2851 "\n";
2852
2853 static const GLchar *varying_names[] = {
2854 "out_input_data",
2855 "out_result_from_first_routine",
2856 "out_result_from_second_routine",
2857 "out_result_from_combined_routines",
2858 "out_result_from_routines_combined_in_reveresed_order",
2859 };
2860
2861 static const GLchar *subroutine_uniform_names[] = {"first_routine", "second_routine"};
2862
2863 static const GLchar *subroutine_names[] = {"inverse_order", "negate", "inverse", "square"};
2864
2865 static const GLuint n_varyings = sizeof(varying_names) / sizeof(varying_names[0]);
2866 static const GLuint transform_feedback_buffer_size = n_varyings * sizeof(GLfloat) * 4 /* vec4 */;
2867
2868 static const GLuint inverse_order_routine_index = 0;
2869 static const GLuint negate_routine_index = 1;
2870 static const GLuint inverse_routine_index = 2;
2871 static const GLuint square_routine_index = 3;
2872
2873 /* Test data */
2874 static const Utils::vec4<GLfloat> inverse_order_negate_data[5] = {
2875 Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
2876 Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f), Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f),
2877 Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f),
2878 };
2879
2880 static const Utils::vec4<GLfloat> inverse_order_inverse_data[5] = {
2881 Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
2882 Utils::vec4<GLfloat>(-0.5f, -1.0f, 1.0f, 0.5f), Utils::vec4<GLfloat>(0.5f, 1.0f, -1.0f, -0.5f),
2883 Utils::vec4<GLfloat>(0.5f, 1.0f, -1.0f, -0.5f),
2884 };
2885
2886 static const Utils::vec4<GLfloat> inverse_order_square_data[5] = {
2887 Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
2888 Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f), Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f),
2889 Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f),
2890 };
2891
2892 static const Utils::vec4<GLfloat> negate_inverse_data[5] = {
2893 Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
2894 Utils::vec4<GLfloat>(-0.5f, -1.0f, 1.0f, 0.5f), Utils::vec4<GLfloat>(0.5f, 1.0f, -1.0f, -0.5f),
2895 Utils::vec4<GLfloat>(0.5f, 1.0f, -1.0f, -0.5f),
2896 };
2897
2898 static const Utils::vec4<GLfloat> negate_square_data[5] = {
2899 Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
2900 Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f), Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f),
2901 Utils::vec4<GLfloat>(-4.0f, -1.0f, -1.0f, -4.0f),
2902 };
2903
2904 static const Utils::vec4<GLfloat> inverse_square_data[5] = {
2905 Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(-0.5f, -1.0f, 1.0f, 0.5f),
2906 Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f), Utils::vec4<GLfloat>(0.25f, 1.0f, 1.0f, 0.25f),
2907 Utils::vec4<GLfloat>(0.25f, 1.0f, 1.0f, 0.25f),
2908 };
2909
2910 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
2911 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
2912 {
2913 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
2914 }
2915
2916 m_n_active_subroutine_uniforms = 2;
2917 m_n_active_subroutine_uniform_locations = 2;
2918 m_n_active_subroutines = 4;
2919 m_n_active_subroutine_uniform_name_length = 0;
2920 m_n_active_subroutine_name_length = 0;
2921 m_n_active_subroutine_uniform_size = 1;
2922
2923 /* GL objects */
2924 Utils::program program(m_context);
2925 Utils::buffer transform_feedback_buffer(m_context);
2926 Utils::vertexArray vao(m_context);
2927
2928 bool result = true;
2929
2930 /* Calculate max name lengths for subroutines and subroutine uniforms */
2931 for (GLint i = 0; i < m_n_active_subroutine_uniforms; ++i)
2932 {
2933 const GLsizei length = (GLsizei)strlen(subroutine_uniform_names[i]);
2934
2935 if (length > m_n_active_subroutine_uniform_name_length)
2936 {
2937 m_n_active_subroutine_uniform_name_length = length;
2938 }
2939 }
2940
2941 for (GLint i = 0; i < m_n_active_subroutines; ++i)
2942 {
2943 const GLsizei length = (GLsizei)strlen(subroutine_names[i]);
2944
2945 if (length > m_n_active_subroutine_name_length)
2946 {
2947 m_n_active_subroutine_name_length = length;
2948 }
2949 }
2950
2951 /* Init */
2952 program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code, varying_names,
2953 n_varyings);
2954
2955 vao.generate();
2956 vao.bind();
2957
2958 transform_feedback_buffer.generate();
2959 transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
2960 GL_DYNAMIC_COPY);
2961 transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
2962
2963 program.use();
2964
2965 /* Inspect Get* API */
2966 if ((false == inspectProgramStageiv(program.m_program_object_id)) ||
2967 (false == inspectActiveSubroutineUniformiv(program.m_program_object_id, subroutine_uniform_names)) ||
2968 (false == inspectActiveSubroutineUniformName(program.m_program_object_id, subroutine_uniform_names)) ||
2969 (false == inspectActiveSubroutineName(program.m_program_object_id, subroutine_names)) ||
2970 (false ==
2971 inspectSubroutineBinding(program.m_program_object_id, subroutine_names, subroutine_uniform_names, false)))
2972 {
2973 result = false;
2974 }
2975
2976 /* Inspect GetProgram* API */
2977 if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_program_interface_query"))
2978 {
2979 if ((false == inspectProgramInterfaceiv(program.m_program_object_id)) ||
2980 (false ==
2981 inspectProgramResourceiv(program.m_program_object_id, subroutine_names, subroutine_uniform_names)) ||
2982 (false ==
2983 inspectSubroutineBinding(program.m_program_object_id, subroutine_names, subroutine_uniform_names, true)))
2984 {
2985 result = false;
2986 }
2987 }
2988
2989 /* Test shader execution */
2990 if ((false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
2991 subroutine_names[negate_routine_index], subroutine_uniform_names, inverse_order_negate_data,
2992 false)) ||
2993 (false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
2994 subroutine_names[inverse_routine_index], subroutine_uniform_names,
2995 inverse_order_inverse_data, false)) ||
2996 (false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
2997 subroutine_names[square_routine_index], subroutine_uniform_names, inverse_order_square_data,
2998 false)) ||
2999 (false == testDraw(program.m_program_object_id, subroutine_names[negate_routine_index],
3000 subroutine_names[inverse_routine_index], subroutine_uniform_names, negate_inverse_data,
3001 false)) ||
3002 (false == testDraw(program.m_program_object_id, subroutine_names[negate_routine_index],
3003 subroutine_names[square_routine_index], subroutine_uniform_names, negate_square_data,
3004 false)) ||
3005 (false == testDraw(program.m_program_object_id, subroutine_names[inverse_routine_index],
3006 subroutine_names[square_routine_index], subroutine_uniform_names, inverse_square_data,
3007 false)))
3008 {
3009 result = false;
3010 }
3011
3012 if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_program_interface_query"))
3013 {
3014 if ((false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
3015 subroutine_names[negate_routine_index], subroutine_uniform_names,
3016 inverse_order_negate_data, true)) ||
3017 (false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
3018 subroutine_names[inverse_routine_index], subroutine_uniform_names,
3019 inverse_order_inverse_data, true)) ||
3020 (false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
3021 subroutine_names[square_routine_index], subroutine_uniform_names,
3022 inverse_order_square_data, true)) ||
3023 (false == testDraw(program.m_program_object_id, subroutine_names[negate_routine_index],
3024 subroutine_names[inverse_routine_index], subroutine_uniform_names, negate_inverse_data,
3025 true)) ||
3026 (false == testDraw(program.m_program_object_id, subroutine_names[negate_routine_index],
3027 subroutine_names[square_routine_index], subroutine_uniform_names, negate_square_data,
3028 true)) ||
3029 (false == testDraw(program.m_program_object_id, subroutine_names[inverse_routine_index],
3030 subroutine_names[square_routine_index], subroutine_uniform_names, inverse_square_data,
3031 true)))
3032 {
3033 result = false;
3034 }
3035 }
3036
3037 /* Done */
3038 if (true == result)
3039 {
3040 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3041 }
3042 else
3043 {
3044 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
3045 }
3046
3047 return tcu::TestNode::STOP;
3048 }
3049
3050 /** Verify result of getProgramStageiv
3051 *
3052 * @param program_id Program object id
3053 * @param pname <pname> parameter for getProgramStageiv
3054 * @param expected Expected value
3055 *
3056 * @return true if result is equal to expected value, flase otherwise
3057 **/
checkProgramStageiv(glw::GLuint program_id,glw::GLenum pname,glw::GLint expected) const3058 bool FunctionalTest3_4::checkProgramStageiv(glw::GLuint program_id, glw::GLenum pname, glw::GLint expected) const
3059 {
3060 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3061 GLint value = 0;
3062
3063 gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, pname, &value);
3064 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3065
3066 if (expected != value)
3067 {
3068 m_context.getTestContext().getLog()
3069 << tcu::TestLog::Message << "Error. Invalid result. Function: getProgramStageiv. "
3070 << "pname: " << Utils::pnameToStr(pname) << ". "
3071 << "Result: " << value << ". "
3072 << "Expected: " << expected << "." << tcu::TestLog::EndMessage;
3073
3074 return false;
3075 }
3076 else
3077 {
3078 return true;
3079 }
3080 }
3081
3082 /** Verify result of getProgramResourceiv
3083 *
3084 * @param program_id Program object id
3085 * @param program_interface Program interface
3086 * @param pname <pname> parameter for getProgramStageiv
3087 * @param resource_name Resource name
3088 * @param expected Expected value
3089 *
3090 * @return true if result is equal to expected value, false otherwise
3091 **/
checkProgramResourceiv(GLuint program_id,GLenum program_interface,GLenum pname,const glw::GLchar * resource_name,GLint expected) const3092 bool FunctionalTest3_4::checkProgramResourceiv(GLuint program_id, GLenum program_interface, GLenum pname,
3093 const glw::GLchar *resource_name, GLint expected) const
3094 {
3095 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3096 GLuint index = gl.getProgramResourceIndex(program_id, program_interface, resource_name);
3097 GLint value = 0;
3098
3099 if (GL_INVALID_INDEX == index)
3100 {
3101 return false;
3102 }
3103
3104 gl.getProgramResourceiv(program_id, program_interface, index, 1, &pname, 1, 0, &value);
3105 GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramResourceiv");
3106
3107 if (expected != value)
3108 {
3109 m_context.getTestContext().getLog()
3110 << tcu::TestLog::Message << "Error. Invalid result. Function: getProgramResourceiv. "
3111 << "Program interface: " << Utils::programInterfaceToStr(program_interface) << ". "
3112 << "Resource name: " << resource_name << ". "
3113 << "Property: " << Utils::pnameToStr(pname) << ". "
3114 << "Result: " << value << ". "
3115 << "Expected: " << expected << "." << tcu::TestLog::EndMessage;
3116
3117 return false;
3118 }
3119 else
3120 {
3121 return true;
3122 }
3123 }
3124
3125 /** Verify result of getProgramInterfaceiv
3126 *
3127 * @param program_id Program object id
3128 * @param program_interface Program interface
3129 * @param pname <pname> parameter for getProgramStageiv
3130 * @param expected Expected value
3131 *
3132 * @return true if result is equal to expected value, flase otherwise
3133 **/
checkProgramInterfaceiv(GLuint program_id,GLenum program_interface,GLenum pname,GLint expected) const3134 bool FunctionalTest3_4::checkProgramInterfaceiv(GLuint program_id, GLenum program_interface, GLenum pname,
3135 GLint expected) const
3136 {
3137 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3138 GLint value = 0;
3139
3140 gl.getProgramInterfaceiv(program_id, program_interface, pname, &value);
3141 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramInterfaceiv");
3142
3143 if (expected != value)
3144 {
3145 m_context.getTestContext().getLog()
3146 << tcu::TestLog::Message << "Error. Invalid result. Function: getProgramInterfaceiv. "
3147 << "Program interface: " << Utils::programInterfaceToStr(program_interface) << ". "
3148 << "pname: " << Utils::pnameToStr(pname) << ". "
3149 << "Result: " << value << ". "
3150 << "Expected: " << expected << "." << tcu::TestLog::EndMessage;
3151
3152 return false;
3153 }
3154 else
3155 {
3156 return true;
3157 }
3158 }
3159
3160 /** Verify result of getActiveSubroutineUniformiv
3161 *
3162 * @param program_id Program object id
3163 * @param index <index> parameter for getActiveSubroutineUniformiv
3164 * @param pname <pname> parameter for getActiveSubroutineUniformiv
3165 * @param expected Expected value
3166 *
3167 * @return true if result is equal to expected value, flase otherwise
3168 **/
checkActiveSubroutineUniformiv(GLuint program_id,GLuint index,GLenum pname,GLint expected) const3169 bool FunctionalTest3_4::checkActiveSubroutineUniformiv(GLuint program_id, GLuint index, GLenum pname,
3170 GLint expected) const
3171 {
3172 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3173 GLint value = 0;
3174
3175 gl.getActiveSubroutineUniformiv(program_id, GL_VERTEX_SHADER, index, pname, &value);
3176 GLU_EXPECT_NO_ERROR(gl.getError(), "getActiveSubroutineUniformiv");
3177
3178 if (expected != value)
3179 {
3180 m_context.getTestContext().getLog()
3181 << tcu::TestLog::Message << "Error. Invalid result. Function: getActiveSubroutineUniformiv. "
3182 << "idnex: " << index << ". "
3183 << "pname: " << Utils::pnameToStr(pname) << ". "
3184 << "Result: " << value << ". "
3185 << "Expected: " << expected << "." << tcu::TestLog::EndMessage;
3186
3187 return false;
3188 }
3189 else
3190 {
3191 return true;
3192 }
3193 }
3194
3195 /** Returns index of program resource
3196 *
3197 * @param program_id Program object id
3198 * @param program_interface Program interface
3199 * @param resource_name Name of resource
3200 *
3201 * @return Index of specified resource
3202 **/
getProgramResourceIndex(GLuint program_id,GLenum program_interface,const glw::GLchar * resource_name) const3203 GLuint FunctionalTest3_4::getProgramResourceIndex(GLuint program_id, GLenum program_interface,
3204 const glw::GLchar *resource_name) const
3205 {
3206 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3207 GLuint index = gl.getProgramResourceIndex(program_id, program_interface, resource_name);
3208
3209 GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramResourceIndex");
3210
3211 if (GL_INVALID_INDEX == index)
3212 {
3213 m_context.getTestContext().getLog()
3214 << tcu::TestLog::Message << "Error. Program resource is not available. "
3215 << "Program interface: " << Utils::programInterfaceToStr(program_interface) << ". "
3216 << "Resource name: " << resource_name << "." << tcu::TestLog::EndMessage;
3217 }
3218
3219 return index;
3220 }
3221
3222 /** Get subroutine index
3223 *
3224 * @param program_id Program object id
3225 * @param subroutine_name Subroutine name
3226 * @param use_program_query If true getProgramResourceIndex is used, otherwise getSubroutineIndex
3227 *
3228 * @return Index of subroutine
3229 **/
getSubroutineIndex(GLuint program_id,const glw::GLchar * subroutine_name,bool use_program_query) const3230 GLuint FunctionalTest3_4::getSubroutineIndex(GLuint program_id, const glw::GLchar *subroutine_name,
3231 bool use_program_query) const
3232 {
3233 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3234 GLuint index = -1;
3235
3236 if (false == use_program_query)
3237 {
3238 index = gl.getSubroutineIndex(program_id, GL_VERTEX_SHADER, subroutine_name);
3239 GLU_EXPECT_NO_ERROR(gl.getError(), "GetSubroutineIndex");
3240 }
3241 else
3242 {
3243 index = gl.getProgramResourceIndex(program_id, GL_VERTEX_SUBROUTINE, subroutine_name);
3244 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramResourceIndex");
3245 }
3246
3247 if (GL_INVALID_INDEX == index)
3248 {
3249 TCU_FAIL("Subroutine is not available");
3250 }
3251
3252 return index;
3253 }
3254
3255 /** Get subroutine uniform location
3256 *
3257 * @param program_id Program object id
3258 * @param uniform_name Subroutine uniform name
3259 * @param use_program_query If true getProgramResourceLocation is used, otherwise getSubroutineUniformLocation
3260 *
3261 * @return Location of subroutine uniform
3262 **/
getSubroutineUniformLocation(GLuint program_id,const glw::GLchar * uniform_name,bool use_program_query) const3263 GLint FunctionalTest3_4::getSubroutineUniformLocation(GLuint program_id, const glw::GLchar *uniform_name,
3264 bool use_program_query) const
3265 {
3266 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3267 GLint location = -1;
3268
3269 if (false == use_program_query)
3270 {
3271 location = gl.getSubroutineUniformLocation(program_id, GL_VERTEX_SHADER, uniform_name);
3272 GLU_EXPECT_NO_ERROR(gl.getError(), "GetSubroutineUniformLocation");
3273 }
3274 else
3275 {
3276 location = gl.getProgramResourceLocation(program_id, GL_VERTEX_SUBROUTINE_UNIFORM, uniform_name);
3277 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramResourceLocation");
3278 }
3279
3280 if (-1 == location)
3281 {
3282 TCU_FAIL("Subroutine uniform is not available");
3283 }
3284
3285 return location;
3286 }
3287
3288 /** Test if getProgramStageiv results are as expected
3289 *
3290 * @param program_id Program object id
3291 *
3292 * @result false in case of invalid result for any pname, true otherwise
3293 **/
inspectProgramStageiv(glw::GLuint program_id) const3294 bool FunctionalTest3_4::inspectProgramStageiv(glw::GLuint program_id) const
3295 {
3296 bool result = true;
3297
3298 const inspectionDetails details[] = {
3299 {GL_ACTIVE_SUBROUTINE_UNIFORMS, m_n_active_subroutine_uniforms},
3300 {GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS, m_n_active_subroutine_uniform_locations},
3301 {GL_ACTIVE_SUBROUTINES, m_n_active_subroutines},
3302 {GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH, m_n_active_subroutine_uniform_name_length + 1},
3303 {GL_ACTIVE_SUBROUTINE_MAX_LENGTH, m_n_active_subroutine_name_length + 1}};
3304 const GLuint n_details = sizeof(details) / sizeof(details[0]);
3305
3306 for (GLuint i = 0; i < n_details; ++i)
3307 {
3308 if (false == checkProgramStageiv(program_id, details[i].pname, details[i].expected_value))
3309 {
3310 result = false;
3311 }
3312 }
3313
3314 return result;
3315 }
3316
3317 /** Test if checkProgramInterfaceiv results are as expected
3318 *
3319 * @param program_id Program object id
3320 *
3321 * @result false in case of invalid result for any pname, true otherwise
3322 **/
inspectProgramInterfaceiv(glw::GLuint program_id) const3323 bool FunctionalTest3_4::inspectProgramInterfaceiv(glw::GLuint program_id) const
3324 {
3325 bool result = true;
3326
3327 const inspectionDetailsForProgramInterface details[] = {
3328 {GL_VERTEX_SUBROUTINE_UNIFORM, GL_ACTIVE_RESOURCES, m_n_active_subroutine_uniforms},
3329 {GL_VERTEX_SUBROUTINE_UNIFORM, GL_MAX_NAME_LENGTH, m_n_active_subroutine_uniform_name_length + 1},
3330 {GL_VERTEX_SUBROUTINE_UNIFORM, GL_MAX_NUM_COMPATIBLE_SUBROUTINES, m_n_active_subroutines},
3331 {GL_VERTEX_SUBROUTINE, GL_ACTIVE_RESOURCES, m_n_active_subroutines},
3332 {GL_VERTEX_SUBROUTINE, GL_MAX_NAME_LENGTH, m_n_active_subroutine_name_length + 1}};
3333 const GLuint n_details = sizeof(details) / sizeof(details[0]);
3334
3335 for (GLuint i = 0; i < n_details; ++i)
3336 {
3337 if (false == checkProgramInterfaceiv(program_id, details[i].program_interface, details[i].pname,
3338 details[i].expected_value))
3339 {
3340 result = false;
3341 }
3342 }
3343
3344 return result;
3345 }
3346
3347 /** Test if checkProgramResourceiv results are as expected
3348 *
3349 * @param program_id Program object id
3350 * @param subroutine_names Array of subroutine names
3351 * @param uniform_names Array of uniform names
3352 *
3353 * @result false in case of invalid result for any pname, true otherwise
3354 **/
inspectProgramResourceiv(GLuint program_id,const GLchar ** subroutine_names,const GLchar ** uniform_names) const3355 bool FunctionalTest3_4::inspectProgramResourceiv(GLuint program_id, const GLchar **subroutine_names,
3356 const GLchar **uniform_names) const
3357 {
3358 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3359 bool result = true;
3360
3361 for (GLint subroutine = 0; subroutine < m_n_active_subroutines; ++subroutine)
3362 {
3363 const GLchar *subroutine_name = subroutine_names[subroutine];
3364 const GLint length = (GLint)strlen(subroutine_name) + 1;
3365
3366 if (false == checkProgramResourceiv(program_id, GL_VERTEX_SUBROUTINE, GL_NAME_LENGTH, subroutine_name, length))
3367 {
3368 result = false;
3369 }
3370 }
3371
3372 inspectionDetails details[] = {
3373 {GL_NAME_LENGTH, 0},
3374 {GL_ARRAY_SIZE, 1},
3375 {GL_NUM_COMPATIBLE_SUBROUTINES, m_n_active_subroutines},
3376 {GL_LOCATION, 0},
3377 };
3378 const GLuint n_details = sizeof(details) / sizeof(details[0]);
3379
3380 for (GLint uniform = 0; uniform < m_n_active_subroutine_uniforms; ++uniform)
3381 {
3382 const GLchar *uniform_name = uniform_names[uniform];
3383 const GLint length = (GLint)strlen(uniform_name) + 1;
3384 const GLint location = getSubroutineUniformLocation(program_id, uniform_name, true);
3385
3386 details[0].expected_value = length;
3387 details[3].expected_value = location;
3388
3389 for (GLuint i = 0; i < n_details; ++i)
3390 {
3391 if (false == checkProgramResourceiv(program_id, GL_VERTEX_SUBROUTINE_UNIFORM, details[i].pname,
3392 uniform_name, details[i].expected_value))
3393 {
3394 result = false;
3395 }
3396 }
3397
3398 /* Check compatible subroutines */
3399 GLuint index = getProgramResourceIndex(program_id, GL_VERTEX_SUBROUTINE_UNIFORM, uniform_name);
3400
3401 if (GL_INVALID_INDEX != index)
3402 {
3403 std::vector<GLint> compatible_subroutines;
3404 GLint index_sum = 0;
3405 GLenum prop = GL_COMPATIBLE_SUBROUTINES;
3406
3407 compatible_subroutines.resize(m_n_active_subroutines);
3408
3409 gl.getProgramResourceiv(program_id, GL_VERTEX_SUBROUTINE_UNIFORM, index, 1, &prop, m_n_active_subroutines,
3410 0, &compatible_subroutines[0]);
3411
3412 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramResourceiv");
3413
3414 /* Expected indices are 0, 1, 2, ... N */
3415 for (GLint i = 0; i < m_n_active_subroutines; ++i)
3416 {
3417 index_sum += compatible_subroutines[i];
3418 }
3419
3420 /* Sum of E1, ..., EN = (E1 + EN) * N / 2 */
3421 if (((m_n_active_subroutines - 1) * m_n_active_subroutines) / 2 != index_sum)
3422 {
3423 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
3424
3425 message << "Error. Invalid result. Function: getProgramResourceiv. "
3426 << "Program interface: GL_VERTEX_SUBROUTINE_UNIFORM. "
3427 << "Resource name: " << uniform_name << ". "
3428 << "Property: GL_COMPATIBLE_SUBROUTINES. "
3429 << "Results: ";
3430
3431 for (GLint i = 1; i < m_n_active_subroutines; ++i)
3432 {
3433 message << compatible_subroutines[i];
3434 }
3435
3436 message << tcu::TestLog::EndMessage;
3437
3438 result = false;
3439 }
3440 }
3441 }
3442
3443 return result;
3444 }
3445
3446 /** Test if getActiveSubroutineUniformiv results are as expected
3447 *
3448 * @param program_id Program object id
3449 * @param uniform_names Array of subroutine uniform names available in program
3450 *
3451 * @result false in case of invalid result for any pname, true otherwise
3452 **/
inspectActiveSubroutineUniformiv(GLuint program_id,const GLchar ** uniform_names) const3453 bool FunctionalTest3_4::inspectActiveSubroutineUniformiv(GLuint program_id, const GLchar **uniform_names) const
3454 {
3455 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3456 bool result = true;
3457 GLint n_active_subroutine_uniforms = 0;
3458
3459 inspectionDetails details[] = {
3460 {GL_NUM_COMPATIBLE_SUBROUTINES, m_n_active_subroutines},
3461 {GL_UNIFORM_SIZE, m_n_active_subroutine_uniform_size},
3462 {GL_UNIFORM_NAME_LENGTH, 0},
3463 };
3464 const GLuint n_details = sizeof(details) / sizeof(details[0]);
3465
3466 /* Get amount of active subroutine uniforms */
3467 gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORMS, &n_active_subroutine_uniforms);
3468 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3469
3470 for (GLint uniform = 0; uniform < n_active_subroutine_uniforms; ++uniform)
3471 {
3472 GLint name_length = (GLint)strlen(uniform_names[uniform]);
3473
3474 details[2].expected_value = name_length + 1;
3475
3476 /* Checks from "details" */
3477 for (GLuint i = 0; i < n_details; ++i)
3478 {
3479 if (false ==
3480 checkActiveSubroutineUniformiv(program_id, uniform, details[i].pname, details[i].expected_value))
3481 {
3482 result = false;
3483 }
3484 }
3485
3486 /* Check compatible subroutines */
3487 std::vector<GLint> compatible_subroutines;
3488 compatible_subroutines.resize(m_n_active_subroutines);
3489 GLint index_sum = 0;
3490
3491 gl.getActiveSubroutineUniformiv(program_id, GL_VERTEX_SHADER, uniform, GL_COMPATIBLE_SUBROUTINES,
3492 &compatible_subroutines[0]);
3493 GLU_EXPECT_NO_ERROR(gl.getError(), "getActiveSubroutineUniformiv");
3494
3495 /* Expected indices are 0, 1, 2, ... N */
3496 for (GLint i = 0; i < m_n_active_subroutines; ++i)
3497 {
3498 index_sum += compatible_subroutines[i];
3499 }
3500
3501 /* Sum of E1, ..., EN = (E1 + EN) * N / 2 */
3502 if (((m_n_active_subroutines - 1) * m_n_active_subroutines) / 2 != index_sum)
3503 {
3504 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
3505
3506 message << "Error. Invalid result. Function: getActiveSubroutineUniformiv. idnex: " << uniform
3507 << ". pname: " << Utils::pnameToStr(GL_COMPATIBLE_SUBROUTINES) << ". Results: ";
3508
3509 for (GLint i = 1; i < m_n_active_subroutines; ++i)
3510 {
3511 message << compatible_subroutines[i];
3512 }
3513
3514 message << tcu::TestLog::EndMessage;
3515
3516 result = false;
3517 }
3518 }
3519
3520 return result;
3521 }
3522
3523 /** Test if getActiveSubroutineUniformName results are as expected
3524 *
3525 * @param program_id Program object id
3526 * @param uniform_names Array of subroutine uniform names available in program
3527 *
3528 * @result false in case of invalid result, true otherwise
3529 **/
inspectActiveSubroutineUniformName(GLuint program_id,const GLchar ** uniform_names) const3530 bool FunctionalTest3_4::inspectActiveSubroutineUniformName(GLuint program_id, const GLchar **uniform_names) const
3531 {
3532 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3533 bool result = true;
3534 GLint n_active_subroutine_uniforms = 0;
3535 std::vector<GLchar> active_uniform_name;
3536
3537 gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORMS, &n_active_subroutine_uniforms);
3538 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3539
3540 active_uniform_name.resize(m_n_active_subroutine_uniform_name_length + 1);
3541
3542 for (GLint uniform = 0; uniform < n_active_subroutine_uniforms; ++uniform)
3543 {
3544 bool is_name_ok = false;
3545
3546 gl.getActiveSubroutineUniformName(program_id, GL_VERTEX_SHADER, uniform, (GLsizei)active_uniform_name.size(),
3547 0 /* length */, &active_uniform_name[0]);
3548 GLU_EXPECT_NO_ERROR(gl.getError(), "GetActiveSubroutineUniformName");
3549
3550 for (GLint name = 0; name < n_active_subroutine_uniforms; ++name)
3551 {
3552 if (0 == strcmp(uniform_names[name], &active_uniform_name[0]))
3553 {
3554 is_name_ok = true;
3555 break;
3556 }
3557 }
3558
3559 if (false == is_name_ok)
3560 {
3561 m_context.getTestContext().getLog()
3562 << tcu::TestLog::Message
3563 << "Error. Invalid result. Function: getActiveSubroutineUniformName. idnex: " << uniform
3564 << ". Result: " << &active_uniform_name[0] << tcu::TestLog::EndMessage;
3565
3566 result = false;
3567 break;
3568 }
3569 }
3570
3571 return result;
3572 }
3573
3574 /** Test if getActiveSubroutineUniformName results are as expected
3575 *
3576 * @param program_id Program object id
3577 * @param subroutine_names Array of subroutine names available in program
3578 *
3579 * @result false in case of invalid result, true otherwise
3580 **/
inspectActiveSubroutineName(GLuint program_id,const GLchar ** subroutine_names) const3581 bool FunctionalTest3_4::inspectActiveSubroutineName(GLuint program_id, const GLchar **subroutine_names) const
3582 {
3583 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3584 bool result = true;
3585 GLint n_active_subroutines = 0;
3586 std::vector<GLchar> active_subroutine_name;
3587
3588 gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINES, &n_active_subroutines);
3589 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3590
3591 active_subroutine_name.resize(m_n_active_subroutine_name_length + 1);
3592
3593 for (GLint uniform = 0; uniform < n_active_subroutines; ++uniform)
3594 {
3595 bool is_name_ok = false;
3596
3597 gl.getActiveSubroutineName(program_id, GL_VERTEX_SHADER, uniform, (GLsizei)active_subroutine_name.size(),
3598 0 /* length */, &active_subroutine_name[0]);
3599 GLU_EXPECT_NO_ERROR(gl.getError(), "getActiveSubroutineName");
3600
3601 for (GLint name = 0; name < n_active_subroutines; ++name)
3602 {
3603 if (0 == strcmp(subroutine_names[name], &active_subroutine_name[0]))
3604 {
3605 is_name_ok = true;
3606 break;
3607 }
3608 }
3609
3610 if (false == is_name_ok)
3611 {
3612 m_context.getTestContext().getLog()
3613 << tcu::TestLog::Message
3614 << "Error. Invalid result. Function: getActiveSubroutineName. idnex: " << uniform
3615 << ". Result: " << &active_subroutine_name[0] << tcu::TestLog::EndMessage;
3616
3617 result = false;
3618 break;
3619 }
3620 }
3621
3622 return result;
3623 }
3624
3625 /** Test if it is possible to "bind" all subroutines uniforms with all subroutines
3626 *
3627 * @param program_id Program object id
3628 * @param subroutine_names Array of subroutine names available in program
3629 * @param uniform_names Array of subroutine uniform names available in program
3630 *
3631 * @result false in case of invalid result, true otherwise
3632 **/
inspectSubroutineBinding(GLuint program_id,const GLchar ** subroutine_names,const GLchar ** uniform_names,bool use_program_query) const3633 bool FunctionalTest3_4::inspectSubroutineBinding(GLuint program_id, const GLchar **subroutine_names,
3634 const GLchar **uniform_names, bool use_program_query) const
3635 {
3636 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3637 bool result = true;
3638 GLint n_active_subroutines = 0;
3639 GLint n_active_subroutine_uniforms = 0;
3640 std::vector<GLuint> subroutine_uniforms;
3641 GLuint queried_subroutine_index = 0;
3642
3643 gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINES, &n_active_subroutines);
3644 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3645
3646 gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORMS, &n_active_subroutine_uniforms);
3647 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3648
3649 subroutine_uniforms.resize(n_active_subroutine_uniforms);
3650
3651 for (GLint uniform = 0; uniform < n_active_subroutine_uniforms; ++uniform)
3652 {
3653 GLuint uniform_location = getSubroutineUniformLocation(program_id, uniform_names[uniform], use_program_query);
3654
3655 for (GLint routine = 0; routine < n_active_subroutines; ++routine)
3656 {
3657 GLuint routine_index = getSubroutineIndex(program_id, subroutine_names[routine], use_program_query);
3658
3659 subroutine_uniforms[uniform] = routine_index;
3660
3661 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, n_active_subroutine_uniforms, &subroutine_uniforms[0]);
3662 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
3663
3664 gl.getUniformSubroutineuiv(GL_VERTEX_SHADER, uniform_location, &queried_subroutine_index);
3665 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv");
3666
3667 if (queried_subroutine_index != routine_index)
3668 {
3669 m_context.getTestContext().getLog()
3670 << tcu::TestLog::Message << "Error. Invalid result. Function: gl.getUniformSubroutineuiv."
3671 << " Subroutine uniform: " << uniform << ", name: " << uniform_names[uniform]
3672 << ", location: " << uniform_location << ". Subroutine: " << routine
3673 << ", name: " << subroutine_names[routine] << ", index: " << routine_index
3674 << ". Result: " << queried_subroutine_index << tcu::TestLog::EndMessage;
3675
3676 result = false;
3677 }
3678 }
3679 }
3680
3681 return result;
3682 }
3683
3684 /** Execute draw call and verify results
3685 *
3686 * @param program_id Program object id
3687 * @param first_routine_name Name of subroutine that shall be used aas first_routine
3688 * @param second_routine_name Name of subroutine that shall be used aas second_routine
3689 * @param uniform_names Name of uniforms
3690 * @param expected_results Test data. [0] is used as input data. All are used as expected_results
3691 * @param use_program_query If true GetProgram* API will be used
3692 *
3693 * @return false in case of invalid result, true otherwise
3694 **/
testDraw(GLuint program_id,const GLchar * first_routine_name,const GLchar * second_routine_name,const GLchar ** uniform_names,const Utils::vec4<GLfloat> expected_results[5],bool use_program_query) const3695 bool FunctionalTest3_4::testDraw(GLuint program_id, const GLchar *first_routine_name, const GLchar *second_routine_name,
3696 const GLchar **uniform_names, const Utils::vec4<GLfloat> expected_results[5],
3697 bool use_program_query) const
3698 {
3699 static const GLuint n_varyings = 5;
3700 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
3701 bool result = true;
3702 GLuint subroutine_uniforms[2] = {0};
3703
3704 /* Get subroutine uniform locations */
3705 GLint first_routine_location = getSubroutineUniformLocation(program_id, uniform_names[0], use_program_query);
3706
3707 GLint second_routine_location = getSubroutineUniformLocation(program_id, uniform_names[1], use_program_query);
3708
3709 /* Get subroutine indices */
3710 GLuint first_routine_index = getSubroutineIndex(program_id, first_routine_name, use_program_query);
3711
3712 GLuint second_routine_index = getSubroutineIndex(program_id, second_routine_name, use_program_query);
3713
3714 /* Map uniforms with subroutines */
3715 subroutine_uniforms[first_routine_location] = first_routine_index;
3716 subroutine_uniforms[second_routine_location] = second_routine_index;
3717
3718 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, 2 /* number of uniforms */, &subroutine_uniforms[0]);
3719 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
3720
3721 /* Get location of input_data */
3722 GLint input_data_location = gl.getUniformLocation(program_id, "input_data");
3723 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation");
3724
3725 if (-1 == input_data_location)
3726 {
3727 TCU_FAIL("Uniform is not available");
3728 }
3729
3730 /* Set up input_data */
3731 gl.uniform4f(input_data_location, expected_results[0].m_x, expected_results[0].m_y, expected_results[0].m_z,
3732 expected_results[0].m_w);
3733 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
3734
3735 /* Execute draw call with transform feedback */
3736 gl.beginTransformFeedback(GL_POINTS);
3737 GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
3738
3739 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
3740 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
3741
3742 gl.endTransformFeedback();
3743 GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
3744
3745 /* Verify results */
3746 GLfloat *feedback_data = (GLfloat *)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
3747 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
3748
3749 Utils::vec4<GLfloat> results[5];
3750
3751 results[0].m_x = feedback_data[0];
3752 results[0].m_y = feedback_data[1];
3753 results[0].m_z = feedback_data[2];
3754 results[0].m_w = feedback_data[3];
3755
3756 results[1].m_x = feedback_data[4];
3757 results[1].m_y = feedback_data[5];
3758 results[1].m_z = feedback_data[6];
3759 results[1].m_w = feedback_data[7];
3760
3761 results[2].m_x = feedback_data[8];
3762 results[2].m_y = feedback_data[9];
3763 results[2].m_z = feedback_data[10];
3764 results[2].m_w = feedback_data[11];
3765
3766 results[3].m_x = feedback_data[12];
3767 results[3].m_y = feedback_data[13];
3768 results[3].m_z = feedback_data[14];
3769 results[3].m_w = feedback_data[15];
3770
3771 results[4].m_x = feedback_data[16];
3772 results[4].m_y = feedback_data[17];
3773 results[4].m_z = feedback_data[18];
3774 results[4].m_w = feedback_data[19];
3775
3776 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
3777 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
3778
3779 for (GLuint i = 0; i < n_varyings; ++i)
3780 {
3781 result = result && (results[i] == expected_results[i]);
3782 }
3783
3784 if (false == result)
3785 {
3786 m_context.getTestContext().getLog()
3787 << tcu::TestLog::Message << "Error. Invalid result. First routine: " << first_routine_name
3788 << ". Second routine: " << second_routine_name << tcu::TestLog::EndMessage;
3789
3790 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
3791
3792 message << "Results:";
3793
3794 for (GLuint i = 0; i < n_varyings; ++i)
3795 {
3796 results[i].log(message);
3797 }
3798
3799 message << tcu::TestLog::EndMessage;
3800
3801 message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
3802
3803 message << "Expected:";
3804
3805 for (GLuint i = 0; i < n_varyings; ++i)
3806 {
3807 expected_results[i].log(message);
3808 }
3809
3810 message << tcu::TestLog::EndMessage;
3811 }
3812
3813 return result;
3814 }
3815
3816 /** Constructor
3817 *
3818 * @param context CTS context
3819 **/
FunctionalTest5(deqp::Context & context)3820 FunctionalTest5::FunctionalTest5(deqp::Context &context)
3821 : TestCase(context, "eight_subroutines_four_uniforms", "Verify multiple subroutine sets")
3822 {
3823 }
3824
3825 /** Execute test
3826 *
3827 * @return tcu::TestNode::STOP
3828 **/
iterate()3829 tcu::TestNode::IterateResult FunctionalTest5::iterate()
3830 {
3831 static const GLchar *vertex_shader_code =
3832 "#version 400 core\n"
3833 "#extension GL_ARB_shader_subroutine : require\n"
3834 "\n"
3835 "precision highp float;\n"
3836 "\n"
3837 "// Subroutine types\n"
3838 "subroutine vec4 routine_type_1(in vec4 left, in vec4 right);\n"
3839 "subroutine vec4 routine_type_2(in vec4 iparam);\n"
3840 "subroutine vec4 routine_type_3(in vec4 a, in vec4 b, in vec4 c);\n"
3841 "subroutine bvec4 routine_type_4(in vec4 left, in vec4 right);\n"
3842 "\n"
3843 "// Subroutine definitions\n"
3844 "// 1st type\n"
3845 "subroutine(routine_type_1) vec4 add(in vec4 left, in vec4 right)\n"
3846 "{\n"
3847 " return left + right;\n"
3848 "}\n"
3849 "\n"
3850 "subroutine(routine_type_1) vec4 subtract(in vec4 left, in vec4 right)\n"
3851 "{\n"
3852 " return left - right;\n"
3853 "}\n"
3854 "\n"
3855 "// 2nd type\n"
3856 "subroutine(routine_type_2) vec4 square(in vec4 iparam)\n"
3857 "{\n"
3858 " return iparam * iparam;\n"
3859 "}\n"
3860 "\n"
3861 "subroutine(routine_type_2) vec4 square_root(in vec4 iparam)\n"
3862 "{\n"
3863 " return sqrt(iparam);\n"
3864 "}\n"
3865 "\n"
3866 "// 3rd type\n"
3867 "subroutine(routine_type_3) vec4 do_fma(in vec4 a, in vec4 b, in vec4 c)\n"
3868 "{\n"
3869 " return fma(a, b, c);\n"
3870 "}\n"
3871 "\n"
3872 "subroutine(routine_type_3) vec4 blend(in vec4 a, in vec4 b, in vec4 c)\n"
3873 "{\n"
3874 " return c * a + (vec4(1) - c) * b;\n"
3875 "}\n"
3876 "\n"
3877 "// 4th type\n"
3878 "subroutine(routine_type_4) bvec4 are_equal(in vec4 left, in vec4 right)\n"
3879 "{\n"
3880 " return equal(left, right);\n"
3881 "}\n"
3882 "\n"
3883 "subroutine(routine_type_4) bvec4 are_greater(in vec4 left, in vec4 right)\n"
3884 "{\n"
3885 " return greaterThan(left, right);\n"
3886 "}\n"
3887 "\n"
3888 "// Sub routine uniforms\n"
3889 "subroutine uniform routine_type_1 first_routine;\n"
3890 "subroutine uniform routine_type_2 second_routine;\n"
3891 "subroutine uniform routine_type_3 third_routine;\n"
3892 "subroutine uniform routine_type_4 fourth_routine;\n"
3893 "\n"
3894 "// Input data\n"
3895 "uniform vec4 first_input;\n"
3896 "uniform vec4 second_input;\n"
3897 "uniform vec4 third_input;\n"
3898 "\n"
3899 "// Output\n"
3900 "out vec4 out_result_from_first_routine;\n"
3901 "out vec4 out_result_from_second_routine;\n"
3902 "out vec4 out_result_from_third_routine;\n"
3903 "out uvec4 out_result_from_fourth_routine;\n"
3904 "\n"
3905 "void main()\n"
3906 "{\n"
3907 " out_result_from_first_routine = first_routine (first_input, second_input);\n"
3908 " out_result_from_second_routine = second_routine(first_input);\n"
3909 " out_result_from_third_routine = third_routine (first_input, second_input, third_input);\n"
3910 " out_result_from_fourth_routine = uvec4(fourth_routine(first_input, second_input));\n"
3911 "}\n"
3912 "\n";
3913
3914 static const GLchar *subroutine_names[4][2] = {
3915 {"add", "subtract"}, {"square", "square_root"}, {"do_fma", "blend"}, {"are_equal", "are_greater"}};
3916
3917 static const GLchar *subroutine_uniform_names[4][1] = {
3918 {"first_routine"}, {"second_routine"}, {"third_routine"}, {"fourth_routine"}};
3919
3920 static const GLuint n_subroutine_types = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
3921 static const GLuint n_subroutines_per_type = sizeof(subroutine_names[0]) / sizeof(subroutine_names[0][0]);
3922 static const GLuint n_subroutine_uniforms_per_type =
3923 sizeof(subroutine_uniform_names[0]) / sizeof(subroutine_uniform_names[0][0]);
3924
3925 static const GLchar *uniform_names[] = {"first_input", "second_input", "third_input"};
3926 static const GLuint n_uniform_names = sizeof(uniform_names) / sizeof(uniform_names[0]);
3927
3928 static const GLchar *varying_names[] = {"out_result_from_first_routine", "out_result_from_second_routine",
3929 "out_result_from_third_routine", "out_result_from_fourth_routine"};
3930 static const GLuint n_varyings = sizeof(varying_names) / sizeof(varying_names[0]);
3931 static const GLuint transform_feedback_buffer_size = n_varyings * sizeof(GLfloat) * 4 /* vec4 */;
3932
3933 /* Test data */
3934 static const Utils::vec4<GLfloat> input_data[3] = {Utils::vec4<GLfloat>(1.0f, 4.0f, 9.0f, 16.0f),
3935 Utils::vec4<GLfloat>(16.0f, 9.0f, 4.0f, 1.0f),
3936 Utils::vec4<GLfloat>(0.25f, 0.5f, 0.75f, 1.0f)};
3937
3938 static const Utils::vec4<GLfloat> expected_result_from_first_routine[2] = {
3939 Utils::vec4<GLfloat>(17.0f, 13.0f, 13.0f, 17.0f), Utils::vec4<GLfloat>(-15.0f, -5.0f, 5.0f, 15.0f)};
3940
3941 static const Utils::vec4<GLfloat> expected_result_from_second_routine[2] = {
3942 Utils::vec4<GLfloat>(1.0f, 16.0f, 81.0f, 256.0f), Utils::vec4<GLfloat>(1.0f, 2.0f, 3.0f, 4.0f)};
3943
3944 static const Utils::vec4<GLfloat> expected_result_from_third_routine[2] = {
3945 Utils::vec4<GLfloat>(16.25f, 36.5f, 36.75f, 17.0f), Utils::vec4<GLfloat>(12.25f, 6.5f, 7.75f, 16.0f)};
3946
3947 static const Utils::vec4<GLuint> expected_result_from_fourth_routine[2] = {Utils::vec4<GLuint>(0, 0, 0, 0),
3948 Utils::vec4<GLuint>(0, 0, 1, 1)};
3949
3950 /* All combinations of subroutines */
3951 static const GLuint subroutine_combinations[][4] = {
3952 {0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 0}, {0, 0, 1, 1}, {0, 1, 0, 0}, {0, 1, 0, 1}, {0, 1, 1, 0}, {0, 1, 1, 1},
3953 {1, 0, 0, 0}, {1, 0, 0, 1}, {1, 0, 1, 0}, {1, 0, 1, 1}, {1, 1, 0, 0}, {1, 1, 0, 1}, {1, 1, 1, 0}, {1, 1, 1, 1}};
3954 static const GLuint n_subroutine_combinations =
3955 sizeof(subroutine_combinations) / sizeof(subroutine_combinations[0]);
3956
3957 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
3958 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
3959 {
3960 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
3961 }
3962
3963 /* Result */
3964 bool result = true;
3965
3966 /* GL objects */
3967 Utils::program program(m_context);
3968 Utils::buffer transform_feedback_buffer(m_context);
3969 Utils::vertexArray vao(m_context);
3970
3971 /* Init GL objects */
3972 program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code, varying_names,
3973 n_varyings);
3974
3975 program.use();
3976
3977 vao.generate();
3978 vao.bind();
3979
3980 transform_feedback_buffer.generate();
3981 transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
3982 GL_DYNAMIC_COPY);
3983 transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
3984
3985 /* Get subroutine uniform locations and subroutine indices */
3986 for (GLuint type = 0; type < n_subroutine_types; ++type)
3987 {
3988 for (GLuint uniform = 0; uniform < n_subroutine_uniforms_per_type; ++uniform)
3989 {
3990 m_subroutine_uniform_locations[type][uniform] =
3991 program.getSubroutineUniformLocation(subroutine_uniform_names[type][uniform], GL_VERTEX_SHADER);
3992 }
3993
3994 for (GLuint routine = 0; routine < n_subroutines_per_type; ++routine)
3995 {
3996 m_subroutine_indices[type][routine] =
3997 program.getSubroutineIndex(subroutine_names[type][routine], GL_VERTEX_SHADER);
3998 }
3999 }
4000
4001 /* Get uniform locations */
4002 for (GLuint i = 0; i < n_uniform_names; ++i)
4003 {
4004 m_uniform_locations[i] = program.getUniformLocation(uniform_names[i]);
4005 }
4006
4007 /* Draw with each routine combination */
4008 for (GLuint i = 0; i < n_subroutine_combinations; ++i)
4009 {
4010 Utils::vec4<GLfloat> first_routine_result;
4011 Utils::vec4<GLfloat> second_routine_result;
4012 Utils::vec4<GLfloat> third_routine_result;
4013 Utils::vec4<GLuint> fourth_routine_result;
4014
4015 testDraw(subroutine_combinations[i], input_data, first_routine_result, second_routine_result,
4016 third_routine_result, fourth_routine_result);
4017
4018 if (false == verify(first_routine_result, second_routine_result, third_routine_result, fourth_routine_result,
4019 expected_result_from_first_routine[subroutine_combinations[i][0]],
4020 expected_result_from_second_routine[subroutine_combinations[i][1]],
4021 expected_result_from_third_routine[subroutine_combinations[i][2]],
4022 expected_result_from_fourth_routine[subroutine_combinations[i][3]]))
4023 {
4024 logError(subroutine_names, subroutine_combinations[i], input_data, first_routine_result,
4025 second_routine_result, third_routine_result, fourth_routine_result,
4026 expected_result_from_first_routine[subroutine_combinations[i][0]],
4027 expected_result_from_second_routine[subroutine_combinations[i][1]],
4028 expected_result_from_third_routine[subroutine_combinations[i][2]],
4029 expected_result_from_fourth_routine[subroutine_combinations[i][3]]);
4030
4031 result = false;
4032 }
4033 }
4034
4035 /* Done */
4036 if (true == result)
4037 {
4038 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4039 }
4040 else
4041 {
4042 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
4043 }
4044
4045 return tcu::TestNode::STOP;
4046 }
4047
4048 /** Log error message
4049 *
4050 * @param subroutine_names Array of subroutine names
4051 * @param subroutine_combination Combination of subroutines
4052 * @param input_data Input data
4053 * @param first_routine_result Result of first routine
4054 * @param second_routine_result Result of second routine
4055 * @param third_routine_result Result of third routine
4056 * @param fourth_routine_result Result of fourth routine
4057 * @param first_routine_expected_result Expected result of first routine
4058 * @param second_routine_expected_result Expected result of second routine
4059 * @param third_routine_expected_result Expected result of third routine
4060 * @param fourth_routine_expected_result Expected result of fourth routine
4061 **/
logError(const glw::GLchar * subroutine_names[4][2],const glw::GLuint subroutine_combination[4],const Utils::vec4<glw::GLfloat> input_data[3],const Utils::vec4<glw::GLfloat> & first_routine_result,const Utils::vec4<glw::GLfloat> & second_routine_result,const Utils::vec4<glw::GLfloat> & third_routine_result,const Utils::vec4<glw::GLuint> & fourth_routine_result,const Utils::vec4<glw::GLfloat> & first_routine_expected_result,const Utils::vec4<glw::GLfloat> & second_routine_expected_result,const Utils::vec4<glw::GLfloat> & third_routine_expected_result,const Utils::vec4<glw::GLuint> & fourth_routine_expected_result) const4062 void FunctionalTest5::logError(const glw::GLchar *subroutine_names[4][2], const glw::GLuint subroutine_combination[4],
4063 const Utils::vec4<glw::GLfloat> input_data[3],
4064 const Utils::vec4<glw::GLfloat> &first_routine_result,
4065 const Utils::vec4<glw::GLfloat> &second_routine_result,
4066 const Utils::vec4<glw::GLfloat> &third_routine_result,
4067 const Utils::vec4<glw::GLuint> &fourth_routine_result,
4068 const Utils::vec4<glw::GLfloat> &first_routine_expected_result,
4069 const Utils::vec4<glw::GLfloat> &second_routine_expected_result,
4070 const Utils::vec4<glw::GLfloat> &third_routine_expected_result,
4071 const Utils::vec4<glw::GLuint> &fourth_routine_expected_result) const
4072 {
4073 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error. Invalid result."
4074 << tcu::TestLog::EndMessage;
4075
4076 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4077
4078 message << "Function: " << subroutine_names[0][subroutine_combination[0]] << "( ";
4079 input_data[0].log(message);
4080 message << ", ";
4081 input_data[1].log(message);
4082 message << " ). Result: ";
4083 first_routine_result.log(message);
4084 message << ". Expected: ";
4085 first_routine_expected_result.log(message);
4086
4087 message << tcu::TestLog::EndMessage;
4088
4089 message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4090
4091 message << "Function: " << subroutine_names[1][subroutine_combination[1]] << "( ";
4092 input_data[0].log(message);
4093 message << " ). Result: ";
4094 second_routine_result.log(message);
4095 message << ". Expected: ";
4096 second_routine_expected_result.log(message);
4097
4098 message << tcu::TestLog::EndMessage;
4099
4100 message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4101
4102 message << "Function: " << subroutine_names[2][subroutine_combination[2]] << "( ";
4103 input_data[0].log(message);
4104 message << ", ";
4105 input_data[1].log(message);
4106 message << ", ";
4107 input_data[2].log(message);
4108 message << "). Result: ";
4109 third_routine_result.log(message);
4110 message << ". Expected: ";
4111 third_routine_expected_result.log(message);
4112
4113 message << tcu::TestLog::EndMessage;
4114
4115 message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4116
4117 message << "Function: " << subroutine_names[3][subroutine_combination[3]] << "( ";
4118 input_data[0].log(message);
4119 message << ", ";
4120 input_data[1].log(message);
4121 message << ", ";
4122 message << " ). Result: ";
4123 fourth_routine_result.log(message);
4124 message << ". Expected: ";
4125 fourth_routine_expected_result.log(message);
4126
4127 message << tcu::TestLog::EndMessage;
4128 }
4129
4130 /** Execute draw call and capture results
4131 *
4132 * @param subroutine_combination Combination of subroutines
4133 * @param input_data Input data
4134 * @param out_first_routine_result Result of first routine
4135 * @param out_second_routine_result Result of second routine
4136 * @param out_third_routine_result Result of third routine
4137 * @param out_fourth_routine_result Result of fourth routine
4138 **/
testDraw(const glw::GLuint subroutine_combination[4],const Utils::vec4<glw::GLfloat> input_data[3],Utils::vec4<glw::GLfloat> & out_first_routine_result,Utils::vec4<glw::GLfloat> & out_second_routine_result,Utils::vec4<glw::GLfloat> & out_third_routine_result,Utils::vec4<glw::GLuint> & out_fourth_routine_result) const4139 void FunctionalTest5::testDraw(const glw::GLuint subroutine_combination[4],
4140 const Utils::vec4<glw::GLfloat> input_data[3],
4141 Utils::vec4<glw::GLfloat> &out_first_routine_result,
4142 Utils::vec4<glw::GLfloat> &out_second_routine_result,
4143 Utils::vec4<glw::GLfloat> &out_third_routine_result,
4144 Utils::vec4<glw::GLuint> &out_fourth_routine_result) const
4145 {
4146 static const GLuint n_uniforms = sizeof(m_uniform_locations) / sizeof(m_uniform_locations[0]);
4147 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
4148 GLuint subroutine_indices[4];
4149 static const GLuint n_subroutine_uniforms = sizeof(subroutine_indices) / sizeof(subroutine_indices[0]);
4150
4151 /* Prepare subroutine uniform data */
4152 for (GLuint i = 0; i < n_subroutine_uniforms; ++i)
4153 {
4154 const GLuint location = m_subroutine_uniform_locations[i][0];
4155
4156 subroutine_indices[location] = m_subroutine_indices[i][subroutine_combination[i]];
4157 }
4158
4159 /* Set up subroutine uniforms */
4160 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, n_subroutine_uniforms, &subroutine_indices[0]);
4161 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
4162
4163 /* Set up input data uniforms */
4164 for (GLuint i = 0; i < n_uniforms; ++i)
4165 {
4166 gl.uniform4f(m_uniform_locations[i], input_data[i].m_x, input_data[i].m_y, input_data[i].m_z,
4167 input_data[i].m_w);
4168 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
4169 }
4170
4171 /* Execute draw call with transform feedback */
4172 gl.beginTransformFeedback(GL_POINTS);
4173 GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
4174
4175 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
4176 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
4177
4178 gl.endTransformFeedback();
4179 GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
4180
4181 /* Capture results */
4182 GLvoid *feedback_data = gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
4183 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
4184
4185 GLfloat *float_ptr = (GLfloat *)feedback_data;
4186
4187 /* First result */
4188 out_first_routine_result.m_x = float_ptr[0];
4189 out_first_routine_result.m_y = float_ptr[1];
4190 out_first_routine_result.m_z = float_ptr[2];
4191 out_first_routine_result.m_w = float_ptr[3];
4192
4193 /* Second result */
4194 out_second_routine_result.m_x = float_ptr[4];
4195 out_second_routine_result.m_y = float_ptr[5];
4196 out_second_routine_result.m_z = float_ptr[6];
4197 out_second_routine_result.m_w = float_ptr[7];
4198
4199 /* Third result */
4200 out_third_routine_result.m_x = float_ptr[8];
4201 out_third_routine_result.m_y = float_ptr[9];
4202 out_third_routine_result.m_z = float_ptr[10];
4203 out_third_routine_result.m_w = float_ptr[11];
4204
4205 /* Fourth result */
4206 GLuint *uint_ptr = (GLuint *)(float_ptr + 12);
4207 out_fourth_routine_result.m_x = uint_ptr[0];
4208 out_fourth_routine_result.m_y = uint_ptr[1];
4209 out_fourth_routine_result.m_z = uint_ptr[2];
4210 out_fourth_routine_result.m_w = uint_ptr[3];
4211
4212 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
4213 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
4214 }
4215
4216 /** Verify if results match expected results
4217 *
4218 * @param first_routine_result Result of first routine
4219 * @param second_routine_result Result of second routine
4220 * @param third_routine_result Result of third routine
4221 * @param fourth_routine_result Result of fourth routine
4222 * @param first_routine_expected_result Expected result of first routine
4223 * @param second_routine_expected_result Expected result of second routine
4224 * @param third_routine_expected_result Expected result of third routine
4225 * @param fourth_routine_expected_result Expected result of fourth routine
4226 **/
verify(const Utils::vec4<glw::GLfloat> & first_routine_result,const Utils::vec4<glw::GLfloat> & second_routine_result,const Utils::vec4<glw::GLfloat> & third_routine_result,const Utils::vec4<glw::GLuint> & fourth_routine_result,const Utils::vec4<glw::GLfloat> & first_routine_expected_result,const Utils::vec4<glw::GLfloat> & second_routine_expected_result,const Utils::vec4<glw::GLfloat> & third_routine_expected_result,const Utils::vec4<glw::GLuint> & fourth_routine_expected_result) const4227 bool FunctionalTest5::verify(const Utils::vec4<glw::GLfloat> &first_routine_result,
4228 const Utils::vec4<glw::GLfloat> &second_routine_result,
4229 const Utils::vec4<glw::GLfloat> &third_routine_result,
4230 const Utils::vec4<glw::GLuint> &fourth_routine_result,
4231 const Utils::vec4<glw::GLfloat> &first_routine_expected_result,
4232 const Utils::vec4<glw::GLfloat> &second_routine_expected_result,
4233 const Utils::vec4<glw::GLfloat> &third_routine_expected_result,
4234 const Utils::vec4<glw::GLuint> &fourth_routine_expected_result) const
4235 {
4236 bool result = true;
4237
4238 result = result && (first_routine_result == first_routine_expected_result);
4239 result = result && (second_routine_result == second_routine_expected_result);
4240 result = result && (third_routine_result == third_routine_expected_result);
4241 result = result && (fourth_routine_result == fourth_routine_expected_result);
4242
4243 return result;
4244 }
4245
4246 /** Constructor
4247 *
4248 * @param context CTS context
4249 **/
FunctionalTest6(deqp::Context & context)4250 FunctionalTest6::FunctionalTest6(deqp::Context &context)
4251 : TestCase(context, "static_subroutine_call", "Verify that subroutine can be called in a static manner")
4252 {
4253 }
4254
4255 /** Execute test
4256 *
4257 * @return tcu::TestNode::STOP
4258 **/
iterate()4259 tcu::TestNode::IterateResult FunctionalTest6::iterate()
4260 {
4261 static const GLchar *vertex_shader_code = "#version 400 core\n"
4262 "#extension GL_ARB_shader_subroutine : require\n"
4263 "\n"
4264 "precision highp float;\n"
4265 "\n"
4266 "// Subroutine type\n"
4267 "subroutine vec4 routine_type(in vec4 iparam);\n"
4268 "\n"
4269 "// Subroutine definition\n"
4270 "subroutine(routine_type) vec4 square(in vec4 iparam)\n"
4271 "{\n"
4272 " return iparam * iparam;\n"
4273 "}\n"
4274 "\n"
4275 "// Sub routine uniform\n"
4276 "subroutine uniform routine_type routine;\n"
4277 "\n"
4278 "// Input data\n"
4279 "uniform vec4 input_data;\n"
4280 "\n"
4281 "// Output\n"
4282 "out vec4 out_result;\n"
4283 "\n"
4284 "void main()\n"
4285 "{\n"
4286 " out_result = square(input_data);\n"
4287 "}\n"
4288 "\n";
4289
4290 static const GLchar *varying_name = "out_result";
4291
4292 /* Test data */
4293 static const Utils::vec4<GLfloat> input_data(1.0f, 4.0f, 9.0f, 16.0f);
4294
4295 static const Utils::vec4<GLfloat> expected_result(1.0f, 16.0f, 81.0f, 256.0f);
4296
4297 static const GLuint transform_feedback_buffer_size = 4 * sizeof(GLfloat);
4298
4299 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
4300 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
4301 {
4302 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
4303 }
4304
4305 /* GL objects */
4306 Utils::program program(m_context);
4307 Utils::buffer transform_feedback_buffer(m_context);
4308 Utils::vertexArray vao(m_context);
4309
4310 /* Init GL objects */
4311 program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code, &varying_name,
4312 1 /* n_varyings */);
4313
4314 program.use();
4315
4316 vao.generate();
4317 vao.bind();
4318
4319 transform_feedback_buffer.generate();
4320 transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
4321 GL_DYNAMIC_COPY);
4322 transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
4323
4324 /* Test */
4325 {
4326 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
4327 const GLint uniform_location = gl.getUniformLocation(program.m_program_object_id, "input_data");
4328
4329 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation");
4330
4331 if (-1 == uniform_location)
4332 {
4333 TCU_FAIL("Uniform is not available");
4334 }
4335
4336 /* Set up input data uniforms */
4337 gl.uniform4f(uniform_location, input_data.m_x, input_data.m_y, input_data.m_z, input_data.m_w);
4338 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
4339
4340 /* Execute draw call with transform feedback */
4341 gl.beginTransformFeedback(GL_POINTS);
4342 GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
4343
4344 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
4345 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
4346
4347 gl.endTransformFeedback();
4348 GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
4349
4350 /* Capture results */
4351 GLfloat *feedback_data = (GLfloat *)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
4352 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
4353
4354 Utils::vec4<GLfloat> result(feedback_data[0], feedback_data[1], feedback_data[2], feedback_data[3]);
4355
4356 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
4357 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
4358
4359 /* Verify */
4360 if (expected_result == result)
4361 {
4362 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4363 }
4364 else
4365 {
4366 m_context.getTestContext().getLog()
4367 << tcu::TestLog::Message << "Error. Invalid result." << tcu::TestLog::EndMessage;
4368
4369 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4370
4371 message << "Function: square( ";
4372 input_data.log(message);
4373 message << " ). Result: ";
4374 result.log(message);
4375 message << ". Expected: ";
4376 expected_result.log(message);
4377
4378 message << tcu::TestLog::EndMessage;
4379
4380 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
4381 }
4382 }
4383
4384 /* Done */
4385 return tcu::TestNode::STOP;
4386 }
4387
4388 /** Constructor
4389 *
4390 * @param context CTS context
4391 **/
FunctionalTest7_8(deqp::Context & context)4392 FunctionalTest7_8::FunctionalTest7_8(deqp::Context &context)
4393 : TestCase(context, "arrayed_subroutine_uniforms", "Verify that subroutine can be called in a static manner")
4394 {
4395 }
4396
4397 /** Execute test
4398 *
4399 * @return tcu::TestNode::STOP
4400 **/
iterate()4401 tcu::TestNode::IterateResult FunctionalTest7_8::iterate()
4402 {
4403 static const GLchar *vertex_shader_code =
4404 "#version 400 core\n"
4405 "#extension GL_ARB_shader_subroutine : require\n"
4406 "\n"
4407 "precision highp float;\n"
4408 "\n"
4409 "// Subroutine type\n"
4410 "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n"
4411 "\n"
4412 "// Subroutine definitions\n"
4413 "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n"
4414 "{\n"
4415 " return left + right;\n"
4416 "}\n"
4417 "\n"
4418 "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n"
4419 "{\n"
4420 " return left * right;\n"
4421 "}\n"
4422 "\n"
4423 "// Sub routine uniform\n"
4424 "subroutine uniform routine_type routine[4];\n"
4425 "\n"
4426 "// Input data\n"
4427 "uniform vec4 uni_left;\n"
4428 "uniform vec4 uni_right;\n"
4429 "uniform uvec4 uni_indices;\n"
4430 "\n"
4431 "// Output\n"
4432 "out vec4 out_combined;\n"
4433 "out vec4 out_combined_inverted;\n"
4434 "out vec4 out_constant;\n"
4435 "out vec4 out_constant_inverted;\n"
4436 "out vec4 out_dynamic;\n"
4437 "out vec4 out_dynamic_inverted;\n"
4438 "out vec4 out_loop;\n"
4439 "out uint out_array_length;\n"
4440 "\n"
4441 "void main()\n"
4442 "{\n"
4443 " out_combined = routine[3](routine[2](routine[1](routine[0](uni_left, uni_right), uni_right), "
4444 "uni_right), uni_right);\n"
4445 " out_combined_inverted = routine[0](routine[1](routine[2](routine[3](uni_left, uni_right), uni_right), "
4446 "uni_right), uni_right);\n"
4447 " \n"
4448 " out_constant = routine[3](routine[2](routine[1](routine[0](vec4(1, 2, 3, 4), vec4(-5, -6, -7, "
4449 "-8)), vec4(-1, -2, -3, -4)), vec4(5, 6, 7, 8)), vec4(1, 2, 3, 4));\n"
4450 " out_constant_inverted = routine[0](routine[1](routine[2](routine[3](vec4(1, 2, 3, 4), vec4(-5, -6, -7, "
4451 "-8)), vec4(-1, -2, -3, -4)), vec4(5, 6, 7, 8)), vec4(1, 2, 3, 4));\n"
4452 " \n"
4453 " out_dynamic = "
4454 "routine[uni_indices.w](routine[uni_indices.z](routine[uni_indices.y](routine[uni_indices.x](uni_left, "
4455 "uni_right), uni_right), uni_right), uni_right);\n"
4456 " out_dynamic_inverted = "
4457 "routine[uni_indices.x](routine[uni_indices.y](routine[uni_indices.z](routine[uni_indices.w](uni_left, "
4458 "uni_right), uni_right), uni_right), uni_right);\n"
4459 " \n"
4460 " out_loop = uni_left;\n"
4461 " for (uint i = 0u; i < routine.length(); ++i)\n"
4462 " {\n"
4463 " out_loop = routine[i](out_loop, uni_right);\n"
4464 " }\n"
4465 " \n"
4466 " out_array_length = routine.length() + 6 - (uni_indices.x + uni_indices.y + uni_indices.z + "
4467 "uni_indices.w);\n"
4468 "}\n"
4469 "\n";
4470
4471 static const GLchar *subroutine_names[] = {
4472 "add",
4473 "multiply",
4474 };
4475 static const GLuint n_subroutine_names = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
4476
4477 static const GLchar *subroutine_uniform_names[] = {"routine[0]", "routine[1]", "routine[2]", "routine[3]"};
4478 static const GLuint n_subroutine_uniform_names =
4479 sizeof(subroutine_uniform_names) / sizeof(subroutine_uniform_names[0]);
4480
4481 static const GLchar *uniform_names[] = {
4482 "uni_left",
4483 "uni_right",
4484 "uni_indices",
4485 };
4486 static const GLuint n_uniform_names = sizeof(uniform_names) / sizeof(uniform_names[0]);
4487
4488 static const GLchar *varying_names[] = {
4489 "out_combined", "out_combined_inverted", "out_constant", "out_constant_inverted",
4490 "out_dynamic", "out_dynamic_inverted", "out_loop", "out_array_length"};
4491
4492 static const GLuint n_varyings = sizeof(varying_names) / sizeof(varying_names[0]);
4493 static const GLuint transform_feedback_buffer_size = n_varyings * 4 * sizeof(GLfloat);
4494
4495 /* Test data */
4496 static const Utils::vec4<GLfloat> uni_left(-1.0f, 0.75f, -0.5f, 0.25f);
4497 static const Utils::vec4<GLfloat> uni_right(1.0f, -0.75f, 0.5f, -0.25f);
4498 static const Utils::vec4<GLuint> uni_indices(1, 2, 0, 3);
4499
4500 static const GLuint subroutine_combinations[][4] = {
4501 {0, 0, 0, 0}, /* + + + + */
4502 {0, 0, 0, 1}, /* + + + * */
4503 {0, 0, 1, 0}, /* + + * + */
4504 {0, 0, 1, 1}, /* + + * * */
4505 {0, 1, 0, 0}, /* + * + + */
4506 {0, 1, 0, 1}, /* + * + * */
4507 {0, 1, 1, 0}, /* + * * + */
4508 {0, 1, 1, 1}, /* + * * * */
4509 {1, 0, 0, 0}, /* * + + + */
4510 {1, 0, 0, 1}, /* * + + * */
4511 {1, 0, 1, 0}, /* * + * + */
4512 {1, 0, 1, 1}, /* * + * * */
4513 {1, 1, 0, 0}, /* * * + + */
4514 {1, 1, 0, 1}, /* * * + * */
4515 {1, 1, 1, 0}, /* * * * + */
4516 {1, 1, 1, 1} /* * * * * */
4517 };
4518 static const GLuint n_subroutine_combinations =
4519 sizeof(subroutine_combinations) / sizeof(subroutine_combinations[0]);
4520
4521 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
4522 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
4523 {
4524 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
4525 }
4526
4527 /* GL objects */
4528 Utils::program program(m_context);
4529 Utils::buffer transform_feedback_buffer(m_context);
4530 Utils::vertexArray vao(m_context);
4531
4532 bool result = true;
4533
4534 /* Init GL objects */
4535 program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code, varying_names,
4536 n_varyings);
4537
4538 program.use();
4539
4540 vao.generate();
4541 vao.bind();
4542
4543 transform_feedback_buffer.generate();
4544
4545 /* Get subroutine indices */
4546 for (GLuint routine = 0; routine < n_subroutine_names; ++routine)
4547 {
4548 m_subroutine_indices[routine] = program.getSubroutineIndex(subroutine_names[routine], GL_VERTEX_SHADER);
4549 }
4550
4551 /* Get subroutine uniform locations */
4552 for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
4553 {
4554 m_subroutine_uniform_locations[uniform] =
4555 program.getSubroutineUniformLocation(subroutine_uniform_names[uniform], GL_VERTEX_SHADER);
4556 }
4557
4558 /* Get uniform locations */
4559 for (GLuint i = 0; i < n_uniform_names; ++i)
4560 {
4561 m_uniform_locations[i] = program.getUniformLocation(uniform_names[i]);
4562 }
4563
4564 /* Test */
4565 for (GLuint i = 0; i < n_subroutine_combinations; ++i)
4566 {
4567 /* Clean */
4568 transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
4569 GL_DYNAMIC_COPY);
4570 transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
4571
4572 /* Verify */
4573 if (false == testDraw(subroutine_combinations[i], uni_left, uni_right, uni_indices))
4574 {
4575 result = false;
4576 }
4577 }
4578
4579 if (true == result)
4580 {
4581 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4582 }
4583 else
4584 {
4585 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
4586 }
4587
4588 /* Done */
4589 return tcu::TestNode::STOP;
4590 }
4591
4592 /* Calculate result of function applied to operands
4593 *
4594 * @param function Function id, 0 is sum, 1 is multiplication
4595 * @param left Left operand
4596 * @param right Right operand
4597 * @param out Function result
4598 **/
calculate(glw::GLuint function,const Utils::vec4<glw::GLfloat> & left,const Utils::vec4<glw::GLfloat> & right,Utils::vec4<glw::GLfloat> & out) const4599 void FunctionalTest7_8::calculate(glw::GLuint function, const Utils::vec4<glw::GLfloat> &left,
4600 const Utils::vec4<glw::GLfloat> &right, Utils::vec4<glw::GLfloat> &out) const
4601 {
4602 if (0 == function)
4603 {
4604 out.m_x = left.m_x + right.m_x;
4605 out.m_y = left.m_y + right.m_y;
4606 out.m_z = left.m_z + right.m_z;
4607 out.m_w = left.m_w + right.m_w;
4608 }
4609 else
4610 {
4611 out.m_x = left.m_x * right.m_x;
4612 out.m_y = left.m_y * right.m_y;
4613 out.m_z = left.m_z * right.m_z;
4614 out.m_w = left.m_w * right.m_w;
4615 }
4616 }
4617
4618 /** Calculate expected values for all operations
4619 *
4620 * @param combination Function combination, first applied function is at index [0]
4621 * @param left Left operand
4622 * @param right Right operand
4623 * @param indices Indices used by dynamic calls
4624 * @param out_combined Expected result of "combined" operation
4625 * @param out_combined_inverted Expected result of "combined_inverted" operation
4626 * @param out_constant Expected result of "constant" operation
4627 * @param out_constant_inverted Expected result of "constant_inverted" operation
4628 * @param out_dynamic Expected result of "dynamic" operation
4629 * @param out_dynamic_inverted Expected result of "out_dynamic_inverted" operation
4630 * @param out_loop Expected result of "loop" operation
4631 **/
calculate(const glw::GLuint combination[4],const Utils::vec4<glw::GLfloat> & left,const Utils::vec4<glw::GLfloat> & right,const Utils::vec4<glw::GLuint> & indices,Utils::vec4<glw::GLfloat> & out_combined,Utils::vec4<glw::GLfloat> & out_combined_inverted,Utils::vec4<glw::GLfloat> & out_constant,Utils::vec4<glw::GLfloat> & out_constant_inverted,Utils::vec4<glw::GLfloat> & out_dynamic,Utils::vec4<glw::GLfloat> & out_dynamic_inverted,Utils::vec4<glw::GLfloat> & out_loop) const4632 void FunctionalTest7_8::calculate(
4633 const glw::GLuint combination[4], const Utils::vec4<glw::GLfloat> &left, const Utils::vec4<glw::GLfloat> &right,
4634 const Utils::vec4<glw::GLuint> &indices, Utils::vec4<glw::GLfloat> &out_combined,
4635 Utils::vec4<glw::GLfloat> &out_combined_inverted, Utils::vec4<glw::GLfloat> &out_constant,
4636 Utils::vec4<glw::GLfloat> &out_constant_inverted, Utils::vec4<glw::GLfloat> &out_dynamic,
4637 Utils::vec4<glw::GLfloat> &out_dynamic_inverted, Utils::vec4<glw::GLfloat> &out_loop) const
4638 {
4639 /* Indices used by "dynamic" operations, range <0..4> */
4640 const GLuint dynamic_combination[4] = {combination[indices.m_x], combination[indices.m_y], combination[indices.m_z],
4641 combination[indices.m_w]};
4642
4643 /* Values used by "constant" operations, come from shader code */
4644 const Utils::vec4<glw::GLfloat> constant_values[] = {
4645 Utils::vec4<glw::GLfloat>(1, 2, 3, 4), Utils::vec4<glw::GLfloat>(-5, -6, -7, -8),
4646 Utils::vec4<glw::GLfloat>(-1, -2, -3, -4), Utils::vec4<glw::GLfloat>(5, 6, 7, 8),
4647 Utils::vec4<glw::GLfloat>(1, 2, 3, 4)};
4648
4649 /* Start values */
4650 Utils::vec4<glw::GLfloat> combined = left;
4651 Utils::vec4<glw::GLfloat> combined_inverted = left;
4652 Utils::vec4<glw::GLfloat> constant = constant_values[0];
4653 Utils::vec4<glw::GLfloat> constant_inverted = constant_values[0];
4654 Utils::vec4<glw::GLfloat> dynamic = left;
4655 Utils::vec4<glw::GLfloat> dynamic_inverted = left;
4656
4657 /* Calculate expected results */
4658 for (GLuint i = 0; i < 4; ++i)
4659 {
4660 GLuint function = combination[i];
4661 GLuint function_inverted = combination[3 - i];
4662 GLuint dynamic_function = dynamic_combination[i];
4663 GLuint dynamic_function_inverted = dynamic_combination[3 - i];
4664
4665 calculate(function, combined, right, combined);
4666 calculate(function_inverted, combined_inverted, right, combined_inverted);
4667 calculate(function, constant, constant_values[i + 1], constant);
4668 calculate(function_inverted, constant_inverted, constant_values[i + 1], constant_inverted);
4669 calculate(dynamic_function, dynamic, right, dynamic);
4670 calculate(dynamic_function_inverted, dynamic_inverted, right, dynamic_inverted);
4671 }
4672
4673 /* Store results */
4674 out_combined = combined;
4675 out_combined_inverted = combined_inverted;
4676 out_constant = constant;
4677 out_constant_inverted = constant_inverted;
4678 out_dynamic = dynamic;
4679 out_dynamic_inverted = dynamic_inverted;
4680 out_loop = combined;
4681 }
4682
4683 /** Log error
4684 *
4685 * @param combination Operations combination
4686 * @param left Left operand
4687 * @param right Right operand
4688 * @param indices Inidices used by "dynamic" calls
4689 * @param vec4_expected Expected results
4690 * @param vec4_result Results
4691 * @param array_length Length of array
4692 * @param result Comparison results
4693 **/
logError(const glw::GLuint combination[4],const Utils::vec4<glw::GLfloat> & left,const Utils::vec4<glw::GLfloat> & right,const Utils::vec4<glw::GLuint> & indices,const Utils::vec4<glw::GLfloat> vec4_expected[7],const Utils::vec4<glw::GLfloat> vec4_result[7],glw::GLuint array_length,bool result[7]) const4694 void FunctionalTest7_8::logError(const glw::GLuint combination[4], const Utils::vec4<glw::GLfloat> &left,
4695 const Utils::vec4<glw::GLfloat> &right, const Utils::vec4<glw::GLuint> &indices,
4696 const Utils::vec4<glw::GLfloat> vec4_expected[7],
4697 const Utils::vec4<glw::GLfloat> vec4_result[7], glw::GLuint array_length,
4698 bool result[7]) const
4699 {
4700 static const GLuint n_functions = 4;
4701 static const GLuint n_operations = 7;
4702
4703 /* Indices used by "dynamic" operations, range <0..4> */
4704 const GLuint dynamic_combination[4] = {combination[indices.m_x], combination[indices.m_y], combination[indices.m_z],
4705 combination[indices.m_w]};
4706
4707 /* Function symbols */
4708 GLchar functions[4];
4709 GLchar functions_inverted[4];
4710 GLchar functions_dynamic[4];
4711 GLchar functions_dynamic_inverted[4];
4712
4713 for (GLuint i = 0; i < n_functions; ++i)
4714 {
4715 GLchar function = (0 == combination[i]) ? '+' : '*';
4716 GLchar dynamic_function = (0 == dynamic_combination[i]) ? '+' : '*';
4717
4718 functions[i] = function;
4719 functions_inverted[n_functions - i - 1] = function;
4720 functions_dynamic[i] = dynamic_function;
4721 functions_dynamic_inverted[n_functions - i - 1] = dynamic_function;
4722 }
4723
4724 /* Values used by "constant" operations, come from shader code */
4725 const Utils::vec4<glw::GLfloat> constant_values[] = {
4726 Utils::vec4<glw::GLfloat>(1, 2, 3, 4), Utils::vec4<glw::GLfloat>(-5, -6, -7, -8),
4727 Utils::vec4<glw::GLfloat>(-1, -2, -3, -4), Utils::vec4<glw::GLfloat>(5, 6, 7, 8),
4728 Utils::vec4<glw::GLfloat>(1, 2, 3, 4)};
4729
4730 /* Values used by non-"constant" operations */
4731 Utils::vec4<glw::GLfloat> dynamic_values[5];
4732 dynamic_values[0] = left;
4733 dynamic_values[1] = right;
4734 dynamic_values[2] = right;
4735 dynamic_values[3] = right;
4736 dynamic_values[4] = right;
4737
4738 /* For each operation */
4739 for (GLuint i = 0; i < n_operations; ++i)
4740 {
4741 /* If result is failure */
4742 if (false == result[i])
4743 {
4744 const GLchar *description = 0;
4745 const Utils::vec4<glw::GLfloat> *input = 0;
4746 const GLchar *operation = 0;
4747
4748 switch (i)
4749 {
4750 case 0:
4751 description = "Call made with predefined array indices";
4752 input = dynamic_values;
4753 operation = functions;
4754 break;
4755 case 1:
4756 description = "Call made with predefined array indices in inverted order";
4757 input = dynamic_values;
4758 operation = functions_inverted;
4759 break;
4760 case 2:
4761 description = "Call made with predefined array indices, for constant values";
4762 input = constant_values;
4763 operation = functions;
4764 break;
4765 case 3:
4766 description = "Call made with predefined array indices in inverted order, for constant values";
4767 input = constant_values;
4768 operation = functions_inverted;
4769 break;
4770 case 4:
4771 description = "Call made with dynamic array indices";
4772 input = dynamic_values;
4773 operation = functions_dynamic;
4774 break;
4775 case 5:
4776 description = "Call made with dynamic array indices in inverted order";
4777 input = dynamic_values;
4778 operation = functions_dynamic_inverted;
4779 break;
4780 case 6:
4781 description = "Call made with loop";
4782 input = dynamic_values;
4783 operation = functions;
4784 break;
4785 }
4786
4787 m_context.getTestContext().getLog()
4788 << tcu::TestLog::Message << "Error. Invalid result." << tcu::TestLog::EndMessage;
4789
4790 m_context.getTestContext().getLog() << tcu::TestLog::Message << description << tcu::TestLog::EndMessage;
4791
4792 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4793
4794 message << "Operation: ((((";
4795 input[0].log(message);
4796 for (GLuint function = 0; function < n_functions; ++function)
4797 {
4798 message << " " << operation[function] << " ";
4799
4800 input[function + 1].log(message);
4801
4802 message << ")";
4803 }
4804
4805 message << tcu::TestLog::EndMessage;
4806
4807 message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4808
4809 message << "Result: ";
4810 vec4_result[i].log(message);
4811
4812 message << tcu::TestLog::EndMessage;
4813
4814 message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4815
4816 message << "Expected: ";
4817 vec4_expected[i].log(message);
4818
4819 message << tcu::TestLog::EndMessage;
4820 }
4821
4822 /* Check array length, it should be 4 */
4823 if (4 != array_length)
4824 {
4825 m_context.getTestContext().getLog()
4826 << tcu::TestLog::Message << "Error. Invalid array length: " << array_length << ". Expected 4."
4827 << tcu::TestLog::EndMessage;
4828 }
4829 }
4830 }
4831
4832 /** Execute draw call and verifies captrued varyings
4833 *
4834 * @param combination Function combination, first applied function is at index [0]
4835 * @param left Left operand
4836 * @param right Right operand
4837 * @param indices Indices used by dynamic calls
4838 *
4839 * @return true if all results match expected values, false otherwise
4840 **/
testDraw(const glw::GLuint combination[4],const Utils::vec4<glw::GLfloat> & left,const Utils::vec4<glw::GLfloat> & right,const Utils::vec4<glw::GLuint> & indices) const4841 bool FunctionalTest7_8::testDraw(const glw::GLuint combination[4], const Utils::vec4<glw::GLfloat> &left,
4842 const Utils::vec4<glw::GLfloat> &right, const Utils::vec4<glw::GLuint> &indices) const
4843 {
4844 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
4845 static const GLuint n_vec4_varyings = 7;
4846 bool result = true;
4847 GLuint subroutine_indices[4];
4848 static const GLuint n_subroutine_uniforms = sizeof(subroutine_indices) / sizeof(subroutine_indices[0]);
4849
4850 /* Prepare expected results */
4851 Utils::vec4<glw::GLfloat> expected_results[7];
4852 calculate(combination, left, right, indices, expected_results[0], expected_results[1], expected_results[2],
4853 expected_results[3], expected_results[4], expected_results[5], expected_results[6]);
4854
4855 /* Set up input data uniforms */
4856 gl.uniform4f(m_uniform_locations[0], left.m_x, left.m_y, left.m_z, left.m_w);
4857 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
4858
4859 gl.uniform4f(m_uniform_locations[1], right.m_x, right.m_y, right.m_z, right.m_w);
4860 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
4861
4862 gl.uniform4ui(m_uniform_locations[2], indices.m_x, indices.m_y, indices.m_z, indices.m_w);
4863 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4ui");
4864
4865 /* Prepare subroutine uniform data */
4866 for (GLuint i = 0; i < n_subroutine_uniforms; ++i)
4867 {
4868 const GLuint location = m_subroutine_uniform_locations[i];
4869
4870 subroutine_indices[location] = m_subroutine_indices[combination[i]];
4871 }
4872
4873 /* Set up subroutine uniforms */
4874 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, n_subroutine_uniforms, &subroutine_indices[0]);
4875 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
4876
4877 /* Execute draw call with transform feedback */
4878 gl.beginTransformFeedback(GL_POINTS);
4879 GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
4880
4881 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
4882 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
4883
4884 gl.endTransformFeedback();
4885 GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
4886
4887 /* Capture results */
4888 GLvoid *feedback_data = (GLvoid *)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
4889 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
4890
4891 Utils::vec4<GLfloat> vec4_results[7];
4892 bool results[7];
4893 GLfloat *float_data = (GLfloat *)feedback_data;
4894 for (GLuint i = 0; i < n_vec4_varyings; ++i)
4895 {
4896 vec4_results[i].m_x = float_data[i * 4 + 0];
4897 vec4_results[i].m_y = float_data[i * 4 + 1];
4898 vec4_results[i].m_z = float_data[i * 4 + 2];
4899 vec4_results[i].m_w = float_data[i * 4 + 3];
4900 }
4901
4902 GLuint *uint_data = (GLuint *)(float_data + (n_vec4_varyings)*4);
4903 GLuint array_length = uint_data[0];
4904
4905 /* Unmap buffer */
4906 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
4907 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
4908
4909 /* Verification */
4910 for (GLuint i = 0; i < n_vec4_varyings; ++i)
4911 {
4912 results[i] = (vec4_results[i] == expected_results[i]);
4913 result = result && results[i];
4914 }
4915
4916 result = result && (4 == array_length);
4917
4918 /* Log error if any */
4919 if (false == result)
4920 {
4921 logError(combination, left, right, indices, expected_results, vec4_results, array_length, results);
4922 }
4923
4924 /* Done */
4925 return result;
4926 }
4927
4928 /** Constructor.
4929 *
4930 * @param context Rendering context.
4931 *
4932 **/
FunctionalTest9(deqp::Context & context)4933 FunctionalTest9::FunctionalTest9(deqp::Context &context)
4934 : TestCase(context, "subroutines_3_subroutine_types_and_subroutine_uniforms_one_function",
4935 "Makes sure that program with one function associated with 3 different "
4936 "subroutine types and 3 subroutine uniforms using that function compiles "
4937 "and works as expected")
4938 , m_has_test_passed(true)
4939 , m_n_points_to_draw(16) /* arbitrary value */
4940 , m_po_id(0)
4941 , m_vao_id(0)
4942 , m_vs_id(0)
4943 , m_xfb_bo_id(0)
4944 {
4945 /* Left blank intentionally */
4946 }
4947
4948 /** De-initializes GL objects that may have been created during test execution. */
deinit()4949 void FunctionalTest9::deinit()
4950 {
4951 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
4952
4953 if (m_po_id != 0)
4954 {
4955 gl.deleteProgram(m_po_id);
4956
4957 m_po_id = 0;
4958 }
4959
4960 if (m_vao_id != 0)
4961 {
4962 gl.deleteVertexArrays(1, &m_vao_id);
4963
4964 m_vao_id = 0;
4965 }
4966
4967 if (m_vs_id != 0)
4968 {
4969 gl.deleteShader(m_vs_id);
4970
4971 m_vs_id = 0;
4972 }
4973
4974 if (m_xfb_bo_id != 0)
4975 {
4976 gl.deleteBuffers(1, &m_xfb_bo_id);
4977
4978 m_xfb_bo_id = 0;
4979 }
4980 }
4981
4982 /** Retrieves body of a vertex shader that should be used
4983 * for the testing purposes.
4984 **/
getVertexShaderBody() const4985 std::string FunctionalTest9::getVertexShaderBody() const
4986 {
4987 return "#version 400\n"
4988 "\n"
4989 "#extension GL_ARB_shader_subroutine : require\n"
4990 "\n"
4991 "subroutine void subroutineType1(inout float);\n"
4992 "subroutine void subroutineType2(inout float);\n"
4993 "subroutine void subroutineType3(inout float);\n"
4994 "\n"
4995 "subroutine(subroutineType1, subroutineType2, subroutineType3) void function(inout float result)\n"
4996 "{\n"
4997 " result += float(0.123) + float(gl_VertexID);\n"
4998 "}\n"
4999 "\n"
5000 "subroutine uniform subroutineType1 subroutine_uniform1;\n"
5001 "subroutine uniform subroutineType2 subroutine_uniform2;\n"
5002 "subroutine uniform subroutineType3 subroutine_uniform3;\n"
5003 "\n"
5004 "out vec4 result;\n"
5005 "\n"
5006 "void main()\n"
5007 "{\n"
5008 " result = vec4(0, 1, 2, 3);\n"
5009 "\n"
5010 " subroutine_uniform1(result.x);\n"
5011 " subroutine_uniform2(result.y);\n"
5012 " subroutine_uniform3(result.z);\n"
5013 "\n"
5014 " result.w += result.x + result.y + result.z;\n"
5015 "}\n";
5016 }
5017
5018 /** Initializes all GL objects required to run the test. */
initTest()5019 void FunctionalTest9::initTest()
5020 {
5021 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
5022
5023 /* Set up program object */
5024 const char *xfb_varyings[] = {"result"};
5025
5026 const unsigned int n_xfb_varyings = sizeof(xfb_varyings) / sizeof(xfb_varyings[0]);
5027 if (!Utils::buildProgram(gl, getVertexShaderBody(), "", /* tc_body */
5028 "", /* te_body */
5029 "", /* gs_body */
5030 "", /* fs_body */
5031 xfb_varyings, n_xfb_varyings, &m_vs_id, DE_NULL, /* out_tc_id */
5032 DE_NULL, /* out_te_id */
5033 DE_NULL, /* out_gs_id */
5034 DE_NULL, /* out_fs_id */
5035 &m_po_id))
5036 {
5037 TCU_FAIL("Program failed to link successfully");
5038 }
5039
5040 /* Set up a buffer object we will use to hold XFB data */
5041 const unsigned int xfb_bo_size = static_cast<unsigned int>(sizeof(float) * 4 /* components */ * m_n_points_to_draw);
5042
5043 gl.genBuffers(1, &m_xfb_bo_id);
5044 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
5045
5046 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_xfb_bo_id);
5047 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
5048
5049 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_xfb_bo_id);
5050 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed.");
5051
5052 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_bo_size, DE_NULL, /* data */
5053 GL_STATIC_COPY);
5054 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
5055
5056 /* Generate & bind a VAO */
5057 gl.genVertexArrays(1, &m_vao_id);
5058 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
5059
5060 gl.bindVertexArray(m_vao_id);
5061 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
5062 }
5063
5064 /** Executes test iteration.
5065 *
5066 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
5067 */
iterate()5068 tcu::TestNode::IterateResult FunctionalTest9::iterate()
5069 {
5070 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
5071
5072 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
5073 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
5074 {
5075 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
5076 }
5077 initTest();
5078
5079 /* Issue a draw call to make use of the three subroutine uniforms that we've defined */
5080 gl.useProgram(m_po_id);
5081 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
5082
5083 gl.beginTransformFeedback(GL_POINTS);
5084 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed.");
5085 {
5086 gl.drawArrays(GL_POINTS, 0 /* first */, m_n_points_to_draw);
5087 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
5088 }
5089 gl.endTransformFeedback();
5090 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed.");
5091
5092 /* Map the XFB BO storage into process space */
5093 const glw::GLvoid *xfb_data_ptr = gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
5094 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer() call failed.");
5095
5096 verifyXFBData(xfb_data_ptr);
5097
5098 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
5099 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
5100
5101 /* All done */
5102 if (m_has_test_passed)
5103 {
5104 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5105 }
5106 else
5107 {
5108 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
5109 }
5110
5111 return STOP;
5112 }
5113
5114 /** Verifies the data XFBed out by the vertex shader. Should the data
5115 * be found invalid, m_has_test_passed will be set to false.
5116 *
5117 * @param data_ptr XFB data.
5118 **/
verifyXFBData(const glw::GLvoid * data_ptr)5119 void FunctionalTest9::verifyXFBData(const glw::GLvoid *data_ptr)
5120 {
5121 const float epsilon = 1e-5f;
5122 bool should_continue = true;
5123 const glw::GLfloat *traveller_ptr = (const glw::GLfloat *)data_ptr;
5124
5125 for (unsigned int n_point = 0; n_point < m_n_points_to_draw && should_continue; ++n_point)
5126 {
5127 tcu::Vec4 expected_result(0, 1, 2, 3);
5128
5129 for (unsigned int n_component = 0; n_component < 3 /* xyz */; ++n_component)
5130 {
5131 expected_result[n_component] += 0.123f + float(n_point);
5132 }
5133
5134 expected_result[3 /* w */] += expected_result[0] + expected_result[1] + expected_result[2];
5135
5136 if (de::abs(expected_result[0] - traveller_ptr[0]) > epsilon ||
5137 de::abs(expected_result[1] - traveller_ptr[1]) > epsilon ||
5138 de::abs(expected_result[2] - traveller_ptr[2]) > epsilon ||
5139 de::abs(expected_result[3] - traveller_ptr[3]) > epsilon)
5140 {
5141 m_testCtx.getLog() << tcu::TestLog::Message
5142 << "XFBed data is invalid. Expected:"
5143 "("
5144 << expected_result[0] << ", " << expected_result[1] << ", " << expected_result[2] << ", "
5145 << expected_result[3] << "), found:(" << traveller_ptr[0] << ", " << traveller_ptr[1]
5146 << ", " << traveller_ptr[2] << ", " << traveller_ptr[3] << ")."
5147 << tcu::TestLog::EndMessage;
5148
5149 m_has_test_passed = false;
5150 should_continue = false;
5151 }
5152
5153 traveller_ptr += 4; /* xyzw */
5154 } /* for (all rendered points) */
5155 }
5156
5157 /** Constructor
5158 *
5159 * @param context CTS context
5160 **/
FunctionalTest10(deqp::Context & context)5161 FunctionalTest10::FunctionalTest10(deqp::Context &context)
5162 : TestCase(context, "arrays_of_arrays_of_uniforms", "Verify that arrays of arrays of uniforms works as expected")
5163 {
5164 }
5165
5166 /** Execute test
5167 *
5168 * @return tcu::TestNode::STOP
5169 **/
iterate()5170 tcu::TestNode::IterateResult FunctionalTest10::iterate()
5171 {
5172 static const GLchar *vertex_shader_code = "#version 400 core\n"
5173 "#extension GL_ARB_arrays_of_arrays : require\n"
5174 "#extension GL_ARB_shader_subroutine : require\n"
5175 "\n"
5176 "precision highp float;\n"
5177 "\n"
5178 "// Subroutine type\n"
5179 "subroutine int routine_type(in int iparam);\n"
5180 "\n"
5181 "// Subroutine definitions\n"
5182 "subroutine(routine_type) int increment(in int iparam)\n"
5183 "{\n"
5184 " return iparam + 1;\n"
5185 "}\n"
5186 "\n"
5187 "subroutine(routine_type) int decrement(in int iparam)\n"
5188 "{\n"
5189 " return iparam - 1;\n"
5190 "}\n"
5191 "\n"
5192 "// Sub routine uniform\n"
5193 "subroutine uniform routine_type routine[4][4];\n"
5194 "\n"
5195 "// Output\n"
5196 "out int out_result;\n"
5197 "\n"
5198 "void main()\n"
5199 "{\n"
5200 " int result = 0;\n"
5201 " \n"
5202 " for (uint j = 0; j < routine.length(); ++j)\n"
5203 " {\n"
5204 " for (uint i = 0; i < routine[j].length(); ++i)\n"
5205 " {\n"
5206 " result = routine[j][i](result);\n"
5207 " }\n"
5208 " }\n"
5209 " \n"
5210 " out_result = result;\n"
5211 "}\n"
5212 "\n";
5213
5214 static const GLchar *subroutine_names[] = {
5215 "increment",
5216 "decrement",
5217 };
5218 static const GLuint n_subroutine_names = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
5219
5220 static const GLchar *subroutine_uniform_names[] = {
5221 "routine[0][0]", "routine[1][0]", "routine[2][0]", "routine[3][0]", "routine[0][1]", "routine[1][1]",
5222 "routine[2][1]", "routine[3][1]", "routine[0][2]", "routine[1][2]", "routine[2][2]", "routine[3][2]",
5223 "routine[0][3]", "routine[1][3]", "routine[2][3]", "routine[3][3]"};
5224 static const GLuint n_subroutine_uniform_names =
5225 sizeof(subroutine_uniform_names) / sizeof(subroutine_uniform_names[0]);
5226
5227 static const GLchar *varying_name = "out_result";
5228 static const GLuint transform_feedback_buffer_size = sizeof(GLint);
5229
5230 static const GLuint configuration_increment[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
5231
5232 static const GLuint configuration_decrement[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
5233
5234 static const GLuint configuration_mix[16] = {1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1};
5235
5236 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
5237 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
5238 {
5239 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
5240 }
5241
5242 /* Do not execute the test if GL_ARB_arrays_of_arrays is not supported */
5243 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_arrays_of_arrays"))
5244 {
5245 throw tcu::NotSupportedError("GL_ARB_arrays_of_arrays is not supported.");
5246 }
5247
5248 bool result = true;
5249
5250 /* GL objects */
5251 Utils::program program(m_context);
5252 Utils::buffer transform_feedback_buffer(m_context);
5253 Utils::vertexArray vao(m_context);
5254
5255 /* Init GL objects */
5256 program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code, &varying_name,
5257 1 /* n_varyings */);
5258
5259 program.use();
5260
5261 vao.generate();
5262 vao.bind();
5263
5264 transform_feedback_buffer.generate();
5265 transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
5266 GL_DYNAMIC_COPY);
5267 transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
5268
5269 /* Get subroutine indices */
5270 for (GLuint routine = 0; routine < n_subroutine_names; ++routine)
5271 {
5272 m_subroutine_indices[routine] = program.getSubroutineIndex(subroutine_names[routine], GL_VERTEX_SHADER);
5273 }
5274
5275 /* Get subroutine uniform locations */
5276 for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
5277 {
5278 m_subroutine_uniform_locations[uniform] =
5279 program.getSubroutineUniformLocation(subroutine_uniform_names[uniform], GL_VERTEX_SHADER);
5280 }
5281
5282 /* Test */
5283 GLint increment_result = testDraw(configuration_increment);
5284 GLint decrement_result = testDraw(configuration_decrement);
5285 GLint mix_result = testDraw(configuration_mix);
5286
5287 /* Verify */
5288 if (16 != increment_result)
5289 {
5290 result = false;
5291 }
5292
5293 if (-16 != decrement_result)
5294 {
5295 result = false;
5296 }
5297 if (0 != mix_result)
5298 {
5299 result = false;
5300 }
5301
5302 /* Set test result */
5303 if (true == result)
5304 {
5305 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5306 }
5307 else
5308 {
5309 m_context.getTestContext().getLog()
5310 << tcu::TestLog::Message << "Error. Invalid result."
5311 << " Incrementation applied 16 times: " << increment_result
5312 << ". Decrementation applied 16 times: " << decrement_result
5313 << ". Incrementation and decrementation applied 8 times: " << mix_result << tcu::TestLog::EndMessage;
5314
5315 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
5316 }
5317
5318 /* Done */
5319 return tcu::TestNode::STOP;
5320 }
5321
5322 /** Execute draw call and return captured varying
5323 *
5324 * @param routine_indices Configuration of subroutine uniforms
5325 *
5326 * @return Value of varying captured with transform feedback
5327 **/
testDraw(const GLuint routine_indices[16]) const5328 GLint FunctionalTest10::testDraw(const GLuint routine_indices[16]) const
5329 {
5330 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
5331 GLuint subroutine_indices[16];
5332 static const GLuint n_subroutine_uniforms = sizeof(subroutine_indices) / sizeof(subroutine_indices[0]);
5333
5334 /* Prepare subroutine uniform data */
5335 for (GLuint i = 0; i < n_subroutine_uniforms; ++i)
5336 {
5337 const GLuint location = m_subroutine_uniform_locations[i];
5338
5339 subroutine_indices[location] = m_subroutine_indices[routine_indices[i]];
5340 }
5341
5342 /* Set up subroutine uniforms */
5343 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, n_subroutine_uniforms, &subroutine_indices[0]);
5344 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
5345
5346 /* Execute draw call with transform feedback */
5347 gl.beginTransformFeedback(GL_POINTS);
5348 GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
5349
5350 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
5351 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
5352
5353 gl.endTransformFeedback();
5354 GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
5355
5356 /* Capture results */
5357 GLint *feedback_data = (GLint *)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
5358 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
5359
5360 GLint result = feedback_data[0];
5361
5362 /* Unmap buffer */
5363 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
5364 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
5365
5366 return result;
5367 }
5368
5369 /* Definitions of constants used by FunctionalTest11 */
5370 const GLuint FunctionalTest11::m_texture_height = 32;
5371 const GLuint FunctionalTest11::m_texture_width = 32;
5372
5373 /** Constructor
5374 *
5375 * @param context CTS context
5376 **/
FunctionalTest11(deqp::Context & context)5377 FunctionalTest11::FunctionalTest11(deqp::Context &context)
5378 : TestCase(context, "globals_sampling_output_discard_function_calls",
5379 "Verify that global variables, texture "
5380 "sampling, fragment output, fragment discard "
5381 "and function calls work as expected")
5382 {
5383 }
5384
5385 /** Execute test
5386 *
5387 * @return tcu::TestNode::STOP
5388 **/
iterate()5389 tcu::TestNode::IterateResult FunctionalTest11::iterate()
5390 {
5391 static const GLchar *fragment_shader_code =
5392 "#version 400 core\n"
5393 "#extension GL_ARB_shader_subroutine : require\n"
5394 "\n"
5395 "precision highp float;\n"
5396 "\n"
5397 "// Output\n"
5398 "layout(location = 0) out vec4 out_color;\n"
5399 "\n"
5400 "// Global variables\n"
5401 "vec4 success_color;\n"
5402 "vec4 failure_color;\n"
5403 "\n"
5404 "// Samplers\n"
5405 "uniform sampler2D sampler_1;\n"
5406 "uniform sampler2D sampler_2;\n"
5407 "\n"
5408 "// Functions\n"
5409 "bool are_same(in vec4 left, in vec4 right)\n"
5410 "{\n"
5411 " bvec4 result;\n"
5412 "\n"
5413 " result.x = (left.x == right.x);\n"
5414 " result.y = (left.y == right.y);\n"
5415 " result.z = (left.z == right.z);\n"
5416 " result.w = (left.w == right.w);\n"
5417 "\n"
5418 " return all(result);\n"
5419 "}\n"
5420 "\n"
5421 "bool are_different(in vec4 left, in vec4 right)\n"
5422 "{\n"
5423 " bvec4 result;\n"
5424 "\n"
5425 " result.x = (left.x != right.x);\n"
5426 " result.y = (left.y != right.y);\n"
5427 " result.z = (left.z != right.z);\n"
5428 " result.w = (left.w != right.w);\n"
5429 "\n"
5430 " return any(result);\n"
5431 "}\n"
5432 "\n"
5433 "// Subroutine types\n"
5434 "subroutine void discard_fragment_type(void);\n"
5435 "subroutine void set_global_colors_type(void);\n"
5436 "subroutine vec4 sample_texture_type(in vec2);\n"
5437 "subroutine bool comparison_type(in vec4 left, in vec4 right);\n"
5438 "subroutine void test_type(void);\n"
5439 "\n"
5440 "// Subroutine definitions\n"
5441 "// discard_fragment_type\n"
5442 "subroutine(discard_fragment_type) void discard_yes(void)\n"
5443 "{\n"
5444 " discard;\n"
5445 "}\n"
5446 "\n"
5447 "subroutine(discard_fragment_type) void discard_no(void)\n"
5448 "{\n"
5449 "}\n"
5450 "\n"
5451 "// set_global_colors_type\n"
5452 "subroutine(set_global_colors_type) void red_pass_blue_fail(void)\n"
5453 "{\n"
5454 " success_color = vec4(1, 0, 0, 1);\n"
5455 " failure_color = vec4(0, 0, 1, 1);\n"
5456 "}\n"
5457 "\n"
5458 "subroutine(set_global_colors_type) void blue_pass_red_fail(void)\n"
5459 "{\n"
5460 " success_color = vec4(0, 0, 1, 1);\n"
5461 " failure_color = vec4(1, 0, 0, 1);\n"
5462 "}\n"
5463 "\n"
5464 "// sample_texture_type\n"
5465 "subroutine(sample_texture_type) vec4 first_sampler(in vec2 coord)\n"
5466 "{\n"
5467 " return texture(sampler_1, coord);\n"
5468 "}\n"
5469 "\n"
5470 "subroutine(sample_texture_type) vec4 second_sampler(in vec2 coord)\n"
5471 "{\n"
5472 " return texture(sampler_2, coord);\n"
5473 "}\n"
5474 "\n"
5475 "// comparison_type\n"
5476 "subroutine(comparison_type) bool check_equal(in vec4 left, in vec4 right)\n"
5477 "{\n"
5478 " return are_same(left, right);\n"
5479 "}\n"
5480 "\n"
5481 "subroutine(comparison_type) bool check_not_equal(in vec4 left, in vec4 right)\n"
5482 "{\n"
5483 " return are_different(left, right);\n"
5484 "}\n"
5485 "\n"
5486 "// Subroutine uniforms\n"
5487 "subroutine uniform discard_fragment_type discard_fragment;\n"
5488 "subroutine uniform set_global_colors_type set_global_colors;\n"
5489 "subroutine uniform sample_texture_type sample_texture;\n"
5490 "subroutine uniform comparison_type compare;\n"
5491 "\n"
5492 "// Subroutine definitions\n"
5493 "// test_type\n"
5494 "subroutine(test_type) void test_with_discard(void)\n"
5495 "{\n"
5496 " discard_fragment();"
5497 "\n"
5498 " out_color = failure_color;\n"
5499 "\n"
5500 " set_global_colors();\n"
5501 "\n"
5502 " vec4 sampled_color = sample_texture(gl_PointCoord);\n"
5503 "\n"
5504 " bool comparison_result = compare(success_color, sampled_color);\n"
5505 "\n"
5506 " if (true == comparison_result)\n"
5507 " {\n"
5508 " out_color = success_color;\n"
5509 " }\n"
5510 " else\n"
5511 " {\n"
5512 " out_color = failure_color;\n"
5513 " }\n"
5514 "}\n"
5515 "\n"
5516 "subroutine(test_type) void test_without_discard(void)\n"
5517 "{\n"
5518 " set_global_colors();\n"
5519 "\n"
5520 " vec4 sampled_color = sample_texture(gl_PointCoord);\n"
5521 "\n"
5522 " bool comparison_result = compare(success_color, sampled_color);\n"
5523 "\n"
5524 " if (true == comparison_result)\n"
5525 " {\n"
5526 " out_color = success_color;\n"
5527 " }\n"
5528 " else\n"
5529 " {\n"
5530 " out_color = failure_color;\n"
5531 " }\n"
5532 "}\n"
5533 "\n"
5534 "// Subroutine uniforms\n"
5535 "subroutine uniform test_type test;\n"
5536 "\n"
5537 "void main()\n"
5538 "{\n"
5539 " // Set colors\n"
5540 " success_color = vec4(0.5, 0.5, 0.5, 0.5);\n"
5541 " failure_color = vec4(0.5, 0.5, 0.5, 0.5);\n"
5542 "\n"
5543 " test();\n"
5544 "}\n"
5545 "\n";
5546
5547 static const GLchar *geometry_shader_code = "#version 400 core\n"
5548 "#extension GL_ARB_shader_subroutine : require\n"
5549 "\n"
5550 "precision highp float;\n"
5551 "\n"
5552 "layout(points) in;\n"
5553 "layout(triangle_strip, max_vertices = 4) out;\n"
5554 "\n"
5555 "void main()\n"
5556 "{\n"
5557 " gl_Position = vec4(-1, -1, 0, 1);\n"
5558 " EmitVertex();\n"
5559 " \n"
5560 " gl_Position = vec4(-1, 1, 0, 1);\n"
5561 " EmitVertex();\n"
5562 " \n"
5563 " gl_Position = vec4( 1, -1, 0, 1);\n"
5564 " EmitVertex();\n"
5565 " \n"
5566 " gl_Position = vec4( 1, 1, 0, 1);\n"
5567 " EmitVertex();\n"
5568 " \n"
5569 " EndPrimitive();\n"
5570 "}\n"
5571 "\n";
5572
5573 static const GLchar *vertex_shader_code = "#version 400 core\n"
5574 "#extension GL_ARB_shader_subroutine : require\n"
5575 "\n"
5576 "precision highp float;\n"
5577 "\n"
5578 "void main()\n"
5579 "{\n"
5580 "}\n"
5581 "\n";
5582
5583 static const GLchar *subroutine_names[][2] = {{"discard_yes", "discard_no"},
5584 {"red_pass_blue_fail", "blue_pass_red_fail"},
5585 {"first_sampler", "second_sampler"},
5586 {"check_equal", "check_not_equal"},
5587 {"test_with_discard", "test_without_discard"}};
5588 static const GLuint n_subroutine_types = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
5589
5590 static const GLchar *subroutine_uniform_names[] = {"discard_fragment", "set_global_colors", "sample_texture",
5591 "compare", "test"};
5592 static const GLuint n_subroutine_uniform_names =
5593 sizeof(subroutine_uniform_names) / sizeof(subroutine_uniform_names[0]);
5594
5595 static const GLchar *uniform_names[] = {
5596 "sampler_1",
5597 "sampler_2",
5598 };
5599 static const GLuint n_uniform_names = sizeof(uniform_names) / sizeof(uniform_names[0]);
5600
5601 /* Colors */
5602 static const GLubyte blue_color[4] = {0, 0, 255, 255};
5603 static const GLubyte clean_color[4] = {0, 0, 0, 0};
5604 static const GLubyte red_color[4] = {255, 0, 0, 255};
5605
5606 /* Configurations */
5607 static const testConfiguration test_configurations[] = {
5608 testConfiguration(
5609 "Expect red color from 1st sampler", red_color, 1 /* discard_fragment : discard_no */,
5610 0 /* set_global_colors : red_pass_blue_fail */, 0 /* sample_texture : first_sampler */,
5611 0 /* compare : check_equal */, 0 /* test : test_with_discard */, 1 /* red */,
5612 0 /* blue */),
5613
5614 testConfiguration(
5615 "Test \"without discard\" option, expect no blue color from 2nd sampler", blue_color,
5616 0 /* discard_fragment : discard_yes */, 1 /* set_global_colors : blue_pass_red_fail */,
5617 1 /* sample_texture : second_sampler */, 1 /* compare : check_not_equal */,
5618 1 /* test : test_without_discard */, 0 /* blue */, 1 /* red */),
5619
5620 testConfiguration("Fragment shoud be discarded", clean_color, 0 /* discard_fragment : discard_yes */,
5621 0 /* set_global_colors : red_pass_blue_fail */,
5622 0 /* sample_texture : first_sampler */,
5623 0 /* compare : check_equal */,
5624 0 /* test : test_with_discard */, 1 /* red */, 0 /* blue */),
5625
5626 testConfiguration(
5627 "Expect blue color from 1st sampler", blue_color, 1 /* discard_fragment : discard_no */,
5628 1 /* set_global_colors : blue_pass_red_fail */, 0 /* sample_texture : first_sampler */,
5629 0 /* compare : check_equal */, 0 /* test : test_with_discard */,
5630 0 /* blue */, 1 /* red */),
5631
5632 testConfiguration(
5633 "Expect red color from 2nd sampler", red_color, 1 /* discard_fragment : discard_no */,
5634 0 /* set_global_colors : red_pass_blue_fail */, 1 /* sample_texture : second_sampler */,
5635 0 /* compare : check_equal */, 0 /* test : test_with_discard */,
5636 0 /* blue */, 1 /* red */),
5637
5638 testConfiguration(
5639 "Expect no blue color from 2nd sampler", blue_color, 1 /* discard_fragment : discard_no */,
5640 1 /* set_global_colors : blue_pass_red_fail */, 1 /* sample_texture : second_sampler */,
5641 1 /* compare : check_not_equal */, 0 /* test : test_with_discard */,
5642 0 /* blue */, 1 /* red */),
5643 };
5644 static const GLuint n_test_cases = sizeof(test_configurations) / sizeof(test_configurations[0]);
5645
5646 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
5647 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
5648 {
5649 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
5650 }
5651
5652 /* GL objects */
5653 Utils::texture blue_texture(m_context);
5654 Utils::texture color_texture(m_context);
5655 Utils::framebuffer framebuffer(m_context);
5656 Utils::program program(m_context);
5657 Utils::texture red_texture(m_context);
5658 Utils::vertexArray vao(m_context);
5659
5660 /* Init GL objects */
5661 program.build(0 /* cs */, fragment_shader_code /* fs */, geometry_shader_code /* gs */, 0 /* tcs */, 0 /* test */,
5662 vertex_shader_code, 0 /* varying_names */, 0 /* n_varyings */);
5663
5664 program.use();
5665
5666 vao.generate();
5667 vao.bind();
5668
5669 blue_texture.create(m_texture_width, m_texture_height, GL_RGBA8);
5670 color_texture.create(m_texture_width, m_texture_height, GL_RGBA8);
5671 red_texture.create(m_texture_width, m_texture_height, GL_RGBA8);
5672
5673 framebuffer.generate();
5674 framebuffer.bind();
5675 framebuffer.attachTexture(GL_COLOR_ATTACHMENT0, color_texture.m_id, m_texture_width, m_texture_height);
5676
5677 /* Get subroutine indices */
5678 for (GLuint type = 0; type < n_subroutine_types; ++type)
5679 {
5680 m_subroutine_indices[type][0] = program.getSubroutineIndex(subroutine_names[type][0], GL_FRAGMENT_SHADER);
5681 m_subroutine_indices[type][1] = program.getSubroutineIndex(subroutine_names[type][1], GL_FRAGMENT_SHADER);
5682 }
5683
5684 /* Get subroutine uniform locations */
5685 for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
5686 {
5687 m_subroutine_uniform_locations[uniform] =
5688 program.getSubroutineUniformLocation(subroutine_uniform_names[uniform], GL_FRAGMENT_SHADER);
5689 }
5690
5691 /* Get uniform locations */
5692 for (GLuint i = 0; i < n_uniform_names; ++i)
5693 {
5694 m_uniform_locations[i] = program.getUniformLocation(uniform_names[i]);
5695 }
5696
5697 /* Prepare textures */
5698 fillTexture(blue_texture, blue_color);
5699 fillTexture(color_texture, clean_color);
5700 fillTexture(red_texture, red_color);
5701
5702 m_source_textures[0] = blue_texture.m_id;
5703 m_source_textures[1] = red_texture.m_id;
5704
5705 framebuffer.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
5706
5707 /* Test */
5708 bool result = true;
5709 for (GLuint i = 0; i < n_test_cases; ++i)
5710 {
5711 /* Clean output texture */
5712 framebuffer.clear(GL_COLOR_BUFFER_BIT);
5713
5714 /* Execute test */
5715 if (false == testDraw(test_configurations[i].m_routines, test_configurations[i].m_samplers,
5716 test_configurations[i].m_expected_color, color_texture))
5717 {
5718 m_context.getTestContext().getLog()
5719 << tcu::TestLog::Message << "Error. Failure for configuration: " << test_configurations[i].m_description
5720 << tcu::TestLog::EndMessage;
5721
5722 result = false;
5723 }
5724 }
5725
5726 /* Set result */
5727 if (true == result)
5728 {
5729 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5730 }
5731 else
5732 {
5733 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
5734 }
5735
5736 /* Done */
5737 return tcu::TestNode::STOP;
5738 }
5739
5740 /** Fill texture with specified color
5741 *
5742 * @param texture Texture instance
5743 * @param color Color
5744 **/
fillTexture(Utils::texture & texture,const glw::GLubyte color[4]) const5745 void FunctionalTest11::fillTexture(Utils::texture &texture, const glw::GLubyte color[4]) const
5746 {
5747 std::vector<GLubyte> texture_data;
5748
5749 /* Prepare texture data */
5750 texture_data.resize(m_texture_width * m_texture_height * 4);
5751
5752 for (GLuint y = 0; y < m_texture_height; ++y)
5753 {
5754 const GLuint line_offset = y * m_texture_width * 4;
5755
5756 for (GLuint x = 0; x < m_texture_width; ++x)
5757 {
5758 const GLuint point_offset = x * 4 + line_offset;
5759
5760 texture_data[point_offset + 0] = color[0]; /* red */
5761 texture_data[point_offset + 1] = color[1]; /* green */
5762 texture_data[point_offset + 2] = color[2]; /* blue */
5763 texture_data[point_offset + 3] = color[3]; /* alpha */
5764 }
5765 }
5766
5767 texture.update(m_texture_width, m_texture_height, GL_RGBA, GL_UNSIGNED_BYTE, &texture_data[0]);
5768 }
5769
5770 /** Execute draw call and verify results
5771 *
5772 * @param routine_configuration Configurations of routines to be used
5773 * @param sampler_configuration Configuration of textures to be bound to samplers
5774 * @param expected_color Expected color of result image
5775 *
5776 * @return true if result image is filled with expected color, false otherwise
5777 **/
testDraw(const glw::GLuint routine_configuration[5],const glw::GLuint sampler_configuration[2],const glw::GLubyte expected_color[4],Utils::texture & color_texture) const5778 bool FunctionalTest11::testDraw(const glw::GLuint routine_configuration[5], const glw::GLuint sampler_configuration[2],
5779 const glw::GLubyte expected_color[4], Utils::texture &color_texture) const
5780 {
5781 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
5782 static const GLint n_samplers = 2;
5783 static const GLint n_subroutine_uniforms = 5;
5784 GLuint subroutine_indices[5];
5785
5786 /* Set samplers */
5787 for (GLuint i = 0; i < n_samplers; ++i)
5788 {
5789 const GLuint location = m_uniform_locations[i];
5790 const GLuint texture = m_source_textures[sampler_configuration[i]];
5791
5792 gl.activeTexture(GL_TEXTURE0 + i);
5793 GLU_EXPECT_NO_ERROR(gl.getError(), "ActiveTexture");
5794
5795 gl.bindTexture(GL_TEXTURE_2D, texture);
5796 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
5797
5798 gl.uniform1i(location, i);
5799 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
5800 }
5801
5802 gl.activeTexture(GL_TEXTURE0 + 0);
5803
5804 /* Set subroutine uniforms */
5805 for (GLuint i = 0; i < n_subroutine_uniforms; ++i)
5806 {
5807 const GLuint location = m_subroutine_uniform_locations[i];
5808 const GLuint routine = routine_configuration[i];
5809
5810 subroutine_indices[location] = m_subroutine_indices[i][routine];
5811 }
5812
5813 gl.uniformSubroutinesuiv(GL_FRAGMENT_SHADER, 5, subroutine_indices);
5814 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
5815
5816 /* Draw */
5817 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
5818 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
5819
5820 /* Capture result */
5821 std::vector<GLubyte> captured_data;
5822 captured_data.resize(m_texture_width * m_texture_height * 4);
5823
5824 color_texture.get(GL_RGBA, GL_UNSIGNED_BYTE, &captured_data[0]);
5825
5826 /* Verify result */
5827 for (GLuint y = 0; y < m_texture_height; ++y)
5828 {
5829 const GLuint line_offset = y * m_texture_width * 4;
5830
5831 for (GLuint x = 0; x < m_texture_width; ++x)
5832 {
5833 const GLuint point_offset = x * 4 + line_offset;
5834 bool is_as_expected = true;
5835
5836 is_as_expected = is_as_expected && (expected_color[0] == captured_data[point_offset + 0]); /* red */
5837 is_as_expected = is_as_expected && (expected_color[1] == captured_data[point_offset + 1]); /* green */
5838 is_as_expected = is_as_expected && (expected_color[2] == captured_data[point_offset + 2]); /* blue */
5839 is_as_expected = is_as_expected && (expected_color[3] == captured_data[point_offset + 3]); /* alpha */
5840
5841 if (false == is_as_expected)
5842 {
5843 return false;
5844 }
5845 }
5846 }
5847
5848 /* Done */
5849 return true;
5850 }
5851
5852 /* Constatns used by FunctionalTest12 */
5853 const glw::GLuint FunctionalTest12::m_texture_height = 16;
5854 const glw::GLuint FunctionalTest12::m_texture_width = 16;
5855
5856 /** Constructor
5857 *
5858 * @param context CTS context
5859 **/
FunctionalTest12(deqp::Context & context)5860 FunctionalTest12::FunctionalTest12(deqp::Context &context)
5861 : TestCase(context, "ssbo_atomic_image_load_store",
5862 "Verify that SSBO, atomic counters and image load store work as expected")
5863 , m_left_image(0)
5864 , m_right_image(0)
5865 {
5866 }
5867
5868 /** Execute test
5869 *
5870 * @return tcu::TestNode::STOP
5871 **/
iterate()5872 tcu::TestNode::IterateResult FunctionalTest12::iterate()
5873 {
5874 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
5875 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
5876 {
5877 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
5878 }
5879
5880 bool result = true;
5881
5882 /* Test atomic counters */
5883 if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_atomic_counters"))
5884 {
5885 if (false == testAtomic())
5886 {
5887 result = false;
5888 }
5889 }
5890
5891 /* Test shader storage buffer */
5892 if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_storage_buffer_object"))
5893 {
5894 if (false == testSSBO())
5895 {
5896 result = false;
5897 }
5898 }
5899
5900 /* Test image load store */
5901 if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_image_load_store"))
5902 {
5903 if (false == testImage())
5904 {
5905 result = false;
5906 }
5907 }
5908
5909 /* Set result */
5910 if (true == result)
5911 {
5912 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5913 }
5914 else
5915 {
5916 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
5917 }
5918
5919 /* Done */
5920 return tcu::TestNode::STOP;
5921 }
5922
5923 /** Fill texture with specified color
5924 *
5925 * @param texture Texture instance
5926 * @param color Color
5927 **/
fillTexture(Utils::texture & texture,const glw::GLuint color[4]) const5928 void FunctionalTest12::fillTexture(Utils::texture &texture, const glw::GLuint color[4]) const
5929 {
5930 std::vector<GLuint> texture_data;
5931
5932 /* Prepare texture data */
5933 texture_data.resize(m_texture_width * m_texture_height * 4);
5934
5935 for (GLuint y = 0; y < m_texture_height; ++y)
5936 {
5937 const GLuint line_offset = y * m_texture_width * 4;
5938
5939 for (GLuint x = 0; x < m_texture_width; ++x)
5940 {
5941 const GLuint point_offset = x * 4 + line_offset;
5942
5943 texture_data[point_offset + 0] = color[0]; /* red */
5944 texture_data[point_offset + 1] = color[1]; /* green */
5945 texture_data[point_offset + 2] = color[2]; /* blue */
5946 texture_data[point_offset + 3] = color[3]; /* alpha */
5947 }
5948 }
5949
5950 texture.update(m_texture_width, m_texture_height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &texture_data[0]);
5951 }
5952
5953 /** Test atomic counters
5954 *
5955 * @return true if test pass, false otherwise
5956 **/
testAtomic()5957 bool FunctionalTest12::testAtomic()
5958 {
5959 static const GLchar *fragment_shader_code = "#version 410 core\n"
5960 "#extension GL_ARB_shader_atomic_counters : require\n"
5961 "#extension GL_ARB_shader_subroutine : require\n"
5962 "\n"
5963 "precision highp float;\n"
5964 "\n"
5965 "layout(location = 0) out uint out_color;\n"
5966 "\n"
5967 "layout(binding = 0, offset = 8) uniform atomic_uint one;\n"
5968 "layout(binding = 0, offset = 4) uniform atomic_uint two;\n"
5969 "layout(binding = 0, offset = 0) uniform atomic_uint three;\n"
5970 "\n"
5971 "subroutine void atomic_routine(void)\n;"
5972 "\n"
5973 "subroutine(atomic_routine) void increment_two(void)\n"
5974 "{\n"
5975 " out_color = atomicCounterIncrement(two);\n"
5976 "}\n"
5977 "\n"
5978 "subroutine(atomic_routine) void decrement_three(void)\n"
5979 "{\n"
5980 " out_color = atomicCounterDecrement(three);\n"
5981 "}\n"
5982 "\n"
5983 "subroutine(atomic_routine) void read_one(void)\n"
5984 "{\n"
5985 " out_color = atomicCounter(one);\n"
5986 "}\n"
5987 "\n"
5988 "subroutine uniform atomic_routine routine;\n"
5989 "\n"
5990 "void main()\n"
5991 "{\n"
5992 " routine();\n"
5993 "}\n"
5994 "\n";
5995
5996 static const GLchar *geometry_shader_code = "#version 400 core\n"
5997 "#extension GL_ARB_shader_subroutine : require\n"
5998 "\n"
5999 "precision highp float;\n"
6000 "\n"
6001 "layout(points) in;\n"
6002 "layout(triangle_strip, max_vertices = 4) out;\n"
6003 "\n"
6004 "void main()\n"
6005 "{\n"
6006 " gl_Position = vec4(-1, -1, 0, 1);\n"
6007 " EmitVertex();\n"
6008 " \n"
6009 " gl_Position = vec4(-1, 1, 0, 1);\n"
6010 " EmitVertex();\n"
6011 " \n"
6012 " gl_Position = vec4( 1, -1, 0, 1);\n"
6013 " EmitVertex();\n"
6014 " \n"
6015 " gl_Position = vec4( 1, 1, 0, 1);\n"
6016 " EmitVertex();\n"
6017 " \n"
6018 " EndPrimitive();\n"
6019 "}\n"
6020 "\n";
6021
6022 static const GLchar *vertex_shader_code = "#version 400 core\n"
6023 "#extension GL_ARB_shader_subroutine : require\n"
6024 "\n"
6025 "precision highp float;\n"
6026 "\n"
6027 "void main()\n"
6028 "{\n"
6029 "}\n"
6030 "\n";
6031
6032 static const GLchar *subroutine_names[] = {"increment_two", "decrement_three", "read_one"};
6033
6034 /* Test data */
6035 static const glw::GLuint atomic_buffer_data[] = {
6036 m_texture_width * m_texture_height, m_texture_width * m_texture_height, m_texture_width * m_texture_height};
6037
6038 static const glw::GLuint expected_incremented_two[] = {atomic_buffer_data[0], 2 * atomic_buffer_data[1],
6039 atomic_buffer_data[2]};
6040
6041 static const glw::GLuint expected_decremented_three[] = {0, expected_incremented_two[1],
6042 expected_incremented_two[2]};
6043
6044 static const glw::GLuint expected_read_one[] = {expected_decremented_three[0], expected_decremented_three[1],
6045 expected_decremented_three[2]};
6046
6047 /* GL objects */
6048 Utils::buffer atomic_buffer(m_context);
6049 Utils::texture color_texture(m_context);
6050 Utils::framebuffer framebuffer(m_context);
6051 Utils::program program(m_context);
6052 Utils::vertexArray vao(m_context);
6053
6054 /* Init GL objects */
6055 program.build(0 /* cs */, fragment_shader_code /* fs */, geometry_shader_code /* gs */, 0 /* tcs */, 0 /* test */,
6056 vertex_shader_code, 0 /* varying_names */, 0 /* n_varyings */);
6057
6058 program.use();
6059
6060 vao.generate();
6061 vao.bind();
6062
6063 color_texture.create(m_texture_width, m_texture_height, GL_R32UI);
6064
6065 atomic_buffer.generate();
6066 atomic_buffer.update(GL_ATOMIC_COUNTER_BUFFER, sizeof(atomic_buffer_data), (GLvoid *)atomic_buffer_data,
6067 GL_STATIC_DRAW);
6068 atomic_buffer.bindRange(GL_ATOMIC_COUNTER_BUFFER, 0 /* index */, 0 /* offset */, sizeof(atomic_buffer_data));
6069
6070 framebuffer.generate();
6071 framebuffer.bind();
6072 framebuffer.attachTexture(GL_COLOR_ATTACHMENT0, color_texture.m_id, m_texture_width, m_texture_height);
6073 framebuffer.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
6074 framebuffer.clear(GL_COLOR_BUFFER_BIT);
6075
6076 /* Subroutine indices */
6077 GLuint increment_two = program.getSubroutineIndex(subroutine_names[0], GL_FRAGMENT_SHADER);
6078 GLuint decrement_three = program.getSubroutineIndex(subroutine_names[1], GL_FRAGMENT_SHADER);
6079 GLuint read_one = program.getSubroutineIndex(subroutine_names[2], GL_FRAGMENT_SHADER);
6080
6081 /* Test */
6082 bool result = true;
6083
6084 if (false == testAtomicDraw(increment_two, expected_incremented_two))
6085 {
6086 result = false;
6087 }
6088
6089 if (false == testAtomicDraw(decrement_three, expected_decremented_three))
6090 {
6091 result = false;
6092 }
6093
6094 if (false == testAtomicDraw(read_one, expected_read_one))
6095 {
6096 result = false;
6097 }
6098
6099 /* Done */
6100 return result;
6101 }
6102
6103 /** Execture draw call and verify results
6104 *
6105 * @param subroutine_index Index of subroutine that shall be used during draw call
6106 * @param expected_results Expected results
6107 *
6108 * @return true if results are as expected, false otherwise
6109 **/
testAtomicDraw(GLuint subroutine_index,const GLuint expected_results[3]) const6110 bool FunctionalTest12::testAtomicDraw(GLuint subroutine_index, const GLuint expected_results[3]) const
6111 {
6112 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
6113
6114 /* Set subroutine uniforms */
6115 gl.uniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &subroutine_index);
6116 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
6117
6118 /* Draw */
6119 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
6120 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
6121
6122 /* Capture results */
6123 GLuint *atomic_results = (GLuint *)gl.mapBuffer(GL_ATOMIC_COUNTER_BUFFER, GL_READ_ONLY);
6124 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
6125
6126 /* Verify */
6127 bool result = (0 == memcmp(expected_results, atomic_results, 3 * sizeof(GLuint)));
6128
6129 if (false == result)
6130 {
6131 m_context.getTestContext().getLog()
6132 << tcu::TestLog::Message << "Error. Invalid result. "
6133 << "Result: [ " << atomic_results[0] << ", " << atomic_results[1] << ", " << atomic_results[2] << " ] "
6134 << "Expected: [ " << expected_results[0] << ", " << expected_results[1] << ", " << expected_results[2]
6135 << " ]" << tcu::TestLog::EndMessage;
6136 }
6137
6138 /* Unmap buffer */
6139 gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
6140 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
6141
6142 /* Done */
6143 return result;
6144 }
6145
6146 /** Test image load store
6147 *
6148 * @return true if test pass, false otherwise
6149 **/
testImage()6150 bool FunctionalTest12::testImage()
6151 {
6152 static const GLchar *fragment_shader_code =
6153 "#version 400 core\n"
6154 "#extension GL_ARB_shader_image_load_store : require\n"
6155 "#extension GL_ARB_shader_subroutine : require\n"
6156 "\n"
6157 "precision highp float;\n"
6158 "\n"
6159 "layout(location = 0) out uvec4 out_color;\n"
6160 "\n"
6161 "layout(rgba32ui) uniform uimage2D left_image;\n"
6162 "layout(rgba32ui) uniform uimage2D right_image;\n"
6163 "\n"
6164 "subroutine void image_routine(void);\n"
6165 "\n"
6166 "subroutine(image_routine) void left_to_right(void)\n"
6167 "{\n"
6168 " out_color = imageLoad (left_image, ivec2(gl_FragCoord.xy));\n"
6169 " imageStore(right_image, ivec2(gl_FragCoord.xy), out_color);\n"
6170 "}\n"
6171 "\n"
6172 "subroutine(image_routine) void right_to_left(void)\n"
6173 "{\n"
6174 " out_color = imageLoad (right_image, ivec2(gl_FragCoord.xy));\n"
6175 " imageStore(left_image, ivec2(gl_FragCoord.xy), out_color);\n"
6176 "}\n"
6177 "\n"
6178 "subroutine uniform image_routine routine;\n"
6179 "\n"
6180 "void main()\n"
6181 "{\n"
6182 " routine();\n"
6183 "}\n"
6184 "\n";
6185
6186 static const GLchar *geometry_shader_code = "#version 400 core\n"
6187 "#extension GL_ARB_shader_subroutine : require\n"
6188 "\n"
6189 "precision highp float;\n"
6190 "\n"
6191 "layout(points) in;\n"
6192 "layout(triangle_strip, max_vertices = 4) out;\n"
6193 "\n"
6194 "void main()\n"
6195 "{\n"
6196 " gl_Position = vec4(-1, -1, 0, 1);\n"
6197 " EmitVertex();\n"
6198 " \n"
6199 " gl_Position = vec4(-1, 1, 0, 1);\n"
6200 " EmitVertex();\n"
6201 " \n"
6202 " gl_Position = vec4( 1, -1, 0, 1);\n"
6203 " EmitVertex();\n"
6204 " \n"
6205 " gl_Position = vec4( 1, 1, 0, 1);\n"
6206 " EmitVertex();\n"
6207 " \n"
6208 " EndPrimitive();\n"
6209 "}\n"
6210 "\n";
6211
6212 static const GLchar *vertex_shader_code = "#version 400 core\n"
6213 "#extension GL_ARB_shader_subroutine : require\n"
6214 "\n"
6215 "precision highp float;\n"
6216 "\n"
6217 "void main()\n"
6218 "{\n"
6219 "}\n"
6220 "\n";
6221
6222 static const GLchar *subroutine_names[] = {"left_to_right", "right_to_left"};
6223
6224 static const GLchar *uniform_names[] = {"left_image", "right_image"};
6225
6226 /* Test data */
6227 static const GLuint blue_color[4] = {0, 0, 255, 255};
6228 static const GLuint clean_color[4] = {16, 32, 64, 128};
6229 static const GLuint red_color[4] = {255, 0, 0, 255};
6230
6231 /* GL objects */
6232 Utils::texture blue_texture(m_context);
6233 Utils::texture destination_texture(m_context);
6234 Utils::texture color_texture(m_context);
6235 Utils::framebuffer framebuffer(m_context);
6236 Utils::program program(m_context);
6237 Utils::texture red_texture(m_context);
6238 Utils::vertexArray vao(m_context);
6239
6240 /* Init GL objects */
6241 program.build(0 /* cs */, fragment_shader_code /* fs */, geometry_shader_code /* gs */, 0 /* tcs */, 0 /* test */,
6242 vertex_shader_code, 0 /* varying_names */, 0 /* n_varyings */);
6243
6244 program.use();
6245
6246 vao.generate();
6247 vao.bind();
6248
6249 blue_texture.create(m_texture_width, m_texture_height, GL_RGBA32UI);
6250 destination_texture.create(m_texture_width, m_texture_height, GL_RGBA32UI);
6251 color_texture.create(m_texture_width, m_texture_height, GL_RGBA32UI);
6252 red_texture.create(m_texture_width, m_texture_height, GL_RGBA32UI);
6253
6254 fillTexture(blue_texture, blue_color);
6255 fillTexture(destination_texture, clean_color);
6256 fillTexture(red_texture, red_color);
6257
6258 framebuffer.generate();
6259 framebuffer.bind();
6260 framebuffer.attachTexture(GL_COLOR_ATTACHMENT0, color_texture.m_id, m_texture_width, m_texture_height);
6261 framebuffer.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
6262 framebuffer.clear(GL_COLOR_BUFFER_BIT);
6263
6264 /* Subroutine indices */
6265 GLuint left_to_right = program.getSubroutineIndex(subroutine_names[0], GL_FRAGMENT_SHADER);
6266 GLuint right_to_left = program.getSubroutineIndex(subroutine_names[1], GL_FRAGMENT_SHADER);
6267
6268 /* Uniform locations */
6269 m_left_image = program.getUniformLocation(uniform_names[0]);
6270 m_right_image = program.getUniformLocation(uniform_names[1]);
6271
6272 /* Test */
6273 bool result = true;
6274
6275 if (false == testImageDraw(left_to_right, blue_texture, destination_texture, blue_color, blue_color))
6276 {
6277 result = false;
6278 }
6279
6280 if (false == testImageDraw(left_to_right, red_texture, destination_texture, red_color, red_color))
6281 {
6282 result = false;
6283 }
6284
6285 if (false == testImageDraw(right_to_left, destination_texture, blue_texture, blue_color, blue_color))
6286 {
6287 result = false;
6288 }
6289
6290 if (false == testImageDraw(right_to_left, destination_texture, red_texture, red_color, red_color))
6291 {
6292 result = false;
6293 }
6294
6295 if (false == testImageDraw(left_to_right, blue_texture, red_texture, blue_color, blue_color))
6296 {
6297 result = false;
6298 }
6299
6300 /* Done */
6301 return result;
6302 }
6303
6304 /** Execute draw call and verifies results
6305 *
6306 * @param subroutine_index Index of subroutine that shall be used during draw call
6307 * @param left "Left" texture
6308 * @param right "Right" texture
6309 * @param expected_left_color Expected color of "left" texture
6310 * @param expected_right_color Expected color of "right" texture
6311 *
6312 * @return true if verification result is positive, false otherwise
6313 **/
testImageDraw(GLuint subroutine_index,Utils::texture & left,Utils::texture & right,const GLuint expected_left_color[4],const GLuint expected_right_color[4]) const6314 bool FunctionalTest12::testImageDraw(GLuint subroutine_index, Utils::texture &left, Utils::texture &right,
6315 const GLuint expected_left_color[4], const GLuint expected_right_color[4]) const
6316 {
6317 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
6318
6319 /* Set subroutine uniforms */
6320 gl.uniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &subroutine_index);
6321 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
6322
6323 /* Set up image units */
6324 gl.uniform1i(m_left_image, 0);
6325 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
6326
6327 gl.uniform1i(m_right_image, 1);
6328 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
6329
6330 gl.bindImageTexture(0, left.m_id, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32UI);
6331 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
6332
6333 gl.bindImageTexture(1, right.m_id, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32UI);
6334 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
6335
6336 /* Draw */
6337 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
6338 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
6339
6340 /* Verify results */
6341 bool result = true;
6342
6343 if (false == verifyTexture(left, expected_left_color))
6344 {
6345 m_context.getTestContext().getLog()
6346 << tcu::TestLog::Message << "Error. Invalid result. Left texture is filled with wrong color."
6347 << tcu::TestLog::EndMessage;
6348 result = false;
6349 }
6350
6351 if (false == verifyTexture(right, expected_right_color))
6352 {
6353 m_context.getTestContext().getLog()
6354 << tcu::TestLog::Message << "Error. Invalid result. Right texture is filled with wrong color."
6355 << tcu::TestLog::EndMessage;
6356 result = false;
6357 }
6358
6359 /* Done */
6360 return result;
6361 }
6362
6363 /** Test shader storage buffer
6364 *
6365 * @return true if test pass, false otherwise
6366 **/
testSSBO()6367 bool FunctionalTest12::testSSBO()
6368 {
6369 static const GLchar *fragment_shader_code = "#version 400 core\n"
6370 "#extension GL_ARB_shader_storage_buffer_object : require\n"
6371 "#extension GL_ARB_shader_subroutine : require\n"
6372 "\n"
6373 "precision highp float;\n"
6374 "\n"
6375 "layout(location = 0) out uvec4 out_color;\n"
6376 "\n"
6377 "layout(std140, binding = 0) buffer Buffer\n"
6378 "{\n"
6379 " uvec4 entry;\n"
6380 "};\n"
6381 "\n"
6382 "subroutine void ssbo_routine(void)\n;"
6383 "\n"
6384 "subroutine(ssbo_routine) void increment(void)\n"
6385 "{\n"
6386 " out_color.x = atomicAdd(entry.x, 1);\n"
6387 " out_color.y = atomicAdd(entry.y, 1);\n"
6388 " out_color.z = atomicAdd(entry.z, 1);\n"
6389 " out_color.w = atomicAdd(entry.w, 1);\n"
6390 "}\n"
6391 "\n"
6392 "subroutine(ssbo_routine) void decrement(void)\n"
6393 "{\n"
6394 " out_color.x = atomicAdd(entry.x, -1);\n"
6395 " out_color.y = atomicAdd(entry.y, -1);\n"
6396 " out_color.z = atomicAdd(entry.z, -1);\n"
6397 " out_color.w = atomicAdd(entry.w, -1);\n"
6398 "}\n"
6399 "\n"
6400 "subroutine uniform ssbo_routine routine;\n"
6401 "\n"
6402 "void main()\n"
6403 "{\n"
6404 " routine();\n"
6405 "}\n"
6406 "\n";
6407
6408 static const GLchar *geometry_shader_code = "#version 400 core\n"
6409 "#extension GL_ARB_shader_subroutine : require\n"
6410 "\n"
6411 "precision highp float;\n"
6412 "\n"
6413 "layout(points) in;\n"
6414 "layout(triangle_strip, max_vertices = 4) out;\n"
6415 "\n"
6416 "void main()\n"
6417 "{\n"
6418 " gl_Position = vec4(-1, -1, 0, 1);\n"
6419 " EmitVertex();\n"
6420 " \n"
6421 " gl_Position = vec4(-1, 1, 0, 1);\n"
6422 " EmitVertex();\n"
6423 " \n"
6424 " gl_Position = vec4( 1, -1, 0, 1);\n"
6425 " EmitVertex();\n"
6426 " \n"
6427 " gl_Position = vec4( 1, 1, 0, 1);\n"
6428 " EmitVertex();\n"
6429 " \n"
6430 " EndPrimitive();\n"
6431 "}\n"
6432 "\n";
6433
6434 static const GLchar *vertex_shader_code = "#version 400 core\n"
6435 "#extension GL_ARB_shader_subroutine : require\n"
6436 "\n"
6437 "precision highp float;\n"
6438 "\n"
6439 "void main()\n"
6440 "{\n"
6441 "}\n"
6442 "\n";
6443
6444 static const GLchar *subroutine_names[] = {"increment", "decrement"};
6445
6446 /* Test data */
6447 static const glw::GLuint buffer_data[] = {
6448 m_texture_width * m_texture_height + 1, m_texture_width * m_texture_height + 2,
6449 m_texture_width * m_texture_height + 3, m_texture_width * m_texture_height + 4};
6450
6451 static const glw::GLuint expected_incremented[] = {
6452 m_texture_width * m_texture_height + buffer_data[0], m_texture_width * m_texture_height + buffer_data[1],
6453 m_texture_width * m_texture_height + buffer_data[2], m_texture_width * m_texture_height + buffer_data[3]};
6454
6455 static const glw::GLuint expected_decremented[] = {buffer_data[0], buffer_data[1], buffer_data[2], buffer_data[3]};
6456
6457 /* GL objects */
6458 Utils::buffer buffer(m_context);
6459 Utils::texture color_texture(m_context);
6460 Utils::framebuffer framebuffer(m_context);
6461 Utils::program program(m_context);
6462 Utils::vertexArray vao(m_context);
6463
6464 /* Init GL objects */
6465 program.build(0 /* cs */, fragment_shader_code /* fs */, geometry_shader_code /* gs */, 0 /* tcs */, 0 /* test */,
6466 vertex_shader_code, 0 /* varying_names */, 0 /* n_varyings */);
6467
6468 program.use();
6469
6470 vao.generate();
6471 vao.bind();
6472
6473 color_texture.create(m_texture_width, m_texture_height, GL_RGBA32UI);
6474
6475 buffer.generate();
6476 buffer.update(GL_SHADER_STORAGE_BUFFER, sizeof(buffer_data), (GLvoid *)buffer_data, GL_STATIC_DRAW);
6477 buffer.bindRange(GL_SHADER_STORAGE_BUFFER, 0 /* index */, 0 /* offset */, sizeof(buffer_data));
6478
6479 framebuffer.generate();
6480 framebuffer.bind();
6481 framebuffer.attachTexture(GL_COLOR_ATTACHMENT0, color_texture.m_id, m_texture_width, m_texture_height);
6482 framebuffer.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
6483 framebuffer.clear(GL_COLOR_BUFFER_BIT);
6484
6485 /* Subroutine indices */
6486 GLuint increment = program.getSubroutineIndex(subroutine_names[0], GL_FRAGMENT_SHADER);
6487 GLuint decrement = program.getSubroutineIndex(subroutine_names[1], GL_FRAGMENT_SHADER);
6488
6489 /* Test */
6490 bool result = true;
6491
6492 if (false == testSSBODraw(increment, expected_incremented))
6493 {
6494 result = false;
6495 }
6496
6497 if (false == testSSBODraw(decrement, expected_decremented))
6498 {
6499 result = false;
6500 }
6501
6502 /* Done */
6503 return result;
6504 }
6505
6506 /** Execute draw call and verify results
6507 *
6508 * @param subroutine_index Index of subroutine that shall be used by draw call
6509 * @param expected_results Expected results
6510 *
6511 *
6512 **/
testSSBODraw(GLuint subroutine_index,const GLuint expected_results[4]) const6513 bool FunctionalTest12::testSSBODraw(GLuint subroutine_index, const GLuint expected_results[4]) const
6514 {
6515 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
6516
6517 /* Set subroutine uniforms */
6518 gl.uniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &subroutine_index);
6519 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
6520
6521 /* Draw */
6522 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
6523 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
6524
6525 /* Capture results */
6526 GLuint *ssbo_results = (GLuint *)gl.mapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
6527 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
6528
6529 /* Verify */
6530 bool result = (0 == memcmp(expected_results, ssbo_results, 4 * sizeof(GLuint)));
6531
6532 if (false == result)
6533 {
6534 m_context.getTestContext().getLog()
6535 << tcu::TestLog::Message << "Error. Invalid result. "
6536 << "Result: [ " << ssbo_results[0] << ", " << ssbo_results[1] << ", " << ssbo_results[2] << ", "
6537 << ssbo_results[3] << " ] "
6538 << "Expected: [ " << expected_results[0] << ", " << expected_results[1] << ", " << expected_results[2]
6539 << ", " << expected_results[3] << " ]" << tcu::TestLog::EndMessage;
6540 }
6541
6542 /* Unmap buffer */
6543 gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
6544 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
6545
6546 /* Done */
6547 return result;
6548 }
6549
6550 /** Check if texture is filled with expected color
6551 *
6552 * @param texture Texture instance
6553 * @param expected_color Expected color
6554 *
6555 * @return true if texture is filled with specified color, false otherwise
6556 **/
verifyTexture(Utils::texture & texture,const GLuint expected_color[4]) const6557 bool FunctionalTest12::verifyTexture(Utils::texture &texture, const GLuint expected_color[4]) const
6558 {
6559 std::vector<GLuint> results;
6560 results.resize(m_texture_width * m_texture_height * 4);
6561
6562 texture.get(GL_RGBA_INTEGER, GL_UNSIGNED_INT, &results[0]);
6563
6564 for (GLuint y = 0; y < m_texture_height; ++y)
6565 {
6566 const GLuint line_offset = y * m_texture_width * 4;
6567
6568 for (GLuint x = 0; x < m_texture_width; ++x)
6569 {
6570 const GLuint point_offset = line_offset + x * 4;
6571 bool result = true;
6572
6573 result = result && (results[point_offset + 0] == expected_color[0]);
6574 result = result && (results[point_offset + 1] == expected_color[1]);
6575 result = result && (results[point_offset + 2] == expected_color[2]);
6576 result = result && (results[point_offset + 3] == expected_color[3]);
6577
6578 if (false == result)
6579 {
6580 return false;
6581 }
6582 }
6583 }
6584
6585 return true;
6586 }
6587
6588 /** Constructor.
6589 *
6590 * @param context Rendering context.
6591 *
6592 **/
FunctionalTest13(deqp::Context & context)6593 FunctionalTest13::FunctionalTest13(deqp::Context &context)
6594 : TestCase(context, "subroutines_with_separate_shader_objects",
6595 "Verifies that subroutines work correctly when used in separate "
6596 "shader objects")
6597 , m_fbo_id(0)
6598 , m_pipeline_id(0)
6599 , m_read_buffer(DE_NULL)
6600 , m_to_height(4)
6601 , m_to_id(0)
6602 , m_to_width(4)
6603 , m_vao_id(0)
6604 , m_has_test_passed(true)
6605 {
6606 memset(m_fs_po_ids, 0, sizeof(m_fs_po_ids));
6607 memset(m_gs_po_ids, 0, sizeof(m_gs_po_ids));
6608 memset(m_tc_po_ids, 0, sizeof(m_tc_po_ids));
6609 memset(m_te_po_ids, 0, sizeof(m_te_po_ids));
6610 memset(m_vs_po_ids, 0, sizeof(m_vs_po_ids));
6611 }
6612
6613 /** Deinitializes all GL objects that may have been created during test
6614 * execution, as well as releases all process-side buffers that may have
6615 * been allocated during the process.
6616 * The function also restores default GL state configuration.
6617 **/
deinit()6618 void FunctionalTest13::deinit()
6619 {
6620 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
6621
6622 if (m_fbo_id != 0)
6623 {
6624 gl.deleteFramebuffers(1, &m_fbo_id);
6625
6626 m_fbo_id = 0;
6627 }
6628
6629 if (m_pipeline_id != 0)
6630 {
6631 gl.deleteProgramPipelines(1, &m_pipeline_id);
6632
6633 m_pipeline_id = 0;
6634 }
6635
6636 if (m_read_buffer != DE_NULL)
6637 {
6638 delete[] m_read_buffer;
6639
6640 m_read_buffer = DE_NULL;
6641 }
6642
6643 for (unsigned int n_id = 0; n_id < 2 /* po id variants */; ++n_id)
6644 {
6645 if (m_fs_po_ids[n_id] != 0)
6646 {
6647 gl.deleteProgram(m_fs_po_ids[n_id]);
6648
6649 m_fs_po_ids[n_id] = 0;
6650 }
6651
6652 if (m_gs_po_ids[n_id] != 0)
6653 {
6654 gl.deleteProgram(m_gs_po_ids[n_id]);
6655
6656 m_gs_po_ids[n_id] = 0;
6657 }
6658
6659 if (m_tc_po_ids[n_id] != 0)
6660 {
6661 gl.deleteProgram(m_tc_po_ids[n_id]);
6662
6663 m_tc_po_ids[n_id] = 0;
6664 }
6665
6666 if (m_te_po_ids[n_id] != 0)
6667 {
6668 gl.deleteProgram(m_te_po_ids[n_id]);
6669
6670 m_te_po_ids[n_id] = 0;
6671 }
6672
6673 if (m_vs_po_ids[n_id] != 0)
6674 {
6675 gl.deleteProgram(m_vs_po_ids[n_id]);
6676
6677 m_vs_po_ids[n_id] = 0;
6678 }
6679 } /* for (both shader program object variants) */
6680
6681 if (m_to_id != 0)
6682 {
6683 gl.deleteTextures(1, &m_to_id);
6684
6685 m_to_id = 0;
6686 }
6687
6688 if (m_vao_id != 0)
6689 {
6690 gl.deleteVertexArrays(1, &m_vao_id);
6691
6692 m_vao_id = 0;
6693 }
6694
6695 /* Restore default GL_PATCH_VERTICES setting value */
6696 gl.patchParameteri(GL_PATCH_VERTICES, 3);
6697
6698 /* Restore default GL_PACK_ALIGNMENT setting value */
6699 gl.pixelStorei(GL_PACK_ALIGNMENT, 4);
6700 }
6701
6702 /** Retrieves body of a fragment shader that should be used for the test.
6703 * The subroutine implementations are slightly changed, depending on the
6704 * index of the shader, as specified by the caller.
6705 *
6706 * @param n_id Index of the shader.
6707 *
6708 * @return Requested string.
6709 **/
getFragmentShaderBody(unsigned int n_id)6710 std::string FunctionalTest13::getFragmentShaderBody(unsigned int n_id)
6711 {
6712 std::stringstream result_sstream;
6713
6714 /* Pre-amble */
6715 result_sstream << "#version 400\n"
6716 "\n"
6717 "#extension GL_ARB_shader_subroutine : require\n"
6718 "\n"
6719 /* Sub-routine */
6720 "subroutine void SubroutineFSType(inout vec4 result);\n"
6721 "\n"
6722 "subroutine(SubroutineFSType) void SubroutineFS1(inout vec4 result)\n"
6723 "{\n"
6724 " result += vec4("
6725 << float(n_id + 1) / 10.0f << ", " << float(n_id + 2) / 10.0f << ", " << float(n_id + 3) / 10.0f
6726 << ", " << float(n_id + 4) / 10.0f
6727 << ");\n"
6728 "}\n"
6729 "subroutine(SubroutineFSType) void SubroutineFS2(inout vec4 result)\n"
6730 "{\n"
6731 " result += vec4("
6732 << float(n_id + 1) / 20.0f << ", " << float(n_id + 2) / 20.0f << ", " << float(n_id + 3) / 20.0f
6733 << ", " << float(n_id + 4) / 20.0f
6734 << ");\n"
6735 "}\n"
6736 "\n"
6737 "subroutine uniform SubroutineFSType function;\n"
6738 "\n"
6739 /* Input block */
6740 "in GS_DATA\n"
6741 "{\n"
6742 " vec4 data;\n"
6743 "} in_gs;\n"
6744 "\n"
6745 "out vec4 result;\n"
6746 /* main() declaration */
6747 "void main()\n"
6748 "{\n"
6749 " vec4 data = in_gs.data;\n"
6750 " function(data);\n"
6751 "\n"
6752 " result = data;\n"
6753 "}\n";
6754
6755 return result_sstream.str();
6756 }
6757
6758 /** Retrieves body of a geometry shader that should be used for the test.
6759 * The subroutine implementations are slightly changed, depending on the
6760 * index of the shader, as specified by the caller.
6761 *
6762 * @param n_id Index of the shader.
6763 *
6764 * @return Requested string.
6765 **/
getGeometryShaderBody(unsigned int n_id)6766 std::string FunctionalTest13::getGeometryShaderBody(unsigned int n_id)
6767 {
6768 std::stringstream result_sstream;
6769
6770 /* Pre-amble */
6771 result_sstream << "#version 400\n"
6772 "\n"
6773 "#extension GL_ARB_shader_subroutine : require\n"
6774 "\n"
6775 "layout(points) in;\n"
6776 "layout(triangle_strip, max_vertices = 4) out;\n"
6777 /* Sub-routine */
6778 "subroutine void SubroutineGSType(inout vec4 result);\n"
6779 "\n"
6780 "subroutine(SubroutineGSType) void SubroutineGS1(inout vec4 result)\n"
6781 "{\n"
6782 " result += vec4(0, 0, 0, "
6783 << float(n_id + 1) * 0.425f
6784 << ");\n"
6785 "}\n"
6786 "subroutine(SubroutineGSType) void SubroutineGS2(inout vec4 result)\n"
6787 "{\n"
6788 " result += vec4(0, 0, 0, "
6789 << float(n_id + 1) * 0.0425f
6790 << ");\n"
6791 "}\n"
6792 "\n"
6793 "subroutine uniform SubroutineGSType function;\n"
6794 "\n"
6795 /* Input block */
6796 "in TE_DATA\n"
6797 "{\n"
6798 " vec4 data;\n"
6799 "} in_te[];\n"
6800 "\n"
6801 /* Output block */
6802 "out GS_DATA\n"
6803 "{\n"
6804 " vec4 data;\n"
6805 "} out_gs;\n"
6806 "\n"
6807 "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n"
6808 "out gl_PerVertex { vec4 gl_Position; };\n"
6809 /* main() declaration */
6810 "void main()\n"
6811 "{\n"
6812 " vec4 data = in_te[0].data;\n"
6813 "\n"
6814 " function(data);\n"
6815 "\n"
6816 " gl_Position = vec4(1, -1, 0, 1);\n"
6817 " out_gs.data = data;\n"
6818 " EmitVertex();\n"
6819 "\n"
6820 " gl_Position = vec4(-1, -1, 0, 1);\n"
6821 " out_gs.data = data;\n"
6822 " EmitVertex();\n"
6823 "\n"
6824 " gl_Position = vec4(1, 1, 0, 1);\n"
6825 " out_gs.data = data;\n"
6826 " EmitVertex();\n"
6827 "\n"
6828 " gl_Position = vec4(-1, 1, 0, 1);\n"
6829 " out_gs.data = data;\n"
6830 " EmitVertex();\n"
6831 " EndPrimitive();\n"
6832 "}\n";
6833
6834 return result_sstream.str();
6835 }
6836
6837 /** Retrieves body of a tessellation control shader that should be used for the test.
6838 * The subroutine implementations are slightly changed, depending on the
6839 * index of the shader, as specified by the caller.
6840 *
6841 * @param n_id Index of the shader.
6842 *
6843 * @return Requested string.
6844 **/
getTessellationControlShaderBody(unsigned int n_id)6845 std::string FunctionalTest13::getTessellationControlShaderBody(unsigned int n_id)
6846 {
6847 std::stringstream result_sstream;
6848
6849 /* Pre-amble */
6850 result_sstream << "#version 400\n"
6851 "\n"
6852 "#extension GL_ARB_shader_subroutine : require\n"
6853 "\n"
6854 "layout(vertices = 4) out;\n"
6855 /* Sub-routine */
6856 "subroutine void SubroutineTCType(inout vec4 result);\n"
6857 "\n"
6858 "subroutine(SubroutineTCType) void SubroutineTC1(inout vec4 result)\n"
6859 "{\n"
6860 " result += vec4(0, "
6861 << float(n_id + 1) * 0.25f
6862 << ", 0, 0);\n"
6863 "}\n"
6864 "subroutine(SubroutineTCType) void SubroutineTC2(inout vec4 result)\n"
6865 "{\n"
6866 " result += vec4(0, "
6867 << float(n_id + 1) * 0.025f
6868 << ", 0, 0);\n"
6869 "}\n"
6870 "\n"
6871 "subroutine uniform SubroutineTCType function;\n"
6872 "\n"
6873 /* Input block */
6874 "in VS_DATA\n"
6875 "{\n"
6876 " vec4 data;\n"
6877 "} in_vs[];\n"
6878 "\n"
6879 /* Output block */
6880 "out TC_DATA\n"
6881 "{\n"
6882 " vec4 data;\n"
6883 "} out_tc[];\n"
6884 "\n"
6885 "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n"
6886 "out gl_PerVertex { vec4 gl_Position; } gl_out[];\n"
6887 /* main() declaration */
6888 "void main()\n"
6889 "{\n"
6890 " gl_TessLevelOuter[0] = 1.0;\n"
6891 " gl_TessLevelOuter[1] = 1.0;\n"
6892 " gl_TessLevelOuter[2] = 1.0;\n"
6893 " gl_TessLevelOuter[3] = 1.0;\n"
6894 " gl_TessLevelInner[0] = 1.0;\n"
6895 " gl_TessLevelInner[1] = 1.0;\n"
6896 " gl_out[gl_InvocationID].gl_Position = gl_in[0].gl_Position;\n"
6897 " out_tc[gl_InvocationID].data = in_vs[0].data;\n"
6898 "\n"
6899 " function(out_tc[gl_InvocationID].data);\n"
6900 "}\n";
6901
6902 return result_sstream.str();
6903 }
6904
6905 /** Retrieves body of a tessellation evaluation shader that should be used for the test.
6906 * The subroutine implementations are slightly changed, depending on the
6907 * index of the shader, as specified by the caller.
6908 *
6909 * @param n_id Index of the shader.
6910 *
6911 * @return Requested string.
6912 **/
getTessellationEvaluationShaderBody(unsigned int n_id)6913 std::string FunctionalTest13::getTessellationEvaluationShaderBody(unsigned int n_id)
6914 {
6915 std::stringstream result_sstream;
6916
6917 /* Pre-amble */
6918 result_sstream << "#version 400\n"
6919 "\n"
6920 "#extension GL_ARB_shader_subroutine : require\n"
6921 "\n"
6922 "layout(quads, point_mode) in;\n"
6923 /* Sub-routine */
6924 "subroutine void SubroutineTEType(inout vec4 result);\n"
6925 "\n"
6926 "subroutine(SubroutineTEType) void SubroutineTE1(inout vec4 result)\n"
6927 "{\n"
6928 " result += vec4(0, 0, "
6929 << float(n_id + 1) * 0.325f
6930 << ", 0);\n"
6931 "}\n"
6932 "subroutine(SubroutineTEType) void SubroutineTE2(inout vec4 result)\n"
6933 "{\n"
6934 " result += vec4(0, 0, "
6935 << float(n_id + 1) * 0.0325f
6936 << ", 0);\n"
6937 "}\n"
6938 "\n"
6939 "subroutine uniform SubroutineTEType function;\n"
6940 "\n"
6941 /* Input block */
6942 "in TC_DATA\n"
6943 "{\n"
6944 " vec4 data;\n"
6945 "} in_tc[];\n"
6946 "\n"
6947 /* Output block */
6948 "out TE_DATA\n"
6949 "{\n"
6950 " vec4 data;\n"
6951 "} out_te;\n"
6952 "\n"
6953 "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n"
6954 "out gl_PerVertex { vec4 gl_Position; };\n"
6955 /* main() declaration */
6956 "void main()\n"
6957 "{\n"
6958 " gl_Position = gl_in[0].gl_Position;\n"
6959 " out_te.data = in_tc[0].data;\n"
6960 "\n"
6961 " function(out_te.data);\n"
6962 "}\n";
6963
6964 return result_sstream.str();
6965 }
6966
6967 /** Retrieves body of a vertex shader that should be used for the test.
6968 * The subroutine implementations are slightly changed, depending on the
6969 * index of the shader, as specified by the caller.
6970 *
6971 * @param n_id Index of the shader.
6972 *
6973 * @return Requested string.
6974 **/
getVertexShaderBody(unsigned int n_id)6975 std::string FunctionalTest13::getVertexShaderBody(unsigned int n_id)
6976 {
6977 std::stringstream result_sstream;
6978
6979 /* Pre-amble */
6980 result_sstream << "#version 400\n"
6981 "\n"
6982 "#extension GL_ARB_shader_subroutine : require\n"
6983 "#extension GL_ARB_separate_shader_objects: require\n"
6984 "\n"
6985 /* Sub-routine */
6986 "subroutine void SubroutineVSType(inout vec4 result);\n"
6987 "\n"
6988 "subroutine(SubroutineVSType) void SubroutineVS1(inout vec4 result)\n"
6989 "{\n"
6990 " result += vec4("
6991 << float(n_id + 1) * 0.125f
6992 << ", 0, 0, 0);\n"
6993 "}\n"
6994 "subroutine(SubroutineVSType) void SubroutineVS2(inout vec4 result)\n"
6995 "{\n"
6996 " result += vec4("
6997 << float(n_id + 1) * 0.0125f
6998 << ", 0, 0, 0);\n"
6999 "}\n"
7000 "\n"
7001 "subroutine uniform SubroutineVSType function;\n"
7002 "\n"
7003 /* Output block */
7004 "out VS_DATA\n"
7005 "{\n"
7006 " vec4 data;\n"
7007 "} out_vs;\n"
7008 "\n"
7009 "out gl_PerVertex { vec4 gl_Position; };\n"
7010 /* main() declaration */
7011 "void main()\n"
7012 "{\n"
7013 " gl_Position = vec4(0, 0, 0, 1);\n"
7014 " out_vs.data = vec4(0);\n"
7015 "\n"
7016 " function(out_vs.data);\n"
7017 "\n"
7018 "}\n";
7019
7020 return result_sstream.str();
7021 }
7022
7023 /** Initializes all GL objects required to run the test. Also modifies a few
7024 * GL states in order for the test to run correctly.
7025 **/
initTest()7026 void FunctionalTest13::initTest()
7027 {
7028 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
7029
7030 /* Set up viewport */
7031 gl.viewport(0 /* x */, 0 /* y */, m_to_width, m_to_height);
7032 GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed.");
7033
7034 /* Make sure no program is used */
7035 gl.useProgram(0);
7036 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
7037
7038 /* Generate a pipeline object */
7039 gl.genProgramPipelines(1, &m_pipeline_id);
7040 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() call failed.");
7041
7042 gl.bindProgramPipeline(m_pipeline_id);
7043 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
7044
7045 /* Initialize all shader programs */
7046 for (unsigned int n_id = 0; n_id < 2 /* variants for each shader type */; ++n_id)
7047 {
7048 std::string fs_body = getFragmentShaderBody(n_id);
7049 const char *fs_body_raw_ptr = fs_body.c_str();
7050 std::string gs_body = getGeometryShaderBody(n_id);
7051 const char *gs_body_raw_ptr = gs_body.c_str();
7052 std::string tc_body = getTessellationControlShaderBody(n_id);
7053 const char *tc_body_raw_ptr = tc_body.c_str();
7054 std::string te_body = getTessellationEvaluationShaderBody(n_id);
7055 const char *te_body_raw_ptr = te_body.c_str();
7056 std::string vs_body = getVertexShaderBody(n_id);
7057 const char *vs_body_raw_ptr = vs_body.c_str();
7058
7059 m_fs_po_ids[n_id] = gl.createShaderProgramv(GL_FRAGMENT_SHADER, 1 /* count */, &fs_body_raw_ptr);
7060 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
7061
7062 m_gs_po_ids[n_id] = gl.createShaderProgramv(GL_GEOMETRY_SHADER, 1 /* count */, &gs_body_raw_ptr);
7063 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
7064
7065 m_tc_po_ids[n_id] = gl.createShaderProgramv(GL_TESS_CONTROL_SHADER, 1 /* count */, &tc_body_raw_ptr);
7066 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
7067
7068 m_te_po_ids[n_id] = gl.createShaderProgramv(GL_TESS_EVALUATION_SHADER, 1 /* count */, &te_body_raw_ptr);
7069 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
7070
7071 m_vs_po_ids[n_id] = gl.createShaderProgramv(GL_VERTEX_SHADER, 1 /* count */, &vs_body_raw_ptr);
7072 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
7073
7074 /* Verify that all shader program objects have been linked successfully */
7075 const glw::GLuint po_ids[] = {
7076 m_fs_po_ids[n_id], m_gs_po_ids[n_id], m_tc_po_ids[n_id], m_te_po_ids[n_id], m_vs_po_ids[n_id],
7077 };
7078 const unsigned int n_po_ids = sizeof(po_ids) / sizeof(po_ids[0]);
7079
7080 for (unsigned int n_po_id = 0; n_po_id < n_po_ids; ++n_po_id)
7081 {
7082 glw::GLint link_status = GL_FALSE;
7083 glw::GLuint po_id = po_ids[n_po_id];
7084
7085 gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status);
7086 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
7087
7088 if (link_status != GL_TRUE)
7089 {
7090 TCU_FAIL("Shader program object linking failed.");
7091 }
7092 } /* for (all shader program objects) */
7093 } /* for (both shader program object variants) */
7094
7095 /* Generate a texture object. We will use the base mip-map as a render-target */
7096 gl.genTextures(1, &m_to_id);
7097 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed.");
7098
7099 gl.bindTexture(GL_TEXTURE_2D, m_to_id);
7100 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
7101
7102 gl.texStorage2D(GL_TEXTURE_2D, 1 /* levels */, GL_RGBA32F, m_to_width, m_to_height);
7103 GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed");
7104
7105 /* Generate and configure a FBO we will use for the draw call */
7106 gl.genFramebuffers(1, &m_fbo_id);
7107 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed.");
7108
7109 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
7110 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed.");
7111
7112 gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0 /* level */);
7113 GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
7114
7115 /* Generate & bind a VAO */
7116 gl.genVertexArrays(1, &m_vao_id);
7117 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
7118
7119 gl.bindVertexArray(m_vao_id);
7120 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
7121
7122 /* Set up tessellation */
7123 gl.patchParameteri(GL_PATCH_VERTICES, 1);
7124 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteri() call failed.");
7125
7126 /* Set up pixel storage alignment */
7127 gl.pixelStorei(GL_PACK_ALIGNMENT, 1);
7128 GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call failed.");
7129
7130 /* Allocate enough space to hold color attachment data */
7131 m_read_buffer = (unsigned char *)new float[m_to_width * m_to_height * 4 /* rgba */];
7132 }
7133
7134 /** Executes test iteration.
7135 *
7136 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
7137 */
iterate()7138 tcu::TestNode::IterateResult FunctionalTest13::iterate()
7139 {
7140 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
7141
7142 /* Do not execute the test if GL_ARB_shader_subroutine and GL_ARB_separate_shader_objects
7143 * are not supported */
7144 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
7145 {
7146 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
7147 }
7148
7149 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_separate_shader_objects"))
7150 {
7151 throw tcu::NotSupportedError("GL_ARB_separate_shader_objects is not supported");
7152 }
7153
7154 /* Initialize all GL objects before we continue */
7155 initTest();
7156
7157 /* Iterate over all possible FS/GS/TC/TE/VS permutations */
7158 for (int n_shader_permutation = 0; n_shader_permutation < 32 /* 2^5 */; ++n_shader_permutation)
7159 {
7160 const unsigned int n_fs_idx = ((n_shader_permutation & (1 << 0)) != 0) ? 1 : 0;
7161 const unsigned int n_gs_idx = ((n_shader_permutation & (1 << 1)) != 0) ? 1 : 0;
7162 const unsigned int n_tc_idx = ((n_shader_permutation & (1 << 2)) != 0) ? 1 : 0;
7163 const unsigned int n_te_idx = ((n_shader_permutation & (1 << 3)) != 0) ? 1 : 0;
7164 const unsigned int n_vs_idx = ((n_shader_permutation & (1 << 4)) != 0) ? 1 : 0;
7165 const unsigned int fs_po_id = m_fs_po_ids[n_fs_idx];
7166 const unsigned int gs_po_id = m_gs_po_ids[n_gs_idx];
7167 const unsigned int tc_po_id = m_tc_po_ids[n_tc_idx];
7168 const unsigned int te_po_id = m_te_po_ids[n_te_idx];
7169 const unsigned int vs_po_id = m_vs_po_ids[n_vs_idx];
7170
7171 /* Configure fragment shader stage */
7172 gl.useProgramStages(m_pipeline_id, GL_FRAGMENT_SHADER_BIT, fs_po_id);
7173 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed for GL_FRAGMENT_SHADER_BIT bit");
7174
7175 /* Configure geometry shader stage */
7176 gl.useProgramStages(m_pipeline_id, GL_GEOMETRY_SHADER_BIT, gs_po_id);
7177 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed for GL_GEOMETRY_SHADER_BIT bit");
7178
7179 /* Configure tessellation control shader stage */
7180 gl.useProgramStages(m_pipeline_id, GL_TESS_CONTROL_SHADER_BIT, tc_po_id);
7181 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed for GL_TESS_CONTROL_SHADER_BIT bit");
7182
7183 /* Configure tessellation evaluation shader stage */
7184 gl.useProgramStages(m_pipeline_id, GL_TESS_EVALUATION_SHADER_BIT, te_po_id);
7185 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed for GL_TESS_EVALUATION_SHADER_BIT bit");
7186
7187 /* Configure vertex shader stage */
7188 gl.useProgramStages(m_pipeline_id, GL_VERTEX_SHADER_BIT, vs_po_id);
7189 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed for GL_VERTEX_SHADER_BIT bit");
7190
7191 /* Validate the pipeline */
7192 glw::GLint validate_status = GL_FALSE;
7193
7194 gl.validateProgramPipeline(m_pipeline_id);
7195 GLU_EXPECT_NO_ERROR(gl.getError(), "glValidateProgramPipeline() call failed.");
7196
7197 gl.getProgramPipelineiv(m_pipeline_id, GL_VALIDATE_STATUS, &validate_status);
7198 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramPipelineiv() call failed.");
7199
7200 if (validate_status != GL_TRUE)
7201 {
7202 TCU_FAIL("Program pipeline has not been validated successfully.");
7203 }
7204
7205 /* Retrieve subroutine indices */
7206 GLuint fs_subroutine_indices[2] = {(GLuint)-1};
7207 GLint fs_subroutine_uniform_index = 0;
7208 GLuint gs_subroutine_indices[2] = {(GLuint)-1};
7209 GLint gs_subroutine_uniform_index = 0;
7210 GLuint tc_subroutine_indices[2] = {(GLuint)-1};
7211 GLint tc_subroutine_uniform_index = 0;
7212 GLuint te_subroutine_indices[2] = {(GLuint)-1};
7213 GLint te_subroutine_uniform_index = 0;
7214 GLuint vs_subroutine_indices[2] = {(GLuint)-1};
7215 GLint vs_subroutine_uniform_index = 0;
7216
7217 for (unsigned int n_subroutine = 0; n_subroutine < 2; ++n_subroutine)
7218 {
7219 std::stringstream fs_subroutine_name_sstream;
7220 std::stringstream gs_subroutine_name_sstream;
7221 std::stringstream tc_subroutine_name_sstream;
7222 std::stringstream te_subroutine_name_sstream;
7223 std::stringstream vs_subroutine_name_sstream;
7224
7225 fs_subroutine_name_sstream << "SubroutineFS" << (n_subroutine + 1);
7226 gs_subroutine_name_sstream << "SubroutineGS" << (n_subroutine + 1);
7227 tc_subroutine_name_sstream << "SubroutineTC" << (n_subroutine + 1);
7228 te_subroutine_name_sstream << "SubroutineTE" << (n_subroutine + 1);
7229 vs_subroutine_name_sstream << "SubroutineVS" << (n_subroutine + 1);
7230
7231 fs_subroutine_indices[n_subroutine] =
7232 gl.getSubroutineIndex(fs_po_id, GL_FRAGMENT_SHADER, fs_subroutine_name_sstream.str().c_str());
7233 gs_subroutine_indices[n_subroutine] =
7234 gl.getSubroutineIndex(gs_po_id, GL_GEOMETRY_SHADER, gs_subroutine_name_sstream.str().c_str());
7235 tc_subroutine_indices[n_subroutine] =
7236 gl.getSubroutineIndex(tc_po_id, GL_TESS_CONTROL_SHADER, tc_subroutine_name_sstream.str().c_str());
7237 te_subroutine_indices[n_subroutine] =
7238 gl.getSubroutineIndex(te_po_id, GL_TESS_EVALUATION_SHADER, te_subroutine_name_sstream.str().c_str());
7239 vs_subroutine_indices[n_subroutine] =
7240 gl.getSubroutineIndex(vs_po_id, GL_VERTEX_SHADER, vs_subroutine_name_sstream.str().c_str());
7241 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineIndex() call(s) failed.");
7242
7243 if (fs_subroutine_indices[n_subroutine] == (GLuint)-1 ||
7244 gs_subroutine_indices[n_subroutine] == (GLuint)-1 ||
7245 tc_subroutine_indices[n_subroutine] == (GLuint)-1 ||
7246 te_subroutine_indices[n_subroutine] == (GLuint)-1 || vs_subroutine_indices[n_subroutine] == (GLuint)-1)
7247 {
7248 m_testCtx.getLog() << tcu::TestLog::Message
7249 << "At least one subroutine was not recognized by glGetSubroutineIndex() call. "
7250 "(fs:"
7251 << fs_subroutine_indices[n_subroutine]
7252 << ", gs:" << gs_subroutine_indices[n_subroutine]
7253 << ", tc:" << tc_subroutine_indices[n_subroutine]
7254 << ", te:" << te_subroutine_indices[n_subroutine]
7255 << ", vs:" << vs_subroutine_indices[n_subroutine] << ")."
7256 << tcu::TestLog::EndMessage;
7257
7258 TCU_FAIL("At least one subroutine was not recognized");
7259 }
7260 } /* for (both subroutines) */
7261
7262 /* Retrieve subroutine uniform indices */
7263 fs_subroutine_uniform_index = gl.getSubroutineUniformLocation(fs_po_id, GL_FRAGMENT_SHADER, "function");
7264 gs_subroutine_uniform_index = gl.getSubroutineUniformLocation(gs_po_id, GL_GEOMETRY_SHADER, "function");
7265 tc_subroutine_uniform_index = gl.getSubroutineUniformLocation(tc_po_id, GL_TESS_CONTROL_SHADER, "function");
7266 te_subroutine_uniform_index = gl.getSubroutineUniformLocation(te_po_id, GL_TESS_EVALUATION_SHADER, "function");
7267 vs_subroutine_uniform_index = gl.getSubroutineUniformLocation(vs_po_id, GL_VERTEX_SHADER, "function");
7268
7269 if (fs_subroutine_uniform_index == -1 || gs_subroutine_uniform_index == -1 ||
7270 tc_subroutine_uniform_index == -1 || te_subroutine_uniform_index == -1 || vs_subroutine_uniform_index == -1)
7271 {
7272 m_testCtx.getLog() << tcu::TestLog::Message
7273 << "At least one subroutine uniform is considered inactive by "
7274 "glGetSubroutineUniformLocation ("
7275 "fs:"
7276 << fs_subroutine_uniform_index << ", gs:" << gs_subroutine_uniform_index
7277 << ", tc:" << tc_subroutine_uniform_index << ", te:" << te_subroutine_uniform_index
7278 << ", vs:" << vs_subroutine_uniform_index << ")." << tcu::TestLog::EndMessage;
7279
7280 TCU_FAIL("At least one subroutine uniform is considered inactive");
7281 }
7282
7283 /* Check if both subroutines work correctly in each stage */
7284 for (int n_subroutine_permutation = 0; n_subroutine_permutation < 32; /* 2^5 */
7285 ++n_subroutine_permutation)
7286 {
7287 unsigned int n_fs_subroutine = ((n_subroutine_permutation & (1 << 0)) != 0) ? 1 : 0;
7288 unsigned int n_gs_subroutine = ((n_subroutine_permutation & (1 << 1)) != 0) ? 1 : 0;
7289 unsigned int n_tc_subroutine = ((n_subroutine_permutation & (1 << 2)) != 0) ? 1 : 0;
7290 unsigned int n_te_subroutine = ((n_subroutine_permutation & (1 << 3)) != 0) ? 1 : 0;
7291 unsigned int n_vs_subroutine = ((n_subroutine_permutation & (1 << 4)) != 0) ? 1 : 0;
7292
7293 /* Configure subroutine uniforms */
7294 struct
7295 {
7296 glw::GLenum stage;
7297 glw::GLuint po_id;
7298 glw::GLuint *indices;
7299 } configurations[] = {
7300 {GL_FRAGMENT_SHADER, fs_po_id, fs_subroutine_indices + n_fs_subroutine},
7301 {GL_GEOMETRY_SHADER, gs_po_id, gs_subroutine_indices + n_gs_subroutine},
7302 {GL_TESS_CONTROL_SHADER, tc_po_id, tc_subroutine_indices + n_tc_subroutine},
7303 {GL_TESS_EVALUATION_SHADER, te_po_id, te_subroutine_indices + n_te_subroutine},
7304 {GL_VERTEX_SHADER, vs_po_id, vs_subroutine_indices + n_vs_subroutine},
7305 };
7306
7307 for (int i = 0; i < 5; ++i)
7308 {
7309 gl.activeShaderProgram(m_pipeline_id, configurations[i].po_id);
7310 GLU_EXPECT_NO_ERROR(gl.getError(), "glActiveShaderProgram() call failed.");
7311
7312 gl.uniformSubroutinesuiv(configurations[i].stage, 1 /* count */, configurations[i].indices);
7313 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniformSubroutinesuiv() call failed.");
7314 }
7315
7316 /* Render a full-screen quad with the pipeline */
7317 gl.clear(GL_COLOR_BUFFER_BIT);
7318 GLU_EXPECT_NO_ERROR(gl.getError(), "glClear() call failed.");
7319
7320 gl.drawArrays(GL_PATCHES, 0 /* first */, 1 /* count */);
7321 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
7322
7323 /* Read color attachment's contents */
7324 gl.readPixels(0, /* x */
7325 0, /* y */
7326 m_to_width, m_to_height, GL_RGBA, GL_FLOAT, m_read_buffer);
7327 GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed.");
7328
7329 /* Verify the contents */
7330 verifyReadBuffer(n_fs_idx, n_fs_subroutine, n_gs_idx, n_gs_subroutine, n_tc_idx, n_tc_subroutine, n_te_idx,
7331 n_te_subroutine, n_vs_idx, n_vs_subroutine);
7332 } /* for (all subroutine permutations) */
7333 } /* for (all program shader object permutations) */
7334
7335 /** All done */
7336 if (m_has_test_passed)
7337 {
7338 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
7339 }
7340 else
7341 {
7342 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
7343 }
7344
7345 return STOP;
7346 }
7347
7348 /** Verifies the data that have been rendered using a pipeline object.
7349 * Contents of the data depends on indices of the shaders, as well as
7350 * on the subroutines that have been activated for particular iteration.
7351 *
7352 * @param n_fs_id Index of the fragment shader used for the iteration;
7353 * @param n_fs_subroutine Index of the subroutine used in the fragment shader
7354 * for the iteration;
7355 * @param n_gs_id Index of the geometry shader used for the iteration;
7356 * @param n_gs_subroutine Index of the subroutine used in the geometry shader
7357 * for the iteration;
7358 * @param n_tc_id Index of the tessellation control shader used for the iteration;
7359 * @param n_tc_subroutine Index of the subroutine used in the tessellation control
7360 * shader for the iteration;
7361 * @param n_te_id Index of the tessellation evaluation shader used for the iteration;
7362 * @param n_te_subroutine Index of the subroutine used in the tessellation evaluation
7363 * shader for the iteration;
7364 * @param n_vs_id Index of the vertex shader used for the iteration;
7365 * @param n_vs_subroutine Index of the subroutine used in the vertex shader for
7366 * the iteration.
7367 */
verifyReadBuffer(unsigned int n_fs_id,unsigned int n_fs_subroutine,unsigned int n_gs_id,unsigned int n_gs_subroutine,unsigned int n_tc_id,unsigned int n_tc_subroutine,unsigned int n_te_id,unsigned int n_te_subroutine,unsigned int n_vs_id,unsigned int n_vs_subroutine)7368 void FunctionalTest13::verifyReadBuffer(unsigned int n_fs_id, unsigned int n_fs_subroutine, unsigned int n_gs_id,
7369 unsigned int n_gs_subroutine, unsigned int n_tc_id,
7370 unsigned int n_tc_subroutine, unsigned int n_te_id,
7371 unsigned int n_te_subroutine, unsigned int n_vs_id,
7372 unsigned int n_vs_subroutine)
7373 {
7374 float expected_color[4] = {0};
7375 float fs_modifier[4] = {0};
7376 float gs_modifier[4] = {0};
7377 float tc_modifier[4] = {0};
7378 float te_modifier[4] = {0};
7379 float vs_modifier[4] = {0};
7380
7381 if (n_fs_subroutine == 0)
7382 {
7383 for (unsigned int n_component = 0; n_component < 4; ++n_component)
7384 {
7385 fs_modifier[n_component] = float(n_fs_id + n_component + 1) / 10.0f;
7386 }
7387 }
7388 else
7389 {
7390 for (unsigned int n_component = 0; n_component < 4; ++n_component)
7391 {
7392 fs_modifier[n_component] = float(n_fs_id + n_component + 1) / 20.0f;
7393 }
7394 }
7395
7396 if (n_gs_subroutine == 0)
7397 {
7398 gs_modifier[3] = float(n_gs_id + 1) * 0.425f;
7399 }
7400 else
7401 {
7402 gs_modifier[3] = float(n_gs_id + 1) * 0.0425f;
7403 }
7404
7405 if (n_tc_subroutine == 0)
7406 {
7407 tc_modifier[1] = float(n_tc_id + 1) * 0.25f;
7408 }
7409 else
7410 {
7411 tc_modifier[1] = float(n_tc_id + 1) * 0.025f;
7412 }
7413
7414 if (n_te_subroutine == 0)
7415 {
7416 te_modifier[2] = float(n_te_id + 1) * 0.325f;
7417 }
7418 else
7419 {
7420 te_modifier[2] = float(n_te_id + 1) * 0.0325f;
7421 }
7422
7423 if (n_vs_subroutine == 0)
7424 {
7425 vs_modifier[0] = float(n_vs_id + 1) * 0.125f;
7426 }
7427 else
7428 {
7429 vs_modifier[0] = float(n_vs_id + 1) * 0.0125f;
7430 }
7431
7432 /* Determine the expected color */
7433 for (unsigned int n_component = 0; n_component < 4 /* rgba */; ++n_component)
7434 {
7435 expected_color[n_component] = fs_modifier[n_component] + gs_modifier[n_component] + tc_modifier[n_component] +
7436 te_modifier[n_component] + vs_modifier[n_component];
7437 }
7438
7439 /* Verify all read texels are valid */
7440 const float epsilon = 1e-5f;
7441 bool should_continue = true;
7442
7443 for (unsigned int y = 0; y < m_to_height && should_continue; ++y)
7444 {
7445 const float *row_ptr = (const float *)m_read_buffer + y * m_to_width * 4; /* rgba */
7446
7447 for (unsigned int x = 0; x < m_to_width && should_continue; ++x)
7448 {
7449 const float *texel_ptr = row_ptr + x * 4; /* rgba */
7450
7451 if (de::abs(texel_ptr[0] - expected_color[0]) > epsilon ||
7452 de::abs(texel_ptr[1] - expected_color[1]) > epsilon ||
7453 de::abs(texel_ptr[2] - expected_color[2]) > epsilon ||
7454 de::abs(texel_ptr[3] - expected_color[3]) > epsilon)
7455 {
7456 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid texel rendered at (" << x << ", " << y
7457 << ") for "
7458 "the following configuration: "
7459 "n_fs_id:"
7460 << n_fs_id << " n_fs_subroutine:" << n_fs_subroutine << " n_gs_id:" << n_gs_id
7461 << " n_gs_subroutine:" << n_gs_subroutine << " n_tc_id:" << n_tc_id
7462 << " n_tc_subroutine:" << n_tc_subroutine << " n_te_id:" << n_te_id
7463 << " n_te_subroutine:" << n_te_subroutine << " n_vs_id:" << n_vs_id
7464 << " n_vs_subroutine:" << n_vs_subroutine
7465 << "; expected:"
7466 "("
7467 << expected_color[0] << ", " << expected_color[1] << ", " << expected_color[2]
7468 << ", " << expected_color[3]
7469 << "), found:"
7470 "("
7471 << texel_ptr[0] << ", " << texel_ptr[1] << ", " << texel_ptr[2] << ", "
7472 << texel_ptr[3] << ")." << tcu::TestLog::EndMessage;
7473
7474 m_has_test_passed = false;
7475 should_continue = false;
7476 }
7477 } /* for (all columns) */
7478 } /* for (all rows) */
7479 }
7480
7481 /** Constructor
7482 *
7483 * @param context CTS context
7484 **/
FunctionalTest14_15(deqp::Context & context)7485 FunctionalTest14_15::FunctionalTest14_15(deqp::Context &context)
7486 : TestCase(context, "structure_parameters_program_binary", "Verify structures can be used as parameters")
7487 , m_uniform_location(0)
7488 {
7489 }
7490
7491 /** Execute test
7492 *
7493 * @return tcu::TestNode::STOP
7494 **/
iterate()7495 tcu::TestNode::IterateResult FunctionalTest14_15::iterate()
7496 {
7497 static const GLchar *vertex_shader_code =
7498 "#version 400 core\n"
7499 "#extension GL_ARB_shader_subroutine : require\n"
7500 "\n"
7501 "precision highp float;\n"
7502 "\n"
7503 "struct data\n"
7504 "{\n"
7505 " uint r;\n"
7506 " uint g;\n"
7507 " uint b;\n"
7508 " uint a;\n"
7509 "};\n"
7510 "\n"
7511 "subroutine void routine_type_1(in data iparam, out data oparam);\n"
7512 "subroutine void routine_type_2(inout data arg);\n"
7513 "\n"
7514 "subroutine (routine_type_1) void invert(in data iparam, out data oparam)\n"
7515 "{\n"
7516 " oparam.r = iparam.a;\n"
7517 " oparam.g = iparam.b;\n"
7518 " oparam.b = iparam.g;\n"
7519 " oparam.a = iparam.r;\n"
7520 "}\n"
7521 "\n"
7522 "subroutine (routine_type_1) void increment(in data iparam, out data oparam)\n"
7523 "{\n"
7524 " oparam.r = 1 + iparam.r;\n"
7525 " oparam.g = 1 + iparam.g;\n"
7526 " oparam.b = 1 + iparam.b;\n"
7527 " oparam.a = 1 + iparam.a;\n"
7528 "}\n"
7529 "\n"
7530 "subroutine (routine_type_2) void div_by_2(inout data arg)\n"
7531 "{\n"
7532 " arg.r = arg.r / 2;\n"
7533 " arg.g = arg.g / 2;\n"
7534 " arg.b = arg.b / 2;\n"
7535 " arg.a = arg.a / 2;\n"
7536 "}\n"
7537 "\n"
7538 "subroutine (routine_type_2) void decrement(inout data arg)\n"
7539 "{\n"
7540 " arg.r = arg.r - 1;\n"
7541 " arg.g = arg.g - 1;\n"
7542 " arg.b = arg.b - 1;\n"
7543 " arg.a = arg.a - 1;\n"
7544 "}\n"
7545 "\n"
7546 "subroutine uniform routine_type_1 routine_1;\n"
7547 "subroutine uniform routine_type_2 routine_2;\n"
7548 "\n"
7549 "uniform uvec4 uni_input;\n"
7550 "\n"
7551 "out uvec4 out_routine_1;\n"
7552 "out uvec4 out_routine_2;\n"
7553 "\n"
7554 "\n"
7555 "void main()\n"
7556 "{\n"
7557 " data routine_1_input;\n"
7558 " data routine_1_output;\n"
7559 " data routine_2_arg;\n"
7560 "\n"
7561 " routine_1_input.r = uni_input.r;\n"
7562 " routine_1_input.g = uni_input.g;\n"
7563 " routine_1_input.b = uni_input.b;\n"
7564 " routine_1_input.a = uni_input.a;\n"
7565 "\n"
7566 " routine_2_arg.r = uni_input.r;\n"
7567 " routine_2_arg.g = uni_input.g;\n"
7568 " routine_2_arg.b = uni_input.b;\n"
7569 " routine_2_arg.a = uni_input.a;\n"
7570 "\n"
7571 " routine_1(routine_1_input, routine_1_output);\n"
7572 " routine_2(routine_2_arg);\n"
7573 "\n"
7574 " out_routine_1.r = routine_1_output.r;\n"
7575 " out_routine_1.g = routine_1_output.g;\n"
7576 " out_routine_1.b = routine_1_output.b;\n"
7577 " out_routine_1.a = routine_1_output.a;\n"
7578 "\n"
7579 " out_routine_2.r = routine_2_arg.r;\n"
7580 " out_routine_2.g = routine_2_arg.g;\n"
7581 " out_routine_2.b = routine_2_arg.b;\n"
7582 " out_routine_2.a = routine_2_arg.a;\n"
7583 "}\n"
7584 "\n";
7585
7586 static const GLchar *subroutine_names[][2] = {{"invert", "increment"}, {"div_by_2", "decrement"}};
7587 static const GLuint n_subroutine_types = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
7588
7589 static const GLchar *subroutine_uniform_names[] = {"routine_1", "routine_2"};
7590 static const GLuint n_subroutine_uniform_names =
7591 sizeof(subroutine_uniform_names) / sizeof(subroutine_uniform_names[0]);
7592
7593 static const GLchar *uniform_name = "uni_input";
7594 static const GLchar *varying_names[] = {"out_routine_1", "out_routine_2"};
7595
7596 static const GLuint n_varying_names = sizeof(varying_names) / sizeof(varying_names[0]);
7597 static const GLuint transform_feedback_buffer_size = n_varying_names * 4 * sizeof(GLuint);
7598
7599 /* Test data */
7600 static const Utils::vec4<GLuint> uni_input[] = {Utils::vec4<GLuint>(8, 64, 4096, 16777216),
7601 Utils::vec4<GLuint>(8, 64, 4096, 16777216)};
7602
7603 static const Utils::vec4<GLuint> out_routine_1[] = {Utils::vec4<GLuint>(16777216, 4096, 64, 8),
7604 Utils::vec4<GLuint>(9, 65, 4097, 16777217)};
7605
7606 static const Utils::vec4<GLuint> out_routine_2[] = {Utils::vec4<GLuint>(4, 32, 2048, 8388608),
7607 Utils::vec4<GLuint>(7, 63, 4095, 16777215)};
7608
7609 static const GLuint n_test_cases = 2;
7610
7611 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
7612 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
7613 {
7614 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
7615 }
7616
7617 /* GL objects */
7618 Utils::program program(m_context);
7619 Utils::buffer transform_feedback_buffer(m_context);
7620 Utils::vertexArray vao(m_context);
7621
7622 bool is_program_binary_supported = program.isProgramBinarySupported();
7623
7624 /* Init GL objects */
7625 program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code,
7626 varying_names /* varying_names */, n_varying_names /* n_varyings */);
7627
7628 /* Do not execute the test if GL_ARB_get_program_binary is not supported */
7629 if (true == is_program_binary_supported)
7630 {
7631 /* Get subroutine indices */
7632 for (GLuint type = 0; type < n_subroutine_types; ++type)
7633 {
7634 m_initial_subroutine_indices[type][0] =
7635 program.getSubroutineIndex(subroutine_names[type][0], GL_VERTEX_SHADER);
7636
7637 m_initial_subroutine_indices[type][1] =
7638 program.getSubroutineIndex(subroutine_names[type][1], GL_VERTEX_SHADER);
7639 }
7640
7641 /* Get subroutine uniform locations */
7642 for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
7643 {
7644 m_initial_subroutine_uniform_locations[uniform] =
7645 program.getSubroutineUniformLocation(subroutine_uniform_names[uniform], GL_VERTEX_SHADER);
7646 }
7647
7648 /* Delete program and recreate it from binary */
7649 std::vector<GLubyte> program_binary;
7650 GLenum binary_format;
7651
7652 program.getBinary(program_binary, binary_format);
7653 program.remove();
7654 program.createFromBinary(program_binary, binary_format);
7655 }
7656
7657 program.use();
7658
7659 vao.generate();
7660 vao.bind();
7661
7662 transform_feedback_buffer.generate();
7663 transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
7664 GL_DYNAMIC_COPY);
7665 transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
7666
7667 /* Get subroutine indices */
7668 for (GLuint type = 0; type < n_subroutine_types; ++type)
7669 {
7670 m_subroutine_indices[type][0] = program.getSubroutineIndex(subroutine_names[type][0], GL_VERTEX_SHADER);
7671 m_subroutine_indices[type][1] = program.getSubroutineIndex(subroutine_names[type][1], GL_VERTEX_SHADER);
7672 }
7673
7674 /* Get subroutine uniform locations */
7675 for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
7676 {
7677 m_subroutine_uniform_locations[uniform] =
7678 program.getSubroutineUniformLocation(subroutine_uniform_names[uniform], GL_VERTEX_SHADER);
7679 }
7680
7681 /* Get uniform locations */
7682 m_uniform_location = program.getUniformLocation(uniform_name);
7683
7684 /* Test */
7685 bool result = true;
7686
7687 /* Test program binary */
7688 if (true == is_program_binary_supported)
7689 {
7690 /* Test indices and locations */
7691 if (false == testIndicesAndLocations())
7692 {
7693 static const GLuint n_subroutines_per_type = 2;
7694
7695 m_context.getTestContext().getLog()
7696 << tcu::TestLog::Message << "Error. Subroutine indices or subroutine uniform location changed."
7697 << tcu::TestLog::EndMessage;
7698
7699 for (GLuint type = 0; type < n_subroutine_types; ++type)
7700 {
7701 for (GLuint i = 0; i < n_subroutines_per_type; ++i)
7702 {
7703 m_context.getTestContext().getLog()
7704 << tcu::TestLog::Message << "Subroutine: " << subroutine_names[type][i]
7705 << " index: " << m_subroutine_indices[type][i]
7706 << " initial index: " << m_initial_subroutine_indices[type][i] << tcu::TestLog::EndMessage;
7707 }
7708 }
7709
7710 for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
7711 {
7712 m_context.getTestContext().getLog()
7713 << tcu::TestLog::Message << "Subroutine uniform: " << subroutine_uniform_names[uniform]
7714 << " location: " << m_subroutine_uniform_locations[uniform]
7715 << " initial location: " << m_initial_subroutine_uniform_locations[uniform]
7716 << tcu::TestLog::EndMessage;
7717 }
7718
7719 result = false;
7720 }
7721
7722 /* Test draw with deafult set of subroutines */
7723 if (false == testDefaultSubroutineSet(uni_input[0], out_routine_1, out_routine_2))
7724 {
7725 result = false;
7726 }
7727 }
7728
7729 for (GLuint i = 0; i < n_test_cases; ++i)
7730 {
7731 if (false == testDraw(i, uni_input[i], out_routine_1[i], out_routine_2[i]))
7732 {
7733 result = false;
7734 }
7735 }
7736
7737 /* Set result */
7738 if (true == result)
7739 {
7740 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
7741 }
7742 else
7743 {
7744 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
7745 }
7746
7747 /* Done */
7748 return tcu::TestNode::STOP;
7749 }
7750
7751 /** Execute draw call and verify results
7752 *
7753 * @param uni_input Input data
7754 * @param expected_routine_1_result Set of expected results of "routine_1"
7755 * @param expected_routine_2_result Set of expected results of "routine_2"
7756 *
7757 * @return true if test pass, false otherwise
7758 **/
testDefaultSubroutineSet(const Utils::vec4<glw::GLuint> & uni_input,const Utils::vec4<glw::GLuint> expected_routine_1_result[2],const Utils::vec4<glw::GLuint> expected_routine_2_result[2]) const7759 bool FunctionalTest14_15::testDefaultSubroutineSet(const Utils::vec4<glw::GLuint> &uni_input,
7760 const Utils::vec4<glw::GLuint> expected_routine_1_result[2],
7761 const Utils::vec4<glw::GLuint> expected_routine_2_result[2]) const
7762 {
7763 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
7764 bool result = true;
7765
7766 /* Set up input data uniforms */
7767 gl.uniform4ui(m_uniform_location, uni_input.m_x, uni_input.m_y, uni_input.m_z, uni_input.m_w);
7768 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
7769
7770 /* Execute draw call with transform feedback */
7771 gl.beginTransformFeedback(GL_POINTS);
7772 GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
7773
7774 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
7775 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
7776
7777 gl.endTransformFeedback();
7778 GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
7779
7780 /* Capture results */
7781 GLuint *feedback_data = (GLuint *)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
7782 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
7783
7784 Utils::vec4<GLuint> routine_1_result;
7785 Utils::vec4<GLuint> routine_2_result;
7786
7787 routine_1_result.m_x = feedback_data[0 + 0];
7788 routine_1_result.m_y = feedback_data[0 + 1];
7789 routine_1_result.m_z = feedback_data[0 + 2];
7790 routine_1_result.m_w = feedback_data[0 + 3];
7791
7792 routine_2_result.m_x = feedback_data[4 + 0];
7793 routine_2_result.m_y = feedback_data[4 + 1];
7794 routine_2_result.m_z = feedback_data[4 + 2];
7795 routine_2_result.m_w = feedback_data[4 + 3];
7796
7797 /* Unmap buffer */
7798 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
7799 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
7800
7801 /* Verifiy */
7802 result = result &&
7803 ((routine_1_result == expected_routine_1_result[0]) || (routine_1_result == expected_routine_1_result[1]));
7804
7805 result = result &&
7806 ((routine_2_result == expected_routine_2_result[0]) || (routine_2_result == expected_routine_2_result[1]));
7807
7808 /* Log error if any */
7809 if (false == result)
7810 {
7811 m_context.getTestContext().getLog()
7812 << tcu::TestLog::Message << "Error. Invalid result." << tcu::TestLog::EndMessage;
7813
7814 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
7815
7816 message << "Routine_1, result: ";
7817
7818 routine_1_result.log(message);
7819
7820 message << "Routine_2, result: ";
7821
7822 routine_2_result.log(message);
7823
7824 message << tcu::TestLog::EndMessage;
7825 }
7826
7827 /* Done */
7828 return result;
7829 }
7830
7831 /** Execute draw call and verify results
7832 *
7833 * @param routine_configuration Subroutine "type" ordinal
7834 * @param uni_input Input data
7835 * @param expected_routine_1_result Expected results of "routine_1"
7836 * @param expected_routine_2_result Expected results of "routine_2"
7837 *
7838 * @return true if test pass, false otherwise
7839 **/
testDraw(glw::GLuint routine_configuration,const Utils::vec4<glw::GLuint> & uni_input,const Utils::vec4<glw::GLuint> & expected_routine_1_result,const Utils::vec4<glw::GLuint> & expected_routine_2_result) const7840 bool FunctionalTest14_15::testDraw(glw::GLuint routine_configuration, const Utils::vec4<glw::GLuint> &uni_input,
7841 const Utils::vec4<glw::GLuint> &expected_routine_1_result,
7842 const Utils::vec4<glw::GLuint> &expected_routine_2_result) const
7843 {
7844 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
7845 bool result = true;
7846 GLuint subroutine_indices[2];
7847 static const GLuint n_subroutine_uniforms = sizeof(subroutine_indices) / sizeof(subroutine_indices[0]);
7848
7849 /* Set up input data uniforms */
7850 gl.uniform4ui(m_uniform_location, uni_input.m_x, uni_input.m_y, uni_input.m_z, uni_input.m_w);
7851 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
7852
7853 /* Prepare subroutine uniform data */
7854 for (GLuint i = 0; i < n_subroutine_uniforms; ++i)
7855 {
7856 const GLuint location = m_subroutine_uniform_locations[i];
7857
7858 subroutine_indices[location] = m_subroutine_indices[i][routine_configuration];
7859 }
7860
7861 /* Set up subroutine uniforms */
7862 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, n_subroutine_uniforms, &subroutine_indices[0]);
7863 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
7864
7865 /* Execute draw call with transform feedback */
7866 gl.beginTransformFeedback(GL_POINTS);
7867 GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
7868
7869 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
7870 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
7871
7872 gl.endTransformFeedback();
7873 GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
7874
7875 /* Capture results */
7876 GLuint *feedback_data = (GLuint *)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
7877 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
7878
7879 Utils::vec4<GLuint> routine_1_result;
7880 Utils::vec4<GLuint> routine_2_result;
7881
7882 routine_1_result.m_x = feedback_data[0 + 0];
7883 routine_1_result.m_y = feedback_data[0 + 1];
7884 routine_1_result.m_z = feedback_data[0 + 2];
7885 routine_1_result.m_w = feedback_data[0 + 3];
7886
7887 routine_2_result.m_x = feedback_data[4 + 0];
7888 routine_2_result.m_y = feedback_data[4 + 1];
7889 routine_2_result.m_z = feedback_data[4 + 2];
7890 routine_2_result.m_w = feedback_data[4 + 3];
7891
7892 /* Unmap buffer */
7893 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
7894 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
7895
7896 /* Verifiy */
7897 result = result && (routine_1_result == expected_routine_1_result);
7898 result = result && (routine_2_result == expected_routine_2_result);
7899
7900 /* Log error if any */
7901 if (false == result)
7902 {
7903 m_context.getTestContext().getLog()
7904 << tcu::TestLog::Message << "Error. Invalid result." << tcu::TestLog::EndMessage;
7905
7906 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
7907
7908 message << "Routine_1, result: ";
7909
7910 routine_1_result.log(message);
7911
7912 message << ", expected: ";
7913
7914 expected_routine_1_result.log(message);
7915
7916 message << "Routine_2, result: ";
7917
7918 routine_2_result.log(message);
7919
7920 message << ", expected: ";
7921
7922 expected_routine_2_result.log(message);
7923
7924 message << tcu::TestLog::EndMessage;
7925 }
7926
7927 /* Done */
7928 return result;
7929 }
7930
7931 /** Verify initial and current values of subroutine indices and subroutines uniform locations
7932 *
7933 * @return true if test pass, false otherwise
7934 **/
testIndicesAndLocations() const7935 bool FunctionalTest14_15::testIndicesAndLocations() const
7936 {
7937 static const GLuint n_subroutine_types = 2;
7938 bool result = true;
7939
7940 /* Verify subroutine indices */
7941 for (GLuint type = 0; type < n_subroutine_types; ++type)
7942 {
7943 result = result && (m_subroutine_indices[type][0] == m_initial_subroutine_indices[type][0]);
7944 result = result && (m_subroutine_indices[type][1] == m_initial_subroutine_indices[type][1]);
7945 }
7946
7947 /* Verify subroutine uniform locations */
7948 for (GLuint uniform = 0; uniform < n_subroutine_types; ++uniform)
7949 {
7950 result = result && (m_subroutine_uniform_locations[uniform] == m_initial_subroutine_uniform_locations[uniform]);
7951 }
7952
7953 return result;
7954 }
7955
7956 /** Constructor.
7957 *
7958 * @param context Rendering context.
7959 *
7960 **/
FunctionalTest16(deqp::Context & context)7961 FunctionalTest16::FunctionalTest16(deqp::Context &context)
7962 : TestCase(context, "subroutine_uniform_reset",
7963 "Checks that when the active program for a shader stage is re-linke or "
7964 "changed by a call to UseProgram, BindProgramPipeline, or UseProgramStages,"
7965 " subroutine uniforms for that stage are reset to arbitrarily chosen default "
7966 "functions with compatible subroutine types.")
7967 , m_are_pipeline_objects_supported(false)
7968 , m_has_test_passed(true)
7969 {
7970 memset(m_fs_ids, 0, sizeof(m_fs_ids));
7971 memset(m_gs_ids, 0, sizeof(m_gs_ids));
7972 memset(m_po_ids, 0, sizeof(m_po_ids));
7973 memset(m_tc_ids, 0, sizeof(m_tc_ids));
7974 memset(m_te_ids, 0, sizeof(m_te_ids));
7975 memset(m_vs_ids, 0, sizeof(m_vs_ids));
7976
7977 memset(m_fs_po_ids, 0, sizeof(m_fs_po_ids));
7978 memset(m_gs_po_ids, 0, sizeof(m_gs_po_ids));
7979 memset(m_pipeline_object_ids, 0, sizeof(m_pipeline_object_ids));
7980 memset(m_tc_po_ids, 0, sizeof(m_tc_po_ids));
7981 memset(m_te_po_ids, 0, sizeof(m_te_po_ids));
7982 memset(m_vs_po_ids, 0, sizeof(m_vs_po_ids));
7983 }
7984
7985 /** Deinitializes all GL objects that may have been created during test execution. */
deinit()7986 void FunctionalTest16::deinit()
7987 {
7988 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
7989
7990 for (unsigned int n_id = 0; n_id < 2; ++n_id)
7991 {
7992 if (m_fs_ids[n_id] != 0)
7993 {
7994 gl.deleteShader(m_fs_ids[n_id]);
7995
7996 m_fs_ids[n_id] = 0;
7997 }
7998
7999 if (m_fs_po_ids[n_id] != 0)
8000 {
8001 gl.deleteProgram(m_fs_po_ids[n_id]);
8002
8003 m_fs_po_ids[n_id] = 0;
8004 }
8005
8006 if (m_gs_ids[n_id] != 0)
8007 {
8008 gl.deleteShader(m_gs_ids[n_id]);
8009
8010 m_gs_ids[n_id] = 0;
8011 }
8012
8013 if (m_gs_po_ids[n_id] != 0)
8014 {
8015 gl.deleteProgram(m_gs_po_ids[n_id]);
8016
8017 m_gs_po_ids[n_id] = 0;
8018 }
8019
8020 if (m_pipeline_object_ids[n_id] != 0)
8021 {
8022 gl.deleteProgramPipelines(1 /* n */, m_pipeline_object_ids + n_id);
8023 }
8024
8025 if (m_po_ids[n_id] != 0)
8026 {
8027 gl.deleteProgram(m_po_ids[n_id]);
8028
8029 m_po_ids[n_id] = 0;
8030 }
8031
8032 if (m_tc_ids[n_id] != 0)
8033 {
8034 gl.deleteShader(m_tc_ids[n_id]);
8035
8036 m_tc_ids[n_id] = 0;
8037 }
8038
8039 if (m_tc_po_ids[n_id] != 0)
8040 {
8041 gl.deleteProgram(m_tc_po_ids[n_id]);
8042
8043 m_tc_po_ids[n_id] = 0;
8044 }
8045
8046 if (m_te_ids[n_id] != 0)
8047 {
8048 gl.deleteShader(m_te_ids[n_id]);
8049
8050 m_te_ids[n_id] = 0;
8051 }
8052
8053 if (m_te_po_ids[n_id] != 0)
8054 {
8055 gl.deleteProgram(m_te_po_ids[n_id]);
8056
8057 m_te_po_ids[n_id] = 0;
8058 }
8059
8060 if (m_vs_ids[n_id] != 0)
8061 {
8062 gl.deleteShader(m_vs_ids[n_id]);
8063
8064 m_vs_ids[n_id] = 0;
8065 }
8066
8067 if (m_vs_po_ids[n_id] != 0)
8068 {
8069 gl.deleteProgram(m_vs_po_ids[n_id]);
8070
8071 m_vs_po_ids[n_id] = 0;
8072 }
8073 } /* for (both IDs) */
8074 }
8075
8076 /** Retrieves body of a shader that should be used for user-specified shader stage.
8077 * This function returns slightly different implementations, depending on index of
8078 * the program/pipeline object the shader will be used for.
8079 *
8080 * @param shader_stage Stage the shader body is to be returned for.
8081 * @param n_id Index of the shader (as per description).
8082 *
8083 * @return Requested string.
8084 **/
getShaderBody(const Utils::_shader_stage & shader_stage,const unsigned int & n_id) const8085 std::string FunctionalTest16::getShaderBody(const Utils::_shader_stage &shader_stage, const unsigned int &n_id) const
8086 {
8087 std::stringstream result_sstream;
8088
8089 result_sstream << "#version 400\n"
8090 "\n"
8091 "#extension GL_ARB_shader_subroutine : require\n"
8092 "\n";
8093
8094 switch (shader_stage)
8095 {
8096 case Utils::SHADER_STAGE_VERTEX:
8097 {
8098 result_sstream << "out gl_PerVertex { vec4 gl_Position; } ;\n";
8099 break;
8100 }
8101 case Utils::SHADER_STAGE_GEOMETRY:
8102 {
8103 result_sstream << "layout(points) in;\n"
8104 "layout(points, max_vertices = 1) out;\n";
8105 result_sstream << "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n";
8106 result_sstream << "out gl_PerVertex { vec4 gl_Position; } ;\n";
8107 break;
8108 }
8109
8110 case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
8111 {
8112 result_sstream << "layout(vertices = 4) out;\n";
8113 result_sstream << "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n";
8114 result_sstream << "out gl_PerVertex { vec4 gl_Position; } gl_out[];\n";
8115 break;
8116 }
8117
8118 case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
8119 {
8120 result_sstream << "layout(quads) in;\n";
8121 result_sstream << "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n";
8122 result_sstream << "out gl_PerVertex { vec4 gl_Position; };\n";
8123 break;
8124 }
8125
8126 default:
8127 break;
8128 } /* switch (shader_stage) */
8129
8130 result_sstream << "\n"
8131 "subroutine void subroutineType (inout vec4 result);\n"
8132 "subroutine vec4 subroutineType2(in vec4 data);\n"
8133 "\n"
8134 "subroutine(subroutineType) void function1(inout vec4 result)\n"
8135 "{\n"
8136 " result += vec4("
8137 << (n_id + 1) << ", " << (n_id + 2) << ", " << (n_id + 3) << ", " << (n_id + 4)
8138 << ");\n"
8139 "}\n"
8140 "subroutine(subroutineType) void function2(inout vec4 result)\n"
8141 "{\n"
8142 " result += vec4("
8143 << (n_id + 2) << ", " << (n_id + 3) << ", " << (n_id + 4) << ", " << (n_id + 5)
8144 << ");\n"
8145 "}\n"
8146 "\n"
8147 "subroutine(subroutineType2) vec4 function3(in vec4 data)\n"
8148 "{\n"
8149 " return data * data;\n"
8150 "}\n"
8151 "subroutine(subroutineType2) vec4 function4(in vec4 data)\n"
8152 "{\n"
8153 " return data + data;\n"
8154 "}\n"
8155 "\n"
8156 "subroutine uniform subroutineType subroutine1;\n"
8157 "subroutine uniform subroutineType subroutine2;\n"
8158 "subroutine uniform subroutineType2 subroutine3;\n"
8159 "subroutine uniform subroutineType2 subroutine4;\n"
8160 "\n";
8161
8162 if (shader_stage == Utils::SHADER_STAGE_FRAGMENT)
8163 {
8164 result_sstream << "out vec4 result;\n";
8165 }
8166
8167 result_sstream << "void main()\n"
8168 "{\n";
8169
8170 switch (shader_stage)
8171 {
8172 case Utils::SHADER_STAGE_FRAGMENT:
8173 {
8174 result_sstream << " result = vec4(0);\n"
8175 << " subroutine1(result);\n"
8176 " subroutine2(result);\n"
8177 " result = subroutine3(result) + subroutine4(result);\n";
8178
8179 break;
8180 }
8181
8182 case Utils::SHADER_STAGE_GEOMETRY:
8183 {
8184 result_sstream << " gl_Position = vec4(0);\n"
8185 " subroutine1(gl_Position);\n"
8186 " subroutine2(gl_Position);\n"
8187 " gl_Position = subroutine3(gl_Position) + subroutine4(gl_Position);\n"
8188 " EmitVertex();\n";
8189
8190 break;
8191 }
8192
8193 case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
8194 {
8195 result_sstream << " gl_out[gl_InvocationID].gl_Position = vec4(0);\n"
8196 " subroutine1(gl_out[gl_InvocationID].gl_Position);\n"
8197 " subroutine2(gl_out[gl_InvocationID].gl_Position);\n"
8198 " gl_out[gl_InvocationID].gl_Position = subroutine3(gl_in[0].gl_Position) + "
8199 "subroutine4(gl_in[0].gl_Position);\n";
8200
8201 break;
8202 }
8203
8204 case Utils::SHADER_STAGE_VERTEX:
8205 case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
8206 {
8207 result_sstream << " gl_Position = vec4(0);\n"
8208 " subroutine1(gl_Position);\n"
8209 " subroutine2(gl_Position);\n"
8210 " gl_Position = subroutine3(gl_Position) + subroutine4(gl_Position);\n";
8211
8212 break;
8213 }
8214
8215 default:
8216 break;
8217 } /* switch (shader_stage) */
8218
8219 result_sstream << "}\n";
8220
8221 return result_sstream.str();
8222 }
8223
8224 /** Initializes all objects required to run the test. */
initTest()8225 void FunctionalTest16::initTest()
8226 {
8227 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
8228
8229 for (unsigned int n_id = 0; n_id < 2 /* test program/shader objects */; ++n_id)
8230 {
8231 const std::string fs_body = getShaderBody(Utils::SHADER_STAGE_FRAGMENT, n_id);
8232 const std::string gs_body = getShaderBody(Utils::SHADER_STAGE_GEOMETRY, n_id);
8233 const std::string tc_body = getShaderBody(Utils::SHADER_STAGE_TESSELLATION_CONTROL, n_id);
8234 const std::string te_body = getShaderBody(Utils::SHADER_STAGE_TESSELLATION_EVALUATION, n_id);
8235 const std::string vs_body = getShaderBody(Utils::SHADER_STAGE_VERTEX, n_id);
8236
8237 if (!Utils::buildProgram(gl, vs_body, tc_body, te_body, gs_body, fs_body, DE_NULL, /* xfb_varyings */
8238 DE_NULL, /* n_xfb_varyings */
8239 m_vs_ids + n_id, m_tc_ids + n_id, m_te_ids + n_id, m_gs_ids + n_id, m_fs_ids + n_id,
8240 m_po_ids + n_id))
8241 {
8242 m_testCtx.getLog() << tcu::TestLog::Message
8243 << "Failed to build test program object, index:"
8244 "["
8245 << n_id << "]" << tcu::TestLog::EndMessage;
8246
8247 TCU_FAIL("Failed to build a test program");
8248 }
8249
8250 if (m_are_pipeline_objects_supported)
8251 {
8252 /* Initialize shader program objects */
8253 const char *fs_body_raw_ptr = fs_body.c_str();
8254 const char *gs_body_raw_ptr = gs_body.c_str();
8255 glw::GLint link_status[5] = {GL_FALSE};
8256 const char *tc_body_raw_ptr = tc_body.c_str();
8257 const char *te_body_raw_ptr = te_body.c_str();
8258 const char *vs_body_raw_ptr = vs_body.c_str();
8259
8260 m_fs_po_ids[n_id] = gl.createShaderProgramv(GL_FRAGMENT_SHADER, 1 /* count */, &fs_body_raw_ptr);
8261 m_gs_po_ids[n_id] = gl.createShaderProgramv(GL_GEOMETRY_SHADER, 1 /* count */, &gs_body_raw_ptr);
8262 m_tc_po_ids[n_id] = gl.createShaderProgramv(GL_TESS_CONTROL_SHADER, 1 /* count */, &tc_body_raw_ptr);
8263 m_te_po_ids[n_id] = gl.createShaderProgramv(GL_TESS_EVALUATION_SHADER, 1 /* count */, &te_body_raw_ptr);
8264 m_vs_po_ids[n_id] = gl.createShaderProgramv(GL_VERTEX_SHADER, 1 /* count */, &vs_body_raw_ptr);
8265 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
8266
8267 gl.getProgramiv(m_fs_po_ids[n_id], GL_LINK_STATUS, link_status + 0);
8268 gl.getProgramiv(m_gs_po_ids[n_id], GL_LINK_STATUS, link_status + 1);
8269 gl.getProgramiv(m_tc_po_ids[n_id], GL_LINK_STATUS, link_status + 2);
8270 gl.getProgramiv(m_te_po_ids[n_id], GL_LINK_STATUS, link_status + 3);
8271 gl.getProgramiv(m_vs_po_ids[n_id], GL_LINK_STATUS, link_status + 4);
8272 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
8273
8274 if (link_status[0] == GL_FALSE)
8275 TCU_FAIL("Fragment shader program failed to link");
8276 if (link_status[1] == GL_FALSE)
8277 TCU_FAIL("Geometry shader program failed to link");
8278 if (link_status[2] == GL_FALSE)
8279 TCU_FAIL("Tessellation control shader program failed to link");
8280 if (link_status[3] == GL_FALSE)
8281 TCU_FAIL("Tessellation evaluation shader program failed to link");
8282 if (link_status[4] == GL_FALSE)
8283 TCU_FAIL("Vertex shader program failed to link");
8284
8285 /* Initialize pipeline program object */
8286 gl.genProgramPipelines(1 /* n */, m_pipeline_object_ids + n_id);
8287 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() call failed.");
8288
8289 gl.useProgramStages(m_pipeline_object_ids[n_id], GL_FRAGMENT_SHADER_BIT, m_fs_po_ids[n_id]);
8290 gl.useProgramStages(m_pipeline_object_ids[n_id], GL_GEOMETRY_SHADER_BIT, m_gs_po_ids[n_id]);
8291 gl.useProgramStages(m_pipeline_object_ids[n_id], GL_TESS_CONTROL_SHADER_BIT, m_tc_po_ids[n_id]);
8292 gl.useProgramStages(m_pipeline_object_ids[n_id], GL_TESS_EVALUATION_SHADER_BIT, m_te_po_ids[n_id]);
8293 gl.useProgramStages(m_pipeline_object_ids[n_id], GL_VERTEX_SHADER_BIT, m_vs_po_ids[n_id]);
8294 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8295 }
8296
8297 /* Retrieve subroutine locations */
8298 struct _item
8299 {
8300 glw::GLuint po_id;
8301 _shader_stage &stage;
8302 glw::GLuint so_id;
8303 glw::GLenum so_type;
8304 } items[] = {
8305 {m_po_ids[n_id], m_po_descriptors[n_id].fragment, m_fs_ids[n_id], GL_FRAGMENT_SHADER},
8306 {m_po_ids[n_id], m_po_descriptors[n_id].geometry, m_gs_ids[n_id], GL_GEOMETRY_SHADER},
8307 {m_po_ids[n_id], m_po_descriptors[n_id].tess_control, m_tc_ids[n_id], GL_TESS_CONTROL_SHADER},
8308 {m_po_ids[n_id], m_po_descriptors[n_id].tess_evaluation, m_te_ids[n_id], GL_TESS_EVALUATION_SHADER},
8309 {m_po_ids[n_id], m_po_descriptors[n_id].vertex, m_vs_ids[n_id], GL_VERTEX_SHADER},
8310
8311 {m_fs_po_ids[n_id], m_fs_po_descriptors[n_id], m_fs_po_ids[n_id], GL_FRAGMENT_SHADER},
8312 {m_gs_po_ids[n_id], m_gs_po_descriptors[n_id], m_gs_po_ids[n_id], GL_GEOMETRY_SHADER},
8313 {m_tc_po_ids[n_id], m_tc_po_descriptors[n_id], m_tc_po_ids[n_id], GL_TESS_CONTROL_SHADER},
8314 {m_te_po_ids[n_id], m_te_po_descriptors[n_id], m_te_po_ids[n_id], GL_TESS_EVALUATION_SHADER},
8315 {m_vs_po_ids[n_id], m_vs_po_descriptors[n_id], m_vs_po_ids[n_id], GL_VERTEX_SHADER},
8316 };
8317 const unsigned int n_items = sizeof(items) / sizeof(items[0]);
8318
8319 for (unsigned int n_item = 0; n_item < n_items; ++n_item)
8320 {
8321 _item ¤t_item = items[n_item];
8322
8323 current_item.stage.function1_index =
8324 gl.getSubroutineIndex(current_item.po_id, current_item.so_type, "function1");
8325 current_item.stage.function2_index =
8326 gl.getSubroutineIndex(current_item.po_id, current_item.so_type, "function2");
8327 current_item.stage.function3_index =
8328 gl.getSubroutineIndex(current_item.po_id, current_item.so_type, "function3");
8329 current_item.stage.function4_index =
8330 gl.getSubroutineIndex(current_item.po_id, current_item.so_type, "function4");
8331 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineIndex() call(s) failed.");
8332
8333 if (current_item.stage.function1_index == GL_INVALID_INDEX ||
8334 current_item.stage.function2_index == GL_INVALID_INDEX ||
8335 current_item.stage.function3_index == GL_INVALID_INDEX ||
8336 current_item.stage.function4_index == GL_INVALID_INDEX)
8337 {
8338 TCU_FAIL("Subroutine name was not recognized.");
8339 }
8340
8341 current_item.stage.subroutine1_uniform_location =
8342 gl.getSubroutineUniformLocation(current_item.po_id, current_item.so_type, "subroutine1");
8343 current_item.stage.subroutine2_uniform_location =
8344 gl.getSubroutineUniformLocation(current_item.po_id, current_item.so_type, "subroutine2");
8345 current_item.stage.subroutine3_uniform_location =
8346 gl.getSubroutineUniformLocation(current_item.po_id, current_item.so_type, "subroutine3");
8347 current_item.stage.subroutine4_uniform_location =
8348 gl.getSubroutineUniformLocation(current_item.po_id, current_item.so_type, "subroutine4");
8349 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineUniformLocation() call(s) failed.");
8350
8351 if (current_item.stage.subroutine1_uniform_location == -1 ||
8352 current_item.stage.subroutine2_uniform_location == -1 ||
8353 current_item.stage.subroutine3_uniform_location == -1 ||
8354 current_item.stage.subroutine4_uniform_location == -1)
8355 {
8356 TCU_FAIL("Subroutine uniform name was not recognized.");
8357 }
8358
8359 if (m_po_ids[n_id] == current_item.po_id)
8360 {
8361 gl.useProgram(current_item.po_id);
8362 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
8363 }
8364 else
8365 {
8366 /* Temporarily bind the program pipeline. */
8367 gl.bindProgramPipeline(m_pipeline_object_ids[n_id]);
8368 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
8369 }
8370
8371 gl.getUniformSubroutineuiv(current_item.so_type, current_item.stage.subroutine1_uniform_location,
8372 ¤t_item.stage.default_subroutine1_value);
8373 gl.getUniformSubroutineuiv(current_item.so_type, current_item.stage.subroutine2_uniform_location,
8374 ¤t_item.stage.default_subroutine2_value);
8375 gl.getUniformSubroutineuiv(current_item.so_type, current_item.stage.subroutine3_uniform_location,
8376 ¤t_item.stage.default_subroutine3_value);
8377 gl.getUniformSubroutineuiv(current_item.so_type, current_item.stage.subroutine4_uniform_location,
8378 ¤t_item.stage.default_subroutine4_value);
8379 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformSubroutineuiv() call(s) failed.");
8380
8381 current_item.stage.gl_stage = current_item.so_type;
8382
8383 if (m_po_ids[n_id] != current_item.po_id)
8384 {
8385 /* Unbind the program pipeline object */
8386 gl.bindProgramPipeline(0);
8387 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
8388 }
8389 } /* for (all items) */
8390
8391 /* Make sure the default subroutine choices are valid. */
8392 verifySubroutineUniformValues(
8393 TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT, /* makes the verification routine use program object descriptor */
8394 n_id, SUBROUTINE_UNIFORMS_SET_TO_VALID_VALUES);
8395
8396 if (m_are_pipeline_objects_supported)
8397 {
8398 gl.useProgram(0);
8399 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
8400
8401 gl.bindProgramPipeline(m_pipeline_object_ids[n_id]);
8402 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
8403 {
8404 verifySubroutineUniformValues(
8405 TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_PIPELINE_OBJECT, /* makes the verification routine use pipeline object descriptor */
8406 n_id, SUBROUTINE_UNIFORMS_SET_TO_VALID_VALUES);
8407 }
8408 gl.bindProgramPipeline(0);
8409 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
8410 }
8411 } /* for (both program descriptors) */
8412 }
8413
8414 /** Retrieves IDs of shaders OR shader program objects, depending on which of the two
8415 * the caller requests for.
8416 *
8417 * @param retrieve_program_object_shader_ids true if the caller wishes to retrieve shader object IDs,
8418 * false to return shader program IDs.
8419 * @param n_id Index of the program/pipeline object the shaders
8420 * are a part of.
8421 * @param out_shader_stages Deref will be used to store exactly five IDs. Must not
8422 * be NULL.
8423 **/
getShaderStages(bool retrieve_program_object_shader_ids,const unsigned int & n_id,const _shader_stage ** out_shader_stages) const8424 void FunctionalTest16::getShaderStages(bool retrieve_program_object_shader_ids, const unsigned int &n_id,
8425 const _shader_stage **out_shader_stages) const
8426 {
8427 if (retrieve_program_object_shader_ids)
8428 {
8429 out_shader_stages[0] = &m_po_descriptors[n_id].vertex;
8430 out_shader_stages[1] = &m_po_descriptors[n_id].tess_control;
8431 out_shader_stages[2] = &m_po_descriptors[n_id].tess_evaluation;
8432 out_shader_stages[3] = &m_po_descriptors[n_id].geometry;
8433 out_shader_stages[4] = &m_po_descriptors[n_id].fragment;
8434 }
8435 else
8436 {
8437 out_shader_stages[0] = m_vs_po_descriptors + n_id;
8438 out_shader_stages[1] = m_tc_po_descriptors + n_id;
8439 out_shader_stages[2] = m_te_po_descriptors + n_id;
8440 out_shader_stages[3] = m_gs_po_descriptors + n_id;
8441 out_shader_stages[4] = m_fs_po_descriptors + n_id;
8442 }
8443 }
8444
8445 /** Executes test iteration.
8446 *
8447 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
8448 */
iterate()8449 tcu::TestNode::IterateResult FunctionalTest16::iterate()
8450 {
8451 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
8452
8453 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
8454 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
8455 {
8456 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
8457 }
8458
8459 m_are_pipeline_objects_supported =
8460 m_context.getContextInfo().isExtensionSupported("GL_ARB_separate_shader_objects");
8461
8462 /* Initialize GL objects required to run the test */
8463 initTest();
8464
8465 /* Iterate over both pipelines/programs and verify that calling glUseProgram() /
8466 * glBindProgramPipeline() / glUseProgramStages() resets subroutine uniform configuration.
8467 */
8468 for (int test_case = static_cast<int>(TEST_CASE_FIRST); test_case != static_cast<int>(TEST_CASE_COUNT); ++test_case)
8469 {
8470 if (static_cast<_test_case>(test_case) != TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT &&
8471 !m_are_pipeline_objects_supported)
8472 {
8473 /* Current test case requires GL_ARB_separate_shader_objects support which is
8474 * unavaiable on the platform that we're testing
8475 */
8476 continue;
8477 }
8478
8479 for (unsigned int n_object_id = 0; n_object_id < 2; /* pipeline/program objects allocated for the test */
8480 ++n_object_id)
8481 {
8482 /* Verify that currently reported subroutine uniform values are equal to default values */
8483 if (test_case == TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT)
8484 {
8485 gl.useProgram(m_po_ids[n_object_id]);
8486 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
8487 }
8488 else
8489 {
8490 gl.bindProgramPipeline(m_pipeline_object_ids[n_object_id]);
8491 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed");
8492 }
8493
8494 verifySubroutineUniformValues(static_cast<_test_case>(test_case), n_object_id,
8495 SUBROUTINE_UNIFORMS_SET_TO_DEFAULT_VALUES);
8496
8497 /* Re-configure subroutine uniforms so that they point to different subroutines than
8498 * the default ones.
8499 */
8500 const _shader_stage *stages[5 /* fs+gs+tc+te+vs */] = {DE_NULL};
8501
8502 getShaderStages(static_cast<_test_case>(test_case) == TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT,
8503 n_object_id, stages);
8504
8505 for (unsigned int n_stage = 0; n_stage < 5 /* fs+gs+tc+te+vs stages */; ++n_stage)
8506 {
8507 const _shader_stage ¤t_stage = *(stages[n_stage]);
8508 glw::GLuint subroutine_configuration[4] = {GL_INVALID_INDEX};
8509
8510 subroutine_configuration[0] =
8511 (current_stage.default_subroutine1_value == current_stage.function1_index) ?
8512 current_stage.function2_index :
8513 current_stage.function1_index;
8514 subroutine_configuration[1] =
8515 (current_stage.default_subroutine2_value == current_stage.function1_index) ?
8516 current_stage.function2_index :
8517 current_stage.function1_index;
8518 subroutine_configuration[2] =
8519 (current_stage.default_subroutine3_value == current_stage.function3_index) ?
8520 current_stage.function4_index :
8521 current_stage.function3_index;
8522 subroutine_configuration[3] =
8523 (current_stage.default_subroutine4_value == current_stage.function3_index) ?
8524 current_stage.function4_index :
8525 current_stage.function3_index;
8526
8527 gl.uniformSubroutinesuiv(current_stage.gl_stage, 4 /* count */, subroutine_configuration);
8528 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniformSubroutinesuiv() call failed.");
8529 } /* for (all stages) */
8530
8531 verifySubroutineUniformValues(static_cast<_test_case>(test_case), n_object_id,
8532 SUBROUTINE_UNIFORMS_SET_TO_NONDEFAULT_VALUES);
8533
8534 /* Execute test case-specific code */
8535 _shader_stage cached_shader_stage_data;
8536 bool stage_reset_status[Utils::SHADER_STAGE_COUNT] = {false, false, false, false, false};
8537 bool uses_stage_reset_status = false;
8538
8539 switch (test_case)
8540 {
8541 case TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT:
8542 {
8543 /* Switch to a different program object and then back to current PO.
8544 * Subroutine uniforms should be back at their default settings, instead of
8545 * the ones we've just set.
8546 */
8547 gl.useProgram(m_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8548 gl.useProgram(m_po_ids[n_object_id]);
8549 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call(s) failed.");
8550
8551 break;
8552 }
8553
8554 case TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_PIPELINE_OBJECT:
8555 {
8556 /* Switch to a different pipeline object and then back to the current one.
8557 * Subroutine uniforms should be back at their default settings, instead of
8558 * the ones we've just set.
8559 */
8560 gl.bindProgramPipeline(
8561 m_pipeline_object_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8562 gl.bindProgramPipeline(m_pipeline_object_ids[n_object_id]);
8563 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call(s) failed.");
8564
8565 break;
8566 }
8567
8568 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_FRAGMENT_STAGE:
8569 {
8570 /* Change the fragment shader stage to a different one.
8571 *
8572 * Note: We also need to update internal descriptor since the subroutine/uniform
8573 * locations may be different between the two programs.
8574 */
8575 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_FRAGMENT_SHADER_BIT,
8576 m_fs_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8577 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8578
8579 cached_shader_stage_data = m_fs_po_descriptors[n_object_id];
8580 m_fs_po_descriptors[n_object_id] = m_fs_po_descriptors[(n_object_id + 1) % 2];
8581
8582 stage_reset_status[Utils::SHADER_STAGE_FRAGMENT] = true;
8583 uses_stage_reset_status = true;
8584
8585 break;
8586 }
8587
8588 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_GEOMETRY_STAGE:
8589 {
8590 /* Change the geometry shader stage to a different one.
8591 *
8592 * Note: We also need to update internal descriptor since the subroutine/uniform
8593 * locations may be different between the two programs.
8594 */
8595 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_GEOMETRY_SHADER_BIT,
8596 m_gs_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8597 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8598
8599 cached_shader_stage_data = m_gs_po_descriptors[n_object_id];
8600 m_gs_po_descriptors[n_object_id] = m_gs_po_descriptors[(n_object_id + 1) % 2];
8601
8602 stage_reset_status[Utils::SHADER_STAGE_GEOMETRY] = true;
8603 uses_stage_reset_status = true;
8604
8605 break;
8606 }
8607
8608 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_TESS_CONTROL_STAGE:
8609 {
8610 /* Change the tessellation control shader stage to a different one.
8611 *
8612 * Note: We also need to update internal descriptor since the subroutine/uniform
8613 * locations may be different between the two programs.
8614 */
8615 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_TESS_CONTROL_SHADER_BIT,
8616 m_tc_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8617 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8618
8619 cached_shader_stage_data = m_tc_po_descriptors[n_object_id];
8620 m_tc_po_descriptors[n_object_id] = m_tc_po_descriptors[(n_object_id + 1) % 2];
8621
8622 stage_reset_status[Utils::SHADER_STAGE_TESSELLATION_CONTROL] = true;
8623 uses_stage_reset_status = true;
8624
8625 break;
8626 }
8627
8628 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_TESS_EVALUATION_STAGE:
8629 {
8630 /* Change the tessellation evaluation shader stage to a different one.
8631 *
8632 * Note: We also need to update internal descriptor since the subroutine/uniform
8633 * locations may be different between the two programs.
8634 */
8635 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_TESS_EVALUATION_SHADER_BIT,
8636 m_te_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8637 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8638
8639 cached_shader_stage_data = m_te_po_descriptors[n_object_id];
8640 m_te_po_descriptors[n_object_id] = m_te_po_descriptors[(n_object_id + 1) % 2];
8641
8642 stage_reset_status[Utils::SHADER_STAGE_TESSELLATION_EVALUATION] = true;
8643 uses_stage_reset_status = true;
8644
8645 break;
8646 }
8647
8648 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_VERTEX_STAGE:
8649 {
8650 /* Change the vertex shader stage to a different one.
8651 *
8652 * Note: We also need to update internal descriptor since the subroutine/uniform
8653 * locations may be different between the two programs.
8654 */
8655 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_VERTEX_SHADER_BIT,
8656 m_vs_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8657 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8658
8659 cached_shader_stage_data = m_vs_po_descriptors[n_object_id];
8660 m_vs_po_descriptors[n_object_id] = m_vs_po_descriptors[(n_object_id + 1) % 2];
8661
8662 stage_reset_status[Utils::SHADER_STAGE_VERTEX] = true;
8663 uses_stage_reset_status = true;
8664
8665 break;
8666 }
8667
8668 default:
8669 {
8670 TCU_FAIL("Unrecognized test case");
8671 }
8672 } /* switch (test_case) */
8673
8674 /* Verify the subroutine uniform values are valid */
8675 if (!uses_stage_reset_status)
8676 {
8677 verifySubroutineUniformValues(static_cast<_test_case>(test_case), n_object_id,
8678 SUBROUTINE_UNIFORMS_SET_TO_DEFAULT_VALUES);
8679 }
8680 else
8681 {
8682 const _shader_stage *shader_stages[Utils::SHADER_STAGE_COUNT] = {DE_NULL};
8683
8684 getShaderStages(static_cast<_test_case>(test_case) == TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT,
8685 n_object_id, shader_stages);
8686
8687 for (unsigned int n_shader_stage = 0; n_shader_stage < Utils::SHADER_STAGE_COUNT; ++n_shader_stage)
8688 {
8689 const _shader_stage ¤t_shader_stage = *(shader_stages[n_shader_stage]);
8690
8691 if (stage_reset_status[n_shader_stage])
8692 {
8693 verifySubroutineUniformValuesForShaderStage(current_shader_stage,
8694 SUBROUTINE_UNIFORMS_SET_TO_DEFAULT_VALUES);
8695 }
8696 else
8697 {
8698 verifySubroutineUniformValuesForShaderStage(current_shader_stage,
8699 SUBROUTINE_UNIFORMS_SET_TO_NONDEFAULT_VALUES);
8700 }
8701 } /* for (all shader stages) */
8702 }
8703
8704 /* Revert the changes some of the test cases appied */
8705 switch (test_case)
8706 {
8707 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_FRAGMENT_STAGE:
8708 {
8709 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_FRAGMENT_SHADER_BIT,
8710 m_fs_po_ids[n_object_id]);
8711 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8712
8713 m_fs_po_descriptors[n_object_id] = cached_shader_stage_data;
8714
8715 break;
8716 }
8717
8718 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_GEOMETRY_STAGE:
8719 {
8720 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_GEOMETRY_SHADER_BIT,
8721 m_gs_po_ids[n_object_id]);
8722 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8723
8724 m_gs_po_descriptors[n_object_id] = cached_shader_stage_data;
8725
8726 break;
8727 }
8728
8729 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_TESS_CONTROL_STAGE:
8730 {
8731 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_TESS_CONTROL_SHADER_BIT,
8732 m_tc_po_ids[n_object_id]);
8733 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8734
8735 m_tc_po_descriptors[n_object_id] = cached_shader_stage_data;
8736
8737 break;
8738 }
8739
8740 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_TESS_EVALUATION_STAGE:
8741 {
8742 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_TESS_EVALUATION_SHADER_BIT,
8743 m_te_po_ids[n_object_id]);
8744 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8745
8746 m_te_po_descriptors[n_object_id] = cached_shader_stage_data;
8747
8748 break;
8749 }
8750
8751 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_VERTEX_STAGE:
8752 {
8753 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_VERTEX_SHADER_BIT, m_vs_po_ids[n_object_id]);
8754 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8755
8756 m_vs_po_descriptors[n_object_id] = cached_shader_stage_data;
8757
8758 break;
8759 }
8760
8761 default:
8762 break;
8763 } /* switch (test_case) */
8764
8765 } /* for (all program object descriptors) */
8766
8767 /* Unbind the program object */
8768 gl.useProgram(0);
8769 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
8770 } /* for (all test cases) */
8771
8772 if (m_has_test_passed)
8773 {
8774 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
8775 }
8776 else
8777 {
8778 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
8779 }
8780
8781 return STOP;
8782 }
8783
8784 /** Verifies the subroutine uniform values reported by GL implementation. Depending on the test case,
8785 * it will either query program object stages or separate shader objects.
8786 *
8787 * @param test_case Test case the verification is to be performed for.
8788 * @param n_id Index of the program/pipeline object to use for the verification
8789 * @param verification Verification method.
8790 */
verifySubroutineUniformValues(const _test_case & test_case,const unsigned int & n_id,const _subroutine_uniform_value_verification & verification)8791 void FunctionalTest16::verifySubroutineUniformValues(const _test_case &test_case, const unsigned int &n_id,
8792 const _subroutine_uniform_value_verification &verification)
8793 {
8794 const _shader_stage *stages[] = {
8795 DE_NULL, /* fragment shader stage slot */
8796 DE_NULL, /* geometry shader stage slot */
8797 DE_NULL, /* tess control shader stage slot */
8798 DE_NULL, /* tess eval shader stage slot */
8799 DE_NULL /* vertex shader stage slot */
8800 };
8801 const unsigned int n_stages = sizeof(stages) / sizeof(stages[0]);
8802
8803 /* Verify that currently reported subroutine uniform values are equal to default values */
8804 getShaderStages(test_case == TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT, n_id, stages);
8805
8806 for (unsigned int n_stage = 0; n_stage < n_stages; ++n_stage)
8807 {
8808 const _shader_stage ¤t_stage = *(stages[n_stage]);
8809
8810 verifySubroutineUniformValuesForShaderStage(current_stage, verification);
8811 } /* for (all items) */
8812 }
8813
8814 /** Verifies the subroutine uniform values reported by GL implementation for user-specified
8815 * shader stage. If the verification fails, m_has_test_passed will be set to false.
8816 *
8817 * @param shader_stage Descriptor of a shader stage that should be used for the process.
8818 * @param verification Type of verification that should be performed.
8819 *
8820 **/
verifySubroutineUniformValuesForShaderStage(const _shader_stage & shader_stage,const _subroutine_uniform_value_verification & verification)8821 void FunctionalTest16::verifySubroutineUniformValuesForShaderStage(
8822 const _shader_stage &shader_stage, const _subroutine_uniform_value_verification &verification)
8823 {
8824 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
8825 glw::GLuint result_values[4] = {0};
8826
8827 gl.getUniformSubroutineuiv(shader_stage.gl_stage, shader_stage.subroutine1_uniform_location, result_values + 0);
8828 gl.getUniformSubroutineuiv(shader_stage.gl_stage, shader_stage.subroutine2_uniform_location, result_values + 1);
8829 gl.getUniformSubroutineuiv(shader_stage.gl_stage, shader_stage.subroutine3_uniform_location, result_values + 2);
8830 gl.getUniformSubroutineuiv(shader_stage.gl_stage, shader_stage.subroutine4_uniform_location, result_values + 3);
8831 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformSubroutineuiv() call(s) failed.");
8832
8833 if (verification == SUBROUTINE_UNIFORMS_SET_TO_VALID_VALUES)
8834 {
8835 if (!((result_values[0] == (GLuint)shader_stage.subroutine1_uniform_location ||
8836 result_values[0] == (GLuint)shader_stage.subroutine2_uniform_location) &&
8837 (result_values[1] == (GLuint)shader_stage.subroutine1_uniform_location ||
8838 result_values[1] == (GLuint)shader_stage.subroutine2_uniform_location) &&
8839 (result_values[2] == (GLuint)shader_stage.subroutine3_uniform_location ||
8840 result_values[2] == (GLuint)shader_stage.subroutine4_uniform_location) &&
8841 (result_values[3] == (GLuint)shader_stage.subroutine3_uniform_location ||
8842 result_values[3] == (GLuint)shader_stage.subroutine4_uniform_location)))
8843 {
8844 m_testCtx.getLog() << tcu::TestLog::Message
8845 << "SUBROUTINE_UNIFORMS_SET_TO_VALID_VALUES validation failed. "
8846 "Shader stage:["
8847 << Utils::getShaderStageStringFromGLEnum(shader_stage.gl_stage)
8848 << "], "
8849 "expected data:["
8850 << shader_stage.subroutine1_uniform_location << " OR "
8851 << shader_stage.subroutine2_uniform_location << " x 2, "
8852 << shader_stage.subroutine3_uniform_location << " OR "
8853 << shader_stage.subroutine4_uniform_location
8854 << " x 2], "
8855 "found data:["
8856 << result_values[0] << ", " << result_values[1] << ", " << result_values[2] << ", "
8857 << result_values[3] << "]." << tcu::TestLog::EndMessage;
8858
8859 m_has_test_passed = false;
8860 }
8861 }
8862 else if (verification == SUBROUTINE_UNIFORMS_SET_TO_DEFAULT_VALUES)
8863 {
8864 if (result_values[0] != shader_stage.default_subroutine1_value ||
8865 result_values[1] != shader_stage.default_subroutine2_value ||
8866 result_values[2] != shader_stage.default_subroutine3_value ||
8867 result_values[3] != shader_stage.default_subroutine4_value)
8868 {
8869 m_testCtx.getLog() << tcu::TestLog::Message
8870 << "SUBROUTINE_UNIFORMS_SET_TO_DEFAULT_VALUES validation failed. "
8871 "Shader stage:["
8872 << Utils::getShaderStageStringFromGLEnum(shader_stage.gl_stage)
8873 << "], "
8874 "expected data:["
8875 << shader_stage.default_subroutine1_value << ", "
8876 << shader_stage.default_subroutine2_value << ", "
8877 << shader_stage.default_subroutine3_value << ", "
8878 << shader_stage.default_subroutine4_value
8879 << "], "
8880 "found data:["
8881 << result_values[0] << ", " << result_values[1] << ", " << result_values[2] << ", "
8882 << result_values[3] << "]." << tcu::TestLog::EndMessage;
8883
8884 m_has_test_passed = false;
8885 }
8886 }
8887 else
8888 {
8889 DE_ASSERT(verification == SUBROUTINE_UNIFORMS_SET_TO_NONDEFAULT_VALUES);
8890
8891 if (result_values[0] == shader_stage.default_subroutine1_value ||
8892 result_values[1] == shader_stage.default_subroutine2_value ||
8893 result_values[2] == shader_stage.default_subroutine3_value ||
8894 result_values[3] == shader_stage.default_subroutine4_value)
8895 {
8896 m_testCtx.getLog() << tcu::TestLog::Message
8897 << "SUBROUTINE_UNIFORMS_SET_TO_NONDEFAULT_VALUES validation failed. "
8898 "Shader stage:["
8899 << Utils::getShaderStageStringFromGLEnum(shader_stage.gl_stage)
8900 << "], "
8901 "expected data:!["
8902 << shader_stage.default_subroutine1_value << ", "
8903 << shader_stage.default_subroutine2_value << ", "
8904 << shader_stage.default_subroutine3_value << ", "
8905 << shader_stage.default_subroutine4_value
8906 << "], "
8907 "found data:["
8908 << result_values[0] << ", " << result_values[1] << ", " << result_values[2] << ", "
8909 << result_values[3] << "]." << tcu::TestLog::EndMessage;
8910
8911 m_has_test_passed = false;
8912 }
8913 }
8914 }
8915
8916 /** Constructor.
8917 *
8918 * @param context Rendering context.
8919 *
8920 **/
FunctionalTest17(deqp::Context & context)8921 FunctionalTest17::FunctionalTest17(deqp::Context &context)
8922 : TestCase(context, "same_subroutine_and_subroutine_uniform_but_different_type_used_in_all_stages",
8923 "Creates a program which uses the same subroutine and subroutine uniform "
8924 "names for every stage (types of subroutines are different in each stage) "
8925 "and then makes sure that such program compiles and works as expected.")
8926 , m_fbo_id(0)
8927 , m_fs_id(0)
8928 , m_gs_id(0)
8929 , m_has_test_passed(true)
8930 , m_po_id(0)
8931 , m_tc_id(0)
8932 , m_te_id(0)
8933 , m_to_data(DE_NULL)
8934 , m_to_height(4) /* arbitrary value */
8935 , m_to_id(0)
8936 , m_to_width(4) /* arbitrary value */
8937 , m_vao_id(0)
8938 , m_vs_id(0)
8939 {
8940 /* Left blank intentionally */
8941 }
8942
8943 /** Deinitializes all GL objects that may have been created during test execution. */
deinit()8944 void FunctionalTest17::deinit()
8945 {
8946 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
8947
8948 if (m_fbo_id != 0)
8949 {
8950 gl.deleteFramebuffers(1, &m_fbo_id);
8951
8952 m_fbo_id = 0;
8953 }
8954
8955 if (m_fs_id != 0)
8956 {
8957 gl.deleteShader(m_fs_id);
8958
8959 m_fs_id = 0;
8960 }
8961
8962 if (m_gs_id != 0)
8963 {
8964 gl.deleteShader(m_gs_id);
8965
8966 m_gs_id = 0;
8967 }
8968
8969 if (m_po_id != 0)
8970 {
8971 gl.deleteProgram(m_po_id);
8972
8973 m_po_id = 0;
8974 }
8975
8976 if (m_tc_id != 0)
8977 {
8978 gl.deleteShader(m_tc_id);
8979
8980 m_tc_id = 0;
8981 }
8982
8983 if (m_te_id != 0)
8984 {
8985 gl.deleteShader(m_te_id);
8986
8987 m_te_id = 0;
8988 }
8989
8990 if (m_to_data != DE_NULL)
8991 {
8992 delete[] m_to_data;
8993
8994 m_to_data = DE_NULL;
8995 }
8996
8997 if (m_to_id != 0)
8998 {
8999 gl.deleteTextures(1, &m_to_id);
9000
9001 m_to_id = 0;
9002 }
9003
9004 if (m_vao_id != 0)
9005 {
9006 gl.deleteVertexArrays(1, &m_vao_id);
9007
9008 m_vao_id = 0;
9009 }
9010
9011 if (m_vs_id != 0)
9012 {
9013 gl.deleteShader(m_vs_id);
9014
9015 m_vs_id = 0;
9016 }
9017
9018 /* Restore original GL configuration */
9019 gl.patchParameteri(GL_PATCH_VERTICES, 3);
9020 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteri() call failed.");
9021
9022 gl.pixelStorei(GL_PACK_ALIGNMENT, 4);
9023 GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call failed.");
9024 }
9025
9026 /** Retrieves body of a fragment shader that should be used by the test program.
9027 *
9028 * @return Requested string.
9029 **/
getFragmentShaderBody() const9030 std::string FunctionalTest17::getFragmentShaderBody() const
9031 {
9032 return "#version 400\n"
9033 "\n"
9034 "#extension GL_ARB_shader_subroutine : require\n"
9035 "\n"
9036 "in GS_DATA\n"
9037 "{\n"
9038 " vec4 gs_data;\n"
9039 " vec4 tc_data;\n"
9040 " vec4 te_data;\n"
9041 " vec4 vs_data;\n"
9042 "} gs;\n"
9043 "\n"
9044 "out vec4 result;\n"
9045 "\n"
9046 "subroutine void subroutineTypeFS(out vec4 result);\n"
9047 "\n"
9048 "subroutine(subroutineTypeFS) void subroutine1(out vec4 result)\n"
9049 "{\n"
9050 " result = vec4(5, 6, 7, 8);\n"
9051 "}\n"
9052 "\n"
9053 "subroutine uniform subroutineTypeFS function;\n"
9054 "\n"
9055 "void main()\n"
9056 "{\n"
9057 " vec4 fs_data;\n"
9058 "\n"
9059 " function(fs_data);\n"
9060 " result = gs.gs_data + gs.tc_data + gs.te_data + gs.vs_data + fs_data;\n"
9061 "}\n";
9062 }
9063
9064 /** Retrieves body of a geometry shader that should be used by the test program.
9065 *
9066 * @return Requested string.
9067 **/
getGeometryShaderBody() const9068 std::string FunctionalTest17::getGeometryShaderBody() const
9069 {
9070 return "#version 400\n"
9071 "\n"
9072 "#extension GL_ARB_shader_subroutine : require\n"
9073 "\n"
9074 "layout(points) in;\n"
9075 "layout(triangle_strip, max_vertices = 4) out;\n"
9076 "\n"
9077 "subroutine void subroutineTypeGS(out vec4 result);\n"
9078 "\n"
9079 "subroutine(subroutineTypeGS) void subroutine1(out vec4 result)\n"
9080 "{\n"
9081 " result = vec4(4, 5, 6, 7);\n"
9082 "}\n"
9083 "\n"
9084 "subroutine uniform subroutineTypeGS function;\n"
9085 "\n"
9086 "in TE_DATA\n"
9087 "{\n"
9088 " vec4 tc_data;\n"
9089 " vec4 te_data;\n"
9090 " vec4 vs_data;\n"
9091 "} te[];\n"
9092 "\n"
9093 "out GS_DATA\n"
9094 "{\n"
9095 " vec4 gs_data;\n"
9096 " vec4 tc_data;\n"
9097 " vec4 te_data;\n"
9098 " vec4 vs_data;\n"
9099 "} result;\n"
9100 "\n"
9101 "void main()\n"
9102 "{\n"
9103 " function(result.gs_data);\n"
9104 " gl_Position = vec4(1, -1, 0, 1);\n"
9105 " result.tc_data = te[0].tc_data;\n"
9106 " result.te_data = te[0].te_data;\n"
9107 " result.vs_data = te[0].vs_data;\n"
9108 " EmitVertex();\n"
9109 "\n"
9110 " function(result.gs_data);\n"
9111 " gl_Position = vec4(-1, -1, 0, 1);\n"
9112 " result.tc_data = te[0].tc_data;\n"
9113 " result.te_data = te[0].te_data;\n"
9114 " result.vs_data = te[0].vs_data;\n"
9115 " EmitVertex();\n"
9116 "\n"
9117 " function(result.gs_data);\n"
9118 " gl_Position = vec4(1, 1, 0, 1);\n"
9119 " result.tc_data = te[0].tc_data;\n"
9120 " result.te_data = te[0].te_data;\n"
9121 " result.vs_data = te[0].vs_data;\n"
9122 " EmitVertex();\n"
9123 "\n"
9124 " function(result.gs_data);\n"
9125 " gl_Position = vec4(-1, 1, 0, 1);\n"
9126 " result.tc_data = te[0].tc_data;\n"
9127 " result.te_data = te[0].te_data;\n"
9128 " result.vs_data = te[0].vs_data;\n"
9129 " EmitVertex();\n"
9130 " EndPrimitive();\n"
9131 "}\n";
9132 }
9133
9134 /** Retrieves body of a tessellation control shader that should be used by the test program.
9135 *
9136 * @return Requested string.
9137 **/
getTessellationControlShaderBody() const9138 std::string FunctionalTest17::getTessellationControlShaderBody() const
9139 {
9140 return "#version 400\n"
9141 "\n"
9142 "#extension GL_ARB_shader_subroutine : require\n"
9143 "\n"
9144 "layout (vertices = 4) out;\n"
9145 "\n"
9146 "subroutine void subroutineTypeTC(out vec4 result);\n"
9147 "\n"
9148 "subroutine(subroutineTypeTC) void subroutine1(out vec4 result)\n"
9149 "{\n"
9150 " result = vec4(2, 3, 4, 5);\n"
9151 "}\n"
9152 "\n"
9153 "subroutine uniform subroutineTypeTC function;\n"
9154 "\n"
9155 "in VS_DATA\n"
9156 "{\n"
9157 " vec4 vs_data;\n"
9158 "} vs[];\n"
9159 "\n"
9160 "out TC_DATA\n"
9161 "{\n"
9162 " vec4 tc_data;\n"
9163 " vec4 vs_data;\n"
9164 "} result[];\n"
9165 "\n"
9166 "void main()\n"
9167 "{\n"
9168 " gl_TessLevelInner[0] = 1.0;\n"
9169 " gl_TessLevelInner[1] = 1.0;\n"
9170 " gl_TessLevelOuter[0] = 1.0;\n"
9171 " gl_TessLevelOuter[1] = 1.0;\n"
9172 " gl_TessLevelOuter[2] = 1.0;\n"
9173 " gl_TessLevelOuter[3] = 1.0;\n"
9174 "\n"
9175 " function(result[gl_InvocationID].tc_data);\n"
9176 " result[gl_InvocationID].vs_data = vs[gl_InvocationID].vs_data;\n"
9177 "}\n";
9178 }
9179
9180 /** Retrieves body of a tessellation evaluation shader that should be used
9181 * by the test program.
9182 *
9183 * @return Requested string.
9184 **/
getTessellationEvaluationShaderBody() const9185 std::string FunctionalTest17::getTessellationEvaluationShaderBody() const
9186 {
9187 return "#version 400\n"
9188 "\n"
9189 "#extension GL_ARB_shader_subroutine : require\n"
9190 "\n"
9191 "layout (quads, point_mode) in;\n"
9192 "\n"
9193 "subroutine void subroutineTypeTE(out vec4 result);\n"
9194 "\n"
9195 "subroutine(subroutineTypeTE) void subroutine1(out vec4 result)\n"
9196 "{\n"
9197 " result = vec4(3, 4, 5, 6);\n"
9198 "}\n"
9199 "\n"
9200 "subroutine uniform subroutineTypeTE function;\n"
9201 "\n"
9202 "in TC_DATA\n"
9203 "{\n"
9204 " vec4 tc_data;\n"
9205 " vec4 vs_data;\n"
9206 "} tc[];\n"
9207 "\n"
9208 "out TE_DATA\n"
9209 "{\n"
9210 " vec4 tc_data;\n"
9211 " vec4 te_data;\n"
9212 " vec4 vs_data;\n"
9213 "} result;\n"
9214 "\n"
9215 "void main()\n"
9216 "{\n"
9217 " result.vs_data = tc[0].vs_data;\n"
9218 " result.tc_data = tc[0].tc_data;\n"
9219 " function(result.te_data);\n"
9220 "}\n";
9221 }
9222
9223 /** Retrieves body of a vertex shader that should be used by the test program.
9224 *
9225 * @return Requested string.
9226 **/
getVertexShaderBody() const9227 std::string FunctionalTest17::getVertexShaderBody() const
9228 {
9229 return "#version 400\n"
9230 "\n"
9231 "#extension GL_ARB_shader_subroutine : require\n"
9232 "\n"
9233 "out VS_DATA\n"
9234 "{\n"
9235 " vec4 vs_data;\n"
9236 "} result;\n"
9237 "\n"
9238 "subroutine void subroutineTypeVS(out vec4 result);\n"
9239 "\n"
9240 "subroutine(subroutineTypeVS) void subroutine1(out vec4 result)\n"
9241 "{\n"
9242 " result = vec4(1, 2, 3, 4);\n"
9243 "}\n"
9244 "\n"
9245 "subroutine uniform subroutineTypeVS function;\n"
9246 "\n"
9247 "void main()\n"
9248 "{\n"
9249 " function(result.vs_data);\n"
9250 "}\n";
9251 }
9252
9253 /** Initializes all buffers and GL objects required to run the test. */
initTest()9254 void FunctionalTest17::initTest()
9255 {
9256 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
9257
9258 /* Configure GL_PATCH_VERTICES so that TC only takes a single patch vertex */
9259 gl.patchParameteri(GL_PATCH_VERTICES, 1);
9260 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteri() call failed.");
9261
9262 /* Generate & bind a VAO */
9263 gl.genVertexArrays(1, &m_vao_id);
9264 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
9265
9266 gl.bindVertexArray(m_vao_id);
9267 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
9268
9269 /* Set up test program object */
9270 std::string fs_body = getFragmentShaderBody();
9271 std::string gs_body = getGeometryShaderBody();
9272 std::string tc_body = getTessellationControlShaderBody();
9273 std::string te_body = getTessellationEvaluationShaderBody();
9274 std::string vs_body = getVertexShaderBody();
9275
9276 if (!Utils::buildProgram(gl, vs_body, tc_body, te_body, gs_body, fs_body, DE_NULL, /* xfb_varyings */
9277 DE_NULL, /* n_xfb_varyings */
9278 &m_vs_id, &m_tc_id, &m_te_id, &m_gs_id, &m_fs_id, &m_po_id))
9279 {
9280 TCU_FAIL("Failed to link test program object");
9281 }
9282
9283 /* Set up a texture object that will be used as a color attachment */
9284 gl.genTextures(1, &m_to_id);
9285 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed.");
9286
9287 gl.bindTexture(GL_TEXTURE_2D, m_to_id);
9288 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
9289
9290 gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
9291 GL_RGBA32F, m_to_width, m_to_height);
9292 GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed.");
9293
9294 /* Set up FBO */
9295 gl.genFramebuffers(1, &m_fbo_id);
9296 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed.");
9297
9298 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
9299 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed.");
9300
9301 gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0 /* level */);
9302 GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
9303
9304 /* Make sure glReadPixels() does not return misaligned data */
9305 gl.pixelStorei(GL_PACK_ALIGNMENT, 1);
9306 GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call failed.");
9307
9308 /* Initialize a buffer that will be used to store rendered data */
9309 m_to_data = new float[m_to_width * m_to_height * 4 /* rgba */];
9310 }
9311
9312 /** Executes test iteration.
9313 *
9314 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
9315 */
iterate()9316 tcu::TestNode::IterateResult FunctionalTest17::iterate()
9317 {
9318 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
9319
9320 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
9321 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
9322 {
9323 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
9324 }
9325
9326 initTest();
9327
9328 /* Use the test program to render a full-screen test quad */
9329 gl.useProgram(m_po_id);
9330 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
9331
9332 gl.drawArrays(GL_PATCHES, 0 /* first */, 1 /* count */);
9333 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
9334
9335 /* Read back the data that was rendered */
9336 gl.readPixels(0, /* x */
9337 0, /* y */
9338 m_to_width, m_to_height, GL_RGBA, GL_FLOAT, m_to_data);
9339 GLU_EXPECT_NO_ERROR(gl.getError(), "glReaDPixels() call failed.");
9340
9341 /* Verify the data */
9342 verifyRenderedData();
9343
9344 /** All done */
9345 if (m_has_test_passed)
9346 {
9347 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
9348 }
9349 else
9350 {
9351 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
9352 }
9353
9354 return STOP;
9355 }
9356
9357 /** Verifies the data that have been rendered by the test program.
9358 *
9359 * It is assumed the rendered data have already been copied to
9360 * m_to_data.
9361 *
9362 * If the rendered data is found to be invalid, m_has_test_passed
9363 * will be set to false.
9364 **/
verifyRenderedData()9365 void FunctionalTest17::verifyRenderedData()
9366 {
9367 const float epsilon = 1e-5f;
9368 const float expected_data[4] = {15.0f, 20.0f, 25.0f, 30.0f};
9369
9370 for (unsigned int y = 0; y < m_to_height && m_has_test_passed; ++y)
9371 {
9372 const float *row_ptr = m_to_data + y * 4 /* rgba */ * m_to_width;
9373
9374 for (unsigned int x = 0; x < m_to_width && m_has_test_passed; ++x)
9375 {
9376 const float *pixel_ptr = row_ptr + 4 /* rgba */ * x;
9377
9378 if (de::abs(pixel_ptr[0] - expected_data[0]) > epsilon ||
9379 de::abs(pixel_ptr[1] - expected_data[1]) > epsilon ||
9380 de::abs(pixel_ptr[2] - expected_data[2]) > epsilon ||
9381 de::abs(pixel_ptr[3] - expected_data[3]) > epsilon)
9382 {
9383 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid texel found at (" << x << ", " << y
9384 << "): "
9385 "expected:("
9386 << expected_data[0] << ", " << expected_data[1] << ", " << expected_data[2] << ", "
9387 << expected_data[3] << "), found:(" << pixel_ptr[0] << ", " << pixel_ptr[1] << ", "
9388 << pixel_ptr[2] << ", " << pixel_ptr[3] << ")." << tcu::TestLog::EndMessage;
9389
9390 m_has_test_passed = false;
9391 }
9392 } /* for (all columns) */
9393 } /* for (all rows) */
9394 }
9395
9396 /** Constructor.
9397 *
9398 * @param context Rendering context.
9399 *
9400 **/
FunctionalTest18_19(deqp::Context & context)9401 FunctionalTest18_19::FunctionalTest18_19(deqp::Context &context)
9402 : TestCase(context, "control_flow_and_returned_subroutine_values_used_as_subroutine_input",
9403 "Makes sure that calling a subroutine with argument value returned by "
9404 "another subroutine works correctly. Also checks that subroutine and "
9405 "subroutine uniforms work as expected when used in connection with control "
9406 "flow functions.")
9407 , m_has_test_passed(true)
9408 , m_n_points_to_draw(16) /* arbitrary value */
9409 , m_po_id(0)
9410 , m_po_subroutine_divide_by_two_location(GL_INVALID_INDEX)
9411 , m_po_subroutine_multiply_by_four_location(GL_INVALID_INDEX)
9412 , m_po_subroutine_returns_false_location(GL_INVALID_INDEX)
9413 , m_po_subroutine_returns_true_location(GL_INVALID_INDEX)
9414 , m_po_subroutine_uniform_bool_operator1(-1)
9415 , m_po_subroutine_uniform_bool_operator2(-1)
9416 , m_po_subroutine_uniform_vec4_processor1(-1)
9417 , m_po_subroutine_uniform_vec4_processor2(-1)
9418 , m_xfb_bo_id(0)
9419 , m_vao_id(0)
9420 , m_vs_id(0)
9421 {
9422 /* Left blank intentionally */
9423 }
9424
9425 /** De-initializes all GL objects that may have been created during test execution */
deinit()9426 void FunctionalTest18_19::deinit()
9427 {
9428 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
9429
9430 if (m_po_id != 0)
9431 {
9432 gl.deleteProgram(m_po_id);
9433
9434 m_po_id = 0;
9435 }
9436
9437 if (m_vao_id != 0)
9438 {
9439 gl.deleteVertexArrays(1, &m_vao_id);
9440
9441 m_vao_id = 0;
9442 }
9443
9444 if (m_vs_id != 0)
9445 {
9446 gl.deleteShader(m_vs_id);
9447
9448 m_vs_id = 0;
9449 }
9450
9451 if (m_xfb_bo_id != 0)
9452 {
9453 gl.deleteBuffers(1, &m_xfb_bo_id);
9454
9455 m_xfb_bo_id = 0;
9456 }
9457 }
9458
9459 /** Executes a single test iteration using user-specified properties. If the
9460 * iterations fails, m_has_test_passed is set to false.
9461 *
9462 * @param bool_operator1_subroutine_location Location of a subroutine to be assigned to
9463 * bool_operator1 subroutine uniform.
9464 * @param bool_operator2_subroutine_location Location of a subroutine to be assigned to
9465 * bool_operator2 subroutine uniform.
9466 * @param vec4_operator1_subroutine_location Location of a subroutine to be assigned to
9467 * vec4_operator1 subroutine uniform.
9468 * @param vec4_operator2_subroutine_location Location of a subroutine to be assigned to
9469 * vec4_operator2 subroutine uniform.
9470 &**/
executeTest(glw::GLuint bool_operator1_subroutine_location,glw::GLuint bool_operator2_subroutine_location,glw::GLuint vec4_operator1_subroutine_location,glw::GLuint vec4_operator2_subroutine_location)9471 void FunctionalTest18_19::executeTest(glw::GLuint bool_operator1_subroutine_location,
9472 glw::GLuint bool_operator2_subroutine_location,
9473 glw::GLuint vec4_operator1_subroutine_location,
9474 glw::GLuint vec4_operator2_subroutine_location)
9475 {
9476 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
9477
9478 /* Set up subroutines */
9479 glw::GLuint subroutine_configuration[4 /* total number of subroutines */] = {0};
9480
9481 subroutine_configuration[m_po_subroutine_uniform_bool_operator1] = bool_operator1_subroutine_location;
9482 subroutine_configuration[m_po_subroutine_uniform_bool_operator2] = bool_operator2_subroutine_location;
9483 subroutine_configuration[m_po_subroutine_uniform_vec4_processor1] = vec4_operator1_subroutine_location;
9484 subroutine_configuration[m_po_subroutine_uniform_vec4_processor2] = vec4_operator2_subroutine_location;
9485
9486 gl.useProgram(m_po_id);
9487 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
9488
9489 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, 4 /* count */, subroutine_configuration);
9490 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniformSubroutinesuiv() call failed");
9491
9492 /* Draw test-specific number of points */
9493 gl.beginTransformFeedback(GL_POINTS);
9494 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed");
9495 {
9496 gl.drawArrays(GL_POINTS, 0 /* first */, m_n_points_to_draw);
9497 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed");
9498 }
9499 gl.endTransformFeedback();
9500 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed");
9501
9502 /* Map the BO storage into process space */
9503 const glw::GLvoid *xfb_data_ptr = gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
9504 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer() call failed.");
9505
9506 verifyXFBData(xfb_data_ptr, bool_operator1_subroutine_location, bool_operator2_subroutine_location,
9507 vec4_operator1_subroutine_location, vec4_operator2_subroutine_location);
9508
9509 /* Unmap BO storage */
9510 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
9511 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
9512 }
9513
9514 /** Retrieves body of a vertex shader to be used by the test. */
getVertexShaderBody() const9515 std::string FunctionalTest18_19::getVertexShaderBody() const
9516 {
9517 return "#version 400\n"
9518 "\n"
9519 "subroutine bool bool_processor();\n"
9520 "subroutine vec4 vec4_processor(in vec4 iparam);\n"
9521 "\n"
9522 "subroutine(bool_processor) bool returnsFalse()\n"
9523 "{\n"
9524 " return false;\n"
9525 "}\n"
9526 "\n"
9527 "subroutine(bool_processor) bool returnsTrue()\n"
9528 "{\n"
9529 " return true;\n"
9530 "}\n"
9531 "\n"
9532 "subroutine(vec4_processor) vec4 divideByTwo(in vec4 iparam)\n"
9533 "{\n"
9534 " return iparam * vec4(0.5);\n"
9535 "}\n"
9536 "\n"
9537 "subroutine(vec4_processor) vec4 multiplyByFour(in vec4 iparam)\n"
9538 "{\n"
9539 " return iparam * vec4(4.0);\n"
9540 "}\n"
9541 "\n"
9542 "subroutine uniform bool_processor bool_operator1;\n"
9543 "subroutine uniform bool_processor bool_operator2;\n"
9544 "subroutine uniform vec4_processor vec4_operator1;\n"
9545 "subroutine uniform vec4_processor vec4_operator2;\n"
9546 "\n"
9547 "out float result;\n"
9548 "\n"
9549 "void main()\n"
9550 "{\n"
9551 " if (bool_operator1() )\n"
9552 " {\n"
9553 " float value = float( (3 * gl_VertexID + 1) * 2);\n"
9554 "\n"
9555 " while (bool_operator1() )\n"
9556 " {\n"
9557 " value /= float(gl_VertexID + 2);\n"
9558 "\n"
9559 " if (value <= 1.0f) break;\n"
9560 " }\n"
9561 "\n"
9562 " result = value;\n"
9563 " }\n"
9564 " else\n"
9565 " {\n"
9566 " vec4 value = vec4(gl_VertexID, gl_VertexID + 1,\n"
9567 " gl_VertexID + 2, gl_VertexID + 3);\n"
9568 "\n"
9569 " switch (gl_VertexID % 2)\n"
9570 " {\n"
9571 " case 0:\n"
9572 " {\n"
9573 " for (int iteration = 0; iteration < gl_VertexID && bool_operator2(); ++iteration)\n"
9574 " {\n"
9575 " value = vec4_operator2(vec4_operator1(value));\n"
9576 " }\n"
9577 "\n"
9578 " break;\n"
9579 " }\n"
9580 "\n"
9581 " case 1:\n"
9582 " {\n"
9583 " for (int iteration = 0; iteration < gl_VertexID * 2; ++iteration)\n"
9584 " {\n"
9585 " value = vec4_operator1(vec4_operator2(value));\n"
9586 " }\n"
9587 "\n"
9588 " break;\n"
9589 " }\n"
9590 " }\n"
9591 "\n"
9592 " result = value.x + value.y + value.z + value.w;\n"
9593 "\n"
9594 " }\n"
9595 "}\n";
9596 }
9597
9598 /** Initializes all GL objects required to run the test. */
initTest()9599 void FunctionalTest18_19::initTest()
9600 {
9601 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
9602 const char *varyings[1] = {"result"};
9603 std::string vs_body = getVertexShaderBody();
9604 const unsigned int n_varyings = sizeof(varyings) / sizeof(varyings[0]);
9605
9606 if (!Utils::buildProgram(gl, vs_body, "", /* tc_body */
9607 "", /* te_body */
9608 "", /* gs_body */
9609 "", /* fs_body */
9610 varyings, n_varyings, &m_vs_id, DE_NULL, /* out_tc_id */
9611 DE_NULL, /* out_te_id */
9612 DE_NULL, /* out_gs_id */
9613 DE_NULL, /* out_fs_id */
9614 &m_po_id))
9615 {
9616 TCU_FAIL("Failed to build test program object");
9617 }
9618
9619 /* Retrieve subroutine & subroutine uniform locations */
9620 m_po_subroutine_divide_by_two_location = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "divideByTwo");
9621 m_po_subroutine_multiply_by_four_location = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "multiplyByFour");
9622 m_po_subroutine_returns_false_location = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "returnsFalse");
9623 m_po_subroutine_returns_true_location = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "returnsTrue");
9624 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineIndex() call(s) failed");
9625
9626 if (m_po_subroutine_divide_by_two_location == GL_INVALID_INDEX ||
9627 m_po_subroutine_multiply_by_four_location == GL_INVALID_INDEX ||
9628 m_po_subroutine_returns_false_location == GL_INVALID_INDEX ||
9629 m_po_subroutine_returns_true_location == GL_INVALID_INDEX)
9630 {
9631 TCU_FAIL("glGetSubroutineIndex() returned GL_INVALID_INDEX for a valid subroutine");
9632 }
9633
9634 m_po_subroutine_uniform_bool_operator1 =
9635 gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "bool_operator1");
9636 m_po_subroutine_uniform_bool_operator2 =
9637 gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "bool_operator2");
9638 m_po_subroutine_uniform_vec4_processor1 =
9639 gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "vec4_operator1");
9640 m_po_subroutine_uniform_vec4_processor2 =
9641 gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "vec4_operator2");
9642 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineUniformLocation() call(s) failed");
9643
9644 if (m_po_subroutine_uniform_bool_operator1 == -1 || m_po_subroutine_uniform_bool_operator2 == -1 ||
9645 m_po_subroutine_uniform_vec4_processor1 == -1 || m_po_subroutine_uniform_vec4_processor2 == -1)
9646 {
9647 TCU_FAIL("glGetSubroutineUniformLocation() returned -1 for an active subroutine uniform");
9648 }
9649
9650 /* Set up XFB BO */
9651 const unsigned int bo_size = static_cast<unsigned int>(sizeof(float) * m_n_points_to_draw);
9652
9653 gl.genBuffers(1, &m_xfb_bo_id);
9654 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
9655
9656 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_xfb_bo_id);
9657 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
9658
9659 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_xfb_bo_id);
9660 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed.");
9661
9662 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, DE_NULL /* data */, GL_STATIC_COPY);
9663 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
9664
9665 /* Set up a VAO */
9666 gl.genVertexArrays(1, &m_vao_id);
9667 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
9668
9669 gl.bindVertexArray(m_vao_id);
9670 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
9671 }
9672
9673 /** Executes test iteration.
9674 *
9675 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
9676 */
iterate()9677 tcu::TestNode::IterateResult FunctionalTest18_19::iterate()
9678 {
9679 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
9680 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
9681 {
9682 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
9683 }
9684
9685 /* Initialize all GL objects required to run the test */
9686 initTest();
9687
9688 /* Iterate over all subroutine permutations */
9689 const glw::GLuint subroutine_bool_operators[] = {m_po_subroutine_returns_false_location,
9690 m_po_subroutine_returns_true_location};
9691 const unsigned int n_subroutine_bool_operators =
9692 sizeof(subroutine_bool_operators) / sizeof(subroutine_bool_operators[0]);
9693
9694 const glw::GLuint subroutine_vec4_operators[] = {m_po_subroutine_divide_by_two_location,
9695 m_po_subroutine_multiply_by_four_location};
9696 const unsigned int n_subroutine_vec4_operators =
9697 sizeof(subroutine_vec4_operators) / sizeof(subroutine_vec4_operators[0]);
9698
9699 for (unsigned int n_subroutine_uniform_bool_operator1 = 0;
9700 n_subroutine_uniform_bool_operator1 < n_subroutine_bool_operators; ++n_subroutine_uniform_bool_operator1)
9701 {
9702 for (unsigned int n_subroutine_uniform_bool_operator2 = 0;
9703 n_subroutine_uniform_bool_operator2 < n_subroutine_bool_operators; ++n_subroutine_uniform_bool_operator2)
9704 {
9705 for (unsigned int n_subroutine_uniform_vec4_operator1 = 0;
9706 n_subroutine_uniform_vec4_operator1 < n_subroutine_vec4_operators;
9707 ++n_subroutine_uniform_vec4_operator1)
9708 {
9709 for (unsigned int n_subroutine_uniform_vec4_operator2 = 0;
9710 n_subroutine_uniform_vec4_operator2 < n_subroutine_vec4_operators;
9711 ++n_subroutine_uniform_vec4_operator2)
9712 {
9713 executeTest(subroutine_bool_operators[n_subroutine_uniform_bool_operator1],
9714 subroutine_bool_operators[n_subroutine_uniform_bool_operator2],
9715 subroutine_vec4_operators[n_subroutine_uniform_vec4_operator1],
9716 subroutine_vec4_operators[n_subroutine_uniform_vec4_operator2]);
9717 } /* for (all subroutine vec4 operator subroutines used for processor2) */
9718 } /* for (all subroutine vec4 operator subroutines used for processor1) */
9719 } /* for (all subroutine bool operator subroutines used for operator2) */
9720 } /* for (all subroutine bool operator subroutines used for operator1) */
9721
9722 /* All done */
9723 if (m_has_test_passed)
9724 {
9725 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
9726 }
9727 else
9728 {
9729 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
9730 }
9731
9732 return STOP;
9733 }
9734
9735 /** Divides input argument by two. The result value is returned to the
9736 * caller.
9737 *
9738 * @param data Input value.
9739 *
9740 * @return As per description.
9741 **/
vec4operator_div2(tcu::Vec4 data)9742 tcu::Vec4 FunctionalTest18_19::vec4operator_div2(tcu::Vec4 data)
9743 {
9744 return data * 0.5f;
9745 }
9746
9747 /** Multiplies input argument by four. The result value is returned to the
9748 * caller.
9749 *
9750 * @param data Input value.
9751 *
9752 * @return As per description.
9753 **/
vec4operator_mul4(tcu::Vec4 data)9754 tcu::Vec4 FunctionalTest18_19::vec4operator_mul4(tcu::Vec4 data)
9755 {
9756 return data * 4.0f;
9757 }
9758
9759 /** Verifies data XFBed out by the vertex shader. It is assumed the subroutines were configured
9760 * as per passed arguments, prior to the draw call.
9761 *
9762 * If the result data is found to be invalid, m_has_test_passed is set to false.
9763 *
9764 * @param data XFBed data.
9765 * @param bool_operator1_subroutine_location Location of a subroutine to be assigned to
9766 * bool_operator1 subroutine uniform.
9767 * @param bool_operator2_subroutine_location Location of a subroutine to be assigned to
9768 * bool_operator2 subroutine uniform.
9769 * @param vec4_operator1_subroutine_location Location of a subroutine to be assigned to
9770 * vec4_operator1 subroutine uniform.
9771 * @param vec4_operator2_subroutine_location Location of a subroutine to be assigned to
9772 * vec4_operator2 subroutine uniform.
9773 */
verifyXFBData(const glw::GLvoid * data,glw::GLuint bool_operator1_subroutine_location,glw::GLuint bool_operator2_subroutine_location,glw::GLuint vec4_operator1_subroutine_location,glw::GLuint vec4_operator2_subroutine_location)9774 void FunctionalTest18_19::verifyXFBData(const glw::GLvoid *data, glw::GLuint bool_operator1_subroutine_location,
9775 glw::GLuint bool_operator2_subroutine_location,
9776 glw::GLuint vec4_operator1_subroutine_location,
9777 glw::GLuint vec4_operator2_subroutine_location)
9778 {
9779 bool bool_operator1_result = false;
9780 bool bool_operator2_result = false;
9781 const float epsilon = 1e-5f;
9782 PFNVEC4OPERATORPROC pVec4Operator1 = NULL;
9783 PFNVEC4OPERATORPROC pVec4Operator2 = NULL;
9784 const glw::GLfloat *traveller_ptr = (const glw::GLfloat *)data;
9785
9786 bool_operator1_result = (bool_operator1_subroutine_location == m_po_subroutine_returns_true_location);
9787 bool_operator2_result = (bool_operator2_subroutine_location == m_po_subroutine_returns_true_location);
9788 pVec4Operator1 = (vec4_operator1_subroutine_location == m_po_subroutine_divide_by_two_location) ?
9789 vec4operator_div2 :
9790 vec4operator_mul4;
9791 pVec4Operator2 = (vec4_operator2_subroutine_location == m_po_subroutine_divide_by_two_location) ?
9792 vec4operator_div2 :
9793 vec4operator_mul4;
9794
9795 for (unsigned int n_vertex = 0; n_vertex < m_n_points_to_draw; ++n_vertex)
9796 {
9797 float expected_value = 0.0f;
9798
9799 if (bool_operator1_result)
9800 {
9801 float value = float((3 * n_vertex + 1) * 2);
9802
9803 while (bool_operator1_result)
9804 {
9805 value /= float(n_vertex + 2);
9806
9807 if (value <= 1.0f)
9808 break;
9809 }
9810
9811 expected_value = value;
9812 }
9813 else
9814 {
9815 tcu::Vec4 value((float)n_vertex, (float)n_vertex + 1, (float)n_vertex + 2, (float)n_vertex + 3);
9816
9817 switch (n_vertex % 2)
9818 {
9819 case 0:
9820 {
9821 for (unsigned int iteration = 0; iteration < n_vertex && bool_operator2_result; ++iteration)
9822 {
9823 value = pVec4Operator2(pVec4Operator1(value));
9824 }
9825
9826 break;
9827 }
9828
9829 case 1:
9830 {
9831 for (unsigned int iteration = 0; iteration < n_vertex * 2; ++iteration)
9832 {
9833 value = pVec4Operator1(pVec4Operator2(value));
9834 }
9835
9836 break;
9837 }
9838 } /* switch (n_vertex % 2) */
9839
9840 expected_value = value.x() + value.y() + value.z() + value.w();
9841 }
9842
9843 if (de::abs(expected_value - *traveller_ptr) > epsilon)
9844 {
9845 m_testCtx.getLog() << tcu::TestLog::Message << "XFBed data was found to be invalid at index [" << n_vertex
9846 << "]"
9847 "for the following subroutine location configuration:"
9848 " bool_operator1_subroutine_location:["
9849 << bool_operator1_subroutine_location
9850 << "]"
9851 " bool_operator2_subroutine_location:["
9852 << bool_operator2_subroutine_location
9853 << "]"
9854 " vec4_operator1_subroutine_location:["
9855 << vec4_operator1_subroutine_location
9856 << "]"
9857 " vec4_operator2_subroutine_location:["
9858 << vec4_operator2_subroutine_location
9859 << "];"
9860 " expected data:"
9861 << expected_value << ", found:" << *traveller_ptr << tcu::TestLog::EndMessage;
9862
9863 m_has_test_passed = false;
9864 }
9865
9866 ++traveller_ptr;
9867 } /* for (all drawn points) */
9868 }
9869
9870 /** Constructor.
9871 *
9872 * @param context Rendering context.
9873 *
9874 **/
NegativeTest1(deqp::Context & context)9875 NegativeTest1::NegativeTest1(deqp::Context &context)
9876 : TestCase(context, "subroutine_errors",
9877 "Verifies all GL_INVALID_OPERATION, GL_INVALID_VALUE, GL_INVALID ENUM "
9878 "errors related to subroutine usage are properly generated.")
9879 , m_has_test_passed(true)
9880 , m_po_active_subroutine_uniform_locations(0)
9881 , m_po_active_subroutine_uniforms(0)
9882 , m_po_active_subroutines(0)
9883 , m_po_subroutine_uniform_function_index(-1)
9884 , m_po_subroutine_uniform_function2_index(-1)
9885 , m_po_subroutine_test1_index(GL_INVALID_INDEX)
9886 , m_po_subroutine_test2_index(GL_INVALID_INDEX)
9887 , m_po_subroutine_test3_index(GL_INVALID_INDEX)
9888 , m_po_not_linked_id(0)
9889 , m_po_id(0)
9890 , m_vs_id(0)
9891 {
9892 /* Left blank intentionally */
9893 }
9894
9895 /** Deinitializes all GL objects that may have been created during
9896 * test execution.
9897 **/
deinit()9898 void NegativeTest1::deinit()
9899 {
9900 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
9901
9902 if (m_po_id != 0)
9903 {
9904 gl.deleteProgram(m_po_id);
9905
9906 m_po_id = 0;
9907 }
9908
9909 if (m_po_not_linked_id != 0)
9910 {
9911 gl.deleteProgram(m_po_not_linked_id);
9912
9913 m_po_not_linked_id = 0;
9914 }
9915
9916 if (m_vs_id != 0)
9917 {
9918 gl.deleteShader(m_vs_id);
9919
9920 m_vs_id = 0;
9921 }
9922 }
9923
9924 /** Initializes all GL objects required to run the test. */
initTest()9925 void NegativeTest1::initTest()
9926 {
9927 glw::GLint compile_status = GL_FALSE;
9928 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
9929
9930 /* Create program objects */
9931 m_po_not_linked_id = gl.createProgram();
9932 m_po_id = gl.createProgram();
9933 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call(s) failed.");
9934
9935 /* Create vertex shader object */
9936 m_vs_id = gl.createShader(GL_VERTEX_SHADER);
9937 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
9938
9939 /* Set up vertex shader */
9940 const char *vs_body = "#version 400\n"
9941 "\n"
9942 "#extension GL_ARB_shader_subroutine : require\n"
9943 "\n"
9944 "subroutine void subroutineType (out ivec2 arg);\n"
9945 "subroutine void subroutineType2(out ivec4 arg);\n"
9946 "\n"
9947 "subroutine(subroutineType) void test1(out ivec2 arg)\n"
9948 "{\n"
9949 " arg = ivec2(1, 2);\n"
9950 "}\n"
9951 "subroutine(subroutineType) void test2(out ivec2 arg)\n"
9952 "{\n"
9953 " arg = ivec2(3,4);\n"
9954 "}\n"
9955 "subroutine(subroutineType2) void test3(out ivec4 arg)\n"
9956 "{\n"
9957 " arg = ivec4(1, 2, 3, 4);\n"
9958 "}\n"
9959 "\n"
9960 "subroutine uniform subroutineType function;\n"
9961 "subroutine uniform subroutineType2 function2;\n"
9962 "\n"
9963 "void main()\n"
9964 "{\n"
9965 " ivec2 test;\n"
9966 " ivec4 test2;\n"
9967 "\n"
9968 " function(test);\n"
9969 "\n"
9970 " if (test.x > 2)\n"
9971 " {\n"
9972 " gl_Position = vec4(1);\n"
9973 " }\n"
9974 " else\n"
9975 " {\n"
9976 " function2(test2);\n"
9977 "\n"
9978 " gl_Position = vec4(float(test2.x) );\n"
9979 " }\n"
9980 "}\n";
9981
9982 gl.shaderSource(m_vs_id, 1 /* count */, &vs_body, DE_NULL /* length */);
9983 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed");
9984
9985 gl.compileShader(m_vs_id);
9986 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed");
9987
9988 gl.getShaderiv(m_vs_id, GL_COMPILE_STATUS, &compile_status);
9989 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed");
9990
9991 if (compile_status == GL_FALSE)
9992 {
9993 TCU_FAIL("Shader compilation failed");
9994 }
9995
9996 /* Set up & link the test program object */
9997 glw::GLint link_status = GL_FALSE;
9998
9999 gl.attachShader(m_po_id, m_vs_id);
10000 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
10001
10002 gl.linkProgram(m_po_id);
10003 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
10004
10005 gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
10006 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
10007
10008 if (link_status == GL_FALSE)
10009 {
10010 TCU_FAIL("Program linking failed");
10011 }
10012
10013 /* Query test program object's properties */
10014 gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS,
10015 &m_po_active_subroutine_uniform_locations);
10016 gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORMS, &m_po_active_subroutine_uniforms);
10017 gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINES, &m_po_active_subroutines);
10018 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramStageiv() call(s) failed.");
10019
10020 if (m_po_active_subroutine_uniform_locations != 2)
10021 {
10022 TCU_FAIL("Invalid GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS value returned");
10023 }
10024
10025 m_po_subroutine_test1_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "test1");
10026 m_po_subroutine_test2_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "test2");
10027 m_po_subroutine_test3_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "test3");
10028 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineIndex() call(s) failed.");
10029
10030 if (m_po_subroutine_test1_index == GL_INVALID_INDEX || m_po_subroutine_test2_index == GL_INVALID_INDEX ||
10031 m_po_subroutine_test3_index == GL_INVALID_INDEX)
10032 {
10033 TCU_FAIL("Invalid subroutine index returned");
10034 }
10035
10036 m_po_subroutine_uniform_function_index = gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "function");
10037 m_po_subroutine_uniform_function2_index = gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "function2");
10038 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineUniformLocation() call(s) failed.");
10039
10040 if (m_po_subroutine_uniform_function_index == -1 || m_po_subroutine_uniform_function2_index == -1)
10041 {
10042 TCU_FAIL("Invalid subroutine uniform index returned");
10043 }
10044 }
10045
10046 /** Executes test iteration.
10047 *
10048 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
10049 */
iterate()10050 tcu::TestNode::IterateResult NegativeTest1::iterate()
10051 {
10052 glw::GLenum error_code = GL_NO_ERROR;
10053 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
10054
10055 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
10056 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
10057 {
10058 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
10059 }
10060
10061 /* Initialize GL objects required to run the test */
10062 initTest();
10063
10064 /* The error INVALID_OPERATION is generated by GetSubroutineUniformLocation
10065 * if the program object identified by <program> has not been successfully
10066 * linked.
10067 */
10068 gl.getSubroutineUniformLocation(m_po_not_linked_id, GL_FRAGMENT_SHADER, "subroutine_uniform_name");
10069
10070 error_code = gl.getError();
10071
10072 if (error_code != GL_INVALID_OPERATION)
10073 {
10074 m_testCtx.getLog() << tcu::TestLog::Message
10075 << "glGetSubroutineUniformLocation() does not generate GL_INVALID_OPERATION "
10076 "error code when called for a non-linked program object."
10077 << tcu::TestLog::EndMessage;
10078
10079 m_has_test_passed = false;
10080 }
10081
10082 /* The error INVALID_VALUE is generated by GetActiveSubroutineUniformiv or
10083 * GetActiveSubroutineUniformName if <index> is greater than or equal to the
10084 * value of ACTIVE_SUBROUTINE_UNIFORMS for the shader stage.
10085 */
10086 glw::GLint temp_length = 0;
10087 glw::GLint temp_values = 0;
10088
10089 gl.getActiveSubroutineUniformiv(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutine_uniforms,
10090 GL_NUM_COMPATIBLE_SUBROUTINES, &temp_values);
10091 error_code = gl.getError();
10092
10093 if (error_code == GL_INVALID_VALUE)
10094 {
10095 gl.getActiveSubroutineUniformiv(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutine_uniforms + 1,
10096 GL_NUM_COMPATIBLE_SUBROUTINES, &temp_values);
10097
10098 error_code = gl.getError();
10099 }
10100
10101 if (error_code != GL_INVALID_VALUE)
10102 {
10103 m_testCtx.getLog() << tcu::TestLog::Message
10104 << "glGetActiveSubroutineUniformiv() does not generate GL_INVALID_VALUE "
10105 "when passed <index> argument that is greater than or equal to "
10106 "the value of GL_ACTIVE_SUBROUTINE_UNIFORMS."
10107 << tcu::TestLog::EndMessage;
10108
10109 m_has_test_passed = false;
10110 }
10111
10112 gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutine_uniforms, 0, /* bufsize */
10113 &temp_length, DE_NULL); /* name */
10114 error_code = gl.getError();
10115
10116 if (error_code == GL_INVALID_VALUE)
10117 {
10118 gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutine_uniforms + 1,
10119 0, /* bufsize */
10120 &temp_length, DE_NULL); /* name */
10121
10122 error_code = gl.getError();
10123 }
10124
10125 if (error_code != GL_INVALID_VALUE)
10126 {
10127 m_testCtx.getLog() << tcu::TestLog::Message
10128 << "glGetActiveSubroutineUniformName() does not generate GL_INVALID_VALUE "
10129 "when passed <index> argument that is greater than or equal to "
10130 "the value of GL_ACTIVE_SUBROUTINE_UNIFORMS."
10131 << tcu::TestLog::EndMessage;
10132
10133 m_has_test_passed = false;
10134 }
10135
10136 /* The error INVALID_VALUE is generated by GetActiveSubroutineName if <index>
10137 * is greater than or equal to the value of ACTIVE_SUBROUTINES for the shader
10138 * stage.
10139 */
10140 gl.getActiveSubroutineName(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutines, 0, /* bufsize */
10141 &temp_length, DE_NULL); /* name */
10142 error_code = gl.getError();
10143
10144 if (error_code == GL_INVALID_VALUE)
10145 {
10146 gl.getActiveSubroutineName(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutines + 1, 0, /* bufsize */
10147 &temp_length, DE_NULL); /* name */
10148
10149 error_code = gl.getError();
10150 }
10151
10152 if (error_code != GL_INVALID_VALUE)
10153 {
10154 m_testCtx.getLog() << tcu::TestLog::Message
10155 << "glGetActiveSubroutineName() does not generate GL_INVALID_VALUE "
10156 "when passed <index> argument that is greater than or equal to "
10157 "the value of GL_ACTIVE_SUBROUTINES."
10158 << tcu::TestLog::EndMessage;
10159
10160 m_has_test_passed = false;
10161 }
10162
10163 /* The error INVALID_VALUE is generated by UniformSubroutinesuiv if <count>
10164 * is not equal to the value of ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS for the
10165 * shader stage <shadertype>.
10166 */
10167 glw::GLuint index = 0;
10168
10169 gl.useProgram(m_po_id);
10170 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
10171
10172 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations - 1, &index);
10173 error_code = gl.getError();
10174
10175 if (error_code == GL_INVALID_VALUE)
10176 {
10177 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations + 1, &index);
10178
10179 error_code = gl.getError();
10180 }
10181
10182 if (error_code != GL_INVALID_VALUE)
10183 {
10184 m_testCtx.getLog() << tcu::TestLog::Message
10185 << "glUniformSubroutinesiv() does not generate GL_INVALID_VALUE "
10186 "when passed <count> argument that is not equal to the value of "
10187 "GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS."
10188 << tcu::TestLog::EndMessage;
10189
10190 m_has_test_passed = false;
10191 }
10192
10193 /* The error INVALID_VALUE is generated by UniformSubroutinesuiv if any value
10194 * in <indices> is greater than or equal to the value of ACTIVE_SUBROUTINES
10195 * for the shader stage.
10196 */
10197 glw::GLuint invalid_subroutine_indices[4] = {(GLuint)m_po_active_subroutines, (GLuint)m_po_active_subroutines,
10198 (GLuint)m_po_active_subroutines + 1,
10199 (GLuint)m_po_active_subroutines + 1};
10200
10201 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations, /* count */
10202 invalid_subroutine_indices + 0);
10203 error_code = gl.getError();
10204
10205 if (error_code == GL_INVALID_VALUE)
10206 {
10207 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations,
10208 invalid_subroutine_indices + 2);
10209
10210 error_code = gl.getError();
10211 }
10212
10213 if (error_code != GL_INVALID_VALUE)
10214 {
10215 m_testCtx.getLog() << tcu::TestLog::Message
10216 << "glUniformSubroutinesuiv() does not generate GL_INVALID_VALUE "
10217 "when the value passed via <indices> argument is greater than "
10218 "or equal to the value of GL_ACTIVE_SUBROUTINES."
10219 << tcu::TestLog::EndMessage;
10220
10221 m_has_test_passed = false;
10222 }
10223
10224 /* The error INVALID_OPERATION is generated by UniformSubroutinesuiv() if any
10225 * subroutine index in <indices> identifies a subroutine not associated with
10226 * the type of the subroutine uniform variable assigned to the corresponding
10227 * location.
10228 */
10229 glw::GLuint invalid_subroutine_indices2[2] = {m_po_subroutine_test1_index, m_po_subroutine_test1_index};
10230
10231 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations, invalid_subroutine_indices2);
10232 error_code = gl.getError();
10233
10234 if (error_code != GL_INVALID_OPERATION)
10235 {
10236 m_testCtx.getLog() << tcu::TestLog::Message
10237 << "glUniformSubroutinesuiv() does not generate GL_INVALID_OPERATION "
10238 "when the subroutine index passed via <indices> argument identifies"
10239 "a subroutine not associated with the type of the subroutine uniform "
10240 "assigned to the corresponding location."
10241 << tcu::TestLog::EndMessage;
10242
10243 m_has_test_passed = false;
10244 }
10245
10246 /* The error INVALID_OPERATION is generated by UniformSubroutinesuiv if no
10247 * program is active.
10248 */
10249 glw::GLuint valid_subroutine_locations[2] = {0};
10250
10251 valid_subroutine_locations[m_po_subroutine_uniform_function_index] = m_po_subroutine_test1_index;
10252 valid_subroutine_locations[m_po_subroutine_uniform_function2_index] = m_po_subroutine_test3_index;
10253
10254 gl.useProgram(0);
10255 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
10256
10257 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations, valid_subroutine_locations);
10258 error_code = gl.getError();
10259
10260 if (error_code != GL_INVALID_OPERATION)
10261 {
10262 m_testCtx.getLog() << tcu::TestLog::Message
10263 << "glUniformSubroutinesuiv() does not generate GL_INVALID_OPERATION "
10264 "when called without an active program object."
10265 << tcu::TestLog::EndMessage;
10266
10267 m_has_test_passed = false;
10268 }
10269
10270 /* The error INVALID_VALUE is generated by GetUniformSubroutineuiv if
10271 * <location> is greater than or equal to the value of
10272 * ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS for the shader stage.
10273 */
10274 glw::GLuint temp_value = 0;
10275
10276 gl.useProgram(m_po_id);
10277 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
10278
10279 gl.getUniformSubroutineuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations, &temp_value);
10280 error_code = gl.getError();
10281
10282 if (error_code == GL_INVALID_VALUE)
10283 {
10284 gl.getUniformSubroutineuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations + 1, &temp_value);
10285 error_code = gl.getError();
10286 }
10287
10288 if (error_code != GL_INVALID_VALUE)
10289 {
10290 m_testCtx.getLog() << tcu::TestLog::Message
10291 << "glGetUniformSubroutineuiv() does not generate GL_INVALID_VALUE "
10292 "when called for location that is greater than or equal to the value "
10293 "of GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS."
10294 << tcu::TestLog::EndMessage;
10295
10296 m_has_test_passed = false;
10297 }
10298
10299 /* The error INVALID_OPERATION is generated by GetUniformSubroutineuiv if no
10300 * program is active for the shader stage identified by <shadertype>.
10301 */
10302 const glw::GLenum undefined_shader_stages[] = {GL_FRAGMENT_SHADER, GL_GEOMETRY_SHADER, GL_TESS_CONTROL_SHADER,
10303 GL_TESS_EVALUATION_SHADER};
10304 const unsigned int n_undefined_shader_stages = sizeof(undefined_shader_stages) / sizeof(undefined_shader_stages[0]);
10305
10306 for (unsigned int n_undefined_shader_stage = 0; n_undefined_shader_stage < n_undefined_shader_stages;
10307 ++n_undefined_shader_stage)
10308 {
10309 glw::GLenum shader_stage = undefined_shader_stages[n_undefined_shader_stage];
10310
10311 gl.getUniformSubroutineuiv(shader_stage, 0, /* location */
10312 &temp_value);
10313 error_code = gl.getError();
10314
10315 if (error_code != GL_INVALID_OPERATION)
10316 {
10317 m_testCtx.getLog() << tcu::TestLog::Message
10318 << "glGetUniformSubroutineuiv() does not generate GL_INVALID_OPERATION "
10319 "when called for a shader stage that is not defined for active "
10320 "program object."
10321 << tcu::TestLog::EndMessage;
10322
10323 m_has_test_passed = false;
10324 }
10325 } /* for (all undefined shader stages) */
10326
10327 /* All done */
10328 if (m_has_test_passed)
10329 {
10330 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
10331 }
10332 else
10333 {
10334 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
10335 }
10336
10337 return STOP;
10338 }
10339
10340 /** Constructor
10341 *
10342 * @param context Rendering context.
10343 *
10344 **/
NegativeTest2(deqp::Context & context)10345 NegativeTest2::NegativeTest2(deqp::Context &context)
10346 : TestCase(context, "subroutine_uniform_scope",
10347 "Verifies subroutine uniforms declared in shader stage A"
10348 "cannot be accessed from a different stage.")
10349 , m_fs_id(0)
10350 , m_gs_id(0)
10351 , m_has_test_passed(true)
10352 , m_po_id(0)
10353 , m_tc_id(0)
10354 , m_te_id(0)
10355 , m_vs_id(0)
10356 {
10357 /* Left blank intentionally */
10358 }
10359
10360 /** Deinitializes all GL objects that may have been created during test execution */
deinit()10361 void NegativeTest2::deinit()
10362 {
10363 deinitGLObjects();
10364 }
10365
10366 /** Deinitializes all GL objects that may have been created during test execution */
deinitGLObjects()10367 void NegativeTest2::deinitGLObjects()
10368 {
10369 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
10370
10371 if (m_fs_id != 0)
10372 {
10373 gl.deleteShader(m_fs_id);
10374
10375 m_fs_id = 0;
10376 }
10377
10378 if (m_gs_id != 0)
10379 {
10380 gl.deleteShader(m_gs_id);
10381
10382 m_gs_id = 0;
10383 }
10384
10385 if (m_tc_id != 0)
10386 {
10387 gl.deleteShader(m_tc_id);
10388
10389 m_tc_id = 0;
10390 }
10391
10392 if (m_te_id != 0)
10393 {
10394 gl.deleteShader(m_te_id);
10395
10396 m_te_id = 0;
10397 }
10398
10399 if (m_vs_id != 0)
10400 {
10401 gl.deleteShader(m_vs_id);
10402
10403 m_vs_id = 0;
10404 }
10405
10406 if (m_po_id != 0)
10407 {
10408 gl.deleteProgram(m_po_id);
10409
10410 m_po_id = 0;
10411 }
10412 }
10413
10414 /** Builds an offending program object and tries to link it. We're either expecting
10415 * a compile-time or link-time error here.
10416 *
10417 * If the program object builds successfully, the test has failed.
10418 *
10419 * @param referencing_stage Shader stage which defines a subroutine uniform that
10420 * should be called from fragment/geometry/tess control/
10421 * tess evaluation/vertex shader stages.
10422 *
10423 **/
executeTestCase(const Utils::_shader_stage & referencing_stage)10424 void NegativeTest2::executeTestCase(const Utils::_shader_stage &referencing_stage)
10425 {
10426 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
10427
10428 const std::string fs_body = getFragmentShaderBody(referencing_stage);
10429 const std::string gs_body = getGeometryShaderBody(referencing_stage);
10430 const std::string tc_body = getTessellationControlShaderBody(referencing_stage);
10431 const std::string te_body = getTessellationEvaluationShaderBody(referencing_stage);
10432 const std::string vs_body = getVertexShaderBody(referencing_stage);
10433
10434 if (Utils::buildProgram(gl, vs_body, tc_body, te_body, gs_body, fs_body, NULL, /* xfb_varyings */
10435 0, /* n_xfb_varyings */
10436 &m_vs_id, &m_tc_id, &m_te_id, &m_gs_id, &m_fs_id, &m_po_id))
10437 {
10438 /* Test program should not have built correctly ! */
10439 m_testCtx.getLog() << tcu::TestLog::Message
10440 << "In the following program, one of the stages references "
10441 "a subroutine that is defined in another stage. This "
10442 "is forbidden by the specification.\n"
10443 "\n"
10444 "Vertex shader:\n\n"
10445 << vs_body.c_str() << "\n\nTessellation control shader:\n\n"
10446 << tc_body.c_str() << "\n\nTessellation evaluation shader:\n\n"
10447 << te_body.c_str() << "\n\nGeometry shader:\n\n"
10448 << gs_body.c_str() << "\n\nFragment shader:\n\n"
10449 << fs_body.c_str() << tcu::TestLog::EndMessage;
10450
10451 m_has_test_passed = false;
10452 } /* if (test program was built successfully) */
10453
10454 /* Release the shaders & the program object that buildProgram() created */
10455 deinitGLObjects();
10456 }
10457
10458 /** Retrieves an offending fragment shader body.
10459 *
10460 * @param referencing_stage Shader stage which defines the subroutine uniform that
10461 * will be called from fragment shader.
10462 *
10463 * @return Requested string.
10464 **/
getFragmentShaderBody(const Utils::_shader_stage & referencing_stage) const10465 std::string NegativeTest2::getFragmentShaderBody(const Utils::_shader_stage &referencing_stage) const
10466 {
10467 std::stringstream result;
10468
10469 /* Form the pre-amble */
10470 result << "#version 400\n"
10471 "\n"
10472 "#extension GL_ARB_shader_subroutine : require\n"
10473 "\n"
10474 "subroutine void testSubroutineType(out vec4 test_argument);\n"
10475 "\n"
10476 /* Define a subroutine */
10477 "subroutine(testSubroutineType) void fs_subroutine(out vec4 test_argument)\n"
10478 "{\n"
10479 " test_argument = vec4(1, 0, 0, 0);\n"
10480 "}\n"
10481 "\n"
10482 /* Define output variables */
10483 "out vec4 result;\n"
10484 "\n"
10485 /* Define uniforms */
10486 "subroutine uniform testSubroutineType test_fs_subroutine;\n"
10487 "\n"
10488 /* Define main() */
10489 "void main()\n"
10490 "{\n"
10491 " "
10492 << getSubroutineUniformName(referencing_stage)
10493 << "(result);\n"
10494 "}\n";
10495
10496 return result.str();
10497 }
10498
10499 /** Retrieves an offending geometry shader body.
10500 *
10501 * @param referencing_stage Shader stage which defines the subroutine uniform that
10502 * will be called from geometry shader.
10503 *
10504 * @return Requested string.
10505 **/
getGeometryShaderBody(const Utils::_shader_stage & referencing_stage) const10506 std::string NegativeTest2::getGeometryShaderBody(const Utils::_shader_stage &referencing_stage) const
10507 {
10508 std::stringstream result;
10509
10510 /* Form the pre-amble */
10511 result << "#version 400\n"
10512 "\n"
10513 "#extension GL_ARB_shader_subroutine : require\n"
10514 "\n"
10515 "subroutine void testSubroutineType(out vec4 test_argument);\n"
10516 "\n"
10517 "layout(points) in;\n"
10518 "layout(points, max_vertices = 1) out;\n"
10519 "\n"
10520 /* Define a subroutine */
10521 "subroutine(testSubroutineType) void gs_subroutine(out vec4 test_argument)\n"
10522 "{\n"
10523 " test_argument = vec4(0, 1, 1, 1);\n"
10524 "}\n"
10525 "\n"
10526 /* Define output variables */
10527 "out vec4 result;\n"
10528 "\n"
10529 /* Define uniforms */
10530 "subroutine uniform testSubroutineType test_gs_subroutine;\n"
10531 "\n"
10532 /* Define main() */
10533 "void main()\n"
10534 "{\n"
10535 " "
10536 << getSubroutineUniformName(referencing_stage)
10537 << "(result);\n"
10538 "}\n";
10539
10540 return result.str();
10541 }
10542
10543 /** Retrieves name of the subroutine uniform that is defined in user-specified
10544 * shader stage.
10545 *
10546 * @param stage Shader stage to retrieve the subroutine uniform name for.
10547 *
10548 * @return As per description.
10549 **/
getSubroutineUniformName(const Utils::_shader_stage & stage) const10550 std::string NegativeTest2::getSubroutineUniformName(const Utils::_shader_stage &stage) const
10551 {
10552 std::string result = "?";
10553
10554 switch (stage)
10555 {
10556 case Utils::SHADER_STAGE_FRAGMENT:
10557 {
10558 result = "test_fs_subroutine";
10559
10560 break;
10561 }
10562
10563 case Utils::SHADER_STAGE_GEOMETRY:
10564 {
10565 result = "test_gs_subroutine";
10566
10567 break;
10568 }
10569
10570 case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
10571 {
10572 result = "test_tc_subroutine";
10573
10574 break;
10575 }
10576
10577 case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
10578 {
10579 result = "test_te_subroutine";
10580
10581 break;
10582 }
10583
10584 case Utils::SHADER_STAGE_VERTEX:
10585 {
10586 result = "test_vs_subroutine";
10587
10588 break;
10589 }
10590
10591 default:
10592 {
10593 TCU_FAIL("Unrecognized shader stage requested");
10594 }
10595 } /* switch (stage) */
10596
10597 return result;
10598 }
10599
10600 /** Retrieves an offending tessellation control shader body.
10601 *
10602 * @param referencing_stage Shader stage which defines the subroutine uniform that
10603 * will be called from tessellation control shader.
10604 *
10605 * @return Requested string.
10606 **/
getTessellationControlShaderBody(const Utils::_shader_stage & referencing_stage) const10607 std::string NegativeTest2::getTessellationControlShaderBody(const Utils::_shader_stage &referencing_stage) const
10608 {
10609 std::stringstream result;
10610
10611 /* Form the pre-amble */
10612 result << "#version 400\n"
10613 "\n"
10614 "#extension GL_ARB_shader_subroutine : require\n"
10615 "\n"
10616 "layout(vertices = 4) out;\n"
10617 "\n"
10618 "subroutine void testSubroutineType(out vec4 test_argument);\n"
10619 "\n"
10620 /* Define a subroutine */
10621 "subroutine(testSubroutineType) void tc_subroutine(out vec4 test_argument)\n"
10622 "{\n"
10623 " test_argument = vec4(0, 0, 1, 0);\n"
10624 "}\n"
10625 "\n"
10626 /* Define uniforms */
10627 "subroutine uniform testSubroutineType test_tc_subroutine;\n"
10628 "\n"
10629 /* Define main() */
10630 "void main()\n"
10631 "{\n"
10632 " "
10633 << getSubroutineUniformName(referencing_stage)
10634 << "(gl_out[gl_InvocationID].gl_Position);\n"
10635 "}\n";
10636
10637 return result.str();
10638 }
10639
10640 /** Retrieves an offending tessellation evaluation shader body.
10641 *
10642 * @param referencing_stage Shader stage which defines the subroutine uniform that
10643 * will be called from tessellation evaluation shader.
10644 *
10645 * @return Requested string.
10646 **/
getTessellationEvaluationShaderBody(const Utils::_shader_stage & referencing_stage) const10647 std::string NegativeTest2::getTessellationEvaluationShaderBody(const Utils::_shader_stage &referencing_stage) const
10648 {
10649 std::stringstream result;
10650
10651 /* Form the pre-amble */
10652 result << "#version 400\n"
10653 "\n"
10654 "#extension GL_ARB_shader_subroutine : require\n"
10655 "\n"
10656 "layout(quads) in;\n"
10657 "\n"
10658 "subroutine void testSubroutineType(out vec4 test_argument);\n"
10659 "\n"
10660 /* Define a subroutine */
10661 "subroutine(testSubroutineType) void te_subroutine(out vec4 test_argument)\n"
10662 "{\n"
10663 " test_argument = vec4(1, 1, 1, 1);\n"
10664 "}\n"
10665 "\n"
10666 /* Define uniforms */
10667 "subroutine uniform testSubroutineType test_te_subroutine;\n"
10668 "\n"
10669 /* Define main() */
10670 "void main()\n"
10671 "{\n"
10672 " "
10673 << getSubroutineUniformName(referencing_stage)
10674 << "(gl_Position);\n"
10675 "}\n";
10676
10677 return result.str();
10678 }
10679
10680 /** Retrieves an offending vertex shader body.
10681 *
10682 * @param referencing_stage Shader stage which defines the subroutine uniform that
10683 * will be called from vertex shader.
10684 *
10685 * @return Requested string.
10686 **/
getVertexShaderBody(const Utils::_shader_stage & referencing_stage) const10687 std::string NegativeTest2::getVertexShaderBody(const Utils::_shader_stage &referencing_stage) const
10688 {
10689 std::stringstream result;
10690
10691 /* Form the pre-amble */
10692 result << "#version 400\n"
10693 "\n"
10694 "#extension GL_ARB_shader_subroutine : require\n"
10695 "\n"
10696 "subroutine void testSubroutineType(out vec4 test_argument);\n"
10697 "\n"
10698 /* Define a subroutine */
10699 "subroutine(testSubroutineType) void vs_subroutine(out vec4 test_argument)\n"
10700 "{\n"
10701 " test_argument = vec4(0, 1, 0, 0);\n"
10702 "}\n"
10703 "\n"
10704 /* Define uniforms */
10705 "subroutine uniform testSubroutineType test_vs_subroutine;\n"
10706 "\n"
10707 /* Define main() */
10708 "void main()\n"
10709 "{\n"
10710 " "
10711 << getSubroutineUniformName(referencing_stage)
10712 << "(gl_Position);\n"
10713 "}\n";
10714
10715 return result.str();
10716 }
10717
10718 /** Executes test iteration.
10719 *
10720 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
10721 */
iterate()10722 tcu::TestNode::IterateResult NegativeTest2::iterate()
10723 {
10724 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
10725 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
10726 {
10727 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
10728 }
10729
10730 /* Iterate over all shader stages and execute the checks */
10731 for (int referencing_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
10732 referencing_stage < static_cast<int>(Utils::SHADER_STAGE_COUNT); ++referencing_stage)
10733 {
10734 executeTestCase(static_cast<Utils::_shader_stage>(referencing_stage));
10735 } /* for (all test cases) */
10736
10737 /* All done */
10738 if (m_has_test_passed)
10739 {
10740 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
10741 }
10742 else
10743 {
10744 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
10745 }
10746
10747 return STOP;
10748 }
10749
10750 /** Constructor.
10751 *
10752 * @param context Rendering context.
10753 *
10754 **/
NegativeTest3(deqp::Context & context)10755 NegativeTest3::NegativeTest3(deqp::Context &context)
10756 : TestCase(context, "missing_subroutine_keyword",
10757 "Verifies that subroutine keyword is necessary when declaring a "
10758 "subroutine uniforn and a compilation error occurs without it.")
10759 , m_has_test_passed(true)
10760 , m_so_id(0)
10761 {
10762 /* Left blank intentionally */
10763 }
10764
10765 /** Deinitializes all GL objects that may have been created during test execution */
deinit()10766 void NegativeTest3::deinit()
10767 {
10768 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
10769
10770 if (m_so_id != 0)
10771 {
10772 gl.deleteShader(m_so_id);
10773
10774 m_so_id = 0;
10775 }
10776 }
10777
10778 /** Verifies that broken shader (for user-specified shader stage) does not compile.
10779 *
10780 * @param shader_stage Shader stage to use for the test.
10781 **/
executeTest(const Utils::_shader_stage & shader_stage)10782 void NegativeTest3::executeTest(const Utils::_shader_stage &shader_stage)
10783 {
10784 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
10785
10786 /* Generate a new shader object */
10787 m_so_id = gl.createShader(Utils::getGLenumForShaderStage(shader_stage));
10788 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
10789
10790 /* Assign body to the shader */
10791 std::string body;
10792 const char *body_raw_ptr = DE_NULL;
10793
10794 switch (shader_stage)
10795 {
10796 case Utils::SHADER_STAGE_VERTEX:
10797 body = getVertexShaderBody();
10798 break;
10799 case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
10800 body = getTessellationControlShaderBody();
10801 break;
10802 case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
10803 body = getTessellationEvaluationShaderBody();
10804 break;
10805 case Utils::SHADER_STAGE_GEOMETRY:
10806 body = getGeometryShaderBody();
10807 break;
10808 case Utils::SHADER_STAGE_FRAGMENT:
10809 body = getFragmentShaderBody();
10810 break;
10811
10812 default:
10813 {
10814 TCU_FAIL("Unrecognized shader stage requested");
10815 }
10816 } /* switch (shader_stage) */
10817
10818 body_raw_ptr = body.c_str();
10819
10820 gl.shaderSource(m_so_id, 1 /* count */, &body_raw_ptr, DE_NULL /* length */);
10821 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
10822
10823 /* Try to compile the shader */
10824 glw::GLint compile_status = 0;
10825
10826 gl.compileShader(m_so_id);
10827 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
10828
10829 gl.getShaderiv(m_so_id, GL_COMPILE_STATUS, &compile_status);
10830 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
10831
10832 if (compile_status == GL_TRUE)
10833 {
10834 m_testCtx.getLog() << tcu::TestLog::Message
10835 << "The following shader was expected to fail to compile but was "
10836 "accepted by the compiler:\n"
10837 "\n"
10838 << body.c_str() << tcu::TestLog::EndMessage;
10839
10840 m_has_test_passed = false;
10841 }
10842
10843 /* Good to release the shader at this point */
10844 gl.deleteShader(m_so_id);
10845 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed.");
10846 }
10847
10848 /** Retrieves body of a broken fragment shader.
10849 *
10850 * @return Requested string.
10851 **/
getFragmentShaderBody() const10852 std::string NegativeTest3::getFragmentShaderBody() const
10853 {
10854 return "#version 400\n"
10855 "\n"
10856 "#extension GL_ARB_shader_subroutine : require\n"
10857 "\n"
10858 "subroutine void testSubroutineType(inout vec4 test);\n"
10859 "\n"
10860 "void testSubroutine1(inout vec4 test)\n"
10861 "{\n"
10862 " test += vec4(3, 4, 5, 6);\n"
10863 "}\n"
10864 "\n"
10865 "uniform testSubroutineType subroutineFunction;\n"
10866 "out vec4 result;\n"
10867 "\n"
10868 "void main()\n"
10869 "{\n"
10870 " vec4 test = vec4(2, 3, 4, 5);\n"
10871 "\n"
10872 " subroutineFunction(test);\n"
10873 "\n"
10874 " result = test;\n"
10875 "}\n";
10876 }
10877
10878 /** Retrieves body of a broken geometry shader.
10879 *
10880 * @return Requested string.
10881 **/
getGeometryShaderBody() const10882 std::string NegativeTest3::getGeometryShaderBody() const
10883 {
10884 return "#version 400\n"
10885 "\n"
10886 "#extension GL_ARB_shader_subroutine : require\n"
10887 "\n"
10888 "layout(points) in;\n"
10889 "layout(points, max_vertices = 1) out;\n"
10890 "\n"
10891 "subroutine void testSubroutineType(inout vec4 test);\n"
10892 "\n"
10893 "void testSubroutine1(inout vec4 test)\n"
10894 "{\n"
10895 " test += vec4(3, 4, 5, 6);\n"
10896 "}\n"
10897 "\n"
10898 "uniform testSubroutineType subroutineFunction;\n"
10899 "\n"
10900 "void main()\n"
10901 "{\n"
10902 " vec4 test = vec4(2, 3, 4, 5);\n"
10903 "\n"
10904 " subroutineFunction(test);\n"
10905 "\n"
10906 " gl_Position = test;\n"
10907 " EmitVertex();\n"
10908 "}\n";
10909 }
10910
10911 /** Retrieves body of a broken tessellation control shader.
10912 *
10913 * @return Requested string.
10914 **/
getTessellationControlShaderBody() const10915 std::string NegativeTest3::getTessellationControlShaderBody() const
10916 {
10917 return "#version 400\n"
10918 "\n"
10919 "#extension GL_ARB_shader_subroutine : require\n"
10920 "\n"
10921 "layout(vertices=4) out;\n"
10922 "\n"
10923 "subroutine void testSubroutineType(inout vec4 test);\n"
10924 "\n"
10925 "void testSubroutine1(inout vec4 test)\n"
10926 "{\n"
10927 " test += vec4(1, 2, 3, 4);\n"
10928 "}\n"
10929 "\n"
10930 "uniform testSubroutineType subroutineFunction;\n"
10931 "\n"
10932 "void main()\n"
10933 "{\n"
10934 " vec4 test = vec4(0, 1, 2, 3);\n"
10935 "\n"
10936 " subroutineFunction(test);\n"
10937 "\n"
10938 " gl_out[gl_InvocationID].gl_Position = test;\n"
10939 "}\n";
10940 }
10941
10942 /** Retrieves body of a broken tessellation evaluation shader.
10943 *
10944 * @return Requested string.
10945 **/
getTessellationEvaluationShaderBody() const10946 std::string NegativeTest3::getTessellationEvaluationShaderBody() const
10947 {
10948 return "#version 400\n"
10949 "\n"
10950 "#extension GL_ARB_shader_subroutine : require\n"
10951 "\n"
10952 "layout(quads) in;\n"
10953 "\n"
10954 "subroutine void testSubroutineType(inout vec4 test);\n"
10955 "\n"
10956 "void testSubroutine1(inout vec4 test)\n"
10957 "{\n"
10958 " test += vec4(2, 3, 4, 5);\n"
10959 "}\n"
10960 "\n"
10961 "uniform testSubroutineType subroutineFunction;\n"
10962 "\n"
10963 "void main()\n"
10964 "{\n"
10965 " vec4 test = vec4(1, 2, 3, 4);\n"
10966 "\n"
10967 " subroutineFunction(test);\n"
10968 "\n"
10969 " gl_Position = test;\n"
10970 "}\n";
10971 }
10972
10973 /** Retrieves body of a broken vertex shader.
10974 *
10975 * @return Requested string.
10976 **/
getVertexShaderBody() const10977 std::string NegativeTest3::getVertexShaderBody() const
10978 {
10979 return "#version 400\n"
10980 "\n"
10981 "#extension GL_ARB_shader_subroutine : require\n"
10982 "\n"
10983 "subroutine void testSubroutineType(inout vec4 test);\n"
10984 "\n"
10985 "void testSubroutine1(inout vec4 test)\n"
10986 "{\n"
10987 " test += vec4(0, 1, 2, 3);\n"
10988 "}\n"
10989 "\n"
10990 "uniform testSubroutineType subroutineFunction;\n"
10991 "\n"
10992 "void main()\n"
10993 "{\n"
10994 " subroutineFunction(gl_Position);\n"
10995 "}\n";
10996 }
10997
10998 /** Executes test iteration.
10999 *
11000 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
11001 */
iterate()11002 tcu::TestNode::IterateResult NegativeTest3::iterate()
11003 {
11004 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
11005 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
11006 {
11007 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
11008 }
11009
11010 /* Iterate over all shader stages */
11011 for (int shader_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
11012 shader_stage < static_cast<int>(Utils::SHADER_STAGE_COUNT); ++shader_stage)
11013 {
11014 executeTest(static_cast<Utils::_shader_stage>(shader_stage));
11015 } /* for (all shader stages) */
11016
11017 /* Done */
11018 if (m_has_test_passed)
11019 {
11020 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
11021 }
11022 else
11023 {
11024 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
11025 }
11026
11027 return STOP;
11028 }
11029
11030 /** Constructor.
11031 *
11032 * @param context Rendering context.
11033 *
11034 **/
NegativeTest4(deqp::Context & context)11035 NegativeTest4::NegativeTest4(deqp::Context &context)
11036 : TestCase(context, "subroutines_incompatible_with_subroutine_type",
11037 "Verifies that a compile-time error is generated when arguments and "
11038 "return type do not match beween the function and each associated "
11039 "subroutine type.")
11040 , m_has_test_passed(true)
11041 , m_so_id(0)
11042 {
11043 /* Left blank intentionally */
11044 }
11045
11046 /** Deinitializes GL objects that may have been created during test
11047 * execution.
11048 **/
deinit()11049 void NegativeTest4::deinit()
11050 {
11051 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
11052
11053 if (m_so_id != 0)
11054 {
11055 gl.deleteShader(m_so_id);
11056
11057 m_so_id = 0;
11058 }
11059 }
11060
11061 /** Retrieves body of a shader of user-specified type that should be used
11062 * for a single test iteration. The shader will define user-specified number
11063 * of subroutine types, with the last type either defining an additional argument
11064 * or using a different return type.
11065 * A subroutine (claimed compatible with *all* subroutine types) will also be
11066 * defined in the shader.
11067 *
11068 * @param shader_stage Shader stage to use for the query.
11069 * @param n_subroutine_types Overall number of subroutine types that will be
11070 * declared & used in the shader. Please see description
11071 * for more details.
11072 *
11073 * @return Requested string.
11074 **/
getShaderBody(const Utils::_shader_stage & shader_stage,const unsigned int & n_subroutine_types,const _test_case & test_case) const11075 std::string NegativeTest4::getShaderBody(const Utils::_shader_stage &shader_stage,
11076 const unsigned int &n_subroutine_types, const _test_case &test_case) const
11077 {
11078 std::stringstream result_sstream;
11079
11080 /* Form the pre-amble */
11081 result_sstream << "#version 400\n"
11082 "\n"
11083 "#extension GL_ARB_shader_subroutine : require\n"
11084 "\n";
11085
11086 /* Inject stage-specific code */
11087 switch (shader_stage)
11088 {
11089 case Utils::SHADER_STAGE_GEOMETRY:
11090 {
11091 result_sstream << "layout (points) in;\n"
11092 "layout (points, max_vertices = 1) out;\n"
11093 "\n";
11094
11095 break;
11096 }
11097
11098 case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
11099 {
11100 result_sstream << "layout (vertices = 4) out;\n"
11101 "\n";
11102
11103 break;
11104 }
11105
11106 case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
11107 {
11108 result_sstream << "layout (quads) in;\n"
11109 "\n";
11110
11111 break;
11112 }
11113
11114 default:
11115 break;
11116 } /* switch (shader_stage) */
11117
11118 /* Insert subroutine type declarations */
11119 for (unsigned int n_subroutine_type = 0; n_subroutine_type < n_subroutine_types - 1; ++n_subroutine_type)
11120 {
11121 result_sstream << "subroutine void subroutineType" << n_subroutine_type << "(inout vec3 argument);\n";
11122 } /* for (all subroutine types) */
11123
11124 switch (test_case)
11125 {
11126 case TEST_CASE_INCOMPATIBLE_ARGUMENT_LIST:
11127 {
11128 result_sstream << "subroutine void subroutineType" << (n_subroutine_types - 1)
11129 << "(inout vec3 argument, out vec4 argument2);\n";
11130
11131 break;
11132 }
11133
11134 case TEST_CASE_INCOMPATIBLE_RETURN_TYPE:
11135 {
11136 result_sstream << "subroutine int subroutineType" << (n_subroutine_types - 1) << "(inout vec3 argument);\n";
11137
11138 break;
11139 }
11140
11141 default:
11142 {
11143 TCU_FAIL("Unrecognized test case");
11144 }
11145 } /* switch (test_case) */
11146
11147 /* Insert subroutine declarations */
11148 result_sstream << "subroutine(";
11149
11150 for (unsigned int n_subroutine_type = 0; n_subroutine_type < n_subroutine_types; ++n_subroutine_type)
11151 {
11152 result_sstream << "subroutineType" << n_subroutine_type;
11153
11154 if (n_subroutine_type != (n_subroutine_types - 1))
11155 {
11156 result_sstream << ", ";
11157 }
11158 } /* for (all subroutine types) */
11159
11160 result_sstream << ") void function(inout vec3 argument)\n"
11161 "{\n"
11162 " argument = vec3(1, 2, 3);\n"
11163 "}\n"
11164 "\n";
11165
11166 /* Insert remaining required stage-specific bits */
11167 switch (shader_stage)
11168 {
11169 case Utils::SHADER_STAGE_FRAGMENT:
11170 {
11171 result_sstream << "out vec4 result;\n"
11172 "\n"
11173 "void main()\n"
11174 "{\n"
11175 " result = vec4(1, 2, 3, 4);\n"
11176 "}\n";
11177
11178 break;
11179 }
11180
11181 case Utils::SHADER_STAGE_GEOMETRY:
11182 {
11183 result_sstream << "void main()\n"
11184 "{\n"
11185 " gl_Position = vec4(1, 2, 3, 4);\n"
11186 " EmitVertex();\n"
11187 "}\n";
11188
11189 break;
11190 }
11191
11192 case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
11193 {
11194 result_sstream << "void main()\n"
11195 "{\n"
11196 " gl_TessLevelInner[0] = 1;\n"
11197 " gl_TessLevelInner[1] = 1;\n"
11198 " gl_TessLevelOuter[0] = 1;\n"
11199 " gl_TessLevelOuter[1] = 1;\n"
11200 " gl_TessLevelOuter[2] = 1;\n"
11201 " gl_TessLevelOuter[3] = 1;\n"
11202 " gl_out[gl_InvocationID].gl_Position = vec4(2, 3, 4, 5);\n"
11203 "}\n";
11204
11205 break;
11206 }
11207
11208 case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
11209 case Utils::SHADER_STAGE_VERTEX:
11210 {
11211 result_sstream << "void main()\n"
11212 "{\n"
11213 " gl_Position = vec4(1, 2, 3, 4);\n"
11214 "}\n";
11215
11216 break;
11217 }
11218
11219 default:
11220 {
11221 TCU_FAIL("Unrecognized shader stage");
11222 }
11223 } /* switch (shader_stage) */
11224
11225 return result_sstream.str();
11226 }
11227
11228 /** Executes test iteration.
11229 *
11230 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
11231 */
iterate()11232 tcu::TestNode::IterateResult NegativeTest4::iterate()
11233 {
11234 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
11235
11236 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
11237 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
11238 {
11239 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
11240 }
11241
11242 /* Iterate over all shader stages.. */
11243 for (int shader_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
11244 shader_stage != static_cast<int>(Utils::SHADER_STAGE_COUNT); ++shader_stage)
11245 {
11246 /* For each shader stage, we will be trying to compile a number of invalid shaders.
11247 * Each shader defines N different subroutine types. (N-1) of them are compatible
11248 * with a subroutine, but exactly 1 will be mismatched. The test passes if GLSL
11249 * compiler correctly detects that all shaders we will be trying to compile are
11250 * broken.
11251 */
11252 const glw::GLenum shader_type = Utils::getGLenumForShaderStage(static_cast<Utils::_shader_stage>(shader_stage));
11253
11254 for (unsigned int n_subroutine_types = 1; n_subroutine_types < 6; /* arbitrary number */
11255 ++n_subroutine_types)
11256 {
11257 for (int test_case = static_cast<int>(TEST_CASE_FIRST); test_case != static_cast<int>(TEST_CASE_COUNT);
11258 ++test_case)
11259 {
11260 std::string body;
11261 const char *body_raw_ptr = NULL;
11262 glw::GLint compile_status = GL_FALSE;
11263
11264 body = getShaderBody(static_cast<Utils::_shader_stage>(shader_stage), n_subroutine_types,
11265 static_cast<_test_case>(test_case));
11266 body_raw_ptr = body.c_str();
11267
11268 /* Try to compile the shader */
11269 m_so_id = gl.createShader(shader_type);
11270 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed");
11271
11272 gl.shaderSource(m_so_id, 1 /* count */, &body_raw_ptr, DE_NULL);
11273 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed");
11274
11275 gl.compileShader(m_so_id);
11276 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed");
11277
11278 gl.getShaderiv(m_so_id, GL_COMPILE_STATUS, &compile_status);
11279 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
11280
11281 if (compile_status == GL_TRUE)
11282 {
11283 m_testCtx.getLog() << tcu::TestLog::Message << "A malformed "
11284 << Utils::getShaderStageString(static_cast<Utils::_shader_stage>(shader_stage))
11285 << " compiled successfully "
11286 "("
11287 << n_subroutine_types
11288 << " subroutine types "
11289 "were defined)."
11290 << tcu::TestLog::EndMessage;
11291
11292 m_has_test_passed = false;
11293 }
11294
11295 /* Release the object */
11296 gl.deleteShader(m_so_id);
11297 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed.");
11298 } /* for (all test cases) */
11299 } /* for (a number of different subroutine type declarations) */
11300 } /* for (all shader stages) */
11301
11302 /* Done */
11303 if (m_has_test_passed)
11304 {
11305 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
11306 }
11307 else
11308 {
11309 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
11310 }
11311
11312 return STOP;
11313 }
11314
11315 /** Constructor.
11316 *
11317 * @param context Rendering context.
11318 *
11319 **/
NegativeTest5(deqp::Context & context)11320 NegativeTest5::NegativeTest5(deqp::Context &context)
11321 : TestCase(context, "subroutine_uniform_wo_matching_subroutines",
11322 "Verifies that a link- or compile-time error occurs when "
11323 "trying to link a program with no subroutine for subroutine "
11324 "uniform variable.")
11325 , m_fs_id(0)
11326 , m_gs_id(0)
11327 , m_has_test_passed(true)
11328 , m_po_id(0)
11329 , m_tc_id(0)
11330 , m_te_id(0)
11331 , m_vs_id(0)
11332 {
11333 /* Left blank intentionally */
11334 }
11335
11336 /** Deinitializes all GL objects that may have been created during test execution */
deinit()11337 void NegativeTest5::deinit()
11338 {
11339 deinitIteration();
11340 }
11341
11342 /** Deinitializes all GL objects that may have been created during a single test
11343 * iteration.
11344 ***/
deinitIteration()11345 void NegativeTest5::deinitIteration()
11346 {
11347 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
11348
11349 if (m_fs_id != 0)
11350 {
11351 gl.deleteShader(m_fs_id);
11352
11353 m_fs_id = 0;
11354 }
11355
11356 if (m_gs_id != 0)
11357 {
11358 gl.deleteShader(m_gs_id);
11359
11360 m_gs_id = 0;
11361 }
11362
11363 if (m_po_id != 0)
11364 {
11365 gl.deleteProgram(m_po_id);
11366
11367 m_po_id = 0;
11368 }
11369
11370 if (m_tc_id != 0)
11371 {
11372 gl.deleteShader(m_tc_id);
11373
11374 m_tc_id = 0;
11375 }
11376
11377 if (m_te_id != 0)
11378 {
11379 gl.deleteShader(m_te_id);
11380
11381 m_te_id = 0;
11382 }
11383
11384 if (m_vs_id != 0)
11385 {
11386 gl.deleteShader(m_vs_id);
11387
11388 m_vs_id = 0;
11389 }
11390 }
11391
11392 /** Executes a single test iteration.
11393 *
11394 * If the iteration fails, m_has_test_passed will be set to false.
11395 *
11396 * @param shader_stage Shader stage, for which a subroutine uniform should be
11397 * declared in the shader without a matching subroutine.
11398 **/
executeIteration(const Utils::_shader_stage & shader_stage)11399 void NegativeTest5::executeIteration(const Utils::_shader_stage &shader_stage)
11400 {
11401 std::string fs_body = getFragmentShaderBody(shader_stage == Utils::SHADER_STAGE_FRAGMENT);
11402 std::string gs_body = getGeometryShaderBody(shader_stage == Utils::SHADER_STAGE_GEOMETRY);
11403 std::string tc_body = getTessellationControlShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_CONTROL);
11404 std::string te_body =
11405 getTessellationEvaluationShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_EVALUATION);
11406 std::string vs_body = getVertexShaderBody(shader_stage == Utils::SHADER_STAGE_VERTEX);
11407
11408 if (Utils::buildProgram(m_context.getRenderContext().getFunctions(), vs_body, tc_body, te_body, gs_body, fs_body,
11409 DE_NULL, /* xfb_varyings */
11410 DE_NULL, /* n_xfb_varyings */
11411 &m_vs_id, &m_tc_id, &m_te_id, &m_gs_id, &m_fs_id, &m_po_id))
11412 {
11413 /* None of the test programs should ever build successfully */
11414 m_testCtx.getLog() << tcu::TestLog::Message
11415 << "A program object, consisting of the following shaders, has linked"
11416 " correctly. One of the shaders defines a subroutine uniform but does "
11417 "not implement any function that matches subroutine type of the uniform."
11418 " This should have resulted in a compilation/link-time error.\n"
11419 "\n"
11420 "Vertex shader:\n"
11421 "\n"
11422 << vs_body
11423 << "\n"
11424 "Tessellation control shader:\n"
11425 "\n"
11426 << tc_body
11427 << "\n"
11428 "Tessellation evaluation shader:\n"
11429 "\n"
11430 << te_body
11431 << "\n"
11432 "Geometry shader:\n"
11433 "\n"
11434 << gs_body
11435 << "\n"
11436 "Fragment shader:\n"
11437 "\n"
11438 << fs_body << tcu::TestLog::EndMessage;
11439
11440 m_has_test_passed = false;
11441 }
11442 }
11443
11444 /** Retrieves fragment shader body.
11445 *
11446 * @param include_invalid_subroutine_uniform_declaration true if the shader should declare
11447 * a subroutine uniform without
11448 * a matching subroutine, false otherwise.
11449 *
11450 * @return Requested string.
11451 **/
getFragmentShaderBody(bool include_invalid_subroutine_uniform_declaration) const11452 std::string NegativeTest5::getFragmentShaderBody(bool include_invalid_subroutine_uniform_declaration) const
11453 {
11454 std::stringstream result_sstream;
11455
11456 result_sstream << "#version 400\n"
11457 "\n"
11458 "#extension GL_ARB_shader_subroutine : require\n"
11459 "\n";
11460
11461 if (include_invalid_subroutine_uniform_declaration)
11462 {
11463 result_sstream << "subroutine void subroutineTestTypeFS(out vec4 test);\n"
11464 "\n"
11465 "subroutine uniform subroutineTestTypeFS test_subroutineFS;\n";
11466 }
11467
11468 result_sstream << "\n"
11469 "out vec4 result;\n"
11470 "\n"
11471 "void main()\n"
11472 "{\n";
11473
11474 if (include_invalid_subroutine_uniform_declaration)
11475 {
11476 result_sstream << " test_subroutineFS(result);\n";
11477 }
11478 else
11479 {
11480 result_sstream << " result = vec4(0, 1, 2, 3);\n";
11481 }
11482
11483 result_sstream << "}\n";
11484
11485 return result_sstream.str();
11486 }
11487
11488 /** Retrieves geometry shader body.
11489 *
11490 * @param include_invalid_subroutine_uniform_declaration true if the shader should declare
11491 * a subroutine uniform without
11492 * a matching subroutine, false otherwise.
11493 *
11494 * @return Requested string.
11495 **/
getGeometryShaderBody(bool include_invalid_subroutine_uniform_declaration) const11496 std::string NegativeTest5::getGeometryShaderBody(bool include_invalid_subroutine_uniform_declaration) const
11497 {
11498 std::stringstream result_sstream;
11499
11500 result_sstream << "#version 400\n"
11501 "\n"
11502 "#extension GL_ARB_shader_subroutine : require\n"
11503 "\n"
11504 "layout (points) in;\n"
11505 "layout (points, max_vertices = 1) out;\n"
11506 "\n";
11507
11508 if (include_invalid_subroutine_uniform_declaration)
11509 {
11510 result_sstream << "subroutine void subroutineTestTypeGS(out vec4 test);\n"
11511 "\n"
11512 "subroutine uniform subroutineTestTypeGS test_subroutineGS;\n";
11513 }
11514
11515 result_sstream << "\n"
11516 "void main()\n"
11517 "{\n";
11518
11519 if (include_invalid_subroutine_uniform_declaration)
11520 {
11521 result_sstream << " test_subroutineGS(gl_Position);\n";
11522 }
11523 else
11524 {
11525 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
11526 }
11527
11528 result_sstream << "EmitVertex();\n"
11529 "}\n";
11530
11531 return result_sstream.str();
11532 }
11533
11534 /** Retrieves tessellation control shader body.
11535 *
11536 * @param include_invalid_subroutine_uniform_declaration true if the shader should declare
11537 * a subroutine uniform without
11538 * a matching subroutine, false otherwise.
11539 *
11540 * @return Requested string.
11541 **/
getTessellationControlShaderBody(bool include_invalid_subroutine_uniform_declaration) const11542 std::string NegativeTest5::getTessellationControlShaderBody(bool include_invalid_subroutine_uniform_declaration) const
11543 {
11544 std::stringstream result_sstream;
11545
11546 result_sstream << "#version 400\n"
11547 "\n"
11548 "#extension GL_ARB_shader_subroutine : require\n"
11549 "\n"
11550 "layout (vertices = 4) out;\n"
11551 "\n";
11552
11553 if (include_invalid_subroutine_uniform_declaration)
11554 {
11555 result_sstream << "subroutine void subroutineTestTypeTC(out vec4 test);\n"
11556 "\n"
11557 "subroutine uniform subroutineTestTypeTC test_subroutineTC;\n";
11558 }
11559
11560 result_sstream << "\n"
11561 "void main()\n"
11562 "{\n";
11563
11564 if (include_invalid_subroutine_uniform_declaration)
11565 {
11566 result_sstream << " test_subroutineTC(gl_out[gl_InvocationID].gl_Position);\n";
11567 }
11568 else
11569 {
11570 result_sstream << " gl_out[gl_InvocationID].gl_Position = vec4(0, 1, 2, 3);\n";
11571 }
11572
11573 result_sstream << "}\n";
11574
11575 return result_sstream.str();
11576 }
11577
11578 /** Retrieves tessellation evaluation body.
11579 *
11580 * @param include_invalid_subroutine_uniform_declaration true if the shader should declare
11581 * a subroutine uniform without
11582 * a matching subroutine, false otherwise.
11583 *
11584 * @return Requested string.
11585 **/
getTessellationEvaluationShaderBody(bool include_invalid_subroutine_uniform_declaration) const11586 std::string NegativeTest5::getTessellationEvaluationShaderBody(
11587 bool include_invalid_subroutine_uniform_declaration) const
11588 {
11589 std::stringstream result_sstream;
11590
11591 result_sstream << "#version 400\n"
11592 "\n"
11593 "#extension GL_ARB_shader_subroutine : require\n"
11594 "\n"
11595 "layout (quads) in;\n"
11596 "\n";
11597
11598 if (include_invalid_subroutine_uniform_declaration)
11599 {
11600 result_sstream << "subroutine void subroutineTestTypeTE(out vec4 test);\n"
11601 "\n"
11602 "subroutine uniform subroutineTestTypeTE test_subroutineTE;\n";
11603 }
11604
11605 result_sstream << "\n"
11606 "void main()\n"
11607 "{\n";
11608
11609 if (include_invalid_subroutine_uniform_declaration)
11610 {
11611 result_sstream << " test_subroutineTE(gl_Position);\n";
11612 }
11613 else
11614 {
11615 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
11616 }
11617
11618 result_sstream << "}\n";
11619
11620 return result_sstream.str();
11621 }
11622
11623 /** Retrieves vertex shader body.
11624 *
11625 * @param include_invalid_subroutine_uniform_declaration true if the shader should declare
11626 * a subroutine uniform without
11627 * a matching subroutine, false otherwise.
11628 *
11629 * @return Requested string.
11630 **/
getVertexShaderBody(bool include_invalid_subroutine_uniform_declaration) const11631 std::string NegativeTest5::getVertexShaderBody(bool include_invalid_subroutine_uniform_declaration) const
11632 {
11633 std::stringstream result_sstream;
11634
11635 result_sstream << "#version 400\n"
11636 "\n"
11637 "#extension GL_ARB_shader_subroutine : require\n"
11638 "\n";
11639
11640 if (include_invalid_subroutine_uniform_declaration)
11641 {
11642 result_sstream << "subroutine void subroutineTestTypeVS(out vec4 test);\n"
11643 "\n"
11644 "subroutine uniform subroutineTestTypeVS test_subroutineVS;\n";
11645 }
11646
11647 result_sstream << "\n"
11648 "void main()\n"
11649 "{\n";
11650
11651 if (include_invalid_subroutine_uniform_declaration)
11652 {
11653 result_sstream << " test_subroutineVS(gl_Position);\n";
11654 }
11655 else
11656 {
11657 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
11658 }
11659
11660 result_sstream << "}\n";
11661
11662 return result_sstream.str();
11663 }
11664
11665 /** Executes test iteration.
11666 *
11667 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
11668 */
iterate()11669 tcu::TestNode::IterateResult NegativeTest5::iterate()
11670 {
11671 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
11672 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
11673 {
11674 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
11675 }
11676
11677 /* Iterate over all shader stages. Iteration-specific shader stage defines a subroutine type &
11678 * a corresponding subroutine uniform, for which no compatible subroutines are available. All
11679 * other shader stages are defined correctly.
11680 */
11681 for (int shader_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
11682 shader_stage < static_cast<int>(Utils::SHADER_STAGE_COUNT); ++shader_stage)
11683 {
11684 executeIteration(static_cast<Utils::_shader_stage>(shader_stage));
11685 deinitIteration();
11686 } /* for (all shader stages) */
11687
11688 /* All done */
11689 if (m_has_test_passed)
11690 {
11691 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
11692 }
11693 else
11694 {
11695 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
11696 }
11697
11698 return STOP;
11699 }
11700
11701 /** Constructor.
11702 *
11703 * @param context Rendering context.
11704 *
11705 **/
NegativeTest6(deqp::Context & context)11706 NegativeTest6::NegativeTest6(deqp::Context &context)
11707 : TestCase(context, "two_duplicate_functions_one_being_a_subroutine",
11708 "Verifies that a link- or compile-time error occurs if any shader in "
11709 "a program object includes two functions with the same name and one "
11710 "of which is associated with a subroutine type.")
11711 , m_fs_id(0)
11712 , m_gs_id(0)
11713 , m_has_test_passed(true)
11714 , m_po_id(0)
11715 , m_tc_id(0)
11716 , m_te_id(0)
11717 , m_vs_id(0)
11718 {
11719 /* Left blank intentionally */
11720 }
11721
11722 /** Deinitializes all GL objects that may have been created during test execution */
deinit()11723 void NegativeTest6::deinit()
11724 {
11725 deinitIteration();
11726 }
11727
11728 /** Deinitializes all GL objects that may have been created during a single test
11729 * iteration.
11730 ***/
deinitIteration()11731 void NegativeTest6::deinitIteration()
11732 {
11733 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
11734
11735 if (m_fs_id != 0)
11736 {
11737 gl.deleteShader(m_fs_id);
11738
11739 m_fs_id = 0;
11740 }
11741
11742 if (m_gs_id != 0)
11743 {
11744 gl.deleteShader(m_gs_id);
11745
11746 m_gs_id = 0;
11747 }
11748
11749 if (m_po_id != 0)
11750 {
11751 gl.deleteProgram(m_po_id);
11752
11753 m_po_id = 0;
11754 }
11755
11756 if (m_tc_id != 0)
11757 {
11758 gl.deleteShader(m_tc_id);
11759
11760 m_tc_id = 0;
11761 }
11762
11763 if (m_te_id != 0)
11764 {
11765 gl.deleteShader(m_te_id);
11766
11767 m_te_id = 0;
11768 }
11769
11770 if (m_vs_id != 0)
11771 {
11772 gl.deleteShader(m_vs_id);
11773
11774 m_vs_id = 0;
11775 }
11776 }
11777
11778 /** Executes a single test iteration.
11779 *
11780 * If the iteration fails, m_has_test_passed will be set to false.
11781 *
11782 * @param shader_stage Shader stage, for which two duplicate functions
11783 * (one additionally marked as subroutine) should
11784 * be defined.
11785 **/
executeIteration(const Utils::_shader_stage & shader_stage)11786 void NegativeTest6::executeIteration(const Utils::_shader_stage &shader_stage)
11787 {
11788 std::string fs_body = getFragmentShaderBody(shader_stage == Utils::SHADER_STAGE_FRAGMENT);
11789 std::string gs_body = getGeometryShaderBody(shader_stage == Utils::SHADER_STAGE_GEOMETRY);
11790 std::string tc_body = getTessellationControlShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_CONTROL);
11791 std::string te_body =
11792 getTessellationEvaluationShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_EVALUATION);
11793 std::string vs_body = getVertexShaderBody(shader_stage == Utils::SHADER_STAGE_VERTEX);
11794
11795 if (Utils::buildProgram(m_context.getRenderContext().getFunctions(), vs_body, tc_body, te_body, gs_body, fs_body,
11796 DE_NULL, /* xfb_varyings */
11797 DE_NULL, /* n_xfb_varyings */
11798 &m_vs_id, &m_tc_id, &m_te_id, &m_gs_id, &m_fs_id, &m_po_id))
11799 {
11800 /* None of the test programs should ever build successfully */
11801 m_testCtx.getLog() << tcu::TestLog::Message
11802 << "A program object, consisting of the following shaders, has linked"
11803 " correctly. This is invalid, because one of the shaders defines two"
11804 " functions with the same name, with an exception that one of the"
11805 " functions is marked as a subroutine.\n"
11806 "\n"
11807 "Vertex shader:\n"
11808 "\n"
11809 << vs_body
11810 << "\n"
11811 "Tessellation control shader:\n"
11812 "\n"
11813 << tc_body
11814 << "\n"
11815 "Tessellation evaluation shader:\n"
11816 "\n"
11817 << te_body
11818 << "\n"
11819 "Geometry shader:\n"
11820 "\n"
11821 << gs_body
11822 << "\n"
11823 "Fragment shader:\n"
11824 "\n"
11825 << fs_body << tcu::TestLog::EndMessage;
11826
11827 m_has_test_passed = false;
11828 }
11829 }
11830
11831 /** Retrieves fragment shader body.
11832 *
11833 * @param include_invalid_declaration true if the shader should include duplicate function
11834 * declaration.
11835 *
11836 * @return Requested string.
11837 **/
getFragmentShaderBody(bool include_invalid_declaration) const11838 std::string NegativeTest6::getFragmentShaderBody(bool include_invalid_declaration) const
11839 {
11840 std::stringstream result_sstream;
11841
11842 result_sstream << "#version 400\n"
11843 "\n"
11844 "#extension GL_ARB_shader_subroutine : require\n"
11845 "\n";
11846
11847 if (include_invalid_declaration)
11848 {
11849 result_sstream << "subroutine void subroutineTestTypeFS(out vec4 test);\n"
11850 "\n"
11851 "subroutine(subroutineTestTypeFS) void test_impl1(out vec4 test)\n"
11852 "{\n"
11853 " test = vec4(1, 2, 3, 4);\n"
11854 "}\n"
11855 "\n"
11856 "void test_impl1(out vec4 test)\n"
11857 "{\n"
11858 " test = vec4(2, 3, 4, 5);\n"
11859 "}\n"
11860 "\n"
11861 "subroutine uniform subroutineTestTypeFS test_subroutineFS;\n";
11862 }
11863
11864 result_sstream << "\n"
11865 "out vec4 result;\n"
11866 "\n"
11867 "void main()\n"
11868 "{\n";
11869
11870 if (include_invalid_declaration)
11871 {
11872 result_sstream << " test_subroutineFS(result);\n";
11873 }
11874 else
11875 {
11876 result_sstream << " result = vec4(0, 1, 2, 3);\n";
11877 }
11878
11879 result_sstream << "}\n";
11880
11881 return result_sstream.str();
11882 }
11883
11884 /** Retrieves geometry shader body.
11885 *
11886 * @param include_invalid_declaration true if the shader should include duplicate function
11887 * declaration.
11888 *
11889 * @return Requested string.
11890 **/
getGeometryShaderBody(bool include_invalid_declaration) const11891 std::string NegativeTest6::getGeometryShaderBody(bool include_invalid_declaration) const
11892 {
11893 std::stringstream result_sstream;
11894
11895 result_sstream << "#version 400\n"
11896 "\n"
11897 "#extension GL_ARB_shader_subroutine : require\n"
11898 "\n"
11899 "layout (points) in;\n"
11900 "layout (points, max_vertices = 1) out;\n"
11901 "\n";
11902
11903 if (include_invalid_declaration)
11904 {
11905 result_sstream << "subroutine void subroutineTestTypeGS(out vec4 test);\n"
11906 "\n"
11907 "subroutine(subroutineTestTypeGS) void test_impl1(out vec4 test)\n"
11908 "{\n"
11909 " test = vec4(1, 2, 3, 4);\n"
11910 "}\n"
11911 "\n"
11912 "void test_impl1(out vec4 test)\n"
11913 "{\n"
11914 " test = vec4(2, 3, 4, 5);\n"
11915 "}\n"
11916 "\n"
11917 "subroutine uniform subroutineTestTypeGS test_subroutineGS;\n";
11918 }
11919
11920 result_sstream << "\n"
11921 "void main()\n"
11922 "{\n";
11923
11924 if (include_invalid_declaration)
11925 {
11926 result_sstream << " test_subroutineGS(gl_Position);\n";
11927 }
11928 else
11929 {
11930 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
11931 }
11932
11933 result_sstream << "EmitVertex();\n"
11934 "}\n";
11935
11936 return result_sstream.str();
11937 }
11938
11939 /** Retrieves tessellation control shader body.
11940 *
11941 * @param include_invalid_declaration true if the shader should include duplicate function
11942 * declaration.
11943 *
11944 * @return Requested string.
11945 **/
getTessellationControlShaderBody(bool include_invalid_declaration) const11946 std::string NegativeTest6::getTessellationControlShaderBody(bool include_invalid_declaration) const
11947 {
11948 std::stringstream result_sstream;
11949
11950 result_sstream << "#version 400\n"
11951 "\n"
11952 "#extension GL_ARB_shader_subroutine : require\n"
11953 "\n"
11954 "layout (vertices = 4) out;\n"
11955 "\n";
11956
11957 if (include_invalid_declaration)
11958 {
11959 result_sstream << "subroutine void subroutineTestTypeTC(out vec4 test);\n"
11960 "\n"
11961 "subroutine(subroutineTestTypeTC) void test_impl1(out vec4 test)\n"
11962 "{\n"
11963 " test = vec4(1, 2, 3, 4);\n"
11964 "}\n"
11965 "\n"
11966 "void test_impl1(out vec4 test)\n"
11967 "{\n"
11968 " test = vec4(2, 3, 4, 5);\n"
11969 "}\n"
11970 "\n"
11971 "subroutine uniform subroutineTestTypeTC test_subroutineTC;\n";
11972 }
11973
11974 result_sstream << "\n"
11975 "void main()\n"
11976 "{\n";
11977
11978 if (include_invalid_declaration)
11979 {
11980 result_sstream << " test_subroutineTC(gl_out[gl_InvocationID].gl_Position);\n";
11981 }
11982 else
11983 {
11984 result_sstream << " gl_out[gl_InvocationID].gl_Position = vec4(0, 1, 2, 3);\n";
11985 }
11986
11987 result_sstream << "}\n";
11988
11989 return result_sstream.str();
11990 }
11991
11992 /** Retrieves tessellation evaluation body.
11993 *
11994 * @param include_invalid_declaration true if the shader should include duplicate function
11995 * declaration.
11996 *
11997 * @return Requested string.
11998 **/
getTessellationEvaluationShaderBody(bool include_invalid_declaration) const11999 std::string NegativeTest6::getTessellationEvaluationShaderBody(bool include_invalid_declaration) const
12000 {
12001 std::stringstream result_sstream;
12002
12003 result_sstream << "#version 400\n"
12004 "\n"
12005 "#extension GL_ARB_shader_subroutine : require\n"
12006 "\n"
12007 "layout (quads) in;\n"
12008 "\n";
12009
12010 if (include_invalid_declaration)
12011 {
12012 result_sstream << "subroutine void subroutineTestTypeTE(out vec4 test);\n"
12013 "\n"
12014 "subroutine(subroutineTestTypeTE) void test_impl1(out vec4 test)\n"
12015 "{\n"
12016 " test = vec4(1, 2, 3, 4);\n"
12017 "}\n"
12018 "\n"
12019 "void test_impl1(out vec4 test)\n"
12020 "{\n"
12021 " test = vec4(2, 3, 4, 5);\n"
12022 "}\n"
12023 "\n"
12024 "subroutine uniform subroutineTestTypeTE test_subroutineTE;\n";
12025 }
12026
12027 result_sstream << "\n"
12028 "void main()\n"
12029 "{\n";
12030
12031 if (include_invalid_declaration)
12032 {
12033 result_sstream << " test_subroutineTE(gl_Position);\n";
12034 }
12035 else
12036 {
12037 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
12038 }
12039
12040 result_sstream << "}\n";
12041
12042 return result_sstream.str();
12043 }
12044
12045 /** Retrieves vertex shader body.
12046 *
12047 * @param include_invalid_declaration true if the shader should include duplicate function
12048 * declaration.
12049 *
12050 * @return Requested string.
12051 **/
getVertexShaderBody(bool include_invalid_declaration) const12052 std::string NegativeTest6::getVertexShaderBody(bool include_invalid_declaration) const
12053 {
12054 std::stringstream result_sstream;
12055
12056 result_sstream << "#version 400\n"
12057 "\n"
12058 "#extension GL_ARB_shader_subroutine : require\n"
12059 "\n";
12060
12061 if (include_invalid_declaration)
12062 {
12063 result_sstream << "subroutine void subroutineTestTypeVS(out vec4 test);\n"
12064 "\n"
12065 "subroutine(subroutineTestTypeVS) void test_impl1(out vec4 test)\n"
12066 "{\n"
12067 " test = vec4(1, 2, 3, 4);\n"
12068 "}\n"
12069 "\n"
12070 "void test_impl1(out vec4 test)\n"
12071 "{\n"
12072 " test = vec4(2, 3, 4, 5);\n"
12073 "}\n"
12074 "\n"
12075 "subroutine uniform subroutineTestTypeVS test_subroutineVS;\n";
12076 }
12077
12078 result_sstream << "\n"
12079 "void main()\n"
12080 "{\n";
12081
12082 if (include_invalid_declaration)
12083 {
12084 result_sstream << " test_subroutineVS(gl_Position);\n";
12085 }
12086 else
12087 {
12088 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
12089 }
12090
12091 result_sstream << "}\n";
12092
12093 return result_sstream.str();
12094 }
12095
12096 /** Executes test iteration.
12097 *
12098 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
12099 */
iterate()12100 tcu::TestNode::IterateResult NegativeTest6::iterate()
12101 {
12102 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
12103 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
12104 {
12105 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
12106 }
12107
12108 /* Iterate over all shader stages. In each iteration, we will inject invalid
12109 * duplicate function declarations to iteration-specific shader stage. All other
12110 * shader stages will be assigned valid bodies. Test should fail if the program
12111 * links successfully.
12112 */
12113 for (int shader_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
12114 shader_stage < static_cast<int>(Utils::SHADER_STAGE_COUNT); ++shader_stage)
12115 {
12116 executeIteration(static_cast<Utils::_shader_stage>(shader_stage));
12117 deinitIteration();
12118 } /* for (all shader stages) */
12119
12120 /* All done */
12121 if (m_has_test_passed)
12122 {
12123 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
12124 }
12125 else
12126 {
12127 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
12128 }
12129
12130 return STOP;
12131 }
12132
12133 /** Constructor
12134 *
12135 * @param context CTS context
12136 **/
NegativeTest7(deqp::Context & context)12137 NegativeTest7::NegativeTest7(deqp::Context &context)
12138 : TestCase(context, "recursion", "Verify that it is not possible to build program with recursing subroutines")
12139 , m_program_id(0)
12140 , m_vertex_shader_id(0)
12141 {
12142 /* Nothing to be done here */
12143 }
12144
12145 /** Deinitializes all GL objects that may have been created during test execution
12146 *
12147 **/
deinit()12148 void NegativeTest7::deinit()
12149 {
12150 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
12151
12152 if (m_program_id != 0)
12153 {
12154 gl.deleteProgram(m_program_id);
12155
12156 m_program_id = 0;
12157 }
12158
12159 if (m_vertex_shader_id != 0)
12160 {
12161 gl.deleteShader(m_vertex_shader_id);
12162
12163 m_vertex_shader_id = 0;
12164 }
12165 }
12166
12167 /** Executes test iteration.
12168 *
12169 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
12170 **/
iterate()12171 tcu::TestNode::IterateResult NegativeTest7::iterate()
12172 {
12173 static const GLchar *vertex_shader_with_static_recursion =
12174 "#version 400\n"
12175 "\n"
12176 "#extension GL_ARB_shader_subroutine : require\n"
12177 "\n"
12178 "precision highp float;\n"
12179 "\n"
12180 "subroutine vec4 routine_type(in vec4 data, in uint control);\n"
12181 "\n"
12182 "subroutine (routine_type) vec4 power_routine(in vec4 data, in uint control)\n"
12183 "{\n"
12184 " if (0 != control)\n"
12185 " {\n"
12186 " return data * power_routine(data, control - 1);\n"
12187 " }\n"
12188 " else\n"
12189 " {\n"
12190 " return vec4(1, 1, 1, 1);\n"
12191 " }\n"
12192 "}\n"
12193 "\n"
12194 "subroutine (routine_type) vec4 select_routine(in vec4 data, in uint control)\n"
12195 "{\n"
12196 " if (0 == control)\n"
12197 " {\n"
12198 " return data.rrrr;\n"
12199 " }\n"
12200 " else if (1 == control)\n"
12201 " {\n"
12202 " return data.gggg;\n"
12203 " }\n"
12204 " else if (2 == control)\n"
12205 " {\n"
12206 " return data.bbbb;\n"
12207 " }\n"
12208 " else\n"
12209 " {\n"
12210 " return data.aaaa;\n"
12211 " }\n"
12212 "}\n"
12213 "\n"
12214 "subroutine uniform routine_type routine;\n"
12215 "\n"
12216 "uniform vec4 uni_value;\n"
12217 "uniform uint uni_control;\n"
12218 "\n"
12219 "out vec4 out_result;\n"
12220 "\n"
12221 "void main()\n"
12222 "{\n"
12223 " out_result = routine(uni_value, uni_control);\n"
12224 "}\n"
12225 "\n";
12226
12227 static const GLchar *vertex_shader_with_dynamic_recursion =
12228 "#version 400\n"
12229 "\n"
12230 "#extension GL_ARB_shader_subroutine : require\n"
12231 "\n"
12232 "precision highp float;\n"
12233 "\n"
12234 "subroutine vec4 routine_type(in vec4 data);\n"
12235 "\n"
12236 "subroutine uniform routine_type routine;\n"
12237 "\n"
12238 "subroutine (routine_type) vec4 div_by_2(in vec4 data)\n"
12239 "{\n"
12240 " return data / 2;\n"
12241 "}\n"
12242 "\n"
12243 "subroutine (routine_type) vec4 div_routine_result_by_2(in vec4 data)\n"
12244 "{\n"
12245 " return routine(data) / 2;\n"
12246 "}\n"
12247 "\n"
12248 "uniform vec4 uni_value;\n"
12249 "\n"
12250 "out vec4 out_result;\n"
12251 "\n"
12252 "void main()\n"
12253 "{\n"
12254 " out_result = routine(uni_value);\n"
12255 "}\n"
12256 "\n";
12257
12258 static const GLchar *vertex_shader_with_subroutine_function_recursion =
12259 "#version 400\n"
12260 "\n"
12261 "#extension GL_ARB_shader_subroutine : require\n"
12262 "\n"
12263 "precision highp float;\n"
12264 "\n"
12265 "subroutine vec4 routine_type(in vec4 data);\n"
12266 "\n"
12267 "subroutine uniform routine_type routine;\n"
12268 "\n"
12269 "vec4 function(in vec4 data)\n"
12270 "{\n"
12271 " return routine(data) + vec4(0.5, 0.5, 0.5, 0.5);\n"
12272 "}\n"
12273 "\n"
12274 "subroutine (routine_type) vec4 routine_a(in vec4 data)\n"
12275 "{\n"
12276 " return function(data) / 2;\n"
12277 "}\n"
12278 "\n"
12279 "subroutine (routine_type) vec4 routine_b(in vec4 data)\n"
12280 "{\n"
12281 " return routine_a(data) * 2;\n"
12282 "}\n"
12283 "\n"
12284 "uniform vec4 uni_value;\n"
12285 "\n"
12286 "out vec4 out_result;\n"
12287 "\n"
12288 "void main()\n"
12289 "{\n"
12290 " out_result = routine(uni_value);\n"
12291 "}\n"
12292 "\n";
12293
12294 bool result = true;
12295
12296 if (false == test(vertex_shader_with_subroutine_function_recursion, "routine_a"))
12297 {
12298 result = false;
12299 }
12300
12301 if (false == test(vertex_shader_with_dynamic_recursion, "div_routine_result_by_2"))
12302 {
12303 result = false;
12304 }
12305
12306 if (false == test(vertex_shader_with_static_recursion, "power_routine"))
12307 {
12308 result = false;
12309 }
12310
12311 /* Set result */
12312 if (true == result)
12313 {
12314 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
12315 }
12316 else
12317 {
12318 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
12319 }
12320
12321 /* Done */
12322 return tcu::TestNode::STOP;
12323 }
12324
12325 /** Try to build program from vertex shader code.
12326 *
12327 * @param vertex_shader_code Source code of vertex shader
12328 * @param name_of_recursive_routine Name of subroutine that should cause link failure due to recursion
12329 *
12330 * @return true build process failed, false otherwise
12331 **/
test(const GLchar * vertex_shader_code,const GLchar * name_of_recursive_routine)12332 bool NegativeTest7::test(const GLchar *vertex_shader_code, const GLchar *name_of_recursive_routine)
12333 {
12334 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
12335 bool result = true;
12336 static const GLchar *varying_name = "out_result";
12337
12338 /* Try to build program */
12339 if (true == Utils::buildProgram(gl, vertex_shader_code, "", "", "", "", &varying_name /* varying_names */,
12340 1 /* n_varyings */, &m_vertex_shader_id, 0, 0, 0, 0, &m_program_id))
12341 {
12342 /* Success is considered an error */
12343
12344 Utils::program program(m_context);
12345 GLuint index = 0;
12346
12347 program.build(0, 0, 0, 0, 0, vertex_shader_code, 0, 0);
12348
12349 /* Verify that recursive subroutine is active */
12350 try
12351 {
12352 index = program.getSubroutineIndex(name_of_recursive_routine, GL_VERTEX_SHADER);
12353 }
12354 catch (const std::exception &exc)
12355 {
12356 /* Something wrong with shader or compilation */
12357 m_context.getTestContext().getLog()
12358 << tcu::TestLog::Message << "It is expected that subroutine: \n"
12359 << name_of_recursive_routine
12360 << " is considered active. This subroutine is potentially recursive and should cause link failure."
12361 << tcu::TestLog::EndMessage;
12362
12363 throw exc;
12364 }
12365
12366 /* Subsoutine is active, however linking should fail */
12367 m_context.getTestContext().getLog()
12368 << tcu::TestLog::Message << "Error. Program with potentially recursive subroutine, "
12369 << name_of_recursive_routine << ", which is active, index: " << index << ", has been built successfully.\n"
12370 << vertex_shader_code << tcu::TestLog::EndMessage;
12371
12372 result = false;
12373 }
12374
12375 /* Delete program and shader */
12376 deinit();
12377
12378 /* Done */
12379 return result;
12380 }
12381
12382 /** Constructor.
12383 *
12384 * @param context Rendering context.
12385 *
12386 **/
NegativeTest8(deqp::Context & context)12387 NegativeTest8::NegativeTest8(deqp::Context &context)
12388 : TestCase(context, "subroutine_wo_body",
12389 "Verifies that a compile- or link-time error occurs if a function "
12390 "declared as a subroutine does not include a body.")
12391 , m_fs_id(0)
12392 , m_gs_id(0)
12393 , m_has_test_passed(true)
12394 , m_po_id(0)
12395 , m_tc_id(0)
12396 , m_te_id(0)
12397 , m_vs_id(0)
12398 {
12399 /* Left blank intentionally */
12400 }
12401
12402 /** Deinitializes all GL objects that may have been created during test execution */
deinit()12403 void NegativeTest8::deinit()
12404 {
12405 deinitIteration();
12406 }
12407
12408 /** Deinitializes all GL objects that may have been created during a single test
12409 * iteration.
12410 ***/
deinitIteration()12411 void NegativeTest8::deinitIteration()
12412 {
12413 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
12414
12415 if (m_fs_id != 0)
12416 {
12417 gl.deleteShader(m_fs_id);
12418
12419 m_fs_id = 0;
12420 }
12421
12422 if (m_gs_id != 0)
12423 {
12424 gl.deleteShader(m_gs_id);
12425
12426 m_gs_id = 0;
12427 }
12428
12429 if (m_po_id != 0)
12430 {
12431 gl.deleteProgram(m_po_id);
12432
12433 m_po_id = 0;
12434 }
12435
12436 if (m_tc_id != 0)
12437 {
12438 gl.deleteShader(m_tc_id);
12439
12440 m_tc_id = 0;
12441 }
12442
12443 if (m_te_id != 0)
12444 {
12445 gl.deleteShader(m_te_id);
12446
12447 m_te_id = 0;
12448 }
12449
12450 if (m_vs_id != 0)
12451 {
12452 gl.deleteShader(m_vs_id);
12453
12454 m_vs_id = 0;
12455 }
12456 }
12457
12458 /** Executes a single test iteration.
12459 *
12460 * If the iteration fails, m_has_test_passed will be set to false.
12461 *
12462 * @param shader_stage Shader stage, for which two duplicate functions
12463 * (one additionally marked as subroutine) should
12464 * be defined.
12465 **/
executeIteration(const Utils::_shader_stage & shader_stage)12466 void NegativeTest8::executeIteration(const Utils::_shader_stage &shader_stage)
12467 {
12468 std::string fs_body = getFragmentShaderBody(shader_stage == Utils::SHADER_STAGE_FRAGMENT);
12469 std::string gs_body = getGeometryShaderBody(shader_stage == Utils::SHADER_STAGE_GEOMETRY);
12470 std::string tc_body = getTessellationControlShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_CONTROL);
12471 std::string te_body =
12472 getTessellationEvaluationShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_EVALUATION);
12473 std::string vs_body = getVertexShaderBody(shader_stage == Utils::SHADER_STAGE_VERTEX);
12474
12475 if (Utils::buildProgram(m_context.getRenderContext().getFunctions(), vs_body, tc_body, te_body, gs_body, fs_body,
12476 DE_NULL, /* xfb_varyings */
12477 DE_NULL, /* n_xfb_varyings */
12478 &m_vs_id, &m_tc_id, &m_te_id, &m_gs_id, &m_fs_id, &m_po_id))
12479 {
12480 /* None of the test programs should ever build successfully */
12481 m_testCtx.getLog() << tcu::TestLog::Message
12482 << "A program object consisting of FS+GS+TC+TE+VS stages has linked successfully, "
12483 "even though one of the shaders only defines a subroutine that lacks any body."
12484 "\n"
12485 "Vertex shader:\n"
12486 "\n"
12487 << vs_body
12488 << "\n"
12489 "Tessellation control shader:\n"
12490 "\n"
12491 << tc_body
12492 << "\n"
12493 "Tessellation evaluation shader:\n"
12494 "\n"
12495 << te_body
12496 << "\n"
12497 "Geometry shader:\n"
12498 "\n"
12499 << gs_body
12500 << "\n"
12501 "Fragment shader:\n"
12502 "\n"
12503 << fs_body << tcu::TestLog::EndMessage;
12504
12505 m_has_test_passed = false;
12506 }
12507 }
12508
12509 /** Retrieves fragment shader body.
12510 *
12511 * @param include_invalid_declaration true if a subroutine prototype should be included in
12512 * the shader, false to skip it.
12513 *
12514 * @return Requested string.
12515 **/
getFragmentShaderBody(bool include_invalid_declaration) const12516 std::string NegativeTest8::getFragmentShaderBody(bool include_invalid_declaration) const
12517 {
12518 std::stringstream result_sstream;
12519
12520 result_sstream << "#version 400\n"
12521 "\n"
12522 "#extension GL_ARB_shader_subroutine : require\n"
12523 "\n";
12524
12525 if (include_invalid_declaration)
12526 {
12527 result_sstream << "subroutine void subroutineTestTypeFS(out vec4 test);\n"
12528 "\n"
12529 "subroutine(subroutineTestTypeFS) void test_impl1(out vec4 test);\n"
12530 "\n"
12531 "subroutine uniform subroutineTestTypeFS test_subroutineFS;\n";
12532 }
12533
12534 result_sstream << "\n"
12535 "out vec4 result;\n"
12536 "\n"
12537 "void main()\n"
12538 "{\n";
12539
12540 if (include_invalid_declaration)
12541 {
12542 result_sstream << " test_subroutineFS(result);\n";
12543 }
12544 else
12545 {
12546 result_sstream << " result = vec4(0, 1, 2, 3);\n";
12547 }
12548
12549 result_sstream << "}\n";
12550
12551 return result_sstream.str();
12552 }
12553
12554 /** Retrieves geometry shader body.
12555 *
12556 * @param include_invalid_declaration true if a subroutine prototype should be included in
12557 * the shader, false to skip it.
12558 *
12559 * @return Requested string.
12560 **/
getGeometryShaderBody(bool include_invalid_declaration) const12561 std::string NegativeTest8::getGeometryShaderBody(bool include_invalid_declaration) const
12562 {
12563 std::stringstream result_sstream;
12564
12565 result_sstream << "#version 400\n"
12566 "\n"
12567 "#extension GL_ARB_shader_subroutine : require\n"
12568 "\n"
12569 "layout (points) in;\n"
12570 "layout (points, max_vertices = 1) out;\n"
12571 "\n";
12572
12573 if (include_invalid_declaration)
12574 {
12575 result_sstream << "subroutine void subroutineTestTypeGS(out vec4 test);\n"
12576 "\n"
12577 "subroutine(subroutineTestTypeGS) void test_impl1(out vec4 test);\n"
12578 "\n"
12579 "subroutine uniform subroutineTestTypeGS test_subroutineGS;\n";
12580 }
12581
12582 result_sstream << "\n"
12583 "void main()\n"
12584 "{\n";
12585
12586 if (include_invalid_declaration)
12587 {
12588 result_sstream << " test_subroutineGS(gl_Position);\n";
12589 }
12590 else
12591 {
12592 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
12593 }
12594
12595 result_sstream << "EmitVertex();\n"
12596 "}\n";
12597
12598 return result_sstream.str();
12599 }
12600
12601 /** Retrieves tessellation control shader body.
12602 *
12603 * @param include_invalid_declaration true if a subroutine prototype should be included in
12604 * the shader, false to skip it.
12605 *
12606 * @return Requested string.
12607 **/
getTessellationControlShaderBody(bool include_invalid_declaration) const12608 std::string NegativeTest8::getTessellationControlShaderBody(bool include_invalid_declaration) const
12609 {
12610 std::stringstream result_sstream;
12611
12612 result_sstream << "#version 400\n"
12613 "\n"
12614 "#extension GL_ARB_shader_subroutine : require\n"
12615 "\n"
12616 "layout (vertices = 4) out;\n"
12617 "\n";
12618
12619 if (include_invalid_declaration)
12620 {
12621 result_sstream << "subroutine void subroutineTestTypeTC(out vec4 test);\n"
12622 "\n"
12623 "subroutine(subroutineTestTypeTC) void test_impl1(out vec4 test);\n"
12624 "\n"
12625 "subroutine uniform subroutineTestTypeTC test_subroutineTC;\n";
12626 }
12627
12628 result_sstream << "\n"
12629 "void main()\n"
12630 "{\n";
12631
12632 if (include_invalid_declaration)
12633 {
12634 result_sstream << " test_subroutineTC(gl_out[gl_InvocationID].gl_Position);\n";
12635 }
12636 else
12637 {
12638 result_sstream << " gl_out[gl_InvocationID].gl_Position = vec4(0, 1, 2, 3);\n";
12639 }
12640
12641 result_sstream << "}\n";
12642
12643 return result_sstream.str();
12644 }
12645
12646 /** Retrieves tessellation evaluation body.
12647 *
12648 * @param include_invalid_declaration true if a subroutine prototype should be included in
12649 * the shader, false to skip it.
12650 *
12651 * @return Requested string.
12652 **/
getTessellationEvaluationShaderBody(bool include_invalid_declaration) const12653 std::string NegativeTest8::getTessellationEvaluationShaderBody(bool include_invalid_declaration) const
12654 {
12655 std::stringstream result_sstream;
12656
12657 result_sstream << "#version 400\n"
12658 "\n"
12659 "#extension GL_ARB_shader_subroutine : require\n"
12660 "\n"
12661 "layout (quads) in;\n"
12662 "\n";
12663
12664 if (include_invalid_declaration)
12665 {
12666 result_sstream << "subroutine void subroutineTestTypeTE(out vec4 test);\n"
12667 "\n"
12668 "subroutine(subroutineTestTypeTE) void test_impl1(out vec4 test);\n"
12669 "\n"
12670 "subroutine uniform subroutineTestTypeTE test_subroutineTE;\n";
12671 }
12672
12673 result_sstream << "\n"
12674 "void main()\n"
12675 "{\n";
12676
12677 if (include_invalid_declaration)
12678 {
12679 result_sstream << " test_subroutineTE(gl_Position);\n";
12680 }
12681 else
12682 {
12683 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
12684 }
12685
12686 result_sstream << "}\n";
12687
12688 return result_sstream.str();
12689 }
12690
12691 /** Retrieves vertex shader body.
12692 *
12693 * @param include_invalid_declaration true if a subroutine prototype should be included in
12694 * the shader, false to skip it.
12695 *
12696 * @return Requested string.
12697 **/
getVertexShaderBody(bool include_invalid_declaration) const12698 std::string NegativeTest8::getVertexShaderBody(bool include_invalid_declaration) const
12699 {
12700 std::stringstream result_sstream;
12701
12702 result_sstream << "#version 400\n"
12703 "\n"
12704 "#extension GL_ARB_shader_subroutine : require\n"
12705 "\n";
12706
12707 if (include_invalid_declaration)
12708 {
12709 result_sstream << "subroutine void subroutineTestTypeVS(out vec4 test);\n"
12710 "\n"
12711 "subroutine(subroutineTestTypeVS) void test_impl1(out vec4 test);\n"
12712 "\n"
12713 "subroutine uniform subroutineTestTypeVS test_subroutineVS;\n";
12714 }
12715
12716 result_sstream << "\n"
12717 "void main()\n"
12718 "{\n";
12719
12720 if (include_invalid_declaration)
12721 {
12722 result_sstream << " test_subroutineVS(gl_Position);\n";
12723 }
12724 else
12725 {
12726 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
12727 }
12728
12729 result_sstream << "}\n";
12730
12731 return result_sstream.str();
12732 }
12733
12734 /** Executes test iteration.
12735 *
12736 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
12737 */
iterate()12738 tcu::TestNode::IterateResult NegativeTest8::iterate()
12739 {
12740 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
12741 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
12742 {
12743 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
12744 }
12745
12746 /* Iterate over all shader stages. For each iteration, iteration-specific shader stage
12747 * will feature an invalid subroutine definition. Other shader stages will be assigned
12748 * valid bodies. The test fails if a program built of such shaders links successfully.
12749 */
12750 for (int shader_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
12751 shader_stage < static_cast<int>(Utils::SHADER_STAGE_COUNT); ++shader_stage)
12752 {
12753 executeIteration(static_cast<Utils::_shader_stage>(shader_stage));
12754 deinitIteration();
12755 } /* for (all shader stages) */
12756
12757 /* All done */
12758 if (m_has_test_passed)
12759 {
12760 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
12761 }
12762 else
12763 {
12764 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
12765 }
12766
12767 return STOP;
12768 }
12769
12770 /** Constructor.
12771 *
12772 * @param context Rendering context.
12773 **/
NegativeTest9(deqp::Context & context)12774 NegativeTest9::NegativeTest9(deqp::Context &context)
12775 : TestCase(context, "subroutines_cannot_be_assigned_float_int_values_or_be_compared",
12776 "Make sure it is not possible to assign float/int to subroutine "
12777 "uniform and that subroutine uniform values cannot be compared.")
12778 , m_has_test_passed(true)
12779 , m_po_id(0)
12780 , m_vs_id(0)
12781 {
12782 /* Left blank intentionally */
12783 }
12784
12785 /** Deinitializes any GL objects that may have been created during
12786 * test execution.
12787 **/
deinit()12788 void NegativeTest9::deinit()
12789 {
12790 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
12791
12792 if (m_po_id != 0)
12793 {
12794 gl.deleteProgram(m_po_id);
12795
12796 m_po_id = 0;
12797 }
12798
12799 if (m_vs_id != 0)
12800 {
12801 gl.deleteShader(m_vs_id);
12802
12803 m_vs_id = 0;
12804 }
12805 }
12806
12807 /** Returns a literal corresponding to user-specified test case enum.
12808 *
12809 * @param test_case As per description.
12810 *
12811 * @return Requested string.
12812 **/
getTestCaseString(const _test_case & test_case)12813 std::string NegativeTest9::getTestCaseString(const _test_case &test_case)
12814 {
12815 std::string result = "?";
12816
12817 switch (test_case)
12818 {
12819 case TEST_CASE_INVALID_FLOAT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT:
12820 result = "TEST_CASE_INVALID_FLOAT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT";
12821 break;
12822 case TEST_CASE_INVALID_INT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT:
12823 result = "TEST_CASE_INVALID_INT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT";
12824 break;
12825 case TEST_CASE_INVALID_SUBROUTINE_UNIFORM_VALUE_COMPARISON:
12826 result = "TEST_CASE_INVALID_SUBROUTINE_UNIFORM_VALUE_COMPARISON";
12827 break;
12828 default:
12829 break;
12830 }
12831
12832 return result;
12833 }
12834
12835 /** Retrieves vertex shader body for user-specified test case.
12836 *
12837 * @param test_case As per description.
12838 *
12839 * @return Requested string.
12840 **/
getVertexShader(const _test_case & test_case)12841 std::string NegativeTest9::getVertexShader(const _test_case &test_case)
12842 {
12843 std::stringstream result_sstream;
12844
12845 /* Form pre-amble */
12846 result_sstream << "#version 400\n"
12847 "\n"
12848 "#extension GL_ARB_shader_subroutine : require\n"
12849 "\n"
12850 /* Define a subroutine */
12851 "subroutine void subroutineType(inout vec4 test);\n"
12852 "\n"
12853 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
12854 "{\n"
12855 " test += vec4(0, 1, 2, 3);\n"
12856 "}\n"
12857 "\n"
12858 "subroutine uniform subroutineType function;\n"
12859 "\n";
12860
12861 /* Include case-specific implementation */
12862 switch (test_case)
12863 {
12864 case TEST_CASE_INVALID_FLOAT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT:
12865 {
12866 result_sstream << "void main()\n"
12867 "{\n"
12868 " function = 1.0f;\n"
12869 "\n"
12870 " function(gl_Position);\n"
12871 "}\n";
12872
12873 break;
12874 }
12875
12876 case TEST_CASE_INVALID_INT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT:
12877 {
12878 result_sstream << "void main()\n"
12879 "{\n"
12880 " function = 1;\n"
12881 "\n"
12882 " function(gl_Position);\n"
12883 "}\n";
12884
12885 break;
12886 }
12887
12888 case TEST_CASE_INVALID_SUBROUTINE_UNIFORM_VALUE_COMPARISON:
12889 {
12890 result_sstream << "subroutine uniform subroutineType function2;\n"
12891 "\n"
12892 "void main()\n"
12893 "{\n"
12894 " if (function == function2)\n"
12895 " {\n"
12896 " function(gl_Position);\n"
12897 " }\n"
12898 " else\n"
12899 " {\n"
12900 " function2(gl_Position);\n"
12901 " }\n"
12902 "}\n";
12903
12904 break;
12905 }
12906
12907 default:
12908 break;
12909 } /* switch (test_case) */
12910
12911 /* Done */
12912 return result_sstream.str();
12913 }
12914
12915 /** Executes test iteration.
12916 *
12917 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
12918 */
iterate()12919 tcu::TestNode::IterateResult NegativeTest9::iterate()
12920 {
12921 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
12922
12923 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
12924 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
12925 {
12926 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
12927 }
12928
12929 /* Iterate over all test cases */
12930 for (int test_case = static_cast<int>(TEST_CASE_FIRST); test_case != static_cast<int>(TEST_CASE_COUNT); ++test_case)
12931 {
12932 /* Try to build a program object using invalid vertex shader, specific to the
12933 * iteration we're currently in */
12934 std::string vs_body = getVertexShader(static_cast<_test_case>(test_case));
12935
12936 if (ShaderSubroutine::Utils::buildProgram(gl, vs_body, "", /* tc_body */
12937 "", /* te_body */
12938 "", /* gs_body */
12939 "", /* fs_body */
12940 DE_NULL, /* xfb_varyings */
12941 0, /* n_xfb_varyings */
12942 &m_vs_id, DE_NULL, /* out_tc_id */
12943 DE_NULL, /* out_te_id */
12944 DE_NULL, /* out_gs_id */
12945 DE_NULL, /* out_fs_id */
12946 &m_po_id))
12947 {
12948 m_testCtx.getLog() << tcu::TestLog::Message << "A program object was successfully built for ["
12949 << getTestCaseString(static_cast<_test_case>(test_case))
12950 << "] test case, even though it was invalid." << tcu::TestLog::EndMessage;
12951
12952 m_has_test_passed = false;
12953 }
12954
12955 /* Delete any objects that may have been created */
12956 deinit();
12957 } /* for (all test cases) */
12958
12959 /** All done */
12960 if (m_has_test_passed)
12961 {
12962 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
12963 }
12964 else
12965 {
12966 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
12967 }
12968
12969 return STOP;
12970 }
12971
12972 /** Constructor.
12973 *
12974 * @param context Rendering context.
12975 **/
NegativeTest10(deqp::Context & context)12976 NegativeTest10::NegativeTest10(deqp::Context &context)
12977 : TestCase(context, "function_overloading_forbidden_for_subroutines",
12978 "Check that an overloaded function cannot be declared with subroutine and "
12979 "a program will fail to compile or link if any shader or stage contains"
12980 " two or more functions with the same name if the name is associated with"
12981 " a subroutine type.")
12982 , m_has_test_passed(true)
12983 , m_fs_id(0)
12984 , m_gs_id(0)
12985 , m_po_id(0)
12986 , m_tc_id(0)
12987 , m_te_id(0)
12988 , m_vs_id(0)
12989 {
12990 /* Left blank intentionally */
12991 }
12992
12993 /** Deinitializes any GL objects that may have been created during
12994 * test execution.
12995 **/
deinit()12996 void NegativeTest10::deinit()
12997 {
12998 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
12999
13000 if (m_fs_id != 0)
13001 {
13002 gl.deleteShader(m_fs_id);
13003
13004 m_fs_id = 0;
13005 }
13006
13007 if (m_gs_id != 0)
13008 {
13009 gl.deleteShader(m_gs_id);
13010
13011 m_gs_id = 0;
13012 }
13013
13014 if (m_po_id != 0)
13015 {
13016 gl.deleteProgram(m_po_id);
13017
13018 m_po_id = 0;
13019 }
13020
13021 if (m_tc_id != 0)
13022 {
13023 gl.deleteShader(m_tc_id);
13024
13025 m_tc_id = 0;
13026 }
13027
13028 if (m_te_id != 0)
13029 {
13030 gl.deleteShader(m_te_id);
13031
13032 m_te_id = 0;
13033 }
13034
13035 if (m_vs_id != 0)
13036 {
13037 gl.deleteShader(m_vs_id);
13038
13039 m_vs_id = 0;
13040 }
13041 }
13042
13043 /** Retrieves fragment shader that should be used for the purpose of the test.
13044 * An overloaded version of a subroutine function is inserted if
13045 * @param include_duplicate_function flag is set to true.
13046 *
13047 * @param include_duplicate_function As per description.
13048 *
13049 * @return Requested string.
13050 **/
getFragmentShader(bool include_duplicate_function)13051 std::string NegativeTest10::getFragmentShader(bool include_duplicate_function)
13052 {
13053 std::stringstream result_sstream;
13054
13055 result_sstream << "#version 400\n"
13056 "\n"
13057 "#extension GL_ARB_shader_subroutine : require\n"
13058 "\n"
13059 "subroutine void subroutineType(inout vec4 test);\n"
13060 "\n"
13061 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13062 "{\n"
13063 " test = vec4(2, 3, 4, 5);\n"
13064 "}\n"
13065 "\n"
13066 "subroutine uniform subroutineType function;\n"
13067 "out vec4 result;\n"
13068 "\n";
13069
13070 if (include_duplicate_function)
13071 {
13072 result_sstream << "void test_function(inout vec4 test)\n"
13073 "{\n"
13074 " test = vec4(3, 4, 5, 6);\n"
13075 "}\n"
13076 "\n";
13077 }
13078
13079 result_sstream << "void main()\n"
13080 "{\n"
13081 " test_function(result);\n"
13082 "}\n";
13083
13084 return result_sstream.str();
13085 }
13086
13087 /** Retrieves geometry shader that should be used for the purpose of the test.
13088 * An overloaded version of a subroutine function is inserted if
13089 * @param include_duplicate_function flag is set to true.
13090 *
13091 * @param include_duplicate_function As per description.
13092 *
13093 * @return Requested string.
13094 **/
getGeometryShader(bool include_duplicate_function)13095 std::string NegativeTest10::getGeometryShader(bool include_duplicate_function)
13096 {
13097 std::stringstream result_sstream;
13098
13099 result_sstream << "#version 400\n"
13100 "\n"
13101 "#extension GL_ARB_shader_subroutine : require\n"
13102 "\n"
13103 "layout (triangles) in;\n"
13104 "layout (triangle_strip, max_vertices = 4) out;\n"
13105 "\n"
13106 "subroutine void subroutineType(inout vec4 test);\n"
13107 "\n"
13108 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13109 "{\n"
13110 " test = vec4(2, 3, 4, 5);\n"
13111 "}\n"
13112 "\n"
13113 "subroutine uniform subroutineType function;\n"
13114 "\n";
13115
13116 if (include_duplicate_function)
13117 {
13118 result_sstream << "void test_function(inout vec4 test)\n"
13119 "{\n"
13120 " test = vec4(3, 4, 5, 6);\n"
13121 "}\n"
13122 "\n";
13123 }
13124
13125 result_sstream << "void main()\n"
13126 "{\n"
13127 " function(gl_Position);\n"
13128 " EmitVertex();\n"
13129 " EndPrimitive();\n"
13130 "}\n";
13131
13132 return result_sstream.str();
13133 }
13134
13135 /** Retrieves tess control shader that should be used for the purpose of the test.
13136 * An overloaded version of a subroutine function is inserted if
13137 * @param include_duplicate_function flag is set to true.
13138 *
13139 * @param include_duplicate_function As per description.
13140 *
13141 * @return Requested string.
13142 **/
getTessellationControlShader(bool include_duplicate_function)13143 std::string NegativeTest10::getTessellationControlShader(bool include_duplicate_function)
13144 {
13145 std::stringstream result_sstream;
13146
13147 result_sstream << "#version 400\n"
13148 "\n"
13149 "#extension GL_ARB_shader_subroutine : require\n"
13150 "\n"
13151 "layout (vertices = 4) out;\n"
13152 "\n"
13153 "subroutine void subroutineType(inout vec4 test);\n"
13154 "\n"
13155 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13156 "{\n"
13157 " test = vec4(2, 3, 4, 5);\n"
13158 "}\n"
13159 "\n"
13160 "subroutine uniform subroutineType function;\n"
13161 "\n";
13162
13163 if (include_duplicate_function)
13164 {
13165 result_sstream << "void test_function(inout vec4 test)\n"
13166 "{\n"
13167 " test = vec4(3, 4, 5, 6);\n"
13168 "}\n"
13169 "\n";
13170 }
13171
13172 result_sstream << "void main()\n"
13173 "{\n"
13174 " vec4 temp;\n"
13175 "\n"
13176 " function(temp);\n"
13177 "\n"
13178 " gl_out[gl_InvocationID].gl_Position = temp;\n"
13179 " gl_TessLevelInner[0] = temp.x;\n"
13180 " gl_TessLevelInner[1] = temp.y;\n"
13181 " gl_TessLevelOuter[0] = temp.z;\n"
13182 " gl_TessLevelOuter[1] = temp.w;\n"
13183 " gl_TessLevelOuter[2] = temp.x;\n"
13184 " gl_TessLevelOuter[3] = temp.y;\n"
13185 "}\n";
13186
13187 return result_sstream.str();
13188 }
13189
13190 /** Retrieves tess evaluation shader that should be used for the purpose of the test.
13191 * An overloaded version of a subroutine function is inserted if
13192 * @param include_duplicate_function flag is set to true.
13193 *
13194 * @param include_duplicate_function As per description.
13195 *
13196 * @return Requested string.
13197 **/
getTessellationEvaluationShader(bool include_duplicate_function)13198 std::string NegativeTest10::getTessellationEvaluationShader(bool include_duplicate_function)
13199 {
13200 std::stringstream result_sstream;
13201
13202 result_sstream << "#version 400\n"
13203 "\n"
13204 "#extension GL_ARB_shader_subroutine : require\n"
13205 "\n"
13206 "layout (quads) in;\n"
13207 "\n"
13208 "subroutine void subroutineType(inout vec4 test);\n"
13209 "\n"
13210 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13211 "{\n"
13212 " test = vec4(2, 3, 4, 5);\n"
13213 "}\n"
13214 "\n"
13215 "subroutine uniform subroutineType function;\n"
13216 "\n";
13217
13218 if (include_duplicate_function)
13219 {
13220 result_sstream << "void test_function(inout vec4 test)\n"
13221 "{\n"
13222 " test = vec4(3, 4, 5, 6);\n"
13223 "}\n"
13224 "\n";
13225 }
13226
13227 result_sstream << "void main()\n"
13228 "{\n"
13229 " vec4 temp;\n"
13230 "\n"
13231 " function(temp);\n"
13232 "\n"
13233 " gl_Position = temp;\n"
13234 "}\n";
13235
13236 return result_sstream.str();
13237 }
13238
13239 /** Retrieves vertex shader that should be used for the purpose of the test.
13240 * An overloaded version of a subroutine function is inserted if
13241 * @param include_duplicate_function flag is set to true.
13242 *
13243 * @param include_duplicate_function As per description.
13244 *
13245 * @return Requested string.
13246 **/
getVertexShader(bool include_duplicate_function)13247 std::string NegativeTest10::getVertexShader(bool include_duplicate_function)
13248 {
13249 std::stringstream result_sstream;
13250
13251 result_sstream << "#version 400\n"
13252 "\n"
13253 "#extension GL_ARB_shader_subroutine : require\n"
13254 "\n"
13255 "subroutine void subroutineType(inout vec4 test);\n"
13256 "\n"
13257 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13258 "{\n"
13259 " test = vec4(2, 3, 4, 5);\n"
13260 "}\n"
13261 "\n"
13262 "subroutine uniform subroutineType function;\n"
13263 "\n";
13264
13265 if (include_duplicate_function)
13266 {
13267 result_sstream << "void test_function(inout vec4 test)\n"
13268 "{\n"
13269 " test = vec4(3, 4, 5, 6);\n"
13270 "}\n"
13271 "\n";
13272 }
13273
13274 result_sstream << "void main()\n"
13275 "{\n"
13276 " function(gl_Position);\n"
13277 "}\n";
13278
13279 return result_sstream.str();
13280 }
13281
13282 /** Fills m_test_cases field with test case descriptors */
initTestCases()13283 void NegativeTest10::initTestCases()
13284 {
13285 /* For each test case, only one shader stage should define a function that
13286 * has already been defined as a subroutine. */
13287 for (int offending_shader_stage_it = static_cast<int>(Utils::SHADER_STAGE_FIRST);
13288 offending_shader_stage_it != static_cast<int>(Utils::SHADER_STAGE_COUNT); ++offending_shader_stage_it)
13289 {
13290 Utils::_shader_stage offending_shader_stage = static_cast<Utils::_shader_stage>(offending_shader_stage_it);
13291 /* Form the test case descriptor */
13292 std::stringstream name_sstream;
13293 _test_case test_case;
13294
13295 name_sstream << "Broken shader stage:" << Utils::getShaderStageString(offending_shader_stage);
13296
13297 test_case.fs_body = getFragmentShader(offending_shader_stage == Utils::SHADER_STAGE_FRAGMENT);
13298 test_case.gs_body = getGeometryShader(offending_shader_stage == Utils::SHADER_STAGE_GEOMETRY);
13299 test_case.name = name_sstream.str();
13300 test_case.tc_body =
13301 getTessellationControlShader(offending_shader_stage == Utils::SHADER_STAGE_TESSELLATION_CONTROL);
13302 test_case.te_body =
13303 getTessellationEvaluationShader(offending_shader_stage == Utils::SHADER_STAGE_TESSELLATION_EVALUATION);
13304 test_case.vs_body = getVertexShader(offending_shader_stage == Utils::SHADER_STAGE_VERTEX);
13305
13306 m_test_cases.push_back(test_case);
13307 }
13308 }
13309
13310 /** Executes test iteration.
13311 *
13312 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
13313 */
iterate()13314 tcu::TestNode::IterateResult NegativeTest10::iterate()
13315 {
13316 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
13317
13318 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
13319 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
13320 {
13321 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
13322 }
13323
13324 /* Form test cases */
13325 initTestCases();
13326
13327 /* Iterate over all test cases */
13328 for (_test_cases_const_iterator test_case_iterator = m_test_cases.begin(); test_case_iterator != m_test_cases.end();
13329 ++test_case_iterator)
13330 {
13331 const _test_case &test_case = *test_case_iterator;
13332
13333 /* Try to build the program object */
13334 if (ShaderSubroutine::Utils::buildProgram(gl, test_case.vs_body, test_case.tc_body, test_case.te_body,
13335 test_case.gs_body, test_case.fs_body, DE_NULL, /* xfb_varyings */
13336 0, /* n_xfb_varyings */
13337 &m_vs_id, (test_case.tc_body.length() > 0) ? &m_tc_id : DE_NULL,
13338 (test_case.te_body.length() > 0) ? &m_te_id : DE_NULL,
13339 (test_case.gs_body.length() > 0) ? &m_gs_id : DE_NULL,
13340 (test_case.fs_body.length() > 0) ? &m_fs_id : DE_NULL, &m_po_id))
13341 {
13342 m_testCtx.getLog() << tcu::TestLog::Message << "A program object was successfully built for ["
13343 << test_case.name << "] test case, even though it was invalid."
13344 << tcu::TestLog::EndMessage;
13345
13346 m_has_test_passed = false;
13347 }
13348
13349 /* Delete any objects that may have been created */
13350 deinit();
13351 } /* for (all test cases) */
13352
13353 /** All done */
13354 if (m_has_test_passed)
13355 {
13356 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
13357 }
13358 else
13359 {
13360 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
13361 }
13362
13363 return STOP;
13364 }
13365
13366 /** Constructor.
13367 *
13368 * @param context Rendering context.
13369 **/
NegativeTest11(deqp::Context & context)13370 NegativeTest11::NegativeTest11(deqp::Context &context)
13371 : TestCase(context, "subroutine_uniforms_used_for_sampling_atomic_image_functions",
13372 "Tries to use subroutine uniforms in invalid way in sampling, "
13373 "atomic and image functions. Verifies that compile- or link-time "
13374 "error occurs.")
13375 , m_has_test_passed(true)
13376 , m_po_id(0)
13377 , m_vs_id(0)
13378 {
13379 /* Left blank intentionally */
13380 }
13381
13382 /** Deinitializes any GL objects that may have been created during
13383 * test execution.
13384 **/
deinit()13385 void NegativeTest11::deinit()
13386 {
13387 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
13388
13389 if (m_po_id != 0)
13390 {
13391 gl.deleteProgram(m_po_id);
13392
13393 m_po_id = 0;
13394 }
13395
13396 if (m_vs_id != 0)
13397 {
13398 gl.deleteShader(m_vs_id);
13399
13400 m_vs_id = 0;
13401 }
13402 }
13403
13404 /** Returns a literal corresponding to user-specified test case enum.
13405 *
13406 * @param test_case As per description.
13407 *
13408 * @return Requested string.
13409 **/
getTestCaseString(const _test_case & test_case)13410 std::string NegativeTest11::getTestCaseString(const _test_case &test_case)
13411 {
13412 std::string result = "?";
13413
13414 switch (test_case)
13415 {
13416 case TEST_CASE_INVALID_TEXTURE_SAMPLING_ATTEMPT:
13417 result = "TEST_CASE_INVALID_TEXTURE_SAMPLING_ATTEMPT";
13418 break;
13419 case TEST_CASE_INVALID_ATOMIC_COUNTER_USAGE_ATTEMPT:
13420 result = "TEST_CASE_INVALID_ATOMIC_COUNTER_USAGE_ATTEMPT";
13421 break;
13422 case TEST_CASE_INVALID_IMAGE_FUNCTION_USAGE_ATTEMPT:
13423 result = "TEST_CASE_INVALID_IMAGE_FUNCTION_USAGE_ATTEMPT";
13424 break;
13425 default:
13426 break;
13427 }
13428
13429 return result;
13430 }
13431
13432 /** Retrieves vertex shader body for user-specified test case.
13433 *
13434 * @param test_case As per description.
13435 *
13436 * @return Requested string.
13437 **/
getVertexShader(const _test_case & test_case)13438 std::string NegativeTest11::getVertexShader(const _test_case &test_case)
13439 {
13440 std::stringstream result_sstream;
13441
13442 /* Form pre-amble */
13443 result_sstream << "#version 400\n"
13444 "\n"
13445 "#extension GL_ARB_shader_subroutine : require\n";
13446
13447 if (test_case == TEST_CASE_INVALID_ATOMIC_COUNTER_USAGE_ATTEMPT)
13448 {
13449 result_sstream << "#extension GL_ARB_shader_atomic_counters : require\n";
13450 }
13451
13452 result_sstream << "\n"
13453 /* Define a subroutine */
13454 "subroutine void subroutineType(inout vec4 test);\n"
13455 "\n"
13456 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13457 "{\n"
13458 " test += vec4(0, 1, 2, 3);\n"
13459 "}\n"
13460 "\n"
13461 "subroutine uniform subroutineType function;\n"
13462 "\n"
13463
13464 /* Define main() body */
13465 "void main()\n"
13466 "{\n";
13467
13468 /* Implement case-specific behavior */
13469 switch (test_case)
13470 {
13471 case TEST_CASE_INVALID_ATOMIC_COUNTER_USAGE_ATTEMPT:
13472 {
13473 result_sstream << "if (atomicCounter(function) > 2)\n"
13474 "{\n"
13475 " gl_Position = vec4(1);\n"
13476 "}\n";
13477
13478 break;
13479 }
13480
13481 case TEST_CASE_INVALID_IMAGE_FUNCTION_USAGE_ATTEMPT:
13482 {
13483 result_sstream << "imageStore(function, vec2(0.0, 1.0), vec4(1.0) );\n";
13484
13485 break;
13486 }
13487
13488 case TEST_CASE_INVALID_TEXTURE_SAMPLING_ATTEMPT:
13489 {
13490 result_sstream << "gl_Position = texture(function, vec2(1.0) );\n";
13491
13492 break;
13493 }
13494
13495 default:
13496 break;
13497 } /* switch (test_case) */
13498
13499 /* Close main() body */
13500 result_sstream << "}\n";
13501
13502 /* Done */
13503 return result_sstream.str();
13504 }
13505
13506 /** Executes test iteration.
13507 *
13508 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
13509 */
iterate()13510 tcu::TestNode::IterateResult NegativeTest11::iterate()
13511 {
13512 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
13513
13514 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
13515 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
13516 {
13517 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
13518 }
13519
13520 /* Iterate over all test cases */
13521 for (int test_case = static_cast<int>(TEST_CASE_FIRST); test_case != static_cast<int>(TEST_CASE_COUNT); ++test_case)
13522 {
13523 if (static_cast<_test_case>(test_case) == TEST_CASE_INVALID_ATOMIC_COUNTER_USAGE_ATTEMPT &&
13524 !m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_atomic_counters"))
13525 {
13526 /* This iteration requires atomic counter support that this GL implementation
13527 * is not capable of. Skip the iteration
13528 */
13529 continue;
13530 }
13531
13532 /* Try to build a program object using invalid vertex shader, specific to the
13533 * iteration we're currently in */
13534 std::string vs_body = getVertexShader(static_cast<_test_case>(test_case));
13535
13536 if (ShaderSubroutine::Utils::buildProgram(gl, vs_body, "", /* tc_body */
13537 "", /* te_body */
13538 "", /* gs_body */
13539 "", /* fs_body */
13540 DE_NULL, /* xfb_varyings */
13541 0, /* n_xfb_varyings */
13542 &m_vs_id, DE_NULL, /* out_tc_id */
13543 DE_NULL, /* out_te_id */
13544 DE_NULL, /* out_gs_id */
13545 DE_NULL, /* out_fs_id */
13546 &m_po_id))
13547 {
13548 m_testCtx.getLog() << tcu::TestLog::Message << "A program object was successfully built for ["
13549 << getTestCaseString(static_cast<_test_case>(test_case))
13550 << "] test case, even though it was invalid." << tcu::TestLog::EndMessage;
13551
13552 m_has_test_passed = false;
13553 }
13554
13555 /* Delete any objects that may have been created */
13556 deinit();
13557 } /* for (all test cases) */
13558
13559 /** All done */
13560 if (m_has_test_passed)
13561 {
13562 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
13563 }
13564 else
13565 {
13566 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
13567 }
13568
13569 return STOP;
13570 }
13571
13572 /** Constructor.
13573 *
13574 * @param context Rendering context.
13575 **/
NegativeTest12(deqp::Context & context)13576 NegativeTest12::NegativeTest12(deqp::Context &context)
13577 : TestCase(context, "subroutines_not_allowed_as_variables_constructors_and_argument_or_return_types",
13578 "Verifies that it is not allowed to use subroutine type for "
13579 "local/global variables, constructors or argument/return type.")
13580 , m_has_test_passed(true)
13581 , m_po_id(0)
13582 , m_vs_id(0)
13583 {
13584 /* Left blank intentionally */
13585 }
13586
13587 /** Deinitializes any GL objects that may have been created during
13588 * test execution.
13589 **/
deinit()13590 void NegativeTest12::deinit()
13591 {
13592 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
13593
13594 if (m_po_id != 0)
13595 {
13596 gl.deleteProgram(m_po_id);
13597
13598 m_po_id = 0;
13599 }
13600
13601 if (m_vs_id != 0)
13602 {
13603 gl.deleteShader(m_vs_id);
13604
13605 m_vs_id = 0;
13606 }
13607 }
13608
13609 /** Returns a literal corresponding to user-specified test case enum.
13610 *
13611 * @param test_case As per description.
13612 *
13613 * @return Requested string.
13614 **/
getTestCaseString(const _test_case & test_case)13615 std::string NegativeTest12::getTestCaseString(const _test_case &test_case)
13616 {
13617 std::string result = "?";
13618
13619 switch (test_case)
13620 {
13621 case TEST_CASE_INVALID_LOCAL_SUBROUTINE_VARIABLE:
13622 result = "TEST_CASE_INVALID_LOCAL_SUBROUTINE_VARIABLE";
13623 break;
13624 case TEST_CASE_INVALID_GLOBAL_SUBROUTINE_VARIABLE:
13625 result = "TEST_CASE_INVALID_GLOBAL_SUBROUTINE_VARIABLE";
13626 break;
13627 case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR:
13628 result = "TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR";
13629 break;
13630 case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_ARGUMENT:
13631 result = "TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_ARGUMENT";
13632 break;
13633 case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_RETURN_TYPE:
13634 result = "TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_RETURN_TYPE";
13635 break;
13636 default:
13637 break;
13638 }
13639
13640 return result;
13641 }
13642
13643 /** Retrieves vertex shader body for user-specified test case.
13644 *
13645 * @param test_case As per description.
13646 *
13647 * @return Requested string.
13648 **/
getVertexShader(const _test_case & test_case)13649 std::string NegativeTest12::getVertexShader(const _test_case &test_case)
13650 {
13651 std::stringstream result_sstream;
13652
13653 /* Form pre-amble */
13654 result_sstream << "#version 400\n"
13655 "\n"
13656 "#extension GL_ARB_shader_subroutine : require\n"
13657 "\n"
13658 /* Define a subroutine */
13659 "subroutine void subroutineType(inout vec4 test);\n"
13660 "\n"
13661 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13662 "{\n"
13663 " test += vec4(0, 1, 2, 3);\n"
13664 "}\n"
13665 "\n"
13666 "subroutine uniform subroutineType function;\n"
13667 "\n";
13668
13669 /* Include case-specific implementation */
13670 switch (test_case)
13671 {
13672 case TEST_CASE_INVALID_LOCAL_SUBROUTINE_VARIABLE:
13673 {
13674 result_sstream << "void main()\n"
13675 "{\n"
13676 " subroutine subroutineType function2;\n"
13677 " vec4 result;\n"
13678 "\n"
13679 " function2(result);\n"
13680 " gl_Position = result;\n"
13681 "}\n";
13682
13683 break;
13684 }
13685
13686 case TEST_CASE_INVALID_GLOBAL_SUBROUTINE_VARIABLE:
13687 {
13688 result_sstream << "subroutine subroutineType function2;\n"
13689 "\n"
13690 "void main()\n"
13691 "{\n"
13692 " vec4 result;\n"
13693 "\n"
13694 " function2(result);\n"
13695 " gl_Position = result;\n"
13696 "}\n";
13697
13698 break;
13699 }
13700
13701 case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR:
13702 {
13703 result_sstream << "void main()\n"
13704 "{\n"
13705 " subroutineType(function);\n"
13706 "}\n";
13707
13708 break;
13709 }
13710
13711 case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_ARGUMENT:
13712 {
13713 result_sstream << "vec4 test_function(subroutineType argument)\n"
13714 "{\n"
13715 " vec4 result = vec4(1, 2, 3, 4);\n"
13716 "\n"
13717 " argument(result);\n"
13718 "\n"
13719 " return result;\n"
13720 "}\n"
13721 "\n"
13722 "void main()\n"
13723 "{\n"
13724 " test_function(function);\n"
13725 "}\n";
13726
13727 break;
13728 }
13729
13730 case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_RETURN_TYPE:
13731 {
13732 result_sstream << "subroutineType test_function()\n"
13733 "{\n"
13734 " return function;\n"
13735 "}\n"
13736 "\n"
13737 "void main()\n"
13738 "{\n"
13739 " test_function()(gl_Position);\n"
13740 "}\n";
13741
13742 break;
13743 }
13744
13745 default:
13746 break;
13747 } /* switch (test_case) */
13748
13749 /* Done */
13750 return result_sstream.str();
13751 }
13752
13753 /** Executes test iteration.
13754 *
13755 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
13756 */
iterate()13757 tcu::TestNode::IterateResult NegativeTest12::iterate()
13758 {
13759 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
13760
13761 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
13762 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
13763 {
13764 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
13765 }
13766
13767 /* Iterate over all test cases */
13768 for (int test_case = static_cast<int>(TEST_CASE_FIRST); test_case != static_cast<int>(TEST_CASE_COUNT); ++test_case)
13769 {
13770 /* Try to build a program object using invalid vertex shader, specific to the
13771 * iteration we're currently in */
13772 std::string vs_body = getVertexShader(static_cast<_test_case>(test_case));
13773
13774 if (ShaderSubroutine::Utils::buildProgram(gl, vs_body, "", /* tc_body */
13775 "", /* te_body */
13776 "", /* gs_body */
13777 "", /* fs_body */
13778 DE_NULL, /* xfb_varyings */
13779 0, /* n_xfb_varyings */
13780 &m_vs_id, DE_NULL, /* out_tc_id */
13781 DE_NULL, /* out_te_id */
13782 DE_NULL, /* out_gs_id */
13783 DE_NULL, /* out_fs_id */
13784 &m_po_id))
13785 {
13786 m_testCtx.getLog() << tcu::TestLog::Message << "A program object was successfully built for ["
13787 << getTestCaseString(static_cast<_test_case>(test_case))
13788 << "] test case, even though it was invalid." << tcu::TestLog::EndMessage;
13789
13790 m_has_test_passed = false;
13791 }
13792
13793 /* Delete any objects that may have been created */
13794 deinit();
13795 } /* for (all test cases) */
13796
13797 /** All done */
13798 if (m_has_test_passed)
13799 {
13800 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
13801 }
13802 else
13803 {
13804 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
13805 }
13806
13807 return STOP;
13808 }
13809
13810 } // namespace ShaderSubroutine
13811
13812 /** Constructor.
13813 *
13814 * @param context Rendering context.
13815 **/
ShaderSubroutineTests(deqp::Context & context)13816 ShaderSubroutineTests::ShaderSubroutineTests(deqp::Context &context)
13817 : TestCaseGroup(context, "shader_subroutine", "Verifies \"shader_subroutine\" functionality")
13818 {
13819 /* Left blank on purpose */
13820 }
13821
13822 /** Initializes a texture_storage_multisample test group.
13823 *
13824 **/
init(void)13825 void ShaderSubroutineTests::init(void)
13826 {
13827 addChild(new ShaderSubroutine::APITest1(m_context));
13828 addChild(new ShaderSubroutine::APITest2(m_context));
13829 addChild(new ShaderSubroutine::FunctionalTest1_2(m_context));
13830 addChild(new ShaderSubroutine::FunctionalTest3_4(m_context));
13831 addChild(new ShaderSubroutine::FunctionalTest5(m_context));
13832 addChild(new ShaderSubroutine::FunctionalTest6(m_context));
13833 addChild(new ShaderSubroutine::FunctionalTest7_8(m_context));
13834 addChild(new ShaderSubroutine::FunctionalTest9(m_context));
13835 addChild(new ShaderSubroutine::FunctionalTest10(m_context));
13836 addChild(new ShaderSubroutine::FunctionalTest11(m_context));
13837 addChild(new ShaderSubroutine::FunctionalTest12(m_context));
13838 addChild(new ShaderSubroutine::FunctionalTest13(m_context));
13839 addChild(new ShaderSubroutine::FunctionalTest14_15(m_context));
13840 addChild(new ShaderSubroutine::FunctionalTest16(m_context));
13841 addChild(new ShaderSubroutine::FunctionalTest17(m_context));
13842 addChild(new ShaderSubroutine::FunctionalTest18_19(m_context));
13843 addChild(new ShaderSubroutine::NegativeTest1(m_context));
13844 addChild(new ShaderSubroutine::NegativeTest2(m_context));
13845 addChild(new ShaderSubroutine::NegativeTest3(m_context));
13846 addChild(new ShaderSubroutine::NegativeTest4(m_context));
13847 addChild(new ShaderSubroutine::NegativeTest5(m_context));
13848 addChild(new ShaderSubroutine::NegativeTest6(m_context));
13849 addChild(new ShaderSubroutine::NegativeTest7(m_context));
13850 addChild(new ShaderSubroutine::NegativeTest8(m_context));
13851 addChild(new ShaderSubroutine::NegativeTest9(m_context));
13852 addChild(new ShaderSubroutine::NegativeTest10(m_context));
13853 addChild(new ShaderSubroutine::NegativeTest11(m_context));
13854 addChild(new ShaderSubroutine::NegativeTest12(m_context));
13855 }
13856
13857 } // namespace gl4cts
13858