1/*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2015-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  gl4cMultiBindTests.cpp
26 * \brief Implements conformance tests for "Multi Bind" functionality.
27 */ /*-------------------------------------------------------------------*/
28
29#include "gl4cMultiBindTests.hpp"
30
31#include "gluDefs.hpp"
32#include "gluStrUtil.hpp"
33#include "glwEnums.hpp"
34#include "glwFunctions.hpp"
35#include "tcuTestLog.hpp"
36
37#include <string>
38
39#define DEBUG_ENBALE_MESSAGE_CALLBACK 0
40
41#if DEBUG_ENBALE_MESSAGE_CALLBACK
42#include <iomanip>
43#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
44
45using namespace glw;
46
47namespace gl4cts
48{
49namespace MultiBind
50{
51
52#if DEBUG_ENBALE_MESSAGE_CALLBACK
53/** Debuging procedure. Logs parameters.
54 *
55 * @param source   As specified in GL spec.
56 * @param type     As specified in GL spec.
57 * @param id       As specified in GL spec.
58 * @param severity As specified in GL spec.
59 * @param ignored
60 * @param message  As specified in GL spec.
61 * @param info     Pointer to instance of deqp::Context used by test.
62 */
63void GLW_APIENTRY debug_proc(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei /* length */,
64							 const GLchar* message, void* info)
65{
66	deqp::Context* ctx = (deqp::Context*)info;
67
68	const GLchar* source_str   = "Unknown";
69	const GLchar* type_str	 = "Unknown";
70	const GLchar* severity_str = "Unknown";
71
72	switch (source)
73	{
74	case GL_DEBUG_SOURCE_API:
75		source_str = "API";
76		break;
77	case GL_DEBUG_SOURCE_APPLICATION:
78		source_str = "APP";
79		break;
80	case GL_DEBUG_SOURCE_OTHER:
81		source_str = "OTR";
82		break;
83	case GL_DEBUG_SOURCE_SHADER_COMPILER:
84		source_str = "COM";
85		break;
86	case GL_DEBUG_SOURCE_THIRD_PARTY:
87		source_str = "3RD";
88		break;
89	case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
90		source_str = "WS";
91		break;
92	default:
93		break;
94	}
95
96	switch (type)
97	{
98	case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
99		type_str = "DEPRECATED_BEHAVIOR";
100		break;
101	case GL_DEBUG_TYPE_ERROR:
102		type_str = "ERROR";
103		break;
104	case GL_DEBUG_TYPE_MARKER:
105		type_str = "MARKER";
106		break;
107	case GL_DEBUG_TYPE_OTHER:
108		type_str = "OTHER";
109		break;
110	case GL_DEBUG_TYPE_PERFORMANCE:
111		type_str = "PERFORMANCE";
112		break;
113	case GL_DEBUG_TYPE_POP_GROUP:
114		type_str = "POP_GROUP";
115		break;
116	case GL_DEBUG_TYPE_PORTABILITY:
117		type_str = "PORTABILITY";
118		break;
119	case GL_DEBUG_TYPE_PUSH_GROUP:
120		type_str = "PUSH_GROUP";
121		break;
122	case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
123		type_str = "UNDEFINED_BEHAVIOR";
124		break;
125	default:
126		break;
127	}
128
129	switch (severity)
130	{
131	case GL_DEBUG_SEVERITY_HIGH:
132		severity_str = "H";
133		break;
134	case GL_DEBUG_SEVERITY_LOW:
135		severity_str = "L";
136		break;
137	case GL_DEBUG_SEVERITY_MEDIUM:
138		severity_str = "M";
139		break;
140	case GL_DEBUG_SEVERITY_NOTIFICATION:
141		severity_str = "N";
142		break;
143	default:
144		break;
145	}
146
147	ctx->getTestContext().getLog() << tcu::TestLog::Message << "DEBUG_INFO: " << std::setw(3) << source_str << "|"
148								   << severity_str << "|" << std::setw(18) << type_str << "|" << std::setw(12) << id
149								   << ": " << message << tcu::TestLog::EndMessage;
150}
151
152#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
153
154/** Represents buffer instance
155 * Provides basic buffer functionality
156 **/
157class Buffer
158{
159public:
160	/* Public methods */
161	/* Ctr & Dtr */
162	Buffer();
163	~Buffer();
164
165	/* Init & Release */
166	void Init(deqp::Context& context);
167
168	void InitData(deqp::Context& context, glw::GLenum target, glw::GLenum usage, glw::GLsizeiptr size,
169				  const glw::GLvoid* data);
170
171	void Release();
172
173	/* Functionality */
174	void Bind() const;
175	void BindBase(glw::GLuint index) const;
176
177	/* Public static routines */
178	/* Functionality */
179	static void Bind(const glw::Functions& gl, glw::GLuint id, glw::GLenum target);
180
181	static void BindBase(const glw::Functions& gl, glw::GLuint id, glw::GLenum target, glw::GLuint index);
182
183	static void Data(const glw::Functions& gl, glw::GLenum target, glw::GLenum usage, glw::GLsizeiptr size,
184					 const glw::GLvoid* data);
185
186	static void Generate(const glw::Functions& gl, glw::GLuint& out_id);
187
188	static void SubData(const glw::Functions& gl, glw::GLenum target, glw::GLintptr offset, glw::GLsizeiptr size,
189						glw::GLvoid* data);
190
191	/* Public fields */
192	glw::GLuint m_id;
193
194	/* Public constants */
195	static const glw::GLuint m_invalid_id;
196
197private:
198	/* Private enums */
199
200	/* Private fields */
201	deqp::Context* m_context;
202	glw::GLenum	m_target;
203};
204
205/** Represents framebuffer
206 * Provides basic functionality
207 **/
208class Framebuffer
209{
210public:
211	/* Public methods */
212	/* Ctr & Dtr */
213	Framebuffer(deqp::Context& context);
214	~Framebuffer();
215
216	/* Init & Release */
217	void Release();
218
219	/* Public static routines */
220	static void AttachTexture(const glw::Functions& gl, glw::GLenum target, glw::GLenum attachment,
221							  glw::GLuint texture_id, glw::GLint level, glw::GLuint width, glw::GLuint height);
222
223	static void Bind(const glw::Functions& gl, glw::GLenum target, glw::GLuint id);
224
225	static void Generate(const glw::Functions& gl, glw::GLuint& out_id);
226
227	/* Public fields */
228	glw::GLuint m_id;
229
230	/* Public constants */
231	static const glw::GLuint m_invalid_id;
232
233private:
234	/* Private fields */
235	deqp::Context& m_context;
236};
237
238/** Represents shader instance.
239 * Provides basic functionality for shaders.
240 **/
241class Shader
242{
243public:
244	/* Public methods */
245	/* Ctr & Dtr */
246	Shader(deqp::Context& context);
247	~Shader();
248
249	/* Init & Realese */
250	void Init(glw::GLenum stage, const std::string& source);
251	void Release();
252
253	/* Public static routines */
254	/* Functionality */
255	static void Compile(const glw::Functions& gl, glw::GLuint id);
256
257	static void Create(const glw::Functions& gl, glw::GLenum stage, glw::GLuint& out_id);
258
259	static void Source(const glw::Functions& gl, glw::GLuint id, const std::string& source);
260
261	/* Public fields */
262	glw::GLuint m_id;
263
264	/* Public constants */
265	static const glw::GLuint m_invalid_id;
266
267private:
268	/* Private fields */
269	deqp::Context& m_context;
270};
271
272/** Represents program instance.
273 * Provides basic functionality
274 **/
275class Program
276{
277public:
278	/* Public methods */
279	/* Ctr & Dtr */
280	Program(deqp::Context& context);
281	~Program();
282
283	/* Init & Release */
284	void Init(const std::string& compute_shader, const std::string& fragment_shader, const std::string& geometry_shader,
285			  const std::string& tesselation_control_shader, const std::string& tesselation_evaluation_shader,
286			  const std::string& vertex_shader);
287	void Release();
288
289	/* Functionality */
290	void Use() const;
291
292	/* Public static routines */
293	/* Functionality */
294	static void Attach(const glw::Functions& gl, glw::GLuint program_id, glw::GLuint shader_id);
295
296	static void Create(const glw::Functions& gl, glw::GLuint& out_id);
297
298	static void Link(const glw::Functions& gl, glw::GLuint id);
299
300	static void Use(const glw::Functions& gl, glw::GLuint id);
301
302	/* Public fields */
303	glw::GLuint m_id;
304
305	Shader m_compute;
306	Shader m_fragment;
307	Shader m_geometry;
308	Shader m_tess_ctrl;
309	Shader m_tess_eval;
310	Shader m_vertex;
311
312	/* Public constants */
313	static const glw::GLuint m_invalid_id;
314
315private:
316	/* Private fields */
317	deqp::Context& m_context;
318};
319
320/** Represents texture instance
321 **/
322class Texture
323{
324public:
325	/* Public methods */
326	/* Ctr & Dtr */
327	Texture();
328	~Texture();
329
330	/* Init & Release */
331	void Init(deqp::Context& context);
332
333	void InitBuffer(deqp::Context& context, glw::GLenum internal_format, glw::GLuint buffer_id);
334
335	void InitStorage(deqp::Context& context, glw::GLenum target, glw::GLsizei levels, glw::GLenum internal_format,
336					 glw::GLuint width, glw::GLuint height, glw::GLuint depth, bool allow_error = false);
337
338	void Release();
339
340	/* Public static routines */
341	/* Functionality */
342	static void Bind(const glw::Functions& gl, glw::GLuint id, glw::GLenum target);
343
344	static void CompressedImage(const glw::Functions& gl, glw::GLenum target, glw::GLint level,
345								glw::GLenum internal_format, glw::GLuint width, glw::GLuint height, glw::GLuint depth,
346								glw::GLsizei image_size, const glw::GLvoid* data);
347
348	static void Generate(const glw::Functions& gl, glw::GLuint& out_id);
349
350	static void GetData(const glw::Functions& gl, glw::GLint level, glw::GLenum target, glw::GLenum format,
351						glw::GLenum type, glw::GLvoid* out_data);
352
353	static void GetLevelParameter(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLenum pname,
354								  glw::GLint* param);
355
356	static void Image(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLenum internal_format,
357					  glw::GLuint width, glw::GLuint height, glw::GLuint depth, glw::GLenum format, glw::GLenum type,
358					  const glw::GLvoid* data);
359
360	static void Storage(const glw::Functions& gl, glw::GLenum target, glw::GLsizei levels, glw::GLenum internal_format,
361						glw::GLuint width, glw::GLuint height, glw::GLuint depth, bool allow_error);
362
363	static void SubImage(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLint x, glw::GLint y,
364						 glw::GLint z, glw::GLsizei width, glw::GLsizei height, glw::GLsizei depth, glw::GLenum format,
365						 glw::GLenum type, const glw::GLvoid* pixels);
366
367	/* Public fields */
368	glw::GLuint m_id;
369
370	/* Public constants */
371	static const glw::GLuint m_invalid_id;
372
373private:
374	/* Private fields */
375	deqp::Context* m_context;
376};
377
378/* Buffer constants */
379const GLuint Buffer::m_invalid_id = -1;
380
381/** Constructor.
382 *
383 **/
384Buffer::Buffer() : m_id(m_invalid_id), m_context(0), m_target(GL_ARRAY_BUFFER)
385{
386}
387
388/** Destructor
389 *
390 **/
391Buffer::~Buffer()
392{
393	Release();
394
395	m_context = 0;
396}
397
398/** Initialize buffer instance
399 *
400 * @param context CTS context.
401 **/
402void Buffer::Init(deqp::Context& context)
403{
404	Release();
405
406	m_context = &context;
407}
408
409/** Initialize buffer instance with some data
410 *
411 * @param context CTS context.
412 * @param target Buffer target
413 * @param usage  Buffer usage enum
414 * @param size   <size> parameter
415 * @param data   <data> parameter
416 **/
417void Buffer::InitData(deqp::Context& context, glw::GLenum target, glw::GLenum usage, glw::GLsizeiptr size,
418					  const glw::GLvoid* data)
419{
420	Init(context);
421
422	m_target = target;
423
424	const Functions& gl = m_context->getRenderContext().getFunctions();
425
426	Generate(gl, m_id);
427	Bind(gl, m_id, m_target);
428	Data(gl, m_target, usage, size, data);
429}
430
431/** Release buffer instance
432 *
433 **/
434void Buffer::Release()
435{
436	if (m_invalid_id != m_id)
437	{
438		const Functions& gl = m_context->getRenderContext().getFunctions();
439
440		gl.deleteBuffers(1, &m_id);
441		m_id = m_invalid_id;
442	}
443}
444
445/** Binds buffer to its target
446 *
447 **/
448void Buffer::Bind() const
449{
450	if (m_invalid_id == m_id)
451	{
452		return;
453	}
454
455	const Functions& gl = m_context->getRenderContext().getFunctions();
456
457	Bind(gl, m_id, m_target);
458}
459
460/** Binds indexed buffer
461 *
462 * @param index <index> parameter
463 **/
464void Buffer::BindBase(glw::GLuint index) const
465{
466	if (m_invalid_id == m_id)
467	{
468		return;
469	}
470
471	const Functions& gl = m_context->getRenderContext().getFunctions();
472
473	BindBase(gl, m_id, m_target, index);
474}
475
476/** Bind buffer to given target
477 *
478 * @param gl     GL functions
479 * @param id     Id of buffer
480 * @param target Buffer target
481 **/
482void Buffer::Bind(const glw::Functions& gl, glw::GLuint id, glw::GLenum target)
483{
484	gl.bindBuffer(target, id);
485	GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer");
486}
487
488/** Binds indexed buffer
489 *
490 * @param gl     GL functions
491 * @param id     Id of buffer
492 * @param target Buffer target
493 * @param index  <index> parameter
494 **/
495void Buffer::BindBase(const glw::Functions& gl, glw::GLuint id, glw::GLenum target, glw::GLuint index)
496{
497	gl.bindBufferBase(target, index, id);
498	GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferBase");
499}
500
501/** Allocate memory for buffer and sends initial content
502 *
503 * @param gl     GL functions
504 * @param target Buffer target
505 * @param usage  Buffer usage enum
506 * @param size   <size> parameter
507 * @param data   <data> parameter
508 **/
509void Buffer::Data(const glw::Functions& gl, glw::GLenum target, glw::GLenum usage, glw::GLsizeiptr size,
510				  const glw::GLvoid* data)
511{
512	gl.bufferData(target, size, data, usage);
513	GLU_EXPECT_NO_ERROR(gl.getError(), "BufferData");
514}
515
516/** Generate buffer
517 *
518 * @param gl     GL functions
519 * @param out_id Id of buffer
520 **/
521void Buffer::Generate(const glw::Functions& gl, glw::GLuint& out_id)
522{
523	GLuint id = m_invalid_id;
524
525	gl.genBuffers(1, &id);
526	GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers");
527
528	if (m_invalid_id == id)
529	{
530		TCU_FAIL("Got invalid id");
531	}
532
533	out_id = id;
534}
535
536/** Update range of buffer
537 *
538 * @param gl     GL functions
539 * @param target Buffer target
540 * @param offset Offset in buffer
541 * @param size   <size> parameter
542 * @param data   <data> parameter
543 **/
544void Buffer::SubData(const glw::Functions& gl, glw::GLenum target, glw::GLintptr offset, glw::GLsizeiptr size,
545					 glw::GLvoid* data)
546{
547	gl.bufferSubData(target, offset, size, data);
548	GLU_EXPECT_NO_ERROR(gl.getError(), "BufferSubData");
549}
550
551/* Framebuffer constants */
552const GLuint Framebuffer::m_invalid_id = -1;
553
554/** Constructor.
555 *
556 * @param context CTS context.
557 **/
558Framebuffer::Framebuffer(deqp::Context& context) : m_id(m_invalid_id), m_context(context)
559{
560	/* Nothing to done here */
561}
562
563/** Destructor
564 *
565 **/
566Framebuffer::~Framebuffer()
567{
568	Release();
569}
570
571/** Release texture instance
572 *
573 **/
574void Framebuffer::Release()
575{
576	if (m_invalid_id != m_id)
577	{
578		const Functions& gl = m_context.getRenderContext().getFunctions();
579
580		gl.deleteFramebuffers(1, &m_id);
581		m_id = m_invalid_id;
582	}
583}
584
585/** Attach texture to specified attachment
586 *
587 * @param gl         GL functions
588 * @param target     Framebuffer target
589 * @param attachment Attachment
590 * @param texture_id Texture id
591 * @param level      Level of mipmap
592 * @param width      Texture width
593 * @param height     Texture height
594 **/
595void Framebuffer::AttachTexture(const glw::Functions& gl, glw::GLenum target, glw::GLenum attachment,
596								glw::GLuint texture_id, glw::GLint level, glw::GLuint width, glw::GLuint height)
597{
598	gl.framebufferTexture(target, attachment, texture_id, level);
599	GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture");
600
601	gl.viewport(0 /* x */, 0 /* y */, width, height);
602	GLU_EXPECT_NO_ERROR(gl.getError(), "Viewport");
603}
604
605/** Binds framebuffer to DRAW_FRAMEBUFFER
606 *
607 * @param gl     GL functions
608 * @param target Framebuffer target
609 * @param id     ID of framebuffer
610 **/
611void Framebuffer::Bind(const glw::Functions& gl, glw::GLenum target, glw::GLuint id)
612{
613	gl.bindFramebuffer(target, id);
614	GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
615}
616
617/** Generate framebuffer
618 *
619 **/
620void Framebuffer::Generate(const glw::Functions& gl, glw::GLuint& out_id)
621{
622	GLuint id = m_invalid_id;
623
624	gl.genFramebuffers(1, &id);
625	GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers");
626
627	if (m_invalid_id == id)
628	{
629		TCU_FAIL("Invalid id");
630	}
631
632	out_id = id;
633}
634
635/* Program constants */
636const GLuint Program::m_invalid_id = 0;
637
638/** Constructor.
639 *
640 * @param context CTS context.
641 **/
642Program::Program(deqp::Context& context)
643	: m_id(m_invalid_id)
644	, m_compute(context)
645	, m_fragment(context)
646	, m_geometry(context)
647	, m_tess_ctrl(context)
648	, m_tess_eval(context)
649	, m_vertex(context)
650	, m_context(context)
651{
652	/* Nothing to be done here */
653}
654
655/** Destructor
656 *
657 **/
658Program::~Program()
659{
660	Release();
661}
662
663/** Initialize program instance
664 *
665 * @param compute_shader                Compute shader source code
666 * @param fragment_shader               Fragment shader source code
667 * @param geometry_shader               Geometry shader source code
668 * @param tesselation_control_shader    Tesselation control shader source code
669 * @param tesselation_evaluation_shader Tesselation evaluation shader source code
670 * @param vertex_shader                 Vertex shader source code
671 **/
672void Program::Init(const std::string& compute_shader, const std::string& fragment_shader,
673				   const std::string& geometry_shader, const std::string& tesselation_control_shader,
674				   const std::string& tesselation_evaluation_shader, const std::string& vertex_shader)
675{
676	/* Delete previous program */
677	Release();
678
679	/* GL entry points */
680	const Functions& gl = m_context.getRenderContext().getFunctions();
681
682	/* Initialize shaders */
683	m_compute.Init(GL_COMPUTE_SHADER, compute_shader);
684	m_fragment.Init(GL_FRAGMENT_SHADER, fragment_shader);
685	m_geometry.Init(GL_GEOMETRY_SHADER, geometry_shader);
686	m_tess_ctrl.Init(GL_TESS_CONTROL_SHADER, tesselation_control_shader);
687	m_tess_eval.Init(GL_TESS_EVALUATION_SHADER, tesselation_evaluation_shader);
688	m_vertex.Init(GL_VERTEX_SHADER, vertex_shader);
689
690	/* Create program, set up transform feedback and attach shaders */
691	Create(gl, m_id);
692	Attach(gl, m_id, m_compute.m_id);
693	Attach(gl, m_id, m_fragment.m_id);
694	Attach(gl, m_id, m_geometry.m_id);
695	Attach(gl, m_id, m_tess_ctrl.m_id);
696	Attach(gl, m_id, m_tess_eval.m_id);
697	Attach(gl, m_id, m_vertex.m_id);
698
699	/* Link program */
700	Link(gl, m_id);
701}
702
703/** Release program instance
704 *
705 **/
706void Program::Release()
707{
708	const Functions& gl = m_context.getRenderContext().getFunctions();
709
710	if (m_invalid_id != m_id)
711	{
712		Use(gl, m_invalid_id);
713
714		gl.deleteProgram(m_id);
715		m_id = m_invalid_id;
716	}
717
718	m_compute.Release();
719	m_fragment.Release();
720	m_geometry.Release();
721	m_tess_ctrl.Release();
722	m_tess_eval.Release();
723	m_vertex.Release();
724}
725
726/** Set program as active
727 *
728 **/
729void Program::Use() const
730{
731	const Functions& gl = m_context.getRenderContext().getFunctions();
732
733	Use(gl, m_id);
734}
735
736/** Attach shader to program
737 *
738 * @param gl         GL functions
739 * @param program_id Id of program
740 * @param shader_id  Id of shader
741 **/
742void Program::Attach(const glw::Functions& gl, glw::GLuint program_id, glw::GLuint shader_id)
743{
744	/* Quick checks */
745	if ((m_invalid_id == program_id) || (Shader::m_invalid_id == shader_id))
746	{
747		return;
748	}
749
750	gl.attachShader(program_id, shader_id);
751	GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
752}
753
754/** Create program instance
755 *
756 * @param gl     GL functions
757 * @param out_id Id of program
758 **/
759void Program::Create(const glw::Functions& gl, glw::GLuint& out_id)
760{
761	const GLuint id = gl.createProgram();
762	GLU_EXPECT_NO_ERROR(gl.getError(), "CreateProgram");
763
764	if (m_invalid_id == id)
765	{
766		TCU_FAIL("Failed to create program");
767	}
768
769	out_id = id;
770}
771
772/** Link program
773 *
774 * @param gl GL functions
775 * @param id Id of program
776 **/
777void Program::Link(const glw::Functions& gl, glw::GLuint id)
778{
779	GLint status = GL_FALSE;
780
781	gl.linkProgram(id);
782	GLU_EXPECT_NO_ERROR(gl.getError(), "LinkProgram");
783
784	/* Get link status */
785	gl.getProgramiv(id, GL_LINK_STATUS, &status);
786	GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
787
788	/* Log link error */
789	if (GL_TRUE != status)
790	{
791		glw::GLint  length = 0;
792		std::string message;
793
794		/* Get error log length */
795		gl.getProgramiv(id, GL_INFO_LOG_LENGTH, &length);
796		GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
797
798		message.resize(length, 0);
799
800		/* Get error log */
801		gl.getProgramInfoLog(id, length, 0, &message[0]);
802		GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramInfoLog");
803
804		TCU_FAIL(message.c_str());
805	}
806}
807
808/** Use program
809 *
810 * @param gl GL functions
811 * @param id Id of program
812 **/
813void Program::Use(const glw::Functions& gl, glw::GLuint id)
814{
815	gl.useProgram(id);
816	GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
817}
818
819/* Shader's constants */
820const GLuint Shader::m_invalid_id = 0;
821
822/** Constructor.
823 *
824 * @param context CTS context.
825 **/
826Shader::Shader(deqp::Context& context) : m_id(m_invalid_id), m_context(context)
827{
828	/* Nothing to be done here */
829}
830
831/** Destructor
832 *
833 **/
834Shader::~Shader()
835{
836	Release();
837}
838
839/** Initialize shader instance
840 *
841 * @param stage  Shader stage
842 * @param source Source code
843 **/
844void Shader::Init(glw::GLenum stage, const std::string& source)
845{
846	if (true == source.empty())
847	{
848		/* No source == no shader */
849		return;
850	}
851
852	/* Delete any previous shader */
853	Release();
854
855	/* Create, set source and compile */
856	const Functions& gl = m_context.getRenderContext().getFunctions();
857
858	Create(gl, stage, m_id);
859	Source(gl, m_id, source);
860
861	Compile(gl, m_id);
862}
863
864/** Release shader instance
865 *
866 **/
867void Shader::Release()
868{
869	if (m_invalid_id != m_id)
870	{
871		const Functions& gl = m_context.getRenderContext().getFunctions();
872
873		gl.deleteShader(m_id);
874		m_id = m_invalid_id;
875	}
876}
877
878/** Compile shader
879 *
880 * @param gl GL functions
881 * @param id Shader id
882 **/
883void Shader::Compile(const glw::Functions& gl, glw::GLuint id)
884{
885	GLint status = GL_FALSE;
886
887	/* Compile */
888	gl.compileShader(id);
889	GLU_EXPECT_NO_ERROR(gl.getError(), "CompileShader");
890
891	/* Get compilation status */
892	gl.getShaderiv(id, GL_COMPILE_STATUS, &status);
893	GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
894
895	/* Log compilation error */
896	if (GL_TRUE != status)
897	{
898		glw::GLint  length = 0;
899		std::string message;
900
901		/* Error log length */
902		gl.getShaderiv(id, GL_INFO_LOG_LENGTH, &length);
903		GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
904
905		/* Prepare storage */
906		message.resize(length, 0);
907
908		/* Get error log */
909		gl.getShaderInfoLog(id, length, 0, &message[0]);
910		GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderInfoLog");
911
912		TCU_FAIL(message.c_str());
913	}
914}
915
916/** Create shader
917 *
918 * @param gl     GL functions
919 * @param stage  Shader stage
920 * @param out_id Shader id
921 **/
922void Shader::Create(const glw::Functions& gl, glw::GLenum stage, glw::GLuint& out_id)
923{
924	const GLuint id = gl.createShader(stage);
925	GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
926
927	if (m_invalid_id == id)
928	{
929		TCU_FAIL("Failed to create shader");
930	}
931
932	out_id = id;
933}
934
935/** Set shader's source code
936 *
937 * @param gl     GL functions
938 * @param id     Shader id
939 * @param source Shader source code
940 **/
941void Shader::Source(const glw::Functions& gl, glw::GLuint id, const std::string& source)
942{
943	const GLchar* code = source.c_str();
944
945	gl.shaderSource(id, 1 /* count */, &code, 0 /* lengths */);
946	GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderSource");
947}
948
949/* Texture static fields */
950const GLuint Texture::m_invalid_id = -1;
951
952/** Constructor.
953 *
954 **/
955Texture::Texture() : m_id(m_invalid_id), m_context(0)
956{
957	/* Nothing to done here */
958}
959
960/** Destructor
961 *
962 **/
963Texture::~Texture()
964{
965	Release();
966}
967
968/** Initialize texture instance
969 *
970 * @param context Test context
971 **/
972void Texture::Init(deqp::Context& context)
973{
974	Release();
975
976	m_context = &context;
977}
978
979/** Initialize texture instance as texture buffer
980 *
981 * @param context         Test context
982 * @param internal_format Internal format of texture
983 * @param buufer_id       ID of buffer that will be used as storage
984 **/
985void Texture::InitBuffer(deqp::Context& context, glw::GLenum internal_format, glw::GLuint buffer_id)
986{
987	Init(context);
988
989	const Functions& gl = m_context->getRenderContext().getFunctions();
990
991	Generate(gl, m_id);
992	Bind(gl, m_id, GL_TEXTURE_BUFFER);
993	Buffer::Bind(gl, buffer_id, GL_TEXTURE_BUFFER);
994
995	gl.texBuffer(GL_TEXTURE_BUFFER, internal_format, buffer_id);
996	GLU_EXPECT_NO_ERROR(gl.getError(), "TexBuffer");
997}
998
999/** Initialize texture instance with storage
1000 *
1001 * @param context         Test context
1002 * @param target          Texture target
1003 * @param levels          Number of levels
1004 * @param internal_format Internal format of texture
1005 * @param width           Width of texture
1006 * @param height          Height of texture
1007 * @param depth           Depth of texture
1008 **/
1009void Texture::InitStorage(deqp::Context& context, glw::GLenum target, glw::GLsizei levels, glw::GLenum internal_format,
1010						  glw::GLuint width, glw::GLuint height, glw::GLuint depth, bool allow_error)
1011{
1012	Init(context);
1013
1014	const Functions& gl = m_context->getRenderContext().getFunctions();
1015
1016	Generate(gl, m_id);
1017	Bind(gl, m_id, target);
1018	Storage(gl, target, levels, internal_format, width, height, depth, allow_error);
1019}
1020
1021/** Release texture instance
1022 *
1023 * @param context CTS context.
1024 **/
1025void Texture::Release()
1026{
1027	if (m_invalid_id != m_id)
1028	{
1029		const Functions& gl = m_context->getRenderContext().getFunctions();
1030
1031		gl.deleteTextures(1, &m_id);
1032		m_id = m_invalid_id;
1033	}
1034}
1035
1036/** Bind texture to target
1037 *
1038 * @param gl       GL functions
1039 * @param id       Id of texture
1040 * @param tex_type Type of texture
1041 **/
1042void Texture::Bind(const glw::Functions& gl, glw::GLuint id, glw::GLenum target)
1043{
1044	gl.bindTexture(target, id);
1045	GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
1046}
1047
1048/** Set contents of compressed texture
1049 *
1050 * @param gl              GL functions
1051 * @param target          Texture target
1052 * @param level           Mipmap level
1053 * @param internal_format Format of data
1054 * @param width           Width of texture
1055 * @param height          Height of texture
1056 * @param depth           Depth of texture
1057 * @param image_size      Size of data
1058 * @param data            Buffer with image data
1059 **/
1060void Texture::CompressedImage(const glw::Functions& gl, glw::GLenum target, glw::GLint level,
1061							  glw::GLenum internal_format, glw::GLuint width, glw::GLuint height, glw::GLuint depth,
1062							  glw::GLsizei image_size, const glw::GLvoid* data)
1063{
1064	switch (target)
1065	{
1066	case GL_TEXTURE_1D:
1067		gl.compressedTexImage1D(target, level, internal_format, width, 0 /* border */, image_size, data);
1068		GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage1D");
1069		break;
1070	case GL_TEXTURE_1D_ARRAY:
1071	case GL_TEXTURE_2D:
1072	case GL_TEXTURE_RECTANGLE:
1073		gl.compressedTexImage2D(target, level, internal_format, width, height, 0 /* border */, image_size, data);
1074		GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage2D");
1075		break;
1076	case GL_TEXTURE_CUBE_MAP:
1077		gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, internal_format, width, height, 0 /* border */,
1078								image_size, data);
1079		gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, internal_format, width, height, 0 /* border */,
1080								image_size, data);
1081		gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, internal_format, width, height, 0 /* border */,
1082								image_size, data);
1083		gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, internal_format, width, height, 0 /* border */,
1084								image_size, data);
1085		gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, internal_format, width, height, 0 /* border */,
1086								image_size, data);
1087		gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, internal_format, width, height, 0 /* border */,
1088								image_size, data);
1089		GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage2D");
1090		break;
1091	case GL_TEXTURE_3D:
1092	case GL_TEXTURE_2D_ARRAY:
1093		gl.compressedTexImage3D(target, level, internal_format, width, height, depth, 0 /* border */, image_size, data);
1094		GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage3D");
1095		break;
1096	default:
1097		TCU_FAIL("Invliad enum");
1098	}
1099}
1100
1101/** Generate texture instance
1102 *
1103 * @param gl     GL functions
1104 * @param out_id Id of texture
1105 **/
1106void Texture::Generate(const glw::Functions& gl, glw::GLuint& out_id)
1107{
1108	GLuint id = m_invalid_id;
1109
1110	gl.genTextures(1, &id);
1111	GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures");
1112
1113	if (m_invalid_id == id)
1114	{
1115		TCU_FAIL("Invalid id");
1116	}
1117
1118	out_id = id;
1119}
1120
1121/** Get texture data
1122 *
1123 * @param gl       GL functions
1124 * @param target   Texture target
1125 * @param format   Format of data
1126 * @param type     Type of data
1127 * @param out_data Buffer for data
1128 **/
1129void Texture::GetData(const glw::Functions& gl, glw::GLint level, glw::GLenum target, glw::GLenum format,
1130					  glw::GLenum type, glw::GLvoid* out_data)
1131{
1132	gl.getTexImage(target, level, format, type, out_data);
1133	GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexImage");
1134}
1135
1136/** Generate texture instance
1137 *
1138 * @param gl     GL functions
1139 * @param target Texture target
1140 * @param level  Mipmap level
1141 * @param pname  Parameter to query
1142 * @param param  Result of query
1143 **/
1144void Texture::GetLevelParameter(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLenum pname,
1145								glw::GLint* param)
1146{
1147	gl.getTexLevelParameteriv(target, level, pname, param);
1148	GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexLevelParameteriv");
1149}
1150
1151/** Set contents of texture
1152 *
1153 * @param gl              GL functions
1154 * @param target          Texture target
1155 * @param level           Mipmap level
1156 * @param internal_format Format of data
1157 * @param width           Width of texture
1158 * @param height          Height of texture
1159 * @param depth           Depth of texture
1160 * @param format          Format of data
1161 * @param type            Type of data
1162 * @param data            Buffer with image data
1163 **/
1164void Texture::Image(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLenum internal_format,
1165					glw::GLuint width, glw::GLuint height, glw::GLuint depth, glw::GLenum format, glw::GLenum type,
1166					const glw::GLvoid* data)
1167{
1168	switch (target)
1169	{
1170	case GL_TEXTURE_1D:
1171		gl.texImage1D(target, level, internal_format, width, 0 /* border */, format, type, data);
1172		GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage1D");
1173		break;
1174	case GL_TEXTURE_1D_ARRAY:
1175	case GL_TEXTURE_2D:
1176	case GL_TEXTURE_RECTANGLE:
1177		gl.texImage2D(target, level, internal_format, width, height, 0 /* border */, format, type, data);
1178		GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage2D");
1179		break;
1180	case GL_TEXTURE_CUBE_MAP:
1181		gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, internal_format, width, height, 0 /* border */, format,
1182					  type, data);
1183		gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, internal_format, width, height, 0 /* border */, format,
1184					  type, data);
1185		gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, internal_format, width, height, 0 /* border */, format,
1186					  type, data);
1187		gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, internal_format, width, height, 0 /* border */, format,
1188					  type, data);
1189		gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, internal_format, width, height, 0 /* border */, format,
1190					  type, data);
1191		gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, internal_format, width, height, 0 /* border */, format,
1192					  type, data);
1193		GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage2D");
1194		break;
1195	case GL_TEXTURE_3D:
1196	case GL_TEXTURE_2D_ARRAY:
1197		gl.texImage3D(target, level, internal_format, width, height, depth, 0 /* border */, format, type, data);
1198		GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage3D");
1199		break;
1200	default:
1201		TCU_FAIL("Invliad enum");
1202	}
1203}
1204
1205/** Allocate storage for texture
1206 *
1207 * @param gl              GL functions
1208 * @param target          Texture target
1209 * @param levels          Number of levels
1210 * @param internal_format Internal format of texture
1211 * @param width           Width of texture
1212 * @param height          Height of texture
1213 * @param depth           Depth of texture
1214 **/
1215void Texture::Storage(const glw::Functions& gl, glw::GLenum target, glw::GLsizei levels, glw::GLenum internal_format,
1216					  glw::GLuint width, glw::GLuint height, glw::GLuint depth, bool allow_error)
1217{
1218	switch (target)
1219	{
1220	case GL_TEXTURE_1D:
1221		gl.texStorage1D(target, levels, internal_format, width);
1222		if (!allow_error)
1223		{
1224			GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage1D");
1225		}
1226		break;
1227	case GL_TEXTURE_1D_ARRAY:
1228	case GL_TEXTURE_2D:
1229	case GL_TEXTURE_RECTANGLE:
1230	case GL_TEXTURE_CUBE_MAP:
1231		gl.texStorage2D(target, levels, internal_format, width, height);
1232		if (!allow_error)
1233		{
1234			GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D");
1235		}
1236		break;
1237	case GL_TEXTURE_2D_MULTISAMPLE:
1238		gl.texStorage2DMultisample(target, levels, internal_format, width, height, GL_FALSE);
1239		if (!allow_error)
1240		{
1241			GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2DMultisample");
1242		}
1243		break;
1244	case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
1245		gl.texStorage3DMultisample(target, levels, internal_format, width, height, depth, GL_FALSE);
1246		if (!allow_error)
1247		{
1248			GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage3DMultisample");
1249		}
1250		break;
1251	case GL_TEXTURE_3D:
1252	case GL_TEXTURE_2D_ARRAY:
1253	case GL_TEXTURE_CUBE_MAP_ARRAY:
1254		gl.texStorage3D(target, levels, internal_format, width, height, depth);
1255		if (!allow_error)
1256		{
1257			GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage3D");
1258		}
1259		break;
1260	default:
1261		TCU_FAIL("Invliad enum");
1262	}
1263}
1264
1265/** Set contents of texture
1266 *
1267 * @param gl              GL functions
1268 * @param target          Texture target
1269 * @param level           Mipmap level
1270 * @param x               X offset
1271 * @param y               Y offset
1272 * @param z               Z offset
1273 * @param width           Width of texture
1274 * @param height          Height of texture
1275 * @param depth           Depth of texture
1276 * @param format          Format of data
1277 * @param type            Type of data
1278 * @param pixels          Buffer with image data
1279 **/
1280void Texture::SubImage(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLint x, glw::GLint y,
1281					   glw::GLint z, glw::GLsizei width, glw::GLsizei height, glw::GLsizei depth, glw::GLenum format,
1282					   glw::GLenum type, const glw::GLvoid* pixels)
1283{
1284	switch (target)
1285	{
1286	case GL_TEXTURE_1D:
1287		gl.texSubImage1D(target, level, x, width, format, type, pixels);
1288		GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage1D");
1289		break;
1290	case GL_TEXTURE_1D_ARRAY:
1291	case GL_TEXTURE_2D:
1292	case GL_TEXTURE_RECTANGLE:
1293		gl.texSubImage2D(target, level, x, y, width, height, format, type, pixels);
1294		GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D");
1295		break;
1296	case GL_TEXTURE_CUBE_MAP:
1297		gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, x, y, width, height, format, type, pixels);
1298		gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, x, y, width, height, format, type, pixels);
1299		gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, x, y, width, height, format, type, pixels);
1300		gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, x, y, width, height, format, type, pixels);
1301		gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, x, y, width, height, format, type, pixels);
1302		gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, x, y, width, height, format, type, pixels);
1303		GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D");
1304		break;
1305	case GL_TEXTURE_3D:
1306	case GL_TEXTURE_2D_ARRAY:
1307	case GL_TEXTURE_CUBE_MAP_ARRAY:
1308		gl.texSubImage3D(target, level, x, y, z, width, height, depth, format, type, pixels);
1309		GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage3D");
1310		break;
1311	default:
1312		TCU_FAIL("Invliad enum");
1313	}
1314}
1315
1316/* Gather info about buffer target */
1317struct bufferTargetInfo
1318{
1319	GLenum m_target;
1320	GLenum m_pname_alignment;
1321	GLenum m_pname_binding;
1322	GLenum m_pname_max;
1323	GLenum m_pname_max_size;
1324};
1325
1326/* Gather info about texture target */
1327struct textureTargetInfo
1328{
1329	GLenum		  m_target;
1330	GLenum		  m_pname_binding;
1331	const GLchar* m_name;
1332};
1333
1334/* Collects information about buffers */
1335static const bufferTargetInfo s_buffer_infos[] = {
1336	{ GL_ATOMIC_COUNTER_BUFFER, 0, GL_ATOMIC_COUNTER_BUFFER_BINDING, GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS,
1337	  GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE },
1338	{
1339		GL_TRANSFORM_FEEDBACK_BUFFER, 0, GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, GL_MAX_TRANSFORM_FEEDBACK_BUFFERS,
1340		GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS,
1341	},
1342	{ GL_UNIFORM_BUFFER, GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, GL_UNIFORM_BUFFER_BINDING, GL_MAX_UNIFORM_BUFFER_BINDINGS,
1343	  GL_MAX_UNIFORM_BLOCK_SIZE },
1344	{ GL_SHADER_STORAGE_BUFFER, GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, GL_SHADER_STORAGE_BUFFER_BINDING,
1345	  GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, GL_MAX_SHADER_STORAGE_BLOCK_SIZE },
1346};
1347
1348static const size_t s_n_buffer_tragets = sizeof(s_buffer_infos) / sizeof(s_buffer_infos[0]);
1349
1350/* Collects information about textures */
1351static const textureTargetInfo s_texture_infos[] = {
1352	{ GL_TEXTURE_1D, GL_TEXTURE_BINDING_1D, "1D" },
1353	{ GL_TEXTURE_1D_ARRAY, GL_TEXTURE_BINDING_1D_ARRAY, "1D_ARRAY" },
1354	{ GL_TEXTURE_2D, GL_TEXTURE_BINDING_2D, "2D" },
1355	{ GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BINDING_2D_ARRAY, "2D_ARRAY" },
1356	{ GL_TEXTURE_3D, GL_TEXTURE_BINDING_3D, "3D" },
1357	{ GL_TEXTURE_BUFFER, GL_TEXTURE_BINDING_BUFFER, "BUFFER" },
1358	{ GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BINDING_CUBE_MAP, "CUBE" },
1359	{ GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_BINDING_CUBE_MAP_ARRAY, "CUBE_ARRAY" },
1360	{ GL_TEXTURE_RECTANGLE, GL_TEXTURE_BINDING_RECTANGLE, "RECTANGLE" },
1361	{ GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_BINDING_2D_MULTISAMPLE, "2D_MS" },
1362	{ GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY, "2D_MS_ARRAY" }
1363};
1364
1365static const size_t s_n_texture_tragets = sizeof(s_texture_infos) / sizeof(s_texture_infos[0]);
1366
1367/** Macro, verifies generated error, logs error message and throws failure
1368 *
1369 * @param expected_error Expected error value
1370 * @param error_message  Message logged if generated error is not the expected one
1371 **/
1372#define CHECK_ERROR(expected_error, error_message)                                                      \
1373	do {                                                                                                   \
1374		GLenum generated_error = gl.getError();                                                         \
1375                                                                                                        \
1376		if (expected_error != generated_error)                                                          \
1377		{                                                                                               \
1378			m_context.getTestContext().getLog()                                                         \
1379				<< tcu::TestLog::Message << "File: " << __FILE__ << ", line: " << __LINE__              \
1380				<< ". Got wrong error: " << glu::getErrorStr(generated_error)                           \
1381				<< ", expected: " << glu::getErrorStr(expected_error) << ", message: " << error_message \
1382				<< tcu::TestLog::EndMessage;                                                            \
1383			TCU_FAIL("Invalid error generated");                                                        \
1384		}                                                                                               \
1385	} while (0)
1386
1387/* Prototypes */
1388void replaceToken(const GLchar* token, size_t& search_position, const GLchar* text, std::string& string);
1389
1390/** Checks binding
1391 *
1392 * @param context        Test contex
1393 * @param pname          Pname of binding
1394 * @param index          Index of binding
1395 * @param target_name    Name of target
1396 * @param expected_value Expected value of binding
1397 **/
1398void checkBinding(deqp::Context& context, GLenum pname, GLuint index, const std::string& target_name,
1399				  GLint expected_value)
1400{
1401	const Functions& gl = context.getRenderContext().getFunctions();
1402
1403	GLint binding = -1;
1404
1405	gl.getIntegeri_v(pname, index, &binding);
1406	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegeri_v");
1407
1408	if (binding != expected_value)
1409	{
1410		context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid binding: " << binding
1411										  << ", expected: " << expected_value << ". Target: " << target_name
1412										  << " at index: " << index << tcu::TestLog::EndMessage;
1413		TCU_FAIL("Invalid binding");
1414	}
1415}
1416
1417/** Checks bindings for given texture unit
1418 *
1419 * @param context        Test contex
1420 * @param pname          Binding pname of <expected_value>
1421 * @param index          Index of texture unit
1422 * @param expected_value Expected value of binding at <pname> target
1423 **/
1424void checkTextureBinding(deqp::Context& context, GLenum pname, GLuint index, GLint expected_value)
1425{
1426	const Functions& gl = context.getRenderContext().getFunctions();
1427
1428	for (size_t i = 0; i < s_n_texture_tragets; ++i)
1429	{
1430		const GLenum  pname_binding = s_texture_infos[i].m_pname_binding;
1431		const GLchar* target_name   = s_texture_infos[i].m_name;
1432
1433		GLint binding = -1;
1434		GLint value   = 0;
1435
1436		gl.getIntegeri_v(pname_binding, index, &binding);
1437		GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegeri_v");
1438
1439		if (pname_binding == pname)
1440		{
1441			value = (GLint)expected_value;
1442		}
1443
1444		if (binding != value)
1445		{
1446			context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid binding: " << binding
1447											  << ", expected: " << expected_value << ". Target: " << target_name
1448											  << " at index: " << index << tcu::TestLog::EndMessage;
1449			TCU_FAIL("Invalid binding");
1450		}
1451	}
1452}
1453
1454/** Checks binding
1455 *
1456 * @param context        Test context
1457 * @param index          Index of binding
1458 * @param expected_value Expected value of binding
1459 **/
1460void checkVertexAttribBinding(deqp::Context& context, GLuint index, GLint expected_value)
1461{
1462	const Functions& gl = context.getRenderContext().getFunctions();
1463
1464	GLint binding = -1;
1465
1466	gl.getVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &binding);
1467	GLU_EXPECT_NO_ERROR(gl.getError(), "GetVertexAttribiv");
1468
1469	if (binding != expected_value)
1470	{
1471		context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid binding: " << binding
1472										  << ", expected: " << expected_value << ". Target: Vertex attribute"
1473										  << " at index: " << index << tcu::TestLog::EndMessage;
1474		TCU_FAIL("Invalid binding");
1475	}
1476}
1477
1478/** Fills MS texture with specified value
1479 *
1480 * @param context        Test context
1481 * @param texture_id     Index of binding
1482 * @param value          Value for texture
1483 * @param is_array       Selects if array target should be used
1484 **/
1485void fillMSTexture(deqp::Context& context, GLuint texture_id, GLuint value, bool is_array)
1486{
1487	/* */
1488	static const GLchar* cs = "#version 430 core\n"
1489							  "\n"
1490							  "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
1491							  "\n"
1492							  "layout (location = 0) writeonly uniform IMAGE uni_image;\n"
1493							  "\n"
1494							  "layout (location = 1) uniform uint uni_value;\n"
1495							  "\n"
1496							  "void main()\n"
1497							  "{\n"
1498							  "    const POINT;\n"
1499							  "\n"
1500							  "    imageStore(uni_image, point, 0, uvec4(uni_value, 0, 0, 0));\n"
1501							  "}\n"
1502							  "\n";
1503
1504	static const GLchar* array_image   = "uimage2DMSArray";
1505	static const GLchar* array_point   = "ivec3 point = ivec3(gl_WorkGroupID.x, gl_WorkGroupID.y, 0)";
1506	static const GLchar* regular_image = "uimage2DMS";
1507	static const GLchar* regular_point = "ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y)";
1508
1509	/* */
1510	const Functions& gl		  = context.getRenderContext().getFunctions();
1511	const GLchar*	image	= (true == is_array) ? array_image : regular_image;
1512	const GLchar*	point	= (true == is_array) ? array_point : regular_point;
1513	size_t			 position = 0;
1514	std::string		 source   = cs;
1515
1516	/* */
1517	replaceToken("IMAGE", position, image, source);
1518	replaceToken("POINT", position, point, source);
1519
1520	/* */
1521	Program program(context);
1522	program.Init(source.c_str(), "", "", "", "", "");
1523	program.Use();
1524
1525	/* */
1526	if (true == is_array)
1527	{
1528		gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_TRUE /* layered */, 0 /* layer */,
1529							GL_WRITE_ONLY, GL_R32UI);
1530	}
1531	else
1532	{
1533		gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
1534							GL_WRITE_ONLY, GL_R32UI);
1535	}
1536
1537	GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
1538
1539	gl.uniform1i(0 /* location */, 0 /* image unit*/);
1540	GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
1541
1542	gl.uniform1ui(1 /* location */, value /* uni_value */);
1543	GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1ui");
1544
1545	/* */
1546	gl.dispatchCompute(6, 6, 1);
1547	GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
1548}
1549
1550/** Get texture binding pname for given index
1551 *
1552 * @param index Index of texture target
1553 *
1554 * @return Pname
1555 **/
1556GLenum getBinding(GLuint index)
1557{
1558	if (index < s_n_texture_tragets)
1559	{
1560		return s_texture_infos[index].m_pname_binding;
1561	}
1562	else
1563	{
1564		return GL_TEXTURE_BINDING_2D;
1565	}
1566}
1567
1568/** Get texture target for given index
1569 *
1570 * @param index Index of texture target
1571 *
1572 * @return Target
1573 **/
1574GLenum getTarget(GLuint index)
1575{
1576	if (index < s_n_texture_tragets)
1577	{
1578		return s_texture_infos[index].m_target;
1579	}
1580	else
1581	{
1582		return GL_TEXTURE_2D;
1583	}
1584}
1585
1586/** Replace first occurance of <token> with <text> in <string> starting at <search_posistion>
1587 *
1588 * @param token           Token string
1589 * @param search_position Position at which find will start, it is updated to position at which replaced text ends
1590 * @param text            String that will be used as replacement for <token>
1591 * @param string          String to work on
1592 **/
1593void replaceToken(const GLchar* token, size_t& search_position, const GLchar* text, std::string& string)
1594{
1595	const size_t text_length	= strlen(text);
1596	const size_t token_length   = strlen(token);
1597	const size_t token_position = string.find(token, search_position);
1598
1599	string.replace(token_position, token_length, text, text_length);
1600
1601	search_position = token_position + text_length;
1602}
1603
1604/** Constructor
1605 *
1606 * @param context Test context
1607 **/
1608ErrorsBindBuffersTest::ErrorsBindBuffersTest(deqp::Context& context)
1609	: TestCase(context, "errors_bind_buffers", "Verifies that proper errors are generated by buffer binding routines")
1610{
1611	/* Nothing to be done */
1612}
1613
1614/** Execute test
1615 *
1616 * @return tcu::TestNode::STOP
1617 **/
1618tcu::TestNode::IterateResult ErrorsBindBuffersTest::iterate()
1619{
1620	const Functions& gl = m_context.getRenderContext().getFunctions();
1621
1622#if DEBUG_ENBALE_MESSAGE_CALLBACK
1623	gl.debugMessageCallback(debug_proc, &m_context);
1624	GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
1625#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
1626
1627	/* - INVALID_ENUM when <target> is not valid; */
1628	{
1629		static const GLintptr buffer_size = 16;
1630		static const GLsizei  count		  = 1;
1631		static const GLuint   first		  = 0;
1632		static const GLintptr offset	  = 4;
1633		static const GLintptr size		  = buffer_size - offset;
1634
1635		Buffer buffer;
1636
1637		buffer.InitData(m_context, GL_ARRAY_BUFFER, GL_DYNAMIC_COPY, buffer_size, 0 /* data */);
1638
1639		gl.bindBuffersBase(GL_ARRAY_BUFFER, first, count, &buffer.m_id);
1640		CHECK_ERROR(GL_INVALID_ENUM, "BindBuffersBase with invalid <target>");
1641
1642		gl.bindBuffersRange(GL_ARRAY_BUFFER, first, count, &buffer.m_id, &offset, &size);
1643		CHECK_ERROR(GL_INVALID_ENUM, "BindBuffersRange with invalid <target>");
1644	}
1645
1646	for (size_t i = 0; i < s_n_buffer_tragets; ++i)
1647	{
1648		static const GLsizei n_buffers = 4;
1649
1650		const GLenum	   pname_alignment = s_buffer_infos[i].m_pname_alignment;
1651		const GLenum	   pname_max	   = s_buffer_infos[i].m_pname_max;
1652		const GLenum	   target		   = s_buffer_infos[i].m_target;
1653		const std::string& target_name	 = glu::getBufferTargetStr(target).toString();
1654
1655		GLintptr buffer_size	  = 16;
1656		GLsizei  count			  = n_buffers;
1657		GLuint   first			  = 0;
1658		GLuint   invalid_id		  = 1; /* Start with 1, as 0 is not valid name */
1659		GLintptr offset			  = 4; /* ATOMIC and XFB require alignment of 4 */
1660		GLint	offset_alignment = 1;
1661		GLint	max_buffers	  = 0;
1662		GLintptr size			  = buffer_size - offset;
1663		size_t   validated_index  = n_buffers - 1;
1664
1665		/* Get alignment */
1666		if (0 != pname_alignment)
1667		{
1668			gl.getIntegerv(pname_alignment, &offset_alignment);
1669			GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
1670
1671			buffer_size += offset_alignment;
1672			offset = offset_alignment;
1673			size   = buffer_size - offset;
1674		}
1675
1676		/* Get max */
1677		gl.getIntegerv(pname_max, &max_buffers);
1678		GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
1679
1680		/* Select count so <first + count> does not exceed max.
1681		 * Validated index shall be in the specified range.
1682		 */
1683		if (n_buffers > max_buffers)
1684		{
1685			count			= max_buffers;
1686			validated_index = max_buffers - 1;
1687		}
1688
1689		/* Storage */
1690		Buffer   buffer[n_buffers];
1691		GLuint   buffer_ids[n_buffers];
1692		GLintptr offsets[n_buffers];
1693		GLintptr sizes[n_buffers];
1694
1695		/* Prepare buffers */
1696		for (size_t j = 0; j < n_buffers; ++j)
1697		{
1698			buffer[j].InitData(m_context, target, GL_DYNAMIC_COPY, buffer_size, 0 /* data */);
1699
1700			buffer_ids[j] = buffer[j].m_id;
1701			offsets[j]	= offset;
1702			sizes[j]	  = size;
1703		}
1704
1705		/* - INVALID_OPERATION when <first> + <count> is greater than allowed limit; */
1706		{
1707			GLsizei t_count = n_buffers;
1708			GLuint  t_first = 0;
1709
1710			/* Select first so <first + count> exceeds max, avoid negative first */
1711			if (n_buffers <= max_buffers)
1712			{
1713				t_first = max_buffers - n_buffers + 1;
1714			}
1715			else
1716			{
1717				t_count = max_buffers + 1;
1718				/* first = 0; */
1719			}
1720
1721			/* Test */
1722			gl.bindBuffersBase(target, t_first, t_count, buffer_ids);
1723			CHECK_ERROR(GL_INVALID_OPERATION,
1724						"BindBuffersBase with invalid <first> + <count>, target: " << target_name);
1725
1726			gl.bindBuffersRange(target, t_first, t_count, buffer_ids, offsets, sizes);
1727			CHECK_ERROR(GL_INVALID_OPERATION,
1728						"BindBuffersRange with invalid <first> + <count>, target: " << target_name);
1729		}
1730
1731		/* - INVALID_OPERATION if any value in <buffers> is not zero or the name of
1732		 * existing buffer;
1733		 */
1734		{
1735			GLuint t_buffer_ids[n_buffers];
1736
1737			memcpy(t_buffer_ids, buffer_ids, sizeof(buffer_ids));
1738
1739			/* Find invalid id */
1740			while (1)
1741			{
1742				if (GL_TRUE != gl.isBuffer(invalid_id))
1743				{
1744					break;
1745				}
1746
1747				invalid_id += 1;
1748			}
1749
1750			/* Invalidate the entry */
1751			t_buffer_ids[validated_index] = invalid_id;
1752
1753			/* Test */
1754			gl.bindBuffersBase(target, first, count, t_buffer_ids);
1755			CHECK_ERROR(GL_INVALID_OPERATION, "BindBuffersBase with invalid buffer id, target: " << target_name);
1756
1757			gl.bindBuffersRange(target, first, count, t_buffer_ids, offsets, sizes);
1758			CHECK_ERROR(GL_INVALID_OPERATION, "BindBuffersRange with invalid buffer id, target: " << target_name);
1759		}
1760
1761		/* - INVALID_VALUE if any value in <offsets> is less than zero; */
1762		{
1763			GLintptr t_offsets[n_buffers];
1764			GLintptr t_sizes[n_buffers];
1765
1766			memcpy(t_offsets, offsets, sizeof(offsets));
1767			memcpy(t_sizes, sizes, sizeof(sizes));
1768
1769			/* Invalidate the entry */
1770			t_offsets[validated_index] = -1;
1771			t_sizes[validated_index]   = -1;
1772
1773			/* Test */
1774			gl.bindBuffersRange(target, first, count, buffer_ids, t_offsets, sizes);
1775			CHECK_ERROR(GL_INVALID_VALUE, "BindBuffersRange with negative offset, target: " << target_name);
1776
1777			/* Test */
1778			gl.bindBuffersRange(target, first, count, buffer_ids, offsets, t_sizes);
1779			CHECK_ERROR(GL_INVALID_VALUE, "BindBuffersRange with negative size, target: " << target_name);
1780		}
1781
1782		/* - INVALID_VALUE if any pair of <offsets> and <sizes> exceeds limits. */
1783		{
1784			GLintptr t_offsets[n_buffers];
1785			GLintptr t_sizes[n_buffers];
1786
1787			memcpy(t_offsets, offsets, sizeof(offsets));
1788			memcpy(t_sizes, sizes, sizeof(sizes));
1789
1790			/* Invalidate the entry */
1791			t_offsets[validated_index] -= 1;	 /* Not aligned by required value */
1792			t_sizes[validated_index] = size - 1; /* Not aligned by required value */
1793
1794			/* Test */
1795			gl.bindBuffersRange(target, first, count, buffer_ids, t_offsets, sizes);
1796			CHECK_ERROR(GL_INVALID_VALUE, "BindBuffersRange with invalid <offset>, target: " << target_name);
1797
1798			/* Test */
1799			if (GL_TRANSFORM_FEEDBACK_BUFFER == target)
1800			{
1801				gl.bindBuffersRange(target, first, count, buffer_ids, offsets, t_sizes);
1802				CHECK_ERROR(GL_INVALID_VALUE, "BindBuffersRange with invalid <size>, target: " << target_name);
1803			}
1804		}
1805	}
1806
1807	/* Set result */
1808	m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
1809
1810	/* Done */
1811	return tcu::TestNode::STOP;
1812}
1813
1814/** Constructor
1815 *
1816 * @param context Test context
1817 **/
1818ErrorsBindTexturesTest::ErrorsBindTexturesTest(deqp::Context& context)
1819	: TestCase(context, "errors_bind_textures", "Verifies that proper errors are generated by texture binding routines")
1820{
1821	/* Nothing to be done */
1822}
1823
1824/** Execute test
1825 *
1826 * @return tcu::TestNode::STOP
1827 **/
1828tcu::TestNode::IterateResult ErrorsBindTexturesTest::iterate()
1829{
1830	static const GLuint  depth		= 8;
1831	static const GLuint  height		= 8;
1832	static const GLsizei n_textures = 4;
1833	static const GLuint  width		= 8;
1834
1835	const Functions& gl = m_context.getRenderContext().getFunctions();
1836
1837#if DEBUG_ENBALE_MESSAGE_CALLBACK
1838	gl.debugMessageCallback(debug_proc, &m_context);
1839	GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
1840#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
1841
1842	GLsizei count			= n_textures;
1843	GLuint  first			= 0;
1844	GLuint  invalid_id		= 1; /* Start with 1, as 0 is not valid name */
1845	GLint   max_textures	= 0;
1846	size_t  validated_index = n_textures - 1;
1847
1848	/* Get max */
1849	gl.getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_textures);
1850	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
1851
1852	/* Select count so <first + count> does not exceed max.
1853	 * Validated index shall be in the specified range.
1854	 */
1855	if (n_textures > max_textures)
1856	{
1857		count			= max_textures;
1858		validated_index = max_textures - 1;
1859	}
1860
1861	/* Storage */
1862	Texture texture[n_textures];
1863	GLuint  texture_ids[n_textures];
1864
1865	/* Prepare textures */
1866	texture[0].InitStorage(m_context, GL_TEXTURE_2D, 1 /* levels */, GL_RGBA8, width, height, depth);
1867	texture[1].InitStorage(m_context, GL_TEXTURE_2D_ARRAY, 1 /* levels */, GL_RGBA8, width, height, depth);
1868	texture[2].InitStorage(m_context, GL_TEXTURE_1D_ARRAY, 1 /* levels */, GL_RGBA8, width, height, depth);
1869	texture[3].InitStorage(m_context, GL_TEXTURE_3D, 1 /* levels */, GL_RGBA8, width, height, depth);
1870
1871	for (size_t i = 0; i < n_textures; ++i)
1872	{
1873		texture_ids[i] = texture[i].m_id;
1874	}
1875
1876	/* - INVALID_OPERATION when <first> + <count> exceed limits; */
1877	{
1878		GLsizei t_count = n_textures;
1879		GLuint  t_first = 0;
1880
1881		/* Select first so <first + count> exceeds max, avoid negative first */
1882		if (n_textures <= max_textures)
1883		{
1884			t_first = max_textures - n_textures + 1;
1885		}
1886		else
1887		{
1888			t_count = max_textures + 1;
1889			/* first = 0; */
1890		}
1891
1892		/* Test */
1893		gl.bindTextures(t_first, t_count, texture_ids);
1894		CHECK_ERROR(GL_INVALID_OPERATION, "BindTextures with invalid <first> + <count>");
1895	}
1896
1897	/* - INVALID_OPERATION if any value in <buffers> is not zero or the name of
1898	 * existing buffer;
1899	 */
1900	{
1901		GLuint t_texture_ids[n_textures];
1902
1903		memcpy(t_texture_ids, texture_ids, sizeof(texture_ids));
1904
1905		/* Find invalid id */
1906		while (1)
1907		{
1908			if (GL_TRUE != gl.isTexture(invalid_id))
1909			{
1910				break;
1911			}
1912
1913			invalid_id += 1;
1914		}
1915
1916		/* Invalidate the entry */
1917		t_texture_ids[validated_index] = invalid_id;
1918
1919		/* Test */
1920		gl.bindTextures(first, count, t_texture_ids);
1921		CHECK_ERROR(GL_INVALID_OPERATION, "BindTextures with invalid texture id");
1922	}
1923
1924	/* Set result */
1925	m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
1926
1927	/* Done */
1928	return tcu::TestNode::STOP;
1929}
1930
1931/** Constructor
1932 *
1933 * @param context Test context
1934 **/
1935ErrorsBindSamplersTest::ErrorsBindSamplersTest(deqp::Context& context)
1936	: TestCase(context, "errors_bind_samplers", "Verifies that proper errors are generated by sampler binding routines")
1937{
1938	/* Nothing to be done */
1939}
1940
1941/** Execute test
1942 *
1943 * @return tcu::TestNode::STOP
1944 **/
1945tcu::TestNode::IterateResult ErrorsBindSamplersTest::iterate()
1946{
1947	static const GLsizei n_samplers = 4;
1948
1949	const Functions& gl = m_context.getRenderContext().getFunctions();
1950
1951#if DEBUG_ENBALE_MESSAGE_CALLBACK
1952	gl.debugMessageCallback(debug_proc, &m_context);
1953	GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
1954#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
1955
1956	GLsizei count			= n_samplers;
1957	GLuint  first			= 0;
1958	GLuint  invalid_id		= 1; /* Start with 1, as 0 is not valid name */
1959	GLint   max_samplers	= 0;
1960	size_t  validated_index = n_samplers - 1;
1961
1962	/* Get max */
1963	gl.getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_samplers);
1964	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
1965
1966	/* Select count so <first + count> does not exceed max.
1967	 * Validated index shall be in the specified range.
1968	 */
1969	if (n_samplers > max_samplers)
1970	{
1971		count			= max_samplers;
1972		validated_index = max_samplers - 1;
1973	}
1974
1975	/* Storage */
1976	GLuint sampler_ids[n_samplers];
1977
1978	/* Prepare samplers */
1979	gl.genSamplers(n_samplers, sampler_ids);
1980	GLU_EXPECT_NO_ERROR(gl.getError(), "GenSamplers");
1981
1982	try
1983	{
1984		/* - INVALID_OPERATION when <first> + <count> exceed limits; */
1985		{
1986			GLsizei t_count = n_samplers;
1987			GLuint  t_first = 0;
1988
1989			/* Select first so <first + count> exceeds max, avoid negative first */
1990			if (n_samplers <= max_samplers)
1991			{
1992				t_first = max_samplers - n_samplers + 1;
1993			}
1994			else
1995			{
1996				t_count = max_samplers + 1;
1997				/* first = 0; */
1998			}
1999
2000			/* Test */
2001			gl.bindSamplers(t_first, t_count, sampler_ids);
2002			CHECK_ERROR(GL_INVALID_OPERATION, "BindSamplers with invalid <first> + <count>");
2003		}
2004
2005		/* - INVALID_OPERATION if any value in <buffers> is not zero or the name of
2006		 * existing buffer;
2007		 */
2008		{
2009			GLuint t_sampler_ids[n_samplers];
2010
2011			memcpy(t_sampler_ids, sampler_ids, sizeof(sampler_ids));
2012
2013			/* Find invalid id */
2014			while (1)
2015			{
2016				if (GL_TRUE != gl.isTexture(invalid_id))
2017				{
2018					break;
2019				}
2020
2021				invalid_id += 1;
2022			}
2023
2024			/* Invalidate the entry */
2025			t_sampler_ids[validated_index] = invalid_id;
2026
2027			/* Test */
2028			gl.bindTextures(first, count, t_sampler_ids);
2029			CHECK_ERROR(GL_INVALID_OPERATION, "BindSamplers with invalid sampler id");
2030		}
2031	}
2032	catch (const std::exception&)
2033	{
2034		gl.deleteSamplers(n_samplers, sampler_ids);
2035
2036		TCU_FAIL("Invalid error generated");
2037	}
2038
2039	/* Delete samplers */
2040	gl.deleteSamplers(n_samplers, sampler_ids);
2041
2042	/* Set result */
2043	m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
2044
2045	/* Done */
2046	return tcu::TestNode::STOP;
2047}
2048
2049/** Constructor
2050 *
2051 * @param context Test context
2052 **/
2053ErrorsBindImageTexturesTest::ErrorsBindImageTexturesTest(deqp::Context& context)
2054	: TestCase(context, "errors_bind_image_textures",
2055			   "Verifies that proper errors are generated by image binding routines")
2056{
2057	/* Nothing to be done */
2058}
2059
2060/** Execute test
2061 *
2062 * @return tcu::TestNode::STOP
2063 **/
2064tcu::TestNode::IterateResult ErrorsBindImageTexturesTest::iterate()
2065{
2066	static const GLuint  depth		= 8;
2067	static const GLuint  height		= 8;
2068	static const GLsizei n_textures = 4;
2069	static const GLuint  width		= 8;
2070
2071	const Functions& gl = m_context.getRenderContext().getFunctions();
2072
2073#if DEBUG_ENBALE_MESSAGE_CALLBACK
2074	gl.debugMessageCallback(debug_proc, &m_context);
2075	GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
2076#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
2077
2078	GLsizei count			= n_textures;
2079	GLuint  first			= 0;
2080	GLuint  invalid_id		= 1; /* Start with 1, as 0 is not valid name */
2081	GLint   max_textures	= 0;
2082	size_t  validated_index = n_textures - 1;
2083
2084	/* Get max */
2085	gl.getIntegerv(GL_MAX_IMAGE_UNITS, &max_textures);
2086	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
2087
2088	/* Select count so <first + count> does not exceed max.
2089	 * Validated index shall be in the specified range.
2090	 */
2091	if (n_textures > max_textures)
2092	{
2093		count			= max_textures;
2094		validated_index = max_textures - 1;
2095	}
2096
2097	/* Storage */
2098	Texture texture[n_textures];
2099	GLuint  texture_ids[n_textures];
2100
2101	/* Prepare textures */
2102	texture[0].InitStorage(m_context, GL_TEXTURE_2D, 1, GL_RGBA8, width, height, depth);
2103	texture[1].InitStorage(m_context, GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, width, height, depth);
2104	texture[2].InitStorage(m_context, GL_TEXTURE_1D_ARRAY, 1, GL_RGBA8, width, height, depth);
2105	texture[3].InitStorage(m_context, GL_TEXTURE_3D, 1, GL_RGBA8, width, height, depth);
2106
2107	for (size_t i = 0; i < n_textures; ++i)
2108	{
2109		texture_ids[i] = texture[i].m_id;
2110	}
2111
2112	/* - INVALID_OPERATION when <first> + <count> exceed limits; */
2113	{
2114		GLsizei t_count = n_textures;
2115		GLuint  t_first = 0;
2116
2117		/* Select first so <first + count> exceeds max, avoid negative first */
2118		if (n_textures <= max_textures)
2119		{
2120			t_first = max_textures - n_textures + 1;
2121		}
2122		else
2123		{
2124			t_count = max_textures + 1;
2125			/* first = 0; */
2126		}
2127
2128		/* Test */
2129		gl.bindImageTextures(t_first, t_count, texture_ids);
2130		CHECK_ERROR(GL_INVALID_OPERATION, "BindImageTextures with invalid <first> + <count>");
2131	}
2132
2133	/* - INVALID_OPERATION if any value in <buffers> is not zero or the name of
2134	 * existing buffer;
2135	 */
2136	{
2137		GLuint t_texture_ids[n_textures];
2138
2139		memcpy(t_texture_ids, texture_ids, sizeof(texture_ids));
2140
2141		/* Find invalid id */
2142		while (1)
2143		{
2144			if (GL_TRUE != gl.isTexture(invalid_id))
2145			{
2146				break;
2147			}
2148
2149			invalid_id += 1;
2150		}
2151
2152		/* Invalidate the entry */
2153		t_texture_ids[validated_index] = invalid_id;
2154
2155		/* Test */
2156		gl.bindImageTextures(first, count, t_texture_ids);
2157		CHECK_ERROR(GL_INVALID_OPERATION, "BindImageTextures with invalid texture id");
2158	}
2159
2160	/* - INVALID_OPERATION if any entry found in <textures> has invalid internal
2161	 * format at level 0;
2162	 */
2163	{
2164		GLuint t_texture_ids[n_textures];
2165
2166		memcpy(t_texture_ids, texture_ids, sizeof(texture_ids));
2167
2168		/* Prepare texture with invalid format */
2169		Texture t_texture;
2170		t_texture.Init(m_context);
2171		t_texture.Generate(gl, t_texture.m_id);
2172		t_texture.Bind(gl, t_texture.m_id, GL_TEXTURE_2D);
2173		gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGB9_E5, width, 0);
2174		CHECK_ERROR(GL_INVALID_VALUE, "texStorage2D has height set to 0");
2175
2176		/* Invalidate the entry */
2177		t_texture_ids[validated_index] = t_texture.m_id;
2178
2179		/* Test */
2180		gl.bindImageTextures(first, count, t_texture_ids);
2181		CHECK_ERROR(GL_INVALID_OPERATION, "BindImageTextures with invalid internal format");
2182	}
2183
2184	/* - INVALID_VALUE when any entry in <textures> has any of dimensions equal
2185	 * to 0 at level 0.
2186	 */
2187	{
2188		GLuint t_texture_ids[n_textures];
2189
2190		memcpy(t_texture_ids, texture_ids, sizeof(texture_ids));
2191
2192		/* Prepare texture with invalid format */
2193		Texture t_texture;
2194		t_texture.InitStorage(m_context, GL_TEXTURE_2D, 1, GL_RGB9_E5, width, 0, depth, true);
2195
2196		/* Invalidate the entry */
2197		t_texture_ids[validated_index] = t_texture.m_id;
2198
2199		/* Test */
2200		gl.bindImageTextures(first, count, t_texture_ids);
2201		CHECK_ERROR(GL_INVALID_VALUE, "BindImageTextures with 2D texture that has height set to 0");
2202	}
2203
2204	/* Set result */
2205	m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
2206
2207	/* Done */
2208	return tcu::TestNode::STOP;
2209}
2210
2211/** Constructor
2212 *
2213 * @param context Test context
2214 **/
2215ErrorsBindVertexBuffersTest::ErrorsBindVertexBuffersTest(deqp::Context& context)
2216	: TestCase(context, "errors_bind_vertex_buffers",
2217			   "Verifies that proper errors are generated by vertex buffer binding routines")
2218{
2219	/* Nothing to be done */
2220}
2221
2222/** Execute test
2223 *
2224 * @return tcu::TestNode::STOP
2225 **/
2226tcu::TestNode::IterateResult ErrorsBindVertexBuffersTest::iterate()
2227{
2228	const Functions& gl = m_context.getRenderContext().getFunctions();
2229
2230#if DEBUG_ENBALE_MESSAGE_CALLBACK
2231	gl.debugMessageCallback(debug_proc, &m_context);
2232	GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
2233#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
2234
2235	static const GLsizei n_buffers = 4;
2236	static const GLsizei stride	= 4;
2237
2238	GLintptr buffer_size	 = 16;
2239	GLsizei  count			 = n_buffers;
2240	GLuint   first			 = 0;
2241	GLuint   invalid_id		 = 1; /* Start with 1, as 0 is not valid name */
2242	GLintptr offset			 = 4; /* ATOMIC and XFB require alignment of 4 */
2243	GLint	max_buffers	 = 0;
2244	size_t   validated_index = n_buffers - 1;
2245
2246	/* Get max */
2247	gl.getIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &max_buffers);
2248	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
2249
2250	/* Select count so <first + count> does not exceed max.
2251	 * Validated index shall be in the specified range.
2252	 */
2253	if (n_buffers > max_buffers)
2254	{
2255		count			= max_buffers;
2256		validated_index = max_buffers - 1;
2257	}
2258
2259	/* Storage */
2260	Buffer   buffer[n_buffers];
2261	GLuint   buffer_ids[n_buffers];
2262	GLintptr offsets[n_buffers];
2263	GLsizei  strides[n_buffers];
2264
2265	/* Prepare buffers */
2266	for (size_t j = 0; j < n_buffers; ++j)
2267	{
2268		buffer[j].InitData(m_context, GL_ARRAY_BUFFER, GL_DYNAMIC_COPY, buffer_size, 0 /* data */);
2269
2270		buffer_ids[j] = buffer[j].m_id;
2271		offsets[j]	= offset;
2272		strides[j]	= stride;
2273	}
2274
2275	/* Prepare VAO */
2276	GLuint vao = 0;
2277	gl.genVertexArrays(1, &vao);
2278	GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays");
2279	try
2280	{
2281		gl.bindVertexArray(vao);
2282		GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArrays");
2283
2284		/* - INVALID_OPERATION when <first> + <count> exceeds limits; */
2285		{
2286			GLsizei t_count = n_buffers;
2287			GLuint  t_first = 0;
2288
2289			/* Select first so <first + count> exceeds max, avoid negative first */
2290			if (n_buffers <= max_buffers)
2291			{
2292				t_first = max_buffers - n_buffers + 1;
2293			}
2294			else
2295			{
2296				t_count = max_buffers + 1;
2297				/* first = 0; */
2298			}
2299
2300			/* Test */
2301			gl.bindVertexBuffers(t_first, t_count, buffer_ids, offsets, strides);
2302			CHECK_ERROR(GL_INVALID_OPERATION, "BindVertexBuffers with invalid <first> + <count>");
2303		}
2304
2305		/* - INVALID_OPERATION if any value in <buffers> is not zero or the name of
2306		 * existing buffer;
2307		 */
2308		{
2309			GLuint t_buffer_ids[n_buffers];
2310
2311			memcpy(t_buffer_ids, buffer_ids, sizeof(buffer_ids));
2312
2313			/* Find invalid id */
2314			while (1)
2315			{
2316				if (GL_TRUE != gl.isBuffer(invalid_id))
2317				{
2318					break;
2319				}
2320
2321				invalid_id += 1;
2322			}
2323
2324			/* Invalidate the entry */
2325			t_buffer_ids[validated_index] = invalid_id;
2326
2327			/* Test */
2328			gl.bindVertexBuffers(first, count, t_buffer_ids, offsets, strides);
2329			CHECK_ERROR(GL_INVALID_OPERATION, "BindVertexBuffers with invalid buffer id");
2330		}
2331
2332		/* - INVALID_VALUE if any value in <offsets> or <strides> is less than zero. */
2333		{
2334			GLintptr t_offsets[n_buffers];
2335			GLsizei  t_strides[n_buffers];
2336
2337			memcpy(t_offsets, offsets, sizeof(offsets));
2338			memcpy(t_strides, strides, sizeof(strides));
2339
2340			/* Invalidate the entry */
2341			t_offsets[validated_index] = -1;
2342			t_strides[validated_index] = -1;
2343
2344			/* Test */
2345			gl.bindVertexBuffers(first, count, buffer_ids, t_offsets, strides);
2346			CHECK_ERROR(GL_INVALID_VALUE, "BindVertexBuffers with negative offset");
2347
2348			gl.bindVertexBuffers(first, count, buffer_ids, offsets, t_strides);
2349			CHECK_ERROR(GL_INVALID_VALUE, "BindVertexBuffers with negative stride");
2350		}
2351	}
2352	catch (const std::exception&)
2353	{
2354		gl.deleteVertexArrays(1, &vao);
2355		TCU_FAIL("Unexpected error generated");
2356	}
2357
2358	gl.deleteVertexArrays(1, &vao);
2359	GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteVertexArrays");
2360
2361	/* Set result */
2362	m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
2363
2364	/* Done */
2365	return tcu::TestNode::STOP;
2366}
2367
2368/** Constructor
2369 *
2370 * @param context Test context
2371 **/
2372FunctionalBindBuffersBaseTest::FunctionalBindBuffersBaseTest(deqp::Context& context)
2373	: TestCase(context, "functional_bind_buffers_base", "Verifies that BindBuffersBase works as expected")
2374{
2375	/* Nothing to be done */
2376}
2377
2378/** Execute test
2379 *
2380 * @return tcu::TestNode::STOP
2381 **/
2382tcu::TestNode::IterateResult FunctionalBindBuffersBaseTest::iterate()
2383{
2384	const Functions& gl = m_context.getRenderContext().getFunctions();
2385
2386#if DEBUG_ENBALE_MESSAGE_CALLBACK
2387	gl.debugMessageCallback(debug_proc, &m_context);
2388	GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
2389#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
2390
2391	for (size_t i = 0; i < s_n_buffer_tragets; ++i)
2392	{
2393		const GLenum	   pname_binding  = s_buffer_infos[i].m_pname_binding;
2394		const GLenum	   pname_max	  = s_buffer_infos[i].m_pname_max;
2395		const GLenum	   pname_max_size = s_buffer_infos[i].m_pname_max_size;
2396		const GLenum	   target		  = s_buffer_infos[i].m_target;
2397		const std::string& target_name	= glu::getBufferTargetStr(target).toString();
2398
2399		GLint max_buffers = 0;
2400		GLint max_size	= 0;
2401
2402		/* Get max */
2403		gl.getIntegerv(pname_max, &max_buffers);
2404		GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
2405
2406		/* Get max size */
2407		gl.getIntegerv(pname_max_size, &max_size);
2408		GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
2409
2410		GLintptr buffer_size = max_size / max_buffers;
2411
2412		/* Storage */
2413		std::vector<Buffer> buffer;
2414		std::vector<GLuint> buffer_ids;
2415
2416		buffer.resize(max_buffers);
2417		buffer_ids.resize(max_buffers);
2418
2419		/* Prepare buffers */
2420		for (GLint j = 0; j < max_buffers; ++j)
2421		{
2422			buffer[j].InitData(m_context, target, GL_DYNAMIC_COPY, buffer_size, 0 /* data */);
2423
2424			buffer_ids[j] = buffer[j].m_id;
2425		}
2426
2427		/*
2428		 * - execute BindBufferBase to bind all buffers to tested target;
2429		 * - inspect if bindings were modified;
2430		 */
2431		gl.bindBuffersBase(target, 0 /* first */, max_buffers /* count */, &buffer_ids[0]);
2432		GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffersBase");
2433
2434		for (GLint j = 0; j < max_buffers; ++j)
2435		{
2436			checkBinding(m_context, pname_binding, j, target_name, buffer_ids[j]);
2437		}
2438
2439		/*
2440		 *
2441		 * - execute BindBufferBase for first half of bindings with NULL as <buffers>
2442		 * to unbind first half of bindings for tested target;
2443		 * - inspect if bindings were modified;
2444		 * - execute BindBufferBase for second half of bindings with NULL as <buffers>
2445		 * to unbind rest of bindings;
2446		 * - inspect if bindings were modified;
2447		 */
2448		GLint half_index = max_buffers / 2;
2449		gl.bindBuffersBase(target, 0 /* first */, half_index /* count */, 0);
2450		GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffersBase");
2451
2452		for (GLint j = 0; j < half_index; ++j)
2453		{
2454			checkBinding(m_context, pname_binding, j, target_name, 0);
2455		}
2456
2457		for (GLint j = half_index; j < max_buffers; ++j)
2458		{
2459			checkBinding(m_context, pname_binding, j, target_name, buffer_ids[j]);
2460		}
2461
2462		gl.bindBuffersBase(target, half_index /* first */, max_buffers - half_index /* count */, 0);
2463		GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffersBase");
2464
2465		for (GLint j = 0; j < max_buffers; ++j)
2466		{
2467			checkBinding(m_context, pname_binding, j, target_name, 0);
2468		}
2469
2470		/*
2471		 * - change <buffers> so first entry is invalid;
2472		 * - execute BindBufferBase to bind all buffers to tested target; It is
2473		 * expected that INVALID_OPERATION will be generated;
2474		 * - inspect if all bindings but first were modified;
2475		 */
2476
2477		/* Find invalid id */
2478		GLuint invalid_id = 1;
2479		while (1)
2480		{
2481			if (GL_TRUE != gl.isBuffer(invalid_id))
2482			{
2483				break;
2484			}
2485
2486			invalid_id += 1;
2487		}
2488
2489		buffer_ids[0] = invalid_id;
2490
2491		gl.bindBuffersBase(target, 0 /* first */, max_buffers /* count */, &buffer_ids[0]);
2492		CHECK_ERROR(GL_INVALID_OPERATION, "BindBufferBase with invalid buffer id");
2493
2494		/* Update buffer_ids */
2495		buffer_ids[0] = 0; /* 0 means unbound */
2496
2497		for (GLint j = 0; j < max_buffers; ++j)
2498		{
2499			checkBinding(m_context, pname_binding, j, target_name, buffer_ids[j]);
2500		}
2501
2502		/*
2503		 * - bind any buffer to first binding;
2504		 * - execute BindBufferBase for 0 as <first>, 1 as <count> and <buffers> filled
2505		 * with zeros to unbind 1st binding for tested target;
2506		 * - inspect if bindings were modified;
2507		 */
2508		gl.bindBufferBase(target, 0, buffer[0].m_id);
2509		GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferBase");
2510		checkBinding(m_context, pname_binding, 0, target_name, buffer[0].m_id);
2511
2512		std::vector<GLuint> t_buffer_ids;
2513		t_buffer_ids.resize(max_buffers);
2514
2515		gl.bindBuffersBase(target, 0 /* first */, 1 /* count */, &t_buffer_ids[0]);
2516		GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffersBase");
2517
2518		for (GLint j = 0; j < max_buffers; ++j)
2519		{
2520			checkBinding(m_context, pname_binding, j, target_name, buffer_ids[j]);
2521		}
2522
2523		/* - unbind all buffers. */
2524		gl.bindBuffersBase(target, 0 /* first */, max_buffers /* count */, 0);
2525	}
2526
2527	/* Set result */
2528	m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
2529
2530	/* Done */
2531	return tcu::TestNode::STOP;
2532}
2533
2534/** Constructor
2535 *
2536 * @param context Test context
2537 **/
2538FunctionalBindBuffersRangeTest::FunctionalBindBuffersRangeTest(deqp::Context& context)
2539	: TestCase(context, "functional_bind_buffers_range", "Verifies that BindBuffersRange works as expected")
2540{
2541	/* Nothing to be done */
2542}
2543
2544/** Execute test
2545 *
2546 * @return tcu::TestNode::STOP
2547 **/
2548tcu::TestNode::IterateResult FunctionalBindBuffersRangeTest::iterate()
2549{
2550	const Functions& gl = m_context.getRenderContext().getFunctions();
2551
2552#if DEBUG_ENBALE_MESSAGE_CALLBACK
2553	gl.debugMessageCallback(debug_proc, &m_context);
2554	GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
2555#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
2556
2557	for (size_t i = 0; i < s_n_buffer_tragets; ++i)
2558	{
2559		const GLenum	   pname_binding  = s_buffer_infos[i].m_pname_binding;
2560		const GLenum	   pname_max	  = s_buffer_infos[i].m_pname_max;
2561		const GLenum	   pname_max_size = s_buffer_infos[i].m_pname_max_size;
2562		const GLenum	   target		  = s_buffer_infos[i].m_target;
2563		const std::string& target_name	= glu::getBufferTargetStr(target).toString();
2564
2565		GLint max_buffers = 0;
2566		GLint max_size	= 0;
2567
2568		/* Get max */
2569		gl.getIntegerv(pname_max, &max_buffers);
2570		GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
2571
2572		/* Get max size */
2573		gl.getIntegerv(pname_max_size, &max_size);
2574		GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
2575
2576		GLintptr buffer_size = max_size / max_buffers;
2577
2578		/* Storage */
2579		std::vector<Buffer>		buffer;
2580		std::vector<GLuint>		buffer_ids;
2581		std::vector<GLintptr>   offsets;
2582		std::vector<GLsizeiptr> sizes;
2583
2584		buffer.resize(max_buffers);
2585		buffer_ids.resize(max_buffers);
2586		offsets.resize(max_buffers);
2587		sizes.resize(max_buffers);
2588
2589		/* Prepare buffers */
2590		for (GLint j = 0; j < max_buffers; ++j)
2591		{
2592			buffer[j].InitData(m_context, target, GL_DYNAMIC_COPY, buffer_size, 0 /* data */);
2593
2594			buffer_ids[j] = buffer[j].m_id;
2595			offsets[j]	= 0;
2596			sizes[j]	  = buffer_size;
2597		}
2598
2599		/*
2600		 * - execute BindBufferBase to bind all buffers to tested target;
2601		 * - inspect if bindings were modified;
2602		 */
2603		gl.bindBuffersRange(target, 0 /* first */, max_buffers /* count */, &buffer_ids[0], &offsets[0], &sizes[0]);
2604		GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffersRange");
2605
2606		for (GLint j = 0; j < max_buffers; ++j)
2607		{
2608			checkBinding(m_context, pname_binding, j, target_name, buffer_ids[j]);
2609		}
2610
2611		/*
2612		 *
2613		 * - execute BindBufferBase for first half of bindings with NULL as <buffers>
2614		 * to unbind first half of bindings for tested target;
2615		 * - inspect if bindings were modified;
2616		 * - execute BindBufferBase for second half of bindings with NULL as <buffers>
2617		 * to unbind rest of bindings;
2618		 * - inspect if bindings were modified;
2619		 */
2620		GLint half_index = max_buffers / 2;
2621		gl.bindBuffersRange(target, 0 /* first */, half_index /* count */, 0, &offsets[0], &sizes[0]);
2622		GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffersRange");
2623
2624		for (GLint j = 0; j < half_index; ++j)
2625		{
2626			checkBinding(m_context, pname_binding, j, target_name, 0);
2627		}
2628
2629		for (GLint j = half_index; j < max_buffers; ++j)
2630		{
2631			checkBinding(m_context, pname_binding, j, target_name, buffer_ids[j]);
2632		}
2633
2634		gl.bindBuffersRange(target, half_index /* first */, max_buffers - half_index /* count */, 0, &offsets[0],
2635							&sizes[0]);
2636		GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffersRange");
2637
2638		for (GLint j = 0; j < max_buffers; ++j)
2639		{
2640			checkBinding(m_context, pname_binding, j, target_name, 0);
2641		}
2642
2643		/*
2644		 * - change <buffers> so first entry is invalid;
2645		 * - execute BindBufferBase to bind all buffers to tested target; It is
2646		 * expected that INVALID_OPERATION will be generated;
2647		 * - inspect if all bindings but first were modified;
2648		 */
2649
2650		/* Find invalid id */
2651		GLuint invalid_id = 1;
2652		while (1)
2653		{
2654			if (GL_TRUE != gl.isBuffer(invalid_id))
2655			{
2656				break;
2657			}
2658
2659			invalid_id += 1;
2660		}
2661
2662		buffer_ids[0] = invalid_id;
2663
2664		gl.bindBuffersRange(target, 0 /* first */, max_buffers /* count */, &buffer_ids[0], &offsets[0], &sizes[0]);
2665		CHECK_ERROR(GL_INVALID_OPERATION, "BindBuffersRange with invalid buffer id");
2666
2667		/* Update buffer_ids */
2668		buffer_ids[0] = 0; /* 0 means unbound */
2669
2670		for (GLint j = 0; j < max_buffers; ++j)
2671		{
2672			checkBinding(m_context, pname_binding, j, target_name, buffer_ids[j]);
2673		}
2674
2675		/*
2676		 * - bind any buffer to first binding;
2677		 * - execute BindBufferBase for 0 as <first>, 1 as <count> and <buffers> filled
2678		 * with zeros to unbind 1st binding for tested target;
2679		 * - inspect if bindings were modified;
2680		 */
2681		gl.bindBufferBase(target, 0, buffer[0].m_id);
2682		GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferBase");
2683		checkBinding(m_context, pname_binding, 0, target_name, buffer[0].m_id);
2684
2685		std::vector<GLuint> t_buffer_ids;
2686		t_buffer_ids.resize(max_buffers);
2687
2688		gl.bindBuffersRange(target, 0 /* first */, 1 /* count */, &t_buffer_ids[0], &offsets[0], &sizes[0]);
2689		GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffersRange");
2690
2691		for (GLint j = 0; j < max_buffers; ++j)
2692		{
2693			checkBinding(m_context, pname_binding, j, target_name, buffer_ids[j]);
2694		}
2695
2696		/* - unbind all buffers. */
2697		gl.bindBuffersBase(target, 0 /* first */, max_buffers /* count */, 0);
2698	}
2699
2700	/* Set result */
2701	m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
2702
2703	/* Done */
2704	return tcu::TestNode::STOP;
2705}
2706
2707/** Constructor
2708 *
2709 * @param context Test context
2710 **/
2711FunctionalBindTexturesTest::FunctionalBindTexturesTest(deqp::Context& context)
2712	: TestCase(context, "functional_bind_textures", "Verifies that BindTextures works as expected")
2713{
2714	/* Nothing to be done */
2715}
2716
2717/** Execute test
2718 *
2719 * @return tcu::TestNode::STOP
2720 **/
2721tcu::TestNode::IterateResult FunctionalBindTexturesTest::iterate()
2722{
2723	static const GLuint depth  = 6;
2724	static const GLuint height = 6;
2725	static const GLuint width  = 6;
2726
2727	const Functions& gl = m_context.getRenderContext().getFunctions();
2728
2729#if DEBUG_ENBALE_MESSAGE_CALLBACK
2730	gl.debugMessageCallback(debug_proc, &m_context);
2731	GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
2732#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
2733
2734	GLuint invalid_id   = 1; /* Start with 1, as 0 is not valid name */
2735	GLint  max_textures = 0;
2736
2737	/* Get max */
2738	gl.getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_textures);
2739	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
2740
2741	/* Storage */
2742	Buffer				 buffer;
2743	std::vector<Texture> texture;
2744	std::vector<GLuint>  texture_ids;
2745	std::vector<GLuint>  t_texture_ids;
2746
2747	texture.resize(max_textures);
2748	texture_ids.resize(max_textures);
2749	t_texture_ids.resize(max_textures);
2750
2751	/* Prepare buffer */
2752	buffer.InitData(m_context, GL_TEXTURE_BUFFER, GL_DYNAMIC_COPY, 16 /* size */, 0 /* data */);
2753
2754	/* Prepare textures */
2755	for (size_t i = 0; i < s_n_texture_tragets; ++i)
2756	{
2757		const GLenum target = s_texture_infos[i].m_target;
2758
2759		if (GL_TEXTURE_BUFFER != target)
2760		{
2761			texture[i].InitStorage(m_context, target, 1, GL_RGBA8, width, height, depth);
2762		}
2763		else
2764		{
2765			texture[i].InitBuffer(m_context, GL_RGBA8, buffer.m_id);
2766		}
2767
2768		/* Unbind */
2769		Texture::Bind(gl, 0, target);
2770	}
2771
2772	for (GLint i = s_n_texture_tragets; i < max_textures; ++i)
2773	{
2774		texture[i].InitStorage(m_context, GL_TEXTURE_2D, 1, GL_RGBA8, width, height, depth);
2775	}
2776
2777	/* Unbind */
2778	Texture::Bind(gl, 0, GL_TEXTURE_2D);
2779
2780	for (GLint i = 0; i < max_textures; ++i)
2781	{
2782		texture_ids[i] = texture[i].m_id;
2783	}
2784
2785	/*
2786	 * - execute BindTextures to bind all textures;
2787	 * - inspect bindings of all texture units to verify that proper bindings were
2788	 * set;
2789	 */
2790	gl.bindTextures(0, max_textures, &texture_ids[0]);
2791	GLU_EXPECT_NO_ERROR(gl.getError(), "BindTextures");
2792
2793	for (GLint i = 0; i < max_textures; ++i)
2794	{
2795		checkTextureBinding(m_context, getBinding(i), i, texture_ids[i]);
2796	}
2797
2798	/*
2799	 * - execute BindTextures for the first half of units with <textures> filled
2800	 * with zeros, to unbind those units;
2801	 * - inspect bindings of all texture units to verify that proper bindings were
2802	 * unbound;
2803	 */
2804	GLint half_index = max_textures / 2;
2805
2806	for (GLint i = 0; i < max_textures; ++i)
2807	{
2808		t_texture_ids[i] = 0;
2809	}
2810
2811	gl.bindTextures(0, half_index, &t_texture_ids[0]);
2812	GLU_EXPECT_NO_ERROR(gl.getError(), "BindTextures");
2813
2814	for (GLint i = 0; i < half_index; ++i)
2815	{
2816		checkTextureBinding(m_context, getBinding(i), i, 0);
2817	}
2818
2819	for (GLint i = half_index; i < max_textures; ++i)
2820	{
2821		checkTextureBinding(m_context, getBinding(i), i, texture_ids[i]);
2822	}
2823
2824	/*
2825	 * - execute BindTextures for the second half of units with NULL as<textures>,
2826	 * to unbind those units;
2827	 * - inspect bindings of all texture units to verify that proper bindings were
2828	 * unbound;
2829	 */
2830	gl.bindTextures(half_index, max_textures - half_index, 0);
2831	GLU_EXPECT_NO_ERROR(gl.getError(), "BindTextures");
2832
2833	for (GLint i = 0; i < max_textures; ++i)
2834	{
2835		checkTextureBinding(m_context, getBinding(i), i, 0);
2836	}
2837
2838	/*
2839	 * - modify <textures> so first entry is invalid;
2840	 * - execute BindTextures to bind all textures; It is expected that
2841	 * INVALID_OPERATION will be generated;
2842	 * - inspect bindings of all texture units to verify that proper bindings were
2843	 * set;
2844	 */
2845
2846	/* Find invalid id */
2847	while (1)
2848	{
2849		if (GL_TRUE != gl.isTexture(invalid_id))
2850		{
2851			break;
2852		}
2853
2854		invalid_id += 1;
2855	}
2856
2857	/* Set invalid id */
2858	texture_ids[0] = invalid_id;
2859
2860	gl.bindTextures(0, max_textures, &texture_ids[0]);
2861	CHECK_ERROR(GL_INVALID_OPERATION, "BindTextures with invalid texture id");
2862
2863	checkTextureBinding(m_context, getBinding(0), 0, 0);
2864	for (GLint i = 1; i < max_textures; ++i)
2865	{
2866		checkTextureBinding(m_context, getBinding(i), i, texture_ids[i]);
2867	}
2868
2869	/* - unbind all textures. */
2870	gl.bindTextures(0, max_textures, 0);
2871	GLU_EXPECT_NO_ERROR(gl.getError(), "BindTextures");
2872
2873	/* Set result */
2874	m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
2875
2876	/* Done */
2877	return tcu::TestNode::STOP;
2878}
2879
2880/** Constructor
2881 *
2882 * @param context Test context
2883 **/
2884FunctionalBindSamplersTest::FunctionalBindSamplersTest(deqp::Context& context)
2885	: TestCase(context, "functional_bind_samplers", "Verifies that BindSamplers works as expected")
2886{
2887	/* Nothing to be done */
2888}
2889
2890/** Execute test
2891 *
2892 * @return tcu::TestNode::STOP
2893 **/
2894tcu::TestNode::IterateResult FunctionalBindSamplersTest::iterate()
2895{
2896	const Functions& gl = m_context.getRenderContext().getFunctions();
2897
2898#if DEBUG_ENBALE_MESSAGE_CALLBACK
2899	gl.debugMessageCallback(debug_proc, &m_context);
2900	GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
2901#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
2902
2903	GLuint invalid_id   = 1; /* Start with 1, as 0 is not valid name */
2904	GLint  max_samplers = 0;
2905
2906	/* Get max */
2907	gl.getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_samplers);
2908	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
2909
2910	/* Storage */
2911	std::vector<GLuint> sampler_ids;
2912	std::vector<GLuint> t_sampler_ids;
2913
2914	sampler_ids.resize(max_samplers);
2915	t_sampler_ids.resize(max_samplers);
2916
2917	for (GLint i = 0; i < max_samplers; ++i)
2918	{
2919		t_sampler_ids[i] = 0;
2920	}
2921
2922	/* Prepare samplers */
2923	gl.genSamplers(max_samplers, &sampler_ids[0]);
2924	GLU_EXPECT_NO_ERROR(gl.getError(), "GenSamplers");
2925
2926	try
2927	{
2928		/* - execute BindSamplers to bind all samplers;
2929		 * - inspect bindings to verify that proper samplers were set;
2930		 */
2931		gl.bindSamplers(0 /* first */, max_samplers /* count */, &sampler_ids[0]);
2932		GLU_EXPECT_NO_ERROR(gl.getError(), "BindSamplers");
2933
2934		for (GLint i = 0; i < max_samplers; ++i)
2935		{
2936			checkBinding(m_context, GL_SAMPLER_BINDING, i, "Sampler", sampler_ids[i]);
2937		}
2938
2939		/* - execute BindSamplers for first half of bindings with <samplers> filled
2940		 * with zeros, to unbind those samplers;
2941		 * - inspect bindings to verify that proper samplers were unbound;
2942		 */
2943		GLint half_index = max_samplers / 2;
2944
2945		gl.bindSamplers(0, half_index, &t_sampler_ids[0]);
2946		GLU_EXPECT_NO_ERROR(gl.getError(), "BindSamplers");
2947
2948		for (GLint i = 0; i < half_index; ++i)
2949		{
2950			checkBinding(m_context, GL_SAMPLER_BINDING, i, "Sampler", 0);
2951		}
2952
2953		for (GLint i = half_index; i < max_samplers; ++i)
2954		{
2955			checkBinding(m_context, GL_SAMPLER_BINDING, i, "Sampler", sampler_ids[i]);
2956		}
2957
2958		/* - execute BindSamplers for second half of bindings with NULL as <samplers>,
2959		 * to unbind those samplers;
2960		 * - inspect bindings to verify that proper samplers were unbound;
2961		 */
2962		gl.bindSamplers(half_index, max_samplers - half_index, 0);
2963		GLU_EXPECT_NO_ERROR(gl.getError(), "BindSamplers");
2964
2965		for (GLint i = 0; i < max_samplers; ++i)
2966		{
2967			checkBinding(m_context, GL_SAMPLER_BINDING, i, "Sampler", 0);
2968		}
2969
2970		/* - modify <samplers> so first entry is invalid;
2971		 * - execute BindSamplers to bind all samplers; It is expected that
2972		 * INVALID_OPERATION will be generated;
2973		 * - inspect bindings to verify that proper samplers were set;
2974		 */
2975
2976		/* Find invalid id */
2977		while (1)
2978		{
2979			if (GL_TRUE != gl.isSampler(invalid_id))
2980			{
2981				break;
2982			}
2983
2984			invalid_id += 1;
2985		}
2986
2987		/* Prepare ids */
2988		t_sampler_ids[0] = invalid_id;
2989
2990		for (GLint i = 1; i < max_samplers; ++i)
2991		{
2992			t_sampler_ids[i] = sampler_ids[i];
2993		}
2994
2995		/* Bind */
2996		gl.bindSamplers(0, max_samplers, &t_sampler_ids[0]);
2997		CHECK_ERROR(GL_INVALID_OPERATION, "BindSamplers with invalid sampler id");
2998
2999		/* Set 0 for invalid entry */
3000		t_sampler_ids[0] = 0;
3001
3002		for (GLint i = 0; i < max_samplers; ++i)
3003		{
3004			checkBinding(m_context, GL_SAMPLER_BINDING, i, "Sampler", t_sampler_ids[i]);
3005		}
3006
3007		/* - unbind all samplers. */
3008		gl.bindSamplers(0, max_samplers, 0);
3009		GLU_EXPECT_NO_ERROR(gl.getError(), "BindSamplers");
3010	}
3011	catch (const std::exception&)
3012	{
3013		gl.deleteSamplers(max_samplers, &sampler_ids[0]);
3014
3015		TCU_FAIL("Invalid error generated");
3016	}
3017
3018	/* Delete samplers */
3019	gl.deleteSamplers(max_samplers, &sampler_ids[0]);
3020
3021	/* Set result */
3022	m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
3023
3024	/* Done */
3025	return tcu::TestNode::STOP;
3026}
3027
3028/** Constructor
3029 *
3030 * @param context Test context
3031 **/
3032FunctionalBindImageTexturesTest::FunctionalBindImageTexturesTest(deqp::Context& context)
3033	: TestCase(context, "functional_bind_image_textures", "Verifies that BindImageTextures works as expected")
3034{
3035	/* Nothing to be done */
3036}
3037
3038/** Execute test
3039 *
3040 * @return tcu::TestNode::STOP
3041 **/
3042tcu::TestNode::IterateResult FunctionalBindImageTexturesTest::iterate()
3043{
3044	static const GLuint depth  = 6;
3045	static const GLuint height = 6;
3046	static const GLuint width  = 6;
3047
3048	const Functions& gl = m_context.getRenderContext().getFunctions();
3049
3050#if DEBUG_ENBALE_MESSAGE_CALLBACK
3051	gl.debugMessageCallback(debug_proc, &m_context);
3052	GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
3053#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
3054
3055	GLuint invalid_id   = 1; /* Start with 1, as 0 is not valid name */
3056	GLint  max_textures = 0;
3057
3058	/* Get max */
3059	gl.getIntegerv(GL_MAX_IMAGE_UNITS, &max_textures);
3060	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
3061
3062	/* Storage */
3063	Buffer				 buffer;
3064	std::vector<Texture> texture;
3065	std::vector<GLuint>  texture_ids;
3066	std::vector<GLuint>  t_texture_ids;
3067
3068	texture.resize(max_textures);
3069	texture_ids.resize(max_textures);
3070	t_texture_ids.resize(max_textures);
3071
3072	/* Prepare buffer */
3073	buffer.InitData(m_context, GL_TEXTURE_BUFFER, GL_DYNAMIC_COPY, 16 /* size */, 0 /* data */);
3074
3075	/* Prepare textures */
3076	for (GLint i = 0; i < (GLint)s_n_texture_tragets; ++i)
3077	{
3078		const GLenum target = s_texture_infos[i].m_target;
3079
3080		if (i >= max_textures)
3081		{
3082			break;
3083		}
3084
3085		if (GL_TEXTURE_BUFFER != target)
3086		{
3087			texture[i].InitStorage(m_context, target, 1, GL_RGBA8, width, height, depth);
3088		}
3089		else
3090		{
3091			texture[i].InitBuffer(m_context, GL_RGBA8, buffer.m_id);
3092		}
3093
3094		/* Unbind */
3095		Texture::Bind(gl, 0, target);
3096	}
3097
3098	for (GLint i = (GLint)s_n_texture_tragets; i < max_textures; ++i)
3099	{
3100		texture[i].InitStorage(m_context, GL_TEXTURE_2D, 1, GL_RGBA8, width, height, depth);
3101	}
3102
3103	/* Unbind */
3104	Texture::Bind(gl, 0, GL_TEXTURE_2D);
3105
3106	for (GLint i = 0; i < max_textures; ++i)
3107	{
3108		texture_ids[i] = texture[i].m_id;
3109	}
3110
3111	/*
3112	 * - execute BindImageTextures to bind all images;
3113	 * - inspect bindings to verify that proper images were set;
3114	 */
3115	gl.bindImageTextures(0, max_textures, &texture_ids[0]);
3116	GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTextures");
3117
3118	for (GLint i = 0; i < max_textures; ++i)
3119	{
3120		checkBinding(m_context, GL_IMAGE_BINDING_NAME, i, "Image unit", texture_ids[i]);
3121	}
3122
3123	/*
3124	 * - execute BindTextures for the first half of units with <textures> filled
3125	 * with zeros, to unbind those units;
3126	 * - inspect bindings of all texture units to verify that proper bindings were
3127	 * unbound;
3128	 */
3129	GLint half_index = max_textures / 2;
3130
3131	for (GLint i = 0; i < max_textures; ++i)
3132	{
3133		t_texture_ids[i] = 0;
3134	}
3135
3136	gl.bindImageTextures(0, half_index, &t_texture_ids[0]);
3137	GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTextures");
3138
3139	for (GLint i = 0; i < half_index; ++i)
3140	{
3141		checkBinding(m_context, GL_IMAGE_BINDING_NAME, i, "Image unit", 0);
3142	}
3143
3144	for (GLint i = half_index; i < max_textures; ++i)
3145	{
3146		checkBinding(m_context, GL_IMAGE_BINDING_NAME, i, "Image unit", texture_ids[i]);
3147	}
3148
3149	/*
3150	 * - execute BindTextures for the second half of units with NULL as<textures>,
3151	 * to unbind those units;
3152	 * - inspect bindings of all texture units to verify that proper bindings were
3153	 * unbound;
3154	 */
3155	gl.bindImageTextures(half_index, max_textures - half_index, 0);
3156	GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTextures");
3157
3158	for (GLint i = 0; i < max_textures; ++i)
3159	{
3160		checkBinding(m_context, GL_IMAGE_BINDING_NAME, i, "Image unit", 0);
3161	}
3162
3163	/*
3164	 * - modify <textures> so first entry is invalid;
3165	 * - execute BindTextures to bind all textures; It is expected that
3166	 * INVALID_OPERATION will be generated;
3167	 * - inspect bindings of all texture units to verify that proper bindings were
3168	 * set;
3169	 */
3170
3171	/* Find invalid id */
3172	while (1)
3173	{
3174		if (GL_TRUE != gl.isTexture(invalid_id))
3175		{
3176			break;
3177		}
3178
3179		invalid_id += 1;
3180	}
3181
3182	/* Set invalid id */
3183	texture_ids[0] = invalid_id;
3184
3185	gl.bindImageTextures(0, max_textures, &texture_ids[0]);
3186	CHECK_ERROR(GL_INVALID_OPERATION, "BindImageTextures with invalid texture id");
3187
3188	checkBinding(m_context, GL_IMAGE_BINDING_NAME, 0, "Image unit", 0);
3189	for (GLint i = 1; i < max_textures; ++i)
3190	{
3191		checkBinding(m_context, GL_IMAGE_BINDING_NAME, i, "Image unit", texture_ids[i]);
3192	}
3193
3194	/* - unbind all textures. */
3195	gl.bindImageTextures(0, max_textures, 0);
3196	GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTextures");
3197
3198	/* Set result */
3199	m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
3200
3201	/* Done */
3202	return tcu::TestNode::STOP;
3203}
3204
3205/** Constructor
3206 *
3207 * @param context Test context
3208 **/
3209FunctionalBindVertexBuffersTest::FunctionalBindVertexBuffersTest(deqp::Context& context)
3210	: TestCase(context, "functional_bind_vertex_buffers", "Verifies that BindVertexBuffers works as expected")
3211{
3212	/* Nothing to be done */
3213}
3214
3215/** Execute test
3216 *
3217 * @return tcu::TestNode::STOP
3218 **/
3219tcu::TestNode::IterateResult FunctionalBindVertexBuffersTest::iterate()
3220{
3221	const Functions& gl = m_context.getRenderContext().getFunctions();
3222
3223#if DEBUG_ENBALE_MESSAGE_CALLBACK
3224	gl.debugMessageCallback(debug_proc, &m_context);
3225	GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
3226#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
3227
3228	static const GLintptr buffer_size = 16;
3229	static const GLintptr offset	  = 4;
3230	static const GLsizei  stride	  = 4;
3231
3232	GLuint invalid_id  = 1; /* Start with 1, as 0 is not valid name */
3233	GLint  max_buffers = 0;
3234
3235	/* Get max */
3236	gl.getIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &max_buffers);
3237	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
3238
3239	/* Storage */
3240	std::vector<Buffer>   buffer;
3241	std::vector<GLuint>   buffer_ids;
3242	std::vector<GLintptr> offsets;
3243	std::vector<GLsizei>  strides;
3244	std::vector<GLuint>   t_buffer_ids;
3245
3246	buffer.resize(max_buffers);
3247	buffer_ids.resize(max_buffers);
3248	offsets.resize(max_buffers);
3249	strides.resize(max_buffers);
3250	t_buffer_ids.resize(max_buffers);
3251
3252	/* Prepare buffers */
3253	for (GLint i = 0; i < max_buffers; ++i)
3254	{
3255		buffer[i].InitData(m_context, GL_ARRAY_BUFFER, GL_DYNAMIC_COPY, buffer_size, 0 /* data */);
3256
3257		buffer_ids[i]   = buffer[i].m_id;
3258		offsets[i]		= offset;
3259		strides[i]		= stride;
3260		t_buffer_ids[i] = 0;
3261	}
3262
3263	GLuint vao = 0;
3264	gl.genVertexArrays(1, &vao);
3265	GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays");
3266	try
3267	{
3268		gl.bindVertexArray(vao);
3269		GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArrays");
3270
3271		/* - execute BindVertexBuffers to bind all buffer;
3272		 * - inspect bindings to verify that proper buffers were set;
3273		 */
3274		gl.bindVertexBuffers(0, max_buffers, &buffer_ids[0], &offsets[0], &strides[0]);
3275		GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexBuffers");
3276
3277		for (GLint i = 0; i < max_buffers; ++i)
3278		{
3279			checkVertexAttribBinding(m_context, i, buffer_ids[i]);
3280		}
3281
3282		/* - execute BindVertexBuffers for first half of bindings with <buffers> filled
3283		 * with zeros, to unbind those buffers;
3284		 * - inspect bindings to verify that proper buffers were unbound;
3285		 */
3286		GLint half_index = max_buffers / 2;
3287
3288		gl.bindVertexBuffers(0, half_index, &t_buffer_ids[0], &offsets[0], &strides[0]);
3289		GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexBuffers");
3290
3291		for (GLint i = 0; i < half_index; ++i)
3292		{
3293			checkVertexAttribBinding(m_context, i, 0);
3294		}
3295
3296		for (GLint i = half_index; i < max_buffers; ++i)
3297		{
3298			checkVertexAttribBinding(m_context, i, buffer_ids[i]);
3299		}
3300
3301		/* - execute BindVertexBuffers for second half of bindings with NULL as
3302		 * <buffers>, to unbind those buffers;
3303		 * - inspect bindings to verify that proper buffers were unbound;
3304		 */
3305		gl.bindVertexBuffers(half_index, max_buffers - half_index, 0, &offsets[0], &strides[0]);
3306		GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexBuffers");
3307
3308		for (GLint i = 0; i < max_buffers; ++i)
3309		{
3310			checkVertexAttribBinding(m_context, i, 0);
3311		}
3312
3313		/* - modify <buffers> so first entry is invalid;
3314		 * - execute BindVertexBuffers to bind all buffers; It is expected that
3315		 * INVALID_OPERATION will be generated;
3316		 * - inspect bindings to verify that proper buffers were set;
3317		 */
3318
3319		/* Find invalid id */
3320		while (1)
3321		{
3322			if (GL_TRUE != gl.isBuffer(invalid_id))
3323			{
3324				break;
3325			}
3326
3327			invalid_id += 1;
3328		}
3329
3330		buffer_ids[0] = invalid_id;
3331		gl.bindVertexBuffers(0, max_buffers, &buffer_ids[0], &offsets[0], &strides[0]);
3332		CHECK_ERROR(GL_INVALID_OPERATION, "BindVertexBuffers with invalid id");
3333
3334		checkVertexAttribBinding(m_context, 0, 0);
3335		for (GLint i = 1; i < max_buffers; ++i)
3336		{
3337			checkVertexAttribBinding(m_context, i, buffer_ids[i]);
3338		}
3339
3340		/* - unbind all buffers. */
3341		gl.bindVertexBuffers(0, max_buffers, 0, &offsets[0], &strides[0]);
3342		GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexBuffers");
3343	}
3344	catch (const std::exception&)
3345	{
3346		gl.deleteVertexArrays(1, &vao);
3347
3348		TCU_FAIL("Unexpected error generated");
3349	}
3350
3351	gl.deleteVertexArrays(1, &vao);
3352	GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteVertexArrays");
3353
3354	/* Set result */
3355	m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
3356
3357	/* Done */
3358	return tcu::TestNode::STOP;
3359}
3360
3361/** Constructor
3362 *
3363 * @param context Test context
3364 **/
3365DispatchBindBuffersBaseTest::DispatchBindBuffersBaseTest(deqp::Context& context)
3366	: TestCase(context, "dispatch_bind_buffers_base", "Tests BindBuffersBase with dispatch command")
3367{
3368	/* Nothing to be done */
3369}
3370
3371/** Execute test
3372 *
3373 * @return tcu::TestNode::STOP
3374 **/
3375tcu::TestNode::IterateResult DispatchBindBuffersBaseTest::iterate()
3376{
3377	static const GLchar* cs = "#version 440 core\n"
3378							  "\n"
3379							  "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
3380							  "\n"
3381							  "UBO_LIST\n"
3382							  "layout (std140, binding = 0) buffer SSB {\n"
3383							  "    vec4 sum;\n"
3384							  "} ssb;\n"
3385							  "\n"
3386							  "void main()\n"
3387							  "{\n"
3388							  "    ssb.sum = SUM_LIST;\n"
3389							  "}\n"
3390							  "\n";
3391
3392	static const GLchar* ubo = "layout (std140, binding = XXX) uniform BXXX { vec4 data; } bXXX;";
3393
3394	static const GLintptr buffer_size = 4 * sizeof(GLfloat);
3395
3396	const Functions& gl = m_context.getRenderContext().getFunctions();
3397
3398	bool test_result = true;
3399
3400#if DEBUG_ENBALE_MESSAGE_CALLBACK
3401	gl.debugMessageCallback(debug_proc, &m_context);
3402	GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
3403#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
3404
3405	GLint   max_buffers = 0;
3406	GLfloat sum[4]		= { 0.0f, 0.0f, 0.0f, 0.0f };
3407
3408	/* Get max */
3409	gl.getIntegerv(GL_MAX_COMPUTE_UNIFORM_BLOCKS, &max_buffers);
3410	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
3411
3412	/* UBO */
3413	/* Storage */
3414	std::vector<Buffer> uni_buffer;
3415	std::vector<GLuint> uni_buffer_ids;
3416
3417	uni_buffer.resize(max_buffers);
3418	uni_buffer_ids.resize(max_buffers);
3419
3420	/* Prepare buffers */
3421	for (GLint i = 0; i < max_buffers; ++i)
3422	{
3423		const GLfloat data[4] = {
3424			(GLfloat)(i * 4 + 0), (GLfloat)(i * 4 + 1), (GLfloat)(i * 4 + 2), (GLfloat)(i * 4 + 3),
3425		};
3426
3427		sum[0] += data[0];
3428		sum[1] += data[1];
3429		sum[2] += data[2];
3430		sum[3] += data[3];
3431
3432		uni_buffer[i].InitData(m_context, GL_UNIFORM_BUFFER, GL_DYNAMIC_COPY, buffer_size, data);
3433
3434		uni_buffer_ids[i] = uni_buffer[i].m_id;
3435	}
3436
3437	gl.bindBuffersBase(GL_UNIFORM_BUFFER, 0 /* first */, max_buffers /* count */, &uni_buffer_ids[0]);
3438	GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffersBase");
3439
3440	/* SSBO */
3441	Buffer ssb_buffer;
3442	ssb_buffer.InitData(m_context, GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, buffer_size, 0 /* data */);
3443
3444	ssb_buffer.BindBase(0);
3445
3446	/* Prepare program */
3447	size_t		ubo_position = 0;
3448	size_t		sum_position = 0;
3449	std::string cs_source	= cs;
3450	for (GLint i = 0; i < max_buffers; ++i)
3451	{
3452		size_t ubo_start_position = ubo_position;
3453		size_t sum_start_position = sum_position;
3454
3455		GLchar index[16];
3456
3457		sprintf(index, "%d", i);
3458
3459		/* Add entry to ubo list */
3460		replaceToken("UBO_LIST", ubo_position, "UBO\nUBO_LIST", cs_source);
3461		ubo_position = ubo_start_position;
3462
3463		replaceToken("UBO", ubo_position, ubo, cs_source);
3464		ubo_position = ubo_start_position;
3465
3466		replaceToken("XXX", ubo_position, index, cs_source);
3467		replaceToken("XXX", ubo_position, index, cs_source);
3468		replaceToken("XXX", ubo_position, index, cs_source);
3469
3470		/* Add entry to sum list */
3471		replaceToken("SUM_LIST", sum_position, "bXXX.data + SUM_LIST", cs_source);
3472		sum_position = sum_start_position;
3473
3474		replaceToken("XXX", sum_position, index, cs_source);
3475	}
3476
3477	/* Remove token for lists */
3478	replaceToken(" + SUM_LIST", sum_position, "", cs_source);
3479	replaceToken("UBO_LIST", ubo_position, "", cs_source);
3480
3481	Program program(m_context);
3482	program.Init(cs_source.c_str(), "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */);
3483
3484	program.Use();
3485
3486	gl.dispatchCompute(1, 1, 1);
3487	GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
3488
3489	gl.memoryBarrier(GL_ALL_BARRIER_BITS);
3490	GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
3491
3492	GLfloat* result = (GLfloat*)gl.mapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
3493	GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
3494
3495	if (0 != memcmp(result, sum, 4 * sizeof(GLfloat)))
3496	{
3497		test_result = false;
3498	}
3499
3500	gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
3501	gl.getError(); /* Ignore error */
3502
3503	/* Set result */
3504	if (true == test_result)
3505	{
3506		m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
3507	}
3508	else
3509	{
3510		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
3511	}
3512
3513	/* Done */
3514	return tcu::TestNode::STOP;
3515}
3516
3517/** Constructor
3518 *
3519 * @param context Test context
3520 **/
3521DispatchBindBuffersRangeTest::DispatchBindBuffersRangeTest(deqp::Context& context)
3522	: TestCase(context, "dispatch_bind_buffers_range", "Tests BindBuffersRange with dispatch command")
3523{
3524	/* Nothing to be done */
3525}
3526
3527/** Execute test
3528 *
3529 * @return tcu::TestNode::STOP
3530 **/
3531tcu::TestNode::IterateResult DispatchBindBuffersRangeTest::iterate()
3532{
3533	static const GLchar* cs = "#version 440 core\n"
3534							  "\n"
3535							  "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
3536							  "\n"
3537							  "layout (std140, binding = 0) uniform B0 { int data; } b0;"
3538							  "layout (std140, binding = 1) uniform B1 { int data; } b1;"
3539							  "layout (std140, binding = 2) uniform B2 { int data; } b2;"
3540							  "layout (std140, binding = 3) uniform B3 { int data; } b3;"
3541							  "\n"
3542							  "layout (std140, binding = 0) buffer SSB {\n"
3543							  "    int sum;\n"
3544							  "} ssb;\n"
3545							  "\n"
3546							  "void main()\n"
3547							  "{\n"
3548							  "    //ssb.sum = b1.data;// + b1.data + b2.data + b3.data;\n"
3549							  "    ssb.sum = b0.data + b1.data + b2.data + b3.data;\n"
3550							  "}\n"
3551							  "\n";
3552
3553	static const GLint  data[]	= { 0x00010001, 0x01000100 };
3554	static const size_t n_buffers = 4;
3555	static const GLint  sum		  = 0x02020202;
3556
3557	const Functions& gl = m_context.getRenderContext().getFunctions();
3558
3559	bool test_result = true;
3560
3561#if DEBUG_ENBALE_MESSAGE_CALLBACK
3562	gl.debugMessageCallback(debug_proc, &m_context);
3563	GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
3564#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
3565
3566	/* UBO */
3567	GLint offset_alignment = 0;
3568
3569	gl.getIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &offset_alignment);
3570	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
3571
3572	/* Storage */
3573	Buffer				 uni_buffer;
3574	GLuint				 uni_buffer_ids[n_buffers];
3575	std::vector<GLubyte> uni_data;
3576	GLintptr			 uni_offsets[n_buffers];
3577	GLintptr			 uni_sizes[n_buffers];
3578
3579	const size_t buffer_size = (n_buffers - 1) * offset_alignment + sizeof(GLint);
3580	uni_data.resize(buffer_size);
3581
3582	for (size_t i = 0; i < buffer_size; ++i)
3583	{
3584		uni_data[i] = 0xaa;
3585	}
3586
3587	for (size_t i = 0; i < n_buffers; ++i)
3588	{
3589		void*		dst = &uni_data[i * offset_alignment];
3590		const void* src = &data[(i % 2)];
3591
3592		memcpy(dst, src, sizeof(GLint));
3593	}
3594
3595	uni_buffer.InitData(m_context, GL_UNIFORM_BUFFER, GL_DYNAMIC_COPY, buffer_size, &uni_data[0]);
3596
3597	for (size_t i = 0; i < n_buffers; ++i)
3598	{
3599		uni_buffer_ids[i] = uni_buffer.m_id;
3600		uni_offsets[i]	= i * offset_alignment;
3601		uni_sizes[i]	  = sizeof(GLint);
3602	}
3603
3604	gl.bindBuffersRange(GL_UNIFORM_BUFFER, 0 /* first */, n_buffers /* count */, &uni_buffer_ids[0], &uni_offsets[0],
3605						&uni_sizes[0]);
3606	GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffersRange");
3607
3608	/* SSBO */
3609	Buffer ssb_buffer;
3610	ssb_buffer.InitData(m_context, GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, sizeof(GLint), 0 /* data */);
3611
3612	ssb_buffer.BindBase(0);
3613
3614	/* Prepare program */
3615	Program program(m_context);
3616	program.Init(cs, "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */);
3617
3618	program.Use();
3619
3620	gl.dispatchCompute(1, 1, 1);
3621	GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
3622
3623	gl.memoryBarrier(GL_ALL_BARRIER_BITS);
3624	GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
3625
3626	GLint* result = (GLint*)gl.mapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
3627	GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
3628
3629	if (0 != memcmp(result, &sum, sizeof(sum)))
3630	{
3631		test_result = false;
3632	}
3633
3634	gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
3635	gl.getError(); /* Ignore error */
3636
3637	/* Set result */
3638	if (true == test_result)
3639	{
3640		m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
3641	}
3642	else
3643	{
3644		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
3645	}
3646
3647	/* Done */
3648	return tcu::TestNode::STOP;
3649}
3650
3651/** Constructor
3652 *
3653 * @param context Test context
3654 **/
3655DispatchBindTexturesTest::DispatchBindTexturesTest(deqp::Context& context)
3656	: TestCase(context, "dispatch_bind_textures", "Tests BindTextures with dispatch command")
3657{
3658	/* Nothing to be done */
3659}
3660
3661/** Execute test
3662 *
3663 * @return tcu::TestNode::STOP
3664 **/
3665tcu::TestNode::IterateResult DispatchBindTexturesTest::iterate()
3666{
3667	static const GLchar* cs = "#version 440 core\n"
3668							  "\n"
3669							  "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
3670							  "\n"
3671							  "SAMPLER_LIST\n"
3672							  "layout (std140, binding = 0) buffer SSB {\n"
3673							  "    uint sum;\n"
3674							  "} ssb;\n"
3675							  "\n"
3676							  "void main()\n"
3677							  "{\n"
3678							  "    uvec4 sum = SUM_LIST;\n"
3679							  "    ssb.sum = sum.r\n;"
3680							  "}\n"
3681							  "\n";
3682
3683	static const GLchar* sampler = "layout (location = XXX) uniform SAMPLER sXXX;";
3684
3685	static const GLchar* sampling[] = {
3686		"texture(sXXX, COORDS)", "texture(sXXX, COORDS)",		"texture(sXXX, COORDS)",	  "texture(sXXX, COORDS)",
3687		"texture(sXXX, COORDS)", "texelFetch(sXXX, COORDS)",	"texture(sXXX, COORDS)",	  "texture(sXXX, COORDS)",
3688		"texture(sXXX, COORDS)", "texelFetch(sXXX, COORDS, 0)", "texelFetch(sXXX, COORDS, 0)"
3689	};
3690
3691	static const GLchar* samplers[] = { "usampler1D",	 "usampler1DArray", "usampler2D",		 "usampler2DArray",
3692										"usampler3D",	 "usamplerBuffer",  "usamplerCube",	 "usamplerCubeArray",
3693										"usampler2DRect", "usampler2DMS",	"usampler2DMSArray" };
3694
3695	static const GLchar* coordinates[] = {
3696		"0.5f",
3697		"vec2(0.5f, 0.0f)",
3698		"vec2(0.5f, 0.5f)",
3699		"vec3(0.5f, 0.5f, 0.0f)",
3700		"vec3(0.5f, 0.5f, 0.5f)",
3701		"0",
3702		"vec3(0.5f, 0.5f, 0.5f)",
3703		"vec4(0.5f, 0.5f, 0.5f, 0.0f)",
3704		"vec2(0.5f, 0.5f)",
3705		"ivec2(0, 0)",
3706		"ivec3(0, 0, 0)",
3707	};
3708
3709	static const GLuint depth  = 6;
3710	static const GLuint height = 6;
3711	static const GLuint width  = 6;
3712
3713	const Functions& gl = m_context.getRenderContext().getFunctions();
3714
3715	bool test_result = true;
3716
3717#if DEBUG_ENBALE_MESSAGE_CALLBACK
3718	gl.debugMessageCallback(debug_proc, &m_context);
3719	GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
3720#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
3721
3722	bool cs_filled_textures	= false;
3723
3724	GLint  max_textures		 = 0;
3725	GLint  max_image_samples = 0;
3726	GLuint sum				 = 0;
3727
3728	/* Get max */
3729	gl.getIntegerv(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, &max_textures);
3730	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
3731
3732	/* Check if load/store from multisampled images is supported */
3733	gl.getIntegerv(GL_MAX_IMAGE_SAMPLES, &max_image_samples);
3734	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
3735
3736	/* Textures */
3737	/* Storage */
3738	std::vector<Texture> texture;
3739	std::vector<GLuint>  texture_ids;
3740	Buffer				 texture_buffer;
3741
3742	texture.resize(max_textures);
3743	texture_ids.resize(max_textures);
3744
3745	/* Prepare */
3746	for (GLint i = 0; i < max_textures; ++i)
3747	{
3748		GLenum target = getTarget(i);
3749		if (target >= GL_TEXTURE_2D_MULTISAMPLE && max_image_samples < 2)
3750			target = GL_TEXTURE_2D;
3751
3752		GLuint data[width * height * depth];
3753
3754		for (GLuint j = 0; j < width * height * depth; ++j)
3755		{
3756			data[j] = i;
3757		}
3758
3759		sum += i;
3760
3761		bool is_array = false;
3762
3763		switch (target)
3764		{
3765		case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
3766			is_array = true;
3767		/* Intentional fallthrough */
3768
3769		case GL_TEXTURE_2D_MULTISAMPLE:
3770			texture[i].InitStorage(m_context, target, 1, GL_R32UI, width, height, depth);
3771			fillMSTexture(m_context, texture[i].m_id, i, is_array);
3772			cs_filled_textures = true;
3773			break;
3774
3775		case GL_TEXTURE_BUFFER:
3776			texture_buffer.InitData(m_context, GL_TEXTURE_BUFFER, GL_DYNAMIC_COPY, sizeof(data), data);
3777			texture[i].InitBuffer(m_context, GL_R32UI, texture_buffer.m_id);
3778			break;
3779
3780		default:
3781			texture[i].InitStorage(m_context, target, 1, GL_R32UI, width, height, depth);
3782			Texture::Bind(gl, texture[i].m_id, target);
3783			Texture::SubImage(gl, target, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height, depth,
3784							  GL_RED_INTEGER, GL_UNSIGNED_INT, &data);
3785			gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3786			gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3787			break;
3788		}
3789
3790		/* Clean */
3791		Texture::Bind(gl, 0, target);
3792
3793		texture_ids[i] = texture[i].m_id;
3794	}
3795
3796	/* Make sure fillMSTexture affects are seen in next compute dispatch */
3797	if (cs_filled_textures)
3798		gl.memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
3799
3800	gl.bindTextures(0 /* first */, max_textures /* count */, &texture_ids[0]);
3801	GLU_EXPECT_NO_ERROR(gl.getError(), "BindTextures");
3802
3803	/* SSBO */
3804	Buffer ssb_buffer;
3805	ssb_buffer.InitData(m_context, GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, sizeof(GLuint), 0 /* data */);
3806
3807	ssb_buffer.BindBase(0);
3808
3809	/* Prepare program */
3810	size_t		sam_position	 = 0;
3811	size_t		sum_position	 = 0;
3812	std::string cs_source		 = cs;
3813	GLint		max_target_index = (GLint)(max_image_samples >= 2 ? s_n_texture_tragets : s_n_texture_tragets - 2);
3814	for (GLint i = 0; i < max_textures; ++i)
3815	{
3816		size_t sam_start_position = sam_position;
3817		size_t sum_start_position = sum_position;
3818
3819		GLchar index[16];
3820
3821		sprintf(index, "%d", i);
3822
3823		const GLchar* coords		= 0;
3824		const GLchar* sampler_type  = 0;
3825		const GLchar* sampling_code = 0;
3826
3827		if (i < max_target_index)
3828		{
3829			coords		  = coordinates[i];
3830			sampler_type  = samplers[i];
3831			sampling_code = sampling[i];
3832		}
3833		else
3834		{
3835			coords		  = coordinates[2]; /* vec2(0.5f, 0.5f) */
3836			sampler_type  = samplers[2];	/* usampler2D */
3837			sampling_code = sampling[2];	/* texture(sXXX, COORDS) */
3838		}
3839
3840		/* Add entry to ubo list */
3841		replaceToken("SAMPLER_LIST", sam_position, "SAMPLER\nSAMPLER_LIST", cs_source);
3842		sam_position = sam_start_position;
3843
3844		replaceToken("SAMPLER", sam_position, sampler, cs_source);
3845		sam_position = sam_start_position;
3846
3847		replaceToken("XXX", sam_position, index, cs_source);
3848		replaceToken("SAMPLER", sam_position, sampler_type, cs_source);
3849		replaceToken("XXX", sam_position, index, cs_source);
3850
3851		/* Add entry to sum list */
3852		replaceToken("SUM_LIST", sum_position, "SAMPLING + SUM_LIST", cs_source);
3853		sum_position = sum_start_position;
3854
3855		replaceToken("SAMPLING", sum_position, sampling_code, cs_source);
3856		sum_position = sum_start_position;
3857
3858		replaceToken("XXX", sum_position, index, cs_source);
3859		replaceToken("COORDS", sum_position, coords, cs_source);
3860	}
3861
3862	/* Remove token for lists */
3863	replaceToken(" + SUM_LIST", sum_position, "", cs_source);
3864	replaceToken("SAMPLER_LIST", sam_position, "", cs_source);
3865
3866	Program program(m_context);
3867	program.Init(cs_source.c_str(), "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */);
3868
3869	program.Use();
3870
3871	/* Set samplers */
3872	for (GLint i = 0; i < max_textures; ++i)
3873	{
3874		gl.uniform1i(i, i);
3875		GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
3876	}
3877
3878	gl.dispatchCompute(1, 1, 1);
3879	GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
3880
3881	gl.memoryBarrier(GL_ALL_BARRIER_BITS);
3882	GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
3883
3884	GLuint* result = (GLuint*)gl.mapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
3885	GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
3886
3887	if (0 != memcmp(result, &sum, sizeof(sum)))
3888	{
3889		test_result = false;
3890	}
3891
3892	gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
3893	gl.getError(); /* Ignore error */
3894
3895	/* Set result */
3896	if (true == test_result)
3897	{
3898		m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
3899	}
3900	else
3901	{
3902		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
3903	}
3904
3905	/* Done */
3906	return tcu::TestNode::STOP;
3907}
3908
3909/** Constructor
3910 *
3911 * @param context Test context
3912 **/
3913DispatchBindImageTexturesTest::DispatchBindImageTexturesTest(deqp::Context& context)
3914	: TestCase(context, "dispatch_bind_image_textures", "Tests BindImageTextures with dispatch command")
3915{
3916	/* Nothing to be done */
3917}
3918
3919/** Execute test
3920 *
3921 * @return tcu::TestNode::STOP
3922 **/
3923tcu::TestNode::IterateResult DispatchBindImageTexturesTest::iterate()
3924{
3925	static const GLchar* cs = "#version 440 core\n"
3926							  "\n"
3927							  "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
3928							  "\n"
3929							  "IMAGE_LIST\n"
3930							  "layout (std140, binding = 0) buffer SSB {\n"
3931							  "    uint sum;\n"
3932							  "} ssb;\n"
3933							  "\n"
3934							  "void main()\n"
3935							  "{\n"
3936							  "    uvec4 sum = SUM_LIST;\n"
3937							  "    ssb.sum = sum.r\n;"
3938							  "}\n"
3939							  "\n";
3940
3941	static const GLchar* image = "layout (location = XXX, r32ui) readonly uniform IMAGE iXXX;";
3942
3943	static const GLchar* loading[] = {
3944		"imageLoad(iXXX, COORDS)", "imageLoad(iXXX, COORDS)",	"imageLoad(iXXX, COORDS)",   "imageLoad(iXXX, COORDS)",
3945		"imageLoad(iXXX, COORDS)", "imageLoad(iXXX, COORDS)",	"imageLoad(iXXX, COORDS)",   "imageLoad(iXXX, COORDS)",
3946		"imageLoad(iXXX, COORDS)", "imageLoad(iXXX, COORDS, 0)", "imageLoad(iXXX, COORDS, 0)"
3947	};
3948
3949	static const GLchar* images[] = { "uimage1D",	 "uimage1DArray", "uimage2D",		 "uimage2DArray",
3950									  "uimage3D",	 "uimageBuffer",  "uimageCube",	 "uimageCubeArray",
3951									  "uimage2DRect", "uimage2DMS",	"uimage2DMSArray" };
3952
3953	static const GLchar* coordinates[] = {
3954		"0",
3955		"ivec2(0, 0)",
3956		"ivec2(0, 0)",
3957		"ivec3(0, 0, 0)",
3958		"ivec3(0, 0, 0)",
3959		"0",
3960		"ivec3(0, 0, 0)",
3961		"ivec3(0, 0, 0)",
3962		"ivec2(0, 0)",
3963		"ivec2(0, 0)",
3964		"ivec3(0, 0, 0)",
3965	};
3966
3967	static const GLuint depth  = 6;
3968	static const GLuint height = 6;
3969	static const GLuint width  = 6;
3970
3971	const Functions& gl = m_context.getRenderContext().getFunctions();
3972
3973	bool test_result = true;
3974
3975#if DEBUG_ENBALE_MESSAGE_CALLBACK
3976	gl.debugMessageCallback(debug_proc, &m_context);
3977	GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
3978#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
3979
3980	bool cs_filled_textures = false;
3981
3982	GLint  max_textures		 = 0;
3983	GLint  max_image_samples = 0;
3984	GLuint sum				 = 0;
3985
3986	/* Get max */
3987	gl.getIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, &max_textures);
3988	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
3989
3990	/* Check if load/store from multisampled images is supported */
3991	gl.getIntegerv(GL_MAX_IMAGE_SAMPLES, &max_image_samples);
3992	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
3993
3994	/* Textures */
3995	/* Storage */
3996	std::vector<Texture> texture;
3997	std::vector<GLuint>  texture_ids;
3998	Buffer				 texture_buffer;
3999
4000	texture.resize(max_textures);
4001	texture_ids.resize(max_textures);
4002
4003	/* Prepare */
4004	for (GLint i = 0; i < max_textures; ++i)
4005	{
4006		GLenum target = getTarget(i);
4007		if (target >= GL_TEXTURE_2D_MULTISAMPLE && max_image_samples == 0)
4008			target = GL_TEXTURE_2D;
4009
4010		GLuint data[width * height * depth];
4011
4012		for (GLuint j = 0; j < width * height * depth; ++j)
4013		{
4014			data[j] = i;
4015		}
4016
4017		sum += i;
4018
4019		bool is_array = false;
4020
4021		switch (target)
4022		{
4023		case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
4024			is_array = true;
4025		/* Intentional fallthrough */
4026
4027		case GL_TEXTURE_2D_MULTISAMPLE:
4028			texture[i].InitStorage(m_context, target, 1, GL_R32UI, width, height, depth);
4029			fillMSTexture(m_context, texture[i].m_id, i, is_array);
4030			cs_filled_textures = true;
4031			break;
4032
4033		case GL_TEXTURE_BUFFER:
4034			texture_buffer.InitData(m_context, GL_TEXTURE_BUFFER, GL_DYNAMIC_COPY, sizeof(data), data);
4035			texture[i].InitBuffer(m_context, GL_R32UI, texture_buffer.m_id);
4036			break;
4037
4038		default:
4039			texture[i].InitStorage(m_context, target, 1, GL_R32UI, width, height, depth);
4040			Texture::Bind(gl, texture[i].m_id, target);
4041			Texture::SubImage(gl, target, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height, depth,
4042							  GL_RED_INTEGER, GL_UNSIGNED_INT, &data);
4043			break;
4044		}
4045
4046		/* Clean */
4047		Texture::Bind(gl, 0, target);
4048
4049		texture_ids[i] = texture[i].m_id;
4050	}
4051
4052	/* Make sure fillMSTexture affects are seen in next compute dispatch */
4053	if (cs_filled_textures)
4054		gl.memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
4055
4056	gl.bindImageTextures(0 /* first */, max_textures /* count */, &texture_ids[0]);
4057	GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTextures");
4058
4059	/* SSBO */
4060	Buffer ssb_buffer;
4061	ssb_buffer.InitData(m_context, GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, sizeof(GLuint), 0 /* data */);
4062
4063	ssb_buffer.BindBase(0);
4064
4065	/* Prepare program */
4066	size_t		load_position	= 0;
4067	size_t		sum_position	 = 0;
4068	std::string cs_source		 = cs;
4069	GLint		max_target_index = (GLint)(max_image_samples > 0 ? s_n_texture_tragets : s_n_texture_tragets - 2);
4070	for (GLint i = 0; i < max_textures; ++i)
4071	{
4072		size_t load_start_position = load_position;
4073		size_t sum_start_position  = sum_position;
4074
4075		GLchar index[16];
4076
4077		sprintf(index, "%d", i);
4078
4079		const GLchar* coords	   = 0;
4080		const GLchar* image_type   = 0;
4081		const GLchar* loading_code = 0;
4082
4083		if (i < max_target_index)
4084		{
4085			coords		 = coordinates[i];
4086			image_type   = images[i];
4087			loading_code = loading[i];
4088		}
4089		else
4090		{
4091			coords		 = coordinates[2]; /* vec2(0.5f, 0.5f) */
4092			image_type   = images[2];	  /* usampler2D */
4093			loading_code = loading[2];	 /* texture(sXXX, COORDS) */
4094		}
4095
4096		/* Add entry to ubo list */
4097		replaceToken("IMAGE_LIST", load_position, "IMAGE\nIMAGE_LIST", cs_source);
4098		load_position = load_start_position;
4099
4100		replaceToken("IMAGE", load_position, image, cs_source);
4101		load_position = load_start_position;
4102
4103		replaceToken("XXX", load_position, index, cs_source);
4104		replaceToken("IMAGE", load_position, image_type, cs_source);
4105		replaceToken("XXX", load_position, index, cs_source);
4106
4107		/* Add entry to sum list */
4108		replaceToken("SUM_LIST", sum_position, "LOADING + SUM_LIST", cs_source);
4109		sum_position = sum_start_position;
4110
4111		replaceToken("LOADING", sum_position, loading_code, cs_source);
4112		sum_position = sum_start_position;
4113
4114		replaceToken("XXX", sum_position, index, cs_source);
4115		replaceToken("COORDS", sum_position, coords, cs_source);
4116	}
4117
4118	/* Remove token for lists */
4119	replaceToken(" + SUM_LIST", sum_position, "", cs_source);
4120	replaceToken("IMAGE_LIST", load_position, "", cs_source);
4121
4122	Program program(m_context);
4123	program.Init(cs_source.c_str(), "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */);
4124
4125	program.Use();
4126
4127	/* Set images */
4128	for (GLint i = 0; i < max_textures; ++i)
4129	{
4130		gl.uniform1i(i, i);
4131		GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
4132	}
4133
4134	gl.dispatchCompute(1, 1, 1);
4135	GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
4136
4137	gl.memoryBarrier(GL_ALL_BARRIER_BITS);
4138	GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
4139
4140	GLuint* result = (GLuint*)gl.mapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
4141	GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
4142
4143	if (0 != memcmp(result, &sum, sizeof(sum)))
4144	{
4145		test_result = false;
4146	}
4147
4148	gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
4149	gl.getError(); /* Ignore error */
4150
4151	/* Set result */
4152	if (true == test_result)
4153	{
4154		m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
4155	}
4156	else
4157	{
4158		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
4159	}
4160
4161	/* Done */
4162	return tcu::TestNode::STOP;
4163}
4164
4165/** Constructor
4166 *
4167 * @param context Test context
4168 **/
4169DispatchBindSamplersTest::DispatchBindSamplersTest(deqp::Context& context)
4170	: TestCase(context, "dispatch_bind_samplers", "Tests BindSamplers with dispatch command")
4171{
4172	/* Nothing to be done */
4173}
4174
4175/** Execute test
4176 *
4177 * @return tcu::TestNode::STOP
4178 **/
4179tcu::TestNode::IterateResult DispatchBindSamplersTest::iterate()
4180{
4181	static const GLchar* cs = "#version 440 core\n"
4182							  "\n"
4183							  "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
4184							  "\n"
4185							  "SAMPLER_LIST\n"
4186							  "layout (std140, binding = 0) buffer SSB {\n"
4187							  "    uint sum;\n"
4188							  "} ssb;\n"
4189							  "\n"
4190							  "void main()\n"
4191							  "{\n"
4192							  "    uvec4 sum = SUM_LIST;\n"
4193							  "    ssb.sum = sum.r\n;"
4194							  "}\n"
4195							  "\n";
4196
4197	static const GLchar* sampler = "layout (location = XXX) uniform usampler2D sXXX;";
4198
4199	static const GLchar* sampling = "texture(sXXX, vec2(1.5f, 0.5f))";
4200
4201	static const GLuint depth  = 1;
4202	static const GLuint height = 8;
4203	static const GLuint width  = 8;
4204
4205	const Functions& gl = m_context.getRenderContext().getFunctions();
4206
4207	bool test_result = true;
4208
4209#if DEBUG_ENBALE_MESSAGE_CALLBACK
4210	gl.debugMessageCallback(debug_proc, &m_context);
4211	GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
4212#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
4213
4214	GLint max_textures = 0;
4215
4216	/* Get max */
4217	gl.getIntegerv(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, &max_textures);
4218	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
4219
4220	/* Textures */
4221	/* Storage */
4222	std::vector<GLuint>  sampler_ids;
4223	std::vector<Texture> texture;
4224	std::vector<GLuint>  texture_ids;
4225
4226	sampler_ids.resize(max_textures);
4227	texture.resize(max_textures);
4228	texture_ids.resize(max_textures);
4229
4230	GLuint data[width * height * depth];
4231
4232	for (GLuint j = 0; j < width * height; ++j)
4233	{
4234		data[j] = 0;
4235	}
4236
4237	{
4238		const size_t last_line_offset		   = (height - 1) * width;
4239		const size_t last_pixel_in_line_offset = width - 1;
4240
4241		for (GLuint j = 0; j < width; ++j)
4242		{
4243			data[j]					   = 1;
4244			data[j + last_line_offset] = 1;
4245		}
4246
4247		for (GLuint j = 0; j < height; ++j)
4248		{
4249			const size_t line_offset = j * width;
4250
4251			data[line_offset]							  = 1;
4252			data[line_offset + last_pixel_in_line_offset] = 1;
4253		}
4254	}
4255
4256	/* Prepare */
4257	for (GLint i = 0; i < max_textures; ++i)
4258	{
4259		texture[i].InitStorage(m_context, GL_TEXTURE_2D, 1, GL_R32UI, width, height, depth);
4260		Texture::Bind(gl, texture[i].m_id, GL_TEXTURE_2D);
4261		Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height, depth,
4262						  GL_RED_INTEGER, GL_UNSIGNED_INT, &data);
4263
4264		texture_ids[i] = texture[i].m_id;
4265	}
4266
4267	/* Clean */
4268	Texture::Bind(gl, 0, GL_TEXTURE_2D);
4269
4270	/* Execute the test */
4271	gl.bindTextures(0 /* first */, max_textures /* count */, &texture_ids[0]);
4272	GLU_EXPECT_NO_ERROR(gl.getError(), "BindTextures");
4273
4274	/* SSBO */
4275	Buffer ssb_buffer;
4276	ssb_buffer.InitData(m_context, GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, sizeof(GLuint), 0 /* data */);
4277
4278	ssb_buffer.BindBase(0);
4279
4280	/* Prepare program */
4281	size_t		sam_position = 0;
4282	size_t		sum_position = 0;
4283	std::string cs_source	= cs;
4284
4285	for (GLint i = 0; i < max_textures; ++i)
4286	{
4287		size_t sam_start_position = sam_position;
4288		size_t sum_start_position = sum_position;
4289
4290		GLchar index[16];
4291
4292		sprintf(index, "%d", i);
4293
4294		/* Add entry to ubo list */
4295		replaceToken("SAMPLER_LIST", sam_position, "SAMPLER\nSAMPLER_LIST", cs_source);
4296		sam_position = sam_start_position;
4297
4298		replaceToken("SAMPLER", sam_position, sampler, cs_source);
4299		sam_position = sam_start_position;
4300
4301		replaceToken("XXX", sam_position, index, cs_source);
4302		replaceToken("XXX", sam_position, index, cs_source);
4303
4304		/* Add entry to sum list */
4305		replaceToken("SUM_LIST", sum_position, "SAMPLING + SUM_LIST", cs_source);
4306		sum_position = sum_start_position;
4307
4308		replaceToken("SAMPLING", sum_position, sampling, cs_source);
4309		sum_position = sum_start_position;
4310
4311		replaceToken("XXX", sum_position, index, cs_source);
4312	}
4313
4314	/* Remove token for lists */
4315	replaceToken(" + SUM_LIST", sum_position, "", cs_source);
4316	replaceToken("SAMPLER_LIST", sam_position, "", cs_source);
4317
4318	Program program(m_context);
4319	program.Init(cs_source.c_str(), "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */);
4320
4321	program.Use();
4322
4323	/* Set texture units */
4324	for (GLint i = 0; i < max_textures; ++i)
4325	{
4326		gl.uniform1i(i, i);
4327		GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i");
4328	}
4329
4330	/* Prepare samplers */
4331	gl.genSamplers(max_textures, &sampler_ids[0]);
4332	GLU_EXPECT_NO_ERROR(gl.getError(), "GenSamplers");
4333
4334	try
4335	{
4336		gl.bindSamplers(0 /* first */, max_textures /* count */, &sampler_ids[0]);
4337		GLU_EXPECT_NO_ERROR(gl.getError(), "BindSamplers");
4338
4339		for (GLint i = 0; i < max_textures; ++i)
4340		{
4341			gl.samplerParameteri(sampler_ids[i], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
4342			gl.samplerParameteri(sampler_ids[i], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4343			gl.samplerParameteri(sampler_ids[i], GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4344			GLU_EXPECT_NO_ERROR(gl.getError(), "SamplerParameteri");
4345		}
4346
4347		gl.dispatchCompute(1, 1, 1);
4348		GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
4349
4350		gl.memoryBarrier(GL_ALL_BARRIER_BITS);
4351		GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier");
4352	}
4353	catch (const std::exception&)
4354	{
4355		gl.deleteSamplers(max_textures, &sampler_ids[0]);
4356
4357		TCU_FAIL("Unexpected error generated");
4358	}
4359
4360	/* Remove samplers */
4361	gl.deleteSamplers(max_textures, &sampler_ids[0]);
4362
4363	/* Verify results */
4364	GLuint* result = (GLuint*)gl.mapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
4365	GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
4366
4367	if (0 != memcmp(result, &max_textures, sizeof(max_textures)))
4368	{
4369		test_result = false;
4370	}
4371
4372	gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
4373	gl.getError(); /* Ignore error */
4374
4375	/* Set result */
4376	if (true == test_result)
4377	{
4378		m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
4379	}
4380	else
4381	{
4382		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
4383	}
4384
4385	/* Done */
4386	return tcu::TestNode::STOP;
4387}
4388
4389/** Constructor
4390 *
4391 * @param context Test context
4392 **/
4393DrawBindVertexBuffersTest::DrawBindVertexBuffersTest(deqp::Context& context)
4394	: TestCase(context, "draw_bind_vertex_buffers", "Tests BindVertexBuffers command with drawArrays")
4395{
4396	/* Nothing to be done */
4397}
4398
4399/** Execute test
4400 *
4401 * @return tcu::TestNode::STOP
4402 **/
4403tcu::TestNode::IterateResult DrawBindVertexBuffersTest::iterate()
4404{
4405	static const GLchar* vs = "#version 440 core\n"
4406							  "\n"
4407							  "ATTRIBUTE_LIST\n"
4408							  "\n"
4409							  "out vec4 vs_gs_sum;\n"
4410							  "\n"
4411							  "void main()\n"
4412							  "{\n"
4413							  "    vs_gs_sum = SUM_LIST;\n"
4414							  "}\n"
4415							  "\n";
4416
4417	static const GLchar* gs = "#version 440 core\n"
4418							  "\n"
4419							  "layout(points)                           in;\n"
4420							  "layout(triangle_strip, max_vertices = 4) out;\n"
4421							  "\n"
4422							  "in  vec4 vs_gs_sum[];\n"
4423							  "out vec4 gs_fs_sum;\n"
4424							  "\n"
4425							  "void main()\n"
4426							  "{\n"
4427							  "    gs_fs_sum   = vs_gs_sum[0];\n"
4428							  "    gl_Position = vec4(-1, -1, 0, 1);\n"
4429							  "    EmitVertex();\n"
4430							  "    gs_fs_sum   = vs_gs_sum[0];\n"
4431							  "    gl_Position = vec4(-1, 1, 0, 1);\n"
4432							  "    EmitVertex();\n"
4433							  "    gs_fs_sum   = vs_gs_sum[0];\n"
4434							  "    gl_Position = vec4(1, -1, 0, 1);\n"
4435							  "    EmitVertex();\n"
4436							  "    gs_fs_sum   = vs_gs_sum[0];\n"
4437							  "    gl_Position = vec4(1, 1, 0, 1);\n"
4438							  "    EmitVertex();\n"
4439							  "}\n"
4440							  "\n";
4441
4442	static const GLchar* fs = "#version 440 core\n"
4443							  "\n"
4444							  "in  vec4 gs_fs_sum;\n"
4445							  "out vec4 fs_out;\n"
4446							  "\n"
4447							  "void main()\n"
4448							  "{\n"
4449							  "    fs_out = gs_fs_sum;\n"
4450							  "}\n"
4451							  "\n";
4452
4453	static const GLchar* attribute = "layout (location = XXX) in vec4 aXXX;";
4454
4455	static const GLuint height = 8;
4456	static const GLuint width  = 8;
4457
4458	const Functions& gl = m_context.getRenderContext().getFunctions();
4459
4460	bool test_result = true;
4461
4462#if DEBUG_ENBALE_MESSAGE_CALLBACK
4463	gl.debugMessageCallback(debug_proc, &m_context);
4464	GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback");
4465#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
4466
4467	static const GLintptr attribute_size = 4 * sizeof(GLfloat);
4468
4469	GLint  max_buffers = 0;
4470	GLuint vao		   = 0;
4471
4472	/* Get max */
4473	gl.getIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &max_buffers);
4474	GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
4475
4476	/* Storage */
4477	Buffer				  buffer;
4478	std::vector<GLuint>   buffer_ids;
4479	std::vector<GLfloat>  data;
4480	std::vector<GLintptr> offsets;
4481	std::vector<GLsizei>  strides;
4482
4483	buffer_ids.resize(max_buffers);
4484	data.resize(max_buffers * 4);
4485	offsets.resize(max_buffers);
4486	strides.resize(max_buffers);
4487
4488	/* Prepare data */
4489	const GLfloat value = 1.0f / (GLfloat)max_buffers;
4490
4491	for (GLint i = 0; i < max_buffers; ++i)
4492	{
4493		data[i * 4 + 0] = value;
4494		data[i * 4 + 1] = value;
4495		data[i * 4 + 2] = value;
4496		data[i * 4 + 3] = value;
4497	}
4498
4499	/* Prepare buffer */
4500	buffer.InitData(m_context, GL_ARRAY_BUFFER, GL_DYNAMIC_COPY, data.size() * sizeof(GLfloat), &data[0]);
4501
4502	for (GLint i = 0; i < max_buffers; ++i)
4503	{
4504		buffer_ids[i] = buffer.m_id;
4505		offsets[i]	= i * attribute_size;
4506		strides[i]	= attribute_size;
4507	}
4508
4509	/* Prepare FBO */
4510	Framebuffer framebuffer(m_context);
4511	Texture		texture;
4512
4513	texture.InitStorage(m_context, GL_TEXTURE_2D, 1 /* levels */, GL_RGBA8, width, height, 1 /* depth */);
4514
4515	/* */
4516	Framebuffer::Generate(gl, framebuffer.m_id);
4517	Framebuffer::Bind(gl, GL_DRAW_FRAMEBUFFER, framebuffer.m_id);
4518	Framebuffer::AttachTexture(gl, GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.m_id, 0 /* level */, width,
4519							   height);
4520
4521	/* Prepare program */
4522	size_t		attr_position = 0;
4523	size_t		sum_position  = 0;
4524	std::string vs_source	 = vs;
4525	for (GLint i = 0; i < max_buffers; ++i)
4526	{
4527		size_t attr_start_position = attr_position;
4528		size_t sum_start_position  = sum_position;
4529
4530		GLchar index[16];
4531
4532		sprintf(index, "%d", i);
4533
4534		/* Add entry to ubo list */
4535		replaceToken("ATTRIBUTE_LIST", attr_position, "ATTRIBUTE\nATTRIBUTE_LIST", vs_source);
4536		attr_position = attr_start_position;
4537
4538		replaceToken("ATTRIBUTE", attr_position, attribute, vs_source);
4539		attr_position = attr_start_position;
4540
4541		replaceToken("XXX", attr_position, index, vs_source);
4542		replaceToken("XXX", attr_position, index, vs_source);
4543
4544		/* Add entry to sum list */
4545		replaceToken("SUM_LIST", sum_position, "aXXX + SUM_LIST", vs_source);
4546		sum_position = sum_start_position;
4547
4548		replaceToken("XXX", sum_position, index, vs_source);
4549	}
4550
4551	/* Remove token for lists */
4552	replaceToken(" + SUM_LIST", sum_position, "", vs_source);
4553	replaceToken("ATTRIBUTE_LIST", attr_position, "", vs_source);
4554
4555	Program program(m_context);
4556	program.Init("" /* cs */, fs, gs, "" /* tcs */, "" /* tes */, vs_source.c_str());
4557
4558	program.Use();
4559
4560	gl.genVertexArrays(1, &vao);
4561	GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays");
4562
4563	try
4564	{
4565		gl.bindVertexArray(vao);
4566		GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArrays");
4567
4568		for (GLint i = 0; i < max_buffers; ++i)
4569		{
4570			gl.enableVertexAttribArray(i);
4571			GLU_EXPECT_NO_ERROR(gl.getError(), "EnableVertexAttribArray");
4572		}
4573
4574		/* */
4575		gl.bindVertexBuffers(0, max_buffers, &buffer_ids[0], &offsets[0], &strides[0]);
4576		GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexBuffers");
4577
4578		/* */
4579		gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
4580		GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
4581
4582		for (GLint i = 0; i < max_buffers; ++i)
4583		{
4584			gl.disableVertexAttribArray(i);
4585			GLU_EXPECT_NO_ERROR(gl.getError(), "DisableVertexAttribArray");
4586		}
4587	}
4588	catch (const std::exception&)
4589	{
4590		gl.deleteVertexArrays(1, &vao);
4591
4592		TCU_FAIL("Unexpected error generated");
4593	}
4594
4595	gl.deleteVertexArrays(1, &vao);
4596	GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteVertexArrays");
4597
4598	/* Verify results */
4599	GLuint pixels[width * height];
4600	for (GLuint i = 0; i < width * height; ++i)
4601	{
4602		pixels[i] = 0;
4603	}
4604
4605	Texture::Bind(gl, texture.m_id, GL_TEXTURE_2D);
4606
4607	Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
4608
4609	/* Unbind */
4610	Texture::Bind(gl, 0, GL_TEXTURE_2D);
4611
4612	/* Verify */
4613	for (GLuint i = 0; i < width * height; ++i)
4614	{
4615		if (0xffffffff != pixels[i])
4616		{
4617			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)pixels[i]
4618												<< " at offset: " << i << tcu::TestLog::EndMessage;
4619
4620			test_result = false;
4621
4622			break;
4623		}
4624	}
4625
4626	/* Set result */
4627	if (true == test_result)
4628	{
4629		m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
4630	}
4631	else
4632	{
4633		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
4634	}
4635
4636	/* Done */
4637	return tcu::TestNode::STOP;
4638}
4639} /* MultiBind */
4640
4641/** Constructor.
4642 *
4643 *  @param context Rendering context.
4644 **/
4645MultiBindTests::MultiBindTests(deqp::Context& context)
4646	: TestCaseGroup(context, "multi_bind", "Verifies \"multi bind\" functionality")
4647{
4648	/* Left blank on purpose */
4649}
4650
4651/** Initializes a multi_bind test group.
4652 *
4653 **/
4654void MultiBindTests::init(void)
4655{
4656	addChild(new MultiBind::DispatchBindTexturesTest(m_context));
4657
4658	addChild(new MultiBind::ErrorsBindBuffersTest(m_context));
4659	addChild(new MultiBind::ErrorsBindTexturesTest(m_context));
4660	addChild(new MultiBind::ErrorsBindSamplersTest(m_context));
4661	addChild(new MultiBind::ErrorsBindImageTexturesTest(m_context));
4662	addChild(new MultiBind::ErrorsBindVertexBuffersTest(m_context));
4663	addChild(new MultiBind::FunctionalBindBuffersBaseTest(m_context));
4664	addChild(new MultiBind::FunctionalBindBuffersRangeTest(m_context));
4665	addChild(new MultiBind::FunctionalBindTexturesTest(m_context));
4666	addChild(new MultiBind::FunctionalBindSamplersTest(m_context));
4667	addChild(new MultiBind::FunctionalBindImageTexturesTest(m_context));
4668	addChild(new MultiBind::FunctionalBindVertexBuffersTest(m_context));
4669	addChild(new MultiBind::DispatchBindBuffersBaseTest(m_context));
4670	addChild(new MultiBind::DispatchBindBuffersRangeTest(m_context));
4671
4672	addChild(new MultiBind::DispatchBindImageTexturesTest(m_context));
4673	addChild(new MultiBind::DispatchBindSamplersTest(m_context));
4674	addChild(new MultiBind::DrawBindVertexBuffersTest(m_context));
4675}
4676
4677} /* gl4cts namespace */
4678