1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2014-2016 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 */ /*!
20 * \file
21 * \brief
22 */ /*-------------------------------------------------------------------*/
23
24 /**
25 * \file gl4cShaderSubroutineTests.cpp
26 * \brief Implements conformance tests for "Shader Subroutine" functionality.
27 */ /*-------------------------------------------------------------------*/
28
29 #include "gl4cShaderSubroutineTests.hpp"
30 #include "gluContextInfo.hpp"
31 #include "glwEnums.hpp"
32 #include "glwFunctions.hpp"
33 #include "tcuMatrix.hpp"
34 #include <cmath>
35 #include <cstring>
36 #include <deMath.h>
37
38 using namespace glw;
39
40 namespace gl4cts
41 {
42 namespace ShaderSubroutine
43 {
44 /** Constructor.
45 *
46 * @param context CTS context.
47 **/
buffer(deqp::Context & context)48 Utils::buffer::buffer(deqp::Context& context) : m_id(0), m_context(context)
49 {
50 }
51
52 /** Destructor
53 *
54 **/
~buffer()55 Utils::buffer::~buffer()
56 {
57 if (0 != m_id)
58 {
59 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
60
61 gl.deleteBuffers(1, &m_id);
62 m_id = 0;
63 }
64 }
65
66 /** Execute BindBufferRange
67 *
68 * @param target <target> parameter
69 * @param index <index> parameter
70 * @param offset <offset> parameter
71 * @param size <size> parameter
72 **/
bindRange(glw::GLenum target,glw::GLuint index,glw::GLintptr offset,glw::GLsizeiptr size)73 void Utils::buffer::bindRange(glw::GLenum target, glw::GLuint index, glw::GLintptr offset, glw::GLsizeiptr size)
74 {
75 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
76
77 gl.bindBufferRange(target, index, m_id, offset, size);
78 GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferRange");
79 }
80
81 /** Execute GenBuffer
82 *
83 **/
generate()84 void Utils::buffer::generate()
85 {
86 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
87
88 gl.genBuffers(1, &m_id);
89 GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers");
90 }
91
92 /** Execute BufferData
93 *
94 * @param target <target> parameter
95 * @param size <size> parameter
96 * @param data <data> parameter
97 * @param usage <usage> parameter
98 **/
update(glw::GLenum target,glw::GLsizeiptr size,glw::GLvoid * data,glw::GLenum usage)99 void Utils::buffer::update(glw::GLenum target, glw::GLsizeiptr size, glw::GLvoid* data, glw::GLenum usage)
100 {
101 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
102
103 gl.bindBuffer(target, m_id);
104 GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer");
105
106 gl.bufferData(target, size, data, usage);
107 GLU_EXPECT_NO_ERROR(gl.getError(), "bufferData");
108 }
109
110 /** Constructor
111 *
112 * @param context CTS context
113 **/
framebuffer(deqp::Context & context)114 Utils::framebuffer::framebuffer(deqp::Context& context) : m_id(0), m_context(context)
115 {
116 /* Nothing to be done here */
117 }
118
119 /** Destructor
120 *
121 **/
~framebuffer()122 Utils::framebuffer::~framebuffer()
123 {
124 if (0 != m_id)
125 {
126 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
127
128 gl.deleteFramebuffers(1, &m_id);
129 m_id = 0;
130 }
131 }
132
133 /** Attach texture to specified attachment
134 *
135 * @param attachment Attachment
136 * @param texture_id Texture id
137 * @param width Texture width
138 * @param height Texture height
139 **/
attachTexture(glw::GLenum attachment,glw::GLuint texture_id,glw::GLuint width,glw::GLuint height)140 void Utils::framebuffer::attachTexture(glw::GLenum attachment, glw::GLuint texture_id, glw::GLuint width,
141 glw::GLuint height)
142 {
143 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
144
145 bind();
146
147 gl.bindTexture(GL_TEXTURE_2D, texture_id);
148 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
149
150 gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, GL_TEXTURE_2D, texture_id, 0 /* level */);
151
152 GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture2D");
153
154 gl.viewport(0 /* x */, 0 /* y */, width, height);
155 GLU_EXPECT_NO_ERROR(gl.getError(), "Viewport");
156 }
157
158 /** Binds framebuffer to DRAW_FRAMEBUFFER
159 *
160 **/
bind()161 void Utils::framebuffer::bind()
162 {
163 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
164
165 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_id);
166 GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
167 }
168
169 /** Clear framebuffer
170 *
171 * @param mask <mask> parameter of glClear. Decides which shall be cleared
172 **/
clear(glw::GLenum mask)173 void Utils::framebuffer::clear(glw::GLenum mask)
174 {
175 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
176
177 gl.clear(mask);
178 GLU_EXPECT_NO_ERROR(gl.getError(), "Clear");
179 }
180
181 /** Specifie clear color
182 *
183 * @param red Red channel
184 * @param green Green channel
185 * @param blue Blue channel
186 * @param alpha Alpha channel
187 **/
clearColor(GLfloat red,GLfloat green,GLfloat blue,GLfloat alpha)188 void Utils::framebuffer::clearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
189 {
190 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
191
192 gl.clearColor(red, green, blue, alpha);
193 GLU_EXPECT_NO_ERROR(gl.getError(), "ClearColor");
194 }
195
196 /** Generate framebuffer
197 *
198 **/
generate()199 void Utils::framebuffer::generate()
200 {
201 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
202
203 gl.genFramebuffers(1, &m_id);
204 GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers");
205 }
206
207 const glw::GLenum Utils::program::ARB_COMPUTE_SHADER = 0x91B9;
208
209 /** Constructor.
210 *
211 * @param context CTS context.
212 **/
program(deqp::Context & context)213 Utils::program::program(deqp::Context& context)
214 : m_compute_shader_id(0)
215 , m_fragment_shader_id(0)
216 , m_geometry_shader_id(0)
217 , m_program_object_id(0)
218 , m_tesselation_control_shader_id(0)
219 , m_tesselation_evaluation_shader_id(0)
220 , m_vertex_shader_id(0)
221 , m_context(context)
222 {
223 /* Nothing to be done here */
224 }
225
226 /** Destructor
227 *
228 **/
~program()229 Utils::program::~program()
230 {
231 remove();
232 }
233
234 /** Build program
235 *
236 * @param compute_shader_code Compute shader source code
237 * @param fragment_shader_code Fragment shader source code
238 * @param geometry_shader_code Geometry shader source code
239 * @param tesselation_control_shader_code Tesselation control shader source code
240 * @param tesselation_evaluation_shader_code Tesselation evaluation shader source code
241 * @param vertex_shader_code Vertex shader source code
242 * @param varying_names Array of strings containing names of varyings to be captured with transfrom feedback
243 * @param n_varying_names Number of varyings to be captured with transfrom feedback
244 * @param is_separable Selects if monolithis or separable program should be built. Defaults to false
245 **/
build(const glw::GLchar * compute_shader_code,const glw::GLchar * fragment_shader_code,const glw::GLchar * geometry_shader_code,const glw::GLchar * tesselation_control_shader_code,const glw::GLchar * tesselation_evaluation_shader_code,const glw::GLchar * vertex_shader_code,const glw::GLchar * const * varying_names,glw::GLuint n_varying_names,bool is_separable)246 void Utils::program::build(const glw::GLchar* compute_shader_code, const glw::GLchar* fragment_shader_code,
247 const glw::GLchar* geometry_shader_code, const glw::GLchar* tesselation_control_shader_code,
248 const glw::GLchar* tesselation_evaluation_shader_code, const glw::GLchar* vertex_shader_code,
249 const glw::GLchar* const* varying_names, glw::GLuint n_varying_names, bool is_separable)
250 {
251 /* GL entry points */
252 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
253
254 /* Create shader objects and compile */
255 if (0 != compute_shader_code)
256 {
257 m_compute_shader_id = gl.createShader(ARB_COMPUTE_SHADER);
258 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
259
260 compile(m_compute_shader_id, compute_shader_code);
261 }
262
263 if (0 != fragment_shader_code)
264 {
265 m_fragment_shader_id = gl.createShader(GL_FRAGMENT_SHADER);
266 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
267
268 compile(m_fragment_shader_id, fragment_shader_code);
269 }
270
271 if (0 != geometry_shader_code)
272 {
273 m_geometry_shader_id = gl.createShader(GL_GEOMETRY_SHADER);
274 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
275
276 compile(m_geometry_shader_id, geometry_shader_code);
277 }
278
279 if (0 != tesselation_control_shader_code)
280 {
281 m_tesselation_control_shader_id = gl.createShader(GL_TESS_CONTROL_SHADER);
282 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
283
284 compile(m_tesselation_control_shader_id, tesselation_control_shader_code);
285 }
286
287 if (0 != tesselation_evaluation_shader_code)
288 {
289 m_tesselation_evaluation_shader_id = gl.createShader(GL_TESS_EVALUATION_SHADER);
290 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
291
292 compile(m_tesselation_evaluation_shader_id, tesselation_evaluation_shader_code);
293 }
294
295 if (0 != vertex_shader_code)
296 {
297 m_vertex_shader_id = gl.createShader(GL_VERTEX_SHADER);
298 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
299
300 compile(m_vertex_shader_id, vertex_shader_code);
301 }
302
303 /* Create program object */
304 m_program_object_id = gl.createProgram();
305 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateProgram");
306
307 /* Set up captyured varyings' names */
308 if (0 != n_varying_names)
309 {
310 gl.transformFeedbackVaryings(m_program_object_id, n_varying_names, varying_names, GL_INTERLEAVED_ATTRIBS);
311 GLU_EXPECT_NO_ERROR(gl.getError(), "TransformFeedbackVaryings");
312 }
313
314 /* Set separable parameter */
315 if (true == is_separable)
316 {
317 gl.programParameteri(m_program_object_id, GL_PROGRAM_SEPARABLE, GL_TRUE);
318 GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramParameteri");
319 }
320
321 /* Link program */
322 link();
323 }
324
325 /** Compile shader
326 *
327 * @param shader_id Shader object id
328 * @param shader_code Shader source code
329 **/
compile(glw::GLuint shader_id,const glw::GLchar * shader_code) const330 void Utils::program::compile(glw::GLuint shader_id, const glw::GLchar* shader_code) const
331 {
332 /* GL entry points */
333 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
334
335 /* Compilation status */
336 glw::GLint status = GL_FALSE;
337
338 /* Set source code */
339 gl.shaderSource(shader_id, 1 /* count */, &shader_code, 0);
340 GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderSource");
341
342 /* Compile */
343 gl.compileShader(shader_id);
344 GLU_EXPECT_NO_ERROR(gl.getError(), "CompileShader");
345
346 /* Get compilation status */
347 gl.getShaderiv(shader_id, GL_COMPILE_STATUS, &status);
348 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
349
350 /* Log compilation error */
351 if (GL_TRUE != status)
352 {
353 glw::GLint length = 0;
354 std::vector<glw::GLchar> message;
355
356 /* Error log length */
357 gl.getShaderiv(shader_id, GL_INFO_LOG_LENGTH, &length);
358 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
359
360 /* Prepare storage */
361 message.resize(length);
362
363 /* Get error log */
364 gl.getShaderInfoLog(shader_id, length, 0, &message[0]);
365 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderInfoLog");
366
367 /* Log */
368 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Failed to compile shader:\n"
369 << &message[0] << "\nShader source\n"
370 << shader_code << tcu::TestLog::EndMessage;
371
372 TCU_FAIL("Failed to compile shader");
373 }
374 }
375
376 /** Checks whether the tested driver supports GL_ARB_get_program_binary
377 *
378 * @return true if the extension is supported and, also, at least one binary format.
379 **/
isProgramBinarySupported() const380 bool Utils::program::isProgramBinarySupported() const
381 {
382 glw::GLint n_program_binary_formats = 0;
383
384 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
385
386 if (m_context.getContextInfo().isExtensionSupported("GL_ARB_get_program_binary"))
387 {
388 gl.getIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &n_program_binary_formats);
389 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed.");
390 }
391
392 return n_program_binary_formats > 0;
393 }
394
395 /** Create program from provided binary
396 *
397 * @param binary Buffer with binary form of program
398 * @param binary_format Format of <binary> data
399 **/
createFromBinary(const std::vector<GLubyte> & binary,GLenum binary_format)400 void Utils::program::createFromBinary(const std::vector<GLubyte>& binary, GLenum binary_format)
401 {
402 /* GL entry points */
403 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
404
405 /* Create program object */
406 m_program_object_id = gl.createProgram();
407 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateProgram");
408
409 gl.programBinary(m_program_object_id, binary_format, &binary[0], (GLsizei)binary.size());
410 GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramBinary");
411 }
412
413 /** Get binary form of program
414 *
415 * @param binary Buffer for binary data
416 * @param binary_format Format of binary data
417 **/
getBinary(std::vector<GLubyte> & binary,GLenum & binary_format) const418 void Utils::program::getBinary(std::vector<GLubyte>& binary, GLenum& binary_format) const
419 {
420 /* GL entry points */
421 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
422
423 /* Get binary size */
424 GLint length = 0;
425 gl.getProgramiv(m_program_object_id, GL_PROGRAM_BINARY_LENGTH, &length);
426 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
427
428 /* Allocate storage */
429 binary.resize(length);
430
431 /* Get binary */
432 gl.getProgramBinary(m_program_object_id, (GLsizei)binary.size(), &length, &binary_format, &binary[0]);
433 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramBinary");
434 }
435
436 /** Get subroutine index
437 *
438 * @param subroutine_name Subroutine name
439 *
440 * @return Index of subroutine
441 **/
getSubroutineIndex(const glw::GLchar * subroutine_name,glw::GLenum shader_stage) const442 GLuint Utils::program::getSubroutineIndex(const glw::GLchar* subroutine_name, glw::GLenum shader_stage) const
443 {
444 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
445 GLuint index = -1;
446
447 index = gl.getSubroutineIndex(m_program_object_id, shader_stage, subroutine_name);
448 GLU_EXPECT_NO_ERROR(gl.getError(), "GetSubroutineIndex");
449
450 if (GL_INVALID_INDEX == index)
451 {
452 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Subroutine: " << subroutine_name
453 << " is not available" << tcu::TestLog::EndMessage;
454
455 TCU_FAIL("Subroutine is not available");
456 }
457
458 return index;
459 }
460
461 /** Get subroutine uniform location
462 *
463 * @param uniform_name Subroutine uniform name
464 *
465 * @return Location of subroutine uniform
466 **/
getSubroutineUniformLocation(const glw::GLchar * uniform_name,glw::GLenum shader_stage) const467 GLint Utils::program::getSubroutineUniformLocation(const glw::GLchar* uniform_name, glw::GLenum shader_stage) const
468 {
469 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
470 GLint location = -1;
471
472 location = gl.getSubroutineUniformLocation(m_program_object_id, shader_stage, uniform_name);
473 GLU_EXPECT_NO_ERROR(gl.getError(), "GetSubroutineUniformLocation");
474
475 if (-1 == location)
476 {
477 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Subroutine uniform: " << uniform_name
478 << " is not available" << tcu::TestLog::EndMessage;
479
480 TCU_FAIL("Subroutine uniform is not available");
481 }
482
483 return location;
484 }
485
486 /** Get uniform location
487 *
488 * @param uniform_name Subroutine uniform name
489 *
490 * @return Location of uniform
491 **/
getUniformLocation(const glw::GLchar * uniform_name) const492 GLint Utils::program::getUniformLocation(const glw::GLchar* uniform_name) const
493 {
494 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
495 GLint location = -1;
496
497 location = gl.getUniformLocation(m_program_object_id, uniform_name);
498 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation");
499
500 if (-1 == location)
501 {
502 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Uniform: " << uniform_name
503 << " is not available" << tcu::TestLog::EndMessage;
504
505 TCU_FAIL("Uniform is not available");
506 }
507
508 return location;
509 }
510
511 /** Attach shaders and link program
512 *
513 **/
link() const514 void Utils::program::link() const
515 {
516 /* GL entry points */
517 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
518
519 /* Link status */
520 glw::GLint status = GL_FALSE;
521
522 /* Attach shaders */
523 if (0 != m_compute_shader_id)
524 {
525 gl.attachShader(m_program_object_id, m_compute_shader_id);
526 GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
527 }
528
529 if (0 != m_fragment_shader_id)
530 {
531 gl.attachShader(m_program_object_id, m_fragment_shader_id);
532 GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
533 }
534
535 if (0 != m_geometry_shader_id)
536 {
537 gl.attachShader(m_program_object_id, m_geometry_shader_id);
538 GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
539 }
540
541 if (0 != m_tesselation_control_shader_id)
542 {
543 gl.attachShader(m_program_object_id, m_tesselation_control_shader_id);
544 GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
545 }
546
547 if (0 != m_tesselation_evaluation_shader_id)
548 {
549 gl.attachShader(m_program_object_id, m_tesselation_evaluation_shader_id);
550 GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
551 }
552
553 if (0 != m_vertex_shader_id)
554 {
555 gl.attachShader(m_program_object_id, m_vertex_shader_id);
556 GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
557 }
558
559 /* Link */
560 gl.linkProgram(m_program_object_id);
561 GLU_EXPECT_NO_ERROR(gl.getError(), "LinkProgram");
562
563 /* Get link status */
564 gl.getProgramiv(m_program_object_id, GL_LINK_STATUS, &status);
565 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
566
567 /* Log link error */
568 if (GL_TRUE != status)
569 {
570 glw::GLint length = 0;
571 std::vector<glw::GLchar> message;
572
573 /* Get error log length */
574 gl.getProgramiv(m_program_object_id, GL_INFO_LOG_LENGTH, &length);
575 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
576
577 message.resize(length);
578
579 /* Get error log */
580 gl.getProgramInfoLog(m_program_object_id, length, 0, &message[0]);
581 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramInfoLog");
582
583 /* Log */
584 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Failed to link program:\n"
585 << &message[0] << tcu::TestLog::EndMessage;
586
587 TCU_FAIL("Failed to link program");
588 }
589 }
590
591 /** Delete program object and all attached shaders
592 *
593 **/
remove()594 void Utils::program::remove()
595 {
596 /* GL entry points */
597 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
598
599 /* Make sure program object is no longer used by GL */
600 gl.useProgram(0);
601
602 /* Clean program object */
603 if (0 != m_program_object_id)
604 {
605 gl.deleteProgram(m_program_object_id);
606 m_program_object_id = 0;
607 }
608
609 /* Clean shaders */
610 if (0 != m_compute_shader_id)
611 {
612 gl.deleteShader(m_compute_shader_id);
613 m_compute_shader_id = 0;
614 }
615
616 if (0 != m_fragment_shader_id)
617 {
618 gl.deleteShader(m_fragment_shader_id);
619 m_fragment_shader_id = 0;
620 }
621
622 if (0 != m_geometry_shader_id)
623 {
624 gl.deleteShader(m_geometry_shader_id);
625 m_geometry_shader_id = 0;
626 }
627
628 if (0 != m_tesselation_control_shader_id)
629 {
630 gl.deleteShader(m_tesselation_control_shader_id);
631 m_tesselation_control_shader_id = 0;
632 }
633
634 if (0 != m_tesselation_evaluation_shader_id)
635 {
636 gl.deleteShader(m_tesselation_evaluation_shader_id);
637 m_tesselation_evaluation_shader_id = 0;
638 }
639
640 if (0 != m_vertex_shader_id)
641 {
642 gl.deleteShader(m_vertex_shader_id);
643 m_vertex_shader_id = 0;
644 }
645 }
646
647 /** Execute UseProgram
648 *
649 **/
use() const650 void Utils::program::use() const
651 {
652 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
653
654 gl.useProgram(m_program_object_id);
655 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
656 }
657
658 /** Constructor.
659 *
660 * @param context CTS context.
661 **/
texture(deqp::Context & context)662 Utils::texture::texture(deqp::Context& context) : m_id(0), m_context(context)
663 {
664 /* Nothing to done here */
665 }
666
667 /** Destructor
668 *
669 **/
~texture()670 Utils::texture::~texture()
671 {
672 if (0 != m_id)
673 {
674 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
675
676 gl.deleteTextures(1, &m_id);
677 m_id = 0;
678 }
679 }
680
681 /** Bind texture to GL_TEXTURE_2D
682 *
683 **/
bind()684 void Utils::texture::bind()
685 {
686 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
687
688 gl.bindTexture(GL_TEXTURE_2D, m_id);
689 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
690 }
691
692 /** Create 2d texture
693 *
694 * @param width Width of texture
695 * @param height Height of texture
696 * @param internal_format Internal format of texture
697 **/
create(glw::GLuint width,glw::GLuint height,glw::GLenum internal_format)698 void Utils::texture::create(glw::GLuint width, glw::GLuint height, glw::GLenum internal_format)
699 {
700 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
701
702 gl.genTextures(1, &m_id);
703 GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures");
704
705 bind();
706
707 gl.texStorage2D(GL_TEXTURE_2D, 1 /* levels */, internal_format, width, height);
708 GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D");
709 }
710
711 /** Get contents of texture
712 *
713 * @param format Format of image
714 * @param type Type of image
715 * @param out_data Buffer for image
716 **/
get(glw::GLenum format,glw::GLenum type,glw::GLvoid * out_data)717 void Utils::texture::get(glw::GLenum format, glw::GLenum type, glw::GLvoid* out_data)
718 {
719 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
720
721 bind();
722
723 gl.getTexImage(GL_TEXTURE_2D, 0, format, type, out_data);
724 GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexImage");
725 }
726
727 /** Update contents of texture
728 *
729 * @param width Width of texture
730 * @param height Height of texture
731 * @param format Format of data
732 * @param type Type of data
733 * @param data Buffer with image
734 **/
update(glw::GLuint width,glw::GLuint height,glw::GLenum format,glw::GLenum type,glw::GLvoid * data)735 void Utils::texture::update(glw::GLuint width, glw::GLuint height, glw::GLenum format, glw::GLenum type,
736 glw::GLvoid* data)
737 {
738 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
739
740 bind();
741
742 gl.texSubImage2D(GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, width, height, format, type, data);
743 GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D");
744 }
745
746 /** Constructor.
747 *
748 * @param context CTS context.
749 **/
vertexArray(deqp::Context & context)750 Utils::vertexArray::vertexArray(deqp::Context& context) : m_id(0), m_context(context)
751 {
752 }
753
754 /** Destructor
755 *
756 **/
~vertexArray()757 Utils::vertexArray::~vertexArray()
758 {
759 if (0 != m_id)
760 {
761 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
762
763 gl.deleteVertexArrays(1, &m_id);
764
765 m_id = 0;
766 }
767 }
768
769 /** Execute BindVertexArray
770 *
771 **/
bind()772 void Utils::vertexArray::bind()
773 {
774 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
775
776 gl.bindVertexArray(m_id);
777 GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArray");
778 }
779
780 /** Execute GenVertexArrays
781 *
782 **/
generate()783 void Utils::vertexArray::generate()
784 {
785 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
786
787 gl.genVertexArrays(1, &m_id);
788 GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays");
789 }
790
791 /** Builds a program object consisting of up to 5 shader stages
792 * (vertex/tessellation control/tessellation evaluation/geometry/fragment).
793 * The shaders are attached to the program object, then compiled. Finally,
794 * the program object is linked.
795 *
796 * XFB can be optionally configured for the program object.
797 *
798 * Should an error be reported by GL implementation, a TestError
799 * exception will be thrown.
800 *
801 * @param gl OpenGL functions from the active rendering context.
802 * @param vs_body Body to use for the vertex shader. Can be an empty string.
803 * @param tc_body Body to use for the tessellation control shader. Can be
804 * an empty string.
805 * @param te_body Body to use for the tessellation evaluation shader. Can be
806 * an empty string.
807 * @param gs_body Body to use for the geometry shader. Can be an empty string.
808 * @param fs_body Body to use for the fragment shader. Can be an empty string.
809 * @param xfb_varyings An array of names of varyings to use for XFB. Can be NULL.
810 * @param n_xfb_varyings Amount of XFB varyings defined in @param xfb_varyings.Can be 0.
811 * @param out_vs_id Deref will be used to store GL id of a generated vertex shader.
812 * Can be NULL in which case no vertex shader will be used for the
813 * program object.
814 * @param out_tc_id Deref will be used to store GL id of a generated tess control shader.
815 * Can be NULL in which case no tess control shader will be used for the
816 * program object.
817 * @param out_te_id Deref will be used to store GL id of a generated tess evaluation shader.
818 * Can be NULL in which case no tess evaluation shader will be used for the
819 * program object.
820 * @param out_gs_id Deref will be used to store GL id of a generated geometry shader.
821 * Can be NULL in which case no geometry shader will be used for the
822 * program object.
823 * @param out_fs_id Deref will be used to store GL id of a generated fragment shader.
824 * Can be NULL in which case no fragment shader will be used for the
825 * program object.
826 * @param out_po_id Deref will be used to store GL id of a generated program object.
827 * Must not be NULL.
828 *
829 * @return true if the program was built successfully, false otherwise.
830 * */
buildProgram(const glw::Functions & gl,const std::string & vs_body,const std::string & tc_body,const std::string & te_body,const std::string & gs_body,const std::string & fs_body,const glw::GLchar ** xfb_varyings,const unsigned int & n_xfb_varyings,glw::GLuint * out_vs_id,glw::GLuint * out_tc_id,glw::GLuint * out_te_id,glw::GLuint * out_gs_id,glw::GLuint * out_fs_id,glw::GLuint * out_po_id)831 bool Utils::buildProgram(const glw::Functions& gl, const std::string& vs_body, const std::string& tc_body,
832 const std::string& te_body, const std::string& gs_body, const std::string& fs_body,
833 const glw::GLchar** xfb_varyings, const unsigned int& n_xfb_varyings, glw::GLuint* out_vs_id,
834 glw::GLuint* out_tc_id, glw::GLuint* out_te_id, glw::GLuint* out_gs_id, glw::GLuint* out_fs_id,
835 glw::GLuint* out_po_id)
836 {
837 bool result = false;
838
839 /* Link the program object */
840 glw::GLint link_status = GL_FALSE;
841
842 /* Create objects, set up shader bodies and attach all requested shaders to the program object */
843 *out_po_id = gl.createProgram();
844 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
845
846 if (out_vs_id != DE_NULL)
847 {
848 const char* vs_body_raw_ptr = vs_body.c_str();
849
850 *out_vs_id = gl.createShader(GL_VERTEX_SHADER);
851 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
852
853 gl.attachShader(*out_po_id, *out_vs_id);
854 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
855
856 gl.shaderSource(*out_vs_id, 1 /* count */, &vs_body_raw_ptr, DE_NULL /* length */);
857 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
858 }
859
860 if (out_tc_id != DE_NULL)
861 {
862 const char* tc_body_raw_ptr = tc_body.c_str();
863
864 *out_tc_id = gl.createShader(GL_TESS_CONTROL_SHADER);
865 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
866
867 gl.attachShader(*out_po_id, *out_tc_id);
868 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
869
870 gl.shaderSource(*out_tc_id, 1 /* count */, &tc_body_raw_ptr, DE_NULL /* length */);
871 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
872 }
873
874 if (out_te_id != DE_NULL)
875 {
876 const char* te_body_raw_ptr = te_body.c_str();
877
878 *out_te_id = gl.createShader(GL_TESS_EVALUATION_SHADER);
879 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
880
881 gl.attachShader(*out_po_id, *out_te_id);
882 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
883
884 gl.shaderSource(*out_te_id, 1 /* count */, &te_body_raw_ptr, DE_NULL /* length */);
885 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
886 }
887
888 if (out_gs_id != DE_NULL)
889 {
890 const char* gs_body_raw_ptr = gs_body.c_str();
891
892 *out_gs_id = gl.createShader(GL_GEOMETRY_SHADER);
893 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
894
895 gl.attachShader(*out_po_id, *out_gs_id);
896 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
897
898 gl.shaderSource(*out_gs_id, 1 /* count */, &gs_body_raw_ptr, DE_NULL /* length */);
899 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
900 }
901
902 if (out_fs_id != DE_NULL)
903 {
904 const char* fs_body_raw_ptr = fs_body.c_str();
905
906 *out_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
907 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
908
909 gl.attachShader(*out_po_id, *out_fs_id);
910 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
911
912 gl.shaderSource(*out_fs_id, 1 /* count */, &fs_body_raw_ptr, DE_NULL /* length */);
913 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
914 }
915
916 /* Compile all shaders */
917 const glw::GLuint so_ids[] = { (out_vs_id != DE_NULL) ? *out_vs_id : 0, (out_tc_id != DE_NULL) ? *out_tc_id : 0,
918 (out_te_id != DE_NULL) ? *out_te_id : 0, (out_gs_id != DE_NULL) ? *out_gs_id : 0,
919 (out_fs_id != DE_NULL) ? *out_fs_id : 0 };
920 const unsigned int n_so_ids = sizeof(so_ids) / sizeof(so_ids[0]);
921
922 for (unsigned int n_so_id = 0; n_so_id < n_so_ids; ++n_so_id)
923 {
924 glw::GLuint so_id = so_ids[n_so_id];
925
926 if (so_id != 0)
927 {
928 glw::GLint compile_status = GL_FALSE;
929
930 gl.compileShader(so_id);
931 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
932
933 gl.getShaderiv(so_id, GL_COMPILE_STATUS, &compile_status);
934 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
935
936 if (compile_status != GL_TRUE)
937 {
938 goto end;
939 }
940 } /* if (so_id != 0) */
941 } /* for (all shader objects) */
942
943 /* Set up XFB */
944 if (xfb_varyings != NULL)
945 {
946 gl.transformFeedbackVaryings(*out_po_id, n_xfb_varyings, xfb_varyings, GL_INTERLEAVED_ATTRIBS);
947 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed.");
948 }
949
950 gl.linkProgram(*out_po_id);
951 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
952
953 gl.getProgramiv(*out_po_id, GL_LINK_STATUS, &link_status);
954 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
955
956 if (link_status != GL_TRUE)
957 {
958 goto end;
959 }
960
961 /* All done */
962 result = true;
963
964 end:
965 return result;
966 }
967
968 /** Retrieves base variable type for user-specified variable type
969 * (eg. float for vec4)
970 *
971 * @param variable_type Variable type to use for the query.
972 *
973 * @return As per description.
974 **/
getBaseVariableType(const _variable_type & variable_type)975 Utils::_variable_type Utils::getBaseVariableType(const _variable_type& variable_type)
976 {
977 _variable_type result = VARIABLE_TYPE_UNKNOWN;
978
979 switch (variable_type)
980 {
981 case VARIABLE_TYPE_BOOL:
982 case VARIABLE_TYPE_BVEC2:
983 case VARIABLE_TYPE_BVEC3:
984 case VARIABLE_TYPE_BVEC4:
985 {
986 result = VARIABLE_TYPE_BOOL;
987
988 break;
989 }
990
991 case VARIABLE_TYPE_DOUBLE:
992 case VARIABLE_TYPE_DVEC2:
993 case VARIABLE_TYPE_DVEC3:
994 case VARIABLE_TYPE_DVEC4:
995 {
996 result = VARIABLE_TYPE_DOUBLE;
997
998 break;
999 }
1000
1001 case VARIABLE_TYPE_FLOAT:
1002 case VARIABLE_TYPE_MAT2:
1003 case VARIABLE_TYPE_MAT2X3:
1004 case VARIABLE_TYPE_MAT2X4:
1005 case VARIABLE_TYPE_MAT3:
1006 case VARIABLE_TYPE_MAT3X2:
1007 case VARIABLE_TYPE_MAT3X4:
1008 case VARIABLE_TYPE_MAT4:
1009 case VARIABLE_TYPE_MAT4X2:
1010 case VARIABLE_TYPE_MAT4X3:
1011 case VARIABLE_TYPE_VEC2:
1012 case VARIABLE_TYPE_VEC3:
1013 case VARIABLE_TYPE_VEC4:
1014 {
1015 result = VARIABLE_TYPE_FLOAT;
1016
1017 break;
1018 }
1019
1020 case VARIABLE_TYPE_INT:
1021 case VARIABLE_TYPE_IVEC2:
1022 case VARIABLE_TYPE_IVEC3:
1023 case VARIABLE_TYPE_IVEC4:
1024 {
1025 result = VARIABLE_TYPE_INT;
1026
1027 break;
1028 }
1029
1030 case VARIABLE_TYPE_UINT:
1031 case VARIABLE_TYPE_UVEC2:
1032 case VARIABLE_TYPE_UVEC3:
1033 case VARIABLE_TYPE_UVEC4:
1034 {
1035 result = VARIABLE_TYPE_UINT;
1036
1037 break;
1038 }
1039
1040 default:
1041 {
1042 TCU_FAIL("Unrecognized variable type");
1043 }
1044 } /* switch (variable_type) */
1045
1046 return result;
1047 }
1048
1049 /** Retrieves size of a single component (in bytes) for user-specified
1050 * variable type.
1051 *
1052 * @param variable_type Variable type to use for the query.
1053 *
1054 * @return As per description.
1055 **/
getComponentSizeForVariableType(const _variable_type & variable_type)1056 unsigned int Utils::getComponentSizeForVariableType(const _variable_type& variable_type)
1057 {
1058 _variable_type base_variable_type = getBaseVariableType(variable_type);
1059 unsigned int result = 0;
1060
1061 switch (base_variable_type)
1062 {
1063 case VARIABLE_TYPE_BOOL:
1064 result = sizeof(bool);
1065 break;
1066 case VARIABLE_TYPE_DOUBLE:
1067 result = sizeof(double);
1068 break;
1069 case VARIABLE_TYPE_FLOAT:
1070 result = sizeof(float);
1071 break;
1072 case VARIABLE_TYPE_INT:
1073 result = sizeof(int);
1074 break;
1075 case VARIABLE_TYPE_UINT:
1076 result = sizeof(unsigned int);
1077 break;
1078
1079 default:
1080 {
1081 TCU_FAIL("Unrecognized base variable type");
1082 }
1083 } /* switch (variable_type) */
1084
1085 return result;
1086 }
1087
1088 /** Retrieves a GLenum value corresponding to internal shader stage
1089 * representation.
1090 *
1091 * @param shader_stage Shader stage to user for the query.
1092 *
1093 * @return Requested value or GL_NONE if the stage was not recognized.
1094 **/
getGLenumForShaderStage(const _shader_stage & shader_stage)1095 glw::GLenum Utils::getGLenumForShaderStage(const _shader_stage& shader_stage)
1096 {
1097 glw::GLenum result = GL_NONE;
1098
1099 switch (shader_stage)
1100 {
1101 case SHADER_STAGE_VERTEX:
1102 result = GL_VERTEX_SHADER;
1103 break;
1104 case SHADER_STAGE_TESSELLATION_CONTROL:
1105 result = GL_TESS_CONTROL_SHADER;
1106 break;
1107 case SHADER_STAGE_TESSELLATION_EVALUATION:
1108 result = GL_TESS_EVALUATION_SHADER;
1109 break;
1110 case SHADER_STAGE_GEOMETRY:
1111 result = GL_GEOMETRY_SHADER;
1112 break;
1113 case SHADER_STAGE_FRAGMENT:
1114 result = GL_FRAGMENT_SHADER;
1115 break;
1116
1117 default:
1118 {
1119 TCU_FAIL("Unrecognized shader stage requested");
1120 }
1121 } /* switch (shader_stage) */
1122
1123 return result;
1124 }
1125
1126 /** Retrieves number of components that user-specified variable type supports.
1127 *
1128 * @param variable_type GLSL variable type to use for the query.
1129 *
1130 * @return As per description.
1131 **/
getNumberOfComponentsForVariableType(const _variable_type & variable_type)1132 unsigned int Utils::getNumberOfComponentsForVariableType(const _variable_type& variable_type)
1133 {
1134 unsigned int result = 0;
1135
1136 switch (variable_type)
1137 {
1138 case VARIABLE_TYPE_BOOL:
1139 case VARIABLE_TYPE_DOUBLE:
1140 case VARIABLE_TYPE_FLOAT:
1141 case VARIABLE_TYPE_INT:
1142 case VARIABLE_TYPE_UINT:
1143 {
1144 result = 1;
1145
1146 break;
1147 }
1148
1149 case VARIABLE_TYPE_BVEC2:
1150 case VARIABLE_TYPE_DVEC2:
1151 case VARIABLE_TYPE_IVEC2:
1152 case VARIABLE_TYPE_UVEC2:
1153 case VARIABLE_TYPE_VEC2:
1154 {
1155 result = 2;
1156
1157 break;
1158 }
1159
1160 case VARIABLE_TYPE_BVEC3:
1161 case VARIABLE_TYPE_DVEC3:
1162 case VARIABLE_TYPE_IVEC3:
1163 case VARIABLE_TYPE_UVEC3:
1164 case VARIABLE_TYPE_VEC3:
1165 {
1166 result = 3;
1167
1168 break;
1169 }
1170
1171 case VARIABLE_TYPE_BVEC4:
1172 case VARIABLE_TYPE_DVEC4:
1173 case VARIABLE_TYPE_IVEC4:
1174 case VARIABLE_TYPE_MAT2:
1175 case VARIABLE_TYPE_UVEC4:
1176 case VARIABLE_TYPE_VEC4:
1177 {
1178 result = 4;
1179
1180 break;
1181 }
1182
1183 case VARIABLE_TYPE_MAT2X3:
1184 case VARIABLE_TYPE_MAT3X2:
1185 {
1186 result = 6;
1187
1188 break;
1189 }
1190
1191 case VARIABLE_TYPE_MAT2X4:
1192 case VARIABLE_TYPE_MAT4X2:
1193 {
1194 result = 8;
1195
1196 break;
1197 }
1198
1199 case VARIABLE_TYPE_MAT3:
1200 {
1201 result = 9;
1202
1203 break;
1204 }
1205
1206 case VARIABLE_TYPE_MAT3X4:
1207 case VARIABLE_TYPE_MAT4X3:
1208 {
1209 result = 12;
1210
1211 break;
1212 }
1213
1214 case VARIABLE_TYPE_MAT4:
1215 {
1216 result = 16;
1217
1218 break;
1219 }
1220
1221 default:
1222 break;
1223 } /* switch (variable_type) */
1224
1225 return result;
1226 }
1227
1228 /** Retrieves a literal defining user-specified shader stage enum.
1229 *
1230 * @param shader_stage Shader stage to use for the query.
1231 *
1232 * @return Requested string or "?" if the stage was not recognized.
1233 **/
getShaderStageString(const _shader_stage & shader_stage)1234 std::string Utils::getShaderStageString(const _shader_stage& shader_stage)
1235 {
1236 std::string result = "?";
1237
1238 switch (shader_stage)
1239 {
1240 case SHADER_STAGE_FRAGMENT:
1241 result = "Fragment Shader";
1242 break;
1243 case SHADER_STAGE_GEOMETRY:
1244 result = "Geometry Shader";
1245 break;
1246 case SHADER_STAGE_TESSELLATION_CONTROL:
1247 result = "Tessellation Control Shader";
1248 break;
1249 case SHADER_STAGE_TESSELLATION_EVALUATION:
1250 result = "Tessellation Evaluation Shader";
1251 break;
1252 case SHADER_STAGE_VERTEX:
1253 result = "Vertex Shader";
1254 break;
1255
1256 default:
1257 {
1258 TCU_FAIL("Unrecognized shader stage");
1259 }
1260 } /* switch (shader_stage) */
1261
1262 return result;
1263 }
1264
1265 /** Retrieves a literal defining user-specified shader stage enum.
1266 *
1267 * @param shader_stage_glenum Shader stage to use for the query.
1268 *
1269 * @return Requested string or "?" if the stage was not recognized.
1270 **/
getShaderStageStringFromGLEnum(const glw::GLenum shader_stage_glenum)1271 std::string Utils::getShaderStageStringFromGLEnum(const glw::GLenum shader_stage_glenum)
1272 {
1273 std::string result = "?";
1274
1275 switch (shader_stage_glenum)
1276 {
1277 case GL_FRAGMENT_SHADER:
1278 result = "Fragment Shader";
1279 break;
1280 case GL_GEOMETRY_SHADER:
1281 result = "Geometry Shader";
1282 break;
1283 case GL_TESS_CONTROL_SHADER:
1284 result = "Tessellation Control Shader";
1285 break;
1286 case GL_TESS_EVALUATION_SHADER:
1287 result = "Tessellation Evaluation Shader";
1288 break;
1289 case GL_VERTEX_SHADER:
1290 result = "Vertex Shader";
1291 break;
1292
1293 default:
1294 {
1295 TCU_FAIL("Unrecognized shader string");
1296 }
1297 } /* switch (shader_stage_glenum) */
1298
1299 return result;
1300 }
1301
1302 /** Returns string that represents program interface name
1303 *
1304 * @param program_interface Program interface
1305 *
1306 * @return String representation of known program interface
1307 **/
programInterfaceToStr(glw::GLenum program_interface)1308 const GLchar* Utils::programInterfaceToStr(glw::GLenum program_interface)
1309 {
1310 const GLchar* string = "Unknown program interface";
1311
1312 switch (program_interface)
1313 {
1314 case GL_VERTEX_SUBROUTINE:
1315 string = "GL_VERTEX_SUBROUTINE";
1316 break;
1317 case GL_VERTEX_SUBROUTINE_UNIFORM:
1318 string = "GL_VERTEX_SUBROUTINE_UNIFORM";
1319 break;
1320 default:
1321 TCU_FAIL("Not implemented");
1322 }
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", "Verifies the implementation returns valid GL_MAX_SUBROUTINE* pnames "
1676 "which meet the minimum maximum requirements enforced by the spec.")
1677 , m_has_test_passed(true)
1678 {
1679 /* Left blank intentionally */
1680 }
1681
1682 /** Executes test iteration.
1683 *
1684 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
1685 */
iterate()1686 tcu::TestNode::IterateResult APITest1::iterate()
1687 {
1688 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1689
1690 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
1691 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
1692 {
1693 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
1694 }
1695
1696 /* Iterate over all pnames */
1697 const struct
1698 {
1699 glw::GLenum pname;
1700 const char* pname_string;
1701 glw::GLint min_value;
1702 } pnames[] = { { GL_MAX_SUBROUTINES, "GL_MAX_SUBROUTINES", 256 },
1703 { GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS, "GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS", 1024 } };
1704 const unsigned int n_pnames = sizeof(pnames) / sizeof(pnames[0]);
1705
1706 for (unsigned int n_pname = 0; n_pname < n_pnames; ++n_pname)
1707 {
1708 glw::GLboolean bool_value = GL_FALSE;
1709 glw::GLdouble double_value = 0.0;
1710 glw::GLfloat float_value = 0.0f;
1711 glw::GLint int_value = 0;
1712 glw::GLint64 int64_value = 0;
1713 const glw::GLint min_value = pnames[n_pname].min_value;
1714 const glw::GLenum& pname = pnames[n_pname].pname;
1715 const char* pname_string = pnames[n_pname].pname_string;
1716
1717 /* Retrieve the pname values */
1718 gl.getBooleanv(pname, &bool_value);
1719 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetBooleanv() call failed.");
1720
1721 gl.getDoublev(pname, &double_value);
1722 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetDoublev() call failed.");
1723
1724 gl.getFloatv(pname, &float_value);
1725 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv() call failed.");
1726
1727 gl.getIntegerv(pname, &int_value);
1728 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed.");
1729
1730 gl.getInteger64v(pname, &int64_value);
1731 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInteger64v() call failed.");
1732
1733 /* Make sure the value reported meets the min max requirement */
1734 if (int_value < min_value)
1735 {
1736 m_testCtx.getLog() << tcu::TestLog::Message << "GL implementation reports a value of [" << int_value
1737 << "]"
1738 " for property ["
1739 << pname_string << "]"
1740 ", whereas the min max for the property is ["
1741 << min_value << "]." << tcu::TestLog::EndMessage;
1742
1743 m_has_test_passed = false;
1744 }
1745
1746 /* Verify the other getters reported valid values */
1747 const float epsilon = 1e-5f;
1748
1749 if (((int_value == 0) && (bool_value == GL_TRUE)) || ((int_value != 0) && (bool_value != GL_TRUE)))
1750 {
1751 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid boolean value [" << bool_value
1752 << "]"
1753 " reported for property ["
1754 << pname_string << "]"
1755 " (int value:["
1756 << int_value << "])" << tcu::TestLog::EndMessage;
1757
1758 m_has_test_passed = false;
1759 }
1760
1761 if (de::abs(double_value - (double)int_value) > epsilon)
1762 {
1763 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid double value [" << double_value
1764 << "]"
1765 " reported for property ["
1766 << pname_string << "]"
1767 " (int value:["
1768 << int_value << "])" << tcu::TestLog::EndMessage;
1769
1770 m_has_test_passed = false;
1771 }
1772
1773 if (de::abs(float_value - (float)int_value) > epsilon)
1774 {
1775 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid float value [" << float_value
1776 << "]"
1777 " reported for property ["
1778 << pname_string << "]"
1779 " (int value:["
1780 << int_value << "])" << tcu::TestLog::EndMessage;
1781
1782 m_has_test_passed = false;
1783 }
1784
1785 if (int64_value != int_value)
1786 {
1787 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid 64-bit integer value [" << float_value
1788 << "]"
1789 " reported for property ["
1790 << pname_string << "]"
1791 " (int value:["
1792 << int_value << "])" << tcu::TestLog::EndMessage;
1793
1794 m_has_test_passed = false;
1795 }
1796 } /* for (all pnames) */
1797
1798 if (m_has_test_passed)
1799 {
1800 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1801 }
1802 else
1803 {
1804 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1805 }
1806
1807 return STOP;
1808 }
1809
1810 /** Constructor.
1811 *
1812 * @param context Rendering context.
1813 *
1814 **/
APITest2(deqp::Context & context)1815 APITest2::APITest2(deqp::Context& context)
1816 : TestCase(context, "name_getters", "Verifies glGetActiveSubroutineName() and glGetActiveSubroutineUniformName() "
1817 "functions work correctly.")
1818 , m_buffer(DE_NULL)
1819 , m_has_test_passed(true)
1820 , m_po_id(0)
1821 , m_subroutine_name1("subroutine1")
1822 , m_subroutine_name2("subroutine2")
1823 , m_subroutine_uniform_name("data_provider")
1824 , m_vs_id(0)
1825 {
1826 /* Left blank intentionally */
1827 }
1828
1829 /** Destroys all ES objects that may have been created during test initialization,
1830 * as well as releases any buffers that may have been allocated during the process.
1831 */
deinit()1832 void APITest2::deinit()
1833 {
1834 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1835
1836 if (m_buffer != DE_NULL)
1837 {
1838 delete[] m_buffer;
1839
1840 m_buffer = DE_NULL;
1841 }
1842
1843 if (m_po_id != 0)
1844 {
1845 gl.deleteProgram(m_po_id);
1846
1847 m_po_id = 0;
1848 }
1849
1850 if (m_vs_id != 0)
1851 {
1852 gl.deleteShader(m_vs_id);
1853
1854 m_vs_id = 0;
1855 }
1856 }
1857
1858 /** Returns body of a vertex shader that should be used for the test.
1859 *
1860 * @return As per description.
1861 **/
getVertexShaderBody()1862 std::string APITest2::getVertexShaderBody()
1863 {
1864 return "#version 400\n"
1865 "\n"
1866 "#extension GL_ARB_shader_subroutine : require\n"
1867 "\n"
1868 "subroutine int ExampleSubroutineType(int example_argument);\n"
1869 "\n"
1870 "subroutine(ExampleSubroutineType) int subroutine1(int example_argument)\n"
1871 "{\n"
1872 " return 1;\n"
1873 "}\n"
1874 "\n"
1875 "subroutine(ExampleSubroutineType) int subroutine2(int example_argument)\n"
1876 "{\n"
1877 " return 2;\n"
1878 "}\n"
1879 "\n"
1880 "subroutine uniform ExampleSubroutineType data_provider;\n"
1881 "\n"
1882 "void main()\n"
1883 "{\n"
1884 " gl_Position = vec4(float(data_provider(0)), vec3(1) );\n"
1885 "}\n";
1886 }
1887
1888 /** Initializes all ES objects required to run the test. */
initTest()1889 void APITest2::initTest()
1890 {
1891 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1892
1893 /* Generate program & shader objects */
1894 m_po_id = gl.createProgram();
1895 m_vs_id = gl.createShader(GL_VERTEX_SHADER);
1896
1897 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() or glCreateShader() call(s) failed.");
1898
1899 /* Attach the shader to the program object */
1900 gl.attachShader(m_po_id, m_vs_id);
1901 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
1902
1903 /* Compile the shader */
1904 glw::GLint compile_status = GL_FALSE;
1905 std::string vs_body = getVertexShaderBody();
1906 const char* vs_body_raw_ptr = vs_body.c_str();
1907
1908 gl.shaderSource(m_vs_id, 1 /* count */, &vs_body_raw_ptr, DE_NULL /* length */);
1909 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
1910
1911 gl.compileShader(m_vs_id);
1912 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
1913
1914 gl.getShaderiv(m_vs_id, GL_COMPILE_STATUS, &compile_status);
1915 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
1916
1917 if (compile_status != GL_TRUE)
1918 {
1919 TCU_FAIL("Shader compilation failed.");
1920 }
1921
1922 /* Try to link the program object */
1923 glw::GLint link_status = GL_FALSE;
1924
1925 gl.linkProgram(m_po_id);
1926 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
1927
1928 gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
1929 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
1930
1931 if (link_status != GL_TRUE)
1932 {
1933 TCU_FAIL("Program linking failed.");
1934 }
1935
1936 /* Perform a few sanity checks */
1937 glw::GLint n_active_subroutines = 0;
1938 glw::GLint n_active_subroutine_uniforms = 0;
1939
1940 gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINES, &n_active_subroutines);
1941 gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORMS, &n_active_subroutine_uniforms);
1942 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramStageiv() call failed.");
1943
1944 if (n_active_subroutines != 2 /* subroutines declared in vertex shader */)
1945 {
1946 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid amount of active subroutines reported; expected: 2,"
1947 " reported:"
1948 << n_active_subroutines << tcu::TestLog::EndMessage;
1949
1950 TCU_FAIL("Invalid GL_ACTIVE_SUBROUTINES property value.");
1951 }
1952
1953 if (n_active_subroutine_uniforms != 1)
1954 {
1955 m_testCtx.getLog() << tcu::TestLog::Message
1956 << "Invalid amount of active subroutine uniforms reported: expected: 1,"
1957 " reported: "
1958 << n_active_subroutine_uniforms << tcu::TestLog::EndMessage;
1959
1960 TCU_FAIL("Invalid GL_ACTIVE_SUBROUTINE_UNIFORMS property value.");
1961 }
1962 }
1963
1964 /** Executes test iteration.
1965 *
1966 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
1967 */
iterate()1968 tcu::TestNode::IterateResult APITest2::iterate()
1969 {
1970 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
1971 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
1972 {
1973 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
1974 }
1975
1976 /* Initialize a test program object */
1977 initTest();
1978
1979 /* Verify glGetActiveSubroutineName() works correctly */
1980 verifyGLGetActiveSubroutineNameFunctionality();
1981
1982 /* Verify glGetActiveSubroutineUniformName() works correctly */
1983 verifyGLGetActiveSubroutineUniformNameFunctionality();
1984
1985 /* Done */
1986 if (m_has_test_passed)
1987 {
1988 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1989 }
1990 else
1991 {
1992 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1993 }
1994
1995 return STOP;
1996 }
1997
1998 /** Verifies glGetActiveSubroutineName() behaves as per GL_ARB_shader_subroutine
1999 * specification.
2000 **/
verifyGLGetActiveSubroutineNameFunctionality()2001 void APITest2::verifyGLGetActiveSubroutineNameFunctionality()
2002 {
2003 GLsizei expected_length1 = (GLsizei)strlen(m_subroutine_name1) + 1;
2004 GLsizei expected_length2 = (GLsizei)strlen(m_subroutine_name1) + 1;
2005 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2006 GLsizei reported_length = 0;
2007
2008 gl.getActiveSubroutineName(m_po_id, GL_VERTEX_SHADER, 0, /* index */
2009 0, /* bufsize */
2010 DE_NULL, /* length */
2011 DE_NULL); /* name */
2012 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineName() call failed.");
2013
2014 gl.getProgramInterfaceiv(m_po_id, GL_VERTEX_SUBROUTINE, GL_MAX_NAME_LENGTH, &reported_length);
2015 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineName() call failed.");
2016
2017 if ((reported_length != expected_length1) && (reported_length != expected_length2))
2018 {
2019 m_testCtx.getLog() << tcu::TestLog::Message
2020 << "Invalid active subroutine name length reported:" << reported_length
2021 << ", instead of: " << expected_length1 << " or " << expected_length2
2022 << tcu::TestLog::EndMessage;
2023
2024 TCU_FAIL("Incorrect length of active subroutine name");
2025 }
2026
2027 m_buffer = new glw::GLchar[reported_length];
2028
2029 memset(m_buffer, 0, reported_length);
2030
2031 gl.getActiveSubroutineName(m_po_id, GL_VERTEX_SHADER, 0, reported_length, DE_NULL, /* length */
2032 m_buffer);
2033 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineName() call failed.");
2034
2035 if (strcmp(m_buffer, m_subroutine_name1) != 0 && strcmp(m_buffer, m_subroutine_name2) != 0)
2036 {
2037 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid active subroutine name reported:[" << m_buffer
2038 << "]"
2039 " instead of:["
2040 << m_subroutine_name1 << "]"
2041 " or:["
2042 << m_subroutine_name2 << "]." << tcu::TestLog::EndMessage;
2043
2044 TCU_FAIL("Invalid active subroutine name reported.");
2045 }
2046
2047 delete[] m_buffer;
2048 m_buffer = DE_NULL;
2049 }
2050
2051 /** Verifies glGetActiveSubroutineUniformName() behaves as per GL_ARB_shader_subroutine
2052 * specification.
2053 **/
verifyGLGetActiveSubroutineUniformNameFunctionality()2054 void APITest2::verifyGLGetActiveSubroutineUniformNameFunctionality()
2055 {
2056 GLsizei expected_length = (GLsizei)strlen(m_subroutine_uniform_name);
2057 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2058 GLsizei reported_length = 0;
2059
2060 gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, 0, /* index */
2061 0, /* bufsize */
2062 DE_NULL, /* length */
2063 DE_NULL); /* name */
2064 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineUniformName() call failed.");
2065
2066 gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, 0, /* index */
2067 0, /* bufsize */
2068 &reported_length, DE_NULL); /* name */
2069 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineUniformName() call failed.");
2070
2071 // reported_length is the actual number of characters written into <name>
2072 // If <bufSize> is 0, reported_length should be 0
2073 if (reported_length != 0)
2074 {
2075 m_testCtx.getLog() << tcu::TestLog::Message
2076 << "Invalid active subroutine uniform name length reported:" << reported_length
2077 << ", instead of: " << 0 << tcu::TestLog::EndMessage;
2078
2079 TCU_FAIL("Incorrect length of active subroutine uniform name");
2080 }
2081
2082 m_buffer = new glw::GLchar[expected_length + 1];
2083
2084 memset(m_buffer, 0, expected_length + 1);
2085
2086 gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, 0, expected_length + 1, &reported_length, m_buffer);
2087 GLU_EXPECT_NO_ERROR(gl.getError(), "getActiveSubroutineUniformName() call failed.");
2088
2089 if (reported_length != expected_length)
2090 {
2091 m_testCtx.getLog() << tcu::TestLog::Message
2092 << "Invalid active subroutine uniform name length reported:" << reported_length
2093 << ", instead of: " << expected_length << tcu::TestLog::EndMessage;
2094
2095 TCU_FAIL("Incorrect length of active subroutine uniform name");
2096 }
2097
2098 if (strcmp(m_buffer, m_subroutine_uniform_name) != 0)
2099 {
2100 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid active subroutine uniform name reported:[" << m_buffer
2101 << "]"
2102 " instead of:["
2103 << m_subroutine_uniform_name << "]" << tcu::TestLog::EndMessage;
2104
2105 TCU_FAIL("Invalid active subroutine uniform name reported.");
2106 }
2107
2108 delete[] m_buffer;
2109 m_buffer = DE_NULL;
2110 }
2111
2112 /** Constructor.
2113 *
2114 * @param context Rendering context.
2115 *
2116 **/
FunctionalTest1_2(deqp::Context & context)2117 FunctionalTest1_2::FunctionalTest1_2(deqp::Context& context)
2118 : TestCase(context, "two_subroutines_single_subroutine_uniform",
2119 "Verifies the subroutines work correctly in a vertex shader for"
2120 " bool/float/int/uint/double/*vec*/*mat* argument and return types")
2121 , m_has_test_passed(true)
2122 , m_po_id(0)
2123 , m_po_getter0_subroutine_index(GL_INVALID_INDEX)
2124 , m_po_getter1_subroutine_index(GL_INVALID_INDEX)
2125 , m_po_subroutine_uniform_index(-1)
2126 , m_xfb_bo_id(0)
2127 , m_vao_id(0)
2128 , m_vs_id(0)
2129 {
2130 /* Left blank intentionally */
2131 }
2132
2133 /** Destroys all ES objects that may have been created during test initialization,
2134 * as well as releases any buffers that may have been allocated during the process.
2135 */
deinit()2136 void FunctionalTest1_2::deinit()
2137 {
2138 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2139
2140 deinitTestIteration();
2141
2142 if (m_xfb_bo_id != 0)
2143 {
2144 gl.deleteBuffers(1, &m_xfb_bo_id);
2145
2146 m_xfb_bo_id = 0;
2147 }
2148
2149 if (m_vao_id != 0)
2150 {
2151 gl.deleteVertexArrays(1, &m_vao_id);
2152
2153 m_vao_id = 0;
2154 }
2155 }
2156
2157 /** Deinitializes GL objects that are iteration-specific */
deinitTestIteration()2158 void FunctionalTest1_2::deinitTestIteration()
2159 {
2160 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2161
2162 if (m_po_id != 0)
2163 {
2164 gl.deleteProgram(m_po_id);
2165
2166 m_po_id = 0;
2167 }
2168
2169 if (m_vs_id != 0)
2170 {
2171 gl.deleteShader(m_vs_id);
2172
2173 m_vs_id = 0;
2174 }
2175 }
2176
2177 /** Executes a single test iteration using user-specified test case propertiesz.
2178 *
2179 * @param test-case Test case descriptor.
2180 *
2181 * @return true if the test iteration passed, false otherwise.
2182 **/
executeTestIteration(const _test_case & test_case)2183 bool FunctionalTest1_2::executeTestIteration(const _test_case& test_case)
2184 {
2185 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2186 bool result = true;
2187
2188 /* Build the test program */
2189 std::string empty_body;
2190 std::string vs_body = getVertexShaderBody(test_case.variable_type, test_case.array_size);
2191 const glw::GLchar* xfb_varyings[] = { "result" };
2192 const unsigned int n_xfb_varyings = sizeof(xfb_varyings) / sizeof(xfb_varyings[0]);
2193
2194 if (!Utils::buildProgram(gl, vs_body, empty_body, empty_body, empty_body, empty_body, xfb_varyings, n_xfb_varyings,
2195 &m_vs_id, NULL, /* out_tc_id */
2196 NULL, /* out_te_id */
2197 NULL, /* out_gs_id */
2198 NULL, &m_po_id))
2199 {
2200 TCU_FAIL("Test program failed to build.");
2201 }
2202
2203 /* Retrieve subroutine locations */
2204 m_po_getter0_subroutine_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "getter0");
2205 m_po_getter1_subroutine_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "getter1");
2206
2207 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineIndex() call(s) failed.");
2208
2209 if (m_po_getter0_subroutine_index == GL_INVALID_INDEX || m_po_getter1_subroutine_index == GL_INVALID_INDEX)
2210 {
2211 TCU_FAIL("At least one subroutine is considered inactive which is invalid.");
2212 }
2213
2214 /* Retrieve subroutine uniform location */
2215 m_po_subroutine_uniform_index = gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "colorGetterUniform");
2216
2217 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineUniformLocation() call failed.");
2218
2219 if (m_po_subroutine_uniform_index == -1)
2220 {
2221 TCU_FAIL("Subroutine uniform is considered inactive which is invalid.");
2222 }
2223
2224 /* Set up XFB BO storage */
2225 const Utils::_variable_type base_variable_type = Utils::getBaseVariableType(test_case.variable_type);
2226 unsigned int iteration_xfb_bo_size = Utils::getComponentSizeForVariableType(base_variable_type) *
2227 Utils::getNumberOfComponentsForVariableType(test_case.variable_type);
2228 unsigned int total_xfb_bo_size = 0;
2229
2230 if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2231 {
2232 /* Boolean varyings are not supported by OpenGL. Instead, we use ints to output
2233 * boolean values. */
2234 iteration_xfb_bo_size = static_cast<unsigned int>(iteration_xfb_bo_size * sizeof(int));
2235 }
2236
2237 total_xfb_bo_size = iteration_xfb_bo_size * 2 /* subroutines we will be testing */;
2238
2239 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, total_xfb_bo_size, DE_NULL /* data */, GL_STATIC_DRAW);
2240 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
2241
2242 /* Activate test program object */
2243 gl.useProgram(m_po_id);
2244 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
2245
2246 /* Run two iterations. Each iteration should invoke different subroutine. */
2247 const glw::GLuint subroutine_indices[] = { m_po_getter0_subroutine_index, m_po_getter1_subroutine_index };
2248 const unsigned int n_subroutine_indices = sizeof(subroutine_indices) / sizeof(subroutine_indices[0]);
2249
2250 for (unsigned int n_subroutine_index = 0; n_subroutine_index < n_subroutine_indices; ++n_subroutine_index)
2251 {
2252 /* Configure which subroutine should be used for the draw call */
2253 glw::GLuint current_subroutine_index = subroutine_indices[n_subroutine_index];
2254
2255 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, 1 /* count */, ¤t_subroutine_index);
2256 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniformSubroutinesuiv() call failed.");
2257
2258 /* Update XFB binding so that we do not overwrite data XFBed in previous iterations */
2259 gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
2260 m_xfb_bo_id, iteration_xfb_bo_size * n_subroutine_index, iteration_xfb_bo_size);
2261 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange() call failed.");
2262
2263 /* Draw a single point */
2264 gl.beginTransformFeedback(GL_POINTS);
2265 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed.");
2266 {
2267 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
2268 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
2269 }
2270 gl.endTransformFeedback();
2271 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed.");
2272 } /* for (all subroutine indices) */
2273
2274 /* Map the BO storage into process space */
2275 const void* xfb_data_ptr = gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
2276 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer() call failed.");
2277
2278 result &= verifyXFBData(xfb_data_ptr, test_case.variable_type);
2279
2280 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
2281 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffeR() call failed.");
2282
2283 return result;
2284 }
2285
2286 /** Retrieves body of a vertex shader that should be used to verify
2287 * subroutine support, given user-specified test iteration properties.
2288 *
2289 * @param variable_type GLSL type that should be used for argument and
2290 * return type definition in a subroutine. This setting
2291 * also affects type of the only output variable in the shader.
2292 * @param array_size 1 if non-arrayed arguments/return types should be tested;
2293 * 2 if arrayed arguments/return types should be tested.
2294 *
2295 * @return Requested string.
2296 **/
getVertexShaderBody(const Utils::_variable_type & variable_type,unsigned int array_size)2297 std::string FunctionalTest1_2::getVertexShaderBody(const Utils::_variable_type& variable_type, unsigned int array_size)
2298 {
2299 Utils::_variable_type base_variable_type = Utils::getBaseVariableType(variable_type);
2300 unsigned int n_variable_type_components = Utils::getNumberOfComponentsForVariableType(variable_type);
2301 std::stringstream result_sstream;
2302 std::string variable_type_glsl = Utils::getVariableTypeGLSLString(variable_type);
2303 std::stringstream variable_type_glsl_array_sstream;
2304 std::stringstream variable_type_glsl_arrayed_sstream;
2305
2306 variable_type_glsl_arrayed_sstream << variable_type_glsl;
2307
2308 if (array_size > 1)
2309 {
2310 variable_type_glsl_array_sstream << "[" << array_size << "]";
2311 variable_type_glsl_arrayed_sstream << variable_type_glsl_array_sstream.str();
2312 }
2313
2314 /* Form pre-amble */
2315 result_sstream << "#version 400\n"
2316 "\n"
2317 "#extension GL_ARB_shader_subroutine : require\n";
2318
2319 if (variable_type == Utils::VARIABLE_TYPE_DOUBLE)
2320 {
2321 result_sstream << "#extension GL_ARB_gpu_shader_fp64 : require\n";
2322 }
2323
2324 /* Form subroutine type declaration */
2325 result_sstream << "\n"
2326 "subroutine "
2327 << variable_type_glsl_arrayed_sstream.str() << " colorGetter(in " << variable_type_glsl
2328 << " in_value" << variable_type_glsl_array_sstream.str() << ");\n"
2329 "\n";
2330
2331 /* Declare getter functions */
2332 for (int n_getter = 0; n_getter < 2; ++n_getter)
2333 {
2334 result_sstream << "subroutine(colorGetter) " << variable_type_glsl_arrayed_sstream.str() << " getter"
2335 << n_getter << "(in " << variable_type_glsl << " in_value"
2336 << variable_type_glsl_array_sstream.str() << ")\n"
2337 "{\n";
2338
2339 if (array_size > 1)
2340 {
2341 result_sstream << variable_type_glsl << " temp" << variable_type_glsl_array_sstream.str() << ";\n";
2342 }
2343
2344 if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2345 {
2346 if (array_size > 1)
2347 {
2348 for (unsigned int array_index = 0; array_index < array_size; ++array_index)
2349 {
2350 result_sstream << " temp[" << array_index << "]"
2351 " = "
2352 << ((n_getter == 0) ? ((variable_type_glsl == "bool") ? "!" : "not") : "")
2353 << "(in_value[" << array_index << "]);\n";
2354 }
2355
2356 result_sstream << " return temp;\n";
2357 }
2358 else
2359 {
2360 result_sstream << " return "
2361 << ((n_getter == 0) ? ((variable_type_glsl == "bool") ? "!" : "not") : "")
2362 << "(in_value);\n";
2363 }
2364 } /* if (base_variable_type == Utils::VARIABLE_TYPE_BOOL) */
2365 else
2366 {
2367 if (array_size > 1)
2368 {
2369 for (unsigned int array_index = 0; array_index < array_size; ++array_index)
2370 {
2371 result_sstream << " temp[" << array_index << "]"
2372 " = in_value["
2373 << array_index << "] + " << (n_getter + 1) << ";\n";
2374 }
2375
2376 result_sstream << " return temp;\n";
2377 }
2378 else
2379 {
2380 result_sstream << " return (in_value + " << (n_getter + 1) << ");\n";
2381 }
2382 }
2383
2384 result_sstream << "}\n";
2385 } /* for (both getter functions) */
2386
2387 /* Declare subroutine uniform */
2388 result_sstream << "subroutine uniform colorGetter colorGetterUniform;\n"
2389 "\n";
2390
2391 /* Declare output variable */
2392 result_sstream << "out ";
2393
2394 if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2395 {
2396 Utils::_variable_type result_as_int_variable_type =
2397 Utils::getVariableTypeFromProperties(Utils::VARIABLE_TYPE_INT, n_variable_type_components);
2398 std::string variable_type_glsl_as_int = Utils::getVariableTypeGLSLString(result_as_int_variable_type);
2399
2400 result_sstream << variable_type_glsl_as_int;
2401 }
2402 else
2403 {
2404 result_sstream << variable_type_glsl;
2405 }
2406
2407 result_sstream << " result;\n"
2408 "\n";
2409
2410 /* Declare main(): prepare input argument for the subroutine function */
2411 result_sstream << "void main()\n"
2412 "{\n"
2413 " "
2414 << variable_type_glsl << " temp";
2415
2416 if (array_size > 1)
2417 {
2418 result_sstream << "[" << array_size << "]";
2419 }
2420
2421 result_sstream << ";\n";
2422
2423 for (unsigned int array_index = 0; array_index < array_size; ++array_index)
2424 {
2425 result_sstream << " temp";
2426
2427 if (array_size > 1)
2428 {
2429 result_sstream << "[" << array_index << "]";
2430 }
2431
2432 result_sstream << " = " << variable_type_glsl << "(";
2433
2434 if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2435 {
2436 result_sstream << "true";
2437 }
2438 else
2439 {
2440 for (unsigned int n_component = 0; n_component < n_variable_type_components; ++n_component)
2441 {
2442 result_sstream << "3";
2443
2444 if (n_component != (n_variable_type_components - 1))
2445 {
2446 result_sstream << ", ";
2447 }
2448 } /* for (all components) */
2449 }
2450
2451 result_sstream << ");\n";
2452 } /* for (all array indices) */
2453
2454 /* Declare main(): call the subroutine. Verify the input and write the result
2455 * to the output variable.
2456 **/
2457 if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2458 {
2459 Utils::_variable_type result_as_int_variable_type =
2460 Utils::getVariableTypeFromProperties(Utils::VARIABLE_TYPE_INT, n_variable_type_components);
2461 std::string variable_type_glsl_as_int = Utils::getVariableTypeGLSLString(result_as_int_variable_type);
2462
2463 result_sstream << variable_type_glsl_arrayed_sstream.str() << " subroutine_result = colorGetterUniform(temp);\n"
2464 "result = ";
2465
2466 for (unsigned int array_index = 0; array_index < array_size; ++array_index)
2467 {
2468 if (variable_type_glsl == "bool")
2469 result_sstream << "bool(subroutine_result";
2470 else
2471 result_sstream << "all(subroutine_result";
2472
2473 if (array_size > 1)
2474 {
2475 result_sstream << "[" << array_index << "]";
2476 }
2477
2478 result_sstream << ")";
2479
2480 if (array_index != (array_size - 1))
2481 {
2482 result_sstream << "&& ";
2483 }
2484 }
2485
2486 result_sstream << " == true ? " << variable_type_glsl_as_int << "(1) : " << variable_type_glsl_as_int << "(0);";
2487 }
2488 else
2489 {
2490 if (array_size > 1)
2491 {
2492 DE_ASSERT(array_size == 2);
2493
2494 result_sstream << variable_type_glsl << " subroutine_result" << variable_type_glsl_array_sstream.str()
2495 << " = colorGetterUniform(temp);\n"
2496 "\n"
2497 "if (subroutine_result[0] == subroutine_result[1]) result = subroutine_result[0];\n"
2498 "else\n"
2499 "result = "
2500 << variable_type_glsl << "(-1);\n";
2501 }
2502 else
2503 {
2504 result_sstream << "result = colorGetterUniform(temp);\n";
2505 }
2506 }
2507
2508 /* All done */
2509 result_sstream << "}\n";
2510
2511 return result_sstream.str();
2512 }
2513
2514 /** Initializes all GL objects required to run the test. */
initTest()2515 void FunctionalTest1_2::initTest()
2516 {
2517 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2518
2519 /* Generate buffer object to hold result XFB data */
2520 gl.genBuffers(1, &m_xfb_bo_id);
2521 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
2522
2523 /* Set up XFB BO bindings */
2524 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_xfb_bo_id);
2525 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
2526
2527 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_xfb_bo_id);
2528 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed.");
2529
2530 /* Generate VAO to use for the draw calls */
2531 gl.genVertexArrays(1, &m_vao_id);
2532 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
2533
2534 gl.bindVertexArray(m_vao_id);
2535 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
2536 }
2537
2538 /** Executes test iteration.
2539 *
2540 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
2541 */
iterate()2542 tcu::TestNode::IterateResult FunctionalTest1_2::iterate()
2543 {
2544 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
2545 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
2546 {
2547 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
2548 }
2549
2550 /* Initialize a test program object */
2551 initTest();
2552
2553 /* Construct test case descriptors: first, iIerate over all
2554 * variable types we want to cover */
2555 const Utils::_variable_type variable_types[] = {
2556 Utils::VARIABLE_TYPE_BOOL, Utils::VARIABLE_TYPE_BVEC2, Utils::VARIABLE_TYPE_BVEC3,
2557 Utils::VARIABLE_TYPE_BVEC4, Utils::VARIABLE_TYPE_DOUBLE, Utils::VARIABLE_TYPE_FLOAT,
2558 Utils::VARIABLE_TYPE_INT, Utils::VARIABLE_TYPE_IVEC2, Utils::VARIABLE_TYPE_IVEC3,
2559 Utils::VARIABLE_TYPE_IVEC4, Utils::VARIABLE_TYPE_MAT2, Utils::VARIABLE_TYPE_MAT2X3,
2560 Utils::VARIABLE_TYPE_MAT2X4, Utils::VARIABLE_TYPE_MAT3, Utils::VARIABLE_TYPE_MAT3X2,
2561 Utils::VARIABLE_TYPE_MAT3X4, Utils::VARIABLE_TYPE_MAT4, Utils::VARIABLE_TYPE_MAT4X2,
2562 Utils::VARIABLE_TYPE_MAT4X3, Utils::VARIABLE_TYPE_UINT, Utils::VARIABLE_TYPE_UVEC2,
2563 Utils::VARIABLE_TYPE_UVEC3, Utils::VARIABLE_TYPE_UVEC4, Utils::VARIABLE_TYPE_VEC2,
2564 Utils::VARIABLE_TYPE_VEC3, Utils::VARIABLE_TYPE_VEC4
2565 };
2566 const unsigned int n_variable_types = sizeof(variable_types) / sizeof(variable_types[0]);
2567
2568 for (unsigned int n_variable_type = 0; n_variable_type < n_variable_types; ++n_variable_type)
2569 {
2570 Utils::_variable_type current_variable_type = variable_types[n_variable_type];
2571
2572 /* We need to test both arrayed and non-arrayed arguments */
2573 for (unsigned int array_size = 1; array_size < 3; ++array_size)
2574 {
2575 /* Exclude double variables if the relevant extension is unavailable */
2576 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gpu_shader_fp64") &&
2577 current_variable_type == Utils::VARIABLE_TYPE_DOUBLE)
2578 {
2579 continue;
2580 }
2581
2582 /* Form the descriptor */
2583 _test_case test_case;
2584
2585 test_case.array_size = array_size;
2586 test_case.variable_type = current_variable_type;
2587
2588 /* Store the test case descriptor */
2589 m_test_cases.push_back(test_case);
2590 } /* for (both arrayed and non-arrayed arguments) */
2591 } /* for (all variable types) */
2592
2593 /* Iterate over all test cases and execute the test */
2594 for (_test_cases_const_iterator test_case_iterator = m_test_cases.begin(); test_case_iterator != m_test_cases.end();
2595 ++test_case_iterator)
2596 {
2597 const _test_case& test_case = *test_case_iterator;
2598
2599 m_has_test_passed &= executeTestIteration(test_case);
2600
2601 /* Release GL objects that were created during the execution */
2602 deinitTestIteration();
2603 } /* for (all test cases) */
2604
2605 /* Done */
2606 if (m_has_test_passed)
2607 {
2608 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2609 }
2610 else
2611 {
2612 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2613 }
2614
2615 return STOP;
2616 }
2617
2618 /** Verifies data that has been XFBed out by the vertex shader.
2619 *
2620 * @param xfb_data Buffer holding the data.
2621 * @param variable_type GLSL type used for the test iteration
2622 * that generated the data at @param xfb_data.
2623 *
2624 * @return true if the data was found to be valid, false if it
2625 * was detected to be incorrect.
2626 **/
verifyXFBData(const void * xfb_data,const Utils::_variable_type & variable_type)2627 bool FunctionalTest1_2::verifyXFBData(const void* xfb_data, const Utils::_variable_type& variable_type)
2628 {
2629 const Utils::_variable_type base_variable_type = Utils::getBaseVariableType(variable_type);
2630 const float epsilon = 1e-5f;
2631 const unsigned int n_variable_type_components = Utils::getNumberOfComponentsForVariableType(variable_type);
2632 bool result = true;
2633 const unsigned char* traveller_ptr = (const unsigned char*)xfb_data;
2634
2635 /* Boolean arguments/return types are tested with a slightly different shader so we
2636 * need to test them in a separate code-path.
2637 */
2638 if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
2639 {
2640 /* 0 should be returned when getter0 is used, 1 otherwise */
2641 const unsigned int ref_values[] = { 0, 1 };
2642 const unsigned int n_ref_values = sizeof(ref_values) / sizeof(ref_values[0]);
2643
2644 for (unsigned int n_ref_value = 0; n_ref_value < n_ref_values; ++n_ref_value)
2645 {
2646 const unsigned int ref_value = ref_values[n_ref_value];
2647
2648 for (unsigned int n_component = 0; n_component < n_variable_type_components; ++n_component)
2649 {
2650 int* result_value_ptr = (int*)(traveller_ptr);
2651
2652 if (*result_value_ptr != (int)ref_value)
2653 {
2654 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value reported by subroutine using "
2655 "["
2656 << Utils::getVariableTypeGLSLString(variable_type) << "]"
2657 << " argument/return types ("
2658 "expected:["
2659 << ref_value << "], found:[" << *result_value_ptr << "])"
2660 << tcu::TestLog::EndMessage;
2661
2662 result = false;
2663 break;
2664 }
2665
2666 traveller_ptr += sizeof(int);
2667 } /* for (all components) */
2668 } /* for (all reference values) */
2669 } /* if (base_variable_type == Utils::VARIABLE_TYPE_BOOL) */
2670 else
2671 {
2672 /* 4 should be returned when getter0 is used, 5 otherwise */
2673 const unsigned int ref_values[] = { 4, 5 };
2674 const unsigned int n_ref_values = sizeof(ref_values) / sizeof(ref_values[0]);
2675
2676 for (unsigned int n_ref_value = 0; n_ref_value < n_ref_values; ++n_ref_value)
2677 {
2678 const unsigned int ref_value = ref_values[n_ref_value];
2679
2680 DE_ASSERT(
2681 base_variable_type == Utils::VARIABLE_TYPE_DOUBLE || base_variable_type == Utils::VARIABLE_TYPE_FLOAT ||
2682 base_variable_type == Utils::VARIABLE_TYPE_INT || base_variable_type == Utils::VARIABLE_TYPE_UINT);
2683
2684 for (unsigned int n_component = 0; n_component < n_variable_type_components; ++n_component)
2685 {
2686 const double* double_value_ptr = (double*)traveller_ptr;
2687 const float* float_value_ptr = (float*)traveller_ptr;
2688 const int* int_value_ptr = (int*)traveller_ptr;
2689
2690 switch (base_variable_type)
2691 {
2692 case Utils::VARIABLE_TYPE_DOUBLE:
2693 {
2694 if (de::abs(*double_value_ptr - (double)ref_value) > epsilon)
2695 {
2696 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value reported by subroutine using "
2697 "["
2698 << Utils::getVariableTypeGLSLString(variable_type) << "]"
2699 << " argument/return types ("
2700 "expected:["
2701 << ref_value << "], found:[" << *double_value_ptr << "])"
2702 << tcu::TestLog::EndMessage;
2703
2704 result = false;
2705 }
2706
2707 traveller_ptr += sizeof(double);
2708 break;
2709 }
2710
2711 case Utils::VARIABLE_TYPE_FLOAT:
2712 {
2713 if (de::abs(*float_value_ptr - (float)ref_value) > epsilon)
2714 {
2715 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value reported by subroutine using "
2716 "["
2717 << Utils::getVariableTypeGLSLString(variable_type) << "]"
2718 << " argument/return types ("
2719 "expected:["
2720 << ref_value << "], found:[" << *float_value_ptr << "])"
2721 << tcu::TestLog::EndMessage;
2722
2723 result = false;
2724 }
2725
2726 traveller_ptr += sizeof(float);
2727 break;
2728 }
2729
2730 case Utils::VARIABLE_TYPE_INT:
2731 case Utils::VARIABLE_TYPE_UINT:
2732 {
2733 if (*int_value_ptr != (int)ref_value)
2734 {
2735 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value reported by subroutine using "
2736 "["
2737 << Utils::getVariableTypeGLSLString(variable_type) << "]"
2738 << " argument/return types ("
2739 "expected:["
2740 << ref_value << "], found:[" << *int_value_ptr << "])"
2741 << tcu::TestLog::EndMessage;
2742
2743 result = false;
2744 }
2745
2746 traveller_ptr += sizeof(int);
2747 break;
2748 }
2749
2750 default:
2751 break;
2752 } /* switch (base_variable_type) */
2753 } /* for (all components) */
2754 } /* for (all reference values) */
2755 }
2756
2757 return result;
2758 }
2759
2760 /** Constructor
2761 *
2762 * @param context CTS context
2763 **/
FunctionalTest3_4(deqp::Context & context)2764 FunctionalTest3_4::FunctionalTest3_4(deqp::Context& context)
2765 : TestCase(context, "four_subroutines_with_two_uniforms", "Verify Get* API and draw calls")
2766 , m_n_active_subroutine_uniforms(0)
2767 , m_n_active_subroutine_uniform_locations(0)
2768 , m_n_active_subroutines(0)
2769 , m_n_active_subroutine_uniform_name_length(0)
2770 , m_n_active_subroutine_name_length(0)
2771 , m_n_active_subroutine_uniform_size(0)
2772 {
2773 /* Nothing to be done here */
2774 }
2775
2776 /** Execute test
2777 *
2778 * @return tcu::TestNode::STOP
2779 **/
iterate()2780 tcu::TestNode::IterateResult FunctionalTest3_4::iterate()
2781 {
2782 static const glw::GLchar* vertex_shader_code =
2783 "#version 400 core\n"
2784 "#extension GL_ARB_shader_subroutine : require\n"
2785 "\n"
2786 "precision highp float;\n"
2787 "\n"
2788 "// Sub routine type declaration\n"
2789 "subroutine vec4 routine_type(in vec4 iparam);\n"
2790 "\n"
2791 "// Sub routine definitions\n"
2792 "subroutine(routine_type) vec4 inverse_order(in vec4 iparam)\n"
2793 "{\n"
2794 " return iparam.wzyx;\n"
2795 "}\n"
2796 "\n"
2797 "subroutine(routine_type) vec4 negate(in vec4 iparam)\n"
2798 "{\n"
2799 " return -iparam;\n"
2800 "}\n"
2801 "\n"
2802 "subroutine(routine_type) vec4 inverse(in vec4 iparam)\n"
2803 "{\n"
2804 " return 1 / iparam;\n"
2805 "}\n"
2806 "\n"
2807 "subroutine(routine_type) vec4 square(in vec4 iparam)\n"
2808 "{\n"
2809 " return iparam * iparam;\n"
2810 "}\n"
2811 "\n"
2812 "// Sub routine uniforms\n"
2813 "subroutine uniform routine_type first_routine;\n"
2814 "subroutine uniform routine_type second_routine;\n"
2815 "\n"
2816 "// Input data\n"
2817 "uniform vec4 input_data;\n"
2818 "\n"
2819 "// Output\n"
2820 "out vec4 out_input_data;\n"
2821 "out vec4 out_result_from_first_routine;\n"
2822 "out vec4 out_result_from_second_routine;\n"
2823 "out vec4 out_result_from_combined_routines;\n"
2824 "out vec4 out_result_from_routines_combined_in_reveresed_order;\n"
2825 "\n"
2826 "void main()\n"
2827 "{\n"
2828 " out_input_data = input_data;\n"
2829 " out_result_from_first_routine = first_routine(input_data);\n"
2830 " out_result_from_second_routine = second_routine(input_data);\n"
2831 " out_result_from_combined_routines = second_routine(first_routine(input_data));\n"
2832 " out_result_from_routines_combined_in_reveresed_order = first_routine(second_routine(input_data));\n"
2833 "}\n"
2834 "\n";
2835
2836 static const GLchar* varying_names[] = {
2837 "out_input_data",
2838 "out_result_from_first_routine",
2839 "out_result_from_second_routine",
2840 "out_result_from_combined_routines",
2841 "out_result_from_routines_combined_in_reveresed_order",
2842 };
2843
2844 static const GLchar* subroutine_uniform_names[] = { "first_routine", "second_routine" };
2845
2846 static const GLchar* subroutine_names[] = { "inverse_order", "negate", "inverse", "square" };
2847
2848 static const GLuint n_varyings = sizeof(varying_names) / sizeof(varying_names[0]);
2849 static const GLuint transform_feedback_buffer_size = n_varyings * sizeof(GLfloat) * 4 /* vec4 */;
2850
2851 static const GLuint inverse_order_routine_index = 0;
2852 static const GLuint negate_routine_index = 1;
2853 static const GLuint inverse_routine_index = 2;
2854 static const GLuint square_routine_index = 3;
2855
2856 /* Test data */
2857 static const Utils::vec4<GLfloat> inverse_order_negate_data[5] = {
2858 Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
2859 Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f), Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f),
2860 Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f),
2861 };
2862
2863 static const Utils::vec4<GLfloat> inverse_order_inverse_data[5] = {
2864 Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
2865 Utils::vec4<GLfloat>(-0.5f, -1.0f, 1.0f, 0.5f), Utils::vec4<GLfloat>(0.5f, 1.0f, -1.0f, -0.5f),
2866 Utils::vec4<GLfloat>(0.5f, 1.0f, -1.0f, -0.5f),
2867 };
2868
2869 static const Utils::vec4<GLfloat> inverse_order_square_data[5] = {
2870 Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
2871 Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f), Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f),
2872 Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f),
2873 };
2874
2875 static const Utils::vec4<GLfloat> negate_inverse_data[5] = {
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>(-0.5f, -1.0f, 1.0f, 0.5f), Utils::vec4<GLfloat>(0.5f, 1.0f, -1.0f, -0.5f),
2878 Utils::vec4<GLfloat>(0.5f, 1.0f, -1.0f, -0.5f),
2879 };
2880
2881 static const Utils::vec4<GLfloat> negate_square_data[5] = {
2882 Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
2883 Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f), Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f),
2884 Utils::vec4<GLfloat>(-4.0f, -1.0f, -1.0f, -4.0f),
2885 };
2886
2887 static const Utils::vec4<GLfloat> inverse_square_data[5] = {
2888 Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(-0.5f, -1.0f, 1.0f, 0.5f),
2889 Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f), Utils::vec4<GLfloat>(0.25f, 1.0f, 1.0f, 0.25f),
2890 Utils::vec4<GLfloat>(0.25f, 1.0f, 1.0f, 0.25f),
2891 };
2892
2893 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
2894 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
2895 {
2896 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
2897 }
2898
2899 m_n_active_subroutine_uniforms = 2;
2900 m_n_active_subroutine_uniform_locations = 2;
2901 m_n_active_subroutines = 4;
2902 m_n_active_subroutine_uniform_name_length = 0;
2903 m_n_active_subroutine_name_length = 0;
2904 m_n_active_subroutine_uniform_size = 1;
2905
2906 /* GL objects */
2907 Utils::program program(m_context);
2908 Utils::buffer transform_feedback_buffer(m_context);
2909 Utils::vertexArray vao(m_context);
2910
2911 bool result = true;
2912
2913 /* Calculate max name lengths for subroutines and subroutine uniforms */
2914 for (GLint i = 0; i < m_n_active_subroutine_uniforms; ++i)
2915 {
2916 const GLsizei length = (GLsizei)strlen(subroutine_uniform_names[i]);
2917
2918 if (length > m_n_active_subroutine_uniform_name_length)
2919 {
2920 m_n_active_subroutine_uniform_name_length = length;
2921 }
2922 }
2923
2924 for (GLint i = 0; i < m_n_active_subroutines; ++i)
2925 {
2926 const GLsizei length = (GLsizei)strlen(subroutine_names[i]);
2927
2928 if (length > m_n_active_subroutine_name_length)
2929 {
2930 m_n_active_subroutine_name_length = length;
2931 }
2932 }
2933
2934 /* Init */
2935 program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code, varying_names,
2936 n_varyings);
2937
2938 vao.generate();
2939 vao.bind();
2940
2941 transform_feedback_buffer.generate();
2942 transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
2943 GL_DYNAMIC_COPY);
2944 transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
2945
2946 program.use();
2947
2948 /* Inspect Get* API */
2949 if ((false == inspectProgramStageiv(program.m_program_object_id)) ||
2950 (false == inspectActiveSubroutineUniformiv(program.m_program_object_id, subroutine_uniform_names)) ||
2951 (false == inspectActiveSubroutineUniformName(program.m_program_object_id, subroutine_uniform_names)) ||
2952 (false == inspectActiveSubroutineName(program.m_program_object_id, subroutine_names)) ||
2953 (false ==
2954 inspectSubroutineBinding(program.m_program_object_id, subroutine_names, subroutine_uniform_names, false)))
2955 {
2956 result = false;
2957 }
2958
2959 /* Inspect GetProgram* API */
2960 if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_program_interface_query"))
2961 {
2962 if ((false == inspectProgramInterfaceiv(program.m_program_object_id)) ||
2963 (false ==
2964 inspectProgramResourceiv(program.m_program_object_id, subroutine_names, subroutine_uniform_names)) ||
2965 (false ==
2966 inspectSubroutineBinding(program.m_program_object_id, subroutine_names, subroutine_uniform_names, true)))
2967 {
2968 result = false;
2969 }
2970 }
2971
2972 /* Test shader execution */
2973 if ((false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
2974 subroutine_names[negate_routine_index], subroutine_uniform_names, inverse_order_negate_data,
2975 false)) ||
2976 (false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
2977 subroutine_names[inverse_routine_index], subroutine_uniform_names,
2978 inverse_order_inverse_data, false)) ||
2979 (false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
2980 subroutine_names[square_routine_index], subroutine_uniform_names, inverse_order_square_data,
2981 false)) ||
2982 (false == testDraw(program.m_program_object_id, subroutine_names[negate_routine_index],
2983 subroutine_names[inverse_routine_index], subroutine_uniform_names, negate_inverse_data,
2984 false)) ||
2985 (false == testDraw(program.m_program_object_id, subroutine_names[negate_routine_index],
2986 subroutine_names[square_routine_index], subroutine_uniform_names, negate_square_data,
2987 false)) ||
2988 (false == testDraw(program.m_program_object_id, subroutine_names[inverse_routine_index],
2989 subroutine_names[square_routine_index], subroutine_uniform_names, inverse_square_data,
2990 false)))
2991 {
2992 result = false;
2993 }
2994
2995 if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_program_interface_query"))
2996 {
2997 if ((false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
2998 subroutine_names[negate_routine_index], subroutine_uniform_names,
2999 inverse_order_negate_data, true)) ||
3000 (false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
3001 subroutine_names[inverse_routine_index], subroutine_uniform_names,
3002 inverse_order_inverse_data, true)) ||
3003 (false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
3004 subroutine_names[square_routine_index], subroutine_uniform_names,
3005 inverse_order_square_data, true)) ||
3006 (false == testDraw(program.m_program_object_id, subroutine_names[negate_routine_index],
3007 subroutine_names[inverse_routine_index], subroutine_uniform_names, negate_inverse_data,
3008 true)) ||
3009 (false == testDraw(program.m_program_object_id, subroutine_names[negate_routine_index],
3010 subroutine_names[square_routine_index], subroutine_uniform_names, negate_square_data,
3011 true)) ||
3012 (false == testDraw(program.m_program_object_id, subroutine_names[inverse_routine_index],
3013 subroutine_names[square_routine_index], subroutine_uniform_names, inverse_square_data,
3014 true)))
3015 {
3016 result = false;
3017 }
3018 }
3019
3020 /* Done */
3021 if (true == result)
3022 {
3023 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3024 }
3025 else
3026 {
3027 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
3028 }
3029
3030 return tcu::TestNode::STOP;
3031 }
3032
3033 /** Verify result of getProgramStageiv
3034 *
3035 * @param program_id Program object id
3036 * @param pname <pname> parameter for getProgramStageiv
3037 * @param expected Expected value
3038 *
3039 * @return true if result is equal to expected value, flase otherwise
3040 **/
checkProgramStageiv(glw::GLuint program_id,glw::GLenum pname,glw::GLint expected) const3041 bool FunctionalTest3_4::checkProgramStageiv(glw::GLuint program_id, glw::GLenum pname, glw::GLint expected) const
3042 {
3043 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3044 GLint value = 0;
3045
3046 gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, pname, &value);
3047 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3048
3049 if (expected != value)
3050 {
3051 m_context.getTestContext().getLog() << tcu::TestLog::Message
3052 << "Error. Invalid result. Function: getProgramStageiv. "
3053 << "pname: " << Utils::pnameToStr(pname) << ". "
3054 << "Result: " << value << ". "
3055 << "Expected: " << expected << "." << tcu::TestLog::EndMessage;
3056
3057 return false;
3058 }
3059 else
3060 {
3061 return true;
3062 }
3063 }
3064
3065 /** Verify result of getProgramResourceiv
3066 *
3067 * @param program_id Program object id
3068 * @param program_interface Program interface
3069 * @param pname <pname> parameter for getProgramStageiv
3070 * @param resource_name Resource name
3071 * @param expected Expected value
3072 *
3073 * @return true if result is equal to expected value, false otherwise
3074 **/
checkProgramResourceiv(GLuint program_id,GLenum program_interface,GLenum pname,const glw::GLchar * resource_name,GLint expected) const3075 bool FunctionalTest3_4::checkProgramResourceiv(GLuint program_id, GLenum program_interface, GLenum pname,
3076 const glw::GLchar* resource_name, GLint expected) const
3077 {
3078 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3079 GLuint index = gl.getProgramResourceIndex(program_id, program_interface, resource_name);
3080 GLint value = 0;
3081
3082 if (GL_INVALID_INDEX == index)
3083 {
3084 return false;
3085 }
3086
3087 gl.getProgramResourceiv(program_id, program_interface, index, 1, &pname, 1, 0, &value);
3088 GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramResourceiv");
3089
3090 if (expected != value)
3091 {
3092 m_context.getTestContext().getLog()
3093 << tcu::TestLog::Message << "Error. Invalid result. Function: getProgramResourceiv. "
3094 << "Program interface: " << Utils::programInterfaceToStr(program_interface) << ". "
3095 << "Resource name: " << resource_name << ". "
3096 << "Property: " << Utils::pnameToStr(pname) << ". "
3097 << "Result: " << value << ". "
3098 << "Expected: " << expected << "." << tcu::TestLog::EndMessage;
3099
3100 return false;
3101 }
3102 else
3103 {
3104 return true;
3105 }
3106 }
3107
3108 /** Verify result of getProgramInterfaceiv
3109 *
3110 * @param program_id Program object id
3111 * @param program_interface Program interface
3112 * @param pname <pname> parameter for getProgramStageiv
3113 * @param expected Expected value
3114 *
3115 * @return true if result is equal to expected value, flase otherwise
3116 **/
checkProgramInterfaceiv(GLuint program_id,GLenum program_interface,GLenum pname,GLint expected) const3117 bool FunctionalTest3_4::checkProgramInterfaceiv(GLuint program_id, GLenum program_interface, GLenum pname,
3118 GLint expected) const
3119 {
3120 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3121 GLint value = 0;
3122
3123 gl.getProgramInterfaceiv(program_id, program_interface, pname, &value);
3124 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramInterfaceiv");
3125
3126 if (expected != value)
3127 {
3128 m_context.getTestContext().getLog()
3129 << tcu::TestLog::Message << "Error. Invalid result. Function: getProgramInterfaceiv. "
3130 << "Program interface: " << Utils::programInterfaceToStr(program_interface) << ". "
3131 << "pname: " << Utils::pnameToStr(pname) << ". "
3132 << "Result: " << value << ". "
3133 << "Expected: " << expected << "." << tcu::TestLog::EndMessage;
3134
3135 return false;
3136 }
3137 else
3138 {
3139 return true;
3140 }
3141 }
3142
3143 /** Verify result of getActiveSubroutineUniformiv
3144 *
3145 * @param program_id Program object id
3146 * @param index <index> parameter for getActiveSubroutineUniformiv
3147 * @param pname <pname> parameter for getActiveSubroutineUniformiv
3148 * @param expected Expected value
3149 *
3150 * @return true if result is equal to expected value, flase otherwise
3151 **/
checkActiveSubroutineUniformiv(GLuint program_id,GLuint index,GLenum pname,GLint expected) const3152 bool FunctionalTest3_4::checkActiveSubroutineUniformiv(GLuint program_id, GLuint index, GLenum pname,
3153 GLint expected) const
3154 {
3155 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3156 GLint value = 0;
3157
3158 gl.getActiveSubroutineUniformiv(program_id, GL_VERTEX_SHADER, index, pname, &value);
3159 GLU_EXPECT_NO_ERROR(gl.getError(), "getActiveSubroutineUniformiv");
3160
3161 if (expected != value)
3162 {
3163 m_context.getTestContext().getLog() << tcu::TestLog::Message
3164 << "Error. Invalid result. Function: getActiveSubroutineUniformiv. "
3165 << "idnex: " << index << ". "
3166 << "pname: " << Utils::pnameToStr(pname) << ". "
3167 << "Result: " << value << ". "
3168 << "Expected: " << expected << "." << tcu::TestLog::EndMessage;
3169
3170 return false;
3171 }
3172 else
3173 {
3174 return true;
3175 }
3176 }
3177
3178 /** Returns index of program resource
3179 *
3180 * @param program_id Program object id
3181 * @param program_interface Program interface
3182 * @param resource_name Name of resource
3183 *
3184 * @return Index of specified resource
3185 **/
getProgramResourceIndex(GLuint program_id,GLenum program_interface,const glw::GLchar * resource_name) const3186 GLuint FunctionalTest3_4::getProgramResourceIndex(GLuint program_id, GLenum program_interface,
3187 const glw::GLchar* resource_name) const
3188 {
3189 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3190 GLuint index = gl.getProgramResourceIndex(program_id, program_interface, resource_name);
3191
3192 GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramResourceIndex");
3193
3194 if (GL_INVALID_INDEX == index)
3195 {
3196 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error. Program resource is not available. "
3197 << "Program interface: " << Utils::programInterfaceToStr(program_interface)
3198 << ". "
3199 << "Resource name: " << resource_name << "." << tcu::TestLog::EndMessage;
3200 }
3201
3202 return index;
3203 }
3204
3205 /** Get subroutine index
3206 *
3207 * @param program_id Program object id
3208 * @param subroutine_name Subroutine name
3209 * @param use_program_query If true getProgramResourceIndex is used, otherwise getSubroutineIndex
3210 *
3211 * @return Index of subroutine
3212 **/
getSubroutineIndex(GLuint program_id,const glw::GLchar * subroutine_name,bool use_program_query) const3213 GLuint FunctionalTest3_4::getSubroutineIndex(GLuint program_id, const glw::GLchar* subroutine_name,
3214 bool use_program_query) const
3215 {
3216 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3217 GLuint index = -1;
3218
3219 if (false == use_program_query)
3220 {
3221 index = gl.getSubroutineIndex(program_id, GL_VERTEX_SHADER, subroutine_name);
3222 GLU_EXPECT_NO_ERROR(gl.getError(), "GetSubroutineIndex");
3223 }
3224 else
3225 {
3226 index = gl.getProgramResourceIndex(program_id, GL_VERTEX_SUBROUTINE, subroutine_name);
3227 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramResourceIndex");
3228 }
3229
3230 if (GL_INVALID_INDEX == index)
3231 {
3232 TCU_FAIL("Subroutine is not available");
3233 }
3234
3235 return index;
3236 }
3237
3238 /** Get subroutine uniform location
3239 *
3240 * @param program_id Program object id
3241 * @param uniform_name Subroutine uniform name
3242 * @param use_program_query If true getProgramResourceLocation is used, otherwise getSubroutineUniformLocation
3243 *
3244 * @return Location of subroutine uniform
3245 **/
getSubroutineUniformLocation(GLuint program_id,const glw::GLchar * uniform_name,bool use_program_query) const3246 GLint FunctionalTest3_4::getSubroutineUniformLocation(GLuint program_id, const glw::GLchar* uniform_name,
3247 bool use_program_query) const
3248 {
3249 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3250 GLint location = -1;
3251
3252 if (false == use_program_query)
3253 {
3254 location = gl.getSubroutineUniformLocation(program_id, GL_VERTEX_SHADER, uniform_name);
3255 GLU_EXPECT_NO_ERROR(gl.getError(), "GetSubroutineUniformLocation");
3256 }
3257 else
3258 {
3259 location = gl.getProgramResourceLocation(program_id, GL_VERTEX_SUBROUTINE_UNIFORM, uniform_name);
3260 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramResourceLocation");
3261 }
3262
3263 if (-1 == location)
3264 {
3265 TCU_FAIL("Subroutine uniform is not available");
3266 }
3267
3268 return location;
3269 }
3270
3271 /** Test if getProgramStageiv results are as expected
3272 *
3273 * @param program_id Program object id
3274 *
3275 * @result false in case of invalid result for any pname, true otherwise
3276 **/
inspectProgramStageiv(glw::GLuint program_id) const3277 bool FunctionalTest3_4::inspectProgramStageiv(glw::GLuint program_id) const
3278 {
3279 bool result = true;
3280
3281 const inspectionDetails details[] = {
3282 { GL_ACTIVE_SUBROUTINE_UNIFORMS, m_n_active_subroutine_uniforms },
3283 { GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS, m_n_active_subroutine_uniform_locations },
3284 { GL_ACTIVE_SUBROUTINES, m_n_active_subroutines },
3285 { GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH, m_n_active_subroutine_uniform_name_length + 1 },
3286 { GL_ACTIVE_SUBROUTINE_MAX_LENGTH, m_n_active_subroutine_name_length + 1 }
3287 };
3288 const GLuint n_details = sizeof(details) / sizeof(details[0]);
3289
3290 for (GLuint i = 0; i < n_details; ++i)
3291 {
3292 if (false == checkProgramStageiv(program_id, details[i].pname, details[i].expected_value))
3293 {
3294 result = false;
3295 }
3296 }
3297
3298 return result;
3299 }
3300
3301 /** Test if checkProgramInterfaceiv results are as expected
3302 *
3303 * @param program_id Program object id
3304 *
3305 * @result false in case of invalid result for any pname, true otherwise
3306 **/
inspectProgramInterfaceiv(glw::GLuint program_id) const3307 bool FunctionalTest3_4::inspectProgramInterfaceiv(glw::GLuint program_id) const
3308 {
3309 bool result = true;
3310
3311 const inspectionDetailsForProgramInterface details[] = {
3312 { GL_VERTEX_SUBROUTINE_UNIFORM, GL_ACTIVE_RESOURCES, m_n_active_subroutine_uniforms },
3313 { GL_VERTEX_SUBROUTINE_UNIFORM, GL_MAX_NAME_LENGTH, m_n_active_subroutine_uniform_name_length + 1 },
3314 { GL_VERTEX_SUBROUTINE_UNIFORM, GL_MAX_NUM_COMPATIBLE_SUBROUTINES, m_n_active_subroutines },
3315 { GL_VERTEX_SUBROUTINE, GL_ACTIVE_RESOURCES, m_n_active_subroutines },
3316 { GL_VERTEX_SUBROUTINE, GL_MAX_NAME_LENGTH, m_n_active_subroutine_name_length + 1 }
3317 };
3318 const GLuint n_details = sizeof(details) / sizeof(details[0]);
3319
3320 for (GLuint i = 0; i < n_details; ++i)
3321 {
3322 if (false == checkProgramInterfaceiv(program_id, details[i].program_interface, details[i].pname,
3323 details[i].expected_value))
3324 {
3325 result = false;
3326 }
3327 }
3328
3329 return result;
3330 }
3331
3332 /** Test if checkProgramResourceiv results are as expected
3333 *
3334 * @param program_id Program object id
3335 * @param subroutine_names Array of subroutine names
3336 * @param uniform_names Array of uniform names
3337 *
3338 * @result false in case of invalid result for any pname, true otherwise
3339 **/
inspectProgramResourceiv(GLuint program_id,const GLchar ** subroutine_names,const GLchar ** uniform_names) const3340 bool FunctionalTest3_4::inspectProgramResourceiv(GLuint program_id, const GLchar** subroutine_names,
3341 const GLchar** uniform_names) const
3342 {
3343 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3344 bool result = true;
3345
3346 for (GLint subroutine = 0; subroutine < m_n_active_subroutines; ++subroutine)
3347 {
3348 const GLchar* subroutine_name = subroutine_names[subroutine];
3349 const GLint length = (GLint)strlen(subroutine_name) + 1;
3350
3351 if (false == checkProgramResourceiv(program_id, GL_VERTEX_SUBROUTINE, GL_NAME_LENGTH, subroutine_name, length))
3352 {
3353 result = false;
3354 }
3355 }
3356
3357 inspectionDetails details[] = {
3358 { GL_NAME_LENGTH, 0 },
3359 { GL_ARRAY_SIZE, 1 },
3360 { GL_NUM_COMPATIBLE_SUBROUTINES, m_n_active_subroutines },
3361 { GL_LOCATION, 0 },
3362 };
3363 const GLuint n_details = sizeof(details) / sizeof(details[0]);
3364
3365 for (GLint uniform = 0; uniform < m_n_active_subroutine_uniforms; ++uniform)
3366 {
3367 const GLchar* uniform_name = uniform_names[uniform];
3368 const GLint length = (GLint)strlen(uniform_name) + 1;
3369 const GLint location = getSubroutineUniformLocation(program_id, uniform_name, true);
3370
3371 details[0].expected_value = length;
3372 details[3].expected_value = location;
3373
3374 for (GLuint i = 0; i < n_details; ++i)
3375 {
3376 if (false == checkProgramResourceiv(program_id, GL_VERTEX_SUBROUTINE_UNIFORM, details[i].pname,
3377 uniform_name, details[i].expected_value))
3378 {
3379 result = false;
3380 }
3381 }
3382
3383 /* Check compatible subroutines */
3384 GLuint index = getProgramResourceIndex(program_id, GL_VERTEX_SUBROUTINE_UNIFORM, uniform_name);
3385
3386 if (GL_INVALID_INDEX != index)
3387 {
3388 std::vector<GLint> compatible_subroutines;
3389 GLint index_sum = 0;
3390 GLenum prop = GL_COMPATIBLE_SUBROUTINES;
3391
3392 compatible_subroutines.resize(m_n_active_subroutines);
3393
3394 gl.getProgramResourceiv(program_id, GL_VERTEX_SUBROUTINE_UNIFORM, index, 1, &prop, m_n_active_subroutines,
3395 0, &compatible_subroutines[0]);
3396
3397 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramResourceiv");
3398
3399 /* Expected indices are 0, 1, 2, ... N */
3400 for (GLint i = 0; i < m_n_active_subroutines; ++i)
3401 {
3402 index_sum += compatible_subroutines[i];
3403 }
3404
3405 /* Sum of E1, ..., EN = (E1 + EN) * N / 2 */
3406 if (((m_n_active_subroutines - 1) * m_n_active_subroutines) / 2 != index_sum)
3407 {
3408 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
3409
3410 message << "Error. Invalid result. Function: getProgramResourceiv. "
3411 << "Program interface: GL_VERTEX_SUBROUTINE_UNIFORM. "
3412 << "Resource name: " << uniform_name << ". "
3413 << "Property: GL_COMPATIBLE_SUBROUTINES. "
3414 << "Results: ";
3415
3416 for (GLint i = 1; i < m_n_active_subroutines; ++i)
3417 {
3418 message << compatible_subroutines[i];
3419 }
3420
3421 message << tcu::TestLog::EndMessage;
3422
3423 result = false;
3424 }
3425 }
3426 }
3427
3428 return result;
3429 }
3430
3431 /** Test if getActiveSubroutineUniformiv results are as expected
3432 *
3433 * @param program_id Program object id
3434 * @param uniform_names Array of subroutine uniform names available in program
3435 *
3436 * @result false in case of invalid result for any pname, true otherwise
3437 **/
inspectActiveSubroutineUniformiv(GLuint program_id,const GLchar ** uniform_names) const3438 bool FunctionalTest3_4::inspectActiveSubroutineUniformiv(GLuint program_id, const GLchar** uniform_names) const
3439 {
3440 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3441 bool result = true;
3442 GLint n_active_subroutine_uniforms = 0;
3443
3444 inspectionDetails details[] = {
3445 { GL_NUM_COMPATIBLE_SUBROUTINES, m_n_active_subroutines },
3446 { GL_UNIFORM_SIZE, m_n_active_subroutine_uniform_size },
3447 { GL_UNIFORM_NAME_LENGTH, 0 },
3448 };
3449 const GLuint n_details = sizeof(details) / sizeof(details[0]);
3450
3451 /* Get amount of active subroutine uniforms */
3452 gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORMS, &n_active_subroutine_uniforms);
3453 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3454
3455 for (GLint uniform = 0; uniform < n_active_subroutine_uniforms; ++uniform)
3456 {
3457 GLint name_length = (GLint)strlen(uniform_names[uniform]);
3458
3459 details[2].expected_value = name_length + 1;
3460
3461 /* Checks from "details" */
3462 for (GLuint i = 0; i < n_details; ++i)
3463 {
3464 if (false ==
3465 checkActiveSubroutineUniformiv(program_id, uniform, details[i].pname, details[i].expected_value))
3466 {
3467 result = false;
3468 }
3469 }
3470
3471 /* Check compatible subroutines */
3472 std::vector<GLint> compatible_subroutines;
3473 compatible_subroutines.resize(m_n_active_subroutines);
3474 GLint index_sum = 0;
3475
3476 gl.getActiveSubroutineUniformiv(program_id, GL_VERTEX_SHADER, uniform, GL_COMPATIBLE_SUBROUTINES,
3477 &compatible_subroutines[0]);
3478 GLU_EXPECT_NO_ERROR(gl.getError(), "getActiveSubroutineUniformiv");
3479
3480 /* Expected indices are 0, 1, 2, ... N */
3481 for (GLint i = 0; i < m_n_active_subroutines; ++i)
3482 {
3483 index_sum += compatible_subroutines[i];
3484 }
3485
3486 /* Sum of E1, ..., EN = (E1 + EN) * N / 2 */
3487 if (((m_n_active_subroutines - 1) * m_n_active_subroutines) / 2 != index_sum)
3488 {
3489 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
3490
3491 message << "Error. Invalid result. Function: getActiveSubroutineUniformiv. idnex: " << uniform
3492 << ". pname: " << Utils::pnameToStr(GL_COMPATIBLE_SUBROUTINES) << ". Results: ";
3493
3494 for (GLint i = 1; i < m_n_active_subroutines; ++i)
3495 {
3496 message << compatible_subroutines[i];
3497 }
3498
3499 message << tcu::TestLog::EndMessage;
3500
3501 result = false;
3502 }
3503 }
3504
3505 return result;
3506 }
3507
3508 /** Test if getActiveSubroutineUniformName results are as expected
3509 *
3510 * @param program_id Program object id
3511 * @param uniform_names Array of subroutine uniform names available in program
3512 *
3513 * @result false in case of invalid result, true otherwise
3514 **/
inspectActiveSubroutineUniformName(GLuint program_id,const GLchar ** uniform_names) const3515 bool FunctionalTest3_4::inspectActiveSubroutineUniformName(GLuint program_id, const GLchar** uniform_names) const
3516 {
3517 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3518 bool result = true;
3519 GLint n_active_subroutine_uniforms = 0;
3520 std::vector<GLchar> active_uniform_name;
3521
3522 gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORMS, &n_active_subroutine_uniforms);
3523 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3524
3525 active_uniform_name.resize(m_n_active_subroutine_uniform_name_length + 1);
3526
3527 for (GLint uniform = 0; uniform < n_active_subroutine_uniforms; ++uniform)
3528 {
3529 bool is_name_ok = false;
3530
3531 gl.getActiveSubroutineUniformName(program_id, GL_VERTEX_SHADER, uniform, (GLsizei)active_uniform_name.size(),
3532 0 /* length */, &active_uniform_name[0]);
3533 GLU_EXPECT_NO_ERROR(gl.getError(), "GetActiveSubroutineUniformName");
3534
3535 for (GLint name = 0; name < n_active_subroutine_uniforms; ++name)
3536 {
3537 if (0 == strcmp(uniform_names[name], &active_uniform_name[0]))
3538 {
3539 is_name_ok = true;
3540 break;
3541 }
3542 }
3543
3544 if (false == is_name_ok)
3545 {
3546 m_context.getTestContext().getLog()
3547 << tcu::TestLog::Message
3548 << "Error. Invalid result. Function: getActiveSubroutineUniformName. idnex: " << uniform
3549 << ". Result: " << &active_uniform_name[0] << tcu::TestLog::EndMessage;
3550
3551 result = false;
3552 break;
3553 }
3554 }
3555
3556 return result;
3557 }
3558
3559 /** Test if getActiveSubroutineUniformName results are as expected
3560 *
3561 * @param program_id Program object id
3562 * @param subroutine_names Array of subroutine names available in program
3563 *
3564 * @result false in case of invalid result, true otherwise
3565 **/
inspectActiveSubroutineName(GLuint program_id,const GLchar ** subroutine_names) const3566 bool FunctionalTest3_4::inspectActiveSubroutineName(GLuint program_id, const GLchar** subroutine_names) const
3567 {
3568 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3569 bool result = true;
3570 GLint n_active_subroutines = 0;
3571 std::vector<GLchar> active_subroutine_name;
3572
3573 gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINES, &n_active_subroutines);
3574 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3575
3576 active_subroutine_name.resize(m_n_active_subroutine_name_length + 1);
3577
3578 for (GLint uniform = 0; uniform < n_active_subroutines; ++uniform)
3579 {
3580 bool is_name_ok = false;
3581
3582 gl.getActiveSubroutineName(program_id, GL_VERTEX_SHADER, uniform, (GLsizei)active_subroutine_name.size(),
3583 0 /* length */, &active_subroutine_name[0]);
3584 GLU_EXPECT_NO_ERROR(gl.getError(), "getActiveSubroutineName");
3585
3586 for (GLint name = 0; name < n_active_subroutines; ++name)
3587 {
3588 if (0 == strcmp(subroutine_names[name], &active_subroutine_name[0]))
3589 {
3590 is_name_ok = true;
3591 break;
3592 }
3593 }
3594
3595 if (false == is_name_ok)
3596 {
3597 m_context.getTestContext().getLog()
3598 << tcu::TestLog::Message
3599 << "Error. Invalid result. Function: getActiveSubroutineName. idnex: " << uniform
3600 << ". Result: " << &active_subroutine_name[0] << tcu::TestLog::EndMessage;
3601
3602 result = false;
3603 break;
3604 }
3605 }
3606
3607 return result;
3608 }
3609
3610 /** Test if it is possible to "bind" all subroutines uniforms with all subroutines
3611 *
3612 * @param program_id Program object id
3613 * @param subroutine_names Array of subroutine names available in program
3614 * @param uniform_names Array of subroutine uniform names available in program
3615 *
3616 * @result false in case of invalid result, true otherwise
3617 **/
inspectSubroutineBinding(GLuint program_id,const GLchar ** subroutine_names,const GLchar ** uniform_names,bool use_program_query) const3618 bool FunctionalTest3_4::inspectSubroutineBinding(GLuint program_id, const GLchar** subroutine_names,
3619 const GLchar** uniform_names, bool use_program_query) const
3620 {
3621 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3622 bool result = true;
3623 GLint n_active_subroutines = 0;
3624 GLint n_active_subroutine_uniforms = 0;
3625 std::vector<GLuint> subroutine_uniforms;
3626 GLuint queried_subroutine_index = 0;
3627
3628 gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINES, &n_active_subroutines);
3629 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3630
3631 gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORMS, &n_active_subroutine_uniforms);
3632 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
3633
3634 subroutine_uniforms.resize(n_active_subroutine_uniforms);
3635
3636 for (GLint uniform = 0; uniform < n_active_subroutine_uniforms; ++uniform)
3637 {
3638 GLuint uniform_location = getSubroutineUniformLocation(program_id, uniform_names[uniform], use_program_query);
3639
3640 for (GLint routine = 0; routine < n_active_subroutines; ++routine)
3641 {
3642 GLuint routine_index = getSubroutineIndex(program_id, subroutine_names[routine], use_program_query);
3643
3644 subroutine_uniforms[uniform] = routine_index;
3645
3646 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, n_active_subroutine_uniforms, &subroutine_uniforms[0]);
3647 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
3648
3649 gl.getUniformSubroutineuiv(GL_VERTEX_SHADER, uniform_location, &queried_subroutine_index);
3650 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformSubroutineuiv");
3651
3652 if (queried_subroutine_index != routine_index)
3653 {
3654 m_context.getTestContext().getLog()
3655 << tcu::TestLog::Message << "Error. Invalid result. Function: gl.getUniformSubroutineuiv."
3656 << " Subroutine uniform: " << uniform << ", name: " << uniform_names[uniform]
3657 << ", location: " << uniform_location << ". Subroutine: " << routine
3658 << ", name: " << subroutine_names[routine] << ", index: " << routine_index
3659 << ". Result: " << queried_subroutine_index << tcu::TestLog::EndMessage;
3660
3661 result = false;
3662 }
3663 }
3664 }
3665
3666 return result;
3667 }
3668
3669 /** Execute draw call and verify results
3670 *
3671 * @param program_id Program object id
3672 * @param first_routine_name Name of subroutine that shall be used aas first_routine
3673 * @param second_routine_name Name of subroutine that shall be used aas second_routine
3674 * @param uniform_names Name of uniforms
3675 * @param expected_results Test data. [0] is used as input data. All are used as expected_results
3676 * @param use_program_query If true GetProgram* API will be used
3677 *
3678 * @return false in case of invalid result, true otherwise
3679 **/
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) const3680 bool FunctionalTest3_4::testDraw(GLuint program_id, const GLchar* first_routine_name, const GLchar* second_routine_name,
3681 const GLchar** uniform_names, const Utils::vec4<GLfloat> expected_results[5],
3682 bool use_program_query) const
3683 {
3684 static const GLuint n_varyings = 5;
3685 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3686 bool result = true;
3687 GLuint subroutine_uniforms[2] = { 0 };
3688
3689 /* Get subroutine uniform locations */
3690 GLint first_routine_location = getSubroutineUniformLocation(program_id, uniform_names[0], use_program_query);
3691
3692 GLint second_routine_location = getSubroutineUniformLocation(program_id, uniform_names[1], use_program_query);
3693
3694 /* Get subroutine indices */
3695 GLuint first_routine_index = getSubroutineIndex(program_id, first_routine_name, use_program_query);
3696
3697 GLuint second_routine_index = getSubroutineIndex(program_id, second_routine_name, use_program_query);
3698
3699 /* Map uniforms with subroutines */
3700 subroutine_uniforms[first_routine_location] = first_routine_index;
3701 subroutine_uniforms[second_routine_location] = second_routine_index;
3702
3703 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, 2 /* number of uniforms */, &subroutine_uniforms[0]);
3704 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
3705
3706 /* Get location of input_data */
3707 GLint input_data_location = gl.getUniformLocation(program_id, "input_data");
3708 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation");
3709
3710 if (-1 == input_data_location)
3711 {
3712 TCU_FAIL("Uniform is not available");
3713 }
3714
3715 /* Set up input_data */
3716 gl.uniform4f(input_data_location, expected_results[0].m_x, expected_results[0].m_y, expected_results[0].m_z,
3717 expected_results[0].m_w);
3718 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
3719
3720 /* Execute draw call with transform feedback */
3721 gl.beginTransformFeedback(GL_POINTS);
3722 GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
3723
3724 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
3725 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
3726
3727 gl.endTransformFeedback();
3728 GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
3729
3730 /* Verify results */
3731 GLfloat* feedback_data = (GLfloat*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
3732 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
3733
3734 Utils::vec4<GLfloat> results[5];
3735
3736 results[0].m_x = feedback_data[0];
3737 results[0].m_y = feedback_data[1];
3738 results[0].m_z = feedback_data[2];
3739 results[0].m_w = feedback_data[3];
3740
3741 results[1].m_x = feedback_data[4];
3742 results[1].m_y = feedback_data[5];
3743 results[1].m_z = feedback_data[6];
3744 results[1].m_w = feedback_data[7];
3745
3746 results[2].m_x = feedback_data[8];
3747 results[2].m_y = feedback_data[9];
3748 results[2].m_z = feedback_data[10];
3749 results[2].m_w = feedback_data[11];
3750
3751 results[3].m_x = feedback_data[12];
3752 results[3].m_y = feedback_data[13];
3753 results[3].m_z = feedback_data[14];
3754 results[3].m_w = feedback_data[15];
3755
3756 results[4].m_x = feedback_data[16];
3757 results[4].m_y = feedback_data[17];
3758 results[4].m_z = feedback_data[18];
3759 results[4].m_w = feedback_data[19];
3760
3761 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
3762 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
3763
3764 for (GLuint i = 0; i < n_varyings; ++i)
3765 {
3766 result = result && (results[i] == expected_results[i]);
3767 }
3768
3769 if (false == result)
3770 {
3771 m_context.getTestContext().getLog() << tcu::TestLog::Message
3772 << "Error. Invalid result. First routine: " << first_routine_name
3773 << ". Second routine: " << second_routine_name << tcu::TestLog::EndMessage;
3774
3775 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
3776
3777 message << "Results:";
3778
3779 for (GLuint i = 0; i < n_varyings; ++i)
3780 {
3781 results[i].log(message);
3782 }
3783
3784 message << tcu::TestLog::EndMessage;
3785
3786 message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
3787
3788 message << "Expected:";
3789
3790 for (GLuint i = 0; i < n_varyings; ++i)
3791 {
3792 expected_results[i].log(message);
3793 }
3794
3795 message << tcu::TestLog::EndMessage;
3796 }
3797
3798 return result;
3799 }
3800
3801 /** Constructor
3802 *
3803 * @param context CTS context
3804 **/
FunctionalTest5(deqp::Context & context)3805 FunctionalTest5::FunctionalTest5(deqp::Context& context)
3806 : TestCase(context, "eight_subroutines_four_uniforms", "Verify multiple subroutine sets")
3807 {
3808 }
3809
3810 /** Execute test
3811 *
3812 * @return tcu::TestNode::STOP
3813 **/
iterate()3814 tcu::TestNode::IterateResult FunctionalTest5::iterate()
3815 {
3816 static const GLchar* vertex_shader_code =
3817 "#version 400 core\n"
3818 "#extension GL_ARB_shader_subroutine : require\n"
3819 "\n"
3820 "precision highp float;\n"
3821 "\n"
3822 "// Subroutine types\n"
3823 "subroutine vec4 routine_type_1(in vec4 left, in vec4 right);\n"
3824 "subroutine vec4 routine_type_2(in vec4 iparam);\n"
3825 "subroutine vec4 routine_type_3(in vec4 a, in vec4 b, in vec4 c);\n"
3826 "subroutine bvec4 routine_type_4(in vec4 left, in vec4 right);\n"
3827 "\n"
3828 "// Subroutine definitions\n"
3829 "// 1st type\n"
3830 "subroutine(routine_type_1) vec4 add(in vec4 left, in vec4 right)\n"
3831 "{\n"
3832 " return left + right;\n"
3833 "}\n"
3834 "\n"
3835 "subroutine(routine_type_1) vec4 subtract(in vec4 left, in vec4 right)\n"
3836 "{\n"
3837 " return left - right;\n"
3838 "}\n"
3839 "\n"
3840 "// 2nd type\n"
3841 "subroutine(routine_type_2) vec4 square(in vec4 iparam)\n"
3842 "{\n"
3843 " return iparam * iparam;\n"
3844 "}\n"
3845 "\n"
3846 "subroutine(routine_type_2) vec4 square_root(in vec4 iparam)\n"
3847 "{\n"
3848 " return sqrt(iparam);\n"
3849 "}\n"
3850 "\n"
3851 "// 3rd type\n"
3852 "subroutine(routine_type_3) vec4 do_fma(in vec4 a, in vec4 b, in vec4 c)\n"
3853 "{\n"
3854 " return fma(a, b, c);\n"
3855 "}\n"
3856 "\n"
3857 "subroutine(routine_type_3) vec4 blend(in vec4 a, in vec4 b, in vec4 c)\n"
3858 "{\n"
3859 " return c * a + (vec4(1) - c) * b;\n"
3860 "}\n"
3861 "\n"
3862 "// 4th type\n"
3863 "subroutine(routine_type_4) bvec4 are_equal(in vec4 left, in vec4 right)\n"
3864 "{\n"
3865 " return equal(left, right);\n"
3866 "}\n"
3867 "\n"
3868 "subroutine(routine_type_4) bvec4 are_greater(in vec4 left, in vec4 right)\n"
3869 "{\n"
3870 " return greaterThan(left, right);\n"
3871 "}\n"
3872 "\n"
3873 "// Sub routine uniforms\n"
3874 "subroutine uniform routine_type_1 first_routine;\n"
3875 "subroutine uniform routine_type_2 second_routine;\n"
3876 "subroutine uniform routine_type_3 third_routine;\n"
3877 "subroutine uniform routine_type_4 fourth_routine;\n"
3878 "\n"
3879 "// Input data\n"
3880 "uniform vec4 first_input;\n"
3881 "uniform vec4 second_input;\n"
3882 "uniform vec4 third_input;\n"
3883 "\n"
3884 "// Output\n"
3885 "out vec4 out_result_from_first_routine;\n"
3886 "out vec4 out_result_from_second_routine;\n"
3887 "out vec4 out_result_from_third_routine;\n"
3888 "out uvec4 out_result_from_fourth_routine;\n"
3889 "\n"
3890 "void main()\n"
3891 "{\n"
3892 " out_result_from_first_routine = first_routine (first_input, second_input);\n"
3893 " out_result_from_second_routine = second_routine(first_input);\n"
3894 " out_result_from_third_routine = third_routine (first_input, second_input, third_input);\n"
3895 " out_result_from_fourth_routine = uvec4(fourth_routine(first_input, second_input));\n"
3896 "}\n"
3897 "\n";
3898
3899 static const GLchar* subroutine_names[4][2] = {
3900 { "add", "subtract" }, { "square", "square_root" }, { "do_fma", "blend" }, { "are_equal", "are_greater" }
3901 };
3902
3903 static const GLchar* subroutine_uniform_names[4][1] = {
3904 { "first_routine" }, { "second_routine" }, { "third_routine" }, { "fourth_routine" }
3905 };
3906
3907 static const GLuint n_subroutine_types = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
3908 static const GLuint n_subroutines_per_type = sizeof(subroutine_names[0]) / sizeof(subroutine_names[0][0]);
3909 static const GLuint n_subroutine_uniforms_per_type =
3910 sizeof(subroutine_uniform_names[0]) / sizeof(subroutine_uniform_names[0][0]);
3911
3912 static const GLchar* uniform_names[] = { "first_input", "second_input", "third_input" };
3913 static const GLuint n_uniform_names = sizeof(uniform_names) / sizeof(uniform_names[0]);
3914
3915 static const GLchar* varying_names[] = { "out_result_from_first_routine", "out_result_from_second_routine",
3916 "out_result_from_third_routine", "out_result_from_fourth_routine" };
3917 static const GLuint n_varyings = sizeof(varying_names) / sizeof(varying_names[0]);
3918 static const GLuint transform_feedback_buffer_size = n_varyings * sizeof(GLfloat) * 4 /* vec4 */;
3919
3920 /* Test data */
3921 static const Utils::vec4<GLfloat> input_data[3] = { Utils::vec4<GLfloat>(1.0f, 4.0f, 9.0f, 16.0f),
3922 Utils::vec4<GLfloat>(16.0f, 9.0f, 4.0f, 1.0f),
3923 Utils::vec4<GLfloat>(0.25f, 0.5f, 0.75f, 1.0f) };
3924
3925 static const Utils::vec4<GLfloat> expected_result_from_first_routine[2] = {
3926 Utils::vec4<GLfloat>(17.0f, 13.0f, 13.0f, 17.0f), Utils::vec4<GLfloat>(-15.0f, -5.0f, 5.0f, 15.0f)
3927 };
3928
3929 static const Utils::vec4<GLfloat> expected_result_from_second_routine[2] = {
3930 Utils::vec4<GLfloat>(1.0f, 16.0f, 81.0f, 256.0f), Utils::vec4<GLfloat>(1.0f, 2.0f, 3.0f, 4.0f)
3931 };
3932
3933 static const Utils::vec4<GLfloat> expected_result_from_third_routine[2] = {
3934 Utils::vec4<GLfloat>(16.25f, 36.5f, 36.75f, 17.0f), Utils::vec4<GLfloat>(12.25f, 6.5f, 7.75f, 16.0f)
3935 };
3936
3937 static const Utils::vec4<GLuint> expected_result_from_fourth_routine[2] = { Utils::vec4<GLuint>(0, 0, 0, 0),
3938 Utils::vec4<GLuint>(0, 0, 1, 1) };
3939
3940 /* All combinations of subroutines */
3941 static const GLuint subroutine_combinations[][4] = {
3942 { 0, 0, 0, 0 }, { 0, 0, 0, 1 }, { 0, 0, 1, 0 }, { 0, 0, 1, 1 }, { 0, 1, 0, 0 }, { 0, 1, 0, 1 },
3943 { 0, 1, 1, 0 }, { 0, 1, 1, 1 }, { 1, 0, 0, 0 }, { 1, 0, 0, 1 }, { 1, 0, 1, 0 }, { 1, 0, 1, 1 },
3944 { 1, 1, 0, 0 }, { 1, 1, 0, 1 }, { 1, 1, 1, 0 }, { 1, 1, 1, 1 }
3945 };
3946 static const GLuint n_subroutine_combinations =
3947 sizeof(subroutine_combinations) / sizeof(subroutine_combinations[0]);
3948
3949 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
3950 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
3951 {
3952 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
3953 }
3954
3955 /* Result */
3956 bool result = true;
3957
3958 /* GL objects */
3959 Utils::program program(m_context);
3960 Utils::buffer transform_feedback_buffer(m_context);
3961 Utils::vertexArray vao(m_context);
3962
3963 /* Init GL objects */
3964 program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code, varying_names,
3965 n_varyings);
3966
3967 program.use();
3968
3969 vao.generate();
3970 vao.bind();
3971
3972 transform_feedback_buffer.generate();
3973 transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
3974 GL_DYNAMIC_COPY);
3975 transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
3976
3977 /* Get subroutine uniform locations and subroutine indices */
3978 for (GLuint type = 0; type < n_subroutine_types; ++type)
3979 {
3980 for (GLuint uniform = 0; uniform < n_subroutine_uniforms_per_type; ++uniform)
3981 {
3982 m_subroutine_uniform_locations[type][uniform] =
3983 program.getSubroutineUniformLocation(subroutine_uniform_names[type][uniform], GL_VERTEX_SHADER);
3984 }
3985
3986 for (GLuint routine = 0; routine < n_subroutines_per_type; ++routine)
3987 {
3988 m_subroutine_indices[type][routine] =
3989 program.getSubroutineIndex(subroutine_names[type][routine], GL_VERTEX_SHADER);
3990 }
3991 }
3992
3993 /* Get uniform locations */
3994 for (GLuint i = 0; i < n_uniform_names; ++i)
3995 {
3996 m_uniform_locations[i] = program.getUniformLocation(uniform_names[i]);
3997 }
3998
3999 /* Draw with each routine combination */
4000 for (GLuint i = 0; i < n_subroutine_combinations; ++i)
4001 {
4002 Utils::vec4<GLfloat> first_routine_result;
4003 Utils::vec4<GLfloat> second_routine_result;
4004 Utils::vec4<GLfloat> third_routine_result;
4005 Utils::vec4<GLuint> fourth_routine_result;
4006
4007 testDraw(subroutine_combinations[i], input_data, first_routine_result, second_routine_result,
4008 third_routine_result, fourth_routine_result);
4009
4010 if (false == verify(first_routine_result, second_routine_result, third_routine_result, fourth_routine_result,
4011 expected_result_from_first_routine[subroutine_combinations[i][0]],
4012 expected_result_from_second_routine[subroutine_combinations[i][1]],
4013 expected_result_from_third_routine[subroutine_combinations[i][2]],
4014 expected_result_from_fourth_routine[subroutine_combinations[i][3]]))
4015 {
4016 logError(subroutine_names, subroutine_combinations[i], input_data, first_routine_result,
4017 second_routine_result, third_routine_result, fourth_routine_result,
4018 expected_result_from_first_routine[subroutine_combinations[i][0]],
4019 expected_result_from_second_routine[subroutine_combinations[i][1]],
4020 expected_result_from_third_routine[subroutine_combinations[i][2]],
4021 expected_result_from_fourth_routine[subroutine_combinations[i][3]]);
4022
4023 result = false;
4024 }
4025 }
4026
4027 /* Done */
4028 if (true == result)
4029 {
4030 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4031 }
4032 else
4033 {
4034 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
4035 }
4036
4037 return tcu::TestNode::STOP;
4038 }
4039
4040 /** Log error message
4041 *
4042 * @param subroutine_names Array of subroutine names
4043 * @param subroutine_combination Combination of subroutines
4044 * @param input_data Input data
4045 * @param first_routine_result Result of first routine
4046 * @param second_routine_result Result of second routine
4047 * @param third_routine_result Result of third routine
4048 * @param fourth_routine_result Result of fourth routine
4049 * @param first_routine_expected_result Expected result of first routine
4050 * @param second_routine_expected_result Expected result of second routine
4051 * @param third_routine_expected_result Expected result of third routine
4052 * @param fourth_routine_expected_result Expected result of fourth routine
4053 **/
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) const4054 void FunctionalTest5::logError(const glw::GLchar* subroutine_names[4][2], const glw::GLuint subroutine_combination[4],
4055 const Utils::vec4<glw::GLfloat> input_data[3],
4056 const Utils::vec4<glw::GLfloat>& first_routine_result,
4057 const Utils::vec4<glw::GLfloat>& second_routine_result,
4058 const Utils::vec4<glw::GLfloat>& third_routine_result,
4059 const Utils::vec4<glw::GLuint>& fourth_routine_result,
4060 const Utils::vec4<glw::GLfloat>& first_routine_expected_result,
4061 const Utils::vec4<glw::GLfloat>& second_routine_expected_result,
4062 const Utils::vec4<glw::GLfloat>& third_routine_expected_result,
4063 const Utils::vec4<glw::GLuint>& fourth_routine_expected_result) const
4064 {
4065 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error. Invalid result."
4066 << tcu::TestLog::EndMessage;
4067
4068 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4069
4070 message << "Function: " << subroutine_names[0][subroutine_combination[0]] << "( ";
4071 input_data[0].log(message);
4072 message << ", ";
4073 input_data[1].log(message);
4074 message << " ). Result: ";
4075 first_routine_result.log(message);
4076 message << ". Expected: ";
4077 first_routine_expected_result.log(message);
4078
4079 message << tcu::TestLog::EndMessage;
4080
4081 message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4082
4083 message << "Function: " << subroutine_names[1][subroutine_combination[1]] << "( ";
4084 input_data[0].log(message);
4085 message << " ). Result: ";
4086 second_routine_result.log(message);
4087 message << ". Expected: ";
4088 second_routine_expected_result.log(message);
4089
4090 message << tcu::TestLog::EndMessage;
4091
4092 message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4093
4094 message << "Function: " << subroutine_names[2][subroutine_combination[2]] << "( ";
4095 input_data[0].log(message);
4096 message << ", ";
4097 input_data[1].log(message);
4098 message << ", ";
4099 input_data[2].log(message);
4100 message << "). Result: ";
4101 third_routine_result.log(message);
4102 message << ". Expected: ";
4103 third_routine_expected_result.log(message);
4104
4105 message << tcu::TestLog::EndMessage;
4106
4107 message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4108
4109 message << "Function: " << subroutine_names[3][subroutine_combination[3]] << "( ";
4110 input_data[0].log(message);
4111 message << ", ";
4112 input_data[1].log(message);
4113 message << ", ";
4114 message << " ). Result: ";
4115 fourth_routine_result.log(message);
4116 message << ". Expected: ";
4117 fourth_routine_expected_result.log(message);
4118
4119 message << tcu::TestLog::EndMessage;
4120 }
4121
4122 /** Execute draw call and capture results
4123 *
4124 * @param subroutine_combination Combination of subroutines
4125 * @param input_data Input data
4126 * @param out_first_routine_result Result of first routine
4127 * @param out_second_routine_result Result of second routine
4128 * @param out_third_routine_result Result of third routine
4129 * @param out_fourth_routine_result Result of fourth routine
4130 **/
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) const4131 void FunctionalTest5::testDraw(const glw::GLuint subroutine_combination[4],
4132 const Utils::vec4<glw::GLfloat> input_data[3],
4133 Utils::vec4<glw::GLfloat>& out_first_routine_result,
4134 Utils::vec4<glw::GLfloat>& out_second_routine_result,
4135 Utils::vec4<glw::GLfloat>& out_third_routine_result,
4136 Utils::vec4<glw::GLuint>& out_fourth_routine_result) const
4137 {
4138 static const GLuint n_uniforms = sizeof(m_uniform_locations) / sizeof(m_uniform_locations[0]);
4139 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
4140 GLuint subroutine_indices[4];
4141 static const GLuint n_subroutine_uniforms = sizeof(subroutine_indices) / sizeof(subroutine_indices[0]);
4142
4143 /* Prepare subroutine uniform data */
4144 for (GLuint i = 0; i < n_subroutine_uniforms; ++i)
4145 {
4146 const GLuint location = m_subroutine_uniform_locations[i][0];
4147
4148 subroutine_indices[location] = m_subroutine_indices[i][subroutine_combination[i]];
4149 }
4150
4151 /* Set up subroutine uniforms */
4152 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, n_subroutine_uniforms, &subroutine_indices[0]);
4153 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
4154
4155 /* Set up input data uniforms */
4156 for (GLuint i = 0; i < n_uniforms; ++i)
4157 {
4158 gl.uniform4f(m_uniform_locations[i], input_data[i].m_x, input_data[i].m_y, input_data[i].m_z,
4159 input_data[i].m_w);
4160 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
4161 }
4162
4163 /* Execute draw call with transform feedback */
4164 gl.beginTransformFeedback(GL_POINTS);
4165 GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
4166
4167 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
4168 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
4169
4170 gl.endTransformFeedback();
4171 GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
4172
4173 /* Capture results */
4174 GLvoid* feedback_data = gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
4175 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
4176
4177 GLfloat* float_ptr = (GLfloat*)feedback_data;
4178
4179 /* First result */
4180 out_first_routine_result.m_x = float_ptr[0];
4181 out_first_routine_result.m_y = float_ptr[1];
4182 out_first_routine_result.m_z = float_ptr[2];
4183 out_first_routine_result.m_w = float_ptr[3];
4184
4185 /* Second result */
4186 out_second_routine_result.m_x = float_ptr[4];
4187 out_second_routine_result.m_y = float_ptr[5];
4188 out_second_routine_result.m_z = float_ptr[6];
4189 out_second_routine_result.m_w = float_ptr[7];
4190
4191 /* Third result */
4192 out_third_routine_result.m_x = float_ptr[8];
4193 out_third_routine_result.m_y = float_ptr[9];
4194 out_third_routine_result.m_z = float_ptr[10];
4195 out_third_routine_result.m_w = float_ptr[11];
4196
4197 /* Fourth result */
4198 GLuint* uint_ptr = (GLuint*)(float_ptr + 12);
4199 out_fourth_routine_result.m_x = uint_ptr[0];
4200 out_fourth_routine_result.m_y = uint_ptr[1];
4201 out_fourth_routine_result.m_z = uint_ptr[2];
4202 out_fourth_routine_result.m_w = uint_ptr[3];
4203
4204 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
4205 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
4206 }
4207
4208 /** Verify if results match expected results
4209 *
4210 * @param first_routine_result Result of first routine
4211 * @param second_routine_result Result of second routine
4212 * @param third_routine_result Result of third routine
4213 * @param fourth_routine_result Result of fourth routine
4214 * @param first_routine_expected_result Expected result of first routine
4215 * @param second_routine_expected_result Expected result of second routine
4216 * @param third_routine_expected_result Expected result of third routine
4217 * @param fourth_routine_expected_result Expected result of fourth routine
4218 **/
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) const4219 bool FunctionalTest5::verify(const Utils::vec4<glw::GLfloat>& first_routine_result,
4220 const Utils::vec4<glw::GLfloat>& second_routine_result,
4221 const Utils::vec4<glw::GLfloat>& third_routine_result,
4222 const Utils::vec4<glw::GLuint>& fourth_routine_result,
4223 const Utils::vec4<glw::GLfloat>& first_routine_expected_result,
4224 const Utils::vec4<glw::GLfloat>& second_routine_expected_result,
4225 const Utils::vec4<glw::GLfloat>& third_routine_expected_result,
4226 const Utils::vec4<glw::GLuint>& fourth_routine_expected_result) const
4227 {
4228 bool result = true;
4229
4230 result = result && (first_routine_result == first_routine_expected_result);
4231 result = result && (second_routine_result == second_routine_expected_result);
4232 result = result && (third_routine_result == third_routine_expected_result);
4233 result = result && (fourth_routine_result == fourth_routine_expected_result);
4234
4235 return result;
4236 }
4237
4238 /** Constructor
4239 *
4240 * @param context CTS context
4241 **/
FunctionalTest6(deqp::Context & context)4242 FunctionalTest6::FunctionalTest6(deqp::Context& context)
4243 : TestCase(context, "static_subroutine_call", "Verify that subroutine can be called in a static manner")
4244 {
4245 }
4246
4247 /** Execute test
4248 *
4249 * @return tcu::TestNode::STOP
4250 **/
iterate()4251 tcu::TestNode::IterateResult FunctionalTest6::iterate()
4252 {
4253 static const GLchar* vertex_shader_code = "#version 400 core\n"
4254 "#extension GL_ARB_shader_subroutine : require\n"
4255 "\n"
4256 "precision highp float;\n"
4257 "\n"
4258 "// Subroutine type\n"
4259 "subroutine vec4 routine_type(in vec4 iparam);\n"
4260 "\n"
4261 "// Subroutine definition\n"
4262 "subroutine(routine_type) vec4 square(in vec4 iparam)\n"
4263 "{\n"
4264 " return iparam * iparam;\n"
4265 "}\n"
4266 "\n"
4267 "// Sub routine uniform\n"
4268 "subroutine uniform routine_type routine;\n"
4269 "\n"
4270 "// Input data\n"
4271 "uniform vec4 input_data;\n"
4272 "\n"
4273 "// Output\n"
4274 "out vec4 out_result;\n"
4275 "\n"
4276 "void main()\n"
4277 "{\n"
4278 " out_result = square(input_data);\n"
4279 "}\n"
4280 "\n";
4281
4282 static const GLchar* varying_name = "out_result";
4283
4284 /* Test data */
4285 static const Utils::vec4<GLfloat> input_data(1.0f, 4.0f, 9.0f, 16.0f);
4286
4287 static const Utils::vec4<GLfloat> expected_result(1.0f, 16.0f, 81.0f, 256.0f);
4288
4289 static const GLuint transform_feedback_buffer_size = 4 * sizeof(GLfloat);
4290
4291 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
4292 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
4293 {
4294 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
4295 }
4296
4297 /* GL objects */
4298 Utils::program program(m_context);
4299 Utils::buffer transform_feedback_buffer(m_context);
4300 Utils::vertexArray vao(m_context);
4301
4302 /* Init GL objects */
4303 program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code, &varying_name,
4304 1 /* n_varyings */);
4305
4306 program.use();
4307
4308 vao.generate();
4309 vao.bind();
4310
4311 transform_feedback_buffer.generate();
4312 transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
4313 GL_DYNAMIC_COPY);
4314 transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
4315
4316 /* Test */
4317 {
4318 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
4319 const GLint uniform_location = gl.getUniformLocation(program.m_program_object_id, "input_data");
4320
4321 GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation");
4322
4323 if (-1 == uniform_location)
4324 {
4325 TCU_FAIL("Uniform is not available");
4326 }
4327
4328 /* Set up input data uniforms */
4329 gl.uniform4f(uniform_location, input_data.m_x, input_data.m_y, input_data.m_z, input_data.m_w);
4330 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
4331
4332 /* Execute draw call with transform feedback */
4333 gl.beginTransformFeedback(GL_POINTS);
4334 GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
4335
4336 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
4337 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
4338
4339 gl.endTransformFeedback();
4340 GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
4341
4342 /* Capture results */
4343 GLfloat* feedback_data = (GLfloat*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
4344 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
4345
4346 Utils::vec4<GLfloat> result(feedback_data[0], feedback_data[1], feedback_data[2], feedback_data[3]);
4347
4348 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
4349 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
4350
4351 /* Verify */
4352 if (expected_result == result)
4353 {
4354 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4355 }
4356 else
4357 {
4358 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error. Invalid result."
4359 << tcu::TestLog::EndMessage;
4360
4361 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4362
4363 message << "Function: square( ";
4364 input_data.log(message);
4365 message << " ). Result: ";
4366 result.log(message);
4367 message << ". Expected: ";
4368 expected_result.log(message);
4369
4370 message << tcu::TestLog::EndMessage;
4371
4372 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
4373 }
4374 }
4375
4376 /* Done */
4377 return tcu::TestNode::STOP;
4378 }
4379
4380 /** Constructor
4381 *
4382 * @param context CTS context
4383 **/
FunctionalTest7_8(deqp::Context & context)4384 FunctionalTest7_8::FunctionalTest7_8(deqp::Context& context)
4385 : TestCase(context, "arrayed_subroutine_uniforms", "Verify that subroutine can be called in a static manner")
4386 {
4387 }
4388
4389 /** Execute test
4390 *
4391 * @return tcu::TestNode::STOP
4392 **/
iterate()4393 tcu::TestNode::IterateResult FunctionalTest7_8::iterate()
4394 {
4395 static const GLchar* vertex_shader_code =
4396 "#version 400 core\n"
4397 "#extension GL_ARB_shader_subroutine : require\n"
4398 "\n"
4399 "precision highp float;\n"
4400 "\n"
4401 "// Subroutine type\n"
4402 "subroutine vec4 routine_type(in vec4 left, in vec4 right);\n"
4403 "\n"
4404 "// Subroutine definitions\n"
4405 "subroutine(routine_type) vec4 add(in vec4 left, in vec4 right)\n"
4406 "{\n"
4407 " return left + right;\n"
4408 "}\n"
4409 "\n"
4410 "subroutine(routine_type) vec4 multiply(in vec4 left, in vec4 right)\n"
4411 "{\n"
4412 " return left * right;\n"
4413 "}\n"
4414 "\n"
4415 "// Sub routine uniform\n"
4416 "subroutine uniform routine_type routine[4];\n"
4417 "\n"
4418 "// Input data\n"
4419 "uniform vec4 uni_left;\n"
4420 "uniform vec4 uni_right;\n"
4421 "uniform uvec4 uni_indices;\n"
4422 "\n"
4423 "// Output\n"
4424 "out vec4 out_combined;\n"
4425 "out vec4 out_combined_inverted;\n"
4426 "out vec4 out_constant;\n"
4427 "out vec4 out_constant_inverted;\n"
4428 "out vec4 out_dynamic;\n"
4429 "out vec4 out_dynamic_inverted;\n"
4430 "out vec4 out_loop;\n"
4431 "out uint out_array_length;\n"
4432 "\n"
4433 "void main()\n"
4434 "{\n"
4435 " out_combined = routine[3](routine[2](routine[1](routine[0](uni_left, uni_right), uni_right), "
4436 "uni_right), uni_right);\n"
4437 " out_combined_inverted = routine[0](routine[1](routine[2](routine[3](uni_left, uni_right), uni_right), "
4438 "uni_right), uni_right);\n"
4439 " \n"
4440 " out_constant = routine[3](routine[2](routine[1](routine[0](vec4(1, 2, 3, 4), vec4(-5, -6, -7, "
4441 "-8)), vec4(-1, -2, -3, -4)), vec4(5, 6, 7, 8)), vec4(1, 2, 3, 4));\n"
4442 " out_constant_inverted = routine[0](routine[1](routine[2](routine[3](vec4(1, 2, 3, 4), vec4(-5, -6, -7, "
4443 "-8)), vec4(-1, -2, -3, -4)), vec4(5, 6, 7, 8)), vec4(1, 2, 3, 4));\n"
4444 " \n"
4445 " out_dynamic = "
4446 "routine[uni_indices.w](routine[uni_indices.z](routine[uni_indices.y](routine[uni_indices.x](uni_left, "
4447 "uni_right), uni_right), uni_right), uni_right);\n"
4448 " out_dynamic_inverted = "
4449 "routine[uni_indices.x](routine[uni_indices.y](routine[uni_indices.z](routine[uni_indices.w](uni_left, "
4450 "uni_right), uni_right), uni_right), uni_right);\n"
4451 " \n"
4452 " out_loop = uni_left;\n"
4453 " for (uint i = 0u; i < routine.length(); ++i)\n"
4454 " {\n"
4455 " out_loop = routine[i](out_loop, uni_right);\n"
4456 " }\n"
4457 " \n"
4458 " out_array_length = routine.length() + 6 - (uni_indices.x + uni_indices.y + uni_indices.z + "
4459 "uni_indices.w);\n"
4460 "}\n"
4461 "\n";
4462
4463 static const GLchar* subroutine_names[] = {
4464 "add", "multiply",
4465 };
4466 static const GLuint n_subroutine_names = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
4467
4468 static const GLchar* subroutine_uniform_names[] = { "routine[0]", "routine[1]", "routine[2]", "routine[3]" };
4469 static const GLuint n_subroutine_uniform_names =
4470 sizeof(subroutine_uniform_names) / sizeof(subroutine_uniform_names[0]);
4471
4472 static const GLchar* uniform_names[] = {
4473 "uni_left", "uni_right", "uni_indices",
4474 };
4475 static const GLuint n_uniform_names = sizeof(uniform_names) / sizeof(uniform_names[0]);
4476
4477 static const GLchar* varying_names[] = { "out_combined", "out_combined_inverted",
4478 "out_constant", "out_constant_inverted",
4479 "out_dynamic", "out_dynamic_inverted",
4480 "out_loop", "out_array_length" };
4481
4482 static const GLuint n_varyings = sizeof(varying_names) / sizeof(varying_names[0]);
4483 static const GLuint transform_feedback_buffer_size = n_varyings * 4 * sizeof(GLfloat);
4484
4485 /* Test data */
4486 static const Utils::vec4<GLfloat> uni_left(-1.0f, 0.75f, -0.5f, 0.25f);
4487 static const Utils::vec4<GLfloat> uni_right(1.0f, -0.75f, 0.5f, -0.25f);
4488 static const Utils::vec4<GLuint> uni_indices(1, 2, 0, 3);
4489
4490 static const GLuint subroutine_combinations[][4] = {
4491 { 0, 0, 0, 0 }, /* + + + + */
4492 { 0, 0, 0, 1 }, /* + + + * */
4493 { 0, 0, 1, 0 }, /* + + * + */
4494 { 0, 0, 1, 1 }, /* + + * * */
4495 { 0, 1, 0, 0 }, /* + * + + */
4496 { 0, 1, 0, 1 }, /* + * + * */
4497 { 0, 1, 1, 0 }, /* + * * + */
4498 { 0, 1, 1, 1 }, /* + * * * */
4499 { 1, 0, 0, 0 }, /* * + + + */
4500 { 1, 0, 0, 1 }, /* * + + * */
4501 { 1, 0, 1, 0 }, /* * + * + */
4502 { 1, 0, 1, 1 }, /* * + * * */
4503 { 1, 1, 0, 0 }, /* * * + + */
4504 { 1, 1, 0, 1 }, /* * * + * */
4505 { 1, 1, 1, 0 }, /* * * * + */
4506 { 1, 1, 1, 1 } /* * * * * */
4507 };
4508 static const GLuint n_subroutine_combinations =
4509 sizeof(subroutine_combinations) / sizeof(subroutine_combinations[0]);
4510
4511 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
4512 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
4513 {
4514 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
4515 }
4516
4517 /* GL objects */
4518 Utils::program program(m_context);
4519 Utils::buffer transform_feedback_buffer(m_context);
4520 Utils::vertexArray vao(m_context);
4521
4522 bool result = true;
4523
4524 /* Init GL objects */
4525 program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code, varying_names,
4526 n_varyings);
4527
4528 program.use();
4529
4530 vao.generate();
4531 vao.bind();
4532
4533 transform_feedback_buffer.generate();
4534
4535 /* Get subroutine indices */
4536 for (GLuint routine = 0; routine < n_subroutine_names; ++routine)
4537 {
4538 m_subroutine_indices[routine] = program.getSubroutineIndex(subroutine_names[routine], GL_VERTEX_SHADER);
4539 }
4540
4541 /* Get subroutine uniform locations */
4542 for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
4543 {
4544 m_subroutine_uniform_locations[uniform] =
4545 program.getSubroutineUniformLocation(subroutine_uniform_names[uniform], GL_VERTEX_SHADER);
4546 }
4547
4548 /* Get uniform locations */
4549 for (GLuint i = 0; i < n_uniform_names; ++i)
4550 {
4551 m_uniform_locations[i] = program.getUniformLocation(uniform_names[i]);
4552 }
4553
4554 /* Test */
4555 for (GLuint i = 0; i < n_subroutine_combinations; ++i)
4556 {
4557 /* Clean */
4558 transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
4559 GL_DYNAMIC_COPY);
4560 transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
4561
4562 /* Verify */
4563 if (false == testDraw(subroutine_combinations[i], uni_left, uni_right, uni_indices))
4564 {
4565 result = false;
4566 }
4567 }
4568
4569 if (true == result)
4570 {
4571 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4572 }
4573 else
4574 {
4575 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
4576 }
4577
4578 /* Done */
4579 return tcu::TestNode::STOP;
4580 }
4581
4582 /* Calculate result of function applied to operands
4583 *
4584 * @param function Function id, 0 is sum, 1 is multiplication
4585 * @param left Left operand
4586 * @param right Right operand
4587 * @param out Function result
4588 **/
calculate(glw::GLuint function,const Utils::vec4<glw::GLfloat> & left,const Utils::vec4<glw::GLfloat> & right,Utils::vec4<glw::GLfloat> & out) const4589 void FunctionalTest7_8::calculate(glw::GLuint function, const Utils::vec4<glw::GLfloat>& left,
4590 const Utils::vec4<glw::GLfloat>& right, Utils::vec4<glw::GLfloat>& out) const
4591 {
4592 if (0 == function)
4593 {
4594 out.m_x = left.m_x + right.m_x;
4595 out.m_y = left.m_y + right.m_y;
4596 out.m_z = left.m_z + right.m_z;
4597 out.m_w = left.m_w + right.m_w;
4598 }
4599 else
4600 {
4601 out.m_x = left.m_x * right.m_x;
4602 out.m_y = left.m_y * right.m_y;
4603 out.m_z = left.m_z * right.m_z;
4604 out.m_w = left.m_w * right.m_w;
4605 }
4606 }
4607
4608 /** Calculate expected values for all operations
4609 *
4610 * @param combination Function combination, first applied function is at index [0]
4611 * @param left Left operand
4612 * @param right Right operand
4613 * @param indices Indices used by dynamic calls
4614 * @param out_combined Expected result of "combined" operation
4615 * @param out_combined_inverted Expected result of "combined_inverted" operation
4616 * @param out_constant Expected result of "constant" operation
4617 * @param out_constant_inverted Expected result of "constant_inverted" operation
4618 * @param out_dynamic Expected result of "dynamic" operation
4619 * @param out_dynamic_inverted Expected result of "out_dynamic_inverted" operation
4620 * @param out_loop Expected result of "loop" operation
4621 **/
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) const4622 void FunctionalTest7_8::calculate(
4623 const glw::GLuint combination[4], const Utils::vec4<glw::GLfloat>& left, const Utils::vec4<glw::GLfloat>& right,
4624 const Utils::vec4<glw::GLuint>& indices, Utils::vec4<glw::GLfloat>& out_combined,
4625 Utils::vec4<glw::GLfloat>& out_combined_inverted, Utils::vec4<glw::GLfloat>& out_constant,
4626 Utils::vec4<glw::GLfloat>& out_constant_inverted, Utils::vec4<glw::GLfloat>& out_dynamic,
4627 Utils::vec4<glw::GLfloat>& out_dynamic_inverted, Utils::vec4<glw::GLfloat>& out_loop) const
4628 {
4629 /* Indices used by "dynamic" operations, range <0..4> */
4630 const GLuint dynamic_combination[4] = { combination[indices.m_x], combination[indices.m_y],
4631 combination[indices.m_z], combination[indices.m_w] };
4632
4633 /* Values used by "constant" operations, come from shader code */
4634 const Utils::vec4<glw::GLfloat> constant_values[] = { Utils::vec4<glw::GLfloat>(1, 2, 3, 4),
4635 Utils::vec4<glw::GLfloat>(-5, -6, -7, -8),
4636 Utils::vec4<glw::GLfloat>(-1, -2, -3, -4),
4637 Utils::vec4<glw::GLfloat>(5, 6, 7, 8),
4638 Utils::vec4<glw::GLfloat>(1, 2, 3, 4) };
4639
4640 /* Start values */
4641 Utils::vec4<glw::GLfloat> combined = left;
4642 Utils::vec4<glw::GLfloat> combined_inverted = left;
4643 Utils::vec4<glw::GLfloat> constant = constant_values[0];
4644 Utils::vec4<glw::GLfloat> constant_inverted = constant_values[0];
4645 Utils::vec4<glw::GLfloat> dynamic = left;
4646 Utils::vec4<glw::GLfloat> dynamic_inverted = left;
4647
4648 /* Calculate expected results */
4649 for (GLuint i = 0; i < 4; ++i)
4650 {
4651 GLuint function = combination[i];
4652 GLuint function_inverted = combination[3 - i];
4653 GLuint dynamic_function = dynamic_combination[i];
4654 GLuint dynamic_function_inverted = dynamic_combination[3 - i];
4655
4656 calculate(function, combined, right, combined);
4657 calculate(function_inverted, combined_inverted, right, combined_inverted);
4658 calculate(function, constant, constant_values[i + 1], constant);
4659 calculate(function_inverted, constant_inverted, constant_values[i + 1], constant_inverted);
4660 calculate(dynamic_function, dynamic, right, dynamic);
4661 calculate(dynamic_function_inverted, dynamic_inverted, right, dynamic_inverted);
4662 }
4663
4664 /* Store results */
4665 out_combined = combined;
4666 out_combined_inverted = combined_inverted;
4667 out_constant = constant;
4668 out_constant_inverted = constant_inverted;
4669 out_dynamic = dynamic;
4670 out_dynamic_inverted = dynamic_inverted;
4671 out_loop = combined;
4672 }
4673
4674 /** Log error
4675 *
4676 * @param combination Operations combination
4677 * @param left Left operand
4678 * @param right Right operand
4679 * @param indices Inidices used by "dynamic" calls
4680 * @param vec4_expected Expected results
4681 * @param vec4_result Results
4682 * @param array_length Length of array
4683 * @param result Comparison results
4684 **/
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]) const4685 void FunctionalTest7_8::logError(const glw::GLuint combination[4], const Utils::vec4<glw::GLfloat>& left,
4686 const Utils::vec4<glw::GLfloat>& right, const Utils::vec4<glw::GLuint>& indices,
4687 const Utils::vec4<glw::GLfloat> vec4_expected[7],
4688 const Utils::vec4<glw::GLfloat> vec4_result[7], glw::GLuint array_length,
4689 bool result[7]) const
4690 {
4691 static const GLuint n_functions = 4;
4692 static const GLuint n_operations = 7;
4693
4694 /* Indices used by "dynamic" operations, range <0..4> */
4695 const GLuint dynamic_combination[4] = { combination[indices.m_x], combination[indices.m_y],
4696 combination[indices.m_z], combination[indices.m_w] };
4697
4698 /* Function symbols */
4699 GLchar functions[4];
4700 GLchar functions_inverted[4];
4701 GLchar functions_dynamic[4];
4702 GLchar functions_dynamic_inverted[4];
4703
4704 for (GLuint i = 0; i < n_functions; ++i)
4705 {
4706 GLchar function = (0 == combination[i]) ? '+' : '*';
4707 GLchar dynamic_function = (0 == dynamic_combination[i]) ? '+' : '*';
4708
4709 functions[i] = function;
4710 functions_inverted[n_functions - i - 1] = function;
4711 functions_dynamic[i] = dynamic_function;
4712 functions_dynamic_inverted[n_functions - i - 1] = dynamic_function;
4713 }
4714
4715 /* Values used by "constant" operations, come from shader code */
4716 const Utils::vec4<glw::GLfloat> constant_values[] = { Utils::vec4<glw::GLfloat>(1, 2, 3, 4),
4717 Utils::vec4<glw::GLfloat>(-5, -6, -7, -8),
4718 Utils::vec4<glw::GLfloat>(-1, -2, -3, -4),
4719 Utils::vec4<glw::GLfloat>(5, 6, 7, 8),
4720 Utils::vec4<glw::GLfloat>(1, 2, 3, 4) };
4721
4722 /* Values used by non-"constant" operations */
4723 Utils::vec4<glw::GLfloat> dynamic_values[5];
4724 dynamic_values[0] = left;
4725 dynamic_values[1] = right;
4726 dynamic_values[2] = right;
4727 dynamic_values[3] = right;
4728 dynamic_values[4] = right;
4729
4730 /* For each operation */
4731 for (GLuint i = 0; i < n_operations; ++i)
4732 {
4733 /* If result is failure */
4734 if (false == result[i])
4735 {
4736 const GLchar* description = 0;
4737 const Utils::vec4<glw::GLfloat>* input = 0;
4738 const GLchar* operation = 0;
4739
4740 switch (i)
4741 {
4742 case 0:
4743 description = "Call made with predefined array indices";
4744 input = dynamic_values;
4745 operation = functions;
4746 break;
4747 case 1:
4748 description = "Call made with predefined array indices in inverted order";
4749 input = dynamic_values;
4750 operation = functions_inverted;
4751 break;
4752 case 2:
4753 description = "Call made with predefined array indices, for constant values";
4754 input = constant_values;
4755 operation = functions;
4756 break;
4757 case 3:
4758 description = "Call made with predefined array indices in inverted order, for constant values";
4759 input = constant_values;
4760 operation = functions_inverted;
4761 break;
4762 case 4:
4763 description = "Call made with dynamic array indices";
4764 input = dynamic_values;
4765 operation = functions_dynamic;
4766 break;
4767 case 5:
4768 description = "Call made with dynamic array indices in inverted order";
4769 input = dynamic_values;
4770 operation = functions_dynamic_inverted;
4771 break;
4772 case 6:
4773 description = "Call made with loop";
4774 input = dynamic_values;
4775 operation = functions;
4776 break;
4777 }
4778
4779 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error. Invalid result."
4780 << tcu::TestLog::EndMessage;
4781
4782 m_context.getTestContext().getLog() << tcu::TestLog::Message << description << tcu::TestLog::EndMessage;
4783
4784 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4785
4786 message << "Operation: ((((";
4787 input[0].log(message);
4788 for (GLuint function = 0; function < n_functions; ++function)
4789 {
4790 message << " " << operation[function] << " ";
4791
4792 input[function + 1].log(message);
4793
4794 message << ")";
4795 }
4796
4797 message << tcu::TestLog::EndMessage;
4798
4799 message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4800
4801 message << "Result: ";
4802 vec4_result[i].log(message);
4803
4804 message << tcu::TestLog::EndMessage;
4805
4806 message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
4807
4808 message << "Expected: ";
4809 vec4_expected[i].log(message);
4810
4811 message << tcu::TestLog::EndMessage;
4812 }
4813
4814 /* Check array length, it should be 4 */
4815 if (4 != array_length)
4816 {
4817 m_context.getTestContext().getLog() << tcu::TestLog::Message
4818 << "Error. Invalid array length: " << array_length << ". Expected 4."
4819 << tcu::TestLog::EndMessage;
4820 }
4821 }
4822 }
4823
4824 /** Execute draw call and verifies captrued varyings
4825 *
4826 * @param combination Function combination, first applied function is at index [0]
4827 * @param left Left operand
4828 * @param right Right operand
4829 * @param indices Indices used by dynamic calls
4830 *
4831 * @return true if all results match expected values, false otherwise
4832 **/
testDraw(const glw::GLuint combination[4],const Utils::vec4<glw::GLfloat> & left,const Utils::vec4<glw::GLfloat> & right,const Utils::vec4<glw::GLuint> & indices) const4833 bool FunctionalTest7_8::testDraw(const glw::GLuint combination[4], const Utils::vec4<glw::GLfloat>& left,
4834 const Utils::vec4<glw::GLfloat>& right, const Utils::vec4<glw::GLuint>& indices) const
4835 {
4836 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
4837 static const GLuint n_vec4_varyings = 7;
4838 bool result = true;
4839 GLuint subroutine_indices[4];
4840 static const GLuint n_subroutine_uniforms = sizeof(subroutine_indices) / sizeof(subroutine_indices[0]);
4841
4842 /* Prepare expected results */
4843 Utils::vec4<glw::GLfloat> expected_results[7];
4844 calculate(combination, left, right, indices, expected_results[0], expected_results[1], expected_results[2],
4845 expected_results[3], expected_results[4], expected_results[5], expected_results[6]);
4846
4847 /* Set up input data uniforms */
4848 gl.uniform4f(m_uniform_locations[0], left.m_x, left.m_y, left.m_z, left.m_w);
4849 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
4850
4851 gl.uniform4f(m_uniform_locations[1], right.m_x, right.m_y, right.m_z, right.m_w);
4852 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
4853
4854 gl.uniform4ui(m_uniform_locations[2], indices.m_x, indices.m_y, indices.m_z, indices.m_w);
4855 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4ui");
4856
4857 /* Prepare subroutine uniform data */
4858 for (GLuint i = 0; i < n_subroutine_uniforms; ++i)
4859 {
4860 const GLuint location = m_subroutine_uniform_locations[i];
4861
4862 subroutine_indices[location] = m_subroutine_indices[combination[i]];
4863 }
4864
4865 /* Set up subroutine uniforms */
4866 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, n_subroutine_uniforms, &subroutine_indices[0]);
4867 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
4868
4869 /* Execute draw call with transform feedback */
4870 gl.beginTransformFeedback(GL_POINTS);
4871 GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
4872
4873 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
4874 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
4875
4876 gl.endTransformFeedback();
4877 GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
4878
4879 /* Capture results */
4880 GLvoid* feedback_data = (GLvoid*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
4881 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
4882
4883 Utils::vec4<GLfloat> vec4_results[7];
4884 bool results[7];
4885 GLfloat* float_data = (GLfloat*)feedback_data;
4886 for (GLuint i = 0; i < n_vec4_varyings; ++i)
4887 {
4888 vec4_results[i].m_x = float_data[i * 4 + 0];
4889 vec4_results[i].m_y = float_data[i * 4 + 1];
4890 vec4_results[i].m_z = float_data[i * 4 + 2];
4891 vec4_results[i].m_w = float_data[i * 4 + 3];
4892 }
4893
4894 GLuint* uint_data = (GLuint*)(float_data + (n_vec4_varyings)*4);
4895 GLuint array_length = uint_data[0];
4896
4897 /* Unmap buffer */
4898 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
4899 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
4900
4901 /* Verification */
4902 for (GLuint i = 0; i < n_vec4_varyings; ++i)
4903 {
4904 results[i] = (vec4_results[i] == expected_results[i]);
4905 result = result && results[i];
4906 }
4907
4908 result = result && (4 == array_length);
4909
4910 /* Log error if any */
4911 if (false == result)
4912 {
4913 logError(combination, left, right, indices, expected_results, vec4_results, array_length, results);
4914 }
4915
4916 /* Done */
4917 return result;
4918 }
4919
4920 /** Constructor.
4921 *
4922 * @param context Rendering context.
4923 *
4924 **/
FunctionalTest9(deqp::Context & context)4925 FunctionalTest9::FunctionalTest9(deqp::Context& context)
4926 : TestCase(context, "subroutines_3_subroutine_types_and_subroutine_uniforms_one_function",
4927 "Makes sure that program with one function associated with 3 different "
4928 "subroutine types and 3 subroutine uniforms using that function compiles "
4929 "and works as expected")
4930 , m_has_test_passed(true)
4931 , m_n_points_to_draw(16) /* arbitrary value */
4932 , m_po_id(0)
4933 , m_vao_id(0)
4934 , m_vs_id(0)
4935 , m_xfb_bo_id(0)
4936 {
4937 /* Left blank intentionally */
4938 }
4939
4940 /** De-initializes GL objects that may have been created during test execution. */
deinit()4941 void FunctionalTest9::deinit()
4942 {
4943 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
4944
4945 if (m_po_id != 0)
4946 {
4947 gl.deleteProgram(m_po_id);
4948
4949 m_po_id = 0;
4950 }
4951
4952 if (m_vao_id != 0)
4953 {
4954 gl.deleteVertexArrays(1, &m_vao_id);
4955
4956 m_vao_id = 0;
4957 }
4958
4959 if (m_vs_id != 0)
4960 {
4961 gl.deleteShader(m_vs_id);
4962
4963 m_vs_id = 0;
4964 }
4965
4966 if (m_xfb_bo_id != 0)
4967 {
4968 gl.deleteBuffers(1, &m_xfb_bo_id);
4969
4970 m_xfb_bo_id = 0;
4971 }
4972 }
4973
4974 /** Retrieves body of a vertex shader that should be used
4975 * for the testing purposes.
4976 **/
getVertexShaderBody() const4977 std::string FunctionalTest9::getVertexShaderBody() const
4978 {
4979 return "#version 400\n"
4980 "\n"
4981 "#extension GL_ARB_shader_subroutine : require\n"
4982 "\n"
4983 "subroutine void subroutineType1(inout float);\n"
4984 "subroutine void subroutineType2(inout float);\n"
4985 "subroutine void subroutineType3(inout float);\n"
4986 "\n"
4987 "subroutine(subroutineType1, subroutineType2, subroutineType3) void function(inout float result)\n"
4988 "{\n"
4989 " result += float(0.123) + float(gl_VertexID);\n"
4990 "}\n"
4991 "\n"
4992 "subroutine uniform subroutineType1 subroutine_uniform1;\n"
4993 "subroutine uniform subroutineType2 subroutine_uniform2;\n"
4994 "subroutine uniform subroutineType3 subroutine_uniform3;\n"
4995 "\n"
4996 "out vec4 result;\n"
4997 "\n"
4998 "void main()\n"
4999 "{\n"
5000 " result = vec4(0, 1, 2, 3);\n"
5001 "\n"
5002 " subroutine_uniform1(result.x);\n"
5003 " subroutine_uniform2(result.y);\n"
5004 " subroutine_uniform3(result.z);\n"
5005 "\n"
5006 " result.w += result.x + result.y + result.z;\n"
5007 "}\n";
5008 }
5009
5010 /** Initializes all GL objects required to run the test. */
initTest()5011 void FunctionalTest9::initTest()
5012 {
5013 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
5014
5015 /* Set up program object */
5016 const char* xfb_varyings[] = { "result" };
5017
5018 const unsigned int n_xfb_varyings = sizeof(xfb_varyings) / sizeof(xfb_varyings[0]);
5019 if (!Utils::buildProgram(gl, getVertexShaderBody(), "", /* tc_body */
5020 "", /* te_body */
5021 "", /* gs_body */
5022 "", /* fs_body */
5023 xfb_varyings, n_xfb_varyings, &m_vs_id, DE_NULL, /* out_tc_id */
5024 DE_NULL, /* out_te_id */
5025 DE_NULL, /* out_gs_id */
5026 DE_NULL, /* out_fs_id */
5027 &m_po_id))
5028 {
5029 TCU_FAIL("Program failed to link successfully");
5030 }
5031
5032 /* Set up a buffer object we will use to hold XFB data */
5033 const unsigned int xfb_bo_size = static_cast<unsigned int>(sizeof(float) * 4 /* components */ * m_n_points_to_draw);
5034
5035 gl.genBuffers(1, &m_xfb_bo_id);
5036 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
5037
5038 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_xfb_bo_id);
5039 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
5040
5041 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_xfb_bo_id);
5042 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed.");
5043
5044 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_bo_size, DE_NULL, /* data */
5045 GL_STATIC_COPY);
5046 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
5047
5048 /* Generate & bind a VAO */
5049 gl.genVertexArrays(1, &m_vao_id);
5050 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
5051
5052 gl.bindVertexArray(m_vao_id);
5053 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
5054 }
5055
5056 /** Executes test iteration.
5057 *
5058 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
5059 */
iterate()5060 tcu::TestNode::IterateResult FunctionalTest9::iterate()
5061 {
5062 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
5063
5064 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
5065 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
5066 {
5067 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
5068 }
5069 initTest();
5070
5071 /* Issue a draw call to make use of the three subroutine uniforms that we've defined */
5072 gl.useProgram(m_po_id);
5073 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
5074
5075 gl.beginTransformFeedback(GL_POINTS);
5076 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed.");
5077 {
5078 gl.drawArrays(GL_POINTS, 0 /* first */, m_n_points_to_draw);
5079 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
5080 }
5081 gl.endTransformFeedback();
5082 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed.");
5083
5084 /* Map the XFB BO storage into process space */
5085 const glw::GLvoid* xfb_data_ptr = gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
5086 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer() call failed.");
5087
5088 verifyXFBData(xfb_data_ptr);
5089
5090 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
5091 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
5092
5093 /* All done */
5094 if (m_has_test_passed)
5095 {
5096 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5097 }
5098 else
5099 {
5100 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
5101 }
5102
5103 return STOP;
5104 }
5105
5106 /** Verifies the data XFBed out by the vertex shader. Should the data
5107 * be found invalid, m_has_test_passed will be set to false.
5108 *
5109 * @param data_ptr XFB data.
5110 **/
verifyXFBData(const glw::GLvoid * data_ptr)5111 void FunctionalTest9::verifyXFBData(const glw::GLvoid* data_ptr)
5112 {
5113 const float epsilon = 1e-5f;
5114 bool should_continue = true;
5115 const glw::GLfloat* traveller_ptr = (const glw::GLfloat*)data_ptr;
5116
5117 for (unsigned int n_point = 0; n_point < m_n_points_to_draw && should_continue; ++n_point)
5118 {
5119 tcu::Vec4 expected_result(0, 1, 2, 3);
5120
5121 for (unsigned int n_component = 0; n_component < 3 /* xyz */; ++n_component)
5122 {
5123 expected_result[n_component] += 0.123f + float(n_point);
5124 }
5125
5126 expected_result[3 /* w */] += expected_result[0] + expected_result[1] + expected_result[2];
5127
5128 if (de::abs(expected_result[0] - traveller_ptr[0]) > epsilon ||
5129 de::abs(expected_result[1] - traveller_ptr[1]) > epsilon ||
5130 de::abs(expected_result[2] - traveller_ptr[2]) > epsilon ||
5131 de::abs(expected_result[3] - traveller_ptr[3]) > epsilon)
5132 {
5133 m_testCtx.getLog() << tcu::TestLog::Message << "XFBed data is invalid. Expected:"
5134 "("
5135 << expected_result[0] << ", " << expected_result[1] << ", " << expected_result[2] << ", "
5136 << expected_result[3] << "), found:(" << traveller_ptr[0] << ", " << traveller_ptr[1]
5137 << ", " << traveller_ptr[2] << ", " << traveller_ptr[3] << ")."
5138 << tcu::TestLog::EndMessage;
5139
5140 m_has_test_passed = false;
5141 should_continue = false;
5142 }
5143
5144 traveller_ptr += 4; /* xyzw */
5145 } /* for (all rendered points) */
5146 }
5147
5148 /** Constructor
5149 *
5150 * @param context CTS context
5151 **/
FunctionalTest10(deqp::Context & context)5152 FunctionalTest10::FunctionalTest10(deqp::Context& context)
5153 : TestCase(context, "arrays_of_arrays_of_uniforms", "Verify that arrays of arrays of uniforms works as expected")
5154 {
5155 }
5156
5157 /** Execute test
5158 *
5159 * @return tcu::TestNode::STOP
5160 **/
iterate()5161 tcu::TestNode::IterateResult FunctionalTest10::iterate()
5162 {
5163 static const GLchar* vertex_shader_code = "#version 400 core\n"
5164 "#extension GL_ARB_arrays_of_arrays : require\n"
5165 "#extension GL_ARB_shader_subroutine : require\n"
5166 "\n"
5167 "precision highp float;\n"
5168 "\n"
5169 "// Subroutine type\n"
5170 "subroutine int routine_type(in int iparam);\n"
5171 "\n"
5172 "// Subroutine definitions\n"
5173 "subroutine(routine_type) int increment(in int iparam)\n"
5174 "{\n"
5175 " return iparam + 1;\n"
5176 "}\n"
5177 "\n"
5178 "subroutine(routine_type) int decrement(in int iparam)\n"
5179 "{\n"
5180 " return iparam - 1;\n"
5181 "}\n"
5182 "\n"
5183 "// Sub routine uniform\n"
5184 "subroutine uniform routine_type routine[4][4];\n"
5185 "\n"
5186 "// Output\n"
5187 "out int out_result;\n"
5188 "\n"
5189 "void main()\n"
5190 "{\n"
5191 " int result = 0;\n"
5192 " \n"
5193 " for (uint j = 0; j < routine.length(); ++j)\n"
5194 " {\n"
5195 " for (uint i = 0; i < routine[j].length(); ++i)\n"
5196 " {\n"
5197 " result = routine[j][i](result);\n"
5198 " }\n"
5199 " }\n"
5200 " \n"
5201 " out_result = result;\n"
5202 "}\n"
5203 "\n";
5204
5205 static const GLchar* subroutine_names[] = {
5206 "increment", "decrement",
5207 };
5208 static const GLuint n_subroutine_names = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
5209
5210 static const GLchar* subroutine_uniform_names[] = {
5211 "routine[0][0]", "routine[1][0]", "routine[2][0]", "routine[3][0]", "routine[0][1]", "routine[1][1]",
5212 "routine[2][1]", "routine[3][1]", "routine[0][2]", "routine[1][2]", "routine[2][2]", "routine[3][2]",
5213 "routine[0][3]", "routine[1][3]", "routine[2][3]", "routine[3][3]"
5214 };
5215 static const GLuint n_subroutine_uniform_names =
5216 sizeof(subroutine_uniform_names) / sizeof(subroutine_uniform_names[0]);
5217
5218 static const GLchar* varying_name = "out_result";
5219 static const GLuint transform_feedback_buffer_size = sizeof(GLint);
5220
5221 static const GLuint configuration_increment[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
5222
5223 static const GLuint configuration_decrement[16] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
5224
5225 static const GLuint configuration_mix[16] = { 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1 };
5226
5227 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
5228 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
5229 {
5230 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
5231 }
5232
5233 /* Do not execute the test if GL_ARB_arrays_of_arrays is not supported */
5234 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_arrays_of_arrays"))
5235 {
5236 throw tcu::NotSupportedError("GL_ARB_arrays_of_arrays is not supported.");
5237 }
5238
5239 bool result = true;
5240
5241 /* GL objects */
5242 Utils::program program(m_context);
5243 Utils::buffer transform_feedback_buffer(m_context);
5244 Utils::vertexArray vao(m_context);
5245
5246 /* Init GL objects */
5247 program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code, &varying_name,
5248 1 /* n_varyings */);
5249
5250 program.use();
5251
5252 vao.generate();
5253 vao.bind();
5254
5255 transform_feedback_buffer.generate();
5256 transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
5257 GL_DYNAMIC_COPY);
5258 transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
5259
5260 /* Get subroutine indices */
5261 for (GLuint routine = 0; routine < n_subroutine_names; ++routine)
5262 {
5263 m_subroutine_indices[routine] = program.getSubroutineIndex(subroutine_names[routine], GL_VERTEX_SHADER);
5264 }
5265
5266 /* Get subroutine uniform locations */
5267 for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
5268 {
5269 m_subroutine_uniform_locations[uniform] =
5270 program.getSubroutineUniformLocation(subroutine_uniform_names[uniform], GL_VERTEX_SHADER);
5271 }
5272
5273 /* Test */
5274 GLint increment_result = testDraw(configuration_increment);
5275 GLint decrement_result = testDraw(configuration_decrement);
5276 GLint mix_result = testDraw(configuration_mix);
5277
5278 /* Verify */
5279 if (16 != increment_result)
5280 {
5281 result = false;
5282 }
5283
5284 if (-16 != decrement_result)
5285 {
5286 result = false;
5287 }
5288 if (0 != mix_result)
5289 {
5290 result = false;
5291 }
5292
5293 /* Set test result */
5294 if (true == result)
5295 {
5296 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5297 }
5298 else
5299 {
5300 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error. Invalid result."
5301 << " Incrementation applied 16 times: " << increment_result
5302 << ". Decrementation applied 16 times: " << decrement_result
5303 << ". Incrementation and decrementation applied 8 times: " << mix_result
5304 << tcu::TestLog::EndMessage;
5305
5306 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
5307 }
5308
5309 /* Done */
5310 return tcu::TestNode::STOP;
5311 }
5312
5313 /** Execute draw call and return captured varying
5314 *
5315 * @param routine_indices Configuration of subroutine uniforms
5316 *
5317 * @return Value of varying captured with transform feedback
5318 **/
testDraw(const GLuint routine_indices[16]) const5319 GLint FunctionalTest10::testDraw(const GLuint routine_indices[16]) const
5320 {
5321 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
5322 GLuint subroutine_indices[16];
5323 static const GLuint n_subroutine_uniforms = sizeof(subroutine_indices) / sizeof(subroutine_indices[0]);
5324
5325 /* Prepare subroutine uniform data */
5326 for (GLuint i = 0; i < n_subroutine_uniforms; ++i)
5327 {
5328 const GLuint location = m_subroutine_uniform_locations[i];
5329
5330 subroutine_indices[location] = m_subroutine_indices[routine_indices[i]];
5331 }
5332
5333 /* Set up subroutine uniforms */
5334 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, n_subroutine_uniforms, &subroutine_indices[0]);
5335 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
5336
5337 /* Execute draw call with transform feedback */
5338 gl.beginTransformFeedback(GL_POINTS);
5339 GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
5340
5341 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
5342 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
5343
5344 gl.endTransformFeedback();
5345 GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
5346
5347 /* Capture results */
5348 GLint* feedback_data = (GLint*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
5349 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
5350
5351 GLint result = feedback_data[0];
5352
5353 /* Unmap buffer */
5354 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
5355 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
5356
5357 return result;
5358 }
5359
5360 /* Definitions of constants used by FunctionalTest11 */
5361 const GLuint FunctionalTest11::m_texture_height = 32;
5362 const GLuint FunctionalTest11::m_texture_width = 32;
5363
5364 /** Constructor
5365 *
5366 * @param context CTS context
5367 **/
FunctionalTest11(deqp::Context & context)5368 FunctionalTest11::FunctionalTest11(deqp::Context& context)
5369 : TestCase(context, "globals_sampling_output_discard_function_calls", "Verify that global variables, texture "
5370 "sampling, fragment output, fragment discard "
5371 "and function calls work as expected")
5372 {
5373 }
5374
5375 /** Execute test
5376 *
5377 * @return tcu::TestNode::STOP
5378 **/
iterate()5379 tcu::TestNode::IterateResult FunctionalTest11::iterate()
5380 {
5381 static const GLchar* fragment_shader_code =
5382 "#version 400 core\n"
5383 "#extension GL_ARB_shader_subroutine : require\n"
5384 "\n"
5385 "precision highp float;\n"
5386 "\n"
5387 "// Output\n"
5388 "layout(location = 0) out vec4 out_color;\n"
5389 "\n"
5390 "// Global variables\n"
5391 "vec4 success_color;\n"
5392 "vec4 failure_color;\n"
5393 "\n"
5394 "// Samplers\n"
5395 "uniform sampler2D sampler_1;\n"
5396 "uniform sampler2D sampler_2;\n"
5397 "\n"
5398 "// Functions\n"
5399 "bool are_same(in vec4 left, in vec4 right)\n"
5400 "{\n"
5401 " bvec4 result;\n"
5402 "\n"
5403 " result.x = (left.x == right.x);\n"
5404 " result.y = (left.y == right.y);\n"
5405 " result.z = (left.z == right.z);\n"
5406 " result.w = (left.w == right.w);\n"
5407 "\n"
5408 " return all(result);\n"
5409 "}\n"
5410 "\n"
5411 "bool are_different(in vec4 left, in vec4 right)\n"
5412 "{\n"
5413 " bvec4 result;\n"
5414 "\n"
5415 " result.x = (left.x != right.x);\n"
5416 " result.y = (left.y != right.y);\n"
5417 " result.z = (left.z != right.z);\n"
5418 " result.w = (left.w != right.w);\n"
5419 "\n"
5420 " return any(result);\n"
5421 "}\n"
5422 "\n"
5423 "// Subroutine types\n"
5424 "subroutine void discard_fragment_type(void);\n"
5425 "subroutine void set_global_colors_type(void);\n"
5426 "subroutine vec4 sample_texture_type(in vec2);\n"
5427 "subroutine bool comparison_type(in vec4 left, in vec4 right);\n"
5428 "subroutine void test_type(void);\n"
5429 "\n"
5430 "// Subroutine definitions\n"
5431 "// discard_fragment_type\n"
5432 "subroutine(discard_fragment_type) void discard_yes(void)\n"
5433 "{\n"
5434 " discard;\n"
5435 "}\n"
5436 "\n"
5437 "subroutine(discard_fragment_type) void discard_no(void)\n"
5438 "{\n"
5439 "}\n"
5440 "\n"
5441 "// set_global_colors_type\n"
5442 "subroutine(set_global_colors_type) void red_pass_blue_fail(void)\n"
5443 "{\n"
5444 " success_color = vec4(1, 0, 0, 1);\n"
5445 " failure_color = vec4(0, 0, 1, 1);\n"
5446 "}\n"
5447 "\n"
5448 "subroutine(set_global_colors_type) void blue_pass_red_fail(void)\n"
5449 "{\n"
5450 " success_color = vec4(0, 0, 1, 1);\n"
5451 " failure_color = vec4(1, 0, 0, 1);\n"
5452 "}\n"
5453 "\n"
5454 "// sample_texture_type\n"
5455 "subroutine(sample_texture_type) vec4 first_sampler(in vec2 coord)\n"
5456 "{\n"
5457 " return texture(sampler_1, coord);\n"
5458 "}\n"
5459 "\n"
5460 "subroutine(sample_texture_type) vec4 second_sampler(in vec2 coord)\n"
5461 "{\n"
5462 " return texture(sampler_2, coord);\n"
5463 "}\n"
5464 "\n"
5465 "// comparison_type\n"
5466 "subroutine(comparison_type) bool check_equal(in vec4 left, in vec4 right)\n"
5467 "{\n"
5468 " return are_same(left, right);\n"
5469 "}\n"
5470 "\n"
5471 "subroutine(comparison_type) bool check_not_equal(in vec4 left, in vec4 right)\n"
5472 "{\n"
5473 " return are_different(left, right);\n"
5474 "}\n"
5475 "\n"
5476 "// Subroutine uniforms\n"
5477 "subroutine uniform discard_fragment_type discard_fragment;\n"
5478 "subroutine uniform set_global_colors_type set_global_colors;\n"
5479 "subroutine uniform sample_texture_type sample_texture;\n"
5480 "subroutine uniform comparison_type compare;\n"
5481 "\n"
5482 "// Subroutine definitions\n"
5483 "// test_type\n"
5484 "subroutine(test_type) void test_with_discard(void)\n"
5485 "{\n"
5486 " discard_fragment();"
5487 "\n"
5488 " out_color = failure_color;\n"
5489 "\n"
5490 " set_global_colors();\n"
5491 "\n"
5492 " vec4 sampled_color = sample_texture(gl_PointCoord);\n"
5493 "\n"
5494 " bool comparison_result = compare(success_color, sampled_color);\n"
5495 "\n"
5496 " if (true == comparison_result)\n"
5497 " {\n"
5498 " out_color = success_color;\n"
5499 " }\n"
5500 " else\n"
5501 " {\n"
5502 " out_color = failure_color;\n"
5503 " }\n"
5504 "}\n"
5505 "\n"
5506 "subroutine(test_type) void test_without_discard(void)\n"
5507 "{\n"
5508 " set_global_colors();\n"
5509 "\n"
5510 " vec4 sampled_color = sample_texture(gl_PointCoord);\n"
5511 "\n"
5512 " bool comparison_result = compare(success_color, sampled_color);\n"
5513 "\n"
5514 " if (true == comparison_result)\n"
5515 " {\n"
5516 " out_color = success_color;\n"
5517 " }\n"
5518 " else\n"
5519 " {\n"
5520 " out_color = failure_color;\n"
5521 " }\n"
5522 "}\n"
5523 "\n"
5524 "// Subroutine uniforms\n"
5525 "subroutine uniform test_type test;\n"
5526 "\n"
5527 "void main()\n"
5528 "{\n"
5529 " // Set colors\n"
5530 " success_color = vec4(0.5, 0.5, 0.5, 0.5);\n"
5531 " failure_color = vec4(0.5, 0.5, 0.5, 0.5);\n"
5532 "\n"
5533 " test();\n"
5534 "}\n"
5535 "\n";
5536
5537 static const GLchar* geometry_shader_code = "#version 400 core\n"
5538 "#extension GL_ARB_shader_subroutine : require\n"
5539 "\n"
5540 "precision highp float;\n"
5541 "\n"
5542 "layout(points) in;\n"
5543 "layout(triangle_strip, max_vertices = 4) out;\n"
5544 "\n"
5545 "void main()\n"
5546 "{\n"
5547 " gl_Position = vec4(-1, -1, 0, 1);\n"
5548 " EmitVertex();\n"
5549 " \n"
5550 " gl_Position = vec4(-1, 1, 0, 1);\n"
5551 " EmitVertex();\n"
5552 " \n"
5553 " gl_Position = vec4( 1, -1, 0, 1);\n"
5554 " EmitVertex();\n"
5555 " \n"
5556 " gl_Position = vec4( 1, 1, 0, 1);\n"
5557 " EmitVertex();\n"
5558 " \n"
5559 " EndPrimitive();\n"
5560 "}\n"
5561 "\n";
5562
5563 static const GLchar* vertex_shader_code = "#version 400 core\n"
5564 "#extension GL_ARB_shader_subroutine : require\n"
5565 "\n"
5566 "precision highp float;\n"
5567 "\n"
5568 "void main()\n"
5569 "{\n"
5570 "}\n"
5571 "\n";
5572
5573 static const GLchar* subroutine_names[][2] = { { "discard_yes", "discard_no" },
5574 { "red_pass_blue_fail", "blue_pass_red_fail" },
5575 { "first_sampler", "second_sampler" },
5576 { "check_equal", "check_not_equal" },
5577 { "test_with_discard", "test_without_discard" } };
5578 static const GLuint n_subroutine_types = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
5579
5580 static const GLchar* subroutine_uniform_names[] = { "discard_fragment", "set_global_colors", "sample_texture",
5581 "compare", "test" };
5582 static const GLuint n_subroutine_uniform_names =
5583 sizeof(subroutine_uniform_names) / sizeof(subroutine_uniform_names[0]);
5584
5585 static const GLchar* uniform_names[] = {
5586 "sampler_1", "sampler_2",
5587 };
5588 static const GLuint n_uniform_names = sizeof(uniform_names) / sizeof(uniform_names[0]);
5589
5590 /* Colors */
5591 static const GLubyte blue_color[4] = { 0, 0, 255, 255 };
5592 static const GLubyte clean_color[4] = { 0, 0, 0, 0 };
5593 static const GLubyte red_color[4] = { 255, 0, 0, 255 };
5594
5595 /* Configurations */
5596 static const testConfiguration test_configurations[] = {
5597 testConfiguration(
5598 "Expect red color from 1st sampler", red_color, 1 /* discard_fragment : discard_no */,
5599 0 /* set_global_colors : red_pass_blue_fail */, 0 /* sample_texture : first_sampler */,
5600 0 /* compare : check_equal */, 0 /* test : test_with_discard */, 1 /* red */,
5601 0 /* blue */),
5602
5603 testConfiguration(
5604 "Test \"without discard\" option, expect no blue color from 2nd sampler", blue_color,
5605 0 /* discard_fragment : discard_yes */, 1 /* set_global_colors : blue_pass_red_fail */,
5606 1 /* sample_texture : second_sampler */, 1 /* compare : check_not_equal */,
5607 1 /* test : test_without_discard */, 0 /* blue */, 1 /* red */),
5608
5609 testConfiguration("Fragment shoud be discarded", clean_color, 0 /* discard_fragment : discard_yes */,
5610 0 /* set_global_colors : red_pass_blue_fail */,
5611 0 /* sample_texture : first_sampler */,
5612 0 /* compare : check_equal */,
5613 0 /* test : test_with_discard */, 1 /* red */, 0 /* blue */),
5614
5615 testConfiguration(
5616 "Expect blue color from 1st sampler", blue_color, 1 /* discard_fragment : discard_no */,
5617 1 /* set_global_colors : blue_pass_red_fail */, 0 /* sample_texture : first_sampler */,
5618 0 /* compare : check_equal */, 0 /* test : test_with_discard */,
5619 0 /* blue */, 1 /* red */),
5620
5621 testConfiguration(
5622 "Expect red color from 2nd sampler", red_color, 1 /* discard_fragment : discard_no */,
5623 0 /* set_global_colors : red_pass_blue_fail */, 1 /* sample_texture : second_sampler */,
5624 0 /* compare : check_equal */, 0 /* test : test_with_discard */,
5625 0 /* blue */, 1 /* red */),
5626
5627 testConfiguration(
5628 "Expect no blue color from 2nd sampler", blue_color, 1 /* discard_fragment : discard_no */,
5629 1 /* set_global_colors : blue_pass_red_fail */, 1 /* sample_texture : second_sampler */,
5630 1 /* compare : check_not_equal */, 0 /* test : test_with_discard */,
5631 0 /* blue */, 1 /* red */),
5632 };
5633 static const GLuint n_test_cases = sizeof(test_configurations) / sizeof(test_configurations[0]);
5634
5635 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
5636 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
5637 {
5638 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
5639 }
5640
5641 /* GL objects */
5642 Utils::texture blue_texture(m_context);
5643 Utils::texture color_texture(m_context);
5644 Utils::framebuffer framebuffer(m_context);
5645 Utils::program program(m_context);
5646 Utils::texture red_texture(m_context);
5647 Utils::vertexArray vao(m_context);
5648
5649 /* Init GL objects */
5650 program.build(0 /* cs */, fragment_shader_code /* fs */, geometry_shader_code /* gs */, 0 /* tcs */, 0 /* test */,
5651 vertex_shader_code, 0 /* varying_names */, 0 /* n_varyings */);
5652
5653 program.use();
5654
5655 vao.generate();
5656 vao.bind();
5657
5658 blue_texture.create(m_texture_width, m_texture_height, GL_RGBA8);
5659 color_texture.create(m_texture_width, m_texture_height, GL_RGBA8);
5660 red_texture.create(m_texture_width, m_texture_height, GL_RGBA8);
5661
5662 framebuffer.generate();
5663 framebuffer.bind();
5664 framebuffer.attachTexture(GL_COLOR_ATTACHMENT0, color_texture.m_id, m_texture_width, m_texture_height);
5665
5666 /* Get subroutine indices */
5667 for (GLuint type = 0; type < n_subroutine_types; ++type)
5668 {
5669 m_subroutine_indices[type][0] = program.getSubroutineIndex(subroutine_names[type][0], GL_FRAGMENT_SHADER);
5670 m_subroutine_indices[type][1] = program.getSubroutineIndex(subroutine_names[type][1], GL_FRAGMENT_SHADER);
5671 }
5672
5673 /* Get subroutine uniform locations */
5674 for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
5675 {
5676 m_subroutine_uniform_locations[uniform] =
5677 program.getSubroutineUniformLocation(subroutine_uniform_names[uniform], GL_FRAGMENT_SHADER);
5678 }
5679
5680 /* Get uniform locations */
5681 for (GLuint i = 0; i < n_uniform_names; ++i)
5682 {
5683 m_uniform_locations[i] = program.getUniformLocation(uniform_names[i]);
5684 }
5685
5686 /* Prepare textures */
5687 fillTexture(blue_texture, blue_color);
5688 fillTexture(color_texture, clean_color);
5689 fillTexture(red_texture, red_color);
5690
5691 m_source_textures[0] = blue_texture.m_id;
5692 m_source_textures[1] = red_texture.m_id;
5693
5694 framebuffer.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
5695
5696 /* Test */
5697 bool result = true;
5698 for (GLuint i = 0; i < n_test_cases; ++i)
5699 {
5700 /* Clean output texture */
5701 framebuffer.clear(GL_COLOR_BUFFER_BIT);
5702
5703 /* Execute test */
5704 if (false == testDraw(test_configurations[i].m_routines, test_configurations[i].m_samplers,
5705 test_configurations[i].m_expected_color, color_texture))
5706 {
5707 m_context.getTestContext().getLog()
5708 << tcu::TestLog::Message << "Error. Failure for configuration: " << test_configurations[i].m_description
5709 << tcu::TestLog::EndMessage;
5710
5711 result = false;
5712 }
5713 }
5714
5715 /* Set result */
5716 if (true == result)
5717 {
5718 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5719 }
5720 else
5721 {
5722 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
5723 }
5724
5725 /* Done */
5726 return tcu::TestNode::STOP;
5727 }
5728
5729 /** Fill texture with specified color
5730 *
5731 * @param texture Texture instance
5732 * @param color Color
5733 **/
fillTexture(Utils::texture & texture,const glw::GLubyte color[4]) const5734 void FunctionalTest11::fillTexture(Utils::texture& texture, const glw::GLubyte color[4]) const
5735 {
5736 std::vector<GLubyte> texture_data;
5737
5738 /* Prepare texture data */
5739 texture_data.resize(m_texture_width * m_texture_height * 4);
5740
5741 for (GLuint y = 0; y < m_texture_height; ++y)
5742 {
5743 const GLuint line_offset = y * m_texture_width * 4;
5744
5745 for (GLuint x = 0; x < m_texture_width; ++x)
5746 {
5747 const GLuint point_offset = x * 4 + line_offset;
5748
5749 texture_data[point_offset + 0] = color[0]; /* red */
5750 texture_data[point_offset + 1] = color[1]; /* green */
5751 texture_data[point_offset + 2] = color[2]; /* blue */
5752 texture_data[point_offset + 3] = color[3]; /* alpha */
5753 }
5754 }
5755
5756 texture.update(m_texture_width, m_texture_height, GL_RGBA, GL_UNSIGNED_BYTE, &texture_data[0]);
5757 }
5758
5759 /** Execute draw call and verify results
5760 *
5761 * @param routine_configuration Configurations of routines to be used
5762 * @param sampler_configuration Configuration of textures to be bound to samplers
5763 * @param expected_color Expected color of result image
5764 *
5765 * @return true if result image is filled with expected color, false otherwise
5766 **/
testDraw(const glw::GLuint routine_configuration[5],const glw::GLuint sampler_configuration[2],const glw::GLubyte expected_color[4],Utils::texture & color_texture) const5767 bool FunctionalTest11::testDraw(const glw::GLuint routine_configuration[5], const glw::GLuint sampler_configuration[2],
5768 const glw::GLubyte expected_color[4], Utils::texture& color_texture) const
5769 {
5770 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
5771 static const GLint n_samplers = 2;
5772 static const GLint n_subroutine_uniforms = 5;
5773 GLuint subroutine_indices[5];
5774
5775 /* Set samplers */
5776 for (GLuint i = 0; i < n_samplers; ++i)
5777 {
5778 const GLuint location = m_uniform_locations[i];
5779 const GLuint texture = m_source_textures[sampler_configuration[i]];
5780
5781 gl.activeTexture(GL_TEXTURE0 + i);
5782 GLU_EXPECT_NO_ERROR(gl.getError(), "ActiveTexture");
5783
5784 gl.bindTexture(GL_TEXTURE_2D, texture);
5785 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
5786
5787 gl.uniform1i(location, i);
5788 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
5789 }
5790
5791 gl.activeTexture(GL_TEXTURE0 + 0);
5792
5793 /* Set subroutine uniforms */
5794 for (GLuint i = 0; i < n_subroutine_uniforms; ++i)
5795 {
5796 const GLuint location = m_subroutine_uniform_locations[i];
5797 const GLuint routine = routine_configuration[i];
5798
5799 subroutine_indices[location] = m_subroutine_indices[i][routine];
5800 }
5801
5802 gl.uniformSubroutinesuiv(GL_FRAGMENT_SHADER, 5, subroutine_indices);
5803 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
5804
5805 /* Draw */
5806 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
5807 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
5808
5809 /* Capture result */
5810 std::vector<GLubyte> captured_data;
5811 captured_data.resize(m_texture_width * m_texture_height * 4);
5812
5813 color_texture.get(GL_RGBA, GL_UNSIGNED_BYTE, &captured_data[0]);
5814
5815 /* Verify result */
5816 for (GLuint y = 0; y < m_texture_height; ++y)
5817 {
5818 const GLuint line_offset = y * m_texture_width * 4;
5819
5820 for (GLuint x = 0; x < m_texture_width; ++x)
5821 {
5822 const GLuint point_offset = x * 4 + line_offset;
5823 bool is_as_expected = true;
5824
5825 is_as_expected = is_as_expected && (expected_color[0] == captured_data[point_offset + 0]); /* red */
5826 is_as_expected = is_as_expected && (expected_color[1] == captured_data[point_offset + 1]); /* green */
5827 is_as_expected = is_as_expected && (expected_color[2] == captured_data[point_offset + 2]); /* blue */
5828 is_as_expected = is_as_expected && (expected_color[3] == captured_data[point_offset + 3]); /* alpha */
5829
5830 if (false == is_as_expected)
5831 {
5832 return false;
5833 }
5834 }
5835 }
5836
5837 /* Done */
5838 return true;
5839 }
5840
5841 /* Constatns used by FunctionalTest12 */
5842 const glw::GLuint FunctionalTest12::m_texture_height = 16;
5843 const glw::GLuint FunctionalTest12::m_texture_width = 16;
5844
5845 /** Constructor
5846 *
5847 * @param context CTS context
5848 **/
FunctionalTest12(deqp::Context & context)5849 FunctionalTest12::FunctionalTest12(deqp::Context& context)
5850 : TestCase(context, "ssbo_atomic_image_load_store",
5851 "Verify that SSBO, atomic counters and image load store work as expected")
5852 , m_left_image(0)
5853 , m_right_image(0)
5854 {
5855 }
5856
5857 /** Execute test
5858 *
5859 * @return tcu::TestNode::STOP
5860 **/
iterate()5861 tcu::TestNode::IterateResult FunctionalTest12::iterate()
5862 {
5863 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
5864 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
5865 {
5866 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
5867 }
5868
5869 bool result = true;
5870
5871 /* Test atomic counters */
5872 if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_atomic_counters"))
5873 {
5874 if (false == testAtomic())
5875 {
5876 result = false;
5877 }
5878 }
5879
5880 /* Test shader storage buffer */
5881 if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_storage_buffer_object"))
5882 {
5883 if (false == testSSBO())
5884 {
5885 result = false;
5886 }
5887 }
5888
5889 /* Test image load store */
5890 if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_image_load_store"))
5891 {
5892 if (false == testImage())
5893 {
5894 result = false;
5895 }
5896 }
5897
5898 /* Set result */
5899 if (true == result)
5900 {
5901 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5902 }
5903 else
5904 {
5905 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
5906 }
5907
5908 /* Done */
5909 return tcu::TestNode::STOP;
5910 }
5911
5912 /** Fill texture with specified color
5913 *
5914 * @param texture Texture instance
5915 * @param color Color
5916 **/
fillTexture(Utils::texture & texture,const glw::GLuint color[4]) const5917 void FunctionalTest12::fillTexture(Utils::texture& texture, const glw::GLuint color[4]) const
5918 {
5919 std::vector<GLuint> texture_data;
5920
5921 /* Prepare texture data */
5922 texture_data.resize(m_texture_width * m_texture_height * 4);
5923
5924 for (GLuint y = 0; y < m_texture_height; ++y)
5925 {
5926 const GLuint line_offset = y * m_texture_width * 4;
5927
5928 for (GLuint x = 0; x < m_texture_width; ++x)
5929 {
5930 const GLuint point_offset = x * 4 + line_offset;
5931
5932 texture_data[point_offset + 0] = color[0]; /* red */
5933 texture_data[point_offset + 1] = color[1]; /* green */
5934 texture_data[point_offset + 2] = color[2]; /* blue */
5935 texture_data[point_offset + 3] = color[3]; /* alpha */
5936 }
5937 }
5938
5939 texture.update(m_texture_width, m_texture_height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &texture_data[0]);
5940 }
5941
5942 /** Test atomic counters
5943 *
5944 * @return true if test pass, false otherwise
5945 **/
testAtomic()5946 bool FunctionalTest12::testAtomic()
5947 {
5948 static const GLchar* fragment_shader_code = "#version 410 core\n"
5949 "#extension GL_ARB_shader_atomic_counters : require\n"
5950 "#extension GL_ARB_shader_subroutine : require\n"
5951 "\n"
5952 "precision highp float;\n"
5953 "\n"
5954 "layout(location = 0) out uint out_color;\n"
5955 "\n"
5956 "layout(binding = 0, offset = 8) uniform atomic_uint one;\n"
5957 "layout(binding = 0, offset = 4) uniform atomic_uint two;\n"
5958 "layout(binding = 0, offset = 0) uniform atomic_uint three;\n"
5959 "\n"
5960 "subroutine void atomic_routine(void)\n;"
5961 "\n"
5962 "subroutine(atomic_routine) void increment_two(void)\n"
5963 "{\n"
5964 " out_color = atomicCounterIncrement(two);\n"
5965 "}\n"
5966 "\n"
5967 "subroutine(atomic_routine) void decrement_three(void)\n"
5968 "{\n"
5969 " out_color = atomicCounterDecrement(three);\n"
5970 "}\n"
5971 "\n"
5972 "subroutine(atomic_routine) void read_one(void)\n"
5973 "{\n"
5974 " out_color = atomicCounter(one);\n"
5975 "}\n"
5976 "\n"
5977 "subroutine uniform atomic_routine routine;\n"
5978 "\n"
5979 "void main()\n"
5980 "{\n"
5981 " routine();\n"
5982 "}\n"
5983 "\n";
5984
5985 static const GLchar* geometry_shader_code = "#version 400 core\n"
5986 "#extension GL_ARB_shader_subroutine : require\n"
5987 "\n"
5988 "precision highp float;\n"
5989 "\n"
5990 "layout(points) in;\n"
5991 "layout(triangle_strip, max_vertices = 4) out;\n"
5992 "\n"
5993 "void main()\n"
5994 "{\n"
5995 " gl_Position = vec4(-1, -1, 0, 1);\n"
5996 " EmitVertex();\n"
5997 " \n"
5998 " gl_Position = vec4(-1, 1, 0, 1);\n"
5999 " EmitVertex();\n"
6000 " \n"
6001 " gl_Position = vec4( 1, -1, 0, 1);\n"
6002 " EmitVertex();\n"
6003 " \n"
6004 " gl_Position = vec4( 1, 1, 0, 1);\n"
6005 " EmitVertex();\n"
6006 " \n"
6007 " EndPrimitive();\n"
6008 "}\n"
6009 "\n";
6010
6011 static const GLchar* vertex_shader_code = "#version 400 core\n"
6012 "#extension GL_ARB_shader_subroutine : require\n"
6013 "\n"
6014 "precision highp float;\n"
6015 "\n"
6016 "void main()\n"
6017 "{\n"
6018 "}\n"
6019 "\n";
6020
6021 static const GLchar* subroutine_names[] = { "increment_two", "decrement_three", "read_one" };
6022
6023 /* Test data */
6024 static const glw::GLuint atomic_buffer_data[] = { m_texture_width * m_texture_height,
6025 m_texture_width * m_texture_height,
6026 m_texture_width * m_texture_height };
6027
6028 static const glw::GLuint expected_incremented_two[] = { atomic_buffer_data[0], 2 * atomic_buffer_data[1],
6029 atomic_buffer_data[2] };
6030
6031 static const glw::GLuint expected_decremented_three[] = { 0, expected_incremented_two[1],
6032 expected_incremented_two[2] };
6033
6034 static const glw::GLuint expected_read_one[] = { expected_decremented_three[0], expected_decremented_three[1],
6035 expected_decremented_three[2] };
6036
6037 /* GL objects */
6038 Utils::buffer atomic_buffer(m_context);
6039 Utils::texture color_texture(m_context);
6040 Utils::framebuffer framebuffer(m_context);
6041 Utils::program program(m_context);
6042 Utils::vertexArray vao(m_context);
6043
6044 /* Init GL objects */
6045 program.build(0 /* cs */, fragment_shader_code /* fs */, geometry_shader_code /* gs */, 0 /* tcs */, 0 /* test */,
6046 vertex_shader_code, 0 /* varying_names */, 0 /* n_varyings */);
6047
6048 program.use();
6049
6050 vao.generate();
6051 vao.bind();
6052
6053 color_texture.create(m_texture_width, m_texture_height, GL_R32UI);
6054
6055 atomic_buffer.generate();
6056 atomic_buffer.update(GL_ATOMIC_COUNTER_BUFFER, sizeof(atomic_buffer_data), (GLvoid*)atomic_buffer_data,
6057 GL_STATIC_DRAW);
6058 atomic_buffer.bindRange(GL_ATOMIC_COUNTER_BUFFER, 0 /* index */, 0 /* offset */, sizeof(atomic_buffer_data));
6059
6060 framebuffer.generate();
6061 framebuffer.bind();
6062 framebuffer.attachTexture(GL_COLOR_ATTACHMENT0, color_texture.m_id, m_texture_width, m_texture_height);
6063 framebuffer.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
6064 framebuffer.clear(GL_COLOR_BUFFER_BIT);
6065
6066 /* Subroutine indices */
6067 GLuint increment_two = program.getSubroutineIndex(subroutine_names[0], GL_FRAGMENT_SHADER);
6068 GLuint decrement_three = program.getSubroutineIndex(subroutine_names[1], GL_FRAGMENT_SHADER);
6069 GLuint read_one = program.getSubroutineIndex(subroutine_names[2], GL_FRAGMENT_SHADER);
6070
6071 /* Test */
6072 bool result = true;
6073
6074 if (false == testAtomicDraw(increment_two, expected_incremented_two))
6075 {
6076 result = false;
6077 }
6078
6079 if (false == testAtomicDraw(decrement_three, expected_decremented_three))
6080 {
6081 result = false;
6082 }
6083
6084 if (false == testAtomicDraw(read_one, expected_read_one))
6085 {
6086 result = false;
6087 }
6088
6089 /* Done */
6090 return result;
6091 }
6092
6093 /** Execture draw call and verify results
6094 *
6095 * @param subroutine_index Index of subroutine that shall be used during draw call
6096 * @param expected_results Expected results
6097 *
6098 * @return true if results are as expected, false otherwise
6099 **/
testAtomicDraw(GLuint subroutine_index,const GLuint expected_results[3]) const6100 bool FunctionalTest12::testAtomicDraw(GLuint subroutine_index, const GLuint expected_results[3]) const
6101 {
6102 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
6103
6104 /* Set subroutine uniforms */
6105 gl.uniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &subroutine_index);
6106 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
6107
6108 /* Draw */
6109 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
6110 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
6111
6112 /* Capture results */
6113 GLuint* atomic_results = (GLuint*)gl.mapBuffer(GL_ATOMIC_COUNTER_BUFFER, GL_READ_ONLY);
6114 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
6115
6116 /* Verify */
6117 bool result = (0 == memcmp(expected_results, atomic_results, 3 * sizeof(GLuint)));
6118
6119 if (false == result)
6120 {
6121 m_context.getTestContext().getLog()
6122 << tcu::TestLog::Message << "Error. Invalid result. "
6123 << "Result: [ " << atomic_results[0] << ", " << atomic_results[1] << ", " << atomic_results[2] << " ] "
6124 << "Expected: [ " << expected_results[0] << ", " << expected_results[1] << ", " << expected_results[2]
6125 << " ]" << tcu::TestLog::EndMessage;
6126 }
6127
6128 /* Unmap buffer */
6129 gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
6130 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
6131
6132 /* Done */
6133 return result;
6134 }
6135
6136 /** Test image load store
6137 *
6138 * @return true if test pass, false otherwise
6139 **/
testImage()6140 bool FunctionalTest12::testImage()
6141 {
6142 static const GLchar* fragment_shader_code =
6143 "#version 400 core\n"
6144 "#extension GL_ARB_shader_image_load_store : require\n"
6145 "#extension GL_ARB_shader_subroutine : require\n"
6146 "\n"
6147 "precision highp float;\n"
6148 "\n"
6149 "layout(location = 0) out uvec4 out_color;\n"
6150 "\n"
6151 "layout(rgba32ui) uniform uimage2D left_image;\n"
6152 "layout(rgba32ui) uniform uimage2D right_image;\n"
6153 "\n"
6154 "subroutine void image_routine(void);\n"
6155 "\n"
6156 "subroutine(image_routine) void left_to_right(void)\n"
6157 "{\n"
6158 " out_color = imageLoad (left_image, ivec2(gl_FragCoord.xy));\n"
6159 " imageStore(right_image, ivec2(gl_FragCoord.xy), out_color);\n"
6160 "}\n"
6161 "\n"
6162 "subroutine(image_routine) void right_to_left(void)\n"
6163 "{\n"
6164 " out_color = imageLoad (right_image, ivec2(gl_FragCoord.xy));\n"
6165 " imageStore(left_image, ivec2(gl_FragCoord.xy), out_color);\n"
6166 "}\n"
6167 "\n"
6168 "subroutine uniform image_routine routine;\n"
6169 "\n"
6170 "void main()\n"
6171 "{\n"
6172 " routine();\n"
6173 "}\n"
6174 "\n";
6175
6176 static const GLchar* geometry_shader_code = "#version 400 core\n"
6177 "#extension GL_ARB_shader_subroutine : require\n"
6178 "\n"
6179 "precision highp float;\n"
6180 "\n"
6181 "layout(points) in;\n"
6182 "layout(triangle_strip, max_vertices = 4) out;\n"
6183 "\n"
6184 "void main()\n"
6185 "{\n"
6186 " gl_Position = vec4(-1, -1, 0, 1);\n"
6187 " EmitVertex();\n"
6188 " \n"
6189 " gl_Position = vec4(-1, 1, 0, 1);\n"
6190 " EmitVertex();\n"
6191 " \n"
6192 " gl_Position = vec4( 1, -1, 0, 1);\n"
6193 " EmitVertex();\n"
6194 " \n"
6195 " gl_Position = vec4( 1, 1, 0, 1);\n"
6196 " EmitVertex();\n"
6197 " \n"
6198 " EndPrimitive();\n"
6199 "}\n"
6200 "\n";
6201
6202 static const GLchar* vertex_shader_code = "#version 400 core\n"
6203 "#extension GL_ARB_shader_subroutine : require\n"
6204 "\n"
6205 "precision highp float;\n"
6206 "\n"
6207 "void main()\n"
6208 "{\n"
6209 "}\n"
6210 "\n";
6211
6212 static const GLchar* subroutine_names[] = { "left_to_right", "right_to_left" };
6213
6214 static const GLchar* uniform_names[] = { "left_image", "right_image" };
6215
6216 /* Test data */
6217 static const GLuint blue_color[4] = { 0, 0, 255, 255 };
6218 static const GLuint clean_color[4] = { 16, 32, 64, 128 };
6219 static const GLuint red_color[4] = { 255, 0, 0, 255 };
6220
6221 /* GL objects */
6222 Utils::texture blue_texture(m_context);
6223 Utils::texture destination_texture(m_context);
6224 Utils::texture color_texture(m_context);
6225 Utils::framebuffer framebuffer(m_context);
6226 Utils::program program(m_context);
6227 Utils::texture red_texture(m_context);
6228 Utils::vertexArray vao(m_context);
6229
6230 /* Init GL objects */
6231 program.build(0 /* cs */, fragment_shader_code /* fs */, geometry_shader_code /* gs */, 0 /* tcs */, 0 /* test */,
6232 vertex_shader_code, 0 /* varying_names */, 0 /* n_varyings */);
6233
6234 program.use();
6235
6236 vao.generate();
6237 vao.bind();
6238
6239 blue_texture.create(m_texture_width, m_texture_height, GL_RGBA32UI);
6240 destination_texture.create(m_texture_width, m_texture_height, GL_RGBA32UI);
6241 color_texture.create(m_texture_width, m_texture_height, GL_RGBA32UI);
6242 red_texture.create(m_texture_width, m_texture_height, GL_RGBA32UI);
6243
6244 fillTexture(blue_texture, blue_color);
6245 fillTexture(destination_texture, clean_color);
6246 fillTexture(red_texture, red_color);
6247
6248 framebuffer.generate();
6249 framebuffer.bind();
6250 framebuffer.attachTexture(GL_COLOR_ATTACHMENT0, color_texture.m_id, m_texture_width, m_texture_height);
6251 framebuffer.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
6252 framebuffer.clear(GL_COLOR_BUFFER_BIT);
6253
6254 /* Subroutine indices */
6255 GLuint left_to_right = program.getSubroutineIndex(subroutine_names[0], GL_FRAGMENT_SHADER);
6256 GLuint right_to_left = program.getSubroutineIndex(subroutine_names[1], GL_FRAGMENT_SHADER);
6257
6258 /* Uniform locations */
6259 m_left_image = program.getUniformLocation(uniform_names[0]);
6260 m_right_image = program.getUniformLocation(uniform_names[1]);
6261
6262 /* Test */
6263 bool result = true;
6264
6265 if (false == testImageDraw(left_to_right, blue_texture, destination_texture, blue_color, blue_color))
6266 {
6267 result = false;
6268 }
6269
6270 if (false == testImageDraw(left_to_right, red_texture, destination_texture, red_color, red_color))
6271 {
6272 result = false;
6273 }
6274
6275 if (false == testImageDraw(right_to_left, destination_texture, blue_texture, blue_color, blue_color))
6276 {
6277 result = false;
6278 }
6279
6280 if (false == testImageDraw(right_to_left, destination_texture, red_texture, red_color, red_color))
6281 {
6282 result = false;
6283 }
6284
6285 if (false == testImageDraw(left_to_right, blue_texture, red_texture, blue_color, blue_color))
6286 {
6287 result = false;
6288 }
6289
6290 /* Done */
6291 return result;
6292 }
6293
6294 /** Execute draw call and verifies results
6295 *
6296 * @param subroutine_index Index of subroutine that shall be used during draw call
6297 * @param left "Left" texture
6298 * @param right "Right" texture
6299 * @param expected_left_color Expected color of "left" texture
6300 * @param expected_right_color Expected color of "right" texture
6301 *
6302 * @return true if verification result is positive, false otherwise
6303 **/
testImageDraw(GLuint subroutine_index,Utils::texture & left,Utils::texture & right,const GLuint expected_left_color[4],const GLuint expected_right_color[4]) const6304 bool FunctionalTest12::testImageDraw(GLuint subroutine_index, Utils::texture& left, Utils::texture& right,
6305 const GLuint expected_left_color[4], const GLuint expected_right_color[4]) const
6306 {
6307 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
6308
6309 /* Set subroutine uniforms */
6310 gl.uniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &subroutine_index);
6311 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
6312
6313 /* Set up image units */
6314 gl.uniform1i(m_left_image, 0);
6315 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
6316
6317 gl.uniform1i(m_right_image, 1);
6318 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
6319
6320 gl.bindImageTexture(0, left.m_id, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32UI);
6321 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
6322
6323 gl.bindImageTexture(1, right.m_id, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32UI);
6324 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
6325
6326 /* Draw */
6327 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
6328 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
6329
6330 /* Verify results */
6331 bool result = true;
6332
6333 if (false == verifyTexture(left, expected_left_color))
6334 {
6335 m_context.getTestContext().getLog() << tcu::TestLog::Message
6336 << "Error. Invalid result. Left texture is filled with wrong color."
6337 << tcu::TestLog::EndMessage;
6338 result = false;
6339 }
6340
6341 if (false == verifyTexture(right, expected_right_color))
6342 {
6343 m_context.getTestContext().getLog() << tcu::TestLog::Message
6344 << "Error. Invalid result. Right texture is filled with wrong color."
6345 << tcu::TestLog::EndMessage;
6346 result = false;
6347 }
6348
6349 /* Done */
6350 return result;
6351 }
6352
6353 /** Test shader storage buffer
6354 *
6355 * @return true if test pass, false otherwise
6356 **/
testSSBO()6357 bool FunctionalTest12::testSSBO()
6358 {
6359 static const GLchar* fragment_shader_code = "#version 400 core\n"
6360 "#extension GL_ARB_shader_storage_buffer_object : require\n"
6361 "#extension GL_ARB_shader_subroutine : require\n"
6362 "\n"
6363 "precision highp float;\n"
6364 "\n"
6365 "layout(location = 0) out uvec4 out_color;\n"
6366 "\n"
6367 "layout(std140, binding = 0) buffer Buffer\n"
6368 "{\n"
6369 " uvec4 entry;\n"
6370 "};\n"
6371 "\n"
6372 "subroutine void ssbo_routine(void)\n;"
6373 "\n"
6374 "subroutine(ssbo_routine) void increment(void)\n"
6375 "{\n"
6376 " out_color.x = atomicAdd(entry.x, 1);\n"
6377 " out_color.y = atomicAdd(entry.y, 1);\n"
6378 " out_color.z = atomicAdd(entry.z, 1);\n"
6379 " out_color.w = atomicAdd(entry.w, 1);\n"
6380 "}\n"
6381 "\n"
6382 "subroutine(ssbo_routine) void decrement(void)\n"
6383 "{\n"
6384 " out_color.x = atomicAdd(entry.x, -1);\n"
6385 " out_color.y = atomicAdd(entry.y, -1);\n"
6386 " out_color.z = atomicAdd(entry.z, -1);\n"
6387 " out_color.w = atomicAdd(entry.w, -1);\n"
6388 "}\n"
6389 "\n"
6390 "subroutine uniform ssbo_routine routine;\n"
6391 "\n"
6392 "void main()\n"
6393 "{\n"
6394 " routine();\n"
6395 "}\n"
6396 "\n";
6397
6398 static const GLchar* geometry_shader_code = "#version 400 core\n"
6399 "#extension GL_ARB_shader_subroutine : require\n"
6400 "\n"
6401 "precision highp float;\n"
6402 "\n"
6403 "layout(points) in;\n"
6404 "layout(triangle_strip, max_vertices = 4) out;\n"
6405 "\n"
6406 "void main()\n"
6407 "{\n"
6408 " gl_Position = vec4(-1, -1, 0, 1);\n"
6409 " EmitVertex();\n"
6410 " \n"
6411 " gl_Position = vec4(-1, 1, 0, 1);\n"
6412 " EmitVertex();\n"
6413 " \n"
6414 " gl_Position = vec4( 1, -1, 0, 1);\n"
6415 " EmitVertex();\n"
6416 " \n"
6417 " gl_Position = vec4( 1, 1, 0, 1);\n"
6418 " EmitVertex();\n"
6419 " \n"
6420 " EndPrimitive();\n"
6421 "}\n"
6422 "\n";
6423
6424 static const GLchar* vertex_shader_code = "#version 400 core\n"
6425 "#extension GL_ARB_shader_subroutine : require\n"
6426 "\n"
6427 "precision highp float;\n"
6428 "\n"
6429 "void main()\n"
6430 "{\n"
6431 "}\n"
6432 "\n";
6433
6434 static const GLchar* subroutine_names[] = { "increment", "decrement" };
6435
6436 /* Test data */
6437 static const glw::GLuint buffer_data[] = { m_texture_width * m_texture_height + 1,
6438 m_texture_width * m_texture_height + 2,
6439 m_texture_width * m_texture_height + 3,
6440 m_texture_width * m_texture_height + 4 };
6441
6442 static const glw::GLuint expected_incremented[] = { m_texture_width * m_texture_height + buffer_data[0],
6443 m_texture_width * m_texture_height + buffer_data[1],
6444 m_texture_width * m_texture_height + buffer_data[2],
6445 m_texture_width * m_texture_height + buffer_data[3] };
6446
6447 static const glw::GLuint expected_decremented[] = { buffer_data[0], buffer_data[1], buffer_data[2],
6448 buffer_data[3] };
6449
6450 /* GL objects */
6451 Utils::buffer buffer(m_context);
6452 Utils::texture color_texture(m_context);
6453 Utils::framebuffer framebuffer(m_context);
6454 Utils::program program(m_context);
6455 Utils::vertexArray vao(m_context);
6456
6457 /* Init GL objects */
6458 program.build(0 /* cs */, fragment_shader_code /* fs */, geometry_shader_code /* gs */, 0 /* tcs */, 0 /* test */,
6459 vertex_shader_code, 0 /* varying_names */, 0 /* n_varyings */);
6460
6461 program.use();
6462
6463 vao.generate();
6464 vao.bind();
6465
6466 color_texture.create(m_texture_width, m_texture_height, GL_RGBA32UI);
6467
6468 buffer.generate();
6469 buffer.update(GL_SHADER_STORAGE_BUFFER, sizeof(buffer_data), (GLvoid*)buffer_data, GL_STATIC_DRAW);
6470 buffer.bindRange(GL_SHADER_STORAGE_BUFFER, 0 /* index */, 0 /* offset */, sizeof(buffer_data));
6471
6472 framebuffer.generate();
6473 framebuffer.bind();
6474 framebuffer.attachTexture(GL_COLOR_ATTACHMENT0, color_texture.m_id, m_texture_width, m_texture_height);
6475 framebuffer.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
6476 framebuffer.clear(GL_COLOR_BUFFER_BIT);
6477
6478 /* Subroutine indices */
6479 GLuint increment = program.getSubroutineIndex(subroutine_names[0], GL_FRAGMENT_SHADER);
6480 GLuint decrement = program.getSubroutineIndex(subroutine_names[1], GL_FRAGMENT_SHADER);
6481
6482 /* Test */
6483 bool result = true;
6484
6485 if (false == testSSBODraw(increment, expected_incremented))
6486 {
6487 result = false;
6488 }
6489
6490 if (false == testSSBODraw(decrement, expected_decremented))
6491 {
6492 result = false;
6493 }
6494
6495 /* Done */
6496 return result;
6497 }
6498
6499 /** Execute draw call and verify results
6500 *
6501 * @param subroutine_index Index of subroutine that shall be used by draw call
6502 * @param expected_results Expected results
6503 *
6504 *
6505 **/
testSSBODraw(GLuint subroutine_index,const GLuint expected_results[4]) const6506 bool FunctionalTest12::testSSBODraw(GLuint subroutine_index, const GLuint expected_results[4]) const
6507 {
6508 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
6509
6510 /* Set subroutine uniforms */
6511 gl.uniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &subroutine_index);
6512 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
6513
6514 /* Draw */
6515 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
6516 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
6517
6518 /* Capture results */
6519 GLuint* ssbo_results = (GLuint*)gl.mapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
6520 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
6521
6522 /* Verify */
6523 bool result = (0 == memcmp(expected_results, ssbo_results, 4 * sizeof(GLuint)));
6524
6525 if (false == result)
6526 {
6527 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error. Invalid result. "
6528 << "Result: [ " << ssbo_results[0] << ", " << ssbo_results[1] << ", "
6529 << ssbo_results[2] << ", " << ssbo_results[3] << " ] "
6530 << "Expected: [ " << expected_results[0] << ", " << expected_results[1]
6531 << ", " << expected_results[2] << ", " << expected_results[3] << " ]"
6532 << tcu::TestLog::EndMessage;
6533 }
6534
6535 /* Unmap buffer */
6536 gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
6537 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
6538
6539 /* Done */
6540 return result;
6541 }
6542
6543 /** Check if texture is filled with expected color
6544 *
6545 * @param texture Texture instance
6546 * @param expected_color Expected color
6547 *
6548 * @return true if texture is filled with specified color, false otherwise
6549 **/
verifyTexture(Utils::texture & texture,const GLuint expected_color[4]) const6550 bool FunctionalTest12::verifyTexture(Utils::texture& texture, const GLuint expected_color[4]) const
6551 {
6552 std::vector<GLuint> results;
6553 results.resize(m_texture_width * m_texture_height * 4);
6554
6555 texture.get(GL_RGBA_INTEGER, GL_UNSIGNED_INT, &results[0]);
6556
6557 for (GLuint y = 0; y < m_texture_height; ++y)
6558 {
6559 const GLuint line_offset = y * m_texture_width * 4;
6560
6561 for (GLuint x = 0; x < m_texture_width; ++x)
6562 {
6563 const GLuint point_offset = line_offset + x * 4;
6564 bool result = true;
6565
6566 result = result && (results[point_offset + 0] == expected_color[0]);
6567 result = result && (results[point_offset + 1] == expected_color[1]);
6568 result = result && (results[point_offset + 2] == expected_color[2]);
6569 result = result && (results[point_offset + 3] == expected_color[3]);
6570
6571 if (false == result)
6572 {
6573 return false;
6574 }
6575 }
6576 }
6577
6578 return true;
6579 }
6580
6581 /** Constructor.
6582 *
6583 * @param context Rendering context.
6584 *
6585 **/
FunctionalTest13(deqp::Context & context)6586 FunctionalTest13::FunctionalTest13(deqp::Context& context)
6587 : TestCase(context, "subroutines_with_separate_shader_objects",
6588 "Verifies that subroutines work correctly when used in separate "
6589 "shader objects")
6590 , m_fbo_id(0)
6591 , m_pipeline_id(0)
6592 , m_read_buffer(DE_NULL)
6593 , m_to_height(4)
6594 , m_to_id(0)
6595 , m_to_width(4)
6596 , m_vao_id(0)
6597 , m_has_test_passed(true)
6598 {
6599 memset(m_fs_po_ids, 0, sizeof(m_fs_po_ids));
6600 memset(m_gs_po_ids, 0, sizeof(m_gs_po_ids));
6601 memset(m_tc_po_ids, 0, sizeof(m_tc_po_ids));
6602 memset(m_te_po_ids, 0, sizeof(m_te_po_ids));
6603 memset(m_vs_po_ids, 0, sizeof(m_vs_po_ids));
6604 }
6605
6606 /** Deinitializes all GL objects that may have been created during test
6607 * execution, as well as releases all process-side buffers that may have
6608 * been allocated during the process.
6609 * The function also restores default GL state configuration.
6610 **/
deinit()6611 void FunctionalTest13::deinit()
6612 {
6613 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
6614
6615 if (m_fbo_id != 0)
6616 {
6617 gl.deleteFramebuffers(1, &m_fbo_id);
6618
6619 m_fbo_id = 0;
6620 }
6621
6622 if (m_pipeline_id != 0)
6623 {
6624 gl.deleteProgramPipelines(1, &m_pipeline_id);
6625
6626 m_pipeline_id = 0;
6627 }
6628
6629 if (m_read_buffer != DE_NULL)
6630 {
6631 delete[] m_read_buffer;
6632
6633 m_read_buffer = DE_NULL;
6634 }
6635
6636 for (unsigned int n_id = 0; n_id < 2 /* po id variants */; ++n_id)
6637 {
6638 if (m_fs_po_ids[n_id] != 0)
6639 {
6640 gl.deleteProgram(m_fs_po_ids[n_id]);
6641
6642 m_fs_po_ids[n_id] = 0;
6643 }
6644
6645 if (m_gs_po_ids[n_id] != 0)
6646 {
6647 gl.deleteProgram(m_gs_po_ids[n_id]);
6648
6649 m_gs_po_ids[n_id] = 0;
6650 }
6651
6652 if (m_tc_po_ids[n_id] != 0)
6653 {
6654 gl.deleteProgram(m_tc_po_ids[n_id]);
6655
6656 m_tc_po_ids[n_id] = 0;
6657 }
6658
6659 if (m_te_po_ids[n_id] != 0)
6660 {
6661 gl.deleteProgram(m_te_po_ids[n_id]);
6662
6663 m_te_po_ids[n_id] = 0;
6664 }
6665
6666 if (m_vs_po_ids[n_id] != 0)
6667 {
6668 gl.deleteProgram(m_vs_po_ids[n_id]);
6669
6670 m_vs_po_ids[n_id] = 0;
6671 }
6672 } /* for (both shader program object variants) */
6673
6674 if (m_to_id != 0)
6675 {
6676 gl.deleteTextures(1, &m_to_id);
6677
6678 m_to_id = 0;
6679 }
6680
6681 if (m_vao_id != 0)
6682 {
6683 gl.deleteVertexArrays(1, &m_vao_id);
6684
6685 m_vao_id = 0;
6686 }
6687
6688 /* Restore default GL_PATCH_VERTICES setting value */
6689 gl.patchParameteri(GL_PATCH_VERTICES, 3);
6690
6691 /* Restore default GL_PACK_ALIGNMENT setting value */
6692 gl.pixelStorei(GL_PACK_ALIGNMENT, 4);
6693 }
6694
6695 /** Retrieves body of a fragment shader that should be used for the test.
6696 * The subroutine implementations are slightly changed, depending on the
6697 * index of the shader, as specified by the caller.
6698 *
6699 * @param n_id Index of the shader.
6700 *
6701 * @return Requested string.
6702 **/
getFragmentShaderBody(unsigned int n_id)6703 std::string FunctionalTest13::getFragmentShaderBody(unsigned int n_id)
6704 {
6705 std::stringstream result_sstream;
6706
6707 /* Pre-amble */
6708 result_sstream << "#version 400\n"
6709 "\n"
6710 "#extension GL_ARB_shader_subroutine : require\n"
6711 "\n"
6712 /* Sub-routine */
6713 "subroutine void SubroutineFSType(inout vec4 result);\n"
6714 "\n"
6715 "subroutine(SubroutineFSType) void SubroutineFS1(inout vec4 result)\n"
6716 "{\n"
6717 " result += vec4("
6718 << float(n_id + 1) / 10.0f << ", " << float(n_id + 2) / 10.0f << ", " << float(n_id + 3) / 10.0f
6719 << ", " << float(n_id + 4) / 10.0f
6720 << ");\n"
6721 "}\n"
6722 "subroutine(SubroutineFSType) void SubroutineFS2(inout vec4 result)\n"
6723 "{\n"
6724 " result += vec4("
6725 << float(n_id + 1) / 20.0f << ", " << float(n_id + 2) / 20.0f << ", " << float(n_id + 3) / 20.0f
6726 << ", " << float(n_id + 4) / 20.0f << ");\n"
6727 "}\n"
6728 "\n"
6729 "subroutine uniform SubroutineFSType function;\n"
6730 "\n"
6731 /* Input block */
6732 "in GS_DATA\n"
6733 "{\n"
6734 " vec4 data;\n"
6735 "} in_gs;\n"
6736 "\n"
6737 "out vec4 result;\n"
6738 /* main() declaration */
6739 "void main()\n"
6740 "{\n"
6741 " vec4 data = in_gs.data;\n"
6742 " function(data);\n"
6743 "\n"
6744 " result = data;\n"
6745 "}\n";
6746
6747 return result_sstream.str();
6748 }
6749
6750 /** Retrieves body of a geometry shader that should be used for the test.
6751 * The subroutine implementations are slightly changed, depending on the
6752 * index of the shader, as specified by the caller.
6753 *
6754 * @param n_id Index of the shader.
6755 *
6756 * @return Requested string.
6757 **/
getGeometryShaderBody(unsigned int n_id)6758 std::string FunctionalTest13::getGeometryShaderBody(unsigned int n_id)
6759 {
6760 std::stringstream result_sstream;
6761
6762 /* Pre-amble */
6763 result_sstream << "#version 400\n"
6764 "\n"
6765 "#extension GL_ARB_shader_subroutine : require\n"
6766 "\n"
6767 "layout(points) in;\n"
6768 "layout(triangle_strip, max_vertices = 4) out;\n"
6769 /* Sub-routine */
6770 "subroutine void SubroutineGSType(inout vec4 result);\n"
6771 "\n"
6772 "subroutine(SubroutineGSType) void SubroutineGS1(inout vec4 result)\n"
6773 "{\n"
6774 " result += vec4(0, 0, 0, "
6775 << float(n_id + 1) * 0.425f << ");\n"
6776 "}\n"
6777 "subroutine(SubroutineGSType) void SubroutineGS2(inout vec4 result)\n"
6778 "{\n"
6779 " result += vec4(0, 0, 0, "
6780 << float(n_id + 1) * 0.0425f << ");\n"
6781 "}\n"
6782 "\n"
6783 "subroutine uniform SubroutineGSType function;\n"
6784 "\n"
6785 /* Input block */
6786 "in TE_DATA\n"
6787 "{\n"
6788 " vec4 data;\n"
6789 "} in_te[];\n"
6790 "\n"
6791 /* Output block */
6792 "out GS_DATA\n"
6793 "{\n"
6794 " vec4 data;\n"
6795 "} out_gs;\n"
6796 "\n"
6797 "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n"
6798 "out gl_PerVertex { vec4 gl_Position; };\n"
6799 /* main() declaration */
6800 "void main()\n"
6801 "{\n"
6802 " vec4 data = in_te[0].data;\n"
6803 "\n"
6804 " function(data);\n"
6805 "\n"
6806 " gl_Position = vec4(1, -1, 0, 1);\n"
6807 " out_gs.data = data;\n"
6808 " EmitVertex();\n"
6809 "\n"
6810 " gl_Position = vec4(-1, -1, 0, 1);\n"
6811 " out_gs.data = data;\n"
6812 " EmitVertex();\n"
6813 "\n"
6814 " gl_Position = vec4(1, 1, 0, 1);\n"
6815 " out_gs.data = data;\n"
6816 " EmitVertex();\n"
6817 "\n"
6818 " gl_Position = vec4(-1, 1, 0, 1);\n"
6819 " out_gs.data = data;\n"
6820 " EmitVertex();\n"
6821 " EndPrimitive();\n"
6822 "}\n";
6823
6824 return result_sstream.str();
6825 }
6826
6827 /** Retrieves body of a tessellation control shader that should be used for the test.
6828 * The subroutine implementations are slightly changed, depending on the
6829 * index of the shader, as specified by the caller.
6830 *
6831 * @param n_id Index of the shader.
6832 *
6833 * @return Requested string.
6834 **/
getTessellationControlShaderBody(unsigned int n_id)6835 std::string FunctionalTest13::getTessellationControlShaderBody(unsigned int n_id)
6836 {
6837 std::stringstream result_sstream;
6838
6839 /* Pre-amble */
6840 result_sstream << "#version 400\n"
6841 "\n"
6842 "#extension GL_ARB_shader_subroutine : require\n"
6843 "\n"
6844 "layout(vertices = 4) out;\n"
6845 /* Sub-routine */
6846 "subroutine void SubroutineTCType(inout vec4 result);\n"
6847 "\n"
6848 "subroutine(SubroutineTCType) void SubroutineTC1(inout vec4 result)\n"
6849 "{\n"
6850 " result += vec4(0, "
6851 << float(n_id + 1) * 0.25f << ", 0, 0);\n"
6852 "}\n"
6853 "subroutine(SubroutineTCType) void SubroutineTC2(inout vec4 result)\n"
6854 "{\n"
6855 " result += vec4(0, "
6856 << float(n_id + 1) * 0.025f
6857 << ", 0, 0);\n"
6858 "}\n"
6859 "\n"
6860 "subroutine uniform SubroutineTCType function;\n"
6861 "\n"
6862 /* Input block */
6863 "in VS_DATA\n"
6864 "{\n"
6865 " vec4 data;\n"
6866 "} in_vs[];\n"
6867 "\n"
6868 /* Output block */
6869 "out TC_DATA\n"
6870 "{\n"
6871 " vec4 data;\n"
6872 "} out_tc[];\n"
6873 "\n"
6874 "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n"
6875 "out gl_PerVertex { vec4 gl_Position; } gl_out[];\n"
6876 /* main() declaration */
6877 "void main()\n"
6878 "{\n"
6879 " gl_TessLevelOuter[0] = 1.0;\n"
6880 " gl_TessLevelOuter[1] = 1.0;\n"
6881 " gl_TessLevelOuter[2] = 1.0;\n"
6882 " gl_TessLevelOuter[3] = 1.0;\n"
6883 " gl_TessLevelInner[0] = 1.0;\n"
6884 " gl_TessLevelInner[1] = 1.0;\n"
6885 " gl_out[gl_InvocationID].gl_Position = gl_in[0].gl_Position;\n"
6886 " out_tc[gl_InvocationID].data = in_vs[0].data;\n"
6887 "\n"
6888 " function(out_tc[gl_InvocationID].data);\n"
6889 "}\n";
6890
6891 return result_sstream.str();
6892 }
6893
6894 /** Retrieves body of a tessellation evaluation shader that should be used for the test.
6895 * The subroutine implementations are slightly changed, depending on the
6896 * index of the shader, as specified by the caller.
6897 *
6898 * @param n_id Index of the shader.
6899 *
6900 * @return Requested string.
6901 **/
getTessellationEvaluationShaderBody(unsigned int n_id)6902 std::string FunctionalTest13::getTessellationEvaluationShaderBody(unsigned int n_id)
6903 {
6904 std::stringstream result_sstream;
6905
6906 /* Pre-amble */
6907 result_sstream << "#version 400\n"
6908 "\n"
6909 "#extension GL_ARB_shader_subroutine : require\n"
6910 "\n"
6911 "layout(quads, point_mode) in;\n"
6912 /* Sub-routine */
6913 "subroutine void SubroutineTEType(inout vec4 result);\n"
6914 "\n"
6915 "subroutine(SubroutineTEType) void SubroutineTE1(inout vec4 result)\n"
6916 "{\n"
6917 " result += vec4(0, 0, "
6918 << float(n_id + 1) * 0.325f << ", 0);\n"
6919 "}\n"
6920 "subroutine(SubroutineTEType) void SubroutineTE2(inout vec4 result)\n"
6921 "{\n"
6922 " result += vec4(0, 0, "
6923 << float(n_id + 1) * 0.0325f << ", 0);\n"
6924 "}\n"
6925 "\n"
6926 "subroutine uniform SubroutineTEType function;\n"
6927 "\n"
6928 /* Input block */
6929 "in TC_DATA\n"
6930 "{\n"
6931 " vec4 data;\n"
6932 "} in_tc[];\n"
6933 "\n"
6934 /* Output block */
6935 "out TE_DATA\n"
6936 "{\n"
6937 " vec4 data;\n"
6938 "} out_te;\n"
6939 "\n"
6940 "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n"
6941 "out gl_PerVertex { vec4 gl_Position; };\n"
6942 /* main() declaration */
6943 "void main()\n"
6944 "{\n"
6945 " gl_Position = gl_in[0].gl_Position;\n"
6946 " out_te.data = in_tc[0].data;\n"
6947 "\n"
6948 " function(out_te.data);\n"
6949 "}\n";
6950
6951 return result_sstream.str();
6952 }
6953
6954 /** Retrieves body of a vertex shader that should be used for the test.
6955 * The subroutine implementations are slightly changed, depending on the
6956 * index of the shader, as specified by the caller.
6957 *
6958 * @param n_id Index of the shader.
6959 *
6960 * @return Requested string.
6961 **/
getVertexShaderBody(unsigned int n_id)6962 std::string FunctionalTest13::getVertexShaderBody(unsigned int n_id)
6963 {
6964 std::stringstream result_sstream;
6965
6966 /* Pre-amble */
6967 result_sstream << "#version 400\n"
6968 "\n"
6969 "#extension GL_ARB_shader_subroutine : require\n"
6970 "#extension GL_ARB_separate_shader_objects: require\n"
6971 "\n"
6972 /* Sub-routine */
6973 "subroutine void SubroutineVSType(inout vec4 result);\n"
6974 "\n"
6975 "subroutine(SubroutineVSType) void SubroutineVS1(inout vec4 result)\n"
6976 "{\n"
6977 " result += vec4("
6978 << float(n_id + 1) * 0.125f << ", 0, 0, 0);\n"
6979 "}\n"
6980 "subroutine(SubroutineVSType) void SubroutineVS2(inout vec4 result)\n"
6981 "{\n"
6982 " result += vec4("
6983 << float(n_id + 1) * 0.0125f << ", 0, 0, 0);\n"
6984 "}\n"
6985 "\n"
6986 "subroutine uniform SubroutineVSType function;\n"
6987 "\n"
6988 /* Output block */
6989 "out VS_DATA\n"
6990 "{\n"
6991 " vec4 data;\n"
6992 "} out_vs;\n"
6993 "\n"
6994 "out gl_PerVertex { vec4 gl_Position; };\n"
6995 /* main() declaration */
6996 "void main()\n"
6997 "{\n"
6998 " gl_Position = vec4(0, 0, 0, 1);\n"
6999 " out_vs.data = vec4(0);\n"
7000 "\n"
7001 " function(out_vs.data);\n"
7002 "\n"
7003 "}\n";
7004
7005 return result_sstream.str();
7006 }
7007
7008 /** Initializes all GL objects required to run the test. Also modifies a few
7009 * GL states in order for the test to run correctly.
7010 **/
initTest()7011 void FunctionalTest13::initTest()
7012 {
7013 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
7014
7015 /* Set up viewport */
7016 gl.viewport(0 /* x */, 0 /* y */, m_to_width, m_to_height);
7017 GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed.");
7018
7019 /* Make sure no program is used */
7020 gl.useProgram(0);
7021 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
7022
7023 /* Generate a pipeline object */
7024 gl.genProgramPipelines(1, &m_pipeline_id);
7025 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() call failed.");
7026
7027 gl.bindProgramPipeline(m_pipeline_id);
7028 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
7029
7030 /* Initialize all shader programs */
7031 for (unsigned int n_id = 0; n_id < 2 /* variants for each shader type */; ++n_id)
7032 {
7033 std::string fs_body = getFragmentShaderBody(n_id);
7034 const char* fs_body_raw_ptr = fs_body.c_str();
7035 std::string gs_body = getGeometryShaderBody(n_id);
7036 const char* gs_body_raw_ptr = gs_body.c_str();
7037 std::string tc_body = getTessellationControlShaderBody(n_id);
7038 const char* tc_body_raw_ptr = tc_body.c_str();
7039 std::string te_body = getTessellationEvaluationShaderBody(n_id);
7040 const char* te_body_raw_ptr = te_body.c_str();
7041 std::string vs_body = getVertexShaderBody(n_id);
7042 const char* vs_body_raw_ptr = vs_body.c_str();
7043
7044 m_fs_po_ids[n_id] = gl.createShaderProgramv(GL_FRAGMENT_SHADER, 1 /* count */, &fs_body_raw_ptr);
7045 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
7046
7047 m_gs_po_ids[n_id] = gl.createShaderProgramv(GL_GEOMETRY_SHADER, 1 /* count */, &gs_body_raw_ptr);
7048 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
7049
7050 m_tc_po_ids[n_id] = gl.createShaderProgramv(GL_TESS_CONTROL_SHADER, 1 /* count */, &tc_body_raw_ptr);
7051 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
7052
7053 m_te_po_ids[n_id] = gl.createShaderProgramv(GL_TESS_EVALUATION_SHADER, 1 /* count */, &te_body_raw_ptr);
7054 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
7055
7056 m_vs_po_ids[n_id] = gl.createShaderProgramv(GL_VERTEX_SHADER, 1 /* count */, &vs_body_raw_ptr);
7057 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
7058
7059 /* Verify that all shader program objects have been linked successfully */
7060 const glw::GLuint po_ids[] = {
7061 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],
7062 };
7063 const unsigned int n_po_ids = sizeof(po_ids) / sizeof(po_ids[0]);
7064
7065 for (unsigned int n_po_id = 0; n_po_id < n_po_ids; ++n_po_id)
7066 {
7067 glw::GLint link_status = GL_FALSE;
7068 glw::GLuint po_id = po_ids[n_po_id];
7069
7070 gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status);
7071 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
7072
7073 if (link_status != GL_TRUE)
7074 {
7075 TCU_FAIL("Shader program object linking failed.");
7076 }
7077 } /* for (all shader program objects) */
7078 } /* for (both shader program object variants) */
7079
7080 /* Generate a texture object. We will use the base mip-map as a render-target */
7081 gl.genTextures(1, &m_to_id);
7082 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed.");
7083
7084 gl.bindTexture(GL_TEXTURE_2D, m_to_id);
7085 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
7086
7087 gl.texStorage2D(GL_TEXTURE_2D, 1 /* levels */, GL_RGBA32F, m_to_width, m_to_height);
7088 GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed");
7089
7090 /* Generate and configure a FBO we will use for the draw call */
7091 gl.genFramebuffers(1, &m_fbo_id);
7092 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed.");
7093
7094 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
7095 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed.");
7096
7097 gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0 /* level */);
7098 GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
7099
7100 /* Generate & bind a VAO */
7101 gl.genVertexArrays(1, &m_vao_id);
7102 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
7103
7104 gl.bindVertexArray(m_vao_id);
7105 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
7106
7107 /* Set up tessellation */
7108 gl.patchParameteri(GL_PATCH_VERTICES, 1);
7109 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteri() call failed.");
7110
7111 /* Set up pixel storage alignment */
7112 gl.pixelStorei(GL_PACK_ALIGNMENT, 1);
7113 GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call failed.");
7114
7115 /* Allocate enough space to hold color attachment data */
7116 m_read_buffer = (unsigned char*)new float[m_to_width * m_to_height * 4 /* rgba */];
7117 }
7118
7119 /** Executes test iteration.
7120 *
7121 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
7122 */
iterate()7123 tcu::TestNode::IterateResult FunctionalTest13::iterate()
7124 {
7125 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
7126
7127 /* Do not execute the test if GL_ARB_shader_subroutine and GL_ARB_separate_shader_objects
7128 * are not supported */
7129 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
7130 {
7131 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
7132 }
7133
7134 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_separate_shader_objects"))
7135 {
7136 throw tcu::NotSupportedError("GL_ARB_separate_shader_objects is not supported");
7137 }
7138
7139 /* Initialize all GL objects before we continue */
7140 initTest();
7141
7142 /* Iterate over all possible FS/GS/TC/TE/VS permutations */
7143 for (int n_shader_permutation = 0; n_shader_permutation < 32 /* 2^5 */; ++n_shader_permutation)
7144 {
7145 const unsigned int n_fs_idx = ((n_shader_permutation & (1 << 0)) != 0) ? 1 : 0;
7146 const unsigned int n_gs_idx = ((n_shader_permutation & (1 << 1)) != 0) ? 1 : 0;
7147 const unsigned int n_tc_idx = ((n_shader_permutation & (1 << 2)) != 0) ? 1 : 0;
7148 const unsigned int n_te_idx = ((n_shader_permutation & (1 << 3)) != 0) ? 1 : 0;
7149 const unsigned int n_vs_idx = ((n_shader_permutation & (1 << 4)) != 0) ? 1 : 0;
7150 const unsigned int fs_po_id = m_fs_po_ids[n_fs_idx];
7151 const unsigned int gs_po_id = m_gs_po_ids[n_gs_idx];
7152 const unsigned int tc_po_id = m_tc_po_ids[n_tc_idx];
7153 const unsigned int te_po_id = m_te_po_ids[n_te_idx];
7154 const unsigned int vs_po_id = m_vs_po_ids[n_vs_idx];
7155
7156 /* Configure fragment shader stage */
7157 gl.useProgramStages(m_pipeline_id, GL_FRAGMENT_SHADER_BIT, fs_po_id);
7158 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed for GL_FRAGMENT_SHADER_BIT bit");
7159
7160 /* Configure geometry shader stage */
7161 gl.useProgramStages(m_pipeline_id, GL_GEOMETRY_SHADER_BIT, gs_po_id);
7162 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed for GL_GEOMETRY_SHADER_BIT bit");
7163
7164 /* Configure tessellation control shader stage */
7165 gl.useProgramStages(m_pipeline_id, GL_TESS_CONTROL_SHADER_BIT, tc_po_id);
7166 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed for GL_TESS_CONTROL_SHADER_BIT bit");
7167
7168 /* Configure tessellation evaluation shader stage */
7169 gl.useProgramStages(m_pipeline_id, GL_TESS_EVALUATION_SHADER_BIT, te_po_id);
7170 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed for GL_TESS_EVALUATION_SHADER_BIT bit");
7171
7172 /* Configure vertex shader stage */
7173 gl.useProgramStages(m_pipeline_id, GL_VERTEX_SHADER_BIT, vs_po_id);
7174 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed for GL_VERTEX_SHADER_BIT bit");
7175
7176 /* Validate the pipeline */
7177 glw::GLint validate_status = GL_FALSE;
7178
7179 gl.validateProgramPipeline(m_pipeline_id);
7180 GLU_EXPECT_NO_ERROR(gl.getError(), "glValidateProgramPipeline() call failed.");
7181
7182 gl.getProgramPipelineiv(m_pipeline_id, GL_VALIDATE_STATUS, &validate_status);
7183 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramPipelineiv() call failed.");
7184
7185 if (validate_status != GL_TRUE)
7186 {
7187 TCU_FAIL("Program pipeline has not been validated successfully.");
7188 }
7189
7190 /* Retrieve subroutine indices */
7191 GLuint fs_subroutine_indices[2] = { (GLuint)-1 };
7192 GLint fs_subroutine_uniform_index = 0;
7193 GLuint gs_subroutine_indices[2] = { (GLuint)-1 };
7194 GLint gs_subroutine_uniform_index = 0;
7195 GLuint tc_subroutine_indices[2] = { (GLuint)-1 };
7196 GLint tc_subroutine_uniform_index = 0;
7197 GLuint te_subroutine_indices[2] = { (GLuint)-1 };
7198 GLint te_subroutine_uniform_index = 0;
7199 GLuint vs_subroutine_indices[2] = { (GLuint)-1 };
7200 GLint vs_subroutine_uniform_index = 0;
7201
7202 for (unsigned int n_subroutine = 0; n_subroutine < 2; ++n_subroutine)
7203 {
7204 std::stringstream fs_subroutine_name_sstream;
7205 std::stringstream gs_subroutine_name_sstream;
7206 std::stringstream tc_subroutine_name_sstream;
7207 std::stringstream te_subroutine_name_sstream;
7208 std::stringstream vs_subroutine_name_sstream;
7209
7210 fs_subroutine_name_sstream << "SubroutineFS" << (n_subroutine + 1);
7211 gs_subroutine_name_sstream << "SubroutineGS" << (n_subroutine + 1);
7212 tc_subroutine_name_sstream << "SubroutineTC" << (n_subroutine + 1);
7213 te_subroutine_name_sstream << "SubroutineTE" << (n_subroutine + 1);
7214 vs_subroutine_name_sstream << "SubroutineVS" << (n_subroutine + 1);
7215
7216 fs_subroutine_indices[n_subroutine] =
7217 gl.getSubroutineIndex(fs_po_id, GL_FRAGMENT_SHADER, fs_subroutine_name_sstream.str().c_str());
7218 gs_subroutine_indices[n_subroutine] =
7219 gl.getSubroutineIndex(gs_po_id, GL_GEOMETRY_SHADER, gs_subroutine_name_sstream.str().c_str());
7220 tc_subroutine_indices[n_subroutine] =
7221 gl.getSubroutineIndex(tc_po_id, GL_TESS_CONTROL_SHADER, tc_subroutine_name_sstream.str().c_str());
7222 te_subroutine_indices[n_subroutine] =
7223 gl.getSubroutineIndex(te_po_id, GL_TESS_EVALUATION_SHADER, te_subroutine_name_sstream.str().c_str());
7224 vs_subroutine_indices[n_subroutine] =
7225 gl.getSubroutineIndex(vs_po_id, GL_VERTEX_SHADER, vs_subroutine_name_sstream.str().c_str());
7226 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineIndex() call(s) failed.");
7227
7228 if (fs_subroutine_indices[n_subroutine] == (GLuint)-1 ||
7229 gs_subroutine_indices[n_subroutine] == (GLuint)-1 ||
7230 tc_subroutine_indices[n_subroutine] == (GLuint)-1 ||
7231 te_subroutine_indices[n_subroutine] == (GLuint)-1 || vs_subroutine_indices[n_subroutine] == (GLuint)-1)
7232 {
7233 m_testCtx.getLog() << tcu::TestLog::Message
7234 << "At least one subroutine was not recognized by glGetSubroutineIndex() call. "
7235 "(fs:"
7236 << fs_subroutine_indices[n_subroutine]
7237 << ", gs:" << gs_subroutine_indices[n_subroutine]
7238 << ", tc:" << tc_subroutine_indices[n_subroutine]
7239 << ", te:" << te_subroutine_indices[n_subroutine]
7240 << ", vs:" << vs_subroutine_indices[n_subroutine] << ")."
7241 << tcu::TestLog::EndMessage;
7242
7243 TCU_FAIL("At least one subroutine was not recognized");
7244 }
7245 } /* for (both subroutines) */
7246
7247 /* Retrieve subroutine uniform indices */
7248 fs_subroutine_uniform_index = gl.getSubroutineUniformLocation(fs_po_id, GL_FRAGMENT_SHADER, "function");
7249 gs_subroutine_uniform_index = gl.getSubroutineUniformLocation(gs_po_id, GL_GEOMETRY_SHADER, "function");
7250 tc_subroutine_uniform_index = gl.getSubroutineUniformLocation(tc_po_id, GL_TESS_CONTROL_SHADER, "function");
7251 te_subroutine_uniform_index = gl.getSubroutineUniformLocation(te_po_id, GL_TESS_EVALUATION_SHADER, "function");
7252 vs_subroutine_uniform_index = gl.getSubroutineUniformLocation(vs_po_id, GL_VERTEX_SHADER, "function");
7253
7254 if (fs_subroutine_uniform_index == -1 || gs_subroutine_uniform_index == -1 ||
7255 tc_subroutine_uniform_index == -1 || te_subroutine_uniform_index == -1 || vs_subroutine_uniform_index == -1)
7256 {
7257 m_testCtx.getLog() << tcu::TestLog::Message << "At least one subroutine uniform is considered inactive by "
7258 "glGetSubroutineUniformLocation ("
7259 "fs:"
7260 << fs_subroutine_uniform_index << ", gs:" << gs_subroutine_uniform_index
7261 << ", tc:" << tc_subroutine_uniform_index << ", te:" << te_subroutine_uniform_index
7262 << ", vs:" << vs_subroutine_uniform_index << ")." << tcu::TestLog::EndMessage;
7263
7264 TCU_FAIL("At least one subroutine uniform is considered inactive");
7265 }
7266
7267 /* Check if both subroutines work correctly in each stage */
7268 for (int n_subroutine_permutation = 0; n_subroutine_permutation < 32; /* 2^5 */
7269 ++n_subroutine_permutation)
7270 {
7271 unsigned int n_fs_subroutine = ((n_subroutine_permutation & (1 << 0)) != 0) ? 1 : 0;
7272 unsigned int n_gs_subroutine = ((n_subroutine_permutation & (1 << 1)) != 0) ? 1 : 0;
7273 unsigned int n_tc_subroutine = ((n_subroutine_permutation & (1 << 2)) != 0) ? 1 : 0;
7274 unsigned int n_te_subroutine = ((n_subroutine_permutation & (1 << 3)) != 0) ? 1 : 0;
7275 unsigned int n_vs_subroutine = ((n_subroutine_permutation & (1 << 4)) != 0) ? 1 : 0;
7276
7277 /* Configure subroutine uniforms */
7278 struct
7279 {
7280 glw::GLenum stage;
7281 glw::GLuint po_id;
7282 glw::GLuint* indices;
7283 } configurations[] = {
7284 { GL_FRAGMENT_SHADER, fs_po_id, fs_subroutine_indices + n_fs_subroutine },
7285 { GL_GEOMETRY_SHADER, gs_po_id, gs_subroutine_indices + n_gs_subroutine },
7286 { GL_TESS_CONTROL_SHADER, tc_po_id, tc_subroutine_indices + n_tc_subroutine },
7287 { GL_TESS_EVALUATION_SHADER, te_po_id, te_subroutine_indices + n_te_subroutine },
7288 { GL_VERTEX_SHADER, vs_po_id, vs_subroutine_indices + n_vs_subroutine },
7289 };
7290
7291 for (int i = 0; i < 5; ++i)
7292 {
7293 gl.activeShaderProgram(m_pipeline_id, configurations[i].po_id);
7294 GLU_EXPECT_NO_ERROR(gl.getError(), "glActiveShaderProgram() call failed.");
7295
7296 gl.uniformSubroutinesuiv(configurations[i].stage, 1 /* count */, configurations[i].indices);
7297 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniformSubroutinesuiv() call failed.");
7298 }
7299
7300 /* Render a full-screen quad with the pipeline */
7301 gl.clear(GL_COLOR_BUFFER_BIT);
7302 GLU_EXPECT_NO_ERROR(gl.getError(), "glClear() call failed.");
7303
7304 gl.drawArrays(GL_PATCHES, 0 /* first */, 1 /* count */);
7305 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
7306
7307 /* Read color attachment's contents */
7308 gl.readPixels(0, /* x */
7309 0, /* y */
7310 m_to_width, m_to_height, GL_RGBA, GL_FLOAT, m_read_buffer);
7311 GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed.");
7312
7313 /* Verify the contents */
7314 verifyReadBuffer(n_fs_idx, n_fs_subroutine, n_gs_idx, n_gs_subroutine, n_tc_idx, n_tc_subroutine, n_te_idx,
7315 n_te_subroutine, n_vs_idx, n_vs_subroutine);
7316 } /* for (all subroutine permutations) */
7317 } /* for (all program shader object permutations) */
7318
7319 /** All done */
7320 if (m_has_test_passed)
7321 {
7322 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
7323 }
7324 else
7325 {
7326 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
7327 }
7328
7329 return STOP;
7330 }
7331
7332 /** Verifies the data that have been rendered using a pipeline object.
7333 * Contents of the data depends on indices of the shaders, as well as
7334 * on the subroutines that have been activated for particular iteration.
7335 *
7336 * @param n_fs_id Index of the fragment shader used for the iteration;
7337 * @param n_fs_subroutine Index of the subroutine used in the fragment shader
7338 * for the iteration;
7339 * @param n_gs_id Index of the geometry shader used for the iteration;
7340 * @param n_gs_subroutine Index of the subroutine used in the geometry shader
7341 * for the iteration;
7342 * @param n_tc_id Index of the tessellation control shader used for the iteration;
7343 * @param n_tc_subroutine Index of the subroutine used in the tessellation control
7344 * shader for the iteration;
7345 * @param n_te_id Index of the tessellation evaluation shader used for the iteration;
7346 * @param n_te_subroutine Index of the subroutine used in the tessellation evaluation
7347 * shader for the iteration;
7348 * @param n_vs_id Index of the vertex shader used for the iteration;
7349 * @param n_vs_subroutine Index of the subroutine used in the vertex shader for
7350 * the iteration.
7351 */
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)7352 void FunctionalTest13::verifyReadBuffer(unsigned int n_fs_id, unsigned int n_fs_subroutine, unsigned int n_gs_id,
7353 unsigned int n_gs_subroutine, unsigned int n_tc_id,
7354 unsigned int n_tc_subroutine, unsigned int n_te_id,
7355 unsigned int n_te_subroutine, unsigned int n_vs_id,
7356 unsigned int n_vs_subroutine)
7357 {
7358 float expected_color[4] = { 0 };
7359 float fs_modifier[4] = { 0 };
7360 float gs_modifier[4] = { 0 };
7361 float tc_modifier[4] = { 0 };
7362 float te_modifier[4] = { 0 };
7363 float vs_modifier[4] = { 0 };
7364
7365 if (n_fs_subroutine == 0)
7366 {
7367 for (unsigned int n_component = 0; n_component < 4; ++n_component)
7368 {
7369 fs_modifier[n_component] = float(n_fs_id + n_component + 1) / 10.0f;
7370 }
7371 }
7372 else
7373 {
7374 for (unsigned int n_component = 0; n_component < 4; ++n_component)
7375 {
7376 fs_modifier[n_component] = float(n_fs_id + n_component + 1) / 20.0f;
7377 }
7378 }
7379
7380 if (n_gs_subroutine == 0)
7381 {
7382 gs_modifier[3] = float(n_gs_id + 1) * 0.425f;
7383 }
7384 else
7385 {
7386 gs_modifier[3] = float(n_gs_id + 1) * 0.0425f;
7387 }
7388
7389 if (n_tc_subroutine == 0)
7390 {
7391 tc_modifier[1] = float(n_tc_id + 1) * 0.25f;
7392 }
7393 else
7394 {
7395 tc_modifier[1] = float(n_tc_id + 1) * 0.025f;
7396 }
7397
7398 if (n_te_subroutine == 0)
7399 {
7400 te_modifier[2] = float(n_te_id + 1) * 0.325f;
7401 }
7402 else
7403 {
7404 te_modifier[2] = float(n_te_id + 1) * 0.0325f;
7405 }
7406
7407 if (n_vs_subroutine == 0)
7408 {
7409 vs_modifier[0] = float(n_vs_id + 1) * 0.125f;
7410 }
7411 else
7412 {
7413 vs_modifier[0] = float(n_vs_id + 1) * 0.0125f;
7414 }
7415
7416 /* Determine the expected color */
7417 for (unsigned int n_component = 0; n_component < 4 /* rgba */; ++n_component)
7418 {
7419 expected_color[n_component] = fs_modifier[n_component] + gs_modifier[n_component] + tc_modifier[n_component] +
7420 te_modifier[n_component] + vs_modifier[n_component];
7421 }
7422
7423 /* Verify all read texels are valid */
7424 const float epsilon = 1e-5f;
7425 bool should_continue = true;
7426
7427 for (unsigned int y = 0; y < m_to_height && should_continue; ++y)
7428 {
7429 const float* row_ptr = (const float*)m_read_buffer + y * m_to_width * 4; /* rgba */
7430
7431 for (unsigned int x = 0; x < m_to_width && should_continue; ++x)
7432 {
7433 const float* texel_ptr = row_ptr + x * 4; /* rgba */
7434
7435 if (de::abs(texel_ptr[0] - expected_color[0]) > epsilon ||
7436 de::abs(texel_ptr[1] - expected_color[1]) > epsilon ||
7437 de::abs(texel_ptr[2] - expected_color[2]) > epsilon ||
7438 de::abs(texel_ptr[3] - expected_color[3]) > epsilon)
7439 {
7440 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid texel rendered at (" << x << ", " << y
7441 << ") for "
7442 "the following configuration: "
7443 "n_fs_id:"
7444 << n_fs_id << " n_fs_subroutine:" << n_fs_subroutine << " n_gs_id:" << n_gs_id
7445 << " n_gs_subroutine:" << n_gs_subroutine << " n_tc_id:" << n_tc_id
7446 << " n_tc_subroutine:" << n_tc_subroutine << " n_te_id:" << n_te_id
7447 << " n_te_subroutine:" << n_te_subroutine << " n_vs_id:" << n_vs_id
7448 << " n_vs_subroutine:" << n_vs_subroutine << "; expected:"
7449 "("
7450 << expected_color[0] << ", " << expected_color[1] << ", " << expected_color[2]
7451 << ", " << expected_color[3] << "), found:"
7452 "("
7453 << texel_ptr[0] << ", " << texel_ptr[1] << ", " << texel_ptr[2] << ", "
7454 << texel_ptr[3] << ")." << tcu::TestLog::EndMessage;
7455
7456 m_has_test_passed = false;
7457 should_continue = false;
7458 }
7459 } /* for (all columns) */
7460 } /* for (all rows) */
7461 }
7462
7463 /** Constructor
7464 *
7465 * @param context CTS context
7466 **/
FunctionalTest14_15(deqp::Context & context)7467 FunctionalTest14_15::FunctionalTest14_15(deqp::Context& context)
7468 : TestCase(context, "structure_parameters_program_binary", "Verify structures can be used as parameters")
7469 , m_uniform_location(0)
7470 {
7471 }
7472
7473 /** Execute test
7474 *
7475 * @return tcu::TestNode::STOP
7476 **/
iterate()7477 tcu::TestNode::IterateResult FunctionalTest14_15::iterate()
7478 {
7479 static const GLchar* vertex_shader_code =
7480 "#version 400 core\n"
7481 "#extension GL_ARB_shader_subroutine : require\n"
7482 "\n"
7483 "precision highp float;\n"
7484 "\n"
7485 "struct data\n"
7486 "{\n"
7487 " uint r;\n"
7488 " uint g;\n"
7489 " uint b;\n"
7490 " uint a;\n"
7491 "};\n"
7492 "\n"
7493 "subroutine void routine_type_1(in data iparam, out data oparam);\n"
7494 "subroutine void routine_type_2(inout data arg);\n"
7495 "\n"
7496 "subroutine (routine_type_1) void invert(in data iparam, out data oparam)\n"
7497 "{\n"
7498 " oparam.r = iparam.a;\n"
7499 " oparam.g = iparam.b;\n"
7500 " oparam.b = iparam.g;\n"
7501 " oparam.a = iparam.r;\n"
7502 "}\n"
7503 "\n"
7504 "subroutine (routine_type_1) void increment(in data iparam, out data oparam)\n"
7505 "{\n"
7506 " oparam.r = 1 + iparam.r;\n"
7507 " oparam.g = 1 + iparam.g;\n"
7508 " oparam.b = 1 + iparam.b;\n"
7509 " oparam.a = 1 + iparam.a;\n"
7510 "}\n"
7511 "\n"
7512 "subroutine (routine_type_2) void div_by_2(inout data arg)\n"
7513 "{\n"
7514 " arg.r = arg.r / 2;\n"
7515 " arg.g = arg.g / 2;\n"
7516 " arg.b = arg.b / 2;\n"
7517 " arg.a = arg.a / 2;\n"
7518 "}\n"
7519 "\n"
7520 "subroutine (routine_type_2) void decrement(inout data arg)\n"
7521 "{\n"
7522 " arg.r = arg.r - 1;\n"
7523 " arg.g = arg.g - 1;\n"
7524 " arg.b = arg.b - 1;\n"
7525 " arg.a = arg.a - 1;\n"
7526 "}\n"
7527 "\n"
7528 "subroutine uniform routine_type_1 routine_1;\n"
7529 "subroutine uniform routine_type_2 routine_2;\n"
7530 "\n"
7531 "uniform uvec4 uni_input;\n"
7532 "\n"
7533 "out uvec4 out_routine_1;\n"
7534 "out uvec4 out_routine_2;\n"
7535 "\n"
7536 "\n"
7537 "void main()\n"
7538 "{\n"
7539 " data routine_1_input;\n"
7540 " data routine_1_output;\n"
7541 " data routine_2_arg;\n"
7542 "\n"
7543 " routine_1_input.r = uni_input.r;\n"
7544 " routine_1_input.g = uni_input.g;\n"
7545 " routine_1_input.b = uni_input.b;\n"
7546 " routine_1_input.a = uni_input.a;\n"
7547 "\n"
7548 " routine_2_arg.r = uni_input.r;\n"
7549 " routine_2_arg.g = uni_input.g;\n"
7550 " routine_2_arg.b = uni_input.b;\n"
7551 " routine_2_arg.a = uni_input.a;\n"
7552 "\n"
7553 " routine_1(routine_1_input, routine_1_output);\n"
7554 " routine_2(routine_2_arg);\n"
7555 "\n"
7556 " out_routine_1.r = routine_1_output.r;\n"
7557 " out_routine_1.g = routine_1_output.g;\n"
7558 " out_routine_1.b = routine_1_output.b;\n"
7559 " out_routine_1.a = routine_1_output.a;\n"
7560 "\n"
7561 " out_routine_2.r = routine_2_arg.r;\n"
7562 " out_routine_2.g = routine_2_arg.g;\n"
7563 " out_routine_2.b = routine_2_arg.b;\n"
7564 " out_routine_2.a = routine_2_arg.a;\n"
7565 "}\n"
7566 "\n";
7567
7568 static const GLchar* subroutine_names[][2] = { { "invert", "increment" }, { "div_by_2", "decrement" } };
7569 static const GLuint n_subroutine_types = sizeof(subroutine_names) / sizeof(subroutine_names[0]);
7570
7571 static const GLchar* subroutine_uniform_names[] = { "routine_1", "routine_2" };
7572 static const GLuint n_subroutine_uniform_names =
7573 sizeof(subroutine_uniform_names) / sizeof(subroutine_uniform_names[0]);
7574
7575 static const GLchar* uniform_name = "uni_input";
7576 static const GLchar* varying_names[] = { "out_routine_1", "out_routine_2" };
7577
7578 static const GLuint n_varying_names = sizeof(varying_names) / sizeof(varying_names[0]);
7579 static const GLuint transform_feedback_buffer_size = n_varying_names * 4 * sizeof(GLuint);
7580
7581 /* Test data */
7582 static const Utils::vec4<GLuint> uni_input[] = { Utils::vec4<GLuint>(8, 64, 4096, 16777216),
7583 Utils::vec4<GLuint>(8, 64, 4096, 16777216) };
7584
7585 static const Utils::vec4<GLuint> out_routine_1[] = { Utils::vec4<GLuint>(16777216, 4096, 64, 8),
7586 Utils::vec4<GLuint>(9, 65, 4097, 16777217) };
7587
7588 static const Utils::vec4<GLuint> out_routine_2[] = { Utils::vec4<GLuint>(4, 32, 2048, 8388608),
7589 Utils::vec4<GLuint>(7, 63, 4095, 16777215) };
7590
7591 static const GLuint n_test_cases = 2;
7592
7593 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
7594 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
7595 {
7596 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
7597 }
7598
7599 /* GL objects */
7600 Utils::program program(m_context);
7601 Utils::buffer transform_feedback_buffer(m_context);
7602 Utils::vertexArray vao(m_context);
7603
7604 bool is_program_binary_supported = program.isProgramBinarySupported();
7605
7606 /* Init GL objects */
7607 program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code,
7608 varying_names /* varying_names */, n_varying_names /* n_varyings */);
7609
7610 /* Do not execute the test if GL_ARB_get_program_binary is not supported */
7611 if (true == is_program_binary_supported)
7612 {
7613 /* Get subroutine indices */
7614 for (GLuint type = 0; type < n_subroutine_types; ++type)
7615 {
7616 m_initial_subroutine_indices[type][0] =
7617 program.getSubroutineIndex(subroutine_names[type][0], GL_VERTEX_SHADER);
7618
7619 m_initial_subroutine_indices[type][1] =
7620 program.getSubroutineIndex(subroutine_names[type][1], GL_VERTEX_SHADER);
7621 }
7622
7623 /* Get subroutine uniform locations */
7624 for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
7625 {
7626 m_initial_subroutine_uniform_locations[uniform] =
7627 program.getSubroutineUniformLocation(subroutine_uniform_names[uniform], GL_VERTEX_SHADER);
7628 }
7629
7630 /* Delete program and recreate it from binary */
7631 std::vector<GLubyte> program_binary;
7632 GLenum binary_format;
7633
7634 program.getBinary(program_binary, binary_format);
7635 program.remove();
7636 program.createFromBinary(program_binary, binary_format);
7637 }
7638
7639 program.use();
7640
7641 vao.generate();
7642 vao.bind();
7643
7644 transform_feedback_buffer.generate();
7645 transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
7646 GL_DYNAMIC_COPY);
7647 transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
7648
7649 /* Get subroutine indices */
7650 for (GLuint type = 0; type < n_subroutine_types; ++type)
7651 {
7652 m_subroutine_indices[type][0] = program.getSubroutineIndex(subroutine_names[type][0], GL_VERTEX_SHADER);
7653 m_subroutine_indices[type][1] = program.getSubroutineIndex(subroutine_names[type][1], GL_VERTEX_SHADER);
7654 }
7655
7656 /* Get subroutine uniform locations */
7657 for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
7658 {
7659 m_subroutine_uniform_locations[uniform] =
7660 program.getSubroutineUniformLocation(subroutine_uniform_names[uniform], GL_VERTEX_SHADER);
7661 }
7662
7663 /* Get uniform locations */
7664 m_uniform_location = program.getUniformLocation(uniform_name);
7665
7666 /* Test */
7667 bool result = true;
7668
7669 /* Test program binary */
7670 if (true == is_program_binary_supported)
7671 {
7672 /* Test indices and locations */
7673 if (false == testIndicesAndLocations())
7674 {
7675 static const GLuint n_subroutines_per_type = 2;
7676
7677 m_context.getTestContext().getLog() << tcu::TestLog::Message
7678 << "Error. Subroutine indices or subroutine uniform location changed."
7679 << tcu::TestLog::EndMessage;
7680
7681 for (GLuint type = 0; type < n_subroutine_types; ++type)
7682 {
7683 for (GLuint i = 0; i < n_subroutines_per_type; ++i)
7684 {
7685 m_context.getTestContext().getLog()
7686 << tcu::TestLog::Message << "Subroutine: " << subroutine_names[type][i]
7687 << " index: " << m_subroutine_indices[type][i]
7688 << " initial index: " << m_initial_subroutine_indices[type][i] << tcu::TestLog::EndMessage;
7689 }
7690 }
7691
7692 for (GLuint uniform = 0; uniform < n_subroutine_uniform_names; ++uniform)
7693 {
7694 m_context.getTestContext().getLog()
7695 << tcu::TestLog::Message << "Subroutine uniform: " << subroutine_uniform_names[uniform]
7696 << " location: " << m_subroutine_uniform_locations[uniform]
7697 << " initial location: " << m_initial_subroutine_uniform_locations[uniform]
7698 << tcu::TestLog::EndMessage;
7699 }
7700
7701 result = false;
7702 }
7703
7704 /* Test draw with deafult set of subroutines */
7705 if (false == testDefaultSubroutineSet(uni_input[0], out_routine_1, out_routine_2))
7706 {
7707 result = false;
7708 }
7709 }
7710
7711 for (GLuint i = 0; i < n_test_cases; ++i)
7712 {
7713 if (false == testDraw(i, uni_input[i], out_routine_1[i], out_routine_2[i]))
7714 {
7715 result = false;
7716 }
7717 }
7718
7719 /* Set result */
7720 if (true == result)
7721 {
7722 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
7723 }
7724 else
7725 {
7726 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
7727 }
7728
7729 /* Done */
7730 return tcu::TestNode::STOP;
7731 }
7732
7733 /** Execute draw call and verify results
7734 *
7735 * @param uni_input Input data
7736 * @param expected_routine_1_result Set of expected results of "routine_1"
7737 * @param expected_routine_2_result Set of expected results of "routine_2"
7738 *
7739 * @return true if test pass, false otherwise
7740 **/
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]) const7741 bool FunctionalTest14_15::testDefaultSubroutineSet(const Utils::vec4<glw::GLuint>& uni_input,
7742 const Utils::vec4<glw::GLuint> expected_routine_1_result[2],
7743 const Utils::vec4<glw::GLuint> expected_routine_2_result[2]) const
7744 {
7745 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
7746 bool result = true;
7747
7748 /* Set up input data uniforms */
7749 gl.uniform4ui(m_uniform_location, uni_input.m_x, uni_input.m_y, uni_input.m_z, uni_input.m_w);
7750 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
7751
7752 /* Execute draw call with transform feedback */
7753 gl.beginTransformFeedback(GL_POINTS);
7754 GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
7755
7756 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
7757 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
7758
7759 gl.endTransformFeedback();
7760 GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
7761
7762 /* Capture results */
7763 GLuint* feedback_data = (GLuint*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
7764 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
7765
7766 Utils::vec4<GLuint> routine_1_result;
7767 Utils::vec4<GLuint> routine_2_result;
7768
7769 routine_1_result.m_x = feedback_data[0 + 0];
7770 routine_1_result.m_y = feedback_data[0 + 1];
7771 routine_1_result.m_z = feedback_data[0 + 2];
7772 routine_1_result.m_w = feedback_data[0 + 3];
7773
7774 routine_2_result.m_x = feedback_data[4 + 0];
7775 routine_2_result.m_y = feedback_data[4 + 1];
7776 routine_2_result.m_z = feedback_data[4 + 2];
7777 routine_2_result.m_w = feedback_data[4 + 3];
7778
7779 /* Unmap buffer */
7780 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
7781 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
7782
7783 /* Verifiy */
7784 result = result &&
7785 ((routine_1_result == expected_routine_1_result[0]) || (routine_1_result == expected_routine_1_result[1]));
7786
7787 result = result &&
7788 ((routine_2_result == expected_routine_2_result[0]) || (routine_2_result == expected_routine_2_result[1]));
7789
7790 /* Log error if any */
7791 if (false == result)
7792 {
7793 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error. Invalid result."
7794 << tcu::TestLog::EndMessage;
7795
7796 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
7797
7798 message << "Routine_1, result: ";
7799
7800 routine_1_result.log(message);
7801
7802 message << "Routine_2, result: ";
7803
7804 routine_2_result.log(message);
7805
7806 message << tcu::TestLog::EndMessage;
7807 }
7808
7809 /* Done */
7810 return result;
7811 }
7812
7813 /** Execute draw call and verify results
7814 *
7815 * @param routine_configuration Subroutine "type" ordinal
7816 * @param uni_input Input data
7817 * @param expected_routine_1_result Expected results of "routine_1"
7818 * @param expected_routine_2_result Expected results of "routine_2"
7819 *
7820 * @return true if test pass, false otherwise
7821 **/
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) const7822 bool FunctionalTest14_15::testDraw(glw::GLuint routine_configuration, const Utils::vec4<glw::GLuint>& uni_input,
7823 const Utils::vec4<glw::GLuint>& expected_routine_1_result,
7824 const Utils::vec4<glw::GLuint>& expected_routine_2_result) const
7825 {
7826 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
7827 bool result = true;
7828 GLuint subroutine_indices[2];
7829 static const GLuint n_subroutine_uniforms = sizeof(subroutine_indices) / sizeof(subroutine_indices[0]);
7830
7831 /* Set up input data uniforms */
7832 gl.uniform4ui(m_uniform_location, uni_input.m_x, uni_input.m_y, uni_input.m_z, uni_input.m_w);
7833 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform4f");
7834
7835 /* Prepare subroutine uniform data */
7836 for (GLuint i = 0; i < n_subroutine_uniforms; ++i)
7837 {
7838 const GLuint location = m_subroutine_uniform_locations[i];
7839
7840 subroutine_indices[location] = m_subroutine_indices[i][routine_configuration];
7841 }
7842
7843 /* Set up subroutine uniforms */
7844 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, n_subroutine_uniforms, &subroutine_indices[0]);
7845 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
7846
7847 /* Execute draw call with transform feedback */
7848 gl.beginTransformFeedback(GL_POINTS);
7849 GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
7850
7851 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
7852 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
7853
7854 gl.endTransformFeedback();
7855 GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
7856
7857 /* Capture results */
7858 GLuint* feedback_data = (GLuint*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
7859 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
7860
7861 Utils::vec4<GLuint> routine_1_result;
7862 Utils::vec4<GLuint> routine_2_result;
7863
7864 routine_1_result.m_x = feedback_data[0 + 0];
7865 routine_1_result.m_y = feedback_data[0 + 1];
7866 routine_1_result.m_z = feedback_data[0 + 2];
7867 routine_1_result.m_w = feedback_data[0 + 3];
7868
7869 routine_2_result.m_x = feedback_data[4 + 0];
7870 routine_2_result.m_y = feedback_data[4 + 1];
7871 routine_2_result.m_z = feedback_data[4 + 2];
7872 routine_2_result.m_w = feedback_data[4 + 3];
7873
7874 /* Unmap buffer */
7875 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
7876 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
7877
7878 /* Verifiy */
7879 result = result && (routine_1_result == expected_routine_1_result);
7880 result = result && (routine_2_result == expected_routine_2_result);
7881
7882 /* Log error if any */
7883 if (false == result)
7884 {
7885 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error. Invalid result."
7886 << tcu::TestLog::EndMessage;
7887
7888 tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
7889
7890 message << "Routine_1, result: ";
7891
7892 routine_1_result.log(message);
7893
7894 message << ", expected: ";
7895
7896 expected_routine_1_result.log(message);
7897
7898 message << "Routine_2, result: ";
7899
7900 routine_2_result.log(message);
7901
7902 message << ", expected: ";
7903
7904 expected_routine_2_result.log(message);
7905
7906 message << tcu::TestLog::EndMessage;
7907 }
7908
7909 /* Done */
7910 return result;
7911 }
7912
7913 /** Verify initial and current values of subroutine indices and subroutines uniform locations
7914 *
7915 * @return true if test pass, false otherwise
7916 **/
testIndicesAndLocations() const7917 bool FunctionalTest14_15::testIndicesAndLocations() const
7918 {
7919 static const GLuint n_subroutine_types = 2;
7920 bool result = true;
7921
7922 /* Verify subroutine indices */
7923 for (GLuint type = 0; type < n_subroutine_types; ++type)
7924 {
7925 result = result && (m_subroutine_indices[type][0] == m_initial_subroutine_indices[type][0]);
7926 result = result && (m_subroutine_indices[type][1] == m_initial_subroutine_indices[type][1]);
7927 }
7928
7929 /* Verify subroutine uniform locations */
7930 for (GLuint uniform = 0; uniform < n_subroutine_types; ++uniform)
7931 {
7932 result = result && (m_subroutine_uniform_locations[uniform] == m_initial_subroutine_uniform_locations[uniform]);
7933 }
7934
7935 return result;
7936 }
7937
7938 /** Constructor.
7939 *
7940 * @param context Rendering context.
7941 *
7942 **/
FunctionalTest16(deqp::Context & context)7943 FunctionalTest16::FunctionalTest16(deqp::Context& context)
7944 : TestCase(context, "subroutine_uniform_reset",
7945 "Checks that when the active program for a shader stage is re-linke or "
7946 "changed by a call to UseProgram, BindProgramPipeline, or UseProgramStages,"
7947 " subroutine uniforms for that stage are reset to arbitrarily chosen default "
7948 "functions with compatible subroutine types.")
7949 , m_are_pipeline_objects_supported(false)
7950 , m_has_test_passed(true)
7951 {
7952 memset(m_fs_ids, 0, sizeof(m_fs_ids));
7953 memset(m_gs_ids, 0, sizeof(m_gs_ids));
7954 memset(m_po_ids, 0, sizeof(m_po_ids));
7955 memset(m_tc_ids, 0, sizeof(m_tc_ids));
7956 memset(m_te_ids, 0, sizeof(m_te_ids));
7957 memset(m_vs_ids, 0, sizeof(m_vs_ids));
7958
7959 memset(m_fs_po_ids, 0, sizeof(m_fs_po_ids));
7960 memset(m_gs_po_ids, 0, sizeof(m_gs_po_ids));
7961 memset(m_pipeline_object_ids, 0, sizeof(m_pipeline_object_ids));
7962 memset(m_tc_po_ids, 0, sizeof(m_tc_po_ids));
7963 memset(m_te_po_ids, 0, sizeof(m_te_po_ids));
7964 memset(m_vs_po_ids, 0, sizeof(m_vs_po_ids));
7965 }
7966
7967 /** Deinitializes all GL objects that may have been created during test execution. */
deinit()7968 void FunctionalTest16::deinit()
7969 {
7970 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
7971
7972 for (unsigned int n_id = 0; n_id < 2; ++n_id)
7973 {
7974 if (m_fs_ids[n_id] != 0)
7975 {
7976 gl.deleteShader(m_fs_ids[n_id]);
7977
7978 m_fs_ids[n_id] = 0;
7979 }
7980
7981 if (m_fs_po_ids[n_id] != 0)
7982 {
7983 gl.deleteProgram(m_fs_po_ids[n_id]);
7984
7985 m_fs_po_ids[n_id] = 0;
7986 }
7987
7988 if (m_gs_ids[n_id] != 0)
7989 {
7990 gl.deleteShader(m_gs_ids[n_id]);
7991
7992 m_gs_ids[n_id] = 0;
7993 }
7994
7995 if (m_gs_po_ids[n_id] != 0)
7996 {
7997 gl.deleteProgram(m_gs_po_ids[n_id]);
7998
7999 m_gs_po_ids[n_id] = 0;
8000 }
8001
8002 if (m_pipeline_object_ids[n_id] != 0)
8003 {
8004 gl.deleteProgramPipelines(1 /* n */, m_pipeline_object_ids + n_id);
8005 }
8006
8007 if (m_po_ids[n_id] != 0)
8008 {
8009 gl.deleteProgram(m_po_ids[n_id]);
8010
8011 m_po_ids[n_id] = 0;
8012 }
8013
8014 if (m_tc_ids[n_id] != 0)
8015 {
8016 gl.deleteShader(m_tc_ids[n_id]);
8017
8018 m_tc_ids[n_id] = 0;
8019 }
8020
8021 if (m_tc_po_ids[n_id] != 0)
8022 {
8023 gl.deleteProgram(m_tc_po_ids[n_id]);
8024
8025 m_tc_po_ids[n_id] = 0;
8026 }
8027
8028 if (m_te_ids[n_id] != 0)
8029 {
8030 gl.deleteShader(m_te_ids[n_id]);
8031
8032 m_te_ids[n_id] = 0;
8033 }
8034
8035 if (m_te_po_ids[n_id] != 0)
8036 {
8037 gl.deleteProgram(m_te_po_ids[n_id]);
8038
8039 m_te_po_ids[n_id] = 0;
8040 }
8041
8042 if (m_vs_ids[n_id] != 0)
8043 {
8044 gl.deleteShader(m_vs_ids[n_id]);
8045
8046 m_vs_ids[n_id] = 0;
8047 }
8048
8049 if (m_vs_po_ids[n_id] != 0)
8050 {
8051 gl.deleteProgram(m_vs_po_ids[n_id]);
8052
8053 m_vs_po_ids[n_id] = 0;
8054 }
8055 } /* for (both IDs) */
8056 }
8057
8058 /** Retrieves body of a shader that should be used for user-specified shader stage.
8059 * This function returns slightly different implementations, depending on index of
8060 * the program/pipeline object the shader will be used for.
8061 *
8062 * @param shader_stage Stage the shader body is to be returned for.
8063 * @param n_id Index of the shader (as per description).
8064 *
8065 * @return Requested string.
8066 **/
getShaderBody(const Utils::_shader_stage & shader_stage,const unsigned int & n_id) const8067 std::string FunctionalTest16::getShaderBody(const Utils::_shader_stage& shader_stage, const unsigned int& n_id) const
8068 {
8069 std::stringstream result_sstream;
8070
8071 result_sstream << "#version 400\n"
8072 "\n"
8073 "#extension GL_ARB_shader_subroutine : require\n"
8074 "\n";
8075
8076 switch (shader_stage)
8077 {
8078 case Utils::SHADER_STAGE_VERTEX:
8079 {
8080 result_sstream << "out gl_PerVertex { vec4 gl_Position; } ;\n";
8081 break;
8082 }
8083 case Utils::SHADER_STAGE_GEOMETRY:
8084 {
8085 result_sstream << "layout(points) in;\n"
8086 "layout(points, max_vertices = 1) out;\n";
8087 result_sstream << "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n";
8088 result_sstream << "out gl_PerVertex { vec4 gl_Position; } ;\n";
8089 break;
8090 }
8091
8092 case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
8093 {
8094 result_sstream << "layout(vertices = 4) out;\n";
8095 result_sstream << "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n";
8096 result_sstream << "out gl_PerVertex { vec4 gl_Position; } gl_out[];\n";
8097 break;
8098 }
8099
8100 case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
8101 {
8102 result_sstream << "layout(quads) in;\n";
8103 result_sstream << "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n";
8104 result_sstream << "out gl_PerVertex { vec4 gl_Position; };\n";
8105 break;
8106 }
8107
8108 default:
8109 break;
8110 } /* switch (shader_stage) */
8111
8112 result_sstream << "\n"
8113 "subroutine void subroutineType (inout vec4 result);\n"
8114 "subroutine vec4 subroutineType2(in vec4 data);\n"
8115 "\n"
8116 "subroutine(subroutineType) void function1(inout vec4 result)\n"
8117 "{\n"
8118 " result += vec4("
8119 << (n_id + 1) << ", " << (n_id + 2) << ", " << (n_id + 3) << ", " << (n_id + 4)
8120 << ");\n"
8121 "}\n"
8122 "subroutine(subroutineType) void function2(inout vec4 result)\n"
8123 "{\n"
8124 " result += vec4("
8125 << (n_id + 2) << ", " << (n_id + 3) << ", " << (n_id + 4) << ", " << (n_id + 5)
8126 << ");\n"
8127 "}\n"
8128 "\n"
8129 "subroutine(subroutineType2) vec4 function3(in vec4 data)\n"
8130 "{\n"
8131 " return data * data;\n"
8132 "}\n"
8133 "subroutine(subroutineType2) vec4 function4(in vec4 data)\n"
8134 "{\n"
8135 " return data + data;\n"
8136 "}\n"
8137 "\n"
8138 "subroutine uniform subroutineType subroutine1;\n"
8139 "subroutine uniform subroutineType subroutine2;\n"
8140 "subroutine uniform subroutineType2 subroutine3;\n"
8141 "subroutine uniform subroutineType2 subroutine4;\n"
8142 "\n";
8143
8144 if (shader_stage == Utils::SHADER_STAGE_FRAGMENT)
8145 {
8146 result_sstream << "out vec4 result;\n";
8147 }
8148
8149 result_sstream << "void main()\n"
8150 "{\n";
8151
8152 switch (shader_stage)
8153 {
8154 case Utils::SHADER_STAGE_FRAGMENT:
8155 {
8156 result_sstream << " result = vec4(0);\n"
8157 << " subroutine1(result);\n"
8158 " subroutine2(result);\n"
8159 " result = subroutine3(result) + subroutine4(result);\n";
8160
8161 break;
8162 }
8163
8164 case Utils::SHADER_STAGE_GEOMETRY:
8165 {
8166 result_sstream << " gl_Position = vec4(0);\n"
8167 " subroutine1(gl_Position);\n"
8168 " subroutine2(gl_Position);\n"
8169 " gl_Position = subroutine3(gl_Position) + subroutine4(gl_Position);\n"
8170 " EmitVertex();\n";
8171
8172 break;
8173 }
8174
8175 case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
8176 {
8177 result_sstream << " gl_out[gl_InvocationID].gl_Position = vec4(0);\n"
8178 " subroutine1(gl_out[gl_InvocationID].gl_Position);\n"
8179 " subroutine2(gl_out[gl_InvocationID].gl_Position);\n"
8180 " gl_out[gl_InvocationID].gl_Position = subroutine3(gl_in[0].gl_Position) + "
8181 "subroutine4(gl_in[0].gl_Position);\n";
8182
8183 break;
8184 }
8185
8186 case Utils::SHADER_STAGE_VERTEX:
8187 case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
8188 {
8189 result_sstream << " gl_Position = vec4(0);\n"
8190 " subroutine1(gl_Position);\n"
8191 " subroutine2(gl_Position);\n"
8192 " gl_Position = subroutine3(gl_Position) + subroutine4(gl_Position);\n";
8193
8194 break;
8195 }
8196
8197 default:
8198 break;
8199 } /* switch (shader_stage) */
8200
8201 result_sstream << "}\n";
8202
8203 return result_sstream.str();
8204 }
8205
8206 /** Initializes all objects required to run the test. */
initTest()8207 void FunctionalTest16::initTest()
8208 {
8209 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
8210
8211 for (unsigned int n_id = 0; n_id < 2 /* test program/shader objects */; ++n_id)
8212 {
8213 const std::string fs_body = getShaderBody(Utils::SHADER_STAGE_FRAGMENT, n_id);
8214 const std::string gs_body = getShaderBody(Utils::SHADER_STAGE_GEOMETRY, n_id);
8215 const std::string tc_body = getShaderBody(Utils::SHADER_STAGE_TESSELLATION_CONTROL, n_id);
8216 const std::string te_body = getShaderBody(Utils::SHADER_STAGE_TESSELLATION_EVALUATION, n_id);
8217 const std::string vs_body = getShaderBody(Utils::SHADER_STAGE_VERTEX, n_id);
8218
8219 if (!Utils::buildProgram(gl, vs_body, tc_body, te_body, gs_body, fs_body, DE_NULL, /* xfb_varyings */
8220 DE_NULL, /* n_xfb_varyings */
8221 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,
8222 m_po_ids + n_id))
8223 {
8224 m_testCtx.getLog() << tcu::TestLog::Message << "Failed to build test program object, index:"
8225 "["
8226 << n_id << "]" << tcu::TestLog::EndMessage;
8227
8228 TCU_FAIL("Failed to build a test program");
8229 }
8230
8231 if (m_are_pipeline_objects_supported)
8232 {
8233 /* Initialize shader program objects */
8234 const char* fs_body_raw_ptr = fs_body.c_str();
8235 const char* gs_body_raw_ptr = gs_body.c_str();
8236 glw::GLint link_status[5] = { GL_FALSE };
8237 const char* tc_body_raw_ptr = tc_body.c_str();
8238 const char* te_body_raw_ptr = te_body.c_str();
8239 const char* vs_body_raw_ptr = vs_body.c_str();
8240
8241 m_fs_po_ids[n_id] = gl.createShaderProgramv(GL_FRAGMENT_SHADER, 1 /* count */, &fs_body_raw_ptr);
8242 m_gs_po_ids[n_id] = gl.createShaderProgramv(GL_GEOMETRY_SHADER, 1 /* count */, &gs_body_raw_ptr);
8243 m_tc_po_ids[n_id] = gl.createShaderProgramv(GL_TESS_CONTROL_SHADER, 1 /* count */, &tc_body_raw_ptr);
8244 m_te_po_ids[n_id] = gl.createShaderProgramv(GL_TESS_EVALUATION_SHADER, 1 /* count */, &te_body_raw_ptr);
8245 m_vs_po_ids[n_id] = gl.createShaderProgramv(GL_VERTEX_SHADER, 1 /* count */, &vs_body_raw_ptr);
8246 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShaderProgramv() call failed.");
8247
8248 gl.getProgramiv(m_fs_po_ids[n_id], GL_LINK_STATUS, link_status + 0);
8249 gl.getProgramiv(m_gs_po_ids[n_id], GL_LINK_STATUS, link_status + 1);
8250 gl.getProgramiv(m_tc_po_ids[n_id], GL_LINK_STATUS, link_status + 2);
8251 gl.getProgramiv(m_te_po_ids[n_id], GL_LINK_STATUS, link_status + 3);
8252 gl.getProgramiv(m_vs_po_ids[n_id], GL_LINK_STATUS, link_status + 4);
8253 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
8254
8255 if (link_status[0] == GL_FALSE)
8256 TCU_FAIL("Fragment shader program failed to link");
8257 if (link_status[1] == GL_FALSE)
8258 TCU_FAIL("Geometry shader program failed to link");
8259 if (link_status[2] == GL_FALSE)
8260 TCU_FAIL("Tessellation control shader program failed to link");
8261 if (link_status[3] == GL_FALSE)
8262 TCU_FAIL("Tessellation evaluation shader program failed to link");
8263 if (link_status[4] == GL_FALSE)
8264 TCU_FAIL("Vertex shader program failed to link");
8265
8266 /* Initialize pipeline program object */
8267 gl.genProgramPipelines(1 /* n */, m_pipeline_object_ids + n_id);
8268 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() call failed.");
8269
8270 gl.useProgramStages(m_pipeline_object_ids[n_id], GL_FRAGMENT_SHADER_BIT, m_fs_po_ids[n_id]);
8271 gl.useProgramStages(m_pipeline_object_ids[n_id], GL_GEOMETRY_SHADER_BIT, m_gs_po_ids[n_id]);
8272 gl.useProgramStages(m_pipeline_object_ids[n_id], GL_TESS_CONTROL_SHADER_BIT, m_tc_po_ids[n_id]);
8273 gl.useProgramStages(m_pipeline_object_ids[n_id], GL_TESS_EVALUATION_SHADER_BIT, m_te_po_ids[n_id]);
8274 gl.useProgramStages(m_pipeline_object_ids[n_id], GL_VERTEX_SHADER_BIT, m_vs_po_ids[n_id]);
8275 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8276 }
8277
8278 /* Retrieve subroutine locations */
8279 struct _item
8280 {
8281 glw::GLuint po_id;
8282 _shader_stage& stage;
8283 glw::GLuint so_id;
8284 glw::GLenum so_type;
8285 } items[] = {
8286 { m_po_ids[n_id], m_po_descriptors[n_id].fragment, m_fs_ids[n_id], GL_FRAGMENT_SHADER },
8287 { m_po_ids[n_id], m_po_descriptors[n_id].geometry, m_gs_ids[n_id], GL_GEOMETRY_SHADER },
8288 { m_po_ids[n_id], m_po_descriptors[n_id].tess_control, m_tc_ids[n_id], GL_TESS_CONTROL_SHADER },
8289 { m_po_ids[n_id], m_po_descriptors[n_id].tess_evaluation, m_te_ids[n_id], GL_TESS_EVALUATION_SHADER },
8290 { m_po_ids[n_id], m_po_descriptors[n_id].vertex, m_vs_ids[n_id], GL_VERTEX_SHADER },
8291
8292 { m_fs_po_ids[n_id], m_fs_po_descriptors[n_id], m_fs_po_ids[n_id], GL_FRAGMENT_SHADER },
8293 { m_gs_po_ids[n_id], m_gs_po_descriptors[n_id], m_gs_po_ids[n_id], GL_GEOMETRY_SHADER },
8294 { m_tc_po_ids[n_id], m_tc_po_descriptors[n_id], m_tc_po_ids[n_id], GL_TESS_CONTROL_SHADER },
8295 { m_te_po_ids[n_id], m_te_po_descriptors[n_id], m_te_po_ids[n_id], GL_TESS_EVALUATION_SHADER },
8296 { m_vs_po_ids[n_id], m_vs_po_descriptors[n_id], m_vs_po_ids[n_id], GL_VERTEX_SHADER },
8297 };
8298 const unsigned int n_items = sizeof(items) / sizeof(items[0]);
8299
8300 for (unsigned int n_item = 0; n_item < n_items; ++n_item)
8301 {
8302 _item& current_item = items[n_item];
8303
8304 current_item.stage.function1_index =
8305 gl.getSubroutineIndex(current_item.po_id, current_item.so_type, "function1");
8306 current_item.stage.function2_index =
8307 gl.getSubroutineIndex(current_item.po_id, current_item.so_type, "function2");
8308 current_item.stage.function3_index =
8309 gl.getSubroutineIndex(current_item.po_id, current_item.so_type, "function3");
8310 current_item.stage.function4_index =
8311 gl.getSubroutineIndex(current_item.po_id, current_item.so_type, "function4");
8312 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineIndex() call(s) failed.");
8313
8314 if (current_item.stage.function1_index == GL_INVALID_INDEX ||
8315 current_item.stage.function2_index == GL_INVALID_INDEX ||
8316 current_item.stage.function3_index == GL_INVALID_INDEX ||
8317 current_item.stage.function4_index == GL_INVALID_INDEX)
8318 {
8319 TCU_FAIL("Subroutine name was not recognized.");
8320 }
8321
8322 current_item.stage.subroutine1_uniform_location =
8323 gl.getSubroutineUniformLocation(current_item.po_id, current_item.so_type, "subroutine1");
8324 current_item.stage.subroutine2_uniform_location =
8325 gl.getSubroutineUniformLocation(current_item.po_id, current_item.so_type, "subroutine2");
8326 current_item.stage.subroutine3_uniform_location =
8327 gl.getSubroutineUniformLocation(current_item.po_id, current_item.so_type, "subroutine3");
8328 current_item.stage.subroutine4_uniform_location =
8329 gl.getSubroutineUniformLocation(current_item.po_id, current_item.so_type, "subroutine4");
8330 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineUniformLocation() call(s) failed.");
8331
8332 if (current_item.stage.subroutine1_uniform_location == -1 ||
8333 current_item.stage.subroutine2_uniform_location == -1 ||
8334 current_item.stage.subroutine3_uniform_location == -1 ||
8335 current_item.stage.subroutine4_uniform_location == -1)
8336 {
8337 TCU_FAIL("Subroutine uniform name was not recognized.");
8338 }
8339
8340 if (m_po_ids[n_id] == current_item.po_id)
8341 {
8342 gl.useProgram(current_item.po_id);
8343 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
8344 }
8345 else
8346 {
8347 /* Temporarily bind the program pipeline. */
8348 gl.bindProgramPipeline(m_pipeline_object_ids[n_id]);
8349 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
8350 }
8351
8352 gl.getUniformSubroutineuiv(current_item.so_type, current_item.stage.subroutine1_uniform_location,
8353 ¤t_item.stage.default_subroutine1_value);
8354 gl.getUniformSubroutineuiv(current_item.so_type, current_item.stage.subroutine2_uniform_location,
8355 ¤t_item.stage.default_subroutine2_value);
8356 gl.getUniformSubroutineuiv(current_item.so_type, current_item.stage.subroutine3_uniform_location,
8357 ¤t_item.stage.default_subroutine3_value);
8358 gl.getUniformSubroutineuiv(current_item.so_type, current_item.stage.subroutine4_uniform_location,
8359 ¤t_item.stage.default_subroutine4_value);
8360 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformSubroutineuiv() call(s) failed.");
8361
8362 current_item.stage.gl_stage = current_item.so_type;
8363
8364 if (m_po_ids[n_id] != current_item.po_id)
8365 {
8366 /* Unbind the program pipeline object */
8367 gl.bindProgramPipeline(0);
8368 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
8369 }
8370 } /* for (all items) */
8371
8372 /* Make sure the default subroutine choices are valid. */
8373 verifySubroutineUniformValues(
8374 TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT, /* makes the verification routine use program object descriptor */
8375 n_id, SUBROUTINE_UNIFORMS_SET_TO_VALID_VALUES);
8376
8377 if (m_are_pipeline_objects_supported)
8378 {
8379 gl.useProgram(0);
8380 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
8381
8382 gl.bindProgramPipeline(m_pipeline_object_ids[n_id]);
8383 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
8384 {
8385 verifySubroutineUniformValues(
8386 TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_PIPELINE_OBJECT, /* makes the verification routine use pipeline object descriptor */
8387 n_id, SUBROUTINE_UNIFORMS_SET_TO_VALID_VALUES);
8388 }
8389 gl.bindProgramPipeline(0);
8390 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed.");
8391 }
8392 } /* for (both program descriptors) */
8393 }
8394
8395 /** Retrieves IDs of shaders OR shader program objects, depending on which of the two
8396 * the caller requests for.
8397 *
8398 * @param retrieve_program_object_shader_ids true if the caller wishes to retrieve shader object IDs,
8399 * false to return shader program IDs.
8400 * @param n_id Index of the program/pipeline object the shaders
8401 * are a part of.
8402 * @param out_shader_stages Deref will be used to store exactly five IDs. Must not
8403 * be NULL.
8404 **/
getShaderStages(bool retrieve_program_object_shader_ids,const unsigned int & n_id,const _shader_stage ** out_shader_stages) const8405 void FunctionalTest16::getShaderStages(bool retrieve_program_object_shader_ids, const unsigned int& n_id,
8406 const _shader_stage** out_shader_stages) const
8407 {
8408 if (retrieve_program_object_shader_ids)
8409 {
8410 out_shader_stages[0] = &m_po_descriptors[n_id].vertex;
8411 out_shader_stages[1] = &m_po_descriptors[n_id].tess_control;
8412 out_shader_stages[2] = &m_po_descriptors[n_id].tess_evaluation;
8413 out_shader_stages[3] = &m_po_descriptors[n_id].geometry;
8414 out_shader_stages[4] = &m_po_descriptors[n_id].fragment;
8415 }
8416 else
8417 {
8418 out_shader_stages[0] = m_vs_po_descriptors + n_id;
8419 out_shader_stages[1] = m_tc_po_descriptors + n_id;
8420 out_shader_stages[2] = m_te_po_descriptors + n_id;
8421 out_shader_stages[3] = m_gs_po_descriptors + n_id;
8422 out_shader_stages[4] = m_fs_po_descriptors + n_id;
8423 }
8424 }
8425
8426 /** Executes test iteration.
8427 *
8428 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
8429 */
iterate()8430 tcu::TestNode::IterateResult FunctionalTest16::iterate()
8431 {
8432 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
8433
8434 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
8435 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
8436 {
8437 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
8438 }
8439
8440 m_are_pipeline_objects_supported =
8441 m_context.getContextInfo().isExtensionSupported("GL_ARB_separate_shader_objects");
8442
8443 /* Initialize GL objects required to run the test */
8444 initTest();
8445
8446 /* Iterate over both pipelines/programs and verify that calling glUseProgram() /
8447 * glBindProgramPipeline() / glUseProgramStages() resets subroutine uniform configuration.
8448 */
8449 for (int test_case = static_cast<int>(TEST_CASE_FIRST); test_case != static_cast<int>(TEST_CASE_COUNT); ++test_case)
8450 {
8451 if (static_cast<_test_case>(test_case) != TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT &&
8452 !m_are_pipeline_objects_supported)
8453 {
8454 /* Current test case requires GL_ARB_separate_shader_objects support which is
8455 * unavaiable on the platform that we're testing
8456 */
8457 continue;
8458 }
8459
8460 for (unsigned int n_object_id = 0; n_object_id < 2; /* pipeline/program objects allocated for the test */
8461 ++n_object_id)
8462 {
8463 /* Verify that currently reported subroutine uniform values are equal to default values */
8464 if (test_case == TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT)
8465 {
8466 gl.useProgram(m_po_ids[n_object_id]);
8467 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
8468 }
8469 else
8470 {
8471 gl.bindProgramPipeline(m_pipeline_object_ids[n_object_id]);
8472 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed");
8473 }
8474
8475 verifySubroutineUniformValues(static_cast<_test_case>(test_case), n_object_id,
8476 SUBROUTINE_UNIFORMS_SET_TO_DEFAULT_VALUES);
8477
8478 /* Re-configure subroutine uniforms so that they point to different subroutines than
8479 * the default ones.
8480 */
8481 const _shader_stage* stages[5 /* fs+gs+tc+te+vs */] = { DE_NULL };
8482
8483 getShaderStages(static_cast<_test_case>(test_case) == TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT,
8484 n_object_id, stages);
8485
8486 for (unsigned int n_stage = 0; n_stage < 5 /* fs+gs+tc+te+vs stages */; ++n_stage)
8487 {
8488 const _shader_stage& current_stage = *(stages[n_stage]);
8489 glw::GLuint subroutine_configuration[4] = { GL_INVALID_INDEX };
8490
8491 subroutine_configuration[0] =
8492 (current_stage.default_subroutine1_value == current_stage.function1_index) ?
8493 current_stage.function2_index :
8494 current_stage.function1_index;
8495 subroutine_configuration[1] =
8496 (current_stage.default_subroutine2_value == current_stage.function1_index) ?
8497 current_stage.function2_index :
8498 current_stage.function1_index;
8499 subroutine_configuration[2] =
8500 (current_stage.default_subroutine3_value == current_stage.function3_index) ?
8501 current_stage.function4_index :
8502 current_stage.function3_index;
8503 subroutine_configuration[3] =
8504 (current_stage.default_subroutine4_value == current_stage.function3_index) ?
8505 current_stage.function4_index :
8506 current_stage.function3_index;
8507
8508 gl.uniformSubroutinesuiv(current_stage.gl_stage, 4 /* count */, subroutine_configuration);
8509 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniformSubroutinesuiv() call failed.");
8510 } /* for (all stages) */
8511
8512 verifySubroutineUniformValues(static_cast<_test_case>(test_case), n_object_id,
8513 SUBROUTINE_UNIFORMS_SET_TO_NONDEFAULT_VALUES);
8514
8515 /* Execute test case-specific code */
8516 _shader_stage cached_shader_stage_data;
8517 bool stage_reset_status[Utils::SHADER_STAGE_COUNT] = { false, false, false, false, false };
8518 bool uses_stage_reset_status = false;
8519
8520 switch (test_case)
8521 {
8522 case TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT:
8523 {
8524 /* Switch to a different program object and then back to current PO.
8525 * Subroutine uniforms should be back at their default settings, instead of
8526 * the ones we've just set.
8527 */
8528 gl.useProgram(m_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8529 gl.useProgram(m_po_ids[n_object_id]);
8530 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call(s) failed.");
8531
8532 break;
8533 }
8534
8535 case TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_PIPELINE_OBJECT:
8536 {
8537 /* Switch to a different pipeline object and then back to the current one.
8538 * Subroutine uniforms should be back at their default settings, instead of
8539 * the ones we've just set.
8540 */
8541 gl.bindProgramPipeline(
8542 m_pipeline_object_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8543 gl.bindProgramPipeline(m_pipeline_object_ids[n_object_id]);
8544 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call(s) failed.");
8545
8546 break;
8547 }
8548
8549 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_FRAGMENT_STAGE:
8550 {
8551 /* Change the fragment shader stage to a different one.
8552 *
8553 * Note: We also need to update internal descriptor since the subroutine/uniform
8554 * locations may be different between the two programs.
8555 */
8556 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_FRAGMENT_SHADER_BIT,
8557 m_fs_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8558 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8559
8560 cached_shader_stage_data = m_fs_po_descriptors[n_object_id];
8561 m_fs_po_descriptors[n_object_id] = m_fs_po_descriptors[(n_object_id + 1) % 2];
8562
8563 stage_reset_status[Utils::SHADER_STAGE_FRAGMENT] = true;
8564 uses_stage_reset_status = true;
8565
8566 break;
8567 }
8568
8569 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_GEOMETRY_STAGE:
8570 {
8571 /* Change the geometry shader stage to a different one.
8572 *
8573 * Note: We also need to update internal descriptor since the subroutine/uniform
8574 * locations may be different between the two programs.
8575 */
8576 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_GEOMETRY_SHADER_BIT,
8577 m_gs_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8578 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8579
8580 cached_shader_stage_data = m_gs_po_descriptors[n_object_id];
8581 m_gs_po_descriptors[n_object_id] = m_gs_po_descriptors[(n_object_id + 1) % 2];
8582
8583 stage_reset_status[Utils::SHADER_STAGE_GEOMETRY] = true;
8584 uses_stage_reset_status = true;
8585
8586 break;
8587 }
8588
8589 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_TESS_CONTROL_STAGE:
8590 {
8591 /* Change the tessellation control shader stage to a different one.
8592 *
8593 * Note: We also need to update internal descriptor since the subroutine/uniform
8594 * locations may be different between the two programs.
8595 */
8596 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_TESS_CONTROL_SHADER_BIT,
8597 m_tc_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8598 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8599
8600 cached_shader_stage_data = m_tc_po_descriptors[n_object_id];
8601 m_tc_po_descriptors[n_object_id] = m_tc_po_descriptors[(n_object_id + 1) % 2];
8602
8603 stage_reset_status[Utils::SHADER_STAGE_TESSELLATION_CONTROL] = true;
8604 uses_stage_reset_status = true;
8605
8606 break;
8607 }
8608
8609 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_TESS_EVALUATION_STAGE:
8610 {
8611 /* Change the tessellation evaluation shader stage to a different one.
8612 *
8613 * Note: We also need to update internal descriptor since the subroutine/uniform
8614 * locations may be different between the two programs.
8615 */
8616 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_TESS_EVALUATION_SHADER_BIT,
8617 m_te_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8618 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8619
8620 cached_shader_stage_data = m_te_po_descriptors[n_object_id];
8621 m_te_po_descriptors[n_object_id] = m_te_po_descriptors[(n_object_id + 1) % 2];
8622
8623 stage_reset_status[Utils::SHADER_STAGE_TESSELLATION_EVALUATION] = true;
8624 uses_stage_reset_status = true;
8625
8626 break;
8627 }
8628
8629 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_VERTEX_STAGE:
8630 {
8631 /* Change the vertex shader stage to a different one.
8632 *
8633 * Note: We also need to update internal descriptor since the subroutine/uniform
8634 * locations may be different between the two programs.
8635 */
8636 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_VERTEX_SHADER_BIT,
8637 m_vs_po_ids[(n_object_id + 1) % 2 /* objects allocated for the test */]);
8638 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8639
8640 cached_shader_stage_data = m_vs_po_descriptors[n_object_id];
8641 m_vs_po_descriptors[n_object_id] = m_vs_po_descriptors[(n_object_id + 1) % 2];
8642
8643 stage_reset_status[Utils::SHADER_STAGE_VERTEX] = true;
8644 uses_stage_reset_status = true;
8645
8646 break;
8647 }
8648
8649 default:
8650 {
8651 TCU_FAIL("Unrecognized test case");
8652 }
8653 } /* switch (test_case) */
8654
8655 /* Verify the subroutine uniform values are valid */
8656 if (!uses_stage_reset_status)
8657 {
8658 verifySubroutineUniformValues(static_cast<_test_case>(test_case), n_object_id,
8659 SUBROUTINE_UNIFORMS_SET_TO_DEFAULT_VALUES);
8660 }
8661 else
8662 {
8663 const _shader_stage* shader_stages[Utils::SHADER_STAGE_COUNT] = { DE_NULL };
8664
8665 getShaderStages(static_cast<_test_case>(test_case) == TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT,
8666 n_object_id, shader_stages);
8667
8668 for (unsigned int n_shader_stage = 0; n_shader_stage < Utils::SHADER_STAGE_COUNT; ++n_shader_stage)
8669 {
8670 const _shader_stage& current_shader_stage = *(shader_stages[n_shader_stage]);
8671
8672 if (stage_reset_status[n_shader_stage])
8673 {
8674 verifySubroutineUniformValuesForShaderStage(current_shader_stage,
8675 SUBROUTINE_UNIFORMS_SET_TO_DEFAULT_VALUES);
8676 }
8677 else
8678 {
8679 verifySubroutineUniformValuesForShaderStage(current_shader_stage,
8680 SUBROUTINE_UNIFORMS_SET_TO_NONDEFAULT_VALUES);
8681 }
8682 } /* for (all shader stages) */
8683 }
8684
8685 /* Revert the changes some of the test cases appied */
8686 switch (test_case)
8687 {
8688 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_FRAGMENT_STAGE:
8689 {
8690 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_FRAGMENT_SHADER_BIT,
8691 m_fs_po_ids[n_object_id]);
8692 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8693
8694 m_fs_po_descriptors[n_object_id] = cached_shader_stage_data;
8695
8696 break;
8697 }
8698
8699 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_GEOMETRY_STAGE:
8700 {
8701 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_GEOMETRY_SHADER_BIT,
8702 m_gs_po_ids[n_object_id]);
8703 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8704
8705 m_gs_po_descriptors[n_object_id] = cached_shader_stage_data;
8706
8707 break;
8708 }
8709
8710 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_TESS_CONTROL_STAGE:
8711 {
8712 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_TESS_CONTROL_SHADER_BIT,
8713 m_tc_po_ids[n_object_id]);
8714 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8715
8716 m_tc_po_descriptors[n_object_id] = cached_shader_stage_data;
8717
8718 break;
8719 }
8720
8721 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_TESS_EVALUATION_STAGE:
8722 {
8723 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_TESS_EVALUATION_SHADER_BIT,
8724 m_te_po_ids[n_object_id]);
8725 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8726
8727 m_te_po_descriptors[n_object_id] = cached_shader_stage_data;
8728
8729 break;
8730 }
8731
8732 case TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_VERTEX_STAGE:
8733 {
8734 gl.useProgramStages(m_pipeline_object_ids[n_object_id], GL_VERTEX_SHADER_BIT, m_vs_po_ids[n_object_id]);
8735 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call failed.");
8736
8737 m_vs_po_descriptors[n_object_id] = cached_shader_stage_data;
8738
8739 break;
8740 }
8741
8742 default:
8743 break;
8744 } /* switch (test_case) */
8745
8746 } /* for (all program object descriptors) */
8747
8748 /* Unbind the program object */
8749 gl.useProgram(0);
8750 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
8751 } /* for (all test cases) */
8752
8753 if (m_has_test_passed)
8754 {
8755 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
8756 }
8757 else
8758 {
8759 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
8760 }
8761
8762 return STOP;
8763 }
8764
8765 /** Verifies the subroutine uniform values reported by GL implementation. Depending on the test case,
8766 * it will either query program object stages or separate shader objects.
8767 *
8768 * @param test_case Test case the verification is to be performed for.
8769 * @param n_id Index of the program/pipeline object to use for the verification
8770 * @param verification Verification method.
8771 */
verifySubroutineUniformValues(const _test_case & test_case,const unsigned int & n_id,const _subroutine_uniform_value_verification & verification)8772 void FunctionalTest16::verifySubroutineUniformValues(const _test_case& test_case, const unsigned int& n_id,
8773 const _subroutine_uniform_value_verification& verification)
8774 {
8775 const _shader_stage* stages[] = {
8776 DE_NULL, /* fragment shader stage slot */
8777 DE_NULL, /* geometry shader stage slot */
8778 DE_NULL, /* tess control shader stage slot */
8779 DE_NULL, /* tess eval shader stage slot */
8780 DE_NULL /* vertex shader stage slot */
8781 };
8782 const unsigned int n_stages = sizeof(stages) / sizeof(stages[0]);
8783
8784 /* Verify that currently reported subroutine uniform values are equal to default values */
8785 getShaderStages(test_case == TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT, n_id, stages);
8786
8787 for (unsigned int n_stage = 0; n_stage < n_stages; ++n_stage)
8788 {
8789 const _shader_stage& current_stage = *(stages[n_stage]);
8790
8791 verifySubroutineUniformValuesForShaderStage(current_stage, verification);
8792 } /* for (all items) */
8793 }
8794
8795 /** Verifies the subroutine uniform values reported by GL implementation for user-specified
8796 * shader stage. If the verification fails, m_has_test_passed will be set to false.
8797 *
8798 * @param shader_stage Descriptor of a shader stage that should be used for the process.
8799 * @param verification Type of verification that should be performed.
8800 *
8801 **/
verifySubroutineUniformValuesForShaderStage(const _shader_stage & shader_stage,const _subroutine_uniform_value_verification & verification)8802 void FunctionalTest16::verifySubroutineUniformValuesForShaderStage(
8803 const _shader_stage& shader_stage, const _subroutine_uniform_value_verification& verification)
8804 {
8805 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
8806 glw::GLuint result_values[4] = { 0 };
8807
8808 gl.getUniformSubroutineuiv(shader_stage.gl_stage, shader_stage.subroutine1_uniform_location, result_values + 0);
8809 gl.getUniformSubroutineuiv(shader_stage.gl_stage, shader_stage.subroutine2_uniform_location, result_values + 1);
8810 gl.getUniformSubroutineuiv(shader_stage.gl_stage, shader_stage.subroutine3_uniform_location, result_values + 2);
8811 gl.getUniformSubroutineuiv(shader_stage.gl_stage, shader_stage.subroutine4_uniform_location, result_values + 3);
8812 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformSubroutineuiv() call(s) failed.");
8813
8814 if (verification == SUBROUTINE_UNIFORMS_SET_TO_VALID_VALUES)
8815 {
8816 if (!((result_values[0] == (GLuint)shader_stage.subroutine1_uniform_location ||
8817 result_values[0] == (GLuint)shader_stage.subroutine2_uniform_location) &&
8818 (result_values[1] == (GLuint)shader_stage.subroutine1_uniform_location ||
8819 result_values[1] == (GLuint)shader_stage.subroutine2_uniform_location) &&
8820 (result_values[2] == (GLuint)shader_stage.subroutine3_uniform_location ||
8821 result_values[2] == (GLuint)shader_stage.subroutine4_uniform_location) &&
8822 (result_values[3] == (GLuint)shader_stage.subroutine3_uniform_location ||
8823 result_values[3] == (GLuint)shader_stage.subroutine4_uniform_location)))
8824 {
8825 m_testCtx.getLog() << tcu::TestLog::Message << "SUBROUTINE_UNIFORMS_SET_TO_VALID_VALUES validation failed. "
8826 "Shader stage:["
8827 << Utils::getShaderStageStringFromGLEnum(shader_stage.gl_stage) << "], "
8828 "expected data:["
8829 << shader_stage.subroutine1_uniform_location << " OR "
8830 << shader_stage.subroutine2_uniform_location << " x 2, "
8831 << shader_stage.subroutine3_uniform_location << " OR "
8832 << shader_stage.subroutine4_uniform_location << " x 2], "
8833 "found data:["
8834 << result_values[0] << ", " << result_values[1] << ", " << result_values[2] << ", "
8835 << result_values[3] << "]." << tcu::TestLog::EndMessage;
8836
8837 m_has_test_passed = false;
8838 }
8839 }
8840 else if (verification == SUBROUTINE_UNIFORMS_SET_TO_DEFAULT_VALUES)
8841 {
8842 if (result_values[0] != shader_stage.default_subroutine1_value ||
8843 result_values[1] != shader_stage.default_subroutine2_value ||
8844 result_values[2] != shader_stage.default_subroutine3_value ||
8845 result_values[3] != shader_stage.default_subroutine4_value)
8846 {
8847 m_testCtx.getLog() << tcu::TestLog::Message
8848 << "SUBROUTINE_UNIFORMS_SET_TO_DEFAULT_VALUES validation failed. "
8849 "Shader stage:["
8850 << Utils::getShaderStageStringFromGLEnum(shader_stage.gl_stage) << "], "
8851 "expected data:["
8852 << shader_stage.default_subroutine1_value << ", "
8853 << shader_stage.default_subroutine2_value << ", "
8854 << shader_stage.default_subroutine3_value << ", "
8855 << shader_stage.default_subroutine4_value << "], "
8856 "found data:["
8857 << result_values[0] << ", " << result_values[1] << ", " << result_values[2] << ", "
8858 << result_values[3] << "]." << tcu::TestLog::EndMessage;
8859
8860 m_has_test_passed = false;
8861 }
8862 }
8863 else
8864 {
8865 DE_ASSERT(verification == SUBROUTINE_UNIFORMS_SET_TO_NONDEFAULT_VALUES);
8866
8867 if (result_values[0] == shader_stage.default_subroutine1_value ||
8868 result_values[1] == shader_stage.default_subroutine2_value ||
8869 result_values[2] == shader_stage.default_subroutine3_value ||
8870 result_values[3] == shader_stage.default_subroutine4_value)
8871 {
8872 m_testCtx.getLog() << tcu::TestLog::Message
8873 << "SUBROUTINE_UNIFORMS_SET_TO_NONDEFAULT_VALUES validation failed. "
8874 "Shader stage:["
8875 << Utils::getShaderStageStringFromGLEnum(shader_stage.gl_stage) << "], "
8876 "expected data:!["
8877 << shader_stage.default_subroutine1_value << ", "
8878 << shader_stage.default_subroutine2_value << ", "
8879 << shader_stage.default_subroutine3_value << ", "
8880 << shader_stage.default_subroutine4_value << "], "
8881 "found data:["
8882 << result_values[0] << ", " << result_values[1] << ", " << result_values[2] << ", "
8883 << result_values[3] << "]." << tcu::TestLog::EndMessage;
8884
8885 m_has_test_passed = false;
8886 }
8887 }
8888 }
8889
8890 /** Constructor.
8891 *
8892 * @param context Rendering context.
8893 *
8894 **/
FunctionalTest17(deqp::Context & context)8895 FunctionalTest17::FunctionalTest17(deqp::Context& context)
8896 : TestCase(context, "same_subroutine_and_subroutine_uniform_but_different_type_used_in_all_stages",
8897 "Creates a program which uses the same subroutine and subroutine uniform "
8898 "names for every stage (types of subroutines are different in each stage) "
8899 "and then makes sure that such program compiles and works as expected.")
8900 , m_fbo_id(0)
8901 , m_fs_id(0)
8902 , m_gs_id(0)
8903 , m_has_test_passed(true)
8904 , m_po_id(0)
8905 , m_tc_id(0)
8906 , m_te_id(0)
8907 , m_to_data(DE_NULL)
8908 , m_to_height(4) /* arbitrary value */
8909 , m_to_id(0)
8910 , m_to_width(4) /* arbitrary value */
8911 , m_vao_id(0)
8912 , m_vs_id(0)
8913 {
8914 /* Left blank intentionally */
8915 }
8916
8917 /** Deinitializes all GL objects that may have been created during test execution. */
deinit()8918 void FunctionalTest17::deinit()
8919 {
8920 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
8921
8922 if (m_fbo_id != 0)
8923 {
8924 gl.deleteFramebuffers(1, &m_fbo_id);
8925
8926 m_fbo_id = 0;
8927 }
8928
8929 if (m_fs_id != 0)
8930 {
8931 gl.deleteShader(m_fs_id);
8932
8933 m_fs_id = 0;
8934 }
8935
8936 if (m_gs_id != 0)
8937 {
8938 gl.deleteShader(m_gs_id);
8939
8940 m_gs_id = 0;
8941 }
8942
8943 if (m_po_id != 0)
8944 {
8945 gl.deleteProgram(m_po_id);
8946
8947 m_po_id = 0;
8948 }
8949
8950 if (m_tc_id != 0)
8951 {
8952 gl.deleteShader(m_tc_id);
8953
8954 m_tc_id = 0;
8955 }
8956
8957 if (m_te_id != 0)
8958 {
8959 gl.deleteShader(m_te_id);
8960
8961 m_te_id = 0;
8962 }
8963
8964 if (m_to_data != DE_NULL)
8965 {
8966 delete[] m_to_data;
8967
8968 m_to_data = DE_NULL;
8969 }
8970
8971 if (m_to_id != 0)
8972 {
8973 gl.deleteTextures(1, &m_to_id);
8974
8975 m_to_id = 0;
8976 }
8977
8978 if (m_vao_id != 0)
8979 {
8980 gl.deleteVertexArrays(1, &m_vao_id);
8981
8982 m_vao_id = 0;
8983 }
8984
8985 if (m_vs_id != 0)
8986 {
8987 gl.deleteShader(m_vs_id);
8988
8989 m_vs_id = 0;
8990 }
8991
8992 /* Restore original GL configuration */
8993 gl.patchParameteri(GL_PATCH_VERTICES, 3);
8994 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteri() call failed.");
8995
8996 gl.pixelStorei(GL_PACK_ALIGNMENT, 4);
8997 GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call failed.");
8998 }
8999
9000 /** Retrieves body of a fragment shader that should be used by the test program.
9001 *
9002 * @return Requested string.
9003 **/
getFragmentShaderBody() const9004 std::string FunctionalTest17::getFragmentShaderBody() const
9005 {
9006 return "#version 400\n"
9007 "\n"
9008 "#extension GL_ARB_shader_subroutine : require\n"
9009 "\n"
9010 "in GS_DATA\n"
9011 "{\n"
9012 " vec4 gs_data;\n"
9013 " vec4 tc_data;\n"
9014 " vec4 te_data;\n"
9015 " vec4 vs_data;\n"
9016 "} gs;\n"
9017 "\n"
9018 "out vec4 result;\n"
9019 "\n"
9020 "subroutine void subroutineTypeFS(out vec4 result);\n"
9021 "\n"
9022 "subroutine(subroutineTypeFS) void subroutine1(out vec4 result)\n"
9023 "{\n"
9024 " result = vec4(5, 6, 7, 8);\n"
9025 "}\n"
9026 "\n"
9027 "subroutine uniform subroutineTypeFS function;\n"
9028 "\n"
9029 "void main()\n"
9030 "{\n"
9031 " vec4 fs_data;\n"
9032 "\n"
9033 " function(fs_data);\n"
9034 " result = gs.gs_data + gs.tc_data + gs.te_data + gs.vs_data + fs_data;\n"
9035 "}\n";
9036 }
9037
9038 /** Retrieves body of a geometry shader that should be used by the test program.
9039 *
9040 * @return Requested string.
9041 **/
getGeometryShaderBody() const9042 std::string FunctionalTest17::getGeometryShaderBody() const
9043 {
9044 return "#version 400\n"
9045 "\n"
9046 "#extension GL_ARB_shader_subroutine : require\n"
9047 "\n"
9048 "layout(points) in;\n"
9049 "layout(triangle_strip, max_vertices = 4) out;\n"
9050 "\n"
9051 "subroutine void subroutineTypeGS(out vec4 result);\n"
9052 "\n"
9053 "subroutine(subroutineTypeGS) void subroutine1(out vec4 result)\n"
9054 "{\n"
9055 " result = vec4(4, 5, 6, 7);\n"
9056 "}\n"
9057 "\n"
9058 "subroutine uniform subroutineTypeGS function;\n"
9059 "\n"
9060 "in TE_DATA\n"
9061 "{\n"
9062 " vec4 tc_data;\n"
9063 " vec4 te_data;\n"
9064 " vec4 vs_data;\n"
9065 "} te[];\n"
9066 "\n"
9067 "out GS_DATA\n"
9068 "{\n"
9069 " vec4 gs_data;\n"
9070 " vec4 tc_data;\n"
9071 " vec4 te_data;\n"
9072 " vec4 vs_data;\n"
9073 "} result;\n"
9074 "\n"
9075 "void main()\n"
9076 "{\n"
9077 " function(result.gs_data);\n"
9078 " gl_Position = vec4(1, -1, 0, 1);\n"
9079 " result.tc_data = te[0].tc_data;\n"
9080 " result.te_data = te[0].te_data;\n"
9081 " result.vs_data = te[0].vs_data;\n"
9082 " EmitVertex();\n"
9083 "\n"
9084 " function(result.gs_data);\n"
9085 " gl_Position = vec4(-1, -1, 0, 1);\n"
9086 " result.tc_data = te[0].tc_data;\n"
9087 " result.te_data = te[0].te_data;\n"
9088 " result.vs_data = te[0].vs_data;\n"
9089 " EmitVertex();\n"
9090 "\n"
9091 " function(result.gs_data);\n"
9092 " gl_Position = vec4(1, 1, 0, 1);\n"
9093 " result.tc_data = te[0].tc_data;\n"
9094 " result.te_data = te[0].te_data;\n"
9095 " result.vs_data = te[0].vs_data;\n"
9096 " EmitVertex();\n"
9097 "\n"
9098 " function(result.gs_data);\n"
9099 " gl_Position = vec4(-1, 1, 0, 1);\n"
9100 " result.tc_data = te[0].tc_data;\n"
9101 " result.te_data = te[0].te_data;\n"
9102 " result.vs_data = te[0].vs_data;\n"
9103 " EmitVertex();\n"
9104 " EndPrimitive();\n"
9105 "}\n";
9106 }
9107
9108 /** Retrieves body of a tessellation control shader that should be used by the test program.
9109 *
9110 * @return Requested string.
9111 **/
getTessellationControlShaderBody() const9112 std::string FunctionalTest17::getTessellationControlShaderBody() const
9113 {
9114 return "#version 400\n"
9115 "\n"
9116 "#extension GL_ARB_shader_subroutine : require\n"
9117 "\n"
9118 "layout (vertices = 4) out;\n"
9119 "\n"
9120 "subroutine void subroutineTypeTC(out vec4 result);\n"
9121 "\n"
9122 "subroutine(subroutineTypeTC) void subroutine1(out vec4 result)\n"
9123 "{\n"
9124 " result = vec4(2, 3, 4, 5);\n"
9125 "}\n"
9126 "\n"
9127 "subroutine uniform subroutineTypeTC function;\n"
9128 "\n"
9129 "in VS_DATA\n"
9130 "{\n"
9131 " vec4 vs_data;\n"
9132 "} vs[];\n"
9133 "\n"
9134 "out TC_DATA\n"
9135 "{\n"
9136 " vec4 tc_data;\n"
9137 " vec4 vs_data;\n"
9138 "} result[];\n"
9139 "\n"
9140 "void main()\n"
9141 "{\n"
9142 " gl_TessLevelInner[0] = 1.0;\n"
9143 " gl_TessLevelInner[1] = 1.0;\n"
9144 " gl_TessLevelOuter[0] = 1.0;\n"
9145 " gl_TessLevelOuter[1] = 1.0;\n"
9146 " gl_TessLevelOuter[2] = 1.0;\n"
9147 " gl_TessLevelOuter[3] = 1.0;\n"
9148 "\n"
9149 " function(result[gl_InvocationID].tc_data);\n"
9150 " result[gl_InvocationID].vs_data = vs[gl_InvocationID].vs_data;\n"
9151 "}\n";
9152 }
9153
9154 /** Retrieves body of a tessellation evaluation shader that should be used
9155 * by the test program.
9156 *
9157 * @return Requested string.
9158 **/
getTessellationEvaluationShaderBody() const9159 std::string FunctionalTest17::getTessellationEvaluationShaderBody() const
9160 {
9161 return "#version 400\n"
9162 "\n"
9163 "#extension GL_ARB_shader_subroutine : require\n"
9164 "\n"
9165 "layout (quads, point_mode) in;\n"
9166 "\n"
9167 "subroutine void subroutineTypeTE(out vec4 result);\n"
9168 "\n"
9169 "subroutine(subroutineTypeTE) void subroutine1(out vec4 result)\n"
9170 "{\n"
9171 " result = vec4(3, 4, 5, 6);\n"
9172 "}\n"
9173 "\n"
9174 "subroutine uniform subroutineTypeTE function;\n"
9175 "\n"
9176 "in TC_DATA\n"
9177 "{\n"
9178 " vec4 tc_data;\n"
9179 " vec4 vs_data;\n"
9180 "} tc[];\n"
9181 "\n"
9182 "out TE_DATA\n"
9183 "{\n"
9184 " vec4 tc_data;\n"
9185 " vec4 te_data;\n"
9186 " vec4 vs_data;\n"
9187 "} result;\n"
9188 "\n"
9189 "void main()\n"
9190 "{\n"
9191 " result.vs_data = tc[0].vs_data;\n"
9192 " result.tc_data = tc[0].tc_data;\n"
9193 " function(result.te_data);\n"
9194 "}\n";
9195 }
9196
9197 /** Retrieves body of a vertex shader that should be used by the test program.
9198 *
9199 * @return Requested string.
9200 **/
getVertexShaderBody() const9201 std::string FunctionalTest17::getVertexShaderBody() const
9202 {
9203 return "#version 400\n"
9204 "\n"
9205 "#extension GL_ARB_shader_subroutine : require\n"
9206 "\n"
9207 "out VS_DATA\n"
9208 "{\n"
9209 " vec4 vs_data;\n"
9210 "} result;\n"
9211 "\n"
9212 "subroutine void subroutineTypeVS(out vec4 result);\n"
9213 "\n"
9214 "subroutine(subroutineTypeVS) void subroutine1(out vec4 result)\n"
9215 "{\n"
9216 " result = vec4(1, 2, 3, 4);\n"
9217 "}\n"
9218 "\n"
9219 "subroutine uniform subroutineTypeVS function;\n"
9220 "\n"
9221 "void main()\n"
9222 "{\n"
9223 " function(result.vs_data);\n"
9224 "}\n";
9225 }
9226
9227 /** Initializes all buffers and GL objects required to run the test. */
initTest()9228 void FunctionalTest17::initTest()
9229 {
9230 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
9231
9232 /* Configure GL_PATCH_VERTICES so that TC only takes a single patch vertex */
9233 gl.patchParameteri(GL_PATCH_VERTICES, 1);
9234 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteri() call failed.");
9235
9236 /* Generate & bind a VAO */
9237 gl.genVertexArrays(1, &m_vao_id);
9238 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
9239
9240 gl.bindVertexArray(m_vao_id);
9241 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
9242
9243 /* Set up test program object */
9244 std::string fs_body = getFragmentShaderBody();
9245 std::string gs_body = getGeometryShaderBody();
9246 std::string tc_body = getTessellationControlShaderBody();
9247 std::string te_body = getTessellationEvaluationShaderBody();
9248 std::string vs_body = getVertexShaderBody();
9249
9250 if (!Utils::buildProgram(gl, vs_body, tc_body, te_body, gs_body, fs_body, DE_NULL, /* xfb_varyings */
9251 DE_NULL, /* n_xfb_varyings */
9252 &m_vs_id, &m_tc_id, &m_te_id, &m_gs_id, &m_fs_id, &m_po_id))
9253 {
9254 TCU_FAIL("Failed to link test program object");
9255 }
9256
9257 /* Set up a texture object that will be used as a color attachment */
9258 gl.genTextures(1, &m_to_id);
9259 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed.");
9260
9261 gl.bindTexture(GL_TEXTURE_2D, m_to_id);
9262 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
9263
9264 gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
9265 GL_RGBA32F, m_to_width, m_to_height);
9266 GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed.");
9267
9268 /* Set up FBO */
9269 gl.genFramebuffers(1, &m_fbo_id);
9270 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed.");
9271
9272 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
9273 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call failed.");
9274
9275 gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0 /* level */);
9276 GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
9277
9278 /* Make sure glReadPixels() does not return misaligned data */
9279 gl.pixelStorei(GL_PACK_ALIGNMENT, 1);
9280 GLU_EXPECT_NO_ERROR(gl.getError(), "glPixelStorei() call failed.");
9281
9282 /* Initialize a buffer that will be used to store rendered data */
9283 m_to_data = new float[m_to_width * m_to_height * 4 /* rgba */];
9284 }
9285
9286 /** Executes test iteration.
9287 *
9288 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
9289 */
iterate()9290 tcu::TestNode::IterateResult FunctionalTest17::iterate()
9291 {
9292 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
9293
9294 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
9295 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
9296 {
9297 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
9298 }
9299
9300 initTest();
9301
9302 /* Use the test program to render a full-screen test quad */
9303 gl.useProgram(m_po_id);
9304 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
9305
9306 gl.drawArrays(GL_PATCHES, 0 /* first */, 1 /* count */);
9307 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
9308
9309 /* Read back the data that was rendered */
9310 gl.readPixels(0, /* x */
9311 0, /* y */
9312 m_to_width, m_to_height, GL_RGBA, GL_FLOAT, m_to_data);
9313 GLU_EXPECT_NO_ERROR(gl.getError(), "glReaDPixels() call failed.");
9314
9315 /* Verify the data */
9316 verifyRenderedData();
9317
9318 /** All done */
9319 if (m_has_test_passed)
9320 {
9321 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
9322 }
9323 else
9324 {
9325 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
9326 }
9327
9328 return STOP;
9329 }
9330
9331 /** Verifies the data that have been rendered by the test program.
9332 *
9333 * It is assumed the rendered data have already been copied to
9334 * m_to_data.
9335 *
9336 * If the rendered data is found to be invalid, m_has_test_passed
9337 * will be set to false.
9338 **/
verifyRenderedData()9339 void FunctionalTest17::verifyRenderedData()
9340 {
9341 const float epsilon = 1e-5f;
9342 const float expected_data[4] = { 15.0f, 20.0f, 25.0f, 30.0f };
9343
9344 for (unsigned int y = 0; y < m_to_height && m_has_test_passed; ++y)
9345 {
9346 const float* row_ptr = m_to_data + y * 4 /* rgba */ * m_to_width;
9347
9348 for (unsigned int x = 0; x < m_to_width && m_has_test_passed; ++x)
9349 {
9350 const float* pixel_ptr = row_ptr + 4 /* rgba */ * x;
9351
9352 if (de::abs(pixel_ptr[0] - expected_data[0]) > epsilon ||
9353 de::abs(pixel_ptr[1] - expected_data[1]) > epsilon ||
9354 de::abs(pixel_ptr[2] - expected_data[2]) > epsilon ||
9355 de::abs(pixel_ptr[3] - expected_data[3]) > epsilon)
9356 {
9357 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid texel found at (" << x << ", " << y
9358 << "): "
9359 "expected:("
9360 << expected_data[0] << ", " << expected_data[1] << ", " << expected_data[2] << ", "
9361 << expected_data[3] << "), found:(" << pixel_ptr[0] << ", " << pixel_ptr[1] << ", "
9362 << pixel_ptr[2] << ", " << pixel_ptr[3] << ")." << tcu::TestLog::EndMessage;
9363
9364 m_has_test_passed = false;
9365 }
9366 } /* for (all columns) */
9367 } /* for (all rows) */
9368 }
9369
9370 /** Constructor.
9371 *
9372 * @param context Rendering context.
9373 *
9374 **/
FunctionalTest18_19(deqp::Context & context)9375 FunctionalTest18_19::FunctionalTest18_19(deqp::Context& context)
9376 : TestCase(context, "control_flow_and_returned_subroutine_values_used_as_subroutine_input",
9377 "Makes sure that calling a subroutine with argument value returned by "
9378 "another subroutine works correctly. Also checks that subroutine and "
9379 "subroutine uniforms work as expected when used in connection with control "
9380 "flow functions.")
9381 , m_has_test_passed(true)
9382 , m_n_points_to_draw(16) /* arbitrary value */
9383 , m_po_id(0)
9384 , m_po_subroutine_divide_by_two_location(GL_INVALID_INDEX)
9385 , m_po_subroutine_multiply_by_four_location(GL_INVALID_INDEX)
9386 , m_po_subroutine_returns_false_location(GL_INVALID_INDEX)
9387 , m_po_subroutine_returns_true_location(GL_INVALID_INDEX)
9388 , m_po_subroutine_uniform_bool_operator1(-1)
9389 , m_po_subroutine_uniform_bool_operator2(-1)
9390 , m_po_subroutine_uniform_vec4_processor1(-1)
9391 , m_po_subroutine_uniform_vec4_processor2(-1)
9392 , m_xfb_bo_id(0)
9393 , m_vao_id(0)
9394 , m_vs_id(0)
9395 {
9396 /* Left blank intentionally */
9397 }
9398
9399 /** De-initializes all GL objects that may have been created during test execution */
deinit()9400 void FunctionalTest18_19::deinit()
9401 {
9402 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
9403
9404 if (m_po_id != 0)
9405 {
9406 gl.deleteProgram(m_po_id);
9407
9408 m_po_id = 0;
9409 }
9410
9411 if (m_vao_id != 0)
9412 {
9413 gl.deleteVertexArrays(1, &m_vao_id);
9414
9415 m_vao_id = 0;
9416 }
9417
9418 if (m_vs_id != 0)
9419 {
9420 gl.deleteShader(m_vs_id);
9421
9422 m_vs_id = 0;
9423 }
9424
9425 if (m_xfb_bo_id != 0)
9426 {
9427 gl.deleteBuffers(1, &m_xfb_bo_id);
9428
9429 m_xfb_bo_id = 0;
9430 }
9431 }
9432
9433 /** Executes a single test iteration using user-specified properties. If the
9434 * iterations fails, m_has_test_passed is set to false.
9435 *
9436 * @param bool_operator1_subroutine_location Location of a subroutine to be assigned to
9437 * bool_operator1 subroutine uniform.
9438 * @param bool_operator2_subroutine_location Location of a subroutine to be assigned to
9439 * bool_operator2 subroutine uniform.
9440 * @param vec4_operator1_subroutine_location Location of a subroutine to be assigned to
9441 * vec4_operator1 subroutine uniform.
9442 * @param vec4_operator2_subroutine_location Location of a subroutine to be assigned to
9443 * vec4_operator2 subroutine uniform.
9444 &**/
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)9445 void FunctionalTest18_19::executeTest(glw::GLuint bool_operator1_subroutine_location,
9446 glw::GLuint bool_operator2_subroutine_location,
9447 glw::GLuint vec4_operator1_subroutine_location,
9448 glw::GLuint vec4_operator2_subroutine_location)
9449 {
9450 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
9451
9452 /* Set up subroutines */
9453 glw::GLuint subroutine_configuration[4 /* total number of subroutines */] = { 0 };
9454
9455 subroutine_configuration[m_po_subroutine_uniform_bool_operator1] = bool_operator1_subroutine_location;
9456 subroutine_configuration[m_po_subroutine_uniform_bool_operator2] = bool_operator2_subroutine_location;
9457 subroutine_configuration[m_po_subroutine_uniform_vec4_processor1] = vec4_operator1_subroutine_location;
9458 subroutine_configuration[m_po_subroutine_uniform_vec4_processor2] = vec4_operator2_subroutine_location;
9459
9460 gl.useProgram(m_po_id);
9461 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
9462
9463 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, 4 /* count */, subroutine_configuration);
9464 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniformSubroutinesuiv() call failed");
9465
9466 /* Draw test-specific number of points */
9467 gl.beginTransformFeedback(GL_POINTS);
9468 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed");
9469 {
9470 gl.drawArrays(GL_POINTS, 0 /* first */, m_n_points_to_draw);
9471 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed");
9472 }
9473 gl.endTransformFeedback();
9474 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed");
9475
9476 /* Map the BO storage into process space */
9477 const glw::GLvoid* xfb_data_ptr = gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
9478 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer() call failed.");
9479
9480 verifyXFBData(xfb_data_ptr, bool_operator1_subroutine_location, bool_operator2_subroutine_location,
9481 vec4_operator1_subroutine_location, vec4_operator2_subroutine_location);
9482
9483 /* Unmap BO storage */
9484 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
9485 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
9486 }
9487
9488 /** Retrieves body of a vertex shader to be used by the test. */
getVertexShaderBody() const9489 std::string FunctionalTest18_19::getVertexShaderBody() const
9490 {
9491 return "#version 400\n"
9492 "\n"
9493 "subroutine bool bool_processor();\n"
9494 "subroutine vec4 vec4_processor(in vec4 iparam);\n"
9495 "\n"
9496 "subroutine(bool_processor) bool returnsFalse()\n"
9497 "{\n"
9498 " return false;\n"
9499 "}\n"
9500 "\n"
9501 "subroutine(bool_processor) bool returnsTrue()\n"
9502 "{\n"
9503 " return true;\n"
9504 "}\n"
9505 "\n"
9506 "subroutine(vec4_processor) vec4 divideByTwo(in vec4 iparam)\n"
9507 "{\n"
9508 " return iparam * vec4(0.5);\n"
9509 "}\n"
9510 "\n"
9511 "subroutine(vec4_processor) vec4 multiplyByFour(in vec4 iparam)\n"
9512 "{\n"
9513 " return iparam * vec4(4.0);\n"
9514 "}\n"
9515 "\n"
9516 "subroutine uniform bool_processor bool_operator1;\n"
9517 "subroutine uniform bool_processor bool_operator2;\n"
9518 "subroutine uniform vec4_processor vec4_operator1;\n"
9519 "subroutine uniform vec4_processor vec4_operator2;\n"
9520 "\n"
9521 "out float result;\n"
9522 "\n"
9523 "void main()\n"
9524 "{\n"
9525 " if (bool_operator1() )\n"
9526 " {\n"
9527 " float value = float( (3 * gl_VertexID + 1) * 2);\n"
9528 "\n"
9529 " while (bool_operator1() )\n"
9530 " {\n"
9531 " value /= float(gl_VertexID + 2);\n"
9532 "\n"
9533 " if (value <= 1.0f) break;\n"
9534 " }\n"
9535 "\n"
9536 " result = value;\n"
9537 " }\n"
9538 " else\n"
9539 " {\n"
9540 " vec4 value = vec4(gl_VertexID, gl_VertexID + 1,\n"
9541 " gl_VertexID + 2, gl_VertexID + 3);\n"
9542 "\n"
9543 " switch (gl_VertexID % 2)\n"
9544 " {\n"
9545 " case 0:\n"
9546 " {\n"
9547 " for (int iteration = 0; iteration < gl_VertexID && bool_operator2(); ++iteration)\n"
9548 " {\n"
9549 " value = vec4_operator2(vec4_operator1(value));\n"
9550 " }\n"
9551 "\n"
9552 " break;\n"
9553 " }\n"
9554 "\n"
9555 " case 1:\n"
9556 " {\n"
9557 " for (int iteration = 0; iteration < gl_VertexID * 2; ++iteration)\n"
9558 " {\n"
9559 " value = vec4_operator1(vec4_operator2(value));\n"
9560 " }\n"
9561 "\n"
9562 " break;\n"
9563 " }\n"
9564 " }\n"
9565 "\n"
9566 " result = value.x + value.y + value.z + value.w;\n"
9567 "\n"
9568 " }\n"
9569 "}\n";
9570 }
9571
9572 /** Initializes all GL objects required to run the test. */
initTest()9573 void FunctionalTest18_19::initTest()
9574 {
9575 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
9576 const char* varyings[1] = { "result" };
9577 std::string vs_body = getVertexShaderBody();
9578 const unsigned int n_varyings = sizeof(varyings) / sizeof(varyings[0]);
9579
9580 if (!Utils::buildProgram(gl, vs_body, "", /* tc_body */
9581 "", /* te_body */
9582 "", /* gs_body */
9583 "", /* fs_body */
9584 varyings, n_varyings, &m_vs_id, DE_NULL, /* out_tc_id */
9585 DE_NULL, /* out_te_id */
9586 DE_NULL, /* out_gs_id */
9587 DE_NULL, /* out_fs_id */
9588 &m_po_id))
9589 {
9590 TCU_FAIL("Failed to build test program object");
9591 }
9592
9593 /* Retrieve subroutine & subroutine uniform locations */
9594 m_po_subroutine_divide_by_two_location = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "divideByTwo");
9595 m_po_subroutine_multiply_by_four_location = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "multiplyByFour");
9596 m_po_subroutine_returns_false_location = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "returnsFalse");
9597 m_po_subroutine_returns_true_location = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "returnsTrue");
9598 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineIndex() call(s) failed");
9599
9600 if (m_po_subroutine_divide_by_two_location == GL_INVALID_INDEX ||
9601 m_po_subroutine_multiply_by_four_location == GL_INVALID_INDEX ||
9602 m_po_subroutine_returns_false_location == GL_INVALID_INDEX ||
9603 m_po_subroutine_returns_true_location == GL_INVALID_INDEX)
9604 {
9605 TCU_FAIL("glGetSubroutineIndex() returned GL_INVALID_INDEX for a valid subroutine");
9606 }
9607
9608 m_po_subroutine_uniform_bool_operator1 =
9609 gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "bool_operator1");
9610 m_po_subroutine_uniform_bool_operator2 =
9611 gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "bool_operator2");
9612 m_po_subroutine_uniform_vec4_processor1 =
9613 gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "vec4_operator1");
9614 m_po_subroutine_uniform_vec4_processor2 =
9615 gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "vec4_operator2");
9616 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineUniformLocation() call(s) failed");
9617
9618 if (m_po_subroutine_uniform_bool_operator1 == -1 || m_po_subroutine_uniform_bool_operator2 == -1 ||
9619 m_po_subroutine_uniform_vec4_processor1 == -1 || m_po_subroutine_uniform_vec4_processor2 == -1)
9620 {
9621 TCU_FAIL("glGetSubroutineUniformLocation() returned -1 for an active subroutine uniform");
9622 }
9623
9624 /* Set up XFB BO */
9625 const unsigned int bo_size = static_cast<unsigned int>(sizeof(float) * m_n_points_to_draw);
9626
9627 gl.genBuffers(1, &m_xfb_bo_id);
9628 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
9629
9630 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_xfb_bo_id);
9631 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
9632
9633 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_xfb_bo_id);
9634 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed.");
9635
9636 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, DE_NULL /* data */, GL_STATIC_COPY);
9637 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
9638
9639 /* Set up a VAO */
9640 gl.genVertexArrays(1, &m_vao_id);
9641 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
9642
9643 gl.bindVertexArray(m_vao_id);
9644 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
9645 }
9646
9647 /** Executes test iteration.
9648 *
9649 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
9650 */
iterate()9651 tcu::TestNode::IterateResult FunctionalTest18_19::iterate()
9652 {
9653 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
9654 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
9655 {
9656 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
9657 }
9658
9659 /* Initialize all GL objects required to run the test */
9660 initTest();
9661
9662 /* Iterate over all subroutine permutations */
9663 const glw::GLuint subroutine_bool_operators[] = { m_po_subroutine_returns_false_location,
9664 m_po_subroutine_returns_true_location };
9665 const unsigned int n_subroutine_bool_operators =
9666 sizeof(subroutine_bool_operators) / sizeof(subroutine_bool_operators[0]);
9667
9668 const glw::GLuint subroutine_vec4_operators[] = { m_po_subroutine_divide_by_two_location,
9669 m_po_subroutine_multiply_by_four_location };
9670 const unsigned int n_subroutine_vec4_operators =
9671 sizeof(subroutine_vec4_operators) / sizeof(subroutine_vec4_operators[0]);
9672
9673 for (unsigned int n_subroutine_uniform_bool_operator1 = 0;
9674 n_subroutine_uniform_bool_operator1 < n_subroutine_bool_operators; ++n_subroutine_uniform_bool_operator1)
9675 {
9676 for (unsigned int n_subroutine_uniform_bool_operator2 = 0;
9677 n_subroutine_uniform_bool_operator2 < n_subroutine_bool_operators; ++n_subroutine_uniform_bool_operator2)
9678 {
9679 for (unsigned int n_subroutine_uniform_vec4_operator1 = 0;
9680 n_subroutine_uniform_vec4_operator1 < n_subroutine_vec4_operators;
9681 ++n_subroutine_uniform_vec4_operator1)
9682 {
9683 for (unsigned int n_subroutine_uniform_vec4_operator2 = 0;
9684 n_subroutine_uniform_vec4_operator2 < n_subroutine_vec4_operators;
9685 ++n_subroutine_uniform_vec4_operator2)
9686 {
9687 executeTest(subroutine_bool_operators[n_subroutine_uniform_bool_operator1],
9688 subroutine_bool_operators[n_subroutine_uniform_bool_operator2],
9689 subroutine_vec4_operators[n_subroutine_uniform_vec4_operator1],
9690 subroutine_vec4_operators[n_subroutine_uniform_vec4_operator2]);
9691 } /* for (all subroutine vec4 operator subroutines used for processor2) */
9692 } /* for (all subroutine vec4 operator subroutines used for processor1) */
9693 } /* for (all subroutine bool operator subroutines used for operator2) */
9694 } /* for (all subroutine bool operator subroutines used for operator1) */
9695
9696 /* All done */
9697 if (m_has_test_passed)
9698 {
9699 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
9700 }
9701 else
9702 {
9703 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
9704 }
9705
9706 return STOP;
9707 }
9708
9709 /** Divides input argument by two. The result value is returned to the
9710 * caller.
9711 *
9712 * @param data Input value.
9713 *
9714 * @return As per description.
9715 **/
vec4operator_div2(tcu::Vec4 data)9716 tcu::Vec4 FunctionalTest18_19::vec4operator_div2(tcu::Vec4 data)
9717 {
9718 return data * 0.5f;
9719 }
9720
9721 /** Multiplies input argument by four. The result value is returned to the
9722 * caller.
9723 *
9724 * @param data Input value.
9725 *
9726 * @return As per description.
9727 **/
vec4operator_mul4(tcu::Vec4 data)9728 tcu::Vec4 FunctionalTest18_19::vec4operator_mul4(tcu::Vec4 data)
9729 {
9730 return data * 4.0f;
9731 }
9732
9733 /** Verifies data XFBed out by the vertex shader. It is assumed the subroutines were configured
9734 * as per passed arguments, prior to the draw call.
9735 *
9736 * If the result data is found to be invalid, m_has_test_passed is set to false.
9737 *
9738 * @param data XFBed data.
9739 * @param bool_operator1_subroutine_location Location of a subroutine to be assigned to
9740 * bool_operator1 subroutine uniform.
9741 * @param bool_operator2_subroutine_location Location of a subroutine to be assigned to
9742 * bool_operator2 subroutine uniform.
9743 * @param vec4_operator1_subroutine_location Location of a subroutine to be assigned to
9744 * vec4_operator1 subroutine uniform.
9745 * @param vec4_operator2_subroutine_location Location of a subroutine to be assigned to
9746 * vec4_operator2 subroutine uniform.
9747 */
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)9748 void FunctionalTest18_19::verifyXFBData(const glw::GLvoid* data, glw::GLuint bool_operator1_subroutine_location,
9749 glw::GLuint bool_operator2_subroutine_location,
9750 glw::GLuint vec4_operator1_subroutine_location,
9751 glw::GLuint vec4_operator2_subroutine_location)
9752 {
9753 bool bool_operator1_result = false;
9754 bool bool_operator2_result = false;
9755 const float epsilon = 1e-5f;
9756 PFNVEC4OPERATORPROC pVec4Operator1 = NULL;
9757 PFNVEC4OPERATORPROC pVec4Operator2 = NULL;
9758 const glw::GLfloat* traveller_ptr = (const glw::GLfloat*)data;
9759
9760 bool_operator1_result = (bool_operator1_subroutine_location == m_po_subroutine_returns_true_location);
9761 bool_operator2_result = (bool_operator2_subroutine_location == m_po_subroutine_returns_true_location);
9762 pVec4Operator1 = (vec4_operator1_subroutine_location == m_po_subroutine_divide_by_two_location) ?
9763 vec4operator_div2 :
9764 vec4operator_mul4;
9765 pVec4Operator2 = (vec4_operator2_subroutine_location == m_po_subroutine_divide_by_two_location) ?
9766 vec4operator_div2 :
9767 vec4operator_mul4;
9768
9769 for (unsigned int n_vertex = 0; n_vertex < m_n_points_to_draw; ++n_vertex)
9770 {
9771 float expected_value = 0.0f;
9772
9773 if (bool_operator1_result)
9774 {
9775 float value = float((3 * n_vertex + 1) * 2);
9776
9777 while (bool_operator1_result)
9778 {
9779 value /= float(n_vertex + 2);
9780
9781 if (value <= 1.0f)
9782 break;
9783 }
9784
9785 expected_value = value;
9786 }
9787 else
9788 {
9789 tcu::Vec4 value((float)n_vertex, (float)n_vertex + 1, (float)n_vertex + 2, (float)n_vertex + 3);
9790
9791 switch (n_vertex % 2)
9792 {
9793 case 0:
9794 {
9795 for (unsigned int iteration = 0; iteration < n_vertex && bool_operator2_result; ++iteration)
9796 {
9797 value = pVec4Operator2(pVec4Operator1(value));
9798 }
9799
9800 break;
9801 }
9802
9803 case 1:
9804 {
9805 for (unsigned int iteration = 0; iteration < n_vertex * 2; ++iteration)
9806 {
9807 value = pVec4Operator1(pVec4Operator2(value));
9808 }
9809
9810 break;
9811 }
9812 } /* switch (n_vertex % 2) */
9813
9814 expected_value = value.x() + value.y() + value.z() + value.w();
9815 }
9816
9817 if (de::abs(expected_value - *traveller_ptr) > epsilon)
9818 {
9819 m_testCtx.getLog() << tcu::TestLog::Message << "XFBed data was found to be invalid at index [" << n_vertex
9820 << "]"
9821 "for the following subroutine location configuration:"
9822 " bool_operator1_subroutine_location:["
9823 << bool_operator1_subroutine_location << "]"
9824 " bool_operator2_subroutine_location:["
9825 << bool_operator2_subroutine_location << "]"
9826 " vec4_operator1_subroutine_location:["
9827 << vec4_operator1_subroutine_location << "]"
9828 " vec4_operator2_subroutine_location:["
9829 << vec4_operator2_subroutine_location << "];"
9830 " expected data:"
9831 << expected_value << ", found:" << *traveller_ptr << tcu::TestLog::EndMessage;
9832
9833 m_has_test_passed = false;
9834 }
9835
9836 ++traveller_ptr;
9837 } /* for (all drawn points) */
9838 }
9839
9840 /** Constructor.
9841 *
9842 * @param context Rendering context.
9843 *
9844 **/
NegativeTest1(deqp::Context & context)9845 NegativeTest1::NegativeTest1(deqp::Context& context)
9846 : TestCase(context, "subroutine_errors", "Verifies all GL_INVALID_OPERATION, GL_INVALID_VALUE, GL_INVALID ENUM "
9847 "errors related to subroutine usage are properly generated.")
9848 , m_has_test_passed(true)
9849 , m_po_active_subroutine_uniform_locations(0)
9850 , m_po_active_subroutine_uniforms(0)
9851 , m_po_active_subroutines(0)
9852 , m_po_subroutine_uniform_function_index(-1)
9853 , m_po_subroutine_uniform_function2_index(-1)
9854 , m_po_subroutine_test1_index(GL_INVALID_INDEX)
9855 , m_po_subroutine_test2_index(GL_INVALID_INDEX)
9856 , m_po_subroutine_test3_index(GL_INVALID_INDEX)
9857 , m_po_not_linked_id(0)
9858 , m_po_id(0)
9859 , m_vs_id(0)
9860 {
9861 /* Left blank intentionally */
9862 }
9863
9864 /** Deinitializes all GL objects that may have been created during
9865 * test execution.
9866 **/
deinit()9867 void NegativeTest1::deinit()
9868 {
9869 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
9870
9871 if (m_po_id != 0)
9872 {
9873 gl.deleteProgram(m_po_id);
9874
9875 m_po_id = 0;
9876 }
9877
9878 if (m_po_not_linked_id != 0)
9879 {
9880 gl.deleteProgram(m_po_not_linked_id);
9881
9882 m_po_not_linked_id = 0;
9883 }
9884
9885 if (m_vs_id != 0)
9886 {
9887 gl.deleteShader(m_vs_id);
9888
9889 m_vs_id = 0;
9890 }
9891 }
9892
9893 /** Initializes all GL objects required to run the test. */
initTest()9894 void NegativeTest1::initTest()
9895 {
9896 glw::GLint compile_status = GL_FALSE;
9897 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
9898
9899 /* Create program objects */
9900 m_po_not_linked_id = gl.createProgram();
9901 m_po_id = gl.createProgram();
9902 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call(s) failed.");
9903
9904 /* Create vertex shader object */
9905 m_vs_id = gl.createShader(GL_VERTEX_SHADER);
9906 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
9907
9908 /* Set up vertex shader */
9909 const char* vs_body = "#version 400\n"
9910 "\n"
9911 "#extension GL_ARB_shader_subroutine : require\n"
9912 "\n"
9913 "subroutine void subroutineType (out ivec2 arg);\n"
9914 "subroutine void subroutineType2(out ivec4 arg);\n"
9915 "\n"
9916 "subroutine(subroutineType) void test1(out ivec2 arg)\n"
9917 "{\n"
9918 " arg = ivec2(1, 2);\n"
9919 "}\n"
9920 "subroutine(subroutineType) void test2(out ivec2 arg)\n"
9921 "{\n"
9922 " arg = ivec2(3,4);\n"
9923 "}\n"
9924 "subroutine(subroutineType2) void test3(out ivec4 arg)\n"
9925 "{\n"
9926 " arg = ivec4(1, 2, 3, 4);\n"
9927 "}\n"
9928 "\n"
9929 "subroutine uniform subroutineType function;\n"
9930 "subroutine uniform subroutineType2 function2;\n"
9931 "\n"
9932 "void main()\n"
9933 "{\n"
9934 " ivec2 test;\n"
9935 " ivec4 test2;\n"
9936 "\n"
9937 " function(test);\n"
9938 "\n"
9939 " if (test.x > 2)\n"
9940 " {\n"
9941 " gl_Position = vec4(1);\n"
9942 " }\n"
9943 " else\n"
9944 " {\n"
9945 " function2(test2);\n"
9946 "\n"
9947 " gl_Position = vec4(float(test2.x) );\n"
9948 " }\n"
9949 "}\n";
9950
9951 gl.shaderSource(m_vs_id, 1 /* count */, &vs_body, DE_NULL /* length */);
9952 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed");
9953
9954 gl.compileShader(m_vs_id);
9955 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed");
9956
9957 gl.getShaderiv(m_vs_id, GL_COMPILE_STATUS, &compile_status);
9958 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed");
9959
9960 if (compile_status == GL_FALSE)
9961 {
9962 TCU_FAIL("Shader compilation failed");
9963 }
9964
9965 /* Set up & link the test program object */
9966 glw::GLint link_status = GL_FALSE;
9967
9968 gl.attachShader(m_po_id, m_vs_id);
9969 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
9970
9971 gl.linkProgram(m_po_id);
9972 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
9973
9974 gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
9975 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
9976
9977 if (link_status == GL_FALSE)
9978 {
9979 TCU_FAIL("Program linking failed");
9980 }
9981
9982 /* Query test program object's properties */
9983 gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS,
9984 &m_po_active_subroutine_uniform_locations);
9985 gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORMS, &m_po_active_subroutine_uniforms);
9986 gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINES, &m_po_active_subroutines);
9987 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramStageiv() call(s) failed.");
9988
9989 if (m_po_active_subroutine_uniform_locations != 2)
9990 {
9991 TCU_FAIL("Invalid GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS value returned");
9992 }
9993
9994 m_po_subroutine_test1_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "test1");
9995 m_po_subroutine_test2_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "test2");
9996 m_po_subroutine_test3_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "test3");
9997 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineIndex() call(s) failed.");
9998
9999 if (m_po_subroutine_test1_index == GL_INVALID_INDEX || m_po_subroutine_test2_index == GL_INVALID_INDEX ||
10000 m_po_subroutine_test3_index == GL_INVALID_INDEX)
10001 {
10002 TCU_FAIL("Invalid subroutine index returned");
10003 }
10004
10005 m_po_subroutine_uniform_function_index = gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "function");
10006 m_po_subroutine_uniform_function2_index = gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "function2");
10007 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineUniformLocation() call(s) failed.");
10008
10009 if (m_po_subroutine_uniform_function_index == -1 || m_po_subroutine_uniform_function2_index == -1)
10010 {
10011 TCU_FAIL("Invalid subroutine uniform index returned");
10012 }
10013 }
10014
10015 /** Executes test iteration.
10016 *
10017 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
10018 */
iterate()10019 tcu::TestNode::IterateResult NegativeTest1::iterate()
10020 {
10021 glw::GLenum error_code = GL_NO_ERROR;
10022 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
10023
10024 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
10025 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
10026 {
10027 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
10028 }
10029
10030 /* Initialize GL objects required to run the test */
10031 initTest();
10032
10033 /* The error INVALID_OPERATION is generated by GetSubroutineUniformLocation
10034 * if the program object identified by <program> has not been successfully
10035 * linked.
10036 */
10037 gl.getSubroutineUniformLocation(m_po_not_linked_id, GL_FRAGMENT_SHADER, "subroutine_uniform_name");
10038
10039 error_code = gl.getError();
10040
10041 if (error_code != GL_INVALID_OPERATION)
10042 {
10043 m_testCtx.getLog() << tcu::TestLog::Message
10044 << "glGetSubroutineUniformLocation() does not generate GL_INVALID_OPERATION "
10045 "error code when called for a non-linked program object."
10046 << tcu::TestLog::EndMessage;
10047
10048 m_has_test_passed = false;
10049 }
10050
10051 /* The error INVALID_VALUE is generated by GetActiveSubroutineUniformiv or
10052 * GetActiveSubroutineUniformName if <index> is greater than or equal to the
10053 * value of ACTIVE_SUBROUTINE_UNIFORMS for the shader stage.
10054 */
10055 glw::GLint temp_length = 0;
10056 glw::GLint temp_values = 0;
10057
10058 gl.getActiveSubroutineUniformiv(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutine_uniforms,
10059 GL_NUM_COMPATIBLE_SUBROUTINES, &temp_values);
10060 error_code = gl.getError();
10061
10062 if (error_code == GL_INVALID_VALUE)
10063 {
10064 gl.getActiveSubroutineUniformiv(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutine_uniforms + 1,
10065 GL_NUM_COMPATIBLE_SUBROUTINES, &temp_values);
10066
10067 error_code = gl.getError();
10068 }
10069
10070 if (error_code != GL_INVALID_VALUE)
10071 {
10072 m_testCtx.getLog() << tcu::TestLog::Message
10073 << "glGetActiveSubroutineUniformiv() does not generate GL_INVALID_VALUE "
10074 "when passed <index> argument that is greater than or equal to "
10075 "the value of GL_ACTIVE_SUBROUTINE_UNIFORMS."
10076 << tcu::TestLog::EndMessage;
10077
10078 m_has_test_passed = false;
10079 }
10080
10081 gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutine_uniforms, 0, /* bufsize */
10082 &temp_length, DE_NULL); /* name */
10083 error_code = gl.getError();
10084
10085 if (error_code == GL_INVALID_VALUE)
10086 {
10087 gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutine_uniforms + 1,
10088 0, /* bufsize */
10089 &temp_length, DE_NULL); /* name */
10090
10091 error_code = gl.getError();
10092 }
10093
10094 if (error_code != GL_INVALID_VALUE)
10095 {
10096 m_testCtx.getLog() << tcu::TestLog::Message
10097 << "glGetActiveSubroutineUniformName() does not generate GL_INVALID_VALUE "
10098 "when passed <index> argument that is greater than or equal to "
10099 "the value of GL_ACTIVE_SUBROUTINE_UNIFORMS."
10100 << tcu::TestLog::EndMessage;
10101
10102 m_has_test_passed = false;
10103 }
10104
10105 /* The error INVALID_VALUE is generated by GetActiveSubroutineName if <index>
10106 * is greater than or equal to the value of ACTIVE_SUBROUTINES for the shader
10107 * stage.
10108 */
10109 gl.getActiveSubroutineName(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutines, 0, /* bufsize */
10110 &temp_length, DE_NULL); /* name */
10111 error_code = gl.getError();
10112
10113 if (error_code == GL_INVALID_VALUE)
10114 {
10115 gl.getActiveSubroutineName(m_po_id, GL_VERTEX_SHADER, m_po_active_subroutines + 1, 0, /* bufsize */
10116 &temp_length, DE_NULL); /* name */
10117
10118 error_code = gl.getError();
10119 }
10120
10121 if (error_code != GL_INVALID_VALUE)
10122 {
10123 m_testCtx.getLog() << tcu::TestLog::Message << "glGetActiveSubroutineName() does not generate GL_INVALID_VALUE "
10124 "when passed <index> argument that is greater than or equal to "
10125 "the value of GL_ACTIVE_SUBROUTINES."
10126 << tcu::TestLog::EndMessage;
10127
10128 m_has_test_passed = false;
10129 }
10130
10131 /* The error INVALID_VALUE is generated by UniformSubroutinesuiv if <count>
10132 * is not equal to the value of ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS for the
10133 * shader stage <shadertype>.
10134 */
10135 glw::GLuint index = 0;
10136
10137 gl.useProgram(m_po_id);
10138 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
10139
10140 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations - 1, &index);
10141 error_code = gl.getError();
10142
10143 if (error_code == GL_INVALID_VALUE)
10144 {
10145 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations + 1, &index);
10146
10147 error_code = gl.getError();
10148 }
10149
10150 if (error_code != GL_INVALID_VALUE)
10151 {
10152 m_testCtx.getLog() << tcu::TestLog::Message << "glUniformSubroutinesiv() does not generate GL_INVALID_VALUE "
10153 "when passed <count> argument that is not equal to the value of "
10154 "GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS."
10155 << tcu::TestLog::EndMessage;
10156
10157 m_has_test_passed = false;
10158 }
10159
10160 /* The error INVALID_VALUE is generated by UniformSubroutinesuiv if any value
10161 * in <indices> is greater than or equal to the value of ACTIVE_SUBROUTINES
10162 * for the shader stage.
10163 */
10164 glw::GLuint invalid_subroutine_indices[4] = { (GLuint)m_po_active_subroutines, (GLuint)m_po_active_subroutines,
10165 (GLuint)m_po_active_subroutines + 1,
10166 (GLuint)m_po_active_subroutines + 1 };
10167
10168 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations, /* count */
10169 invalid_subroutine_indices + 0);
10170 error_code = gl.getError();
10171
10172 if (error_code == GL_INVALID_VALUE)
10173 {
10174 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations,
10175 invalid_subroutine_indices + 2);
10176
10177 error_code = gl.getError();
10178 }
10179
10180 if (error_code != GL_INVALID_VALUE)
10181 {
10182 m_testCtx.getLog() << tcu::TestLog::Message << "glUniformSubroutinesuiv() does not generate GL_INVALID_VALUE "
10183 "when the value passed via <indices> argument is greater than "
10184 "or equal to the value of GL_ACTIVE_SUBROUTINES."
10185 << tcu::TestLog::EndMessage;
10186
10187 m_has_test_passed = false;
10188 }
10189
10190 /* The error INVALID_OPERATION is generated by UniformSubroutinesuiv() if any
10191 * subroutine index in <indices> identifies a subroutine not associated with
10192 * the type of the subroutine uniform variable assigned to the corresponding
10193 * location.
10194 */
10195 glw::GLuint invalid_subroutine_indices2[2] = { m_po_subroutine_test1_index, m_po_subroutine_test1_index };
10196
10197 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations, invalid_subroutine_indices2);
10198 error_code = gl.getError();
10199
10200 if (error_code != GL_INVALID_OPERATION)
10201 {
10202 m_testCtx.getLog() << tcu::TestLog::Message
10203 << "glUniformSubroutinesuiv() does not generate GL_INVALID_OPERATION "
10204 "when the subroutine index passed via <indices> argument identifies"
10205 "a subroutine not associated with the type of the subroutine uniform "
10206 "assigned to the corresponding location."
10207 << tcu::TestLog::EndMessage;
10208
10209 m_has_test_passed = false;
10210 }
10211
10212 /* The error INVALID_OPERATION is generated by UniformSubroutinesuiv if no
10213 * program is active.
10214 */
10215 glw::GLuint valid_subroutine_locations[2] = { 0 };
10216
10217 valid_subroutine_locations[m_po_subroutine_uniform_function_index] = m_po_subroutine_test1_index;
10218 valid_subroutine_locations[m_po_subroutine_uniform_function2_index] = m_po_subroutine_test3_index;
10219
10220 gl.useProgram(0);
10221 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
10222
10223 gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations, valid_subroutine_locations);
10224 error_code = gl.getError();
10225
10226 if (error_code != GL_INVALID_OPERATION)
10227 {
10228 m_testCtx.getLog() << tcu::TestLog::Message
10229 << "glUniformSubroutinesuiv() does not generate GL_INVALID_OPERATION "
10230 "when called without an active program object."
10231 << tcu::TestLog::EndMessage;
10232
10233 m_has_test_passed = false;
10234 }
10235
10236 /* The error INVALID_VALUE is generated by GetUniformSubroutineuiv if
10237 * <location> is greater than or equal to the value of
10238 * ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS for the shader stage.
10239 */
10240 glw::GLuint temp_value = 0;
10241
10242 gl.useProgram(m_po_id);
10243 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
10244
10245 gl.getUniformSubroutineuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations, &temp_value);
10246 error_code = gl.getError();
10247
10248 if (error_code == GL_INVALID_VALUE)
10249 {
10250 gl.getUniformSubroutineuiv(GL_VERTEX_SHADER, m_po_active_subroutine_uniform_locations + 1, &temp_value);
10251 error_code = gl.getError();
10252 }
10253
10254 if (error_code != GL_INVALID_VALUE)
10255 {
10256 m_testCtx.getLog() << tcu::TestLog::Message
10257 << "glGetUniformSubroutineuiv() does not generate GL_INVALID_VALUE "
10258 "when called for location that is greater than or equal to the value "
10259 "of GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS."
10260 << tcu::TestLog::EndMessage;
10261
10262 m_has_test_passed = false;
10263 }
10264
10265 /* The error INVALID_OPERATION is generated by GetUniformSubroutineuiv if no
10266 * program is active for the shader stage identified by <shadertype>.
10267 */
10268 const glw::GLenum undefined_shader_stages[] = { GL_FRAGMENT_SHADER, GL_GEOMETRY_SHADER, GL_TESS_CONTROL_SHADER,
10269 GL_TESS_EVALUATION_SHADER };
10270 const unsigned int n_undefined_shader_stages = sizeof(undefined_shader_stages) / sizeof(undefined_shader_stages[0]);
10271
10272 for (unsigned int n_undefined_shader_stage = 0; n_undefined_shader_stage < n_undefined_shader_stages;
10273 ++n_undefined_shader_stage)
10274 {
10275 glw::GLenum shader_stage = undefined_shader_stages[n_undefined_shader_stage];
10276
10277 gl.getUniformSubroutineuiv(shader_stage, 0, /* location */
10278 &temp_value);
10279 error_code = gl.getError();
10280
10281 if (error_code != GL_INVALID_OPERATION)
10282 {
10283 m_testCtx.getLog() << tcu::TestLog::Message
10284 << "glGetUniformSubroutineuiv() does not generate GL_INVALID_OPERATION "
10285 "when called for a shader stage that is not defined for active "
10286 "program object."
10287 << tcu::TestLog::EndMessage;
10288
10289 m_has_test_passed = false;
10290 }
10291 } /* for (all undefined shader stages) */
10292
10293 /* All done */
10294 if (m_has_test_passed)
10295 {
10296 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
10297 }
10298 else
10299 {
10300 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
10301 }
10302
10303 return STOP;
10304 }
10305
10306 /** Constructor
10307 *
10308 * @param context Rendering context.
10309 *
10310 **/
NegativeTest2(deqp::Context & context)10311 NegativeTest2::NegativeTest2(deqp::Context& context)
10312 : TestCase(context, "subroutine_uniform_scope", "Verifies subroutine uniforms declared in shader stage A"
10313 "cannot be accessed from a different stage.")
10314 , m_fs_id(0)
10315 , m_gs_id(0)
10316 , m_has_test_passed(true)
10317 , m_po_id(0)
10318 , m_tc_id(0)
10319 , m_te_id(0)
10320 , m_vs_id(0)
10321 {
10322 /* Left blank intentionally */
10323 }
10324
10325 /** Deinitializes all GL objects that may have been created during test execution */
deinit()10326 void NegativeTest2::deinit()
10327 {
10328 deinitGLObjects();
10329 }
10330
10331 /** Deinitializes all GL objects that may have been created during test execution */
deinitGLObjects()10332 void NegativeTest2::deinitGLObjects()
10333 {
10334 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
10335
10336 if (m_fs_id != 0)
10337 {
10338 gl.deleteShader(m_fs_id);
10339
10340 m_fs_id = 0;
10341 }
10342
10343 if (m_gs_id != 0)
10344 {
10345 gl.deleteShader(m_gs_id);
10346
10347 m_gs_id = 0;
10348 }
10349
10350 if (m_tc_id != 0)
10351 {
10352 gl.deleteShader(m_tc_id);
10353
10354 m_tc_id = 0;
10355 }
10356
10357 if (m_te_id != 0)
10358 {
10359 gl.deleteShader(m_te_id);
10360
10361 m_te_id = 0;
10362 }
10363
10364 if (m_vs_id != 0)
10365 {
10366 gl.deleteShader(m_vs_id);
10367
10368 m_vs_id = 0;
10369 }
10370
10371 if (m_po_id != 0)
10372 {
10373 gl.deleteProgram(m_po_id);
10374
10375 m_po_id = 0;
10376 }
10377 }
10378
10379 /** Builds an offending program object and tries to link it. We're either expecting
10380 * a compile-time or link-time error here.
10381 *
10382 * If the program object builds successfully, the test has failed.
10383 *
10384 * @param referencing_stage Shader stage which defines a subroutine uniform that
10385 * should be called from fragment/geometry/tess control/
10386 * tess evaluation/vertex shader stages.
10387 *
10388 **/
executeTestCase(const Utils::_shader_stage & referencing_stage)10389 void NegativeTest2::executeTestCase(const Utils::_shader_stage& referencing_stage)
10390 {
10391 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
10392
10393 const std::string fs_body = getFragmentShaderBody(referencing_stage);
10394 const std::string gs_body = getGeometryShaderBody(referencing_stage);
10395 const std::string tc_body = getTessellationControlShaderBody(referencing_stage);
10396 const std::string te_body = getTessellationEvaluationShaderBody(referencing_stage);
10397 const std::string vs_body = getVertexShaderBody(referencing_stage);
10398
10399 if (Utils::buildProgram(gl, vs_body, tc_body, te_body, gs_body, fs_body, NULL, /* xfb_varyings */
10400 0, /* n_xfb_varyings */
10401 &m_vs_id, &m_tc_id, &m_te_id, &m_gs_id, &m_fs_id, &m_po_id))
10402 {
10403 /* Test program should not have built correctly ! */
10404 m_testCtx.getLog() << tcu::TestLog::Message << "In the following program, one of the stages references "
10405 "a subroutine that is defined in another stage. This "
10406 "is forbidden by the specification.\n"
10407 "\n"
10408 "Vertex shader:\n\n"
10409 << vs_body.c_str() << "\n\nTessellation control shader:\n\n"
10410 << tc_body.c_str() << "\n\nTessellation evaluation shader:\n\n"
10411 << te_body.c_str() << "\n\nGeometry shader:\n\n"
10412 << gs_body.c_str() << "\n\nFragment shader:\n\n"
10413 << fs_body.c_str() << tcu::TestLog::EndMessage;
10414
10415 m_has_test_passed = false;
10416 } /* if (test program was built successfully) */
10417
10418 /* Release the shaders & the program object that buildProgram() created */
10419 deinitGLObjects();
10420 }
10421
10422 /** Retrieves an offending fragment shader body.
10423 *
10424 * @param referencing_stage Shader stage which defines the subroutine uniform that
10425 * will be called from fragment shader.
10426 *
10427 * @return Requested string.
10428 **/
getFragmentShaderBody(const Utils::_shader_stage & referencing_stage) const10429 std::string NegativeTest2::getFragmentShaderBody(const Utils::_shader_stage& referencing_stage) const
10430 {
10431 std::stringstream result;
10432
10433 /* Form the pre-amble */
10434 result << "#version 400\n"
10435 "\n"
10436 "#extension GL_ARB_shader_subroutine : require\n"
10437 "\n"
10438 "subroutine void testSubroutineType(out vec4 test_argument);\n"
10439 "\n"
10440 /* Define a subroutine */
10441 "subroutine(testSubroutineType) void fs_subroutine(out vec4 test_argument)\n"
10442 "{\n"
10443 " test_argument = vec4(1, 0, 0, 0);\n"
10444 "}\n"
10445 "\n"
10446 /* Define output variables */
10447 "out vec4 result;\n"
10448 "\n"
10449 /* Define uniforms */
10450 "subroutine uniform testSubroutineType test_fs_subroutine;\n"
10451 "\n"
10452 /* Define main() */
10453 "void main()\n"
10454 "{\n"
10455 " "
10456 << getSubroutineUniformName(referencing_stage) << "(result);\n"
10457 "}\n";
10458
10459 return result.str();
10460 }
10461
10462 /** Retrieves an offending geometry shader body.
10463 *
10464 * @param referencing_stage Shader stage which defines the subroutine uniform that
10465 * will be called from geometry shader.
10466 *
10467 * @return Requested string.
10468 **/
getGeometryShaderBody(const Utils::_shader_stage & referencing_stage) const10469 std::string NegativeTest2::getGeometryShaderBody(const Utils::_shader_stage& referencing_stage) const
10470 {
10471 std::stringstream result;
10472
10473 /* Form the pre-amble */
10474 result << "#version 400\n"
10475 "\n"
10476 "#extension GL_ARB_shader_subroutine : require\n"
10477 "\n"
10478 "subroutine void testSubroutineType(out vec4 test_argument);\n"
10479 "\n"
10480 "layout(points) in;\n"
10481 "layout(points, max_vertices = 1) out;\n"
10482 "\n"
10483 /* Define a subroutine */
10484 "subroutine(testSubroutineType) void gs_subroutine(out vec4 test_argument)\n"
10485 "{\n"
10486 " test_argument = vec4(0, 1, 1, 1);\n"
10487 "}\n"
10488 "\n"
10489 /* Define output variables */
10490 "out vec4 result;\n"
10491 "\n"
10492 /* Define uniforms */
10493 "subroutine uniform testSubroutineType test_gs_subroutine;\n"
10494 "\n"
10495 /* Define main() */
10496 "void main()\n"
10497 "{\n"
10498 " "
10499 << getSubroutineUniformName(referencing_stage) << "(result);\n"
10500 "}\n";
10501
10502 return result.str();
10503 }
10504
10505 /** Retrieves name of the subroutine uniform that is defined in user-specified
10506 * shader stage.
10507 *
10508 * @param stage Shader stage to retrieve the subroutine uniform name for.
10509 *
10510 * @return As per description.
10511 **/
getSubroutineUniformName(const Utils::_shader_stage & stage) const10512 std::string NegativeTest2::getSubroutineUniformName(const Utils::_shader_stage& stage) const
10513 {
10514 std::string result = "?";
10515
10516 switch (stage)
10517 {
10518 case Utils::SHADER_STAGE_FRAGMENT:
10519 {
10520 result = "test_fs_subroutine";
10521
10522 break;
10523 }
10524
10525 case Utils::SHADER_STAGE_GEOMETRY:
10526 {
10527 result = "test_gs_subroutine";
10528
10529 break;
10530 }
10531
10532 case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
10533 {
10534 result = "test_tc_subroutine";
10535
10536 break;
10537 }
10538
10539 case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
10540 {
10541 result = "test_te_subroutine";
10542
10543 break;
10544 }
10545
10546 case Utils::SHADER_STAGE_VERTEX:
10547 {
10548 result = "test_vs_subroutine";
10549
10550 break;
10551 }
10552
10553 default:
10554 {
10555 TCU_FAIL("Unrecognized shader stage requested");
10556 }
10557 } /* switch (stage) */
10558
10559 return result;
10560 }
10561
10562 /** Retrieves an offending tessellation control shader body.
10563 *
10564 * @param referencing_stage Shader stage which defines the subroutine uniform that
10565 * will be called from tessellation control shader.
10566 *
10567 * @return Requested string.
10568 **/
getTessellationControlShaderBody(const Utils::_shader_stage & referencing_stage) const10569 std::string NegativeTest2::getTessellationControlShaderBody(const Utils::_shader_stage& referencing_stage) const
10570 {
10571 std::stringstream result;
10572
10573 /* Form the pre-amble */
10574 result << "#version 400\n"
10575 "\n"
10576 "#extension GL_ARB_shader_subroutine : require\n"
10577 "\n"
10578 "layout(vertices = 4) out;\n"
10579 "\n"
10580 "subroutine void testSubroutineType(out vec4 test_argument);\n"
10581 "\n"
10582 /* Define a subroutine */
10583 "subroutine(testSubroutineType) void tc_subroutine(out vec4 test_argument)\n"
10584 "{\n"
10585 " test_argument = vec4(0, 0, 1, 0);\n"
10586 "}\n"
10587 "\n"
10588 /* Define uniforms */
10589 "subroutine uniform testSubroutineType test_tc_subroutine;\n"
10590 "\n"
10591 /* Define main() */
10592 "void main()\n"
10593 "{\n"
10594 " "
10595 << getSubroutineUniformName(referencing_stage) << "(gl_out[gl_InvocationID].gl_Position);\n"
10596 "}\n";
10597
10598 return result.str();
10599 }
10600
10601 /** Retrieves an offending tessellation evaluation shader body.
10602 *
10603 * @param referencing_stage Shader stage which defines the subroutine uniform that
10604 * will be called from tessellation evaluation shader.
10605 *
10606 * @return Requested string.
10607 **/
getTessellationEvaluationShaderBody(const Utils::_shader_stage & referencing_stage) const10608 std::string NegativeTest2::getTessellationEvaluationShaderBody(const Utils::_shader_stage& referencing_stage) const
10609 {
10610 std::stringstream result;
10611
10612 /* Form the pre-amble */
10613 result << "#version 400\n"
10614 "\n"
10615 "#extension GL_ARB_shader_subroutine : require\n"
10616 "\n"
10617 "layout(quads) in;\n"
10618 "\n"
10619 "subroutine void testSubroutineType(out vec4 test_argument);\n"
10620 "\n"
10621 /* Define a subroutine */
10622 "subroutine(testSubroutineType) void te_subroutine(out vec4 test_argument)\n"
10623 "{\n"
10624 " test_argument = vec4(1, 1, 1, 1);\n"
10625 "}\n"
10626 "\n"
10627 /* Define uniforms */
10628 "subroutine uniform testSubroutineType test_te_subroutine;\n"
10629 "\n"
10630 /* Define main() */
10631 "void main()\n"
10632 "{\n"
10633 " "
10634 << getSubroutineUniformName(referencing_stage) << "(gl_Position);\n"
10635 "}\n";
10636
10637 return result.str();
10638 }
10639
10640 /** Retrieves an offending vertex shader body.
10641 *
10642 * @param referencing_stage Shader stage which defines the subroutine uniform that
10643 * will be called from vertex shader.
10644 *
10645 * @return Requested string.
10646 **/
getVertexShaderBody(const Utils::_shader_stage & referencing_stage) const10647 std::string NegativeTest2::getVertexShaderBody(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 "subroutine void testSubroutineType(out vec4 test_argument);\n"
10657 "\n"
10658 /* Define a subroutine */
10659 "subroutine(testSubroutineType) void vs_subroutine(out vec4 test_argument)\n"
10660 "{\n"
10661 " test_argument = vec4(0, 1, 0, 0);\n"
10662 "}\n"
10663 "\n"
10664 /* Define uniforms */
10665 "subroutine uniform testSubroutineType test_vs_subroutine;\n"
10666 "\n"
10667 /* Define main() */
10668 "void main()\n"
10669 "{\n"
10670 " "
10671 << getSubroutineUniformName(referencing_stage) << "(gl_Position);\n"
10672 "}\n";
10673
10674 return result.str();
10675 }
10676
10677 /** Executes test iteration.
10678 *
10679 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
10680 */
iterate()10681 tcu::TestNode::IterateResult NegativeTest2::iterate()
10682 {
10683 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
10684 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
10685 {
10686 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
10687 }
10688
10689 /* Iterate over all shader stages and execute the checks */
10690 for (int referencing_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
10691 referencing_stage < static_cast<int>(Utils::SHADER_STAGE_COUNT); ++referencing_stage)
10692 {
10693 executeTestCase(static_cast<Utils::_shader_stage>(referencing_stage));
10694 } /* for (all test cases) */
10695
10696 /* All done */
10697 if (m_has_test_passed)
10698 {
10699 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
10700 }
10701 else
10702 {
10703 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
10704 }
10705
10706 return STOP;
10707 }
10708
10709 /** Constructor.
10710 *
10711 * @param context Rendering context.
10712 *
10713 **/
NegativeTest3(deqp::Context & context)10714 NegativeTest3::NegativeTest3(deqp::Context& context)
10715 : TestCase(context, "missing_subroutine_keyword", "Verifies that subroutine keyword is necessary when declaring a "
10716 "subroutine uniforn and a compilation error occurs without it.")
10717 , m_has_test_passed(true)
10718 , m_so_id(0)
10719 {
10720 /* Left blank intentionally */
10721 }
10722
10723 /** Deinitializes all GL objects that may have been created during test execution */
deinit()10724 void NegativeTest3::deinit()
10725 {
10726 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
10727
10728 if (m_so_id != 0)
10729 {
10730 gl.deleteShader(m_so_id);
10731
10732 m_so_id = 0;
10733 }
10734 }
10735
10736 /** Verifies that broken shader (for user-specified shader stage) does not compile.
10737 *
10738 * @param shader_stage Shader stage to use for the test.
10739 **/
executeTest(const Utils::_shader_stage & shader_stage)10740 void NegativeTest3::executeTest(const Utils::_shader_stage& shader_stage)
10741 {
10742 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
10743
10744 /* Generate a new shader object */
10745 m_so_id = gl.createShader(Utils::getGLenumForShaderStage(shader_stage));
10746 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
10747
10748 /* Assign body to the shader */
10749 std::string body;
10750 const char* body_raw_ptr = DE_NULL;
10751
10752 switch (shader_stage)
10753 {
10754 case Utils::SHADER_STAGE_VERTEX:
10755 body = getVertexShaderBody();
10756 break;
10757 case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
10758 body = getTessellationControlShaderBody();
10759 break;
10760 case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
10761 body = getTessellationEvaluationShaderBody();
10762 break;
10763 case Utils::SHADER_STAGE_GEOMETRY:
10764 body = getGeometryShaderBody();
10765 break;
10766 case Utils::SHADER_STAGE_FRAGMENT:
10767 body = getFragmentShaderBody();
10768 break;
10769
10770 default:
10771 {
10772 TCU_FAIL("Unrecognized shader stage requested");
10773 }
10774 } /* switch (shader_stage) */
10775
10776 body_raw_ptr = body.c_str();
10777
10778 gl.shaderSource(m_so_id, 1 /* count */, &body_raw_ptr, DE_NULL /* length */);
10779 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
10780
10781 /* Try to compile the shader */
10782 glw::GLint compile_status = 0;
10783
10784 gl.compileShader(m_so_id);
10785 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
10786
10787 gl.getShaderiv(m_so_id, GL_COMPILE_STATUS, &compile_status);
10788 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
10789
10790 if (compile_status == GL_TRUE)
10791 {
10792 m_testCtx.getLog() << tcu::TestLog::Message << "The following shader was expected to fail to compile but was "
10793 "accepted by the compiler:\n"
10794 "\n"
10795 << body.c_str() << tcu::TestLog::EndMessage;
10796
10797 m_has_test_passed = false;
10798 }
10799
10800 /* Good to release the shader at this point */
10801 gl.deleteShader(m_so_id);
10802 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed.");
10803 }
10804
10805 /** Retrieves body of a broken fragment shader.
10806 *
10807 * @return Requested string.
10808 **/
getFragmentShaderBody() const10809 std::string NegativeTest3::getFragmentShaderBody() const
10810 {
10811 return "#version 400\n"
10812 "\n"
10813 "#extension GL_ARB_shader_subroutine : require\n"
10814 "\n"
10815 "subroutine void testSubroutineType(inout vec4 test);\n"
10816 "\n"
10817 "void testSubroutine1(inout vec4 test)\n"
10818 "{\n"
10819 " test += vec4(3, 4, 5, 6);\n"
10820 "}\n"
10821 "\n"
10822 "uniform testSubroutineType subroutineFunction;\n"
10823 "out vec4 result;\n"
10824 "\n"
10825 "void main()\n"
10826 "{\n"
10827 " vec4 test = vec4(2, 3, 4, 5);\n"
10828 "\n"
10829 " subroutineFunction(test);\n"
10830 "\n"
10831 " result = test;\n"
10832 "}\n";
10833 }
10834
10835 /** Retrieves body of a broken geometry shader.
10836 *
10837 * @return Requested string.
10838 **/
getGeometryShaderBody() const10839 std::string NegativeTest3::getGeometryShaderBody() const
10840 {
10841 return "#version 400\n"
10842 "\n"
10843 "#extension GL_ARB_shader_subroutine : require\n"
10844 "\n"
10845 "layout(points) in;\n"
10846 "layout(points, max_vertices = 1) out;\n"
10847 "\n"
10848 "subroutine void testSubroutineType(inout vec4 test);\n"
10849 "\n"
10850 "void testSubroutine1(inout vec4 test)\n"
10851 "{\n"
10852 " test += vec4(3, 4, 5, 6);\n"
10853 "}\n"
10854 "\n"
10855 "uniform testSubroutineType subroutineFunction;\n"
10856 "\n"
10857 "void main()\n"
10858 "{\n"
10859 " vec4 test = vec4(2, 3, 4, 5);\n"
10860 "\n"
10861 " subroutineFunction(test);\n"
10862 "\n"
10863 " gl_Position = test;\n"
10864 " EmitVertex();\n"
10865 "}\n";
10866 }
10867
10868 /** Retrieves body of a broken tessellation control shader.
10869 *
10870 * @return Requested string.
10871 **/
getTessellationControlShaderBody() const10872 std::string NegativeTest3::getTessellationControlShaderBody() const
10873 {
10874 return "#version 400\n"
10875 "\n"
10876 "#extension GL_ARB_shader_subroutine : require\n"
10877 "\n"
10878 "layout(vertices=4) out;\n"
10879 "\n"
10880 "subroutine void testSubroutineType(inout vec4 test);\n"
10881 "\n"
10882 "void testSubroutine1(inout vec4 test)\n"
10883 "{\n"
10884 " test += vec4(1, 2, 3, 4);\n"
10885 "}\n"
10886 "\n"
10887 "uniform testSubroutineType subroutineFunction;\n"
10888 "\n"
10889 "void main()\n"
10890 "{\n"
10891 " vec4 test = vec4(0, 1, 2, 3);\n"
10892 "\n"
10893 " subroutineFunction(test);\n"
10894 "\n"
10895 " gl_out[gl_InvocationID].gl_Position = test;\n"
10896 "}\n";
10897 }
10898
10899 /** Retrieves body of a broken tessellation evaluation shader.
10900 *
10901 * @return Requested string.
10902 **/
getTessellationEvaluationShaderBody() const10903 std::string NegativeTest3::getTessellationEvaluationShaderBody() const
10904 {
10905 return "#version 400\n"
10906 "\n"
10907 "#extension GL_ARB_shader_subroutine : require\n"
10908 "\n"
10909 "layout(quads) in;\n"
10910 "\n"
10911 "subroutine void testSubroutineType(inout vec4 test);\n"
10912 "\n"
10913 "void testSubroutine1(inout vec4 test)\n"
10914 "{\n"
10915 " test += vec4(2, 3, 4, 5);\n"
10916 "}\n"
10917 "\n"
10918 "uniform testSubroutineType subroutineFunction;\n"
10919 "\n"
10920 "void main()\n"
10921 "{\n"
10922 " vec4 test = vec4(1, 2, 3, 4);\n"
10923 "\n"
10924 " subroutineFunction(test);\n"
10925 "\n"
10926 " gl_Position = test;\n"
10927 "}\n";
10928 }
10929
10930 /** Retrieves body of a broken vertex shader.
10931 *
10932 * @return Requested string.
10933 **/
getVertexShaderBody() const10934 std::string NegativeTest3::getVertexShaderBody() const
10935 {
10936 return "#version 400\n"
10937 "\n"
10938 "#extension GL_ARB_shader_subroutine : require\n"
10939 "\n"
10940 "subroutine void testSubroutineType(inout vec4 test);\n"
10941 "\n"
10942 "void testSubroutine1(inout vec4 test)\n"
10943 "{\n"
10944 " test += vec4(0, 1, 2, 3);\n"
10945 "}\n"
10946 "\n"
10947 "uniform testSubroutineType subroutineFunction;\n"
10948 "\n"
10949 "void main()\n"
10950 "{\n"
10951 " subroutineFunction(gl_Position);\n"
10952 "}\n";
10953 }
10954
10955 /** Executes test iteration.
10956 *
10957 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
10958 */
iterate()10959 tcu::TestNode::IterateResult NegativeTest3::iterate()
10960 {
10961 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
10962 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
10963 {
10964 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
10965 }
10966
10967 /* Iterate over all shader stages */
10968 for (int shader_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
10969 shader_stage < static_cast<int>(Utils::SHADER_STAGE_COUNT); ++shader_stage)
10970 {
10971 executeTest(static_cast<Utils::_shader_stage>(shader_stage));
10972 } /* for (all shader stages) */
10973
10974 /* Done */
10975 if (m_has_test_passed)
10976 {
10977 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
10978 }
10979 else
10980 {
10981 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
10982 }
10983
10984 return STOP;
10985 }
10986
10987 /** Constructor.
10988 *
10989 * @param context Rendering context.
10990 *
10991 **/
NegativeTest4(deqp::Context & context)10992 NegativeTest4::NegativeTest4(deqp::Context& context)
10993 : TestCase(context, "subroutines_incompatible_with_subroutine_type",
10994 "Verifies that a compile-time error is generated when arguments and "
10995 "return type do not match beween the function and each associated "
10996 "subroutine type.")
10997 , m_has_test_passed(true)
10998 , m_so_id(0)
10999 {
11000 /* Left blank intentionally */
11001 }
11002
11003 /** Deinitializes GL objects that may have been created during test
11004 * execution.
11005 **/
deinit()11006 void NegativeTest4::deinit()
11007 {
11008 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
11009
11010 if (m_so_id != 0)
11011 {
11012 gl.deleteShader(m_so_id);
11013
11014 m_so_id = 0;
11015 }
11016 }
11017
11018 /** Retrieves body of a shader of user-specified type that should be used
11019 * for a single test iteration. The shader will define user-specified number
11020 * of subroutine types, with the last type either defining an additional argument
11021 * or using a different return type.
11022 * A subroutine (claimed compatible with *all* subroutine types) will also be
11023 * defined in the shader.
11024 *
11025 * @param shader_stage Shader stage to use for the query.
11026 * @param n_subroutine_types Overall number of subroutine types that will be
11027 * declared & used in the shader. Please see description
11028 * for more details.
11029 *
11030 * @return Requested string.
11031 **/
getShaderBody(const Utils::_shader_stage & shader_stage,const unsigned int & n_subroutine_types,const _test_case & test_case) const11032 std::string NegativeTest4::getShaderBody(const Utils::_shader_stage& shader_stage,
11033 const unsigned int& n_subroutine_types, const _test_case& test_case) const
11034 {
11035 std::stringstream result_sstream;
11036
11037 /* Form the pre-amble */
11038 result_sstream << "#version 400\n"
11039 "\n"
11040 "#extension GL_ARB_shader_subroutine : require\n"
11041 "\n";
11042
11043 /* Inject stage-specific code */
11044 switch (shader_stage)
11045 {
11046 case Utils::SHADER_STAGE_GEOMETRY:
11047 {
11048 result_sstream << "layout (points) in;\n"
11049 "layout (points, max_vertices = 1) out;\n"
11050 "\n";
11051
11052 break;
11053 }
11054
11055 case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
11056 {
11057 result_sstream << "layout (vertices = 4) out;\n"
11058 "\n";
11059
11060 break;
11061 }
11062
11063 case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
11064 {
11065 result_sstream << "layout (quads) in;\n"
11066 "\n";
11067
11068 break;
11069 }
11070
11071 default:
11072 break;
11073 } /* switch (shader_stage) */
11074
11075 /* Insert subroutine type declarations */
11076 for (unsigned int n_subroutine_type = 0; n_subroutine_type < n_subroutine_types - 1; ++n_subroutine_type)
11077 {
11078 result_sstream << "subroutine void subroutineType" << n_subroutine_type << "(inout vec3 argument);\n";
11079 } /* for (all subroutine types) */
11080
11081 switch (test_case)
11082 {
11083 case TEST_CASE_INCOMPATIBLE_ARGUMENT_LIST:
11084 {
11085 result_sstream << "subroutine void subroutineType" << (n_subroutine_types - 1)
11086 << "(inout vec3 argument, out vec4 argument2);\n";
11087
11088 break;
11089 }
11090
11091 case TEST_CASE_INCOMPATIBLE_RETURN_TYPE:
11092 {
11093 result_sstream << "subroutine int subroutineType" << (n_subroutine_types - 1) << "(inout vec3 argument);\n";
11094
11095 break;
11096 }
11097
11098 default:
11099 {
11100 TCU_FAIL("Unrecognized test case");
11101 }
11102 } /* switch (test_case) */
11103
11104 /* Insert subroutine declarations */
11105 result_sstream << "subroutine(";
11106
11107 for (unsigned int n_subroutine_type = 0; n_subroutine_type < n_subroutine_types; ++n_subroutine_type)
11108 {
11109 result_sstream << "subroutineType" << n_subroutine_type;
11110
11111 if (n_subroutine_type != (n_subroutine_types - 1))
11112 {
11113 result_sstream << ", ";
11114 }
11115 } /* for (all subroutine types) */
11116
11117 result_sstream << ") void function(inout vec3 argument)\n"
11118 "{\n"
11119 " argument = vec3(1, 2, 3);\n"
11120 "}\n"
11121 "\n";
11122
11123 /* Insert remaining required stage-specific bits */
11124 switch (shader_stage)
11125 {
11126 case Utils::SHADER_STAGE_FRAGMENT:
11127 {
11128 result_sstream << "out vec4 result;\n"
11129 "\n"
11130 "void main()\n"
11131 "{\n"
11132 " result = vec4(1, 2, 3, 4);\n"
11133 "}\n";
11134
11135 break;
11136 }
11137
11138 case Utils::SHADER_STAGE_GEOMETRY:
11139 {
11140 result_sstream << "void main()\n"
11141 "{\n"
11142 " gl_Position = vec4(1, 2, 3, 4);\n"
11143 " EmitVertex();\n"
11144 "}\n";
11145
11146 break;
11147 }
11148
11149 case Utils::SHADER_STAGE_TESSELLATION_CONTROL:
11150 {
11151 result_sstream << "void main()\n"
11152 "{\n"
11153 " gl_TessLevelInner[0] = 1;\n"
11154 " gl_TessLevelInner[1] = 1;\n"
11155 " gl_TessLevelOuter[0] = 1;\n"
11156 " gl_TessLevelOuter[1] = 1;\n"
11157 " gl_TessLevelOuter[2] = 1;\n"
11158 " gl_TessLevelOuter[3] = 1;\n"
11159 " gl_out[gl_InvocationID].gl_Position = vec4(2, 3, 4, 5);\n"
11160 "}\n";
11161
11162 break;
11163 }
11164
11165 case Utils::SHADER_STAGE_TESSELLATION_EVALUATION:
11166 case Utils::SHADER_STAGE_VERTEX:
11167 {
11168 result_sstream << "void main()\n"
11169 "{\n"
11170 " gl_Position = vec4(1, 2, 3, 4);\n"
11171 "}\n";
11172
11173 break;
11174 }
11175
11176 default:
11177 {
11178 TCU_FAIL("Unrecognized shader stage");
11179 }
11180 } /* switch (shader_stage) */
11181
11182 return result_sstream.str();
11183 }
11184
11185 /** Executes test iteration.
11186 *
11187 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
11188 */
iterate()11189 tcu::TestNode::IterateResult NegativeTest4::iterate()
11190 {
11191 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
11192
11193 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
11194 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
11195 {
11196 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
11197 }
11198
11199 /* Iterate over all shader stages.. */
11200 for (int shader_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
11201 shader_stage != static_cast<int>(Utils::SHADER_STAGE_COUNT); ++shader_stage)
11202 {
11203 /* For each shader stage, we will be trying to compile a number of invalid shaders.
11204 * Each shader defines N different subroutine types. (N-1) of them are compatible
11205 * with a subroutine, but exactly 1 will be mismatched. The test passes if GLSL
11206 * compiler correctly detects that all shaders we will be trying to compile are
11207 * broken.
11208 */
11209 const glw::GLenum shader_type = Utils::getGLenumForShaderStage(static_cast<Utils::_shader_stage>(shader_stage));
11210
11211 for (unsigned int n_subroutine_types = 1; n_subroutine_types < 6; /* arbitrary number */
11212 ++n_subroutine_types)
11213 {
11214 for (int test_case = static_cast<int>(TEST_CASE_FIRST); test_case != static_cast<int>(TEST_CASE_COUNT);
11215 ++test_case)
11216 {
11217 std::string body;
11218 const char* body_raw_ptr = NULL;
11219 glw::GLint compile_status = GL_FALSE;
11220
11221 body = getShaderBody(static_cast<Utils::_shader_stage>(shader_stage), n_subroutine_types,
11222 static_cast<_test_case>(test_case));
11223 body_raw_ptr = body.c_str();
11224
11225 /* Try to compile the shader */
11226 m_so_id = gl.createShader(shader_type);
11227 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed");
11228
11229 gl.shaderSource(m_so_id, 1 /* count */, &body_raw_ptr, DE_NULL);
11230 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed");
11231
11232 gl.compileShader(m_so_id);
11233 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed");
11234
11235 gl.getShaderiv(m_so_id, GL_COMPILE_STATUS, &compile_status);
11236 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
11237
11238 if (compile_status == GL_TRUE)
11239 {
11240 m_testCtx.getLog() << tcu::TestLog::Message << "A malformed "
11241 << Utils::getShaderStageString(static_cast<Utils::_shader_stage>(shader_stage))
11242 << " compiled successfully "
11243 "("
11244 << n_subroutine_types << " subroutine types "
11245 "were defined)."
11246 << tcu::TestLog::EndMessage;
11247
11248 m_has_test_passed = false;
11249 }
11250
11251 /* Release the object */
11252 gl.deleteShader(m_so_id);
11253 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed.");
11254 } /* for (all test cases) */
11255 } /* for (a number of different subroutine type declarations) */
11256 } /* for (all shader stages) */
11257
11258 /* Done */
11259 if (m_has_test_passed)
11260 {
11261 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
11262 }
11263 else
11264 {
11265 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
11266 }
11267
11268 return STOP;
11269 }
11270
11271 /** Constructor.
11272 *
11273 * @param context Rendering context.
11274 *
11275 **/
NegativeTest5(deqp::Context & context)11276 NegativeTest5::NegativeTest5(deqp::Context& context)
11277 : TestCase(context, "subroutine_uniform_wo_matching_subroutines",
11278 "Verifies that a link- or compile-time error occurs when "
11279 "trying to link a program with no subroutine for subroutine "
11280 "uniform variable.")
11281 , m_fs_id(0)
11282 , m_gs_id(0)
11283 , m_has_test_passed(true)
11284 , m_po_id(0)
11285 , m_tc_id(0)
11286 , m_te_id(0)
11287 , m_vs_id(0)
11288 {
11289 /* Left blank intentionally */
11290 }
11291
11292 /** Deinitializes all GL objects that may have been created during test execution */
deinit()11293 void NegativeTest5::deinit()
11294 {
11295 deinitIteration();
11296 }
11297
11298 /** Deinitializes all GL objects that may have been created during a single test
11299 * iteration.
11300 ***/
deinitIteration()11301 void NegativeTest5::deinitIteration()
11302 {
11303 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
11304
11305 if (m_fs_id != 0)
11306 {
11307 gl.deleteShader(m_fs_id);
11308
11309 m_fs_id = 0;
11310 }
11311
11312 if (m_gs_id != 0)
11313 {
11314 gl.deleteShader(m_gs_id);
11315
11316 m_gs_id = 0;
11317 }
11318
11319 if (m_po_id != 0)
11320 {
11321 gl.deleteProgram(m_po_id);
11322
11323 m_po_id = 0;
11324 }
11325
11326 if (m_tc_id != 0)
11327 {
11328 gl.deleteShader(m_tc_id);
11329
11330 m_tc_id = 0;
11331 }
11332
11333 if (m_te_id != 0)
11334 {
11335 gl.deleteShader(m_te_id);
11336
11337 m_te_id = 0;
11338 }
11339
11340 if (m_vs_id != 0)
11341 {
11342 gl.deleteShader(m_vs_id);
11343
11344 m_vs_id = 0;
11345 }
11346 }
11347
11348 /** Executes a single test iteration.
11349 *
11350 * If the iteration fails, m_has_test_passed will be set to false.
11351 *
11352 * @param shader_stage Shader stage, for which a subroutine uniform should be
11353 * declared in the shader without a matching subroutine.
11354 **/
executeIteration(const Utils::_shader_stage & shader_stage)11355 void NegativeTest5::executeIteration(const Utils::_shader_stage& shader_stage)
11356 {
11357 std::string fs_body = getFragmentShaderBody(shader_stage == Utils::SHADER_STAGE_FRAGMENT);
11358 std::string gs_body = getGeometryShaderBody(shader_stage == Utils::SHADER_STAGE_GEOMETRY);
11359 std::string tc_body = getTessellationControlShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_CONTROL);
11360 std::string te_body =
11361 getTessellationEvaluationShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_EVALUATION);
11362 std::string vs_body = getVertexShaderBody(shader_stage == Utils::SHADER_STAGE_VERTEX);
11363
11364 if (Utils::buildProgram(m_context.getRenderContext().getFunctions(), vs_body, tc_body, te_body, gs_body, fs_body,
11365 DE_NULL, /* xfb_varyings */
11366 DE_NULL, /* n_xfb_varyings */
11367 &m_vs_id, &m_tc_id, &m_te_id, &m_gs_id, &m_fs_id, &m_po_id))
11368 {
11369 /* None of the test programs should ever build successfully */
11370 m_testCtx.getLog() << tcu::TestLog::Message
11371 << "A program object, consisting of the following shaders, has linked"
11372 " correctly. One of the shaders defines a subroutine uniform but does "
11373 "not implement any function that matches subroutine type of the uniform."
11374 " This should have resulted in a compilation/link-time error.\n"
11375 "\n"
11376 "Vertex shader:\n"
11377 "\n"
11378 << vs_body << "\n"
11379 "Tessellation control shader:\n"
11380 "\n"
11381 << tc_body << "\n"
11382 "Tessellation evaluation shader:\n"
11383 "\n"
11384 << te_body << "\n"
11385 "Geometry shader:\n"
11386 "\n"
11387 << gs_body << "\n"
11388 "Fragment shader:\n"
11389 "\n"
11390 << fs_body << tcu::TestLog::EndMessage;
11391
11392 m_has_test_passed = false;
11393 }
11394 }
11395
11396 /** Retrieves fragment shader body.
11397 *
11398 * @param include_invalid_subroutine_uniform_declaration true if the shader should declare
11399 * a subroutine uniform without
11400 * a matching subroutine, false otherwise.
11401 *
11402 * @return Requested string.
11403 **/
getFragmentShaderBody(bool include_invalid_subroutine_uniform_declaration) const11404 std::string NegativeTest5::getFragmentShaderBody(bool include_invalid_subroutine_uniform_declaration) const
11405 {
11406 std::stringstream result_sstream;
11407
11408 result_sstream << "#version 400\n"
11409 "\n"
11410 "#extension GL_ARB_shader_subroutine : require\n"
11411 "\n";
11412
11413 if (include_invalid_subroutine_uniform_declaration)
11414 {
11415 result_sstream << "subroutine void subroutineTestTypeFS(out vec4 test);\n"
11416 "\n"
11417 "subroutine uniform subroutineTestTypeFS test_subroutineFS;\n";
11418 }
11419
11420 result_sstream << "\n"
11421 "out vec4 result;\n"
11422 "\n"
11423 "void main()\n"
11424 "{\n";
11425
11426 if (include_invalid_subroutine_uniform_declaration)
11427 {
11428 result_sstream << " test_subroutineFS(result);\n";
11429 }
11430 else
11431 {
11432 result_sstream << " result = vec4(0, 1, 2, 3);\n";
11433 }
11434
11435 result_sstream << "}\n";
11436
11437 return result_sstream.str();
11438 }
11439
11440 /** Retrieves geometry shader body.
11441 *
11442 * @param include_invalid_subroutine_uniform_declaration true if the shader should declare
11443 * a subroutine uniform without
11444 * a matching subroutine, false otherwise.
11445 *
11446 * @return Requested string.
11447 **/
getGeometryShaderBody(bool include_invalid_subroutine_uniform_declaration) const11448 std::string NegativeTest5::getGeometryShaderBody(bool include_invalid_subroutine_uniform_declaration) const
11449 {
11450 std::stringstream result_sstream;
11451
11452 result_sstream << "#version 400\n"
11453 "\n"
11454 "#extension GL_ARB_shader_subroutine : require\n"
11455 "\n"
11456 "layout (points) in;\n"
11457 "layout (points, max_vertices = 1) out;\n"
11458 "\n";
11459
11460 if (include_invalid_subroutine_uniform_declaration)
11461 {
11462 result_sstream << "subroutine void subroutineTestTypeGS(out vec4 test);\n"
11463 "\n"
11464 "subroutine uniform subroutineTestTypeGS test_subroutineGS;\n";
11465 }
11466
11467 result_sstream << "\n"
11468 "void main()\n"
11469 "{\n";
11470
11471 if (include_invalid_subroutine_uniform_declaration)
11472 {
11473 result_sstream << " test_subroutineGS(gl_Position);\n";
11474 }
11475 else
11476 {
11477 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
11478 }
11479
11480 result_sstream << "EmitVertex();\n"
11481 "}\n";
11482
11483 return result_sstream.str();
11484 }
11485
11486 /** Retrieves tessellation control shader body.
11487 *
11488 * @param include_invalid_subroutine_uniform_declaration true if the shader should declare
11489 * a subroutine uniform without
11490 * a matching subroutine, false otherwise.
11491 *
11492 * @return Requested string.
11493 **/
getTessellationControlShaderBody(bool include_invalid_subroutine_uniform_declaration) const11494 std::string NegativeTest5::getTessellationControlShaderBody(bool include_invalid_subroutine_uniform_declaration) const
11495 {
11496 std::stringstream result_sstream;
11497
11498 result_sstream << "#version 400\n"
11499 "\n"
11500 "#extension GL_ARB_shader_subroutine : require\n"
11501 "\n"
11502 "layout (vertices = 4) out;\n"
11503 "\n";
11504
11505 if (include_invalid_subroutine_uniform_declaration)
11506 {
11507 result_sstream << "subroutine void subroutineTestTypeTC(out vec4 test);\n"
11508 "\n"
11509 "subroutine uniform subroutineTestTypeTC test_subroutineTC;\n";
11510 }
11511
11512 result_sstream << "\n"
11513 "void main()\n"
11514 "{\n";
11515
11516 if (include_invalid_subroutine_uniform_declaration)
11517 {
11518 result_sstream << " test_subroutineTC(gl_out[gl_InvocationID].gl_Position);\n";
11519 }
11520 else
11521 {
11522 result_sstream << " gl_out[gl_InvocationID].gl_Position = vec4(0, 1, 2, 3);\n";
11523 }
11524
11525 result_sstream << "}\n";
11526
11527 return result_sstream.str();
11528 }
11529
11530 /** Retrieves tessellation evaluation body.
11531 *
11532 * @param include_invalid_subroutine_uniform_declaration true if the shader should declare
11533 * a subroutine uniform without
11534 * a matching subroutine, false otherwise.
11535 *
11536 * @return Requested string.
11537 **/
getTessellationEvaluationShaderBody(bool include_invalid_subroutine_uniform_declaration) const11538 std::string NegativeTest5::getTessellationEvaluationShaderBody(
11539 bool include_invalid_subroutine_uniform_declaration) const
11540 {
11541 std::stringstream result_sstream;
11542
11543 result_sstream << "#version 400\n"
11544 "\n"
11545 "#extension GL_ARB_shader_subroutine : require\n"
11546 "\n"
11547 "layout (quads) in;\n"
11548 "\n";
11549
11550 if (include_invalid_subroutine_uniform_declaration)
11551 {
11552 result_sstream << "subroutine void subroutineTestTypeTE(out vec4 test);\n"
11553 "\n"
11554 "subroutine uniform subroutineTestTypeTE test_subroutineTE;\n";
11555 }
11556
11557 result_sstream << "\n"
11558 "void main()\n"
11559 "{\n";
11560
11561 if (include_invalid_subroutine_uniform_declaration)
11562 {
11563 result_sstream << " test_subroutineTE(gl_Position);\n";
11564 }
11565 else
11566 {
11567 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
11568 }
11569
11570 result_sstream << "}\n";
11571
11572 return result_sstream.str();
11573 }
11574
11575 /** Retrieves vertex shader body.
11576 *
11577 * @param include_invalid_subroutine_uniform_declaration true if the shader should declare
11578 * a subroutine uniform without
11579 * a matching subroutine, false otherwise.
11580 *
11581 * @return Requested string.
11582 **/
getVertexShaderBody(bool include_invalid_subroutine_uniform_declaration) const11583 std::string NegativeTest5::getVertexShaderBody(bool include_invalid_subroutine_uniform_declaration) const
11584 {
11585 std::stringstream result_sstream;
11586
11587 result_sstream << "#version 400\n"
11588 "\n"
11589 "#extension GL_ARB_shader_subroutine : require\n"
11590 "\n";
11591
11592 if (include_invalid_subroutine_uniform_declaration)
11593 {
11594 result_sstream << "subroutine void subroutineTestTypeVS(out vec4 test);\n"
11595 "\n"
11596 "subroutine uniform subroutineTestTypeVS test_subroutineVS;\n";
11597 }
11598
11599 result_sstream << "\n"
11600 "void main()\n"
11601 "{\n";
11602
11603 if (include_invalid_subroutine_uniform_declaration)
11604 {
11605 result_sstream << " test_subroutineVS(gl_Position);\n";
11606 }
11607 else
11608 {
11609 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
11610 }
11611
11612 result_sstream << "}\n";
11613
11614 return result_sstream.str();
11615 }
11616
11617 /** Executes test iteration.
11618 *
11619 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
11620 */
iterate()11621 tcu::TestNode::IterateResult NegativeTest5::iterate()
11622 {
11623 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
11624 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
11625 {
11626 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
11627 }
11628
11629 /* Iterate over all shader stages. Iteration-specific shader stage defines a subroutine type &
11630 * a corresponding subroutine uniform, for which no compatible subroutines are available. All
11631 * other shader stages are defined correctly.
11632 */
11633 for (int shader_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
11634 shader_stage < static_cast<int>(Utils::SHADER_STAGE_COUNT); ++shader_stage)
11635 {
11636 executeIteration(static_cast<Utils::_shader_stage>(shader_stage));
11637 deinitIteration();
11638 } /* for (all shader stages) */
11639
11640 /* All done */
11641 if (m_has_test_passed)
11642 {
11643 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
11644 }
11645 else
11646 {
11647 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
11648 }
11649
11650 return STOP;
11651 }
11652
11653 /** Constructor.
11654 *
11655 * @param context Rendering context.
11656 *
11657 **/
NegativeTest6(deqp::Context & context)11658 NegativeTest6::NegativeTest6(deqp::Context& context)
11659 : TestCase(context, "two_duplicate_functions_one_being_a_subroutine",
11660 "Verifies that a link- or compile-time error occurs if any shader in "
11661 "a program object includes two functions with the same name and one "
11662 "of which is associated with a subroutine type.")
11663 , m_fs_id(0)
11664 , m_gs_id(0)
11665 , m_has_test_passed(true)
11666 , m_po_id(0)
11667 , m_tc_id(0)
11668 , m_te_id(0)
11669 , m_vs_id(0)
11670 {
11671 /* Left blank intentionally */
11672 }
11673
11674 /** Deinitializes all GL objects that may have been created during test execution */
deinit()11675 void NegativeTest6::deinit()
11676 {
11677 deinitIteration();
11678 }
11679
11680 /** Deinitializes all GL objects that may have been created during a single test
11681 * iteration.
11682 ***/
deinitIteration()11683 void NegativeTest6::deinitIteration()
11684 {
11685 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
11686
11687 if (m_fs_id != 0)
11688 {
11689 gl.deleteShader(m_fs_id);
11690
11691 m_fs_id = 0;
11692 }
11693
11694 if (m_gs_id != 0)
11695 {
11696 gl.deleteShader(m_gs_id);
11697
11698 m_gs_id = 0;
11699 }
11700
11701 if (m_po_id != 0)
11702 {
11703 gl.deleteProgram(m_po_id);
11704
11705 m_po_id = 0;
11706 }
11707
11708 if (m_tc_id != 0)
11709 {
11710 gl.deleteShader(m_tc_id);
11711
11712 m_tc_id = 0;
11713 }
11714
11715 if (m_te_id != 0)
11716 {
11717 gl.deleteShader(m_te_id);
11718
11719 m_te_id = 0;
11720 }
11721
11722 if (m_vs_id != 0)
11723 {
11724 gl.deleteShader(m_vs_id);
11725
11726 m_vs_id = 0;
11727 }
11728 }
11729
11730 /** Executes a single test iteration.
11731 *
11732 * If the iteration fails, m_has_test_passed will be set to false.
11733 *
11734 * @param shader_stage Shader stage, for which two duplicate functions
11735 * (one additionally marked as subroutine) should
11736 * be defined.
11737 **/
executeIteration(const Utils::_shader_stage & shader_stage)11738 void NegativeTest6::executeIteration(const Utils::_shader_stage& shader_stage)
11739 {
11740 std::string fs_body = getFragmentShaderBody(shader_stage == Utils::SHADER_STAGE_FRAGMENT);
11741 std::string gs_body = getGeometryShaderBody(shader_stage == Utils::SHADER_STAGE_GEOMETRY);
11742 std::string tc_body = getTessellationControlShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_CONTROL);
11743 std::string te_body =
11744 getTessellationEvaluationShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_EVALUATION);
11745 std::string vs_body = getVertexShaderBody(shader_stage == Utils::SHADER_STAGE_VERTEX);
11746
11747 if (Utils::buildProgram(m_context.getRenderContext().getFunctions(), vs_body, tc_body, te_body, gs_body, fs_body,
11748 DE_NULL, /* xfb_varyings */
11749 DE_NULL, /* n_xfb_varyings */
11750 &m_vs_id, &m_tc_id, &m_te_id, &m_gs_id, &m_fs_id, &m_po_id))
11751 {
11752 /* None of the test programs should ever build successfully */
11753 m_testCtx.getLog() << tcu::TestLog::Message
11754 << "A program object, consisting of the following shaders, has linked"
11755 " correctly. This is invalid, because one of the shaders defines two"
11756 " functions with the same name, with an exception that one of the"
11757 " functions is marked as a subroutine.\n"
11758 "\n"
11759 "Vertex shader:\n"
11760 "\n"
11761 << vs_body << "\n"
11762 "Tessellation control shader:\n"
11763 "\n"
11764 << tc_body << "\n"
11765 "Tessellation evaluation shader:\n"
11766 "\n"
11767 << te_body << "\n"
11768 "Geometry shader:\n"
11769 "\n"
11770 << gs_body << "\n"
11771 "Fragment shader:\n"
11772 "\n"
11773 << fs_body << tcu::TestLog::EndMessage;
11774
11775 m_has_test_passed = false;
11776 }
11777 }
11778
11779 /** Retrieves fragment shader body.
11780 *
11781 * @param include_invalid_declaration true if the shader should include duplicate function
11782 * declaration.
11783 *
11784 * @return Requested string.
11785 **/
getFragmentShaderBody(bool include_invalid_declaration) const11786 std::string NegativeTest6::getFragmentShaderBody(bool include_invalid_declaration) const
11787 {
11788 std::stringstream result_sstream;
11789
11790 result_sstream << "#version 400\n"
11791 "\n"
11792 "#extension GL_ARB_shader_subroutine : require\n"
11793 "\n";
11794
11795 if (include_invalid_declaration)
11796 {
11797 result_sstream << "subroutine void subroutineTestTypeFS(out vec4 test);\n"
11798 "\n"
11799 "subroutine(subroutineTestTypeFS) void test_impl1(out vec4 test)\n"
11800 "{\n"
11801 " test = vec4(1, 2, 3, 4);\n"
11802 "}\n"
11803 "\n"
11804 "void test_impl1(out vec4 test)\n"
11805 "{\n"
11806 " test = vec4(2, 3, 4, 5);\n"
11807 "}\n"
11808 "\n"
11809 "subroutine uniform subroutineTestTypeFS test_subroutineFS;\n";
11810 }
11811
11812 result_sstream << "\n"
11813 "out vec4 result;\n"
11814 "\n"
11815 "void main()\n"
11816 "{\n";
11817
11818 if (include_invalid_declaration)
11819 {
11820 result_sstream << " test_subroutineFS(result);\n";
11821 }
11822 else
11823 {
11824 result_sstream << " result = vec4(0, 1, 2, 3);\n";
11825 }
11826
11827 result_sstream << "}\n";
11828
11829 return result_sstream.str();
11830 }
11831
11832 /** Retrieves geometry shader body.
11833 *
11834 * @param include_invalid_declaration true if the shader should include duplicate function
11835 * declaration.
11836 *
11837 * @return Requested string.
11838 **/
getGeometryShaderBody(bool include_invalid_declaration) const11839 std::string NegativeTest6::getGeometryShaderBody(bool include_invalid_declaration) const
11840 {
11841 std::stringstream result_sstream;
11842
11843 result_sstream << "#version 400\n"
11844 "\n"
11845 "#extension GL_ARB_shader_subroutine : require\n"
11846 "\n"
11847 "layout (points) in;\n"
11848 "layout (points, max_vertices = 1) out;\n"
11849 "\n";
11850
11851 if (include_invalid_declaration)
11852 {
11853 result_sstream << "subroutine void subroutineTestTypeGS(out vec4 test);\n"
11854 "\n"
11855 "subroutine(subroutineTestTypeGS) void test_impl1(out vec4 test)\n"
11856 "{\n"
11857 " test = vec4(1, 2, 3, 4);\n"
11858 "}\n"
11859 "\n"
11860 "void test_impl1(out vec4 test)\n"
11861 "{\n"
11862 " test = vec4(2, 3, 4, 5);\n"
11863 "}\n"
11864 "\n"
11865 "subroutine uniform subroutineTestTypeGS test_subroutineGS;\n";
11866 }
11867
11868 result_sstream << "\n"
11869 "void main()\n"
11870 "{\n";
11871
11872 if (include_invalid_declaration)
11873 {
11874 result_sstream << " test_subroutineGS(gl_Position);\n";
11875 }
11876 else
11877 {
11878 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
11879 }
11880
11881 result_sstream << "EmitVertex();\n"
11882 "}\n";
11883
11884 return result_sstream.str();
11885 }
11886
11887 /** Retrieves tessellation control shader body.
11888 *
11889 * @param include_invalid_declaration true if the shader should include duplicate function
11890 * declaration.
11891 *
11892 * @return Requested string.
11893 **/
getTessellationControlShaderBody(bool include_invalid_declaration) const11894 std::string NegativeTest6::getTessellationControlShaderBody(bool include_invalid_declaration) const
11895 {
11896 std::stringstream result_sstream;
11897
11898 result_sstream << "#version 400\n"
11899 "\n"
11900 "#extension GL_ARB_shader_subroutine : require\n"
11901 "\n"
11902 "layout (vertices = 4) out;\n"
11903 "\n";
11904
11905 if (include_invalid_declaration)
11906 {
11907 result_sstream << "subroutine void subroutineTestTypeTC(out vec4 test);\n"
11908 "\n"
11909 "subroutine(subroutineTestTypeTC) void test_impl1(out vec4 test)\n"
11910 "{\n"
11911 " test = vec4(1, 2, 3, 4);\n"
11912 "}\n"
11913 "\n"
11914 "void test_impl1(out vec4 test)\n"
11915 "{\n"
11916 " test = vec4(2, 3, 4, 5);\n"
11917 "}\n"
11918 "\n"
11919 "subroutine uniform subroutineTestTypeTC test_subroutineTC;\n";
11920 }
11921
11922 result_sstream << "\n"
11923 "void main()\n"
11924 "{\n";
11925
11926 if (include_invalid_declaration)
11927 {
11928 result_sstream << " test_subroutineTC(gl_out[gl_InvocationID].gl_Position);\n";
11929 }
11930 else
11931 {
11932 result_sstream << " gl_out[gl_InvocationID].gl_Position = vec4(0, 1, 2, 3);\n";
11933 }
11934
11935 result_sstream << "}\n";
11936
11937 return result_sstream.str();
11938 }
11939
11940 /** Retrieves tessellation evaluation body.
11941 *
11942 * @param include_invalid_declaration true if the shader should include duplicate function
11943 * declaration.
11944 *
11945 * @return Requested string.
11946 **/
getTessellationEvaluationShaderBody(bool include_invalid_declaration) const11947 std::string NegativeTest6::getTessellationEvaluationShaderBody(bool include_invalid_declaration) const
11948 {
11949 std::stringstream result_sstream;
11950
11951 result_sstream << "#version 400\n"
11952 "\n"
11953 "#extension GL_ARB_shader_subroutine : require\n"
11954 "\n"
11955 "layout (quads) in;\n"
11956 "\n";
11957
11958 if (include_invalid_declaration)
11959 {
11960 result_sstream << "subroutine void subroutineTestTypeTE(out vec4 test);\n"
11961 "\n"
11962 "subroutine(subroutineTestTypeTE) void test_impl1(out vec4 test)\n"
11963 "{\n"
11964 " test = vec4(1, 2, 3, 4);\n"
11965 "}\n"
11966 "\n"
11967 "void test_impl1(out vec4 test)\n"
11968 "{\n"
11969 " test = vec4(2, 3, 4, 5);\n"
11970 "}\n"
11971 "\n"
11972 "subroutine uniform subroutineTestTypeTE test_subroutineTE;\n";
11973 }
11974
11975 result_sstream << "\n"
11976 "void main()\n"
11977 "{\n";
11978
11979 if (include_invalid_declaration)
11980 {
11981 result_sstream << " test_subroutineTE(gl_Position);\n";
11982 }
11983 else
11984 {
11985 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
11986 }
11987
11988 result_sstream << "}\n";
11989
11990 return result_sstream.str();
11991 }
11992
11993 /** Retrieves vertex shader body.
11994 *
11995 * @param include_invalid_declaration true if the shader should include duplicate function
11996 * declaration.
11997 *
11998 * @return Requested string.
11999 **/
getVertexShaderBody(bool include_invalid_declaration) const12000 std::string NegativeTest6::getVertexShaderBody(bool include_invalid_declaration) const
12001 {
12002 std::stringstream result_sstream;
12003
12004 result_sstream << "#version 400\n"
12005 "\n"
12006 "#extension GL_ARB_shader_subroutine : require\n"
12007 "\n";
12008
12009 if (include_invalid_declaration)
12010 {
12011 result_sstream << "subroutine void subroutineTestTypeVS(out vec4 test);\n"
12012 "\n"
12013 "subroutine(subroutineTestTypeVS) void test_impl1(out vec4 test)\n"
12014 "{\n"
12015 " test = vec4(1, 2, 3, 4);\n"
12016 "}\n"
12017 "\n"
12018 "void test_impl1(out vec4 test)\n"
12019 "{\n"
12020 " test = vec4(2, 3, 4, 5);\n"
12021 "}\n"
12022 "\n"
12023 "subroutine uniform subroutineTestTypeVS test_subroutineVS;\n";
12024 }
12025
12026 result_sstream << "\n"
12027 "void main()\n"
12028 "{\n";
12029
12030 if (include_invalid_declaration)
12031 {
12032 result_sstream << " test_subroutineVS(gl_Position);\n";
12033 }
12034 else
12035 {
12036 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
12037 }
12038
12039 result_sstream << "}\n";
12040
12041 return result_sstream.str();
12042 }
12043
12044 /** Executes test iteration.
12045 *
12046 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
12047 */
iterate()12048 tcu::TestNode::IterateResult NegativeTest6::iterate()
12049 {
12050 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
12051 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
12052 {
12053 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
12054 }
12055
12056 /* Iterate over all shader stages. In each iteration, we will inject invalid
12057 * duplicate function declarations to iteration-specific shader stage. All other
12058 * shader stages will be assigned valid bodies. Test should fail if the program
12059 * links successfully.
12060 */
12061 for (int shader_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
12062 shader_stage < static_cast<int>(Utils::SHADER_STAGE_COUNT); ++shader_stage)
12063 {
12064 executeIteration(static_cast<Utils::_shader_stage>(shader_stage));
12065 deinitIteration();
12066 } /* for (all shader stages) */
12067
12068 /* All done */
12069 if (m_has_test_passed)
12070 {
12071 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
12072 }
12073 else
12074 {
12075 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
12076 }
12077
12078 return STOP;
12079 }
12080
12081 /** Constructor
12082 *
12083 * @param context CTS context
12084 **/
NegativeTest7(deqp::Context & context)12085 NegativeTest7::NegativeTest7(deqp::Context& context)
12086 : TestCase(context, "recursion", "Verify that it is not possible to build program with recursing subroutines")
12087 , m_program_id(0)
12088 , m_vertex_shader_id(0)
12089 {
12090 /* Nothing to be done here */
12091 }
12092
12093 /** Deinitializes all GL objects that may have been created during test execution
12094 *
12095 **/
deinit()12096 void NegativeTest7::deinit()
12097 {
12098 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
12099
12100 if (m_program_id != 0)
12101 {
12102 gl.deleteProgram(m_program_id);
12103
12104 m_program_id = 0;
12105 }
12106
12107 if (m_vertex_shader_id != 0)
12108 {
12109 gl.deleteShader(m_vertex_shader_id);
12110
12111 m_vertex_shader_id = 0;
12112 }
12113 }
12114
12115 /** Executes test iteration.
12116 *
12117 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
12118 **/
iterate()12119 tcu::TestNode::IterateResult NegativeTest7::iterate()
12120 {
12121 static const GLchar* vertex_shader_with_static_recursion =
12122 "#version 400\n"
12123 "\n"
12124 "#extension GL_ARB_shader_subroutine : require\n"
12125 "\n"
12126 "precision highp float;\n"
12127 "\n"
12128 "subroutine vec4 routine_type(in vec4 data, in uint control);\n"
12129 "\n"
12130 "subroutine (routine_type) vec4 power_routine(in vec4 data, in uint control)\n"
12131 "{\n"
12132 " if (0 != control)\n"
12133 " {\n"
12134 " return data * power_routine(data, control - 1);\n"
12135 " }\n"
12136 " else\n"
12137 " {\n"
12138 " return vec4(1, 1, 1, 1);\n"
12139 " }\n"
12140 "}\n"
12141 "\n"
12142 "subroutine (routine_type) vec4 select_routine(in vec4 data, in uint control)\n"
12143 "{\n"
12144 " if (0 == control)\n"
12145 " {\n"
12146 " return data.rrrr;\n"
12147 " }\n"
12148 " else if (1 == control)\n"
12149 " {\n"
12150 " return data.gggg;\n"
12151 " }\n"
12152 " else if (2 == control)\n"
12153 " {\n"
12154 " return data.bbbb;\n"
12155 " }\n"
12156 " else\n"
12157 " {\n"
12158 " return data.aaaa;\n"
12159 " }\n"
12160 "}\n"
12161 "\n"
12162 "subroutine uniform routine_type routine;\n"
12163 "\n"
12164 "uniform vec4 uni_value;\n"
12165 "uniform uint uni_control;\n"
12166 "\n"
12167 "out vec4 out_result;\n"
12168 "\n"
12169 "void main()\n"
12170 "{\n"
12171 " out_result = routine(uni_value, uni_control);\n"
12172 "}\n"
12173 "\n";
12174
12175 static const GLchar* vertex_shader_with_dynamic_recursion =
12176 "#version 400\n"
12177 "\n"
12178 "#extension GL_ARB_shader_subroutine : require\n"
12179 "\n"
12180 "precision highp float;\n"
12181 "\n"
12182 "subroutine vec4 routine_type(in vec4 data);\n"
12183 "\n"
12184 "subroutine uniform routine_type routine;\n"
12185 "\n"
12186 "subroutine (routine_type) vec4 div_by_2(in vec4 data)\n"
12187 "{\n"
12188 " return data / 2;\n"
12189 "}\n"
12190 "\n"
12191 "subroutine (routine_type) vec4 div_routine_result_by_2(in vec4 data)\n"
12192 "{\n"
12193 " return routine(data) / 2;\n"
12194 "}\n"
12195 "\n"
12196 "uniform vec4 uni_value;\n"
12197 "\n"
12198 "out vec4 out_result;\n"
12199 "\n"
12200 "void main()\n"
12201 "{\n"
12202 " out_result = routine(uni_value);\n"
12203 "}\n"
12204 "\n";
12205
12206 static const GLchar* vertex_shader_with_subroutine_function_recursion =
12207 "#version 400\n"
12208 "\n"
12209 "#extension GL_ARB_shader_subroutine : require\n"
12210 "\n"
12211 "precision highp float;\n"
12212 "\n"
12213 "subroutine vec4 routine_type(in vec4 data);\n"
12214 "\n"
12215 "subroutine uniform routine_type routine;\n"
12216 "\n"
12217 "vec4 function(in vec4 data)\n"
12218 "{\n"
12219 " return routine(data) + vec4(0.5, 0.5, 0.5, 0.5);\n"
12220 "}\n"
12221 "\n"
12222 "subroutine (routine_type) vec4 routine_a(in vec4 data)\n"
12223 "{\n"
12224 " return function(data) / 2;\n"
12225 "}\n"
12226 "\n"
12227 "subroutine (routine_type) vec4 routine_b(in vec4 data)\n"
12228 "{\n"
12229 " return routine_a(data) * 2;\n"
12230 "}\n"
12231 "\n"
12232 "uniform vec4 uni_value;\n"
12233 "\n"
12234 "out vec4 out_result;\n"
12235 "\n"
12236 "void main()\n"
12237 "{\n"
12238 " out_result = routine(uni_value);\n"
12239 "}\n"
12240 "\n";
12241
12242 bool result = true;
12243
12244 if (false == test(vertex_shader_with_subroutine_function_recursion, "routine_a"))
12245 {
12246 result = false;
12247 }
12248
12249 if (false == test(vertex_shader_with_dynamic_recursion, "div_routine_result_by_2"))
12250 {
12251 result = false;
12252 }
12253
12254 if (false == test(vertex_shader_with_static_recursion, "power_routine"))
12255 {
12256 result = false;
12257 }
12258
12259 /* Set result */
12260 if (true == result)
12261 {
12262 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
12263 }
12264 else
12265 {
12266 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
12267 }
12268
12269 /* Done */
12270 return tcu::TestNode::STOP;
12271 }
12272
12273 /** Try to build program from vertex shader code.
12274 *
12275 * @param vertex_shader_code Source code of vertex shader
12276 * @param name_of_recursive_routine Name of subroutine that should cause link failure due to recursion
12277 *
12278 * @return true build process failed, false otherwise
12279 **/
test(const GLchar * vertex_shader_code,const GLchar * name_of_recursive_routine)12280 bool NegativeTest7::test(const GLchar* vertex_shader_code, const GLchar* name_of_recursive_routine)
12281 {
12282 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
12283 bool result = true;
12284 static const GLchar* varying_name = "out_result";
12285
12286 /* Try to build program */
12287 if (true == Utils::buildProgram(gl, vertex_shader_code, "", "", "", "", &varying_name /* varying_names */,
12288 1 /* n_varyings */, &m_vertex_shader_id, 0, 0, 0, 0, &m_program_id))
12289 {
12290 /* Success is considered an error */
12291
12292 Utils::program program(m_context);
12293 GLuint index = 0;
12294
12295 program.build(0, 0, 0, 0, 0, vertex_shader_code, 0, 0);
12296
12297 /* Verify that recursive subroutine is active */
12298 try
12299 {
12300 index = program.getSubroutineIndex(name_of_recursive_routine, GL_VERTEX_SHADER);
12301 }
12302 catch (const std::exception& exc)
12303 {
12304 /* Something wrong with shader or compilation */
12305 m_context.getTestContext().getLog()
12306 << tcu::TestLog::Message << "It is expected that subroutine: \n"
12307 << name_of_recursive_routine
12308 << " is considered active. This subroutine is potentially recursive and should cause link failure."
12309 << tcu::TestLog::EndMessage;
12310
12311 throw exc;
12312 }
12313
12314 /* Subsoutine is active, however linking should fail */
12315 m_context.getTestContext().getLog()
12316 << tcu::TestLog::Message << "Error. Program with potentially recursive subroutine, "
12317 << name_of_recursive_routine << ", which is active, index: " << index << ", has been built successfully.\n"
12318 << vertex_shader_code << tcu::TestLog::EndMessage;
12319
12320 result = false;
12321 }
12322
12323 /* Delete program and shader */
12324 deinit();
12325
12326 /* Done */
12327 return result;
12328 }
12329
12330 /** Constructor.
12331 *
12332 * @param context Rendering context.
12333 *
12334 **/
NegativeTest8(deqp::Context & context)12335 NegativeTest8::NegativeTest8(deqp::Context& context)
12336 : TestCase(context, "subroutine_wo_body", "Verifies that a compile- or link-time error occurs if a function "
12337 "declared as a subroutine does not include a body.")
12338 , m_fs_id(0)
12339 , m_gs_id(0)
12340 , m_has_test_passed(true)
12341 , m_po_id(0)
12342 , m_tc_id(0)
12343 , m_te_id(0)
12344 , m_vs_id(0)
12345 {
12346 /* Left blank intentionally */
12347 }
12348
12349 /** Deinitializes all GL objects that may have been created during test execution */
deinit()12350 void NegativeTest8::deinit()
12351 {
12352 deinitIteration();
12353 }
12354
12355 /** Deinitializes all GL objects that may have been created during a single test
12356 * iteration.
12357 ***/
deinitIteration()12358 void NegativeTest8::deinitIteration()
12359 {
12360 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
12361
12362 if (m_fs_id != 0)
12363 {
12364 gl.deleteShader(m_fs_id);
12365
12366 m_fs_id = 0;
12367 }
12368
12369 if (m_gs_id != 0)
12370 {
12371 gl.deleteShader(m_gs_id);
12372
12373 m_gs_id = 0;
12374 }
12375
12376 if (m_po_id != 0)
12377 {
12378 gl.deleteProgram(m_po_id);
12379
12380 m_po_id = 0;
12381 }
12382
12383 if (m_tc_id != 0)
12384 {
12385 gl.deleteShader(m_tc_id);
12386
12387 m_tc_id = 0;
12388 }
12389
12390 if (m_te_id != 0)
12391 {
12392 gl.deleteShader(m_te_id);
12393
12394 m_te_id = 0;
12395 }
12396
12397 if (m_vs_id != 0)
12398 {
12399 gl.deleteShader(m_vs_id);
12400
12401 m_vs_id = 0;
12402 }
12403 }
12404
12405 /** Executes a single test iteration.
12406 *
12407 * If the iteration fails, m_has_test_passed will be set to false.
12408 *
12409 * @param shader_stage Shader stage, for which two duplicate functions
12410 * (one additionally marked as subroutine) should
12411 * be defined.
12412 **/
executeIteration(const Utils::_shader_stage & shader_stage)12413 void NegativeTest8::executeIteration(const Utils::_shader_stage& shader_stage)
12414 {
12415 std::string fs_body = getFragmentShaderBody(shader_stage == Utils::SHADER_STAGE_FRAGMENT);
12416 std::string gs_body = getGeometryShaderBody(shader_stage == Utils::SHADER_STAGE_GEOMETRY);
12417 std::string tc_body = getTessellationControlShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_CONTROL);
12418 std::string te_body =
12419 getTessellationEvaluationShaderBody(shader_stage == Utils::SHADER_STAGE_TESSELLATION_EVALUATION);
12420 std::string vs_body = getVertexShaderBody(shader_stage == Utils::SHADER_STAGE_VERTEX);
12421
12422 if (Utils::buildProgram(m_context.getRenderContext().getFunctions(), vs_body, tc_body, te_body, gs_body, fs_body,
12423 DE_NULL, /* xfb_varyings */
12424 DE_NULL, /* n_xfb_varyings */
12425 &m_vs_id, &m_tc_id, &m_te_id, &m_gs_id, &m_fs_id, &m_po_id))
12426 {
12427 /* None of the test programs should ever build successfully */
12428 m_testCtx.getLog() << tcu::TestLog::Message
12429 << "A program object consisting of FS+GS+TC+TE+VS stages has linked successfully, "
12430 "even though one of the shaders only defines a subroutine that lacks any body."
12431 "\n"
12432 "Vertex shader:\n"
12433 "\n"
12434 << vs_body << "\n"
12435 "Tessellation control shader:\n"
12436 "\n"
12437 << tc_body << "\n"
12438 "Tessellation evaluation shader:\n"
12439 "\n"
12440 << te_body << "\n"
12441 "Geometry shader:\n"
12442 "\n"
12443 << gs_body << "\n"
12444 "Fragment shader:\n"
12445 "\n"
12446 << fs_body << tcu::TestLog::EndMessage;
12447
12448 m_has_test_passed = false;
12449 }
12450 }
12451
12452 /** Retrieves fragment shader body.
12453 *
12454 * @param include_invalid_declaration true if a subroutine prototype should be included in
12455 * the shader, false to skip it.
12456 *
12457 * @return Requested string.
12458 **/
getFragmentShaderBody(bool include_invalid_declaration) const12459 std::string NegativeTest8::getFragmentShaderBody(bool include_invalid_declaration) const
12460 {
12461 std::stringstream result_sstream;
12462
12463 result_sstream << "#version 400\n"
12464 "\n"
12465 "#extension GL_ARB_shader_subroutine : require\n"
12466 "\n";
12467
12468 if (include_invalid_declaration)
12469 {
12470 result_sstream << "subroutine void subroutineTestTypeFS(out vec4 test);\n"
12471 "\n"
12472 "subroutine(subroutineTestTypeFS) void test_impl1(out vec4 test);\n"
12473 "\n"
12474 "subroutine uniform subroutineTestTypeFS test_subroutineFS;\n";
12475 }
12476
12477 result_sstream << "\n"
12478 "out vec4 result;\n"
12479 "\n"
12480 "void main()\n"
12481 "{\n";
12482
12483 if (include_invalid_declaration)
12484 {
12485 result_sstream << " test_subroutineFS(result);\n";
12486 }
12487 else
12488 {
12489 result_sstream << " result = vec4(0, 1, 2, 3);\n";
12490 }
12491
12492 result_sstream << "}\n";
12493
12494 return result_sstream.str();
12495 }
12496
12497 /** Retrieves geometry shader body.
12498 *
12499 * @param include_invalid_declaration true if a subroutine prototype should be included in
12500 * the shader, false to skip it.
12501 *
12502 * @return Requested string.
12503 **/
getGeometryShaderBody(bool include_invalid_declaration) const12504 std::string NegativeTest8::getGeometryShaderBody(bool include_invalid_declaration) const
12505 {
12506 std::stringstream result_sstream;
12507
12508 result_sstream << "#version 400\n"
12509 "\n"
12510 "#extension GL_ARB_shader_subroutine : require\n"
12511 "\n"
12512 "layout (points) in;\n"
12513 "layout (points, max_vertices = 1) out;\n"
12514 "\n";
12515
12516 if (include_invalid_declaration)
12517 {
12518 result_sstream << "subroutine void subroutineTestTypeGS(out vec4 test);\n"
12519 "\n"
12520 "subroutine(subroutineTestTypeGS) void test_impl1(out vec4 test);\n"
12521 "\n"
12522 "subroutine uniform subroutineTestTypeGS test_subroutineGS;\n";
12523 }
12524
12525 result_sstream << "\n"
12526 "void main()\n"
12527 "{\n";
12528
12529 if (include_invalid_declaration)
12530 {
12531 result_sstream << " test_subroutineGS(gl_Position);\n";
12532 }
12533 else
12534 {
12535 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
12536 }
12537
12538 result_sstream << "EmitVertex();\n"
12539 "}\n";
12540
12541 return result_sstream.str();
12542 }
12543
12544 /** Retrieves tessellation control shader body.
12545 *
12546 * @param include_invalid_declaration true if a subroutine prototype should be included in
12547 * the shader, false to skip it.
12548 *
12549 * @return Requested string.
12550 **/
getTessellationControlShaderBody(bool include_invalid_declaration) const12551 std::string NegativeTest8::getTessellationControlShaderBody(bool include_invalid_declaration) const
12552 {
12553 std::stringstream result_sstream;
12554
12555 result_sstream << "#version 400\n"
12556 "\n"
12557 "#extension GL_ARB_shader_subroutine : require\n"
12558 "\n"
12559 "layout (vertices = 4) out;\n"
12560 "\n";
12561
12562 if (include_invalid_declaration)
12563 {
12564 result_sstream << "subroutine void subroutineTestTypeTC(out vec4 test);\n"
12565 "\n"
12566 "subroutine(subroutineTestTypeTC) void test_impl1(out vec4 test);\n"
12567 "\n"
12568 "subroutine uniform subroutineTestTypeTC test_subroutineTC;\n";
12569 }
12570
12571 result_sstream << "\n"
12572 "void main()\n"
12573 "{\n";
12574
12575 if (include_invalid_declaration)
12576 {
12577 result_sstream << " test_subroutineTC(gl_out[gl_InvocationID].gl_Position);\n";
12578 }
12579 else
12580 {
12581 result_sstream << " gl_out[gl_InvocationID].gl_Position = vec4(0, 1, 2, 3);\n";
12582 }
12583
12584 result_sstream << "}\n";
12585
12586 return result_sstream.str();
12587 }
12588
12589 /** Retrieves tessellation evaluation body.
12590 *
12591 * @param include_invalid_declaration true if a subroutine prototype should be included in
12592 * the shader, false to skip it.
12593 *
12594 * @return Requested string.
12595 **/
getTessellationEvaluationShaderBody(bool include_invalid_declaration) const12596 std::string NegativeTest8::getTessellationEvaluationShaderBody(bool include_invalid_declaration) const
12597 {
12598 std::stringstream result_sstream;
12599
12600 result_sstream << "#version 400\n"
12601 "\n"
12602 "#extension GL_ARB_shader_subroutine : require\n"
12603 "\n"
12604 "layout (quads) in;\n"
12605 "\n";
12606
12607 if (include_invalid_declaration)
12608 {
12609 result_sstream << "subroutine void subroutineTestTypeTE(out vec4 test);\n"
12610 "\n"
12611 "subroutine(subroutineTestTypeTE) void test_impl1(out vec4 test);\n"
12612 "\n"
12613 "subroutine uniform subroutineTestTypeTE test_subroutineTE;\n";
12614 }
12615
12616 result_sstream << "\n"
12617 "void main()\n"
12618 "{\n";
12619
12620 if (include_invalid_declaration)
12621 {
12622 result_sstream << " test_subroutineTE(gl_Position);\n";
12623 }
12624 else
12625 {
12626 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
12627 }
12628
12629 result_sstream << "}\n";
12630
12631 return result_sstream.str();
12632 }
12633
12634 /** Retrieves vertex shader body.
12635 *
12636 * @param include_invalid_declaration true if a subroutine prototype should be included in
12637 * the shader, false to skip it.
12638 *
12639 * @return Requested string.
12640 **/
getVertexShaderBody(bool include_invalid_declaration) const12641 std::string NegativeTest8::getVertexShaderBody(bool include_invalid_declaration) const
12642 {
12643 std::stringstream result_sstream;
12644
12645 result_sstream << "#version 400\n"
12646 "\n"
12647 "#extension GL_ARB_shader_subroutine : require\n"
12648 "\n";
12649
12650 if (include_invalid_declaration)
12651 {
12652 result_sstream << "subroutine void subroutineTestTypeVS(out vec4 test);\n"
12653 "\n"
12654 "subroutine(subroutineTestTypeVS) void test_impl1(out vec4 test);\n"
12655 "\n"
12656 "subroutine uniform subroutineTestTypeVS test_subroutineVS;\n";
12657 }
12658
12659 result_sstream << "\n"
12660 "void main()\n"
12661 "{\n";
12662
12663 if (include_invalid_declaration)
12664 {
12665 result_sstream << " test_subroutineVS(gl_Position);\n";
12666 }
12667 else
12668 {
12669 result_sstream << " gl_Position = vec4(0, 1, 2, 3);\n";
12670 }
12671
12672 result_sstream << "}\n";
12673
12674 return result_sstream.str();
12675 }
12676
12677 /** Executes test iteration.
12678 *
12679 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
12680 */
iterate()12681 tcu::TestNode::IterateResult NegativeTest8::iterate()
12682 {
12683 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
12684 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
12685 {
12686 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
12687 }
12688
12689 /* Iterate over all shader stages. For each iteration, iteration-specific shader stage
12690 * will feature an invalid subroutine definition. Other shader stages will be assigned
12691 * valid bodies. The test fails if a program built of such shaders links successfully.
12692 */
12693 for (int shader_stage = static_cast<int>(Utils::SHADER_STAGE_FIRST);
12694 shader_stage < static_cast<int>(Utils::SHADER_STAGE_COUNT); ++shader_stage)
12695 {
12696 executeIteration(static_cast<Utils::_shader_stage>(shader_stage));
12697 deinitIteration();
12698 } /* for (all shader stages) */
12699
12700 /* All done */
12701 if (m_has_test_passed)
12702 {
12703 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
12704 }
12705 else
12706 {
12707 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
12708 }
12709
12710 return STOP;
12711 }
12712
12713 /** Constructor.
12714 *
12715 * @param context Rendering context.
12716 **/
NegativeTest9(deqp::Context & context)12717 NegativeTest9::NegativeTest9(deqp::Context& context)
12718 : TestCase(context, "subroutines_cannot_be_assigned_float_int_values_or_be_compared",
12719 "Make sure it is not possible to assign float/int to subroutine "
12720 "uniform and that subroutine uniform values cannot be compared.")
12721 , m_has_test_passed(true)
12722 , m_po_id(0)
12723 , m_vs_id(0)
12724 {
12725 /* Left blank intentionally */
12726 }
12727
12728 /** Deinitializes any GL objects that may have been created during
12729 * test execution.
12730 **/
deinit()12731 void NegativeTest9::deinit()
12732 {
12733 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
12734
12735 if (m_po_id != 0)
12736 {
12737 gl.deleteProgram(m_po_id);
12738
12739 m_po_id = 0;
12740 }
12741
12742 if (m_vs_id != 0)
12743 {
12744 gl.deleteShader(m_vs_id);
12745
12746 m_vs_id = 0;
12747 }
12748 }
12749
12750 /** Returns a literal corresponding to user-specified test case enum.
12751 *
12752 * @param test_case As per description.
12753 *
12754 * @return Requested string.
12755 **/
getTestCaseString(const _test_case & test_case)12756 std::string NegativeTest9::getTestCaseString(const _test_case& test_case)
12757 {
12758 std::string result = "?";
12759
12760 switch (test_case)
12761 {
12762 case TEST_CASE_INVALID_FLOAT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT:
12763 result = "TEST_CASE_INVALID_FLOAT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT";
12764 break;
12765 case TEST_CASE_INVALID_INT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT:
12766 result = "TEST_CASE_INVALID_INT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT";
12767 break;
12768 case TEST_CASE_INVALID_SUBROUTINE_UNIFORM_VALUE_COMPARISON:
12769 result = "TEST_CASE_INVALID_SUBROUTINE_UNIFORM_VALUE_COMPARISON";
12770 break;
12771 default:
12772 break;
12773 }
12774
12775 return result;
12776 }
12777
12778 /** Retrieves vertex shader body for user-specified test case.
12779 *
12780 * @param test_case As per description.
12781 *
12782 * @return Requested string.
12783 **/
getVertexShader(const _test_case & test_case)12784 std::string NegativeTest9::getVertexShader(const _test_case& test_case)
12785 {
12786 std::stringstream result_sstream;
12787
12788 /* Form pre-amble */
12789 result_sstream << "#version 400\n"
12790 "\n"
12791 "#extension GL_ARB_shader_subroutine : require\n"
12792 "\n"
12793 /* Define a subroutine */
12794 "subroutine void subroutineType(inout vec4 test);\n"
12795 "\n"
12796 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
12797 "{\n"
12798 " test += vec4(0, 1, 2, 3);\n"
12799 "}\n"
12800 "\n"
12801 "subroutine uniform subroutineType function;\n"
12802 "\n";
12803
12804 /* Include case-specific implementation */
12805 switch (test_case)
12806 {
12807 case TEST_CASE_INVALID_FLOAT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT:
12808 {
12809 result_sstream << "void main()\n"
12810 "{\n"
12811 " function = 1.0f;\n"
12812 "\n"
12813 " function(gl_Position);\n"
12814 "}\n";
12815
12816 break;
12817 }
12818
12819 case TEST_CASE_INVALID_INT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT:
12820 {
12821 result_sstream << "void main()\n"
12822 "{\n"
12823 " function = 1;\n"
12824 "\n"
12825 " function(gl_Position);\n"
12826 "}\n";
12827
12828 break;
12829 }
12830
12831 case TEST_CASE_INVALID_SUBROUTINE_UNIFORM_VALUE_COMPARISON:
12832 {
12833 result_sstream << "subroutine uniform subroutineType function2;\n"
12834 "\n"
12835 "void main()\n"
12836 "{\n"
12837 " if (function == function2)\n"
12838 " {\n"
12839 " function(gl_Position);\n"
12840 " }\n"
12841 " else\n"
12842 " {\n"
12843 " function2(gl_Position);\n"
12844 " }\n"
12845 "}\n";
12846
12847 break;
12848 }
12849
12850 default:
12851 break;
12852 } /* switch (test_case) */
12853
12854 /* Done */
12855 return result_sstream.str();
12856 }
12857
12858 /** Executes test iteration.
12859 *
12860 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
12861 */
iterate()12862 tcu::TestNode::IterateResult NegativeTest9::iterate()
12863 {
12864 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
12865
12866 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
12867 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
12868 {
12869 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
12870 }
12871
12872 /* Iterate over all test cases */
12873 for (int test_case = static_cast<int>(TEST_CASE_FIRST); test_case != static_cast<int>(TEST_CASE_COUNT); ++test_case)
12874 {
12875 /* Try to build a program object using invalid vertex shader, specific to the
12876 * iteration we're currently in */
12877 std::string vs_body = getVertexShader(static_cast<_test_case>(test_case));
12878
12879 if (ShaderSubroutine::Utils::buildProgram(gl, vs_body, "", /* tc_body */
12880 "", /* te_body */
12881 "", /* gs_body */
12882 "", /* fs_body */
12883 DE_NULL, /* xfb_varyings */
12884 0, /* n_xfb_varyings */
12885 &m_vs_id, DE_NULL, /* out_tc_id */
12886 DE_NULL, /* out_te_id */
12887 DE_NULL, /* out_gs_id */
12888 DE_NULL, /* out_fs_id */
12889 &m_po_id))
12890 {
12891 m_testCtx.getLog() << tcu::TestLog::Message << "A program object was successfully built for ["
12892 << getTestCaseString(static_cast<_test_case>(test_case))
12893 << "] test case, even though it was invalid." << tcu::TestLog::EndMessage;
12894
12895 m_has_test_passed = false;
12896 }
12897
12898 /* Delete any objects that may have been created */
12899 deinit();
12900 } /* for (all test cases) */
12901
12902 /** All done */
12903 if (m_has_test_passed)
12904 {
12905 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
12906 }
12907 else
12908 {
12909 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
12910 }
12911
12912 return STOP;
12913 }
12914
12915 /** Constructor.
12916 *
12917 * @param context Rendering context.
12918 **/
NegativeTest10(deqp::Context & context)12919 NegativeTest10::NegativeTest10(deqp::Context& context)
12920 : TestCase(context, "function_overloading_forbidden_for_subroutines",
12921 "Check that an overloaded function cannot be declared with subroutine and "
12922 "a program will fail to compile or link if any shader or stage contains"
12923 " two or more functions with the same name if the name is associated with"
12924 " a subroutine type.")
12925 , m_has_test_passed(true)
12926 , m_fs_id(0)
12927 , m_gs_id(0)
12928 , m_po_id(0)
12929 , m_tc_id(0)
12930 , m_te_id(0)
12931 , m_vs_id(0)
12932 {
12933 /* Left blank intentionally */
12934 }
12935
12936 /** Deinitializes any GL objects that may have been created during
12937 * test execution.
12938 **/
deinit()12939 void NegativeTest10::deinit()
12940 {
12941 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
12942
12943 if (m_fs_id != 0)
12944 {
12945 gl.deleteShader(m_fs_id);
12946
12947 m_fs_id = 0;
12948 }
12949
12950 if (m_gs_id != 0)
12951 {
12952 gl.deleteShader(m_gs_id);
12953
12954 m_gs_id = 0;
12955 }
12956
12957 if (m_po_id != 0)
12958 {
12959 gl.deleteProgram(m_po_id);
12960
12961 m_po_id = 0;
12962 }
12963
12964 if (m_tc_id != 0)
12965 {
12966 gl.deleteShader(m_tc_id);
12967
12968 m_tc_id = 0;
12969 }
12970
12971 if (m_te_id != 0)
12972 {
12973 gl.deleteShader(m_te_id);
12974
12975 m_te_id = 0;
12976 }
12977
12978 if (m_vs_id != 0)
12979 {
12980 gl.deleteShader(m_vs_id);
12981
12982 m_vs_id = 0;
12983 }
12984 }
12985
12986 /** Retrieves fragment shader that should be used for the purpose of the test.
12987 * An overloaded version of a subroutine function is inserted if
12988 * @param include_duplicate_function flag is set to true.
12989 *
12990 * @param include_duplicate_function As per description.
12991 *
12992 * @return Requested string.
12993 **/
getFragmentShader(bool include_duplicate_function)12994 std::string NegativeTest10::getFragmentShader(bool include_duplicate_function)
12995 {
12996 std::stringstream result_sstream;
12997
12998 result_sstream << "#version 400\n"
12999 "\n"
13000 "#extension GL_ARB_shader_subroutine : require\n"
13001 "\n"
13002 "subroutine void subroutineType(inout vec4 test);\n"
13003 "\n"
13004 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13005 "{\n"
13006 " test = vec4(2, 3, 4, 5);\n"
13007 "}\n"
13008 "\n"
13009 "subroutine uniform subroutineType function;\n"
13010 "out vec4 result;\n"
13011 "\n";
13012
13013 if (include_duplicate_function)
13014 {
13015 result_sstream << "void test_function(inout vec4 test)\n"
13016 "{\n"
13017 " test = vec4(3, 4, 5, 6);\n"
13018 "}\n"
13019 "\n";
13020 }
13021
13022 result_sstream << "void main()\n"
13023 "{\n"
13024 " test_function(result);\n"
13025 "}\n";
13026
13027 return result_sstream.str();
13028 }
13029
13030 /** Retrieves geometry shader that should be used for the purpose of the test.
13031 * An overloaded version of a subroutine function is inserted if
13032 * @param include_duplicate_function flag is set to true.
13033 *
13034 * @param include_duplicate_function As per description.
13035 *
13036 * @return Requested string.
13037 **/
getGeometryShader(bool include_duplicate_function)13038 std::string NegativeTest10::getGeometryShader(bool include_duplicate_function)
13039 {
13040 std::stringstream result_sstream;
13041
13042 result_sstream << "#version 400\n"
13043 "\n"
13044 "#extension GL_ARB_shader_subroutine : require\n"
13045 "\n"
13046 "layout (triangles) in;\n"
13047 "layout (triangle_strip, max_vertices = 4) out;\n"
13048 "\n"
13049 "subroutine void subroutineType(inout vec4 test);\n"
13050 "\n"
13051 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13052 "{\n"
13053 " test = vec4(2, 3, 4, 5);\n"
13054 "}\n"
13055 "\n"
13056 "subroutine uniform subroutineType function;\n"
13057 "\n";
13058
13059 if (include_duplicate_function)
13060 {
13061 result_sstream << "void test_function(inout vec4 test)\n"
13062 "{\n"
13063 " test = vec4(3, 4, 5, 6);\n"
13064 "}\n"
13065 "\n";
13066 }
13067
13068 result_sstream << "void main()\n"
13069 "{\n"
13070 " function(gl_Position);\n"
13071 " EmitVertex();\n"
13072 " EndPrimitive();\n"
13073 "}\n";
13074
13075 return result_sstream.str();
13076 }
13077
13078 /** Retrieves tess control shader that should be used for the purpose of the test.
13079 * An overloaded version of a subroutine function is inserted if
13080 * @param include_duplicate_function flag is set to true.
13081 *
13082 * @param include_duplicate_function As per description.
13083 *
13084 * @return Requested string.
13085 **/
getTessellationControlShader(bool include_duplicate_function)13086 std::string NegativeTest10::getTessellationControlShader(bool include_duplicate_function)
13087 {
13088 std::stringstream result_sstream;
13089
13090 result_sstream << "#version 400\n"
13091 "\n"
13092 "#extension GL_ARB_shader_subroutine : require\n"
13093 "\n"
13094 "layout (vertices = 4) out;\n"
13095 "\n"
13096 "subroutine void subroutineType(inout vec4 test);\n"
13097 "\n"
13098 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13099 "{\n"
13100 " test = vec4(2, 3, 4, 5);\n"
13101 "}\n"
13102 "\n"
13103 "subroutine uniform subroutineType function;\n"
13104 "\n";
13105
13106 if (include_duplicate_function)
13107 {
13108 result_sstream << "void test_function(inout vec4 test)\n"
13109 "{\n"
13110 " test = vec4(3, 4, 5, 6);\n"
13111 "}\n"
13112 "\n";
13113 }
13114
13115 result_sstream << "void main()\n"
13116 "{\n"
13117 " vec4 temp;\n"
13118 "\n"
13119 " function(temp);\n"
13120 "\n"
13121 " gl_out[gl_InvocationID].gl_Position = temp;\n"
13122 " gl_TessLevelInner[0] = temp.x;\n"
13123 " gl_TessLevelInner[1] = temp.y;\n"
13124 " gl_TessLevelOuter[0] = temp.z;\n"
13125 " gl_TessLevelOuter[1] = temp.w;\n"
13126 " gl_TessLevelOuter[2] = temp.x;\n"
13127 " gl_TessLevelOuter[3] = temp.y;\n"
13128 "}\n";
13129
13130 return result_sstream.str();
13131 }
13132
13133 /** Retrieves tess evaluation shader that should be used for the purpose of the test.
13134 * An overloaded version of a subroutine function is inserted if
13135 * @param include_duplicate_function flag is set to true.
13136 *
13137 * @param include_duplicate_function As per description.
13138 *
13139 * @return Requested string.
13140 **/
getTessellationEvaluationShader(bool include_duplicate_function)13141 std::string NegativeTest10::getTessellationEvaluationShader(bool include_duplicate_function)
13142 {
13143 std::stringstream result_sstream;
13144
13145 result_sstream << "#version 400\n"
13146 "\n"
13147 "#extension GL_ARB_shader_subroutine : require\n"
13148 "\n"
13149 "layout (quads) in;\n"
13150 "\n"
13151 "subroutine void subroutineType(inout vec4 test);\n"
13152 "\n"
13153 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13154 "{\n"
13155 " test = vec4(2, 3, 4, 5);\n"
13156 "}\n"
13157 "\n"
13158 "subroutine uniform subroutineType function;\n"
13159 "\n";
13160
13161 if (include_duplicate_function)
13162 {
13163 result_sstream << "void test_function(inout vec4 test)\n"
13164 "{\n"
13165 " test = vec4(3, 4, 5, 6);\n"
13166 "}\n"
13167 "\n";
13168 }
13169
13170 result_sstream << "void main()\n"
13171 "{\n"
13172 " vec4 temp;\n"
13173 "\n"
13174 " function(temp);\n"
13175 "\n"
13176 " gl_Position = temp;\n"
13177 "}\n";
13178
13179 return result_sstream.str();
13180 }
13181
13182 /** Retrieves vertex shader that should be used for the purpose of the test.
13183 * An overloaded version of a subroutine function is inserted if
13184 * @param include_duplicate_function flag is set to true.
13185 *
13186 * @param include_duplicate_function As per description.
13187 *
13188 * @return Requested string.
13189 **/
getVertexShader(bool include_duplicate_function)13190 std::string NegativeTest10::getVertexShader(bool include_duplicate_function)
13191 {
13192 std::stringstream result_sstream;
13193
13194 result_sstream << "#version 400\n"
13195 "\n"
13196 "#extension GL_ARB_shader_subroutine : require\n"
13197 "\n"
13198 "subroutine void subroutineType(inout vec4 test);\n"
13199 "\n"
13200 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13201 "{\n"
13202 " test = vec4(2, 3, 4, 5);\n"
13203 "}\n"
13204 "\n"
13205 "subroutine uniform subroutineType function;\n"
13206 "\n";
13207
13208 if (include_duplicate_function)
13209 {
13210 result_sstream << "void test_function(inout vec4 test)\n"
13211 "{\n"
13212 " test = vec4(3, 4, 5, 6);\n"
13213 "}\n"
13214 "\n";
13215 }
13216
13217 result_sstream << "void main()\n"
13218 "{\n"
13219 " function(gl_Position);\n"
13220 "}\n";
13221
13222 return result_sstream.str();
13223 }
13224
13225 /** Fills m_test_cases field with test case descriptors */
initTestCases()13226 void NegativeTest10::initTestCases()
13227 {
13228 /* For each test case, only one shader stage should define a function that
13229 * has already been defined as a subroutine. */
13230 for (int offending_shader_stage_it = static_cast<int>(Utils::SHADER_STAGE_FIRST);
13231 offending_shader_stage_it != static_cast<int>(Utils::SHADER_STAGE_COUNT); ++offending_shader_stage_it)
13232 {
13233 Utils::_shader_stage offending_shader_stage = static_cast<Utils::_shader_stage>(offending_shader_stage_it);
13234 /* Form the test case descriptor */
13235 std::stringstream name_sstream;
13236 _test_case test_case;
13237
13238 name_sstream << "Broken shader stage:" << Utils::getShaderStageString(offending_shader_stage);
13239
13240 test_case.fs_body = getFragmentShader(offending_shader_stage == Utils::SHADER_STAGE_FRAGMENT);
13241 test_case.gs_body = getGeometryShader(offending_shader_stage == Utils::SHADER_STAGE_GEOMETRY);
13242 test_case.name = name_sstream.str();
13243 test_case.tc_body =
13244 getTessellationControlShader(offending_shader_stage == Utils::SHADER_STAGE_TESSELLATION_CONTROL);
13245 test_case.te_body =
13246 getTessellationEvaluationShader(offending_shader_stage == Utils::SHADER_STAGE_TESSELLATION_EVALUATION);
13247 test_case.vs_body = getVertexShader(offending_shader_stage == Utils::SHADER_STAGE_VERTEX);
13248
13249 m_test_cases.push_back(test_case);
13250 }
13251 }
13252
13253 /** Executes test iteration.
13254 *
13255 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
13256 */
iterate()13257 tcu::TestNode::IterateResult NegativeTest10::iterate()
13258 {
13259 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
13260
13261 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
13262 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
13263 {
13264 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
13265 }
13266
13267 /* Form test cases */
13268 initTestCases();
13269
13270 /* Iterate over all test cases */
13271 for (_test_cases_const_iterator test_case_iterator = m_test_cases.begin(); test_case_iterator != m_test_cases.end();
13272 ++test_case_iterator)
13273 {
13274 const _test_case& test_case = *test_case_iterator;
13275
13276 /* Try to build the program object */
13277 if (ShaderSubroutine::Utils::buildProgram(gl, test_case.vs_body, test_case.tc_body, test_case.te_body,
13278 test_case.gs_body, test_case.fs_body, DE_NULL, /* xfb_varyings */
13279 0, /* n_xfb_varyings */
13280 &m_vs_id, (test_case.tc_body.length() > 0) ? &m_tc_id : DE_NULL,
13281 (test_case.te_body.length() > 0) ? &m_te_id : DE_NULL,
13282 (test_case.gs_body.length() > 0) ? &m_gs_id : DE_NULL,
13283 (test_case.fs_body.length() > 0) ? &m_fs_id : DE_NULL, &m_po_id))
13284 {
13285 m_testCtx.getLog() << tcu::TestLog::Message << "A program object was successfully built for ["
13286 << test_case.name << "] test case, even though it was invalid."
13287 << tcu::TestLog::EndMessage;
13288
13289 m_has_test_passed = false;
13290 }
13291
13292 /* Delete any objects that may have been created */
13293 deinit();
13294 } /* for (all test cases) */
13295
13296 /** All done */
13297 if (m_has_test_passed)
13298 {
13299 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
13300 }
13301 else
13302 {
13303 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
13304 }
13305
13306 return STOP;
13307 }
13308
13309 /** Constructor.
13310 *
13311 * @param context Rendering context.
13312 **/
NegativeTest11(deqp::Context & context)13313 NegativeTest11::NegativeTest11(deqp::Context& context)
13314 : TestCase(context, "subroutine_uniforms_used_for_sampling_atomic_image_functions",
13315 "Tries to use subroutine uniforms in invalid way in sampling, "
13316 "atomic and image functions. Verifies that compile- or link-time "
13317 "error occurs.")
13318 , m_has_test_passed(true)
13319 , m_po_id(0)
13320 , m_vs_id(0)
13321 {
13322 /* Left blank intentionally */
13323 }
13324
13325 /** Deinitializes any GL objects that may have been created during
13326 * test execution.
13327 **/
deinit()13328 void NegativeTest11::deinit()
13329 {
13330 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
13331
13332 if (m_po_id != 0)
13333 {
13334 gl.deleteProgram(m_po_id);
13335
13336 m_po_id = 0;
13337 }
13338
13339 if (m_vs_id != 0)
13340 {
13341 gl.deleteShader(m_vs_id);
13342
13343 m_vs_id = 0;
13344 }
13345 }
13346
13347 /** Returns a literal corresponding to user-specified test case enum.
13348 *
13349 * @param test_case As per description.
13350 *
13351 * @return Requested string.
13352 **/
getTestCaseString(const _test_case & test_case)13353 std::string NegativeTest11::getTestCaseString(const _test_case& test_case)
13354 {
13355 std::string result = "?";
13356
13357 switch (test_case)
13358 {
13359 case TEST_CASE_INVALID_TEXTURE_SAMPLING_ATTEMPT:
13360 result = "TEST_CASE_INVALID_TEXTURE_SAMPLING_ATTEMPT";
13361 break;
13362 case TEST_CASE_INVALID_ATOMIC_COUNTER_USAGE_ATTEMPT:
13363 result = "TEST_CASE_INVALID_ATOMIC_COUNTER_USAGE_ATTEMPT";
13364 break;
13365 case TEST_CASE_INVALID_IMAGE_FUNCTION_USAGE_ATTEMPT:
13366 result = "TEST_CASE_INVALID_IMAGE_FUNCTION_USAGE_ATTEMPT";
13367 break;
13368 default:
13369 break;
13370 }
13371
13372 return result;
13373 }
13374
13375 /** Retrieves vertex shader body for user-specified test case.
13376 *
13377 * @param test_case As per description.
13378 *
13379 * @return Requested string.
13380 **/
getVertexShader(const _test_case & test_case)13381 std::string NegativeTest11::getVertexShader(const _test_case& test_case)
13382 {
13383 std::stringstream result_sstream;
13384
13385 /* Form pre-amble */
13386 result_sstream << "#version 400\n"
13387 "\n"
13388 "#extension GL_ARB_shader_subroutine : require\n";
13389
13390 if (test_case == TEST_CASE_INVALID_ATOMIC_COUNTER_USAGE_ATTEMPT)
13391 {
13392 result_sstream << "#extension GL_ARB_shader_atomic_counters : require\n";
13393 }
13394
13395 result_sstream << "\n"
13396 /* Define a subroutine */
13397 "subroutine void subroutineType(inout vec4 test);\n"
13398 "\n"
13399 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13400 "{\n"
13401 " test += vec4(0, 1, 2, 3);\n"
13402 "}\n"
13403 "\n"
13404 "subroutine uniform subroutineType function;\n"
13405 "\n"
13406
13407 /* Define main() body */
13408 "void main()\n"
13409 "{\n";
13410
13411 /* Implement case-specific behavior */
13412 switch (test_case)
13413 {
13414 case TEST_CASE_INVALID_ATOMIC_COUNTER_USAGE_ATTEMPT:
13415 {
13416 result_sstream << "if (atomicCounter(function) > 2)\n"
13417 "{\n"
13418 " gl_Position = vec4(1);\n"
13419 "}\n";
13420
13421 break;
13422 }
13423
13424 case TEST_CASE_INVALID_IMAGE_FUNCTION_USAGE_ATTEMPT:
13425 {
13426 result_sstream << "imageStore(function, vec2(0.0, 1.0), vec4(1.0) );\n";
13427
13428 break;
13429 }
13430
13431 case TEST_CASE_INVALID_TEXTURE_SAMPLING_ATTEMPT:
13432 {
13433 result_sstream << "gl_Position = texture(function, vec2(1.0) );\n";
13434
13435 break;
13436 }
13437
13438 default:
13439 break;
13440 } /* switch (test_case) */
13441
13442 /* Close main() body */
13443 result_sstream << "}\n";
13444
13445 /* Done */
13446 return result_sstream.str();
13447 }
13448
13449 /** Executes test iteration.
13450 *
13451 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
13452 */
iterate()13453 tcu::TestNode::IterateResult NegativeTest11::iterate()
13454 {
13455 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
13456
13457 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
13458 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
13459 {
13460 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
13461 }
13462
13463 /* Iterate over all test cases */
13464 for (int test_case = static_cast<int>(TEST_CASE_FIRST); test_case != static_cast<int>(TEST_CASE_COUNT); ++test_case)
13465 {
13466 if (static_cast<_test_case>(test_case) == TEST_CASE_INVALID_ATOMIC_COUNTER_USAGE_ATTEMPT &&
13467 !m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_atomic_counters"))
13468 {
13469 /* This iteration requires atomic counter support that this GL implementation
13470 * is not capable of. Skip the iteration
13471 */
13472 continue;
13473 }
13474
13475 /* Try to build a program object using invalid vertex shader, specific to the
13476 * iteration we're currently in */
13477 std::string vs_body = getVertexShader(static_cast<_test_case>(test_case));
13478
13479 if (ShaderSubroutine::Utils::buildProgram(gl, vs_body, "", /* tc_body */
13480 "", /* te_body */
13481 "", /* gs_body */
13482 "", /* fs_body */
13483 DE_NULL, /* xfb_varyings */
13484 0, /* n_xfb_varyings */
13485 &m_vs_id, DE_NULL, /* out_tc_id */
13486 DE_NULL, /* out_te_id */
13487 DE_NULL, /* out_gs_id */
13488 DE_NULL, /* out_fs_id */
13489 &m_po_id))
13490 {
13491 m_testCtx.getLog() << tcu::TestLog::Message << "A program object was successfully built for ["
13492 << getTestCaseString(static_cast<_test_case>(test_case))
13493 << "] test case, even though it was invalid." << tcu::TestLog::EndMessage;
13494
13495 m_has_test_passed = false;
13496 }
13497
13498 /* Delete any objects that may have been created */
13499 deinit();
13500 } /* for (all test cases) */
13501
13502 /** All done */
13503 if (m_has_test_passed)
13504 {
13505 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
13506 }
13507 else
13508 {
13509 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
13510 }
13511
13512 return STOP;
13513 }
13514
13515 /** Constructor.
13516 *
13517 * @param context Rendering context.
13518 **/
NegativeTest12(deqp::Context & context)13519 NegativeTest12::NegativeTest12(deqp::Context& context)
13520 : TestCase(context, "subroutines_not_allowed_as_variables_constructors_and_argument_or_return_types",
13521 "Verifies that it is not allowed to use subroutine type for "
13522 "local/global variables, constructors or argument/return type.")
13523 , m_has_test_passed(true)
13524 , m_po_id(0)
13525 , m_vs_id(0)
13526 {
13527 /* Left blank intentionally */
13528 }
13529
13530 /** Deinitializes any GL objects that may have been created during
13531 * test execution.
13532 **/
deinit()13533 void NegativeTest12::deinit()
13534 {
13535 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
13536
13537 if (m_po_id != 0)
13538 {
13539 gl.deleteProgram(m_po_id);
13540
13541 m_po_id = 0;
13542 }
13543
13544 if (m_vs_id != 0)
13545 {
13546 gl.deleteShader(m_vs_id);
13547
13548 m_vs_id = 0;
13549 }
13550 }
13551
13552 /** Returns a literal corresponding to user-specified test case enum.
13553 *
13554 * @param test_case As per description.
13555 *
13556 * @return Requested string.
13557 **/
getTestCaseString(const _test_case & test_case)13558 std::string NegativeTest12::getTestCaseString(const _test_case& test_case)
13559 {
13560 std::string result = "?";
13561
13562 switch (test_case)
13563 {
13564 case TEST_CASE_INVALID_LOCAL_SUBROUTINE_VARIABLE:
13565 result = "TEST_CASE_INVALID_LOCAL_SUBROUTINE_VARIABLE";
13566 break;
13567 case TEST_CASE_INVALID_GLOBAL_SUBROUTINE_VARIABLE:
13568 result = "TEST_CASE_INVALID_GLOBAL_SUBROUTINE_VARIABLE";
13569 break;
13570 case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR:
13571 result = "TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR";
13572 break;
13573 case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_ARGUMENT:
13574 result = "TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_ARGUMENT";
13575 break;
13576 case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_RETURN_TYPE:
13577 result = "TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_RETURN_TYPE";
13578 break;
13579 default:
13580 break;
13581 }
13582
13583 return result;
13584 }
13585
13586 /** Retrieves vertex shader body for user-specified test case.
13587 *
13588 * @param test_case As per description.
13589 *
13590 * @return Requested string.
13591 **/
getVertexShader(const _test_case & test_case)13592 std::string NegativeTest12::getVertexShader(const _test_case& test_case)
13593 {
13594 std::stringstream result_sstream;
13595
13596 /* Form pre-amble */
13597 result_sstream << "#version 400\n"
13598 "\n"
13599 "#extension GL_ARB_shader_subroutine : require\n"
13600 "\n"
13601 /* Define a subroutine */
13602 "subroutine void subroutineType(inout vec4 test);\n"
13603 "\n"
13604 "subroutine(subroutineType) void test_function(inout vec4 test)\n"
13605 "{\n"
13606 " test += vec4(0, 1, 2, 3);\n"
13607 "}\n"
13608 "\n"
13609 "subroutine uniform subroutineType function;\n"
13610 "\n";
13611
13612 /* Include case-specific implementation */
13613 switch (test_case)
13614 {
13615 case TEST_CASE_INVALID_LOCAL_SUBROUTINE_VARIABLE:
13616 {
13617 result_sstream << "void main()\n"
13618 "{\n"
13619 " subroutine subroutineType function2;\n"
13620 " vec4 result;\n"
13621 "\n"
13622 " function2(result);\n"
13623 " gl_Position = result;\n"
13624 "}\n";
13625
13626 break;
13627 }
13628
13629 case TEST_CASE_INVALID_GLOBAL_SUBROUTINE_VARIABLE:
13630 {
13631 result_sstream << "subroutine subroutineType function2;\n"
13632 "\n"
13633 "void main()\n"
13634 "{\n"
13635 " vec4 result;\n"
13636 "\n"
13637 " function2(result);\n"
13638 " gl_Position = result;\n"
13639 "}\n";
13640
13641 break;
13642 }
13643
13644 case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR:
13645 {
13646 result_sstream << "void main()\n"
13647 "{\n"
13648 " subroutineType(function);\n"
13649 "}\n";
13650
13651 break;
13652 }
13653
13654 case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_ARGUMENT:
13655 {
13656 result_sstream << "vec4 test_function(subroutineType argument)\n"
13657 "{\n"
13658 " vec4 result = vec4(1, 2, 3, 4);\n"
13659 "\n"
13660 " argument(result);\n"
13661 "\n"
13662 " return result;\n"
13663 "}\n"
13664 "\n"
13665 "void main()\n"
13666 "{\n"
13667 " test_function(function);\n"
13668 "}\n";
13669
13670 break;
13671 }
13672
13673 case TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_RETURN_TYPE:
13674 {
13675 result_sstream << "subroutineType test_function()\n"
13676 "{\n"
13677 " return function;\n"
13678 "}\n"
13679 "\n"
13680 "void main()\n"
13681 "{\n"
13682 " test_function()(gl_Position);\n"
13683 "}\n";
13684
13685 break;
13686 }
13687
13688 default:
13689 break;
13690 } /* switch (test_case) */
13691
13692 /* Done */
13693 return result_sstream.str();
13694 }
13695
13696 /** Executes test iteration.
13697 *
13698 * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
13699 */
iterate()13700 tcu::TestNode::IterateResult NegativeTest12::iterate()
13701 {
13702 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
13703
13704 /* Do not execute the test if GL_ARB_shader_subroutine is not supported */
13705 if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
13706 {
13707 throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
13708 }
13709
13710 /* Iterate over all test cases */
13711 for (int test_case = static_cast<int>(TEST_CASE_FIRST); test_case != static_cast<int>(TEST_CASE_COUNT); ++test_case)
13712 {
13713 /* Try to build a program object using invalid vertex shader, specific to the
13714 * iteration we're currently in */
13715 std::string vs_body = getVertexShader(static_cast<_test_case>(test_case));
13716
13717 if (ShaderSubroutine::Utils::buildProgram(gl, vs_body, "", /* tc_body */
13718 "", /* te_body */
13719 "", /* gs_body */
13720 "", /* fs_body */
13721 DE_NULL, /* xfb_varyings */
13722 0, /* n_xfb_varyings */
13723 &m_vs_id, DE_NULL, /* out_tc_id */
13724 DE_NULL, /* out_te_id */
13725 DE_NULL, /* out_gs_id */
13726 DE_NULL, /* out_fs_id */
13727 &m_po_id))
13728 {
13729 m_testCtx.getLog() << tcu::TestLog::Message << "A program object was successfully built for ["
13730 << getTestCaseString(static_cast<_test_case>(test_case))
13731 << "] test case, even though it was invalid." << tcu::TestLog::EndMessage;
13732
13733 m_has_test_passed = false;
13734 }
13735
13736 /* Delete any objects that may have been created */
13737 deinit();
13738 } /* for (all test cases) */
13739
13740 /** All done */
13741 if (m_has_test_passed)
13742 {
13743 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
13744 }
13745 else
13746 {
13747 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
13748 }
13749
13750 return STOP;
13751 }
13752
13753 } /* ShaderSubroutine */
13754
13755 /** Constructor.
13756 *
13757 * @param context Rendering context.
13758 **/
ShaderSubroutineTests(deqp::Context & context)13759 ShaderSubroutineTests::ShaderSubroutineTests(deqp::Context& context)
13760 : TestCaseGroup(context, "shader_subroutine", "Verifies \"shader_subroutine\" functionality")
13761 {
13762 /* Left blank on purpose */
13763 }
13764
13765 /** Initializes a texture_storage_multisample test group.
13766 *
13767 **/
init(void)13768 void ShaderSubroutineTests::init(void)
13769 {
13770 addChild(new ShaderSubroutine::APITest1(m_context));
13771 addChild(new ShaderSubroutine::APITest2(m_context));
13772 addChild(new ShaderSubroutine::FunctionalTest1_2(m_context));
13773 addChild(new ShaderSubroutine::FunctionalTest3_4(m_context));
13774 addChild(new ShaderSubroutine::FunctionalTest5(m_context));
13775 addChild(new ShaderSubroutine::FunctionalTest6(m_context));
13776 addChild(new ShaderSubroutine::FunctionalTest7_8(m_context));
13777 addChild(new ShaderSubroutine::FunctionalTest9(m_context));
13778 addChild(new ShaderSubroutine::FunctionalTest10(m_context));
13779 addChild(new ShaderSubroutine::FunctionalTest11(m_context));
13780 addChild(new ShaderSubroutine::FunctionalTest12(m_context));
13781 addChild(new ShaderSubroutine::FunctionalTest13(m_context));
13782 addChild(new ShaderSubroutine::FunctionalTest14_15(m_context));
13783 addChild(new ShaderSubroutine::FunctionalTest16(m_context));
13784 addChild(new ShaderSubroutine::FunctionalTest17(m_context));
13785 addChild(new ShaderSubroutine::FunctionalTest18_19(m_context));
13786 addChild(new ShaderSubroutine::NegativeTest1(m_context));
13787 addChild(new ShaderSubroutine::NegativeTest2(m_context));
13788 addChild(new ShaderSubroutine::NegativeTest3(m_context));
13789 addChild(new ShaderSubroutine::NegativeTest4(m_context));
13790 addChild(new ShaderSubroutine::NegativeTest5(m_context));
13791 addChild(new ShaderSubroutine::NegativeTest6(m_context));
13792 addChild(new ShaderSubroutine::NegativeTest7(m_context));
13793 addChild(new ShaderSubroutine::NegativeTest8(m_context));
13794 addChild(new ShaderSubroutine::NegativeTest9(m_context));
13795 addChild(new ShaderSubroutine::NegativeTest10(m_context));
13796 addChild(new ShaderSubroutine::NegativeTest11(m_context));
13797 addChild(new ShaderSubroutine::NegativeTest12(m_context));
13798 }
13799
13800 } /* glcts namespace */
13801