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  glcViewportArrayTests.cpp
26 * \brief Implements conformance tests for "Viewport Array" functionality.
27 */ /*-------------------------------------------------------------------*/
28
29#include "glcViewportArrayTests.hpp"
30
31#include "gluContextInfo.hpp"
32#include "gluDefs.hpp"
33#include "gluStrUtil.hpp"
34#include "glwEnums.hpp"
35#include "glwFunctions.hpp"
36#include "tcuRenderTarget.hpp"
37#include "tcuTestLog.hpp"
38
39#include <algorithm>
40#include <iomanip>
41#include <string>
42#include <vector>
43
44using namespace glw;
45
46namespace glcts
47{
48
49namespace ViewportArray
50{
51/** Constructor.
52 *
53 * @param context CTS context.
54 **/
55Utils::buffer::buffer(deqp::Context& context) : m_id(0), m_context(context), m_target(0)
56{
57}
58
59/** Destructor
60 *
61 **/
62Utils::buffer::~buffer()
63{
64	if (0 != m_id)
65	{
66		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
67
68		gl.deleteBuffers(1, &m_id);
69		m_id = 0;
70	}
71}
72
73/** Execute BindBuffer
74 *
75 **/
76void Utils::buffer::bind() const
77{
78	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
79
80	gl.bindBuffer(m_target, m_id);
81	GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer");
82}
83
84/** Execute BindBufferRange
85 *
86 * @param index  <index> parameter
87 * @param offset <offset> parameter
88 * @param size   <size> parameter
89 **/
90void Utils::buffer::bindRange(glw::GLuint index, glw::GLintptr offset, glw::GLsizeiptr size)
91{
92	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
93
94	gl.bindBufferRange(m_target, index, m_id, offset, size);
95	GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferRange");
96}
97
98/** Execute GenBuffer
99 *
100 * @param target Target that will be used by this buffer
101 **/
102void Utils::buffer::generate(glw::GLenum target)
103{
104	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
105
106	m_target = target;
107
108	gl.genBuffers(1, &m_id);
109	GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers");
110}
111
112/** Maps buffer content
113 *
114 * @param access Access rights for mapped region
115 *
116 * @return Mapped memory
117 **/
118void* Utils::buffer::map(GLenum access) const
119{
120	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
121
122	gl.bindBuffer(m_target, m_id);
123	GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer");
124
125	void* result = gl.mapBuffer(m_target, access);
126	GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
127
128	return result;
129}
130
131/** Unmaps buffer
132 *
133 **/
134void Utils::buffer::unmap() const
135{
136	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
137
138	gl.bindBuffer(m_target, m_id);
139	GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer");
140
141	gl.unmapBuffer(m_target);
142	GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
143}
144
145/** Execute BufferData
146 *
147 * @param size   <size> parameter
148 * @param data   <data> parameter
149 * @param usage  <usage> parameter
150 **/
151void Utils::buffer::update(glw::GLsizeiptr size, glw::GLvoid* data, glw::GLenum usage)
152{
153	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
154
155	gl.bindBuffer(m_target, m_id);
156	GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer");
157
158	gl.bufferData(m_target, size, data, usage);
159	GLU_EXPECT_NO_ERROR(gl.getError(), "bufferData");
160}
161
162/** Constructor
163 *
164 * @param context CTS context
165 **/
166Utils::framebuffer::framebuffer(deqp::Context& context) : m_id(0), m_context(context)
167{
168	/* Nothing to be done here */
169}
170
171/** Destructor
172 *
173 **/
174Utils::framebuffer::~framebuffer()
175{
176	if (0 != m_id)
177	{
178		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
179
180		gl.deleteFramebuffers(1, &m_id);
181		m_id = 0;
182	}
183}
184
185/** Attach texture to specified attachment
186 *
187 * @param attachment Attachment
188 * @param texture_id Texture id
189 * @param width      Texture width
190 * @param height     Texture height
191 **/
192void Utils::framebuffer::attachTexture(glw::GLenum attachment, glw::GLuint texture_id, glw::GLuint width,
193									   glw::GLuint height)
194{
195	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
196
197	bind();
198
199	gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, attachment, texture_id, 0 /* level */);
200	GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture");
201
202	gl.viewport(0 /* x */, 0 /* y */, width, height);
203	GLU_EXPECT_NO_ERROR(gl.getError(), "Viewport");
204}
205
206/** Binds framebuffer to DRAW_FRAMEBUFFER
207 *
208 **/
209void Utils::framebuffer::bind()
210{
211	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
212
213	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_id);
214	GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
215}
216
217/** Clear framebuffer
218 *
219 * @param mask <mask> parameter of glClear. Decides which shall be cleared
220 **/
221void Utils::framebuffer::clear(glw::GLenum mask)
222{
223	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
224
225	gl.clear(mask);
226	GLU_EXPECT_NO_ERROR(gl.getError(), "Clear");
227}
228
229/** Specifies clear color
230 *
231 * @param red   Red channel
232 * @param green Green channel
233 * @param blue  Blue channel
234 * @param alpha Alpha channel
235 **/
236void Utils::framebuffer::clearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
237{
238	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
239
240	gl.clearColor(red, green, blue, alpha);
241	GLU_EXPECT_NO_ERROR(gl.getError(), "ClearColor");
242}
243
244/** Generate framebuffer
245 *
246 **/
247void Utils::framebuffer::generate()
248{
249	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
250
251	gl.genFramebuffers(1, &m_id);
252	GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers");
253}
254
255Utils::shaderCompilationException::shaderCompilationException(const glw::GLchar* source, const glw::GLchar* message)
256	: m_shader_source(source), m_error_message(message)
257{
258	/* Nothing to be done */
259}
260
261const char* Utils::shaderCompilationException::what() const throw()
262{
263	return "Shader compilation failed";
264}
265
266Utils::programLinkageException::programLinkageException(const glw::GLchar* message) : m_error_message(message)
267{
268	/* Nothing to be done */
269}
270
271const char* Utils::programLinkageException::what() const throw()
272{
273	return "Program linking failed";
274}
275
276const glw::GLenum Utils::program::ARB_COMPUTE_SHADER = 0x91B9;
277
278/** Constructor.
279 *
280 * @param context CTS context.
281 **/
282Utils::program::program(deqp::Context& context)
283	: m_compute_shader_id(0)
284	, m_fragment_shader_id(0)
285	, m_geometry_shader_id(0)
286	, m_program_object_id(0)
287	, m_tesselation_control_shader_id(0)
288	, m_tesselation_evaluation_shader_id(0)
289	, m_vertex_shader_id(0)
290	, m_context(context)
291{
292	/* Nothing to be done here */
293}
294
295/** Destructor
296 *
297 **/
298Utils::program::~program()
299{
300	remove();
301}
302
303/** Build program
304 *
305 * @param compute_shader_code                Compute shader source code
306 * @param fragment_shader_code               Fragment shader source code
307 * @param geometry_shader_code               Geometry shader source code
308 * @param tesselation_control_shader_code    Tesselation control shader source code
309 * @param tesselation_evaluation_shader_code Tesselation evaluation shader source code
310 * @param vertex_shader_code                 Vertex shader source code
311 * @param varying_names                      Array of strings containing names of varyings to be captured with transfrom feedback
312 * @param n_varying_names                    Number of varyings to be captured with transfrom feedback
313 * @param is_separable                       Selects if monolithis or separable program should be built. Defaults to false
314 **/
315void Utils::program::build(const glw::GLchar* compute_shader_code, const glw::GLchar* fragment_shader_code,
316						   const glw::GLchar* geometry_shader_code, const glw::GLchar* tesselation_control_shader_code,
317						   const glw::GLchar* tesselation_evaluation_shader_code, const glw::GLchar* vertex_shader_code,
318						   const glw::GLchar* const* varying_names, glw::GLuint n_varying_names, bool is_separable)
319{
320	/* GL entry points */
321	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
322
323	/* Create shader objects and compile */
324	if (0 != compute_shader_code)
325	{
326		m_compute_shader_id = gl.createShader(ARB_COMPUTE_SHADER);
327		GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
328
329		compile(m_compute_shader_id, compute_shader_code);
330	}
331
332	if (0 != fragment_shader_code)
333	{
334		m_fragment_shader_id = gl.createShader(GL_FRAGMENT_SHADER);
335		GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
336
337		compile(m_fragment_shader_id, fragment_shader_code);
338	}
339
340	if (0 != geometry_shader_code)
341	{
342		m_geometry_shader_id = gl.createShader(GL_GEOMETRY_SHADER);
343		GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
344
345		compile(m_geometry_shader_id, geometry_shader_code);
346	}
347
348	if (0 != tesselation_control_shader_code)
349	{
350		m_tesselation_control_shader_id = gl.createShader(GL_TESS_CONTROL_SHADER);
351		GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
352
353		compile(m_tesselation_control_shader_id, tesselation_control_shader_code);
354	}
355
356	if (0 != tesselation_evaluation_shader_code)
357	{
358		m_tesselation_evaluation_shader_id = gl.createShader(GL_TESS_EVALUATION_SHADER);
359		GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
360
361		compile(m_tesselation_evaluation_shader_id, tesselation_evaluation_shader_code);
362	}
363
364	if (0 != vertex_shader_code)
365	{
366		m_vertex_shader_id = gl.createShader(GL_VERTEX_SHADER);
367		GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
368
369		compile(m_vertex_shader_id, vertex_shader_code);
370	}
371
372	/* Create program object */
373	m_program_object_id = gl.createProgram();
374	GLU_EXPECT_NO_ERROR(gl.getError(), "CreateProgram");
375
376	/* Set up captyured varyings' names */
377	if (0 != n_varying_names)
378	{
379		gl.transformFeedbackVaryings(m_program_object_id, n_varying_names, varying_names, GL_INTERLEAVED_ATTRIBS);
380		GLU_EXPECT_NO_ERROR(gl.getError(), "TransformFeedbackVaryings");
381	}
382
383	/* Set separable parameter */
384	if (true == is_separable)
385	{
386		gl.programParameteri(m_program_object_id, GL_PROGRAM_SEPARABLE, GL_TRUE);
387		GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramParameteri");
388	}
389
390	/* Link program */
391	link();
392}
393
394void Utils::program::compile(GLuint shader_id, const GLchar* source) const
395{
396	/* GL entry points */
397	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
398
399	/* Compilation status */
400	glw::GLint status = GL_FALSE;
401
402	/* Set source code */
403	gl.shaderSource(shader_id, 1 /* count */, &source, 0 /* lengths */);
404	GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderSource");
405
406	/* Compile */
407	gl.compileShader(shader_id);
408	GLU_EXPECT_NO_ERROR(gl.getError(), "CompileShader");
409
410	/* Get compilation status */
411	gl.getShaderiv(shader_id, GL_COMPILE_STATUS, &status);
412	GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
413
414	/* Log compilation error */
415	if (GL_TRUE != status)
416	{
417		glw::GLint				 length = 0;
418		std::vector<glw::GLchar> message;
419
420		/* Error log length */
421		gl.getShaderiv(shader_id, GL_INFO_LOG_LENGTH, &length);
422		GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
423
424		/* Prepare storage */
425		message.resize(length);
426
427		/* Get error log */
428		gl.getShaderInfoLog(shader_id, length, 0, &message[0]);
429		GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderInfoLog");
430
431		throw shaderCompilationException(source, &message[0]);
432	}
433}
434
435glw::GLint Utils::program::getAttribLocation(const glw::GLchar* name) const
436{
437	/* GL entry points */
438	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
439
440	GLint location = gl.getAttribLocation(m_program_object_id, name);
441	GLU_EXPECT_NO_ERROR(gl.getError(), "GetAttribLocation");
442
443	return location;
444}
445
446/** Get subroutine index
447 *
448 * @param subroutine_name Subroutine name
449 *
450 * @return Index of subroutine
451 **/
452GLuint Utils::program::getSubroutineIndex(const glw::GLchar* subroutine_name, glw::GLenum shader_stage) const
453{
454	const glw::Functions& gl	= m_context.getRenderContext().getFunctions();
455	GLuint				  index = -1;
456
457	index = gl.getSubroutineIndex(m_program_object_id, shader_stage, subroutine_name);
458	GLU_EXPECT_NO_ERROR(gl.getError(), "GetSubroutineIndex");
459
460	if (GL_INVALID_INDEX == index)
461	{
462		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Subroutine: " << subroutine_name
463											<< " is not available" << tcu::TestLog::EndMessage;
464
465		TCU_FAIL("Subroutine is not available");
466	}
467
468	return index;
469}
470
471/** Get subroutine uniform location
472 *
473 * @param uniform_name Subroutine uniform name
474 *
475 * @return Location of subroutine uniform
476 **/
477GLint Utils::program::getSubroutineUniformLocation(const glw::GLchar* uniform_name, glw::GLenum shader_stage) const
478{
479	const glw::Functions& gl	   = m_context.getRenderContext().getFunctions();
480	GLint				  location = -1;
481
482	location = gl.getSubroutineUniformLocation(m_program_object_id, shader_stage, uniform_name);
483	GLU_EXPECT_NO_ERROR(gl.getError(), "GetSubroutineUniformLocation");
484
485	if (-1 == location)
486	{
487		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Subroutine uniform: " << uniform_name
488											<< " is not available" << tcu::TestLog::EndMessage;
489
490		TCU_FAIL("Subroutine uniform is not available");
491	}
492
493	return location;
494}
495
496/** Get uniform location
497 *
498 * @param uniform_name Subroutine uniform name
499 *
500 * @return Location of uniform
501 **/
502GLint Utils::program::getUniformLocation(const glw::GLchar* uniform_name) const
503{
504	const glw::Functions& gl	   = m_context.getRenderContext().getFunctions();
505	GLint				  location = -1;
506
507	location = gl.getUniformLocation(m_program_object_id, uniform_name);
508	GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation");
509
510	if (-1 == location)
511	{
512		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Uniform: " << uniform_name
513											<< " is not available" << tcu::TestLog::EndMessage;
514
515		TCU_FAIL("Uniform is not available");
516	}
517
518	return location;
519}
520
521/** Attach shaders and link program
522 *
523 **/
524void Utils::program::link() const
525{
526	/* GL entry points */
527	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
528
529	/* Link status */
530	glw::GLint status = GL_FALSE;
531
532	/* Attach shaders */
533	if (0 != m_compute_shader_id)
534	{
535		gl.attachShader(m_program_object_id, m_compute_shader_id);
536		GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
537	}
538
539	if (0 != m_fragment_shader_id)
540	{
541		gl.attachShader(m_program_object_id, m_fragment_shader_id);
542		GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
543	}
544
545	if (0 != m_geometry_shader_id)
546	{
547		gl.attachShader(m_program_object_id, m_geometry_shader_id);
548		GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
549	}
550
551	if (0 != m_tesselation_control_shader_id)
552	{
553		gl.attachShader(m_program_object_id, m_tesselation_control_shader_id);
554		GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
555	}
556
557	if (0 != m_tesselation_evaluation_shader_id)
558	{
559		gl.attachShader(m_program_object_id, m_tesselation_evaluation_shader_id);
560		GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
561	}
562
563	if (0 != m_vertex_shader_id)
564	{
565		gl.attachShader(m_program_object_id, m_vertex_shader_id);
566		GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
567	}
568
569	/* Link */
570	gl.linkProgram(m_program_object_id);
571	GLU_EXPECT_NO_ERROR(gl.getError(), "LinkProgram");
572
573	/* Get link status */
574	gl.getProgramiv(m_program_object_id, GL_LINK_STATUS, &status);
575	GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
576
577	/* Log link error */
578	if (GL_TRUE != status)
579	{
580		glw::GLint				 length = 0;
581		std::vector<glw::GLchar> message;
582
583		/* Get error log length */
584		gl.getProgramiv(m_program_object_id, GL_INFO_LOG_LENGTH, &length);
585		GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
586
587		message.resize(length);
588
589		/* Get error log */
590		gl.getProgramInfoLog(m_program_object_id, length, 0, &message[0]);
591		GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramInfoLog");
592
593		throw programLinkageException(&message[0]);
594	}
595}
596
597/** Delete program object and all attached shaders
598 *
599 **/
600void Utils::program::remove()
601{
602	/* GL entry points */
603	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
604
605	/* Make sure program object is no longer used by GL */
606	gl.useProgram(0);
607
608	/* Clean program object */
609	if (0 != m_program_object_id)
610	{
611		gl.deleteProgram(m_program_object_id);
612		m_program_object_id = 0;
613	}
614
615	/* Clean shaders */
616	if (0 != m_compute_shader_id)
617	{
618		gl.deleteShader(m_compute_shader_id);
619		m_compute_shader_id = 0;
620	}
621
622	if (0 != m_fragment_shader_id)
623	{
624		gl.deleteShader(m_fragment_shader_id);
625		m_fragment_shader_id = 0;
626	}
627
628	if (0 != m_geometry_shader_id)
629	{
630		gl.deleteShader(m_geometry_shader_id);
631		m_geometry_shader_id = 0;
632	}
633
634	if (0 != m_tesselation_control_shader_id)
635	{
636		gl.deleteShader(m_tesselation_control_shader_id);
637		m_tesselation_control_shader_id = 0;
638	}
639
640	if (0 != m_tesselation_evaluation_shader_id)
641	{
642		gl.deleteShader(m_tesselation_evaluation_shader_id);
643		m_tesselation_evaluation_shader_id = 0;
644	}
645
646	if (0 != m_vertex_shader_id)
647	{
648		gl.deleteShader(m_vertex_shader_id);
649		m_vertex_shader_id = 0;
650	}
651}
652
653/** Execute UseProgram
654 *
655 **/
656void Utils::program::use() const
657{
658	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
659
660	gl.useProgram(m_program_object_id);
661	GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
662}
663
664void Utils::program::printShaderSource(const GLchar* source, tcu::MessageBuilder& log)
665{
666	GLuint line_number = 0;
667
668	log << "Shader source.";
669
670	log << "\nLine||Source\n";
671
672	while (0 != source)
673	{
674		std::string   line;
675		const GLchar* next_line = strchr(source, '\n');
676
677		if (0 != next_line)
678		{
679			next_line += 1;
680			line.assign(source, next_line - source);
681		}
682		else
683		{
684			line = source;
685		}
686
687		if (0 != *source)
688		{
689			log << std::setw(4) << line_number << "||" << line;
690		}
691
692		source = next_line;
693		line_number += 1;
694	}
695}
696
697/** Constructor.
698 *
699 * @param context CTS context.
700 **/
701Utils::texture::texture(deqp::Context& context)
702	: m_id(0), m_width(0), m_height(0), m_depth(0), m_context(context), m_is_array(false)
703{
704	/* Nothing to done here */
705}
706
707/** Destructor
708 *
709 **/
710Utils::texture::~texture()
711{
712	release();
713}
714
715/** Bind texture to GL_TEXTURE_2D
716 *
717 **/
718void Utils::texture::bind() const
719{
720	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
721
722	if (false == m_is_array)
723	{
724		gl.bindTexture(GL_TEXTURE_2D, m_id);
725		GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
726	}
727	else
728	{
729		gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_id);
730		GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
731	}
732}
733
734/** Create 2d texture
735 *
736 * @param width           Width of texture
737 * @param height          Height of texture
738 * @param internal_format Internal format of texture
739 **/
740void Utils::texture::create(GLuint width, GLuint height, GLenum internal_format)
741{
742	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
743
744	release();
745
746	m_width	= width;
747	m_height   = height;
748	m_depth	= 1;
749	m_is_array = false;
750
751	gl.genTextures(1, &m_id);
752	GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures");
753
754	bind();
755
756	gl.texStorage2D(GL_TEXTURE_2D, 1 /* levels */, internal_format, width, height);
757	GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D");
758}
759
760/** Create 2d texture array
761 *
762 * @param width           Width of texture
763 * @param height          Height of texture
764 * @param depth           Depth of texture
765 * @param internal_format Internal format of texture
766 **/
767void Utils::texture::create(GLuint width, GLuint height, GLuint depth, GLenum internal_format)
768{
769	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
770
771	release();
772
773	m_width	= width;
774	m_height   = height;
775	m_depth	= depth;
776	m_is_array = true;
777
778	gl.genTextures(1, &m_id);
779	GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures");
780
781	bind();
782
783	gl.texStorage3D(GL_TEXTURE_2D_ARRAY, 1 /* levels */, internal_format, width, height, depth);
784	GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage3D");
785}
786
787/** Get contents of texture
788 *
789 * @param format   Format of image
790 * @param type     Type of image
791 * @param out_data Buffer for image
792 **/
793void Utils::texture::get(glw::GLenum format, glw::GLenum type, glw::GLvoid* out_data) const
794{
795	const glw::Functions&   gl			 = m_context.getRenderContext().getFunctions();
796	const glu::ContextType& context_type = m_context.getRenderContext().getType();
797
798	bind();
799
800	GLenum textarget = GL_TEXTURE_2D;
801
802	if (true == m_is_array)
803	{
804		textarget = GL_TEXTURE_2D_ARRAY;
805	}
806
807	if (glu::isContextTypeGLCore(context_type))
808	{
809		gl.getTexImage(textarget, 0 /* level */, format, type, out_data);
810		GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexImage");
811	}
812	else
813	{
814		DE_ASSERT(glu::isContextTypeES(context_type));
815
816		GLuint temp_fbo = 0;
817		gl.genFramebuffers(1, &temp_fbo);
818		gl.bindFramebuffer(GL_READ_FRAMEBUFFER, temp_fbo);
819
820		/* OpenGL ES only guarantees support for RGBA formats of each type.
821		Since the tests are only expecting single-channel formats, we read them back
822		in RGBA to a temporary buffer and then copy only the first component
823		to the actual output buffer */
824		GLenum read_format = format;
825		switch (format)
826		{
827		case GL_RED:
828			read_format = GL_RGBA;
829			break;
830		case GL_RED_INTEGER:
831			read_format = GL_RGBA_INTEGER;
832			break;
833		default:
834			TCU_FAIL("unexpected format");
835		}
836		/* we can get away just handling one type of data, as long as the components are the same size */
837		if (type != GL_INT && type != GL_FLOAT)
838		{
839			TCU_FAIL("unexpected type");
840		}
841		std::vector<GLint> read_data;
842		const GLuint	   layer_size = m_width * m_height * 4;
843		read_data.resize(layer_size * m_depth);
844
845		if (m_is_array)
846		{
847			for (GLuint layer = 0; layer < m_depth; ++layer)
848			{
849				gl.framebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_id, 0, layer);
850				gl.readPixels(0, 0, m_width, m_height, read_format, type, &read_data[layer * layer_size]);
851			}
852		}
853		else
854		{
855			gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textarget, m_id, 0);
856			gl.readPixels(0, 0, m_width, m_height, read_format, type, &read_data[0]);
857		}
858		GLU_EXPECT_NO_ERROR(gl.getError(), "ReadPixels");
859		gl.deleteFramebuffers(1, &temp_fbo);
860
861		/* copy the first channel from the readback buffer to the output buffer */
862		GLint* out_data_int = (GLint*)out_data;
863		for (GLuint elem = 0; elem < (m_width * m_height * m_depth); ++elem)
864		{
865			out_data_int[elem] = read_data[elem * 4];
866		}
867	}
868}
869
870/** Delete texture
871 *
872 **/
873void Utils::texture::release()
874{
875	if (0 != m_id)
876	{
877		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
878
879		gl.deleteTextures(1, &m_id);
880		m_id = 0;
881	}
882}
883
884/** Update contents of texture
885 *
886 * @param width  Width of texture
887 * @param height Height of texture
888 * @param depth  Depth of texture
889 * @param format Format of data
890 * @param type   Type of data
891 * @param data   Buffer with image
892 **/
893void Utils::texture::update(glw::GLuint width, glw::GLuint height, glw::GLuint depth, glw::GLenum format,
894							glw::GLenum type, glw::GLvoid* data)
895{
896	static const GLuint level = 0;
897
898	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
899
900	bind();
901
902	if (false == m_is_array)
903	{
904		gl.texSubImage2D(GL_TEXTURE_2D, level, 0 /* x */, 0 /* y */, width, height, format, type, data);
905		GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D");
906	}
907	else
908	{
909		gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, level, 0 /* x */, 0 /* y */, 0 /* z */, width, height, depth, format,
910						 type, data);
911		GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D");
912	}
913}
914
915/** Constructor.
916 *
917 * @param context CTS context.
918 **/
919Utils::vertexArray::vertexArray(deqp::Context& context) : m_id(0), m_context(context)
920{
921}
922
923/** Destructor
924 *
925 **/
926Utils::vertexArray::~vertexArray()
927{
928	if (0 != m_id)
929	{
930		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
931
932		gl.deleteVertexArrays(1, &m_id);
933
934		m_id = 0;
935	}
936}
937
938/** Execute BindVertexArray
939 *
940 **/
941void Utils::vertexArray::bind()
942{
943	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
944
945	gl.bindVertexArray(m_id);
946	GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArray");
947}
948
949/** Execute GenVertexArrays
950 *
951 **/
952void Utils::vertexArray::generate()
953{
954	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
955
956	gl.genVertexArrays(1, &m_id);
957	GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays");
958}
959
960/** Constructor
961 *
962 * @param context          Test context
963 **/
964APIErrors::APIErrors(deqp::Context& context, const glcts::ExtParameters& extParams)
965	: TestCaseBase(context, extParams, "api_errors", "Test verifies error generated by API")
966{
967	/* Nothing to be done here */
968}
969
970template <typename T>
971void APIErrors::depthRangeArrayHelper(Utils::DepthFuncWrapper& depthFunc, GLint max_viewports, bool& test_result, T*)
972{
973	std::vector<T> data;
974	data.resize(max_viewports * 2 /* near + far */);
975
976	for (GLint i = 0; i < max_viewports; ++i)
977	{
978		data[i * 2]		= (T)0.0;
979		data[i * 2 + 1] = (T)1.0;
980	}
981
982	depthFunc.depthRangeArray(0, max_viewports - 1, &data[0]);
983	checkGLError(GL_NO_ERROR, "depthRangeArray, correct parameters", test_result);
984
985	depthFunc.depthRangeArray(max_viewports, 1, &data[0]);
986	checkGLError(GL_INVALID_VALUE, "depthRangeArray, <first> == GL_MAX_VIEWPORTS", test_result);
987
988	depthFunc.depthRangeArray(1, max_viewports - 1, &data[0]);
989	checkGLError(GL_NO_ERROR, "depthRangeArray, <first> + <count> == GL_MAX_VIEWPORTS", test_result);
990
991	depthFunc.depthRangeArray(1, max_viewports, &data[0]);
992	checkGLError(GL_INVALID_VALUE, "depthRangeArray, <first> + <count> > GL_MAX_VIEWPORTS", test_result);
993}
994
995template <typename T>
996void APIErrors::depthRangeIndexedHelper(Utils::DepthFuncWrapper& depthFunc, GLint max_viewports, bool& test_result, T*)
997{
998	depthFunc.depthRangeIndexed(0 /* index */, (T)0.0, (T)1.0);
999	checkGLError(GL_NO_ERROR, "depthRangeIndexed, <index> == 0", test_result);
1000
1001	depthFunc.depthRangeIndexed(max_viewports - 1 /* index */, (T)0.0, (T)1.0);
1002	checkGLError(GL_NO_ERROR, "depthRangeIndexed, <index> == GL_MAX_VIEWPORTS - 1", test_result);
1003
1004	depthFunc.depthRangeIndexed(max_viewports /* index */, (T)0.0, (T)1.0);
1005	checkGLError(GL_INVALID_VALUE, "depthRangeIndexed, <index> == GL_MAX_VIEWPORTS", test_result);
1006
1007	depthFunc.depthRangeIndexed(max_viewports + 1 /* index */, (T)0.0, (T)1.0);
1008	checkGLError(GL_INVALID_VALUE, "depthRangeIndexed, <index> > GL_MAX_VIEWPORTS", test_result);
1009}
1010
1011template <typename T>
1012void APIErrors::getDepthHelper(Utils::DepthFuncWrapper& depthFunc, GLint max_viewports, bool& test_result, T*)
1013{
1014	T data[4];
1015
1016	depthFunc.getDepthi_v(GL_DEPTH_RANGE, max_viewports - 1, data);
1017	checkGLError(GL_NO_ERROR, "getDouble/Floati_v, <index> == GL_MAX_VIEWPORTS - 1", test_result);
1018
1019	depthFunc.getDepthi_v(GL_DEPTH_RANGE, max_viewports, data);
1020	checkGLError(GL_INVALID_VALUE, "getDouble/Floati_v, <index> == GL_MAX_VIEWPORTS", test_result);
1021}
1022
1023/** Execute test
1024 *
1025 * @return tcu::TestNode::CONTINUE after executing test case, tcu::TestNode::STOP otherwise
1026 **/
1027tcu::TestNode::IterateResult APIErrors::iterate()
1028{
1029	if (!m_is_viewport_array_supported)
1030	{
1031		throw tcu::NotSupportedError(VIEWPORT_ARRAY_NOT_SUPPORTED, "", __FILE__, __LINE__);
1032	}
1033
1034	/* GL entry points */
1035	const glw::Functions&   gl			 = m_context.getRenderContext().getFunctions();
1036	const glu::ContextType& context_type = m_context.getRenderContext().getType();
1037	Utils::DepthFuncWrapper depthFunc(m_context);
1038
1039	/* Test result */
1040	bool test_result = true;
1041
1042	GLint max_viewports = 0;
1043	gl.getIntegerv(GL_MAX_VIEWPORTS, &max_viewports);
1044	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
1045
1046	/*
1047	 *   * DepthRangeArrayv generates INVALID_VALUE when <first> + <count> is greater
1048	 *   than or equal to the value of MAX_VIEWPORTS;
1049	 */
1050	if (glu::isContextTypeGLCore(context_type))
1051	{
1052		depthRangeArrayHelper<GLdouble>(depthFunc, max_viewports, test_result);
1053	}
1054	else
1055	{
1056		DE_ASSERT(glu::isContextTypeES(context_type));
1057		depthRangeArrayHelper<GLfloat>(depthFunc, max_viewports, test_result);
1058	}
1059
1060	/*
1061	 *   * DepthRangeIndexed generates INVALID_VALUE when <index> is greater than or
1062	 *   equal to the value of MAX_VIEWPORTS;
1063	 */
1064	if (glu::isContextTypeGLCore(context_type))
1065	{
1066		depthRangeIndexedHelper<GLdouble>(depthFunc, max_viewports, test_result);
1067	}
1068	else
1069	{
1070		DE_ASSERT(glu::isContextTypeES(context_type));
1071		depthRangeIndexedHelper<GLfloat>(depthFunc, max_viewports, test_result);
1072	}
1073
1074	/*
1075	 *   * ViewportArrayv generates INVALID_VALUE when <first> + <count> is greater
1076	 *   than or equal to the value of MAX_VIEWPORTS;
1077	 */
1078	{
1079		std::vector<GLfloat> data;
1080		data.resize(max_viewports * 4 /* x + y + w + h */);
1081
1082		for (GLint i = 0; i < max_viewports; ++i)
1083		{
1084			data[i * 4 + 0] = 0.0f;
1085			data[i * 4 + 1] = 0.0f;
1086			data[i * 4 + 2] = 1.0f;
1087			data[i * 4 + 3] = 1.0f;
1088		}
1089
1090		gl.viewportArrayv(0, max_viewports - 1, &data[0]);
1091		checkGLError(GL_NO_ERROR, "viewportArrayv, correct parameters", test_result);
1092
1093		gl.viewportArrayv(max_viewports, 1, &data[0]);
1094		checkGLError(GL_INVALID_VALUE, "viewportArrayv, <first> == GL_MAX_VIEWPORTS", test_result);
1095
1096		gl.viewportArrayv(1, max_viewports - 1, &data[0]);
1097		checkGLError(GL_NO_ERROR, "viewportArrayv, <first> + <count> == GL_MAX_VIEWPORTS", test_result);
1098
1099		gl.viewportArrayv(1, max_viewports, &data[0]);
1100		checkGLError(GL_INVALID_VALUE, "viewportArrayv, <first> + <count> > GL_MAX_VIEWPORTS", test_result);
1101	}
1102
1103	/*
1104	 *   * ViewportIndexedf and ViewportIndexedfv generate INVALID_VALUE when <index>
1105	 *   is greater than or equal to the value of MAX_VIEWPORTS;
1106	 */
1107	{
1108		GLfloat data[4 /* x + y + w + h */];
1109
1110		data[0] = 0.0f;
1111		data[1] = 0.0f;
1112		data[2] = 1.0f;
1113		data[3] = 1.0f;
1114
1115		gl.viewportIndexedf(0 /* index */, 0.0f, 0.0f, 1.0f, 1.0f);
1116		checkGLError(GL_NO_ERROR, "viewportIndexedf, <index> == 0", test_result);
1117
1118		gl.viewportIndexedf(max_viewports - 1 /* index */, 0.0f, 0.0f, 1.0f, 1.0f);
1119		checkGLError(GL_NO_ERROR, "viewportIndexedf, <index> == GL_MAX_VIEWPORTS - 1", test_result);
1120
1121		gl.viewportIndexedf(max_viewports /* index */, 0.0f, 0.0f, 1.0f, 1.0f);
1122		checkGLError(GL_INVALID_VALUE, "viewportIndexedf, <index> == GL_MAX_VIEWPORTS", test_result);
1123
1124		gl.viewportIndexedf(max_viewports + 1 /* index */, 0.0f, 0.0f, 1.0f, 1.0f);
1125		checkGLError(GL_INVALID_VALUE, "viewportIndexedf, <index> > GL_MAX_VIEWPORTS", test_result);
1126
1127		gl.viewportIndexedfv(0 /* index */, data);
1128		checkGLError(GL_NO_ERROR, "viewportIndexedfv, <index> == 0", test_result);
1129
1130		gl.viewportIndexedfv(max_viewports - 1 /* index */, data);
1131		checkGLError(GL_NO_ERROR, "viewportIndexedfv, <index> == GL_MAX_VIEWPORTS - 1", test_result);
1132
1133		gl.viewportIndexedfv(max_viewports /* index */, data);
1134		checkGLError(GL_INVALID_VALUE, "viewportIndexedfv, <index> == GL_MAX_VIEWPORTS", test_result);
1135
1136		gl.viewportIndexedfv(max_viewports + 1 /* index */, data);
1137		checkGLError(GL_INVALID_VALUE, "viewportIndexedfv, <index> > GL_MAX_VIEWPORTS", test_result);
1138	}
1139
1140	/*
1141	 *   * ViewportArrayv, Viewport, ViewportIndexedf and ViewportIndexedfv generate
1142	 *   INVALID_VALUE when <w> or <h> values are negative;
1143	 */
1144	{
1145		gl.viewport(0, 0, -1, 1);
1146		checkGLError(GL_INVALID_VALUE, "viewport, negative width", test_result);
1147
1148		gl.viewport(0, 0, 1, -1);
1149		checkGLError(GL_INVALID_VALUE, "viewport, negative height", test_result);
1150
1151		for (GLint i = 0; i < max_viewports; ++i)
1152		{
1153			std::vector<GLfloat> data;
1154			data.resize(max_viewports * 4 /* x + y + w + h */);
1155
1156			for (GLint j = 0; j < max_viewports; ++j)
1157			{
1158				data[j * 4 + 0] = 0.0f;
1159				data[j * 4 + 1] = 0.0f;
1160				data[j * 4 + 2] = 1.0f;
1161				data[j * 4 + 3] = 1.0f;
1162			}
1163
1164			/* Set width to -1 */
1165			data[i * 4 + 2] = -1.0f;
1166
1167			gl.viewportArrayv(0, max_viewports, &data[0]);
1168			checkGLError(GL_INVALID_VALUE, "viewportArrayv, negative width", test_result);
1169
1170			gl.viewportIndexedf(i /* index */, 0.0f, 0.0f, -1.0f, 1.0f);
1171			checkGLError(GL_INVALID_VALUE, "viewportIndexedf, negative width", test_result);
1172
1173			gl.viewportIndexedfv(i /* index */, &data[i * 4]);
1174			checkGLError(GL_INVALID_VALUE, "viewportIndexedfv, negative width", test_result);
1175
1176			/* Set width to 1 and height to -1*/
1177			data[i * 4 + 2] = 1.0f;
1178			data[i * 4 + 3] = -1.0f;
1179
1180			gl.viewportArrayv(0, max_viewports, &data[0]);
1181			checkGLError(GL_INVALID_VALUE, "viewportArrayv, negative height", test_result);
1182
1183			gl.viewportIndexedf(i /* index */, 0.0f, 0.0f, 1.0f, -1.0f);
1184			checkGLError(GL_INVALID_VALUE, "viewportIndexedf, negative height", test_result);
1185
1186			gl.viewportIndexedfv(i /* index */, &data[i * 4]);
1187			checkGLError(GL_INVALID_VALUE, "viewportIndexedfv, negative height", test_result);
1188		}
1189	}
1190
1191	/*
1192	 *   * ScissorArrayv generates INVALID_VALUE when <first> + <count> is greater
1193	 *   than or equal to the value of MAX_VIEWPORTS;
1194	 */
1195	{
1196		std::vector<GLint> data;
1197		data.resize(max_viewports * 4 /* x + y + w + h */);
1198
1199		for (GLint i = 0; i < max_viewports; ++i)
1200		{
1201			data[i * 4 + 0] = 0;
1202			data[i * 4 + 1] = 0;
1203			data[i * 4 + 2] = 1;
1204			data[i * 4 + 3] = 1;
1205		}
1206
1207		gl.scissorArrayv(0, max_viewports - 1, &data[0]);
1208		checkGLError(GL_NO_ERROR, "scissorArrayv, correct parameters", test_result);
1209
1210		gl.scissorArrayv(max_viewports, 1, &data[0]);
1211		checkGLError(GL_INVALID_VALUE, "scissorArrayv, <first> == GL_MAX_VIEWPORTS", test_result);
1212
1213		gl.scissorArrayv(1, max_viewports - 1, &data[0]);
1214		checkGLError(GL_NO_ERROR, "scissorArrayv, <first> + <count> == GL_MAX_VIEWPORTS", test_result);
1215
1216		gl.scissorArrayv(1, max_viewports, &data[0]);
1217		checkGLError(GL_INVALID_VALUE, "scissorArrayv, <first> + <count> > GL_MAX_VIEWPORTS", test_result);
1218	}
1219
1220	/*
1221	 *   * ScissorIndexed and ScissorIndexedv generate INVALID_VALUE when <index> is
1222	 *   greater than or equal to the value of MAX_VIEWPORTS;
1223	 */
1224	{
1225		GLint data[4 /* x + y + w + h */];
1226
1227		data[0] = 0;
1228		data[1] = 0;
1229		data[2] = 1;
1230		data[3] = 1;
1231
1232		gl.scissorIndexed(0 /* index */, 0, 0, 1, 1);
1233		checkGLError(GL_NO_ERROR, "scissorIndexed, <index> == 0", test_result);
1234
1235		gl.scissorIndexed(max_viewports - 1 /* index */, 0, 0, 1, 1);
1236		checkGLError(GL_NO_ERROR, "scissorIndexed, <index> == GL_MAX_VIEWPORTS - 1", test_result);
1237
1238		gl.scissorIndexed(max_viewports /* index */, 0, 0, 1, 1);
1239		checkGLError(GL_INVALID_VALUE, "scissorIndexed, <index> == GL_MAX_VIEWPORTS", test_result);
1240
1241		gl.scissorIndexed(max_viewports + 1 /* index */, 0, 0, 1, 1);
1242		checkGLError(GL_INVALID_VALUE, "scissorIndexed, <index> > GL_MAX_VIEWPORTS", test_result);
1243
1244		gl.scissorIndexedv(0 /* index */, data);
1245		checkGLError(GL_NO_ERROR, "scissorIndexedv, <index> == 0", test_result);
1246
1247		gl.scissorIndexedv(max_viewports - 1 /* index */, data);
1248		checkGLError(GL_NO_ERROR, "scissorIndexedv, <index> == GL_MAX_VIEWPORTS - 1", test_result);
1249
1250		gl.scissorIndexedv(max_viewports /* index */, data);
1251		checkGLError(GL_INVALID_VALUE, "scissorIndexedv, <index> == GL_MAX_VIEWPORTS", test_result);
1252
1253		gl.scissorIndexedv(max_viewports + 1 /* index */, data);
1254		checkGLError(GL_INVALID_VALUE, "scissorIndexedv, <index> > GL_MAX_VIEWPORTS", test_result);
1255	}
1256
1257	/*
1258	 *   * ScissorArrayv, ScissorIndexed, ScissorIndexedv and Scissor generate
1259	 *   INVALID_VALUE when <width> or <height> values are negative;
1260	 */
1261	{
1262		gl.scissor(0, 0, -1, 1);
1263		checkGLError(GL_INVALID_VALUE, "scissor, negative width", test_result);
1264
1265		gl.scissor(0, 0, 1, -1);
1266		checkGLError(GL_INVALID_VALUE, "scissor, negative height", test_result);
1267
1268		for (GLint i = 0; i < max_viewports; ++i)
1269		{
1270			std::vector<GLint> data;
1271			data.resize(max_viewports * 4 /* x + y + w + h */);
1272
1273			for (GLint j = 0; j < max_viewports; ++j)
1274			{
1275				data[j * 4 + 0] = 0;
1276				data[j * 4 + 1] = 0;
1277				data[j * 4 + 2] = 1;
1278				data[j * 4 + 3] = 1;
1279			}
1280
1281			/* Set width to -1 */
1282			data[i * 4 + 2] = -1;
1283
1284			gl.scissorArrayv(0, max_viewports, &data[0]);
1285			checkGLError(GL_INVALID_VALUE, "scissorArrayv, negative width", test_result);
1286
1287			gl.scissorIndexed(i /* index */, 0, 0, -1, 1);
1288			checkGLError(GL_INVALID_VALUE, "scissorIndexed, negative width", test_result);
1289
1290			gl.scissorIndexedv(i /* index */, &data[i * 4]);
1291			checkGLError(GL_INVALID_VALUE, "scissorIndexedv, negative width", test_result);
1292
1293			/* Set width to 1 and height to -1*/
1294			data[i * 4 + 2] = 1;
1295			data[i * 4 + 3] = -1;
1296
1297			gl.scissorArrayv(0, max_viewports, &data[0]);
1298			checkGLError(GL_INVALID_VALUE, "scissorArrayv, negative height", test_result);
1299
1300			gl.scissorIndexed(i /* index */, 0, 0, 1, -1);
1301			checkGLError(GL_INVALID_VALUE, "scissorIndexed, negative height", test_result);
1302
1303			gl.scissorIndexedv(i /* index */, &data[i * 4]);
1304			checkGLError(GL_INVALID_VALUE, "scissorIndexedv, negative height", test_result);
1305		}
1306	}
1307
1308	/*
1309	 *   * Disablei, Enablei and IsEnabledi generate INVALID_VALUE when <cap> is
1310	 *   SCISSOR_TEST and <index> is greater than or equal to the
1311	 *   value of MAX_VIEWPORTS;
1312	 */
1313	{
1314		gl.disablei(GL_SCISSOR_TEST, max_viewports - 1);
1315		checkGLError(GL_NO_ERROR, "disablei, <index> == GL_MAX_VIEWPORTS - 1", test_result);
1316
1317		gl.disablei(GL_SCISSOR_TEST, max_viewports);
1318		checkGLError(GL_INVALID_VALUE, "disablei, <index> == GL_MAX_VIEWPORTS", test_result);
1319
1320		gl.enablei(GL_SCISSOR_TEST, max_viewports - 1);
1321		checkGLError(GL_NO_ERROR, "enablei, <index> == GL_MAX_VIEWPORTS - 1", test_result);
1322
1323		gl.enablei(GL_SCISSOR_TEST, max_viewports);
1324		checkGLError(GL_INVALID_VALUE, "enablei, <index> == GL_MAX_VIEWPORTS", test_result);
1325
1326		gl.isEnabledi(GL_SCISSOR_TEST, max_viewports - 1);
1327		checkGLError(GL_NO_ERROR, "isEnabledi, <index> == GL_MAX_VIEWPORTS - 1", test_result);
1328
1329		gl.isEnabledi(GL_SCISSOR_TEST, max_viewports);
1330		checkGLError(GL_INVALID_VALUE, "isEnabledi, <index> == GL_MAX_VIEWPORTS", test_result);
1331	}
1332
1333	/*
1334	 *   * GetIntegeri_v generates INVALID_VALUE when <target> is SCISSOR_BOX and
1335	 *   <index> is greater than or equal to the value of MAX_VIEWPORTS;
1336	 */
1337	{
1338		GLint data[4];
1339
1340		gl.getIntegeri_v(GL_SCISSOR_BOX, max_viewports - 1, data);
1341		checkGLError(GL_NO_ERROR, "getIntegeri_v, <index> == GL_MAX_VIEWPORTS - 1", test_result);
1342
1343		gl.getIntegeri_v(GL_SCISSOR_BOX, max_viewports, data);
1344		checkGLError(GL_INVALID_VALUE, "getIntegeri_v, <index> == GL_MAX_VIEWPORTS", test_result);
1345	}
1346
1347	/*
1348	 *   * GetFloati_v generates INVALID_VALUE when <target> is VIEWPORT and <index>
1349	 *   is greater than or equal to the value of MAX_VIEWPORTS;
1350	 */
1351	{
1352		GLfloat data[4];
1353
1354		gl.getFloati_v(GL_VIEWPORT, max_viewports - 1, data);
1355		checkGLError(GL_NO_ERROR, "getFloati_v, <index> == GL_MAX_VIEWPORTS - 1", test_result);
1356
1357		gl.getFloati_v(GL_VIEWPORT, max_viewports, data);
1358		checkGLError(GL_INVALID_VALUE, "getFloati_v, <index> == GL_MAX_VIEWPORTS", test_result);
1359	}
1360
1361	/*
1362	 *   * GetDoublei_v generates INVALID_VALUE when <target> is DEPTH_RANGE and
1363	 *   <index> is greater than or equal to the value of MAX_VIEWPORTS;
1364	 */
1365	if (glu::isContextTypeGLCore(context_type))
1366	{
1367		getDepthHelper<GLdouble>(depthFunc, max_viewports, test_result);
1368	}
1369	else
1370	{
1371		DE_ASSERT(glu::isContextTypeES(context_type));
1372		getDepthHelper<GLfloat>(depthFunc, max_viewports, test_result);
1373	}
1374
1375	/* Set result */
1376	if (true == test_result)
1377	{
1378		m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
1379	}
1380	else
1381	{
1382		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1383	}
1384
1385	/* Done */
1386	return tcu::TestNode::STOP;
1387}
1388
1389/** Check if glGetError returns expected error
1390 *
1391 * @param expected_error Expected error code
1392 * @param description    Description of test case
1393 * @param out_result     Set to false if the current error is not equal to expected one
1394 **/
1395void APIErrors::checkGLError(GLenum expected_error, const GLchar* description, bool& out_result)
1396{
1397	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1398
1399	GLenum error = gl.getError();
1400
1401	if (expected_error != error)
1402	{
1403		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Test case fail. Description: " << description
1404											<< " Invalid error: " << glu::getErrorStr(error)
1405											<< " expected: " << glu::getErrorStr(expected_error)
1406											<< tcu::TestLog::EndMessage;
1407
1408		out_result = false;
1409	}
1410}
1411
1412/** Constructor
1413 *
1414 * @param context          Test context
1415 **/
1416Queries::Queries(deqp::Context& context, const glcts::ExtParameters& extParams)
1417	: TestCaseBase(context, extParams, "queries", "Test verifies initial state of API")
1418{
1419	/* Nothing to be done here */
1420}
1421
1422template <typename T>
1423void Queries::depthRangeInitialValuesHelper(Utils::DepthFuncWrapper& depthFunc, GLint max_viewports, bool& test_result,
1424											T*)
1425{
1426	std::vector<T> data;
1427	data.resize(max_viewports * 2 /* near + far */);
1428
1429	for (GLint i = 0; i < max_viewports; ++i)
1430	{
1431		depthFunc.getDepthi_v(GL_DEPTH_RANGE, i, &data[i * 2]);
1432		GLU_EXPECT_NO_ERROR(depthFunc.getFunctions().getError(), "getDouble/Floati_v");
1433	}
1434
1435	for (GLint i = 0; i < max_viewports; ++i)
1436	{
1437		GLint near = (GLint)data[2 * i + 0];
1438		GLint far  = (GLint)data[2 * i + 1];
1439
1440		if ((0.0 != near) || (1.0 != far))
1441		{
1442			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid initial depth range [" << i
1443												<< "]: " << near << " : " << far << " expected: 0.0 : 1.0"
1444												<< tcu::TestLog::EndMessage;
1445
1446			test_result = false;
1447			break;
1448		}
1449	}
1450}
1451/** Execute test
1452 *
1453 * @return tcu::TestNode::CONTINUE after executing test case, tcu::TestNode::STOP otherwise
1454 **/
1455tcu::TestNode::IterateResult Queries::iterate()
1456{
1457	if (!m_is_viewport_array_supported)
1458	{
1459		throw tcu::NotSupportedError(VIEWPORT_ARRAY_NOT_SUPPORTED, "", __FILE__, __LINE__);
1460	}
1461
1462	/* GL entry points */
1463	const glw::Functions&   gl			 = m_context.getRenderContext().getFunctions();
1464	const glu::ContextType& context_type = m_context.getRenderContext().getType();
1465	Utils::DepthFuncWrapper depthFunc(m_context);
1466
1467	/* Test result */
1468	bool test_result = true;
1469
1470	GLint   layer_provoking_vertex	= 0;
1471	GLint   max_viewports			  = 0;
1472	GLfloat max_renderbuffer_size	 = 0.0f;
1473	GLfloat max_viewport_dims[2]	  = { 0.0f, 0.0f };
1474	GLfloat viewport_bounds_range[2]  = { 0.0, 0.0f };
1475	GLint   viewport_provoking_vertex = 0;
1476	GLint   viewport_subpixel_bits	= -1;
1477
1478	gl.getIntegerv(GL_LAYER_PROVOKING_VERTEX, &layer_provoking_vertex);
1479	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
1480
1481	gl.getIntegerv(GL_MAX_VIEWPORTS, &max_viewports);
1482	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
1483
1484	gl.getFloatv(GL_MAX_RENDERBUFFER_SIZE, &max_renderbuffer_size);
1485	GLU_EXPECT_NO_ERROR(gl.getError(), "getFloatv");
1486
1487	gl.getFloatv(GL_MAX_VIEWPORT_DIMS, max_viewport_dims);
1488	GLU_EXPECT_NO_ERROR(gl.getError(), "GetFloatv");
1489
1490	gl.getFloatv(GL_VIEWPORT_BOUNDS_RANGE, viewport_bounds_range);
1491	GLU_EXPECT_NO_ERROR(gl.getError(), "GetFloatv");
1492
1493	gl.getIntegerv(GL_VIEWPORT_INDEX_PROVOKING_VERTEX, &viewport_provoking_vertex);
1494	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
1495
1496	gl.getIntegerv(GL_VIEWPORT_SUBPIXEL_BITS, &viewport_subpixel_bits);
1497	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
1498
1499	const GLint window_width  = m_context.getRenderContext().getRenderTarget().getWidth();
1500	const GLint window_height = m_context.getRenderContext().getRenderTarget().getHeight();
1501
1502	/*
1503	 *   * Initial dimensions of VIEWPORT returned by GetFloati_v match dimensions of
1504	 *   the window into which GL is rendering;
1505	 */
1506	{
1507		std::vector<GLfloat> data;
1508		data.resize(max_viewports * 4 /* x + y + w+ h */);
1509
1510		for (GLint i = 0; i < max_viewports; ++i)
1511		{
1512			gl.getFloati_v(GL_VIEWPORT, i, &data[i * 4]);
1513			GLU_EXPECT_NO_ERROR(gl.getError(), "GetFloati_v");
1514		}
1515
1516		for (GLint i = 0; i < max_viewports; ++i)
1517		{
1518			GLint viewport_width  = (GLint)data[4 * i + 2];
1519			GLint viewport_height = (GLint)data[4 * i + 3];
1520
1521			if ((window_width != viewport_width) || (window_height != viewport_height))
1522			{
1523				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid initial viewport [" << i
1524													<< "] dimennsions: " << viewport_width << " x " << viewport_height
1525													<< " expected: " << window_width << " x " << window_height
1526													<< tcu::TestLog::EndMessage;
1527
1528				test_result = false;
1529				break;
1530			}
1531		}
1532	}
1533
1534	/*
1535	 *   * Initial values of DEPTH_RANGE returned by GetDoublei_v are [0, 1];
1536	 */
1537	if (glu::isContextTypeGLCore(context_type))
1538	{
1539		depthRangeInitialValuesHelper<GLdouble>(depthFunc, max_viewports, test_result);
1540	}
1541	else
1542	{
1543		DE_ASSERT(glu::isContextTypeES(context_type));
1544		depthRangeInitialValuesHelper<GLfloat>(depthFunc, max_viewports, test_result);
1545	}
1546
1547	/*
1548	 *   * Initial state of SCISSOR_TEST returned by IsEnabledi is FALSE;
1549	 */
1550	{
1551		for (GLint i = 0; i < max_viewports; ++i)
1552		{
1553			if (GL_FALSE != gl.isEnabledi(GL_SCISSOR_TEST, i))
1554			{
1555				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Scissor test is enabled at " << i
1556													<< ". Expected disabled." << tcu::TestLog::EndMessage;
1557
1558				test_result = false;
1559				break;
1560			}
1561		}
1562	}
1563
1564	/*
1565	 *   * Initial dimensions of SCISSOR_BOX returned by GetIntegeri_v are either
1566	 *   zeros or match dimensions of the window into which GL is rendering;
1567	 */
1568	{
1569		std::vector<GLint> data;
1570		data.resize(max_viewports * 4 /* x + y + w+ h */);
1571
1572		for (GLint i = 0; i < max_viewports; ++i)
1573		{
1574			gl.getIntegeri_v(GL_SCISSOR_BOX, i, &data[i * 4]);
1575			GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegeri_v");
1576		}
1577
1578		for (GLint i = 0; i < max_viewports; ++i)
1579		{
1580			GLint scissor_width  = data[4 * i + 2];
1581			GLint scissor_height = data[4 * i + 3];
1582
1583			if ((window_width != scissor_width) || (window_height != scissor_height))
1584			{
1585				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid initial scissor box [" << i
1586													<< "] dimennsions: " << scissor_width << " x " << scissor_height
1587													<< " expected: " << window_width << " x " << window_height
1588													<< tcu::TestLog::EndMessage;
1589
1590				test_result = false;
1591				break;
1592			}
1593		}
1594	}
1595
1596	/*
1597	 *   * Dimensions of MAX_VIEWPORT_DIMS returned by GetFloati_v are at least
1598	 *   as big as supported dimensions of render buffers, see MAX_RENDERBUFFER_SIZE;
1599	 */
1600	{
1601		if ((max_viewport_dims[0] < max_renderbuffer_size) || (max_viewport_dims[1] < max_renderbuffer_size))
1602		{
1603			m_context.getTestContext().getLog()
1604				<< tcu::TestLog::Message << "Invalid MAX_VIEWPORT_DIMS: " << max_viewport_dims[0] << " x "
1605				<< max_viewport_dims[1] << " expected: " << max_renderbuffer_size << " x " << max_renderbuffer_size
1606				<< tcu::TestLog::EndMessage;
1607
1608			test_result = false;
1609		}
1610	}
1611
1612	/*
1613	 *   * Value of MAX_VIEWPORTS returned by GetIntegeri_v is at least 16;
1614	 */
1615	{
1616		if (16 > max_viewports)
1617		{
1618			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid MAX_VIEWPORTS: " << max_viewports
1619												<< " expected at least 16." << tcu::TestLog::EndMessage;
1620
1621			test_result = false;
1622		}
1623	}
1624
1625	/*
1626	 *   * Value of VIEWPORT_SUBPIXEL_BITS returned by GetIntegeri_v is at least 0;
1627	 */
1628	{
1629		if (0 > viewport_subpixel_bits)
1630		{
1631			m_context.getTestContext().getLog() << tcu::TestLog::Message
1632												<< "Invalid VIEWPORT_SUBPIXEL_BITS: " << viewport_subpixel_bits
1633												<< " expected at least 0." << tcu::TestLog::EndMessage;
1634
1635			test_result = false;
1636		}
1637	}
1638
1639	/*
1640	 *   * Values of VIEWPORT_BOUNDS_RANGE returned by GetFloatv are
1641	 *   at least [-32768, 32767];
1642	 */
1643	{
1644		if ((-32768.0f < viewport_bounds_range[0]) || (32767.0f > viewport_bounds_range[1]))
1645		{
1646			m_context.getTestContext().getLog()
1647				<< tcu::TestLog::Message << "Invalid VIEWPORT_BOUNDS_RANGE: " << viewport_bounds_range[0] << " : "
1648				<< viewport_bounds_range[1] << " expected at least: -32768.0f : 32767.0f" << tcu::TestLog::EndMessage;
1649
1650			test_result = false;
1651		}
1652	}
1653
1654	/*
1655	 *   * Values of LAYER_PROVOKING_VERTEX and VIEWPORT_INDEX_PROVOKING_VERTEX
1656	 *   returned by GetIntegerv are located in the following set
1657	 *   { FIRST_VERTEX_CONVENTION, LAST_VERTEX_CONVENTION, PROVOKING_VERTEX,
1658	 *   UNDEFINED_VERTEX };
1659	 */
1660	{
1661		switch (layer_provoking_vertex)
1662		{
1663		case GL_FIRST_VERTEX_CONVENTION:
1664		case GL_LAST_VERTEX_CONVENTION:
1665		case GL_PROVOKING_VERTEX:
1666		case GL_UNDEFINED_VERTEX:
1667			break;
1668		default:
1669			m_context.getTestContext().getLog() << tcu::TestLog::Message
1670												<< "Invalid LAYER_PROVOKING_VERTEX: " << layer_provoking_vertex
1671												<< tcu::TestLog::EndMessage;
1672
1673			test_result = false;
1674		}
1675
1676		switch (viewport_provoking_vertex)
1677		{
1678		case GL_FIRST_VERTEX_CONVENTION:
1679		case GL_LAST_VERTEX_CONVENTION:
1680		case GL_PROVOKING_VERTEX:
1681		case GL_UNDEFINED_VERTEX:
1682			break;
1683		default:
1684			m_context.getTestContext().getLog() << tcu::TestLog::Message
1685												<< "Invalid LAYER_PROVOKING_VERTEX: " << layer_provoking_vertex
1686												<< tcu::TestLog::EndMessage;
1687
1688			test_result = false;
1689		}
1690	}
1691
1692	/* Set result */
1693	if (true == test_result)
1694	{
1695		m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
1696	}
1697	else
1698	{
1699		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1700	}
1701
1702	/* Done */
1703	return tcu::TestNode::STOP;
1704}
1705
1706/* Constants used by ViewportAPI */
1707const GLuint ViewportAPI::m_n_elements = 4;
1708
1709/** Constructor
1710 *
1711 * @param context          Test context
1712 **/
1713ViewportAPI::ViewportAPI(deqp::Context& context, const glcts::ExtParameters& extParams)
1714	: TestCaseBase(context, extParams, "viewport_api", "Test verifies that \viewport api\" works as expected")
1715{
1716	/* Nothing to be done here */
1717}
1718
1719/** Execute test
1720 *
1721 * @return tcu::TestNode::CONTINUE after executing test case, tcu::TestNode::STOP otherwise
1722 **/
1723tcu::TestNode::IterateResult ViewportAPI::iterate()
1724{
1725	if (!m_is_viewport_array_supported)
1726	{
1727		throw tcu::NotSupportedError(VIEWPORT_ARRAY_NOT_SUPPORTED, "", __FILE__, __LINE__);
1728	}
1729
1730	/* GL entry points */
1731	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1732
1733	/* Test result */
1734	bool test_result = true;
1735
1736	GLint max_viewports = 0;
1737
1738	gl.getIntegerv(GL_MAX_VIEWPORTS, &max_viewports);
1739	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
1740
1741	std::vector<GLfloat> scissor_box_data_a;
1742	std::vector<GLfloat> scissor_box_data_b;
1743
1744	scissor_box_data_a.resize(max_viewports * m_n_elements);
1745	scissor_box_data_b.resize(max_viewports * m_n_elements);
1746
1747	/*
1748	 *   - get initial dimensions of VIEWPORT for all MAX_VIEWPORTS indices;
1749	 *   - change location and dimensions of all indices at once with
1750	 *   ViewportArrayv;
1751	 *   - get VIEWPORT for all MAX_VIEWPORTS indices and verify results;
1752	 */
1753	getViewports(max_viewports, scissor_box_data_a);
1754
1755	for (GLint i = 0; i < max_viewports; ++i)
1756	{
1757		scissor_box_data_a[i * m_n_elements + 0] += 0.125f;
1758		scissor_box_data_a[i * m_n_elements + 1] += 0.125f;
1759		scissor_box_data_a[i * m_n_elements + 2] -= 0.125f;
1760		scissor_box_data_a[i * m_n_elements + 3] -= 0.125f;
1761	}
1762
1763	gl.viewportArrayv(0, max_viewports, &scissor_box_data_a[0]);
1764	GLU_EXPECT_NO_ERROR(gl.getError(), "viewportArrayv");
1765
1766	getViewports(max_viewports, scissor_box_data_b);
1767	compareViewports(scissor_box_data_a, scissor_box_data_b, "viewportArrayv", test_result);
1768
1769	/*
1770	 *   - for each index:
1771	 *     * modify with ViewportIndexedf,
1772	 *     * get VIEWPORT for all MAX_VIEWPORTS indices and verify results;
1773	 */
1774	for (GLint i = 0; i < max_viewports; ++i)
1775	{
1776		scissor_box_data_b[i * m_n_elements + 0] = 0.25f;
1777		scissor_box_data_b[i * m_n_elements + 1] = 0.25f;
1778		scissor_box_data_b[i * m_n_elements + 2] = 0.75f;
1779		scissor_box_data_b[i * m_n_elements + 3] = 0.75f;
1780
1781		gl.viewportIndexedf(i, 0.25f, 0.25f, 0.75f, 0.75f);
1782		GLU_EXPECT_NO_ERROR(gl.getError(), "viewportIndexedf");
1783
1784		getViewports(max_viewports, scissor_box_data_a);
1785		compareViewports(scissor_box_data_a, scissor_box_data_b, "viewportIndexedf", test_result);
1786	}
1787
1788	/*
1789	 *   - for each index:
1790	 *     * modify with ViewportIndexedfv,
1791	 *     * get VIEWPORT for all MAX_VIEWPORTS indices and verify results;
1792	 */
1793	for (GLint i = 0; i < max_viewports; ++i)
1794	{
1795		scissor_box_data_a[i * m_n_elements + 0] = 0.375f;
1796		scissor_box_data_a[i * m_n_elements + 1] = 0.375f;
1797		scissor_box_data_a[i * m_n_elements + 2] = 0.625f;
1798		scissor_box_data_a[i * m_n_elements + 3] = 0.625f;
1799
1800		gl.viewportIndexedfv(i, &scissor_box_data_a[i * m_n_elements]);
1801		GLU_EXPECT_NO_ERROR(gl.getError(), "viewportIndexedfv");
1802
1803		getViewports(max_viewports, scissor_box_data_b);
1804		compareViewports(scissor_box_data_a, scissor_box_data_b, "viewportIndexedfv", test_result);
1805	}
1806
1807	/*
1808	 *   - for each index:
1809	 *     * modify all indices before and after current one with ViewportArrayv,
1810	 *     * get VIEWPORT for all MAX_VIEWPORTS indices and verify results;
1811	 */
1812	for (GLint i = 0; i < max_viewports; ++i)
1813	{
1814		const GLfloat value = (0 == i % 2) ? 1.0f : 0.25f;
1815
1816		for (GLint j = 0; j < i; ++j)
1817		{
1818			scissor_box_data_b[j * m_n_elements + 0] = value;
1819			scissor_box_data_b[j * m_n_elements + 1] = value;
1820			scissor_box_data_b[j * m_n_elements + 2] = value;
1821			scissor_box_data_b[j * m_n_elements + 3] = value;
1822		}
1823
1824		for (GLint j = i + 1; j < max_viewports; ++j)
1825		{
1826			scissor_box_data_b[j * m_n_elements + 0] = value;
1827			scissor_box_data_b[j * m_n_elements + 1] = value;
1828			scissor_box_data_b[j * m_n_elements + 2] = value;
1829			scissor_box_data_b[j * m_n_elements + 3] = value;
1830		}
1831
1832		gl.viewportArrayv(0, max_viewports, &scissor_box_data_b[0]);
1833		GLU_EXPECT_NO_ERROR(gl.getError(), "viewportArrayv");
1834
1835		getViewports(max_viewports, scissor_box_data_a);
1836		compareViewports(scissor_box_data_a, scissor_box_data_b, "viewportArrayv", test_result);
1837	}
1838
1839	/*
1840	 *   - change location and dimensions of all indices at once with Viewport;
1841	 *   - get VIEWPORT for all MAX_VIEWPORTS indices and verify results;
1842	 */
1843	for (GLint i = 0; i < max_viewports; ++i)
1844	{
1845		scissor_box_data_a[i * m_n_elements + 0] = 0.0f;
1846		scissor_box_data_a[i * m_n_elements + 1] = 0.0f;
1847		scissor_box_data_a[i * m_n_elements + 2] = 1.0f;
1848		scissor_box_data_a[i * m_n_elements + 3] = 1.0f;
1849	}
1850
1851	gl.viewport(0, 0, 1, 1);
1852	GLU_EXPECT_NO_ERROR(gl.getError(), "viewport");
1853
1854	getViewports(max_viewports, scissor_box_data_b);
1855	compareViewports(scissor_box_data_a, scissor_box_data_b, "viewport", test_result);
1856
1857	/* Set result */
1858	if (true == test_result)
1859	{
1860		m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
1861	}
1862	else
1863	{
1864		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
1865	}
1866
1867	/* Done */
1868	return tcu::TestNode::STOP;
1869}
1870
1871/** Compare two sets of viewport data (simple vector comparison)
1872 *
1873 * @param left        Left set
1874 * @param right       Right set
1875 * @param description Test case description
1876 * @param out_result  Set to false if sets are different, not modified otherwise
1877 **/
1878void ViewportAPI::compareViewports(std::vector<GLfloat>& left, std::vector<GLfloat>& right, const GLchar* description,
1879								   bool& out_result)
1880{
1881	for (size_t i = 0; i < left.size(); ++i)
1882	{
1883		if (left[i] != right[i])
1884		{
1885			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Test case: " << description
1886												<< " Invalid values [" << i << "] " << left[i] << " " << right[i]
1887												<< tcu::TestLog::EndMessage;
1888
1889			out_result = false;
1890		}
1891	}
1892}
1893
1894/** Get position of all viewports
1895 *
1896 * @param max_viewports Number of viewports to capture, MAX_VIEWPORTS
1897 * @param data          Memory buffer prepared for captured data
1898 **/
1899void ViewportAPI::getViewports(GLint max_viewports, std::vector<GLfloat>& out_data)
1900{
1901	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1902
1903	for (GLint i = 0; i < max_viewports; ++i)
1904	{
1905		gl.getFloati_v(GL_VIEWPORT, i, &out_data[i * 4]);
1906		GLU_EXPECT_NO_ERROR(gl.getError(), "getFloati_v");
1907	}
1908}
1909
1910/* Constants used by ScissorAPI */
1911const GLuint ScissorAPI::m_n_elements = 4;
1912
1913/** Constructor
1914 *
1915 * @param context          Test context
1916 **/
1917ScissorAPI::ScissorAPI(deqp::Context& context, const glcts::ExtParameters& extParams)
1918	: TestCaseBase(context, extParams, "scissor_api", "Test verifies that \"scissor api\" works as expected")
1919{
1920	/* Nothing to be done here */
1921}
1922
1923/** Execute test
1924 *
1925 * @return tcu::TestNode::CONTINUE after executing test case, tcu::TestNode::STOP otherwise
1926 **/
1927tcu::TestNode::IterateResult ScissorAPI::iterate()
1928{
1929	if (!m_is_viewport_array_supported)
1930	{
1931		throw tcu::NotSupportedError(VIEWPORT_ARRAY_NOT_SUPPORTED, "", __FILE__, __LINE__);
1932	}
1933
1934	/* GL entry points */
1935	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1936
1937	/* Test result */
1938	bool test_result = true;
1939
1940	GLint max_viewports = 0;
1941
1942	gl.getIntegerv(GL_MAX_VIEWPORTS, &max_viewports);
1943	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
1944
1945	std::vector<GLint> scissor_box_data_a;
1946	std::vector<GLint> scissor_box_data_b;
1947
1948	scissor_box_data_a.resize(max_viewports * m_n_elements);
1949	scissor_box_data_b.resize(max_viewports * m_n_elements);
1950
1951	/*
1952	 *   - get initial dimensions of SCISSOR_BOX for all MAX_VIEWPORTS indices;
1953	 *   - change location and dimensions of all indices at once with
1954	 *   ScissorArrayv;
1955	 *   - get SCISSOR_BOX for all MAX_VIEWPORTS indices and verify results;
1956	 */
1957	getScissorBoxes(max_viewports, scissor_box_data_a);
1958
1959	for (GLint i = 0; i < max_viewports; ++i)
1960	{
1961		scissor_box_data_a[i * m_n_elements + 0] += 1;
1962		scissor_box_data_a[i * m_n_elements + 1] += 1;
1963		scissor_box_data_a[i * m_n_elements + 2] -= 1;
1964		scissor_box_data_a[i * m_n_elements + 3] -= 1;
1965	}
1966
1967	gl.scissorArrayv(0, max_viewports, &scissor_box_data_a[0]);
1968	GLU_EXPECT_NO_ERROR(gl.getError(), "scissorArrayv");
1969
1970	getScissorBoxes(max_viewports, scissor_box_data_b);
1971	compareScissorBoxes(scissor_box_data_a, scissor_box_data_b, "scissorArrayv", test_result);
1972
1973	/*
1974	 *   - for each index:
1975	 *     * modify with ScissorIndexed,
1976	 *     * get SCISSOR_BOX for all MAX_VIEWPORTS indices and verify results;
1977	 */
1978	for (GLint i = 0; i < max_viewports; ++i)
1979	{
1980		scissor_box_data_b[i * m_n_elements + 0] = 4;
1981		scissor_box_data_b[i * m_n_elements + 1] = 4;
1982		scissor_box_data_b[i * m_n_elements + 2] = 8;
1983		scissor_box_data_b[i * m_n_elements + 3] = 8;
1984
1985		gl.scissorIndexed(i, 4, 4, 8, 8);
1986		GLU_EXPECT_NO_ERROR(gl.getError(), "scissorIndexed");
1987
1988		getScissorBoxes(max_viewports, scissor_box_data_a);
1989		compareScissorBoxes(scissor_box_data_a, scissor_box_data_b, "scissorIndexed", test_result);
1990	}
1991
1992	/*
1993	 *   - for each index:
1994	 *     * modify with ScissorIndexedv,
1995	 *     * get SCISSOR_BOX for all MAX_VIEWPORTS indices and verify results;
1996	 */
1997	for (GLint i = 0; i < max_viewports; ++i)
1998	{
1999		scissor_box_data_a[i * m_n_elements + 0] = 8;
2000		scissor_box_data_a[i * m_n_elements + 1] = 8;
2001		scissor_box_data_a[i * m_n_elements + 2] = 12;
2002		scissor_box_data_a[i * m_n_elements + 3] = 12;
2003
2004		gl.scissorIndexedv(i, &scissor_box_data_a[i * m_n_elements]);
2005		GLU_EXPECT_NO_ERROR(gl.getError(), "scissorIndexedv");
2006
2007		getScissorBoxes(max_viewports, scissor_box_data_b);
2008		compareScissorBoxes(scissor_box_data_a, scissor_box_data_b, "scissorIndexedv", test_result);
2009	}
2010
2011	/*
2012	 *   - for each index:
2013	 *     * modify all indices before and after current one with ScissorArrayv,
2014	 *     * get SCISSOR_BOX for all MAX_VIEWPORTS indices and verify results;
2015	 */
2016	for (GLint i = 0; i < max_viewports; ++i)
2017	{
2018		const GLint value = (0 == i % 2) ? 1 : 4;
2019
2020		for (GLint j = 0; j < i; ++j)
2021		{
2022			scissor_box_data_b[j * m_n_elements + 0] = value;
2023			scissor_box_data_b[j * m_n_elements + 1] = value;
2024			scissor_box_data_b[j * m_n_elements + 2] = value;
2025			scissor_box_data_b[j * m_n_elements + 3] = value;
2026		}
2027
2028		for (GLint j = i + 1; j < max_viewports; ++j)
2029		{
2030			scissor_box_data_b[j * m_n_elements + 0] = value;
2031			scissor_box_data_b[j * m_n_elements + 1] = value;
2032			scissor_box_data_b[j * m_n_elements + 2] = value;
2033			scissor_box_data_b[j * m_n_elements + 3] = value;
2034		}
2035
2036		gl.scissorArrayv(0, max_viewports, &scissor_box_data_b[0]);
2037		GLU_EXPECT_NO_ERROR(gl.getError(), "scissorArrayv");
2038
2039		getScissorBoxes(max_viewports, scissor_box_data_a);
2040		compareScissorBoxes(scissor_box_data_a, scissor_box_data_b, "scissorArrayv", test_result);
2041	}
2042
2043	/*
2044	 *   - change location and dimensions of all indices at once with Scissor;
2045	 *   - get SCISSOR_BOX for all MAX_VIEWPORTS indices and verify results;
2046	 */
2047	for (GLint i = 0; i < max_viewports; ++i)
2048	{
2049		scissor_box_data_a[i * m_n_elements + 0] = 0;
2050		scissor_box_data_a[i * m_n_elements + 1] = 0;
2051		scissor_box_data_a[i * m_n_elements + 2] = 1;
2052		scissor_box_data_a[i * m_n_elements + 3] = 1;
2053	}
2054
2055	gl.scissor(0, 0, 1, 1);
2056	GLU_EXPECT_NO_ERROR(gl.getError(), "scissor");
2057
2058	getScissorBoxes(max_viewports, scissor_box_data_b);
2059	compareScissorBoxes(scissor_box_data_a, scissor_box_data_b, "scissor", test_result);
2060
2061	/* Set result */
2062	if (true == test_result)
2063	{
2064		m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
2065	}
2066	else
2067	{
2068		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2069	}
2070
2071	/* Done */
2072	return tcu::TestNode::STOP;
2073}
2074
2075/** Compare two sets of scissor box data (simple vector comparison)
2076 *
2077 * @param left        Left set
2078 * @param right       Right set
2079 * @param description Test case description
2080 * @param out_result  Set to false if sets are different, not modified otherwise
2081 **/
2082void ScissorAPI::compareScissorBoxes(std::vector<GLint>& left, std::vector<GLint>& right, const GLchar* description,
2083									 bool& out_result)
2084{
2085	for (size_t i = 0; i < left.size(); ++i)
2086	{
2087		if (left[i] != right[i])
2088		{
2089			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Test case: " << description
2090												<< " Invalid values [" << i << "] " << left[i] << " " << right[i]
2091												<< tcu::TestLog::EndMessage;
2092
2093			out_result = false;
2094		}
2095	}
2096}
2097
2098/** Get position of all scissor boxes
2099 *
2100 * @param max_viewports Number of scissor boxes to capture, MAX_VIEWPORTS
2101 * @param data          Memory buffer prepared for captured data
2102 **/
2103void ScissorAPI::getScissorBoxes(GLint max_viewports, std::vector<GLint>& out_data)
2104{
2105	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2106
2107	for (GLint i = 0; i < max_viewports; ++i)
2108	{
2109		gl.getIntegeri_v(GL_SCISSOR_BOX, i, &out_data[i * 4]);
2110		GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegeri_v");
2111	}
2112}
2113
2114/* Constants used by DepthRangeAPI */
2115const GLuint DepthRangeAPI::m_n_elements = 2 /* near + far */;
2116
2117/** Constructor
2118 *
2119 * @param context          Test context
2120 **/
2121DepthRangeAPI::DepthRangeAPI(deqp::Context& context, const glcts::ExtParameters& extParams)
2122	: TestCaseBase(context, extParams, "depth_range_api", "Test verifies that \"depth range api\" works as expected")
2123{
2124	/* Nothing to be done here */
2125}
2126
2127/** Execute test
2128 *
2129 * @return tcu::TestNode::CONTINUE after executing test case, tcu::TestNode::STOP otherwise
2130 **/
2131tcu::TestNode::IterateResult DepthRangeAPI::iterate()
2132{
2133	if (!m_is_viewport_array_supported)
2134	{
2135		throw tcu::NotSupportedError(VIEWPORT_ARRAY_NOT_SUPPORTED, "", __FILE__, __LINE__);
2136	}
2137
2138	bool					test_result;
2139	const glu::ContextType& context_type = m_context.getRenderContext().getType();
2140
2141	if (glu::isContextTypeGLCore(context_type))
2142	{
2143		test_result = iterateHelper<GLdouble>();
2144	}
2145	else
2146	{
2147		DE_ASSERT(glu::isContextTypeES(context_type));
2148		test_result = iterateHelper<GLfloat>();
2149	}
2150
2151	/* Set result */
2152	if (true == test_result)
2153	{
2154		m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
2155	}
2156	else
2157	{
2158		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2159	}
2160
2161	/* Done */
2162	return tcu::TestNode::STOP;
2163}
2164
2165template <typename T>
2166bool DepthRangeAPI::iterateHelper(T*)
2167{
2168	/* GL entry points */
2169	const glw::Functions&   gl = m_context.getRenderContext().getFunctions();
2170	Utils::DepthFuncWrapper depthFunc(m_context);
2171
2172	bool test_result = true;
2173
2174	GLint max_viewports = 0;
2175
2176	gl.getIntegerv(GL_MAX_VIEWPORTS, &max_viewports);
2177	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
2178
2179	std::vector<T> depth_range_data_a;
2180	std::vector<T> depth_range_data_b;
2181
2182	depth_range_data_a.resize(max_viewports * m_n_elements);
2183	depth_range_data_b.resize(max_viewports * m_n_elements);
2184
2185	/*
2186	 *   - get initial values of DEPTH_RANGE for all MAX_VIEWPORTS indices;
2187	 *   - change values of all indices at once with DepthRangeArrayv;
2188	 *   - get DEPTH_RANGE for all MAX_VIEWPORTS indices and verify results;
2189	 */
2190	getDepthRanges(depthFunc, max_viewports, depth_range_data_a);
2191
2192	for (GLint i = 0; i < max_viewports; ++i)
2193	{
2194		depth_range_data_a[i * m_n_elements + 0] += 0.125;
2195		depth_range_data_a[i * m_n_elements + 1] -= 0.125;
2196	}
2197
2198	depthFunc.depthRangeArray(0, max_viewports, &depth_range_data_a[0]);
2199	GLU_EXPECT_NO_ERROR(gl.getError(), "depthRangeArray");
2200
2201	getDepthRanges(depthFunc, max_viewports, depth_range_data_b);
2202	compareDepthRanges(depth_range_data_a, depth_range_data_b, "depthRangeArray", test_result);
2203
2204	/*
2205	 *   - for each index:
2206	 *     * modify with DepthRangeIndexed,
2207	 *     * get DEPTH_RANGE for all MAX_VIEWPORTS indices and verify results;
2208	 */
2209	for (GLint i = 0; i < max_viewports; ++i)
2210	{
2211		depth_range_data_b[i * m_n_elements + 0] = 0.25;
2212		depth_range_data_b[i * m_n_elements + 1] = 0.75;
2213
2214		depthFunc.depthRangeIndexed(i, (T)0.25, (T)0.75);
2215		GLU_EXPECT_NO_ERROR(gl.getError(), "depthRangeIndexed");
2216
2217		getDepthRanges(depthFunc, max_viewports, depth_range_data_a);
2218		compareDepthRanges(depth_range_data_a, depth_range_data_b, "depthRangeIndexed", test_result);
2219	}
2220
2221	/*
2222	 *   - for each index:
2223	 *     * modify all indices before and after current one with DepthRangeArrayv,
2224	 *     * get DEPTH_RANGE for all MAX_VIEWPORTS indices and verify results;
2225	 */
2226	for (GLint i = 0; i < max_viewports; ++i)
2227	{
2228		const T value = (0 == i % 2) ? T(1.0) : T(0.25);
2229
2230		for (GLint j = 0; j < i; ++j)
2231		{
2232			depth_range_data_b[j * m_n_elements + 0] = value;
2233			depth_range_data_b[j * m_n_elements + 1] = value;
2234		}
2235
2236		for (GLint j = i + 1; j < max_viewports; ++j)
2237		{
2238			depth_range_data_b[j * m_n_elements + 0] = value;
2239			depth_range_data_b[j * m_n_elements + 1] = value;
2240		}
2241
2242		depthFunc.depthRangeArray(0, max_viewports, &depth_range_data_b[0]);
2243		GLU_EXPECT_NO_ERROR(gl.getError(), "depthRangeArray");
2244
2245		getDepthRanges(depthFunc, max_viewports, depth_range_data_a);
2246		compareDepthRanges(depth_range_data_a, depth_range_data_b, "depthRangeArray", test_result);
2247	}
2248
2249	/*
2250	 *   - change values of all indices at once with DepthRange;
2251	 *   - get DEPTH_RANGE for all MAX_VIEWPORTS indices and verify results;
2252	 */
2253	for (GLint i = 0; i < max_viewports; ++i)
2254	{
2255		depth_range_data_a[i * m_n_elements + 0] = 0.0f;
2256		depth_range_data_a[i * m_n_elements + 1] = 1.0f;
2257	}
2258
2259	depthFunc.depthRange((T)0.0, (T)1.0);
2260	GLU_EXPECT_NO_ERROR(gl.getError(), "depthRange");
2261
2262	getDepthRanges(depthFunc, max_viewports, depth_range_data_b);
2263	compareDepthRanges(depth_range_data_a, depth_range_data_b, "depthRange", test_result);
2264
2265	return test_result;
2266}
2267
2268/** Compare two sets of depth range data (simple vector comparison)
2269 *
2270 * @param left        Left set
2271 * @param right       Right set
2272 * @param description Test case description
2273 * @param out_result  Set to false if sets are different, not modified otherwise
2274 **/
2275template <typename T>
2276void DepthRangeAPI::compareDepthRanges(std::vector<T>& left, std::vector<T>& right, const GLchar* description,
2277									   bool& out_result)
2278{
2279	for (size_t i = 0; i < left.size(); ++i)
2280	{
2281		if (left[i] != right[i])
2282		{
2283			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Test case: " << description
2284												<< " Invalid values [" << i << "] " << left[i] << " " << right[i]
2285												<< tcu::TestLog::EndMessage;
2286			out_result = false;
2287		}
2288	}
2289}
2290
2291/** Get all depth ranges
2292 *
2293 * @param max_viewports Number of viewports to capture, MAX_VIEWPORTS
2294 * @param data          Memory buffer prepared for captured data
2295 **/
2296template <typename T>
2297void DepthRangeAPI::getDepthRanges(Utils::DepthFuncWrapper& depthFunc, GLint max_viewports, std::vector<T>& out_data)
2298{
2299	for (GLint i = 0; i < max_viewports; ++i)
2300	{
2301		depthFunc.getDepthi_v(GL_DEPTH_RANGE, i, &out_data[i * m_n_elements]);
2302		GLU_EXPECT_NO_ERROR(depthFunc.getFunctions().getError(), "getDouble/Floati_v");
2303	}
2304}
2305
2306/** Constructor
2307 *
2308 * @param context          Test context
2309 **/
2310ScissorTestStateAPI::ScissorTestStateAPI(deqp::Context& context, const glcts::ExtParameters& extParams)
2311	: TestCaseBase(context, extParams, "scissor_test_state_api",
2312				   "Test verifies that \"enable/disable api\" works as expected for scissor test")
2313{
2314	/* Nothing to be done here */
2315}
2316
2317/** Execute test
2318 *
2319 * @return tcu::TestNode::CONTINUE after executing test case, tcu::TestNode::STOP otherwise
2320 **/
2321tcu::TestNode::IterateResult ScissorTestStateAPI::iterate()
2322{
2323	if (!m_is_viewport_array_supported)
2324	{
2325		throw tcu::NotSupportedError(VIEWPORT_ARRAY_NOT_SUPPORTED, "", __FILE__, __LINE__);
2326	}
2327
2328	/* GL entry points */
2329	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2330
2331	/* Test result */
2332	bool test_result = true;
2333
2334	GLint max_viewports = 0;
2335
2336	gl.getIntegerv(GL_MAX_VIEWPORTS, &max_viewports);
2337	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
2338
2339	std::vector<GLboolean> scissor_test_states_a;
2340	std::vector<GLboolean> scissor_test_states_b;
2341
2342	scissor_test_states_a.resize(max_viewports);
2343	scissor_test_states_b.resize(max_viewports);
2344
2345	/*
2346	 *   - get initial state of SCISSOR_TEST for all MAX_VIEWPORTS indices;
2347	 *   - for each index:
2348	 *     * toggle SCISSOR_TEST,
2349	 *     * get state of SCISSOR_TEST for all MAX_VIEWPORTS indices and verify;
2350	 *   - for each index:
2351	 *     * toggle SCISSOR_TEST,
2352	 *     * get state of SCISSOR_TEST for all MAX_VIEWPORTS indices and verify;
2353	 */
2354	getScissorTestStates(max_viewports, scissor_test_states_a);
2355
2356	for (GLint i = 0; i < max_viewports; ++i)
2357	{
2358		if (GL_FALSE == scissor_test_states_a[i])
2359		{
2360			gl.enablei(GL_SCISSOR_TEST, i);
2361			GLU_EXPECT_NO_ERROR(gl.getError(), "Enablei");
2362
2363			scissor_test_states_a[i] = GL_TRUE;
2364		}
2365		else
2366		{
2367			gl.disablei(GL_SCISSOR_TEST, i);
2368			GLU_EXPECT_NO_ERROR(gl.getError(), "Disablei");
2369
2370			scissor_test_states_a[i] = GL_FALSE;
2371		}
2372
2373		getScissorTestStates(max_viewports, scissor_test_states_b);
2374		compareScissorTestStates(scissor_test_states_a, scissor_test_states_b, "1st toggle", test_result);
2375	}
2376
2377	for (GLint i = 0; i < max_viewports; ++i)
2378	{
2379		if (GL_FALSE == scissor_test_states_a[i])
2380		{
2381			gl.enablei(GL_SCISSOR_TEST, i);
2382			GLU_EXPECT_NO_ERROR(gl.getError(), "Enablei");
2383
2384			scissor_test_states_a[i] = GL_TRUE;
2385		}
2386		else
2387		{
2388			gl.disablei(GL_SCISSOR_TEST, i);
2389			GLU_EXPECT_NO_ERROR(gl.getError(), "Disablei");
2390
2391			scissor_test_states_a[i] = GL_FALSE;
2392		}
2393
2394		getScissorTestStates(max_viewports, scissor_test_states_b);
2395		compareScissorTestStates(scissor_test_states_a, scissor_test_states_b, "2nd toggle", test_result);
2396	}
2397
2398	/*
2399	 *   - enable SCISSOR_TEST for all indices at once with Enable;
2400	 *   - get state of SCISSOR_TEST for all MAX_VIEWPORTS indices and verify;
2401	 */
2402	for (GLint i = 0; i < max_viewports; ++i)
2403	{
2404		scissor_test_states_a[i] = GL_TRUE;
2405	}
2406
2407	gl.enable(GL_SCISSOR_TEST);
2408	GLU_EXPECT_NO_ERROR(gl.getError(), "Enable");
2409
2410	getScissorTestStates(max_viewports, scissor_test_states_b);
2411	compareScissorTestStates(scissor_test_states_a, scissor_test_states_b, "1st enable all", test_result);
2412
2413	/*
2414	 *   - disable SCISSOR_TEST for all indices at once with Disable;
2415	 *   - get state of SCISSOR_TEST for all MAX_VIEWPORTS indices and verify;
2416	 */
2417	for (GLint i = 0; i < max_viewports; ++i)
2418	{
2419		scissor_test_states_a[i] = GL_FALSE;
2420	}
2421
2422	gl.disable(GL_SCISSOR_TEST);
2423	GLU_EXPECT_NO_ERROR(gl.getError(), "Disable");
2424
2425	getScissorTestStates(max_viewports, scissor_test_states_b);
2426	compareScissorTestStates(scissor_test_states_a, scissor_test_states_b, "Disable all", test_result);
2427
2428	/*
2429	 *   - enable SCISSOR_TEST for all indices at once with Enable;
2430	 *   - get state of SCISSOR_TEST for all MAX_VIEWPORTS indices and verify;
2431	 */
2432	for (GLint i = 0; i < max_viewports; ++i)
2433	{
2434		scissor_test_states_a[i] = GL_TRUE;
2435	}
2436
2437	gl.enable(GL_SCISSOR_TEST);
2438	GLU_EXPECT_NO_ERROR(gl.getError(), "Enable");
2439
2440	getScissorTestStates(max_viewports, scissor_test_states_b);
2441	compareScissorTestStates(scissor_test_states_a, scissor_test_states_b, "2nd enable all", test_result);
2442
2443	/* Set result */
2444	if (true == test_result)
2445	{
2446		m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
2447	}
2448	else
2449	{
2450		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2451	}
2452
2453	/* Done */
2454	return tcu::TestNode::STOP;
2455}
2456
2457/** Compare two sets of depth range data (simple vector comparison)
2458 *
2459 * @param left        Left set
2460 * @param right       Right set
2461 * @param description Test case description
2462 * @param out_result  Set to false if sets are different, not modified otherwise
2463 **/
2464void ScissorTestStateAPI::compareScissorTestStates(std::vector<GLboolean>& left, std::vector<GLboolean>& right,
2465												   const GLchar* description, bool& out_result)
2466{
2467	for (size_t i = 0; i < left.size(); ++i)
2468	{
2469		if (left[i] != right[i])
2470		{
2471			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Test case: " << description
2472												<< " Invalid values [" << i << "] " << left[i] << " " << right[i]
2473												<< tcu::TestLog::EndMessage;
2474
2475			out_result = false;
2476		}
2477	}
2478}
2479
2480/** Get all depth ranges
2481 *
2482 * @param max_viewports Number of viewports to capture, MAX_VIEWPORTS
2483 * @param data          Memory buffer prepared for captured data
2484 **/
2485void ScissorTestStateAPI::getScissorTestStates(GLint max_viewports, std::vector<GLboolean>& out_data)
2486{
2487	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2488
2489	for (GLint i = 0; i < max_viewports; ++i)
2490	{
2491		out_data[i] = gl.isEnabledi(GL_SCISSOR_TEST, i);
2492		GLU_EXPECT_NO_ERROR(gl.getError(), "isEnabledi");
2493	}
2494}
2495
2496/* Constants used by DrawTestBase */
2497const GLuint DrawTestBase::m_depth		  = 16;
2498const GLuint DrawTestBase::m_height		  = 128;
2499const GLuint DrawTestBase::m_width		  = 128;
2500const GLuint DrawTestBase::m_r32f_height  = 2;
2501const GLuint DrawTestBase::m_r32f_width   = 16;
2502const GLuint DrawTestBase::m_r32ix4_depth = 4;
2503
2504/** Constructor
2505 *
2506 * @param context          Test context
2507 * @param test_name        Test name
2508 * @param test_description Test description
2509 **/
2510DrawTestBase::DrawTestBase(deqp::Context& context, const glcts::ExtParameters& extParams, const GLchar* test_name,
2511						   const GLchar* test_description)
2512	: TestCaseBase(context, extParams, test_name, test_description)
2513{
2514	/* Nothing to be done here */
2515}
2516
2517/** Execute test
2518 *
2519 * @return tcu::TestNode::CONTINUE after executing test case, tcu::TestNode::STOP otherwise
2520 **/
2521tcu::TestNode::IterateResult DrawTestBase::iterate()
2522{
2523	if (!m_is_viewport_array_supported)
2524	{
2525		throw tcu::NotSupportedError(VIEWPORT_ARRAY_NOT_SUPPORTED, "", __FILE__, __LINE__);
2526	}
2527
2528	const glw::Functions&   gl			 = m_context.getRenderContext().getFunctions();
2529	const glu::ContextType& context_type = m_context.getRenderContext().getType();
2530
2531	/* Test result */
2532	bool test_result = true;
2533
2534	/* Get type of test */
2535	const TEST_TYPE test_type = getTestType();
2536
2537	GLuint n_draw_calls = getDrawCallsNumber();
2538	GLuint n_iterations = 0;
2539	switch (test_type)
2540	{
2541	case VIEWPORT:
2542	case SCISSOR:
2543		n_iterations = 3;
2544		break;
2545	case DEPTHRANGE:
2546	case PROVOKING:
2547		n_iterations = 2;
2548		break;
2549	default:
2550		TCU_FAIL("Invalid enum");
2551	}
2552
2553	/* Get shader sources and specialize them */
2554	const std::string& frag = getFragmentShader();
2555	const std::string& geom = getGeometryShader();
2556	const std::string& vert = getVertexShader();
2557
2558	const GLchar* frag_template = frag.c_str();
2559	const GLchar* geom_template = geom.c_str();
2560	const GLchar* vert_template = vert.c_str();
2561
2562	std::string fragment = specializeShader(1, &frag_template);
2563	std::string geometry = specializeShader(1, &geom_template);
2564	std::string vertex   = specializeShader(1, &vert_template);
2565
2566	/* Prepare program */
2567	Utils::program program(m_context);
2568
2569	try
2570	{
2571		program.build(0 /* compute */, fragment.c_str(), geometry.c_str(), 0 /* tess ctrl */, 0 /* tess eval */,
2572					  vertex.c_str(), 0 /* varying names */, 0 /* n_varyings */);
2573	}
2574	catch (Utils::shaderCompilationException& exc)
2575	{
2576		/* Something wrong with compilation, test case failed */
2577		tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
2578
2579		message << "Shader compilation failed. Error message: " << exc.m_error_message;
2580
2581		Utils::program::printShaderSource(exc.m_shader_source.c_str(), message);
2582
2583		message << tcu::TestLog::EndMessage;
2584
2585		TCU_FAIL("Shader compilation failed");
2586	}
2587	catch (Utils::programLinkageException& exc)
2588	{
2589		/* Something wrong with linking, test case failed */
2590		m_context.getTestContext().getLog() << tcu::TestLog::Message
2591											<< "Program linking failed. Error message: " << exc.m_error_message
2592											<< tcu::TestLog::EndMessage;
2593		TCU_FAIL("Program linking failed");
2594	}
2595
2596	program.use();
2597
2598	/* Prepare VAO */
2599	Utils::vertexArray vao(m_context);
2600	vao.generate();
2601	vao.bind();
2602
2603	/* For each iteration from test type */
2604	for (GLuint i = 0; i < n_iterations; ++i)
2605	{
2606		/* Prepare textures */
2607		Utils::texture texture_0(m_context);
2608		Utils::texture texture_1(m_context);
2609
2610		prepareTextures(texture_0, texture_1);
2611
2612		/* Prepare framebuffer */
2613		Utils::framebuffer framebuffer(m_context);
2614		framebuffer.generate();
2615		setupFramebuffer(framebuffer, texture_0, texture_1);
2616		framebuffer.bind();
2617
2618		/* Set up viewports */
2619		setupViewports(test_type, i);
2620
2621		if (false == isClearTest())
2622		{
2623			/* For each draw call */
2624			for (GLuint draw_call = 0; draw_call < n_draw_calls; ++draw_call)
2625			{
2626				prepareUniforms(program, draw_call);
2627
2628				bool	is_clear;
2629				GLfloat depth_value;
2630
2631				getClearSettings(is_clear, draw_call, depth_value);
2632
2633				if (true == is_clear)
2634				{
2635					if (glu::isContextTypeGLCore(context_type))
2636					{
2637						gl.clearDepth((GLdouble)depth_value);
2638					}
2639					else
2640					{
2641						gl.clearDepthf(depth_value);
2642					}
2643					GLU_EXPECT_NO_ERROR(gl.getError(), "ClearDepth");
2644
2645					gl.clear(GL_DEPTH_BUFFER_BIT);
2646					GLU_EXPECT_NO_ERROR(gl.getError(), "Clear");
2647				}
2648
2649				gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
2650				GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
2651
2652				bool result = checkResults(texture_0, texture_1, draw_call);
2653
2654				if (false == result)
2655				{
2656					test_result = false;
2657					goto end;
2658				}
2659			}
2660		}
2661		else
2662		{
2663			gl.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
2664			GLU_EXPECT_NO_ERROR(gl.getError(), "ClearColor");
2665
2666			gl.clear(GL_COLOR_BUFFER_BIT);
2667			GLU_EXPECT_NO_ERROR(gl.getError(), "Clear");
2668
2669			bool result = checkResults(texture_0, texture_1, 0);
2670
2671			if (false == result)
2672			{
2673				test_result = false;
2674				goto end;
2675			}
2676		}
2677	}
2678
2679end:
2680	/* Set result */
2681	if (true == test_result)
2682	{
2683		m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
2684	}
2685	else
2686	{
2687		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2688	}
2689
2690	/* Done */
2691	return tcu::TestNode::STOP;
2692}
2693
2694/** Check if R32I texture is filled with 4x4 regions of increasing values <0:15>
2695 *
2696 * @param texture_0 Verified texture
2697 * @param ignored
2698 * @param ignored
2699 *
2700 * @return True if texture_0 is filled with expected pattern
2701 **/
2702bool DrawTestBase::checkResults(Utils::texture& texture_0, Utils::texture& /* texture_1 */, GLuint /*draw_call_index */)
2703{
2704	bool  check_result = true;
2705	GLint index		   = 0;
2706
2707	std::vector<GLint> texture_data;
2708	texture_data.resize(m_width * m_height);
2709	texture_0.get(GL_RED_INTEGER, GL_INT, &texture_data[0]);
2710
2711	for (GLuint y = 0; y < 4; ++y)
2712	{
2713		for (GLuint x = 0; x < 4; ++x)
2714		{
2715			bool result = checkRegionR32I(x, y, index, &texture_data[0]);
2716
2717			if (false == result)
2718			{
2719				check_result = false;
2720				goto end;
2721			}
2722
2723			index += 1;
2724		}
2725	}
2726
2727end:
2728	return check_result;
2729}
2730
2731/** Get settings of clear operation
2732 *
2733 * @param clear_depth_before_draw Selects if clear depth should be executed before draw.
2734 * @param ignored
2735 * @param ignored
2736 **/
2737void DrawTestBase::getClearSettings(bool& clear_depth_before_draw, GLuint /* iteration_index */,
2738									GLfloat& /* depth_value */)
2739{
2740	clear_depth_before_draw = false;
2741}
2742
2743/** Get number of draw call to be executed during test
2744 *
2745 * @return 1
2746 **/
2747GLuint DrawTestBase::getDrawCallsNumber()
2748{
2749	return 1;
2750}
2751
2752/** Get test type
2753 *
2754 * @return VIEWPORT
2755 **/
2756DrawTestBase::TEST_TYPE DrawTestBase::getTestType()
2757{
2758	return VIEWPORT;
2759}
2760
2761/** Selects if test should do draw or clear operation
2762 *
2763 * @return false - draw operation
2764 **/
2765bool DrawTestBase::isClearTest()
2766{
2767	return false;
2768}
2769
2770/** Prepare textures used as framebuffer's attachments for current draw call
2771 *
2772 * @param texture_0 R32I texture
2773 * @param ignored
2774 **/
2775void DrawTestBase::prepareTextures(Utils::texture& texture_0, Utils::texture& /* texture_1 */)
2776{
2777	prepareTextureR32I(texture_0);
2778}
2779
2780/** Prepare uniforms for given draw call
2781 *
2782 * @param ignored
2783 * @param ignored
2784 **/
2785void DrawTestBase::prepareUniforms(Utils::program& /* program */, GLuint /* draw_call_index */)
2786{
2787	/* empty */
2788}
2789
2790/** Attach textures to framebuffer
2791 *
2792 * @param framebuffer Framebuffer instance
2793 * @param texture_0   Texture attached as color 0
2794 * @param ignored
2795 **/
2796void DrawTestBase::setupFramebuffer(Utils::framebuffer& framebuffer, Utils::texture& texture_0,
2797									Utils::texture& /* texture_1 */)
2798{
2799	framebuffer.attachTexture(GL_COLOR_ATTACHMENT0, texture_0.m_id, m_width, m_height);
2800}
2801
2802/** Check if region specified with <x and <y> is filled with expected value.
2803 * Note: there is assumption that there are 4x4 regions
2804 *
2805 * @param x              X coordinate of region
2806 * @param y              Y coordinate of region
2807 * @param expected_value Expected value
2808 * @param data           Texture data (not region, but whole texture)
2809 *
2810 * @return True if region is filled with <expected_value>, false otherwise
2811 **/
2812bool DrawTestBase::checkRegionR32I(GLuint x, GLuint y, GLint expected_value, GLint* data)
2813{
2814	static GLuint width  = m_width / 4;
2815	static GLuint height = m_height / 4;
2816
2817	return checkRegionR32I(x, y, width, height, expected_value, data);
2818}
2819
2820/** Check if region specified with <x and <y> is filled with expected value.
2821 * Note: there is assumption that there are 4x4 regions
2822 *
2823 * @param x              X coordinate of region
2824 * @param y              Y coordinate of region
2825 * @param width          Width of region
2826 * @param height         Height of region
2827 * @param expected_value Expected value
2828 * @param data           Texture data (not region, but whole texture)
2829 *
2830 * @return True if region is filled with <expected_value>, false otherwise
2831 **/
2832bool DrawTestBase::checkRegionR32I(GLuint x, GLuint y, GLuint width, GLuint height, GLint expected_value, GLint* data)
2833{
2834	bool result = true;
2835
2836	const GLuint offset = (y * height * m_width) + (x * width);
2837
2838	for (GLuint line = 0; line < height; ++line)
2839	{
2840		const GLuint line_offset = offset + line * m_width;
2841
2842		for (GLuint texel = 0; texel < width; ++texel)
2843		{
2844			const GLuint texel_offset = line_offset + texel;
2845
2846			const GLint value = data[texel_offset];
2847
2848			if (expected_value != value)
2849			{
2850				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid result. Region (" << x << "x"
2851													<< y << "). Expected: " << expected_value << " got " << value
2852													<< tcu::TestLog::EndMessage;
2853
2854				result = false;
2855				goto end;
2856			}
2857		}
2858	}
2859
2860end:
2861	return result;
2862}
2863
2864/** Return boiler-plate vertex shader
2865 *
2866 * @return Source code of vertex shader
2867 **/
2868std::string DrawTestBase::getVertexShader()
2869{
2870	static const GLchar* source = "${VERSION}\n"
2871								  "\n"
2872								  "void main()\n"
2873								  "{\n"
2874								  "    /* empty */;\n"
2875								  "}\n"
2876								  "\n";
2877
2878	std::string result = source;
2879
2880	return result;
2881}
2882
2883/** Set up viewports
2884 *
2885 * @param type            Type of test
2886 * @param iteration_index Index of iteration for given test type
2887 **/
2888void DrawTestBase::setupViewports(TEST_TYPE type, GLuint iteration_index)
2889{
2890	switch (type)
2891	{
2892	case VIEWPORT:
2893	{
2894		VIEWPORT_METHOD method;
2895		switch (iteration_index)
2896		{
2897		case 0:
2898		case 1:
2899		case 2:
2900			method = (VIEWPORT_METHOD)iteration_index;
2901			break;
2902		default:
2903			TCU_FAIL("Invalid value");
2904		}
2905		setup4x4Viewport(method);
2906	}
2907	break;
2908	case SCISSOR:
2909	{
2910		SCISSOR_METHOD method;
2911		switch (iteration_index)
2912		{
2913		case 0:
2914		case 1:
2915		case 2:
2916			method = (SCISSOR_METHOD)iteration_index;
2917			break;
2918		default:
2919			TCU_FAIL("Invalid value");
2920		}
2921		setup4x4Scissor(method, false /* set_zeros */);
2922	}
2923	break;
2924	case DEPTHRANGE:
2925	{
2926		DEPTH_RANGE_METHOD method;
2927		switch (iteration_index)
2928		{
2929		case 0:
2930		case 1:
2931			method = (DEPTH_RANGE_METHOD)iteration_index;
2932			break;
2933		default:
2934			TCU_FAIL("Invalid value");
2935		}
2936		setup16x2Depths(method);
2937	}
2938	break;
2939	case PROVOKING:
2940	{
2941		PROVOKING_VERTEX provoking;
2942		switch (iteration_index)
2943		{
2944		case 0:
2945		case 1:
2946			provoking = (PROVOKING_VERTEX)iteration_index;
2947			break;
2948		default:
2949			TCU_FAIL("Invalid value");
2950		}
2951		setup2x2Viewport(provoking);
2952	}
2953	break;
2954	default:
2955		TCU_FAIL("Invalid enum");
2956	}
2957}
2958
2959/** Prepare R32I texture filled with value -1
2960 *
2961 * @param texture Texture instance
2962 **/
2963void DrawTestBase::prepareTextureR32I(Utils::texture& texture)
2964{
2965	static const GLuint size = m_width * m_height;
2966	GLint				data[size];
2967
2968	for (GLuint i = 0; i < size; ++i)
2969	{
2970		data[i] = -1;
2971	}
2972
2973	texture.create(m_width, m_height, GL_R32I);
2974	texture.update(m_width, m_height, 0 /* depth */, GL_RED_INTEGER, GL_INT, data);
2975}
2976
2977/** Prepare R32I array texture filled with value -1, 4 layers
2978 *
2979 * @param texture Texture instance
2980 **/
2981void DrawTestBase::prepareTextureR32Ix4(Utils::texture& texture)
2982{
2983	static const GLuint size = m_width * m_height * m_r32ix4_depth;
2984
2985	std::vector<GLint> data;
2986	data.resize(size);
2987
2988	for (GLuint i = 0; i < size; ++i)
2989	{
2990		data[i] = -1;
2991	}
2992
2993	texture.create(m_width, m_height, m_r32ix4_depth, GL_R32I);
2994	texture.update(m_width, m_height, m_r32ix4_depth, GL_RED_INTEGER, GL_INT, &data[0]);
2995}
2996
2997/** Prepare R32I array texture filled with value -1
2998 *
2999 * @param texture Texture instance
3000 **/
3001void DrawTestBase::prepareTextureArrayR32I(Utils::texture& texture)
3002{
3003	static const GLuint size = m_width * m_height * m_depth;
3004
3005	std::vector<GLint> data;
3006	data.resize(size);
3007
3008	for (GLuint i = 0; i < size; ++i)
3009	{
3010		data[i] = -1;
3011	}
3012
3013	texture.create(m_width, m_height, m_depth, GL_R32I);
3014	texture.update(m_width, m_height, m_depth, GL_RED_INTEGER, GL_INT, &data[0]);
3015}
3016
3017/** Prepare R32F texture filled with value -1
3018 *
3019 * @param texture Texture instance
3020 **/
3021void DrawTestBase::prepareTextureR32F(Utils::texture& texture)
3022{
3023	static const GLuint size = m_r32f_width * m_r32f_height;
3024	GLfloat				data[size];
3025
3026	for (GLuint i = 0; i < size; ++i)
3027	{
3028		data[i] = -1.0f;
3029	}
3030
3031	texture.create(m_r32f_width, m_r32f_height, GL_R32F);
3032	texture.update(m_r32f_width, m_r32f_height, 0 /* depth */, GL_RED, GL_FLOAT, data);
3033}
3034
3035/** Prepare D32F texture filled with value -1
3036 *
3037 * @param texture Texture instance
3038 **/
3039void DrawTestBase::prepareTextureD32F(Utils::texture& texture)
3040{
3041	static const GLuint size = m_width * m_height;
3042	GLfloat				data[size];
3043
3044	for (GLuint i = 0; i < size; ++i)
3045	{
3046		data[i] = -1.0f;
3047	}
3048
3049	texture.create(m_width, m_height, GL_DEPTH_COMPONENT32F);
3050	texture.update(m_width, m_height, 0 /* depth */, GL_DEPTH_COMPONENT, GL_FLOAT, data);
3051}
3052
3053/** Set up 16 viewports and depth ranges horizontally
3054 *
3055 * @param method Method used to set depth ranges
3056 **/
3057void DrawTestBase::setup16x2Depths(DEPTH_RANGE_METHOD method)
3058{
3059	const glu::ContextType& context_type = m_context.getRenderContext().getType();
3060
3061	if (glu::isContextTypeGLCore(context_type))
3062	{
3063		setup16x2DepthsHelper<GLdouble>(method);
3064	}
3065	else
3066	{
3067		DE_ASSERT(glu::isContextTypeES(context_type));
3068		setup16x2DepthsHelper<GLfloat>(method);
3069	}
3070}
3071
3072template <typename T>
3073void DrawTestBase::setup16x2DepthsHelper(DEPTH_RANGE_METHOD method, T*)
3074{
3075	static const T step = 1.0 / 16.0;
3076
3077	const glw::Functions&   gl = m_context.getRenderContext().getFunctions();
3078	Utils::DepthFuncWrapper depthFunc(m_context);
3079
3080	T		depth_data[16 * 2];
3081	GLfloat viewport_data[16 * 4];
3082
3083	for (GLuint i = 0; i < 16; ++i)
3084	{
3085		const T near = step * (T)i;
3086
3087		depth_data[i * 2 + 0] = near;
3088		depth_data[i * 2 + 1] = T(1.0) - near;
3089
3090		viewport_data[i * 4 + 0] = (GLfloat)i;
3091		viewport_data[i * 4 + 1] = 0.0f;
3092		viewport_data[i * 4 + 2] = 1.0f;
3093		viewport_data[i * 4 + 3] = 2.0f;
3094	}
3095
3096	gl.viewportArrayv(0 /* first */, 16 /* count */, viewport_data);
3097	GLU_EXPECT_NO_ERROR(gl.getError(), "ViewportArrayv");
3098
3099	switch (method)
3100	{
3101	case DEPTHRANGEINDEXED:
3102		for (GLuint i = 0; i < 16; ++i)
3103		{
3104			depthFunc.depthRangeIndexed(i, depth_data[i * 2 + 0], depth_data[i * 2 + 1]);
3105			GLU_EXPECT_NO_ERROR(gl.getError(), "DepthRangeIndexed");
3106		}
3107		break;
3108
3109	case DEPTHRANGEARRAYV:
3110		depthFunc.depthRangeArray(0 /* first */, 16 /* count */, depth_data);
3111		GLU_EXPECT_NO_ERROR(gl.getError(), "DepthRangeArray");
3112		break;
3113
3114	default:
3115		TCU_FAIL("Invalid enum");
3116	}
3117}
3118
3119/** Set up 4x4 scissor boxes with enabled test
3120 *
3121 * @param method    Method used to set scissor boxes
3122 * @param set_zeros Select if width and height should be 0 or image_dim / 4
3123 **/
3124void DrawTestBase::setup4x4Scissor(SCISSOR_METHOD method, bool set_zeros)
3125{
3126	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3127
3128	for (GLuint i = 0; i < 16; ++i)
3129	{
3130		gl.enablei(GL_SCISSOR_TEST, i);
3131		GLU_EXPECT_NO_ERROR(gl.getError(), "Enablei");
3132	}
3133
3134	GLint index = 0;
3135	GLint data[16 * 4 /* 4x4 * (x + y + w + h) */];
3136
3137	GLint width  = m_width / 4;
3138	GLint height = m_height / 4;
3139
3140	for (GLuint y = 0; y < 4; ++y)
3141	{
3142		for (GLuint x = 0; x < 4; ++x)
3143		{
3144			data[index * 4 + 0] = x * width;
3145			data[index * 4 + 1] = y * height;
3146			if (false == set_zeros)
3147			{
3148				data[index * 4 + 2] = width;
3149				data[index * 4 + 3] = height;
3150			}
3151			else
3152			{
3153				data[index * 4 + 2] = 0;
3154				data[index * 4 + 3] = 0;
3155			}
3156
3157			index += 1;
3158		}
3159	}
3160
3161	switch (method)
3162	{
3163	case SCISSORARRAYV:
3164		gl.scissorArrayv(0 /* first */, 16 /*count */, data);
3165		GLU_EXPECT_NO_ERROR(gl.getError(), "ScissorArrayv");
3166		break;
3167	case SCISSORINDEXEDF:
3168		for (GLuint i = 0; i < 16; ++i)
3169		{
3170			const GLint x = data[i * 4 + 0];
3171			const GLint y = data[i * 4 + 1];
3172			const GLint w = data[i * 4 + 2];
3173			const GLint h = data[i * 4 + 3];
3174
3175			gl.scissorIndexed(i, x, y, w, h);
3176			GLU_EXPECT_NO_ERROR(gl.getError(), "ScissorIndexed");
3177		}
3178		break;
3179	case SCISSORINDEXEDF_V:
3180		for (GLuint i = 0; i < 16; ++i)
3181		{
3182			gl.scissorIndexedv(i, &data[i * 4]);
3183			GLU_EXPECT_NO_ERROR(gl.getError(), "ScissorIndexedv");
3184		}
3185		break;
3186	default:
3187		TCU_FAIL("Invalid enum");
3188	}
3189}
3190
3191/** Set up 4x4 viewports
3192 *
3193 * @param method Method used to set viewports
3194 **/
3195void DrawTestBase::setup4x4Viewport(VIEWPORT_METHOD method)
3196{
3197	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3198
3199	GLint   index = 0;
3200	GLfloat data[16 * 4 /* 4x4 * (x + y + w + h) */];
3201
3202	GLfloat width  = (GLfloat)(m_width / 4);
3203	GLfloat height = (GLfloat)(m_height / 4);
3204
3205	for (GLuint y = 0; y < 4; ++y)
3206	{
3207		for (GLuint x = 0; x < 4; ++x)
3208		{
3209			data[index * 4 + 0] = (GLfloat)((GLfloat)x * width);
3210			data[index * 4 + 1] = (GLfloat)((GLfloat)y * height);
3211			data[index * 4 + 2] = width;
3212			data[index * 4 + 3] = height;
3213
3214			index += 1;
3215		}
3216	}
3217
3218	switch (method)
3219	{
3220	case VIEWPORTARRAYV:
3221		gl.viewportArrayv(0 /* first */, 16 /*count */, data);
3222		GLU_EXPECT_NO_ERROR(gl.getError(), "ViewportArrayv");
3223		break;
3224	case VIEWPORTINDEXEDF:
3225		for (GLuint i = 0; i < 16; ++i)
3226		{
3227			const GLfloat x = data[i * 4 + 0];
3228			const GLfloat y = data[i * 4 + 1];
3229			const GLfloat w = data[i * 4 + 2];
3230			const GLfloat h = data[i * 4 + 3];
3231
3232			gl.viewportIndexedf(i, x, y, w, h);
3233			GLU_EXPECT_NO_ERROR(gl.getError(), "ViewportIndexedf");
3234		}
3235		break;
3236	case VIEWPORTINDEXEDF_V:
3237		for (GLuint i = 0; i < 16; ++i)
3238		{
3239			gl.viewportIndexedfv(i, &data[i * 4]);
3240			GLU_EXPECT_NO_ERROR(gl.getError(), "ViewportIndexedfv");
3241		}
3242		break;
3243	default:
3244		TCU_FAIL("Invalid enum");
3245	}
3246}
3247
3248/** Set up 4x4 viewports
3249 *
3250 * @param method Method used to set viewports
3251 **/
3252void DrawTestBase::setup2x2Viewport(PROVOKING_VERTEX provoking)
3253{
3254	const glw::Functions&   gl			 = m_context.getRenderContext().getFunctions();
3255	const glu::ContextType& context_type = m_context.getRenderContext().getType();
3256
3257	GLint   index = 0;
3258	GLfloat data[4 * 4 /* 4x4 * (x + y + w + h) */];
3259
3260	GLfloat width  = (GLfloat)(m_width / 2);
3261	GLfloat height = (GLfloat)(m_height / 2);
3262
3263	for (GLuint y = 0; y < 2; ++y)
3264	{
3265		for (GLuint x = 0; x < 2; ++x)
3266		{
3267			data[index * 4 + 0] = (GLfloat)((GLfloat)x * width);
3268			data[index * 4 + 1] = (GLfloat)((GLfloat)y * height);
3269			data[index * 4 + 2] = width;
3270			data[index * 4 + 3] = height;
3271
3272			index += 1;
3273		}
3274	}
3275
3276	gl.viewportArrayv(0 /* first */, 4 /*count */, data);
3277	GLU_EXPECT_NO_ERROR(gl.getError(), "ViewportArrayv");
3278
3279	if (glu::isContextTypeGLCore(context_type))
3280	{
3281		GLenum mode = 0;
3282		switch (provoking)
3283		{
3284		case FIRST:
3285			mode = GL_FIRST_VERTEX_CONVENTION;
3286			break;
3287		case LAST:
3288			mode = GL_LAST_VERTEX_CONVENTION;
3289			break;
3290		default:
3291			TCU_FAIL("Invalid enum");
3292		}
3293
3294		gl.provokingVertex(mode);
3295		GLU_EXPECT_NO_ERROR(gl.getError(), "ProvokingVertex");
3296	}
3297	else
3298	{
3299		/* can't control the provoking vertex in ES yet - it stays as LAST */
3300		DE_ASSERT(glu::isContextTypeES(context_type));
3301		DE_UNREF(provoking);
3302	}
3303}
3304
3305/** Constructor
3306 *
3307 * @param context          Test context
3308 **/
3309DrawToSingleLayerWithMultipleViewports::DrawToSingleLayerWithMultipleViewports(deqp::Context&			   context,
3310																			   const glcts::ExtParameters& extParams)
3311	: DrawTestBase(context, extParams, "draw_to_single_layer_with_multiple_viewports",
3312				   "Test verifies that multiple viewports can be used to draw to single layer")
3313{
3314	/* Nothing to be done here */
3315}
3316
3317/** Get string with fragment shader source code
3318 *
3319 * @return Fragment shader source
3320 **/
3321std::string DrawToSingleLayerWithMultipleViewports::getFragmentShader()
3322{
3323	static const GLchar* source = "${VERSION}\n"
3324								  "\n"
3325								  "flat in  int gs_fs_color;\n"
3326								  "     out int fs_out_color;\n"
3327								  "\n"
3328								  "void main()\n"
3329								  "{\n"
3330								  "    fs_out_color = gs_fs_color;\n"
3331								  "}\n"
3332								  "\n";
3333
3334	std::string result = source;
3335
3336	return result;
3337}
3338
3339/** Get string with geometry shader source code
3340 *
3341 * @return Geometry shader source
3342 **/
3343std::string DrawToSingleLayerWithMultipleViewports::getGeometryShader()
3344{
3345	static const GLchar* source = "${VERSION}\n"
3346								  "\n"
3347								  "${GEOMETRY_SHADER_ENABLE}\n"
3348								  "${VIEWPORT_ARRAY_ENABLE}\n"
3349								  "\n"
3350								  "layout(points, invocations = 16)         in;\n"
3351								  "layout(triangle_strip, max_vertices = 4) out;\n"
3352								  "\n"
3353								  "flat out int gs_fs_color;\n"
3354								  "\n"
3355								  "void main()\n"
3356								  "{\n"
3357								  "    gs_fs_color      = gl_InvocationID;\n"
3358								  "    gl_ViewportIndex = gl_InvocationID;\n"
3359								  "    gl_Position  = vec4(-1, -1, 0, 1);\n"
3360								  "    EmitVertex();\n"
3361								  "    gs_fs_color      = gl_InvocationID;\n"
3362								  "    gl_ViewportIndex = gl_InvocationID;\n"
3363								  "    gl_Position  = vec4(-1, 1, 0, 1);\n"
3364								  "    EmitVertex();\n"
3365								  "    gs_fs_color      = gl_InvocationID;\n"
3366								  "    gl_ViewportIndex = gl_InvocationID;\n"
3367								  "    gl_Position  = vec4(1, -1, 0, 1);\n"
3368								  "    EmitVertex();\n"
3369								  "    gs_fs_color      = gl_InvocationID;\n"
3370								  "    gl_ViewportIndex = gl_InvocationID;\n"
3371								  "    gl_Position  = vec4(1, 1, 0, 1);\n"
3372								  "    EmitVertex();\n"
3373								  "}\n"
3374								  "\n";
3375
3376	std::string result = source;
3377
3378	return result;
3379}
3380
3381/** Constructor
3382 *
3383 * @param context          Test context
3384 **/
3385DynamicViewportIndex::DynamicViewportIndex(deqp::Context& context, const glcts::ExtParameters& extParams)
3386	: DrawTestBase(context, extParams, "dynamic_viewport_index",
3387				   "Test verifies that gl_ViewportIndex can be assigned with dynamic value")
3388{
3389	/* Nothing to be done here */
3390}
3391
3392/** Get string with fragment shader source code
3393 *
3394 * @return Fragment shader source
3395 **/
3396std::string DynamicViewportIndex::getFragmentShader()
3397{
3398	static const GLchar* source = "${VERSION}\n"
3399								  "\n"
3400								  "flat in  int gs_fs_color;\n"
3401								  "     out int fs_out_color;\n"
3402								  "\n"
3403								  "void main()\n"
3404								  "{\n"
3405								  "    fs_out_color = gs_fs_color;\n"
3406								  "}\n"
3407								  "\n";
3408
3409	std::string result = source;
3410
3411	return result;
3412}
3413
3414/** Get string with geometry shader source code
3415 *
3416 * @return Geometry shader source
3417 **/
3418std::string DynamicViewportIndex::getGeometryShader()
3419{
3420	static const GLchar* source = "${VERSION}\n"
3421								  "\n"
3422								  "${GEOMETRY_SHADER_ENABLE}\n"
3423								  "${VIEWPORT_ARRAY_ENABLE}\n"
3424								  "\n"
3425								  "layout(points, invocations = 1)          in;\n"
3426								  "layout(triangle_strip, max_vertices = 4) out;\n"
3427								  "\n"
3428								  "uniform int uni_index;\n"
3429								  "\n"
3430								  "flat out int gs_fs_color;\n"
3431								  "\n"
3432								  "void main()\n"
3433								  "{\n"
3434								  "    gs_fs_color      = uni_index;\n"
3435								  "    gl_ViewportIndex = uni_index;\n"
3436								  "    gl_Position  = vec4(-1, -1, 0, 1);\n"
3437								  "    EmitVertex();\n"
3438								  "    gs_fs_color      = uni_index;\n"
3439								  "    gl_ViewportIndex = uni_index;\n"
3440								  "    gl_Position  = vec4(-1, 1, 0, 1);\n"
3441								  "    EmitVertex();\n"
3442								  "    gs_fs_color      = uni_index;\n"
3443								  "    gl_ViewportIndex = uni_index;\n"
3444								  "    gl_Position  = vec4(1, -1, 0, 1);\n"
3445								  "    EmitVertex();\n"
3446								  "    gs_fs_color      = uni_index;\n"
3447								  "    gl_ViewportIndex = uni_index;\n"
3448								  "    gl_Position  = vec4(1, 1, 0, 1);\n"
3449								  "    EmitVertex();\n"
3450								  "}\n"
3451								  "\n";
3452
3453	std::string result = source;
3454
3455	return result;
3456}
3457
3458/** Check if R32I texture is filled with 4x4 regions of increasing values <0:15>
3459 *
3460 * @param texture_0       Verified texture
3461 * @param ignored
3462 * @param draw_call_index Draw call that was executed
3463 *
3464 * @return True if texture_0 is filled with expected pattern
3465 **/
3466bool DynamicViewportIndex::checkResults(Utils::texture& texture_0, Utils::texture& /* texture_1 */,
3467										GLuint			draw_call_index)
3468{
3469	bool   check_result = true;
3470	GLuint index		= 0;
3471
3472	std::vector<GLint> texture_data;
3473	texture_data.resize(m_width * m_height);
3474	texture_0.get(GL_RED_INTEGER, GL_INT, &texture_data[0]);
3475
3476	for (GLuint y = 0; y < 4; ++y)
3477	{
3478		for (GLuint x = 0; x < 4; ++x)
3479		{
3480			GLint expected_value = -1;
3481			if (index <= draw_call_index)
3482			{
3483				expected_value = index;
3484			}
3485
3486			bool result = checkRegionR32I(x, y, expected_value, &texture_data[0]);
3487
3488			if (false == result)
3489			{
3490				check_result = false;
3491				goto end;
3492			}
3493
3494			index += 1;
3495		}
3496	}
3497
3498end:
3499	return check_result;
3500}
3501
3502/** Get number of draw call to be executed during test
3503 *
3504 * @return 16
3505 **/
3506GLuint DynamicViewportIndex::getDrawCallsNumber()
3507{
3508	return 16;
3509}
3510
3511/** Prepare uniforms for given draw call
3512 *
3513 * @param program         Program object
3514 * @param draw_call_index Index of draw call to be executed
3515 **/
3516void DynamicViewportIndex::prepareUniforms(Utils::program& program, GLuint draw_call_index)
3517{
3518	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3519
3520	GLint location = program.getUniformLocation("uni_index");
3521
3522	gl.uniform1i(location, (GLint)draw_call_index);
3523	GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
3524}
3525
3526/** Constructor
3527 *
3528 * @param context          Test context
3529 **/
3530DrawMulitpleViewportsWithSingleInvocation::DrawMulitpleViewportsWithSingleInvocation(
3531	deqp::Context& context, const glcts::ExtParameters& extParams)
3532	: DrawTestBase(context, extParams, "draw_mulitple_viewports_with_single_invocation",
3533				   "Test verifies that single invocation can output to multiple viewports")
3534{
3535	/* Nothing to be done here */
3536}
3537
3538/** Get string with fragment shader source code
3539 *
3540 * @return Fragment shader source
3541 **/
3542std::string DrawMulitpleViewportsWithSingleInvocation::getFragmentShader()
3543{
3544	static const GLchar* source = "${VERSION}\n"
3545								  "\n"
3546								  "flat in  int gs_fs_color;\n"
3547								  "     out int fs_out_color;\n"
3548								  "\n"
3549								  "void main()\n"
3550								  "{\n"
3551								  "    fs_out_color = gs_fs_color;\n"
3552								  "}\n"
3553								  "\n";
3554
3555	std::string result = source;
3556
3557	return result;
3558}
3559
3560/** Get string with geometry shader source code
3561 *
3562 * @return Geometry shader source
3563 **/
3564std::string DrawMulitpleViewportsWithSingleInvocation::getGeometryShader()
3565{
3566	static const GLchar* source = "${VERSION}\n"
3567								  "\n"
3568								  "${GEOMETRY_SHADER_ENABLE}\n"
3569								  "${VIEWPORT_ARRAY_ENABLE}\n"
3570								  "\n"
3571								  "layout(points, invocations = 1)           in;\n"
3572								  "layout(triangle_strip, max_vertices = 64) out;\n"
3573								  "\n"
3574								  "flat out int gs_fs_color;\n"
3575								  "\n"
3576								  "void routine(int index)\n"
3577								  "{\n"
3578								  "    gs_fs_color      = index;\n"
3579								  "    gl_ViewportIndex = index;\n"
3580								  "    gl_Position  = vec4(-1, -1, 0, 1);\n"
3581								  "    EmitVertex();\n"
3582								  "    gs_fs_color      = index;\n"
3583								  "    gl_ViewportIndex = index;\n"
3584								  "    gl_Position  = vec4(-1, 1, 0, 1);\n"
3585								  "    EmitVertex();\n"
3586								  "    gs_fs_color      = index;\n"
3587								  "    gl_ViewportIndex = index;\n"
3588								  "    gl_Position  = vec4(1, -1, 0, 1);\n"
3589								  "    EmitVertex();\n"
3590								  "    gs_fs_color      = index;\n"
3591								  "    gl_ViewportIndex = index;\n"
3592								  "    gl_Position  = vec4(1, 1, 0, 1);\n"
3593								  "    EmitVertex();\n"
3594								  "    EndPrimitive();\n"
3595								  "}\n"
3596								  "\n"
3597								  "void main()\n"
3598								  "{\n"
3599								  "    for(int i = 0; i < 16; ++i)\n"
3600								  "    {\n"
3601								  "        routine(i);\n"
3602								  "    }\n"
3603								  "}\n"
3604								  "\n";
3605
3606	std::string result = source;
3607
3608	return result;
3609}
3610
3611/** Constructor
3612 *
3613 * @param context          Test context
3614 **/
3615ViewportIndexSubroutine::ViewportIndexSubroutine(deqp::Context& context, const glcts::ExtParameters& extParams)
3616	: DrawTestBase(context, extParams, "viewport_index_subroutine",
3617				   "Test verifies subroutines can be used to output data to specific viewport")
3618{
3619	/* Nothing to be done here */
3620}
3621
3622/** Execute test
3623 *
3624 * @return tcu::TestNode::CONTINUE after executing test case, tcu::TestNode::STOP otherwise
3625 **/
3626tcu::TestNode::IterateResult ViewportIndexSubroutine::iterate()
3627{
3628	/* this exists solely to check for subroutine support, which is not supported in ES.
3629	   The real work is done in DrawTestBase::iterate() */
3630	const glu::ContextType& context_type = m_context.getRenderContext().getType();
3631	if (!glu::isContextTypeGLCore(context_type))
3632	{
3633		throw tcu::NotSupportedError("Subroutines not supported", "", __FILE__, __LINE__);
3634	}
3635
3636	return DrawTestBase::iterate();
3637}
3638
3639/** Get string with fragment shader source code
3640 *
3641 * @return Fragment shader source
3642 **/
3643std::string ViewportIndexSubroutine::getFragmentShader()
3644{
3645	static const GLchar* source = "${VERSION}\n"
3646								  "\n"
3647								  "flat in  int gs_fs_color;\n"
3648								  "     out int fs_out_color;\n"
3649								  "\n"
3650								  "void main()\n"
3651								  "{\n"
3652								  "    fs_out_color = gs_fs_color;\n"
3653								  "}\n"
3654								  "\n";
3655
3656	std::string result = source;
3657
3658	return result;
3659}
3660
3661/** Get string with geometry shader source code
3662 *
3663 * @return Geometry shader source
3664 **/
3665std::string ViewportIndexSubroutine::getGeometryShader()
3666{
3667	static const GLchar* source = "${VERSION}\n"
3668								  "\n"
3669								  "${GEOMETRY_SHADER_ENABLE}\n"
3670								  "${VIEWPORT_ARRAY_ENABLE}\n"
3671								  "\n"
3672								  "layout(points, invocations = 1)          in;\n"
3673								  "layout(triangle_strip, max_vertices = 4) out;\n"
3674								  "\n"
3675								  "flat out int gs_fs_color;\n"
3676								  "\n"
3677								  "subroutine void indexSetter(void);\n"
3678								  "\n"
3679								  "subroutine(indexSetter) void four()\n"
3680								  "{\n"
3681								  "    gs_fs_color      = 4;\n"
3682								  "    gl_ViewportIndex = 4;\n"
3683								  "}\n"
3684								  "\n"
3685								  "subroutine(indexSetter) void five()\n"
3686								  "{\n"
3687								  "    gs_fs_color      = 5;\n"
3688								  "    gl_ViewportIndex = 5;\n"
3689								  "}\n"
3690								  "\n"
3691								  "subroutine uniform indexSetter routine;\n"
3692								  "\n"
3693								  "void main()\n"
3694								  "{\n"
3695								  "    routine();\n"
3696								  "    gl_Position  = vec4(-1, -1, 0, 1);\n"
3697								  "    EmitVertex();\n"
3698								  "    routine();\n"
3699								  "    gl_Position  = vec4(-1, 1, 0, 1);\n"
3700								  "    EmitVertex();\n"
3701								  "    routine();\n"
3702								  "    gl_Position  = vec4(1, -1, 0, 1);\n"
3703								  "    EmitVertex();\n"
3704								  "    routine();\n"
3705								  "    gl_Position  = vec4(1, 1, 0, 1);\n"
3706								  "    EmitVertex();\n"
3707								  "}\n"
3708								  "\n";
3709
3710	std::string result = source;
3711
3712	return result;
3713}
3714
3715/** Check if R32I texture is filled with two halves, left is 4, right is either -1 or 5
3716 *
3717 * @param texture_0       Verified texture
3718 * @param ignored
3719 * @param draw_call_index Draw call that was executed
3720 *
3721 * @return True if texture_0 is filled with expected pattern
3722 **/
3723bool ViewportIndexSubroutine::checkResults(Utils::texture& texture_0, Utils::texture& /* texture_1 */,
3724										   GLuint		   draw_call_index)
3725{
3726	bool check_result = true;
3727
3728	std::vector<GLint> texture_data;
3729	texture_data.resize(m_width * m_height);
3730	texture_0.get(GL_RED_INTEGER, GL_INT, &texture_data[0]);
3731
3732	/* Left is 4 and right is -1, or left is 4 and right is 5 */
3733	GLint expected_left  = 4;
3734	GLint expected_right = (1 == draw_call_index) ? 5 : -1;
3735
3736	for (GLuint y = 0; y < 4; ++y)
3737	{
3738		for (GLuint x = 0; x < 2; ++x)
3739		{
3740			bool result = checkRegionR32I(x, y, expected_left, &texture_data[0]);
3741
3742			if (false == result)
3743			{
3744				check_result = false;
3745				goto end;
3746			}
3747		}
3748	}
3749
3750	for (GLuint y = 0; y < 4; ++y)
3751	{
3752		for (GLuint x = 2; x < 4; ++x)
3753		{
3754			bool result = checkRegionR32I(x, y, expected_right, &texture_data[0]);
3755
3756			if (false == result)
3757			{
3758				check_result = false;
3759				goto end;
3760			}
3761		}
3762	}
3763
3764end:
3765	return check_result;
3766}
3767
3768/** Get number of draw call to be executed during test
3769 *
3770 * @return 2
3771 **/
3772GLuint ViewportIndexSubroutine::getDrawCallsNumber()
3773{
3774	return 2;
3775}
3776
3777/** Prepare uniforms for given draw call
3778 *
3779 * @param program         Program object
3780 * @param draw_call_index Index of draw call to be executed
3781 **/
3782void ViewportIndexSubroutine::prepareUniforms(Utils::program& program, GLuint draw_call_index)
3783{
3784	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3785
3786	const GLchar* subroutine_name = (0 == draw_call_index) ? "four" : "five";
3787
3788	GLint  location = program.getSubroutineUniformLocation("routine", GL_GEOMETRY_SHADER);
3789	GLuint index	= program.getSubroutineIndex(subroutine_name, GL_GEOMETRY_SHADER);
3790
3791	if (0 != location)
3792	{
3793		TCU_FAIL("Something wrong, subroutine uniform location is not 0. Mistake in geometry shader?");
3794	}
3795
3796	gl.uniformSubroutinesuiv(GL_GEOMETRY_SHADER, 1, &index);
3797	GLU_EXPECT_NO_ERROR(gl.getError(), "UniformSubroutinesuiv");
3798}
3799
3800/** Set 4th viewport on left half and 5 on right half of framebuffer. Rest span over whole image.
3801 *
3802 * @param ignored
3803 * @param iteration_index Index of iteration, used to select "viewport" method
3804 **/
3805void ViewportIndexSubroutine::setupViewports(TEST_TYPE /* type */, glw::GLuint iteration_index)
3806{
3807	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3808
3809	GLfloat data[2 * 4] = { 0.0f, 0.0f, 64.0f, 128.0f, 64.0f, 0.0f, 64.0f, 128.0f };
3810
3811	gl.viewport(0, 0, m_width, m_height);
3812	GLU_EXPECT_NO_ERROR(gl.getError(), "Viewport");
3813
3814	switch (iteration_index)
3815	{
3816	case 0:
3817
3818		gl.viewportArrayv(4, 2, data);
3819		GLU_EXPECT_NO_ERROR(gl.getError(), "ViewportArrayv");
3820
3821		break;
3822
3823	case 1:
3824
3825		gl.viewportIndexedf(4, data[0], data[1], data[2], data[3]);
3826		GLU_EXPECT_NO_ERROR(gl.getError(), "ViewportIndexedf");
3827
3828		gl.viewportIndexedf(5, data[4], data[5], data[6], data[7]);
3829		GLU_EXPECT_NO_ERROR(gl.getError(), "ViewportIndexedf");
3830
3831		break;
3832
3833	case 2:
3834
3835		gl.viewportIndexedfv(4, &data[0]);
3836		GLU_EXPECT_NO_ERROR(gl.getError(), "ViewportIndexedfv");
3837
3838		gl.viewportIndexedfv(5, &data[4]);
3839		GLU_EXPECT_NO_ERROR(gl.getError(), "ViewportIndexedfv");
3840
3841		break;
3842
3843	default:
3844		TCU_FAIL("Invalid value");
3845	}
3846}
3847
3848/** Constructor
3849 *
3850 * @param context Test context
3851 **/
3852DrawMultipleLayers::DrawMultipleLayers(deqp::Context& context, const glcts::ExtParameters& extParams)
3853	: DrawTestBase(context, extParams, "draw_multiple_layers",
3854				   "Test verifies that single viewport affects multiple layers in the same way")
3855{
3856	/* Nothing to be done here */
3857}
3858
3859/** Constructor
3860 *
3861 * @param context          Test context
3862 * @param test_name        Test name
3863 * @param test_description Test description
3864 **/
3865DrawMultipleLayers::DrawMultipleLayers(deqp::Context& context, const glcts::ExtParameters& extParams,
3866									   const GLchar* test_name, const GLchar* test_description)
3867	: DrawTestBase(context, extParams, test_name, test_description)
3868{
3869	/* Nothing to be done here */
3870}
3871
3872/** Get string with fragment shader source code
3873 *
3874 * @return Fragment shader source
3875 **/
3876std::string DrawMultipleLayers::getFragmentShader()
3877{
3878	static const GLchar* source = "${VERSION}\n"
3879								  "\n"
3880								  "flat in  int gs_fs_color;\n"
3881								  "     out int fs_out_color;\n"
3882								  "\n"
3883								  "void main()\n"
3884								  "{\n"
3885								  "    fs_out_color = gs_fs_color;\n"
3886								  "}\n"
3887								  "\n";
3888
3889	std::string result = source;
3890
3891	return result;
3892}
3893
3894/** Get string with geometry shader source code
3895 *
3896 * @return Geometry shader source
3897 **/
3898std::string DrawMultipleLayers::getGeometryShader()
3899{
3900	static const GLchar* source = "${VERSION}\n"
3901								  "\n"
3902								  "${GEOMETRY_SHADER_ENABLE}\n"
3903								  "${VIEWPORT_ARRAY_ENABLE}\n"
3904								  "\n"
3905								  "layout(points, invocations = 16)         in;\n"
3906								  "layout(triangle_strip, max_vertices = 4) out;\n"
3907								  "\n"
3908								  "flat out int gs_fs_color;\n"
3909								  "\n"
3910								  "void main()\n"
3911								  "{\n"
3912								  "    gs_fs_color      = gl_InvocationID;\n"
3913								  "    gl_ViewportIndex = gl_InvocationID;\n"
3914								  "    gl_Layer         = gl_InvocationID;\n"
3915								  "    gl_Position  = vec4(-1, -1, 0, 1);\n"
3916								  "    EmitVertex();\n"
3917								  "    gs_fs_color      = gl_InvocationID;\n"
3918								  "    gl_ViewportIndex = gl_InvocationID;\n"
3919								  "    gl_Layer         = gl_InvocationID;\n"
3920								  "    gl_Position  = vec4(-1, 1, 0, 1);\n"
3921								  "    EmitVertex();\n"
3922								  "    gs_fs_color      = gl_InvocationID;\n"
3923								  "    gl_ViewportIndex = gl_InvocationID;\n"
3924								  "    gl_Layer         = gl_InvocationID;\n"
3925								  "    gl_Position  = vec4(1, -1, 0, 1);\n"
3926								  "    EmitVertex();\n"
3927								  "    gs_fs_color      = gl_InvocationID;\n"
3928								  "    gl_ViewportIndex = gl_InvocationID;\n"
3929								  "    gl_Layer         = gl_InvocationID;\n"
3930								  "    gl_Position  = vec4(1, 1, 0, 1);\n"
3931								  "    EmitVertex();\n"
3932								  "}\n"
3933								  "\n";
3934
3935	std::string result = source;
3936
3937	return result;
3938}
3939
3940/** Check if R32I texture is filled with 4x4 regions of increasing values <0:15>
3941 *
3942 * @param texture_0       Verified texture
3943 * @param ignored
3944 * @param ignored
3945 *
3946 * @return True if texture_0 is filled with expected pattern
3947 **/
3948bool DrawMultipleLayers::checkResults(Utils::texture& texture_0, Utils::texture& /* texture_1 */,
3949									  GLuint /* draw_call_index */)
3950{
3951	static const GLuint layer_size = m_width * m_height;
3952
3953	bool check_result = true;
3954
3955	std::vector<GLint> texture_data;
3956	texture_data.resize(layer_size * m_depth);
3957	texture_0.get(GL_RED_INTEGER, GL_INT, &texture_data[0]);
3958
3959	/* 16 layers, only region corresponding with layer index should be modified */
3960	for (GLuint layer = 0; layer < m_depth; ++layer)
3961	{
3962		GLuint index = 0;
3963
3964		for (GLuint y = 0; y < 4; ++y)
3965		{
3966			for (GLuint x = 0; x < 4; ++x)
3967			{
3968				GLint* layer_data = &texture_data[layer * layer_size];
3969
3970				GLint expected_value = -1;
3971				if (index == layer)
3972				{
3973					expected_value = index;
3974				}
3975
3976				bool result = checkRegionR32I(x, y, expected_value, layer_data);
3977
3978				if (false == result)
3979				{
3980					check_result = false;
3981					goto end;
3982				}
3983
3984				index += 1;
3985			}
3986		}
3987	}
3988
3989end:
3990	return check_result;
3991}
3992
3993/** Prepare textures used as framebuffer's attachments for current draw call
3994 *
3995 * @param texture_0 R32I texture
3996 * @param ignored
3997 **/
3998void DrawMultipleLayers::prepareTextures(Utils::texture& texture_0, Utils::texture& /* texture_1 */)
3999{
4000	prepareTextureArrayR32I(texture_0);
4001}
4002
4003/** Constructor
4004 *
4005 * @param context          Test context
4006 * @param test_name        Test name
4007 * @param test_description Test description
4008 **/
4009Scissor::Scissor(deqp::Context& context, const glcts::ExtParameters& extParams)
4010	: DrawMultipleLayers(context, extParams, "scissor", "Test verifies that scissor test is applied as expected")
4011{
4012	/* Nothing to be done here */
4013}
4014
4015/** Get test type
4016 *
4017 * @return SCISSOR
4018 **/
4019DrawTestBase::TEST_TYPE Scissor::getTestType()
4020{
4021	return SCISSOR;
4022}
4023
4024/** Constructor
4025 *
4026 * @param context          Test context
4027 * @param test_name        Test name
4028 * @param test_description Test description
4029 **/
4030ScissorZeroDimension::ScissorZeroDimension(deqp::Context& context, const glcts::ExtParameters& extParams)
4031	: DrawMultipleLayers(context, extParams, "scissor_zero_dimension",
4032						 "Test verifies that scissor test discard all fragments when width and height is set to zero")
4033{
4034	/* Nothing to be done here */
4035}
4036
4037/** Check if R32I texture is filled with 4x4 regions of increasing values <0:15>
4038 *
4039 * @param texture_0       Verified texture
4040 * @param ignored
4041 * @param ignored
4042 *
4043 * @return True if texture_0 is filled with expected pattern
4044 **/
4045bool ScissorZeroDimension::checkResults(Utils::texture& texture_0, Utils::texture& /* texture_1 */,
4046										GLuint /* draw_call_index */)
4047{
4048	static const GLuint layer_size = m_width * m_height;
4049
4050	bool check_result = true;
4051
4052	std::vector<GLint> texture_data;
4053	texture_data.resize(layer_size * m_depth);
4054	texture_0.get(GL_RED_INTEGER, GL_INT, &texture_data[0]);
4055
4056	/* 16 layers, all regions were not modified */
4057	for (GLuint layer = 0; layer < m_depth; ++layer)
4058	{
4059		for (GLuint y = 0; y < 4; ++y)
4060		{
4061			for (GLuint x = 0; x < 4; ++x)
4062			{
4063				GLint* layer_data = &texture_data[layer * layer_size];
4064
4065				GLint expected_value = -1;
4066
4067				bool result = checkRegionR32I(x, y, expected_value, layer_data);
4068
4069				if (false == result)
4070				{
4071					check_result = false;
4072					goto end;
4073				}
4074			}
4075		}
4076	}
4077
4078end:
4079	return check_result;
4080}
4081
4082/** Get test type
4083 *
4084 * @return SCISSOR
4085 **/
4086DrawTestBase::TEST_TYPE ScissorZeroDimension::getTestType()
4087{
4088	return SCISSOR;
4089}
4090
4091/** Set up viewports
4092 *
4093 * @param Ignored
4094 * @param iteration_index Index of iteration for given test type
4095 **/
4096void ScissorZeroDimension::setupViewports(TEST_TYPE /* type */, GLuint iteration_index)
4097{
4098	SCISSOR_METHOD method;
4099	switch (iteration_index)
4100	{
4101	case 0:
4102	case 1:
4103	case 2:
4104		method = (SCISSOR_METHOD)iteration_index;
4105		break;
4106	default:
4107		TCU_FAIL("Invalid value");
4108	}
4109
4110	setup4x4Scissor(method, true /* set_zeros */);
4111}
4112
4113/** Constructor
4114 *
4115 * @param context          Test context
4116 * @param test_name        Test name
4117 * @param test_description Test description
4118 **/
4119ScissorClear::ScissorClear(deqp::Context& context, const glcts::ExtParameters& extParams)
4120	: DrawMultipleLayers(context, extParams, "scissor_clear",
4121						 "Test verifies that Clear is affected only by settings of scissor test in first viewport")
4122{
4123	/* Nothing to be done here */
4124}
4125
4126/** Check if R32I texture is filled with 4x4 regions of increasing values <0:15>
4127 *
4128 * @param texture_0 Verified texture
4129 * @param ignored
4130 * @param ignored
4131 *
4132 * @return True if texture_0 is filled with expected pattern
4133 **/
4134bool ScissorClear::checkResults(Utils::texture& texture_0, Utils::texture& /* texture_1 */, GLuint /*draw_call_index */)
4135{
4136	static const GLuint layer_size = m_width * m_height;
4137
4138	bool check_result = true;
4139
4140	std::vector<GLint> texture_data;
4141	texture_data.resize(layer_size * m_depth);
4142	texture_0.get(GL_RED_INTEGER, GL_INT, &texture_data[0]);
4143
4144	/* 16 layers, only region corresponding with scissor box 0 should be modified */
4145	for (GLuint layer = 0; layer < m_depth; ++layer)
4146	{
4147		for (GLuint y = 0; y < 4; ++y)
4148		{
4149			for (GLuint x = 0; x < 4; ++x)
4150			{
4151				GLint* layer_data = &texture_data[layer * layer_size];
4152
4153				GLint expected_value = -1;
4154				if ((0 == x) && (0 == y))
4155				{
4156					expected_value = 0;
4157				}
4158
4159				bool result = checkRegionR32I(x, y, expected_value, layer_data);
4160
4161				if (false == result)
4162				{
4163					check_result = false;
4164					goto end;
4165				}
4166			}
4167		}
4168	}
4169
4170end:
4171	return check_result;
4172}
4173
4174/** Get test type
4175 *
4176 * @return SCISSOR
4177 **/
4178DrawTestBase::TEST_TYPE ScissorClear::getTestType()
4179{
4180	return SCISSOR;
4181}
4182
4183/** Selects if test should do draw or clear operation
4184 *
4185 * @return true - clear operation
4186 **/
4187bool ScissorClear::isClearTest()
4188{
4189	return true;
4190}
4191
4192/** Constructor
4193 *
4194 * @param context          Test context
4195 * @param test_name        Test name
4196 * @param test_description Test description
4197 **/
4198DepthRange::DepthRange(deqp::Context& context, const glcts::ExtParameters& extParams)
4199	: DrawTestBase(context, extParams, "depth_range", "Test verifies that depth range is applied as expected")
4200{
4201	/* Nothing to be done here */
4202}
4203
4204/** Check if R32F texture is filled with two rows, top with decreasing values, bottom with incresing values
4205 *
4206 * @param texture_0 Verified texture
4207 * @param ignored
4208 * @param ignored
4209 *
4210 * @return True if texture_0 is filled with expected pattern
4211 **/
4212bool DepthRange::checkResults(Utils::texture& texture_0, Utils::texture& /* texture_1 */, GLuint /*draw_call_index */)
4213{
4214	static const GLfloat step = 1.0f / 16.0f;
4215
4216	bool check_result = true;
4217
4218	std::vector<GLfloat> texture_data;
4219	texture_data.resize(m_r32f_width * m_r32f_height);
4220	texture_0.get(GL_RED, GL_FLOAT, &texture_data[0]);
4221
4222	GLfloat depth_data[16 * 2];
4223
4224	for (GLuint i = 0; i < 16; ++i)
4225	{
4226		const GLfloat near = step * (GLfloat)i;
4227
4228		depth_data[i * 2 + 0] = near;
4229		depth_data[i * 2 + 1] = 1.0f - near;
4230	}
4231
4232	for (GLuint i = 0; i < 16; ++i)
4233	{
4234		const GLfloat expected_near = depth_data[i * 2 + 0];
4235		const GLfloat expected_far  = depth_data[i * 2 + 1];
4236
4237		/* Bottom row should contain near values, top one should contain far values */
4238		const GLfloat near = texture_data[i];
4239		const GLfloat far  = texture_data[i + 16];
4240
4241		if ((expected_near != near) || (expected_far != far))
4242		{
4243			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid values at " << i << " expected ["
4244												<< expected_near << ", " << expected_far << "] got [" << near << ", "
4245												<< far << "]" << tcu::TestLog::EndMessage;
4246
4247			check_result = false;
4248			break;
4249		}
4250	}
4251
4252	return check_result;
4253}
4254
4255/** Get string with fragment shader source code
4256 *
4257 * @return Fragment shader source
4258 **/
4259std::string DepthRange::getFragmentShader()
4260{
4261	static const GLchar* source = "${VERSION}\n"
4262								  "\n"
4263								  "#ifdef GL_ES\n"
4264								  "precision highp float;\n"
4265								  "#endif\n"
4266								  "out float fs_out_color;\n"
4267								  "\n"
4268								  "void main()\n"
4269								  "{\n"
4270								  "    fs_out_color = gl_FragCoord.z;\n"
4271								  "}\n"
4272								  "\n";
4273
4274	std::string result = source;
4275
4276	return result;
4277}
4278
4279/** Get string with geometry shader source code
4280 *
4281 * @return Geometry shader source
4282 **/
4283std::string DepthRange::getGeometryShader()
4284{
4285	static const GLchar* source = "${VERSION}\n"
4286								  "\n"
4287								  "${GEOMETRY_SHADER_ENABLE}\n"
4288								  "${VIEWPORT_ARRAY_ENABLE}\n"
4289								  "\n"
4290								  "layout(points, invocations = 16)         in;\n"
4291								  "layout(triangle_strip, max_vertices = 8) out;\n"
4292								  "\n"
4293								  "void main()\n"
4294								  "{\n"
4295								  "    const float top_z    = 1.0;\n"
4296								  "    const float bottom_z = -1.0;\n"
4297								  "\n"
4298								  "    /* Bottom */\n"
4299								  "    gl_ViewportIndex = gl_InvocationID;\n"
4300								  "    gl_Position  = vec4(-1, -1, bottom_z, 1);\n"
4301								  "    EmitVertex();\n"
4302								  "    gl_ViewportIndex = gl_InvocationID;\n"
4303								  "    gl_Position  = vec4(-1, 0, bottom_z, 1);\n"
4304								  "    EmitVertex();\n"
4305								  "    gl_ViewportIndex = gl_InvocationID;\n"
4306								  "    gl_Position  = vec4(1, -1, bottom_z, 1);\n"
4307								  "    EmitVertex();\n"
4308								  "    gl_ViewportIndex = gl_InvocationID;\n"
4309								  "    gl_Position  = vec4(1, 0, bottom_z, 1);\n"
4310								  "    EmitVertex();\n"
4311								  "    EndPrimitive();\n"
4312								  "\n"
4313								  "    /* Top */\n"
4314								  "    gl_ViewportIndex = gl_InvocationID;\n"
4315								  "    gl_Position  = vec4(-1, 0, top_z, 1);\n"
4316								  "    EmitVertex();\n"
4317								  "    gl_ViewportIndex = gl_InvocationID;\n"
4318								  "    gl_Position  = vec4(-1, 1, top_z, 1);\n"
4319								  "    EmitVertex();\n"
4320								  "    gl_ViewportIndex = gl_InvocationID;\n"
4321								  "    gl_Position  = vec4(1, 0, top_z, 1);\n"
4322								  "    EmitVertex();\n"
4323								  "    gl_ViewportIndex = gl_InvocationID;\n"
4324								  "    gl_Position  = vec4(1, 1, top_z, 1);\n"
4325								  "    EmitVertex();\n"
4326								  "    EndPrimitive();\n"
4327								  "}\n"
4328								  "\n";
4329
4330	std::string result = source;
4331
4332	return result;
4333}
4334
4335/** Get test type
4336 *
4337 * @return DEPTHRANGE
4338 **/
4339DrawTestBase::TEST_TYPE DepthRange::getTestType()
4340{
4341	return DEPTHRANGE;
4342}
4343
4344/** Prepare textures used as framebuffer's attachments for current draw call
4345 *
4346 * @param texture_0 R32F texture
4347 * @param ignored
4348 **/
4349void DepthRange::prepareTextures(Utils::texture& texture_0, Utils::texture& /* texture_1 */)
4350{
4351	prepareTextureR32F(texture_0);
4352}
4353
4354/** Constructor
4355 *
4356 * @param context          Test context
4357 * @param test_name        Test name
4358 * @param test_description Test description
4359 **/
4360DepthRangeDepthTest::DepthRangeDepthTest(deqp::Context& context, const glcts::ExtParameters& extParams)
4361	: DrawTestBase(context, extParams, "depth_range_depth_test",
4362				   "Test verifies that depth test work as expected with multiple viewports")
4363{
4364	/* Nothing to be done here */
4365}
4366
4367/** Check if R32F texture is filled with two rows of values less than expected depth
4368 *
4369 * @param texture_0       Verified texture
4370 * @param ignored
4371 * @param draw_call_index Index of draw call
4372 *
4373 * @return True if texture_0 is filled with expected pattern
4374 **/
4375bool DepthRangeDepthTest::checkResults(Utils::texture& texture_0, Utils::texture& /* texture_1 */,
4376									   GLuint		   draw_call_index)
4377{
4378	static const GLfloat step = 1.0f / 16.0f;
4379
4380	const GLfloat depth_value = step * (GLfloat)draw_call_index;
4381
4382	bool check_result = true;
4383
4384	std::vector<GLfloat> texture_data;
4385	texture_data.resize(m_r32f_width * m_r32f_height);
4386	texture_0.get(GL_RED, GL_FLOAT, &texture_data[0]);
4387
4388	for (GLuint i = 0; i < 16; ++i)
4389	{
4390		/* Bottom row should contain near values, top one should contain far values */
4391		const GLfloat near = texture_data[i];
4392		const GLfloat far  = texture_data[i + 16];
4393
4394		if ((depth_value <= near) || (depth_value <= far))
4395		{
4396			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid values at " << i << " depth value "
4397												<< depth_value << " got [" << near << ", " << far << "]"
4398												<< tcu::TestLog::EndMessage;
4399
4400			check_result = false;
4401			break;
4402		}
4403	}
4404
4405	return check_result;
4406}
4407
4408/** Get settings of clear operation
4409 *
4410 * @param clear_depth_before_draw Selects if clear should be executed before draw.
4411 * @param iteration_index         Index of draw call
4412 * @param depth_value             Value that will be used to clear depth buffer
4413 **/
4414void DepthRangeDepthTest::getClearSettings(bool& clear_depth_before_draw, GLuint iteration_index, GLfloat& depth_value)
4415{
4416	static const GLfloat step = 1.0 / 16.0;
4417
4418	clear_depth_before_draw = true;
4419
4420	depth_value = step * (GLfloat)iteration_index;
4421}
4422
4423/** Get number of draw call to be executed during test
4424 *
4425 * @return 18
4426 **/
4427GLuint DepthRangeDepthTest::getDrawCallsNumber()
4428{
4429	return 18;
4430}
4431
4432/** Get string with fragment shader source code
4433 *
4434 * @return Fragment shader source
4435 **/
4436std::string DepthRangeDepthTest::getFragmentShader()
4437{
4438	static const GLchar* source = "${VERSION}\n"
4439								  "\n"
4440								  "#ifdef GL_ES\n"
4441								  "precision highp float;\n"
4442								  "#endif\n"
4443								  "out float fs_out_color;\n"
4444								  "\n"
4445								  "void main()\n"
4446								  "{\n"
4447								  "    fs_out_color = gl_FragCoord.z;\n"
4448								  "}\n"
4449								  "\n";
4450
4451	std::string result = source;
4452
4453	return result;
4454}
4455
4456/** Get string with geometry shader source code
4457 *
4458 * @return Geometry shader source
4459 **/
4460std::string DepthRangeDepthTest::getGeometryShader()
4461{
4462	static const GLchar* source = "${VERSION}\n"
4463								  "\n"
4464								  "${GEOMETRY_SHADER_ENABLE}\n"
4465								  "${VIEWPORT_ARRAY_ENABLE}\n"
4466								  "\n"
4467								  "layout(points, invocations = 16)         in;\n"
4468								  "layout(triangle_strip, max_vertices = 8) out;\n"
4469								  "\n"
4470								  "void main()\n"
4471								  "{\n"
4472								  "    const float top_z    = 1.0;\n"
4473								  "    const float bottom_z = -1.0;\n"
4474								  "\n"
4475								  "    /* Bottom */\n"
4476								  "    gl_ViewportIndex = gl_InvocationID;\n"
4477								  "    gl_Position  = vec4(-1, -1, bottom_z, 1);\n"
4478								  "    EmitVertex();\n"
4479								  "    gl_ViewportIndex = gl_InvocationID;\n"
4480								  "    gl_Position  = vec4(-1, 0, bottom_z, 1);\n"
4481								  "    EmitVertex();\n"
4482								  "    gl_ViewportIndex = gl_InvocationID;\n"
4483								  "    gl_Position  = vec4(1, -1, bottom_z, 1);\n"
4484								  "    EmitVertex();\n"
4485								  "    gl_ViewportIndex = gl_InvocationID;\n"
4486								  "    gl_Position  = vec4(1, 0, bottom_z, 1);\n"
4487								  "    EmitVertex();\n"
4488								  "\n"
4489								  "    /* Top */\n"
4490								  "    gl_ViewportIndex = gl_InvocationID;\n"
4491								  "    gl_Position  = vec4(-1, 0, top_z, 1);\n"
4492								  "    EmitVertex();\n"
4493								  "    gl_ViewportIndex = gl_InvocationID;\n"
4494								  "    gl_Position  = vec4(-1, 1, top_z, 1);\n"
4495								  "    EmitVertex();\n"
4496								  "    gl_ViewportIndex = gl_InvocationID;\n"
4497								  "    gl_Position  = vec4(1, 0, top_z, 1);\n"
4498								  "    EmitVertex();\n"
4499								  "    gl_ViewportIndex = gl_InvocationID;\n"
4500								  "    gl_Position  = vec4(1, 1, top_z, 1);\n"
4501								  "    EmitVertex();\n"
4502								  "    EndPrimitive();\n"
4503								  "}\n"
4504								  "\n";
4505
4506	std::string result = source;
4507
4508	return result;
4509}
4510
4511/** Get test type
4512 *
4513 * @return DEPTHRANGE
4514 **/
4515DrawTestBase::TEST_TYPE DepthRangeDepthTest::getTestType()
4516{
4517	return DEPTHRANGE;
4518}
4519
4520/** Prepare textures used as framebuffer's attachments for current draw call
4521 *
4522 * @param texture_0 R32F texture
4523 * @param texture_1 D32F texture
4524 **/
4525void DepthRangeDepthTest::prepareTextures(Utils::texture& texture_0, Utils::texture& texture_1)
4526{
4527	prepareTextureR32F(texture_0);
4528	prepareTextureD32F(texture_1);
4529}
4530
4531/** Attach textures to framebuffer
4532 *
4533 * @param framebuffer Framebuffer instance
4534 * @param texture_0   Texture attached as color 0
4535 * @param texture_1   Texture attached as depth
4536 **/
4537void DepthRangeDepthTest::setupFramebuffer(Utils::framebuffer& framebuffer, Utils::texture& texture_0,
4538										   Utils::texture& texture_1)
4539{
4540	framebuffer.attachTexture(GL_COLOR_ATTACHMENT0, texture_0.m_id, m_width, m_height);
4541	framebuffer.attachTexture(GL_DEPTH_ATTACHMENT, texture_1.m_id, m_width, m_height);
4542}
4543
4544/** Set up viewports
4545 *
4546 * @param ignored
4547 * @param iteration_index Index of iteration for given test type
4548 **/
4549void DepthRangeDepthTest::setupViewports(TEST_TYPE /* type */, GLuint iteration_index)
4550{
4551	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
4552
4553	DEPTH_RANGE_METHOD method;
4554	switch (iteration_index)
4555	{
4556	case 0:
4557	case 1:
4558		method = (DEPTH_RANGE_METHOD)iteration_index;
4559		break;
4560	default:
4561		TCU_FAIL("Invalid value");
4562	}
4563	setup16x2Depths(method);
4564
4565	gl.enable(GL_DEPTH_TEST);
4566	GLU_EXPECT_NO_ERROR(gl.getError(), "Enable");
4567}
4568
4569/** Constructor
4570 *
4571 * @param context          Test context
4572 * @param test_name        Test name
4573 * @param test_description Test description
4574 **/
4575ProvokingVertex::ProvokingVertex(deqp::Context& context, const glcts::ExtParameters& extParams)
4576	: DrawTestBase(context, extParams, "provoking_vertex", "Test verifies that provoking vertex work as expected")
4577{
4578	/* Nothing to be done here */
4579}
4580
4581/** Check if R32I texture is filled with 4x4 regions of increasing values <0:15>
4582 *
4583 * @param texture_0 Verified texture
4584 * @param ignored
4585 * @param ignored
4586 *
4587 * @return True if texture_0 is filled with expected pattern
4588 **/
4589bool ProvokingVertex::checkResults(Utils::texture& texture_0, Utils::texture& /* texture_1 */,
4590								   GLuint /*draw_call_index */)
4591{
4592	static const GLuint layer_size = m_width * m_height;
4593
4594	const glw::Functions&   gl			 = m_context.getRenderContext().getFunctions();
4595	const glu::ContextType& context_type = m_context.getRenderContext().getType();
4596
4597	GLint layer_mode	= 0;
4598	GLint viewport_mode = 0;
4599	gl.getIntegerv(GL_LAYER_PROVOKING_VERTEX, &layer_mode);
4600	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
4601	gl.getIntegerv(GL_VIEWPORT_INDEX_PROVOKING_VERTEX, &viewport_mode);
4602	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
4603
4604	if ((GL_UNDEFINED_VERTEX == layer_mode) || (GL_UNDEFINED_VERTEX == viewport_mode))
4605	{
4606		/* Results are undefined, therefore it does not make sense to verify them */
4607		return true;
4608	}
4609
4610	bool  check_result = true;
4611	GLint provoking	= 0;
4612
4613	std::vector<GLint> texture_data;
4614	texture_data.resize(layer_size * m_r32ix4_depth);
4615	texture_0.get(GL_RED_INTEGER, GL_INT, &texture_data[0]);
4616
4617	if (glu::isContextTypeGLCore(context_type))
4618	{
4619		gl.getIntegerv(GL_PROVOKING_VERTEX, &provoking);
4620		GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
4621	}
4622	else
4623	{
4624		DE_ASSERT(glu::isContextTypeES(context_type));
4625		/* ES doesn't have provoking vertex control, so it's always LAST */
4626		provoking = GL_LAST_VERTEX_CONVENTION;
4627	}
4628
4629	GLuint expected_layer	= 0;
4630	GLint  expected_viewport = 0;
4631
4632	/* Mode is 1st, or mode is provoking and provoking is 1st */
4633	if ((GL_FIRST_VERTEX_CONVENTION == layer_mode) ||
4634		((GL_PROVOKING_VERTEX == layer_mode) && (GL_FIRST_VERTEX_CONVENTION == provoking)))
4635	{
4636		expected_layer = 0;
4637	}
4638	else
4639	{
4640		expected_layer = 2;
4641	}
4642
4643	if ((GL_FIRST_VERTEX_CONVENTION == viewport_mode) ||
4644		((GL_PROVOKING_VERTEX == viewport_mode) && (GL_FIRST_VERTEX_CONVENTION == provoking)))
4645	{
4646		expected_viewport = 0;
4647	}
4648	else
4649	{
4650		expected_viewport = 2;
4651	}
4652
4653	for (GLuint layer = 0; layer < m_r32ix4_depth; ++layer)
4654	{
4655		GLint* layer_data = &texture_data[layer * layer_size];
4656		GLint  viewport   = 0;
4657
4658		for (GLuint y = 0; y < 2; ++y)
4659		{
4660			for (GLuint x = 0; x < 2; ++x)
4661			{
4662				/* If layer and viewport are expected ones, than result shall be 1, otherwise -1. */
4663				const GLint expected_value = ((expected_viewport == viewport) && (expected_layer == layer)) ? 1 : -1;
4664
4665				bool result = checkRegionR32I(x, y, m_width / 2, m_height / 2, expected_value, layer_data);
4666
4667				if (false == result)
4668				{
4669					check_result = false;
4670					goto end;
4671				}
4672
4673				viewport += 1;
4674			}
4675		}
4676	}
4677
4678end:
4679	return check_result;
4680}
4681
4682/** Get string with fragment shader source code
4683 *
4684 * @return Fragment shader source
4685 **/
4686std::string ProvokingVertex::getFragmentShader()
4687{
4688	static const GLchar* source = "${VERSION}\n"
4689								  "\n"
4690								  "flat in  int gs_fs_color;\n"
4691								  "     out int fs_out_color;\n"
4692								  "\n"
4693								  "void main()\n"
4694								  "{\n"
4695								  "    fs_out_color = gs_fs_color;\n"
4696								  "}\n"
4697								  "\n";
4698
4699	std::string result = source;
4700
4701	return result;
4702}
4703
4704/** Get string with geometry shader source code
4705 *
4706 * @return Geometry shader source
4707 **/
4708std::string ProvokingVertex::getGeometryShader()
4709{
4710	static const GLchar* source = "${VERSION}\n"
4711								  "\n"
4712								  "${GEOMETRY_SHADER_ENABLE}\n"
4713								  "${VIEWPORT_ARRAY_ENABLE}\n"
4714								  "\n"
4715								  "layout(points, invocations = 1)          in;\n"
4716								  "layout(triangle_strip, max_vertices = 6) out;\n"
4717								  "\n"
4718								  "flat out int gs_fs_color;\n"
4719								  "\n"
4720								  "void main()\n"
4721								  "{\n"
4722								  "    /* Left-bottom half */\n"
4723								  "    gs_fs_color      = 1;\n"
4724								  "    gl_ViewportIndex = 0;\n"
4725								  "    gl_Layer         = 0;\n"
4726								  "    gl_Position  = vec4(-1, -1, 0, 1);\n"
4727								  "    EmitVertex();\n"
4728								  "    gs_fs_color      = 1;\n"
4729								  "    gl_ViewportIndex = 1;\n"
4730								  "    gl_Layer         = 1;\n"
4731								  "    gl_Position  = vec4(-1, 1, 0, 1);\n"
4732								  "    EmitVertex();\n"
4733								  "    gs_fs_color      = 1;\n"
4734								  "    gl_ViewportIndex = 2;\n"
4735								  "    gl_Layer         = 2;\n"
4736								  "    gl_Position  = vec4(1, -1, 0, 1);\n"
4737								  "    EmitVertex();\n"
4738								  "    EndPrimitive();\n"
4739								  "\n"
4740								  "    /* Right-top half */\n"
4741								  "    gs_fs_color      = 1;\n"
4742								  "    gl_ViewportIndex = 0;\n"
4743								  "    gl_Layer         = 0;\n"
4744								  "    gl_Position  = vec4(-1, 1, 0, 1);\n"
4745								  "    EmitVertex();\n"
4746								  "    gs_fs_color      = 1;\n"
4747								  "    gl_ViewportIndex = 1;\n"
4748								  "    gl_Layer         = 1;\n"
4749								  "    gl_Position  = vec4(1, 1, 0, 1);\n"
4750								  "    EmitVertex();\n"
4751								  "    gs_fs_color      = 1;\n"
4752								  "    gl_ViewportIndex = 2;\n"
4753								  "    gl_Layer         = 2;\n"
4754								  "    gl_Position  = vec4(1, -1, 0, 1);\n"
4755								  "    EmitVertex();\n"
4756								  "    EndPrimitive();\n"
4757								  "}\n"
4758								  "\n";
4759
4760	std::string result = source;
4761
4762	return result;
4763}
4764
4765/** Get test type
4766 *
4767 * @return PROVOKING
4768 **/
4769DrawTestBase::TEST_TYPE ProvokingVertex::getTestType()
4770{
4771	return PROVOKING;
4772}
4773
4774/** Prepare textures used as framebuffer's attachments for current draw call
4775 *
4776 * @param texture_0 R32I texture
4777 * @param ignored
4778 **/
4779void ProvokingVertex::prepareTextures(Utils::texture& texture_0, Utils::texture& /* texture_1 */)
4780{
4781	prepareTextureR32Ix4(texture_0);
4782}
4783
4784} /* ViewportArray namespace */
4785
4786/** Constructor.
4787 *
4788 *  @param context Rendering context.
4789 **/
4790ViewportArrayTests::ViewportArrayTests(deqp::Context& context, const glcts::ExtParameters& extParams)
4791	: TestCaseGroupBase(context, extParams, "viewport_array", "Verifies \"viewport_array\" functionality")
4792{
4793	/* Left blank on purpose */
4794}
4795
4796/** Initializes a texture_storage_multisample test group.
4797 *
4798 **/
4799void ViewportArrayTests::init(void)
4800{
4801	addChild(new ViewportArray::APIErrors(m_context, m_extParams));
4802	addChild(new ViewportArray::Queries(m_context, m_extParams));
4803	addChild(new ViewportArray::ViewportAPI(m_context, m_extParams));
4804	addChild(new ViewportArray::ScissorAPI(m_context, m_extParams));
4805	addChild(new ViewportArray::DepthRangeAPI(m_context, m_extParams));
4806	addChild(new ViewportArray::ScissorTestStateAPI(m_context, m_extParams));
4807	addChild(new ViewportArray::DrawToSingleLayerWithMultipleViewports(m_context, m_extParams));
4808	addChild(new ViewportArray::DynamicViewportIndex(m_context, m_extParams));
4809	addChild(new ViewportArray::DrawMulitpleViewportsWithSingleInvocation(m_context, m_extParams));
4810	addChild(new ViewportArray::ViewportIndexSubroutine(m_context, m_extParams));
4811	addChild(new ViewportArray::DrawMultipleLayers(m_context, m_extParams));
4812	addChild(new ViewportArray::Scissor(m_context, m_extParams));
4813	addChild(new ViewportArray::ScissorZeroDimension(m_context, m_extParams));
4814	addChild(new ViewportArray::ScissorClear(m_context, m_extParams));
4815	addChild(new ViewportArray::DepthRange(m_context, m_extParams));
4816	addChild(new ViewportArray::DepthRangeDepthTest(m_context, m_extParams));
4817	addChild(new ViewportArray::ProvokingVertex(m_context, m_extParams));
4818}
4819
4820} /* glcts namespace */
4821