1/*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2014-2016 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 */ /*!
20 * \file
21 * \brief
22 */ /*-------------------------------------------------------------------*/
23
24/**
25 */ /*!
26 * \file  es31cTextureStorageMultisampleFunctionalTests.cpp
27 * \brief Implements conformance tests that verify behavior of
28 *        multisample texture functionality (ES3.1 only).
29 */ /*-------------------------------------------------------------------*/
30
31#include "es31cTextureStorageMultisampleFunctionalTests.hpp"
32#include "gluContextInfo.hpp"
33#include "gluDefs.hpp"
34#include "glwEnums.hpp"
35#include "glwFunctions.hpp"
36#include "tcuRenderTarget.hpp"
37#include "tcuTestLog.hpp"
38
39#include <algorithm>
40#include <string.h>
41#include <string>
42#include <vector>
43
44namespace glcts
45{
46/** Constructor.
47 *
48 *  @param context CTS context handle.
49 **/
50MultisampleTextureFunctionalTestsBlittingTest::MultisampleTextureFunctionalTestsBlittingTest(Context& context)
51	: TestCase(context, "multisampled_fbo_to_singlesampled_fbo_blit",
52			   "Verifies that blitting from a multi-sampled framebuffer object "
53			   "to a single-sampled framebuffer object does not generate an error.")
54	, dst_fbo_id(0)
55	, dst_to_color_id(0)
56	, dst_to_depth_stencil_id(0)
57	, src_fbo_id(0)
58	, src_to_color_id(0)
59	, src_to_depth_stencil_id(0)
60{
61	/* Left blank on purpose */
62}
63
64/** Deinitializes ES objects created during test execution */
65void MultisampleTextureFunctionalTestsBlittingTest::deinit()
66{
67	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
68
69	if (dst_fbo_id != 0)
70	{
71		gl.deleteFramebuffers(1, &dst_fbo_id);
72
73		dst_fbo_id = 0;
74	}
75
76	if (src_fbo_id != 0)
77	{
78		gl.deleteFramebuffers(1, &src_fbo_id);
79
80		src_fbo_id = 0;
81	}
82
83	if (dst_to_color_id != 0)
84	{
85		gl.deleteTextures(1, &dst_to_color_id);
86
87		dst_to_color_id = 0;
88	}
89
90	if (dst_to_depth_stencil_id != 0)
91	{
92		gl.deleteTextures(1, &dst_to_depth_stencil_id);
93
94		dst_to_depth_stencil_id = 0;
95	}
96
97	if (src_to_color_id != 0)
98	{
99		gl.deleteTextures(1, &src_to_color_id);
100
101		src_to_color_id = 0;
102	}
103
104	if (src_to_depth_stencil_id != 0)
105	{
106		gl.deleteTextures(1, &src_to_depth_stencil_id);
107
108		src_to_depth_stencil_id = 0;
109	}
110
111	/* Call base class' deinit() */
112	TestCase::deinit();
113}
114
115/** Executes test iteration.
116 *
117 *  @return Returns STOP when test has finished executing.
118 */
119tcu::TestNode::IterateResult MultisampleTextureFunctionalTestsBlittingTest::iterate()
120{
121	bool are_2d_ms_array_tos_supported =
122		m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array");
123	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
124
125	/* Set up texture objects */
126	gl.genTextures(1, &dst_to_color_id);
127	gl.genTextures(1, &dst_to_depth_stencil_id);
128	gl.genTextures(1, &src_to_color_id);
129	gl.genTextures(1, &src_to_depth_stencil_id);
130
131	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up texture objects");
132
133	if (are_2d_ms_array_tos_supported)
134	{
135		gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES, src_to_color_id);
136		gl.texStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES, 2, /* samples */
137								   GL_RGBA8, 4,							   /* width */
138								   4,									   /* height */
139								   4,									   /* depth */
140								   GL_TRUE);							   /* fixedsamplelocations */
141		GLU_EXPECT_NO_ERROR(gl.getError(),
142							"gltexStorage3DMultisample() call failed for texture object src_to_color_id");
143	}
144	else
145	{
146		gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, src_to_color_id);
147		gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 2, /* samples */
148								   GL_RGBA8, 4,					 /* width */
149								   4,							 /* height */
150								   GL_TRUE);					 /* fixedsamplelocations */
151
152		GLU_EXPECT_NO_ERROR(gl.getError(),
153							"gltexStorage3DMultisample() call failed for texture object src_to_color_id");
154	}
155
156	gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, src_to_depth_stencil_id);
157	gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 2, /* samples */
158							   GL_DEPTH32F_STENCIL8, 4,		 /* width */
159							   4,							 /* height */
160							   GL_TRUE);					 /* fixedsamplelocations */
161	GLU_EXPECT_NO_ERROR(gl.getError(),
162						"glTexStorage2DMultisample() call failed for texture object src_to_depth_stencil_id");
163
164	gl.bindTexture(GL_TEXTURE_2D, dst_to_color_id);
165	gl.texImage2D(GL_TEXTURE_2D, 0,					/* level */
166				  GL_RGBA8, 4,						/* width */
167				  4,								/* height */
168				  0,								/* border */
169				  GL_RGBA, GL_UNSIGNED_BYTE, NULL); /* data */
170	GLU_EXPECT_NO_ERROR(gl.getError(), "glTexImage2D() call failed for texture object dst_to_color_id");
171
172	gl.bindTexture(GL_TEXTURE_2D_ARRAY, dst_to_depth_stencil_id);
173	gl.texImage3D(GL_TEXTURE_2D_ARRAY, 0,									  /* level */
174				  GL_DEPTH32F_STENCIL8, 4,									  /* width */
175				  4,														  /* height */
176				  4,														  /* depth */
177				  0,														  /* border */
178				  GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, NULL); /* data */
179	GLU_EXPECT_NO_ERROR(gl.getError(), "glTexImage3D9) call failed for texture object dst_to_depth_stencil_id");
180
181	/* Set up framebuffer objects */
182	gl.genFramebuffers(1, &dst_fbo_id);
183	gl.genFramebuffers(1, &src_fbo_id);
184	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, dst_fbo_id);
185	gl.bindFramebuffer(GL_READ_FRAMEBUFFER, src_fbo_id);
186
187	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up framebuffer objects");
188
189	/* Set up source FBO attachments. */
190	glw::GLenum fbo_completeness_status = 0;
191
192	if (are_2d_ms_array_tos_supported)
193	{
194		gl.framebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, src_to_color_id, 0, /* level */
195								   0);															  /* layer */
196	}
197	else
198	{
199		gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, src_to_color_id,
200								0); /* level */
201	}
202
203	gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE,
204							src_to_depth_stencil_id, 0); /* level */
205
206	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up source framebuffer's attachments");
207
208	fbo_completeness_status = gl.checkFramebufferStatus(GL_READ_FRAMEBUFFER);
209
210	if (fbo_completeness_status != GL_FRAMEBUFFER_COMPLETE)
211	{
212		m_testCtx.getLog() << tcu::TestLog::Message << "Source FBO completeness status is: " << fbo_completeness_status
213						   << ", expected: GL_FRAMEBUFFER_COMPLETE" << tcu::TestLog::EndMessage;
214
215		TCU_FAIL("Source FBO is considered incomplete which is invalid");
216	}
217
218	/* Set up draw FBO attachments */
219	gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_to_color_id, 0);   /* level */
220	gl.framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, dst_to_depth_stencil_id, 0, /* level */
221							   0);																			 /* layer */
222	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up draw framebuffer's attachments");
223
224	fbo_completeness_status = gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER);
225
226	if (fbo_completeness_status != GL_FRAMEBUFFER_COMPLETE)
227	{
228		m_testCtx.getLog() << tcu::TestLog::Message << "Draw FBO completeness status is: " << fbo_completeness_status
229						   << ", expected: GL_FRAMEBUFFER_COMPLETE" << tcu::TestLog::EndMessage;
230
231		TCU_FAIL("Draw FBO is considered incomplete which is invalid");
232	}
233
234	/* Perform the blitting operation */
235	gl.blitFramebuffer(0, /* srcX0 */
236					   0, /* srcY0 */
237					   4, /* srcX1 */
238					   4, /* srcY1 */
239					   0, /* dstX0 */
240					   0, /* dstY0 */
241					   4, /* dstX1 */
242					   4, /* dstY1 */
243					   GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
244					   GL_NEAREST); /* An INVALID_OPERATION error is generated if ...., and filter is not NEAREST. */
245
246	/* Make sure no error was generated */
247	GLU_EXPECT_NO_ERROR(gl.getError(), "glBlitFramebuffer() call failed.");
248
249	/* All done */
250	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
251
252	return STOP;
253}
254
255/** Constructor.
256 *
257 *  @param context CTS context handle.
258 **/
259MultisampleTextureFunctionalTestsBlittingMultisampledDepthAttachmentTest::
260	MultisampleTextureFunctionalTestsBlittingMultisampledDepthAttachmentTest(Context& context)
261	: TestCase(context, "blitting_multisampled_depth_attachment",
262			   "Verifies that blitting a multi-sampled depth attachment to "
263			   "a single-sampled depth attachment gives valid results")
264	, fbo_dst_id(0)
265	, fbo_src_id(0)
266	, fs_depth_preview_id(0)
267	, fs_id(0)
268	, po_depth_preview_id(0)
269	, po_id(0)
270	, to_dst_preview_id(0)
271	, to_dst_id(0)
272	, to_src_id(0)
273	, vao_id(0)
274	, vs_id(0)
275{
276	/* Left blank on purpose */
277}
278
279/** Deinitializes ES objects created during test execution */
280void MultisampleTextureFunctionalTestsBlittingMultisampledDepthAttachmentTest::deinit()
281{
282	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
283
284	if (fbo_dst_id != 0)
285	{
286		gl.deleteFramebuffers(1, &fbo_dst_id);
287
288		fbo_dst_id = 0;
289	}
290
291	if (fbo_src_id != 0)
292	{
293		gl.deleteFramebuffers(1, &fbo_src_id);
294
295		fbo_src_id = 0;
296	}
297
298	if (to_dst_preview_id != 0)
299	{
300		gl.deleteTextures(1, &to_dst_preview_id);
301
302		to_dst_preview_id = 0;
303	}
304
305	if (to_dst_id != 0)
306	{
307		gl.deleteTextures(1, &to_dst_id);
308
309		to_dst_id = 0;
310	}
311
312	if (to_src_id != 0)
313	{
314		gl.deleteTextures(1, &to_src_id);
315
316		to_src_id = 0;
317	}
318
319	if (fs_id != 0)
320	{
321		gl.deleteShader(fs_id);
322
323		fs_id = 0;
324	}
325
326	if (fs_depth_preview_id != 0)
327	{
328		gl.deleteShader(fs_depth_preview_id);
329
330		fs_depth_preview_id = 0;
331	}
332
333	if (po_depth_preview_id != 0)
334	{
335		gl.deleteProgram(po_depth_preview_id);
336
337		po_depth_preview_id = 0;
338	}
339
340	if (po_id != 0)
341	{
342		gl.deleteProgram(po_id);
343
344		po_id = 0;
345	}
346
347	if (vao_id != 0)
348	{
349		gl.deleteVertexArrays(1, &vao_id);
350
351		vao_id = 0;
352	}
353
354	if (vs_id != 0)
355	{
356		gl.deleteShader(vs_id);
357
358		vs_id = 0;
359	}
360
361	/* Call base class' deinit() */
362	TestCase::deinit();
363}
364
365/** Executes test iteration.
366 *
367 *  @return Returns STOP when test has finished executing.
368 */
369tcu::TestNode::IterateResult MultisampleTextureFunctionalTestsBlittingMultisampledDepthAttachmentTest::iterate()
370{
371	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
372
373	/* Generate all objects this test will use */
374	fs_depth_preview_id = gl.createShader(GL_FRAGMENT_SHADER);
375	fs_id				= gl.createShader(GL_FRAGMENT_SHADER);
376	vs_id				= gl.createShader(GL_VERTEX_SHADER);
377
378	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
379
380	po_depth_preview_id = gl.createProgram();
381	po_id				= gl.createProgram();
382
383	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
384
385	gl.genTextures(1, &to_src_id);
386	gl.genTextures(1, &to_dst_preview_id);
387	gl.genTextures(1, &to_dst_id);
388
389	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed");
390
391	gl.genFramebuffers(1, &fbo_src_id);
392	gl.genFramebuffers(1, &fbo_dst_id);
393
394	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() failed");
395
396	gl.genVertexArrays(1, &vao_id);
397
398	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() failed");
399
400	/* Bind FBOs to relevant FB targets */
401	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_dst_id);
402	gl.bindFramebuffer(GL_READ_FRAMEBUFFER, fbo_src_id);
403
404	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() call(s) failed");
405
406	/* Configure body of vs_id vertex shader */
407	const glw::GLchar* vs_body = "#version 310 es\n"
408								 "\n"
409								 "precision highp float;\n"
410								 "\n"
411								 "out vec2 uv;\n"
412								 "\n"
413								 "void main()\n"
414								 "{\n"
415								 "    switch(gl_VertexID)\n"
416								 "    {\n"
417								 "        case 0: gl_Position = vec4(-1, -1, 0, 1); uv = vec2(0, 0); break;\n"
418								 "        case 1: gl_Position = vec4(-1,  1, 0, 1); uv = vec2(0, 1); break;\n"
419								 "        case 2: gl_Position = vec4( 1,  1, 0, 1); uv = vec2(1, 1); break;\n"
420								 "        case 3: gl_Position = vec4( 1, -1, 0, 1); uv = vec2(1, 0); break;\n"
421								 "    }\n"
422								 "}\n";
423
424	gl.shaderSource(vs_id, 1 /* count */, &vs_body, NULL);
425	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader of vs_id id");
426
427	/* Configure body of fs_id fragment shader */
428	const glw::GLchar* fs_body = "#version 310 es\n"
429								 "\n"
430								 "precision highp float;\n"
431								 "\n"
432								 "in vec2 uv;\n"
433								 "\n"
434								 "void main()\n"
435								 "{\n"
436								 "    gl_FragDepth = uv.x * uv.y;\n"
437								 "}\n";
438
439	gl.shaderSource(fs_id, 1 /* count */, &fs_body, NULL);
440	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader of fs_id id");
441
442	/* Configure body of fs_depth_preview_id fragment shader */
443	const glw::GLchar* fs_depth_preview_body = "#version 310 es\n"
444											   "\n"
445											   "precision highp int;\n"
446											   "precision highp float;\n"
447											   "\n"
448											   "in      vec2      uv;\n"
449											   "out     uint      result;\n"
450											   "uniform sampler2D tex;\n"
451											   "\n"
452											   "void main()\n"
453											   "{\n"
454											   "    result = floatBitsToUint(textureLod(tex, uv, 0.0).x);\n"
455											   "}\n";
456
457	gl.shaderSource(fs_depth_preview_id, 1 /* count */, &fs_depth_preview_body, NULL);
458	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader of fs_depth_preview_id id");
459
460	/* Compile all the shaders */
461	const glw::GLuint  shader_ids[] = { fs_id, fs_depth_preview_id, vs_id };
462	const unsigned int n_shader_ids = sizeof(shader_ids) / sizeof(shader_ids[0]);
463
464	for (unsigned int n_shader_id = 0; n_shader_id < n_shader_ids; ++n_shader_id)
465	{
466		glw::GLint compile_status = GL_FALSE;
467
468		gl.compileShader(shader_ids[n_shader_id]);
469		GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed");
470
471		gl.getShaderiv(shader_ids[n_shader_id], GL_COMPILE_STATUS, &compile_status);
472		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed");
473
474		if (compile_status != GL_TRUE)
475		{
476			TCU_FAIL("Shader compilation failure");
477		}
478	} /* for (all shader ids) */
479
480	/* Configure and link both program objects */
481	const glw::GLuint  program_ids[] = { po_depth_preview_id, po_id };
482	const unsigned int n_program_ids = sizeof(program_ids) / sizeof(program_ids[0]);
483
484	gl.attachShader(po_depth_preview_id, fs_depth_preview_id);
485	gl.attachShader(po_depth_preview_id, vs_id);
486	gl.attachShader(po_id, fs_id);
487	gl.attachShader(po_id, vs_id);
488	GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() failed");
489
490	for (unsigned int n_program_id = 0; n_program_id < n_program_ids; ++n_program_id)
491	{
492		glw::GLint link_status = GL_FALSE;
493
494		gl.linkProgram(program_ids[n_program_id]);
495		GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() failed");
496
497		gl.getProgramiv(program_ids[n_program_id], GL_LINK_STATUS, &link_status);
498		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
499
500		if (link_status != GL_TRUE)
501		{
502			TCU_FAIL("Program linking failure");
503		}
504	} /* for (all program ids) */
505
506	/* Retrieve maximum amount of samples that can be used for GL_DEPTH_COMPONENT32F internalformat */
507	glw::GLint n_depth_component32f_max_samples = 0;
508
509	gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_DEPTH_COMPONENT32F, GL_SAMPLES, 1, /* bufSize */
510						   &n_depth_component32f_max_samples);
511	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInternalformativ() failed");
512
513	/* Configure texture storage for to_src_id */
514	gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, to_src_id);
515	gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, n_depth_component32f_max_samples, GL_DEPTH_COMPONENT32F,
516							   64,		  /* width */
517							   64,		  /* height */
518							   GL_FALSE); /* fixedsamplelocations */
519
520	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not configure texture storage for texture object to_src_id");
521
522	gl.texParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
523
524	/* When <target> is TEXTURE_2D_MULTISAMPLE  or
525	 TEXTURE_2D_MULTISAMPLE_ARRAY_XXX, certain texture parameters may not be
526	 specified. In this case, an INVALID_ENUM error is generated if the
527	 parameter is any sampler state value from table 6.10. */
528	glw::GLenum error_code = gl.getError();
529	if (error_code != GL_INVALID_ENUM)
530	{
531		m_testCtx.getLog() << tcu::TestLog::Message << "glTexParameteri() call generated an error " << error_code
532						   << " instead of the expected error code " << GL_INVALID_ENUM << tcu::TestLog::EndMessage;
533
534		TCU_FAIL("glTexParameterf() with target GL_TEXTURE_2D_MULTISAMPLE and pname=GL_TEXTURE_MIN_FILTER did not "
535				 "generate GL_INVALID_ENUM.");
536	}
537
538	/* Configure texture storage for to_dst_id */
539	gl.bindTexture(GL_TEXTURE_2D, to_dst_id);
540	gl.texStorage2D(GL_TEXTURE_2D, 1,		   /* levels */
541					GL_DEPTH_COMPONENT32F, 64, /* width */
542					64);					   /* height */
543
544	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not configure texture storage for texture object to_dst_id");
545
546	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
547	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set nearest minification filter for texture object to_dst_id");
548
549	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
550	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set nearest magnification filter for texture object to_dst_id");
551
552	/* Configure draw framebuffer */
553	gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE, to_src_id,
554							0); /* level */
555	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not configure draw framebuffer for depth data rendering");
556
557	/* Render the test geometry.
558	 *
559	 * NOTE: Original test spec rendered to fbo_dst_id which would have been invalid,
560	 *       since fbo_dst_id is the assumed destination for the blitting operation.
561	 *       Actual FBO management code has been rewritten to improve code clarity.
562	 *
563	 * NOTE: Original test spec didn't enable the depth tests, which are necessary
564	 *       for the depth buffer to be updated.
565	 **/
566	gl.viewport(0, 0, 64 /* rt width */, 64 /* rt height */);
567	GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() failed");
568
569	gl.enable(GL_DEPTH_TEST);
570	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_DEPTH_TEST) failed");
571
572	gl.depthFunc(GL_ALWAYS);
573	GLU_EXPECT_NO_ERROR(gl.getError(), "gldepthFunc(GL_ALWAYS) failed");
574
575	gl.useProgram(po_id);
576	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() for program object po_id failed");
577
578	gl.bindVertexArray(vao_id);
579	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() failed");
580
581	gl.drawArrays(GL_TRIANGLE_FAN, 0 /* first */, 4 /* count */);
582	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
583
584	/* Configure FBOs for blitting */
585	gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE, to_src_id,
586							0); /* level */
587
588	gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, to_dst_id, 0); /* level */
589
590	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not configure FBOs for blitting");
591
592	/* Blit source FBO to destination FBO */
593	gl.blitFramebuffer(0,  /* srcX0 */
594					   0,  /* srcY0 */
595					   64, /* srcX1 */
596					   64, /* srcY1 */
597					   0,  /* dstX0 */
598					   0,  /* dstY0 */
599					   64, /* dstX1 */
600					   64, /* dstY1 */
601					   GL_DEPTH_BUFFER_BIT, GL_NEAREST);
602	GLU_EXPECT_NO_ERROR(gl.getError(), "glBlitFramebuffer() failed");
603
604	/* Single-sampled depth data is now stored in dst_to_id in GL_DEPTH_COMPONENT32F which may
605	 * not work too well with glReadPixels().
606	 *
607	 * We will now convert it to GL_R32UI using the other program */
608	gl.useProgram(po_depth_preview_id);
609	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed for program object po_depth_preview_id");
610
611	/* Configure texture storage for the destination texture object */
612	gl.bindTexture(GL_TEXTURE_2D, to_dst_preview_id);
613	gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
614					GL_R32UI, 64,	 /* width */
615					64);			  /* height */
616
617	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up texcture storage for texture object to_dst_preview_id");
618
619	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
620	GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri() failed for texture object to_dst_preview_id");
621
622	/* Update draw framebuffer configuration */
623	gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, /* texture */
624							0);															/* level */
625
626	gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, to_dst_preview_id, 0); /* level */
627
628	GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() failed for depth preview pass");
629
630	/* Render a full-screen quad */
631	gl.bindTexture(GL_TEXTURE_2D, to_dst_id);
632
633	gl.drawArrays(GL_TRIANGLE_FAN, 0 /* first */, 4 /* count */);
634	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed for depth preview pass");
635
636	/* to_dst_id now contains the result data.
637	 *
638	 * Before we do a glReadPixels() call, we need to re-configure the read FBO */
639	gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, /* texture */
640							0);															/* level */
641
642	gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, to_dst_preview_id, 0); /* level */
643
644	GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() failed for depth data download pass");
645
646	/* Read the data */
647	unsigned int buffer[64 /* width */ * 64 /* height */ * 4 /* components */];
648
649	gl.readPixels(0,  /* x */
650				  0,  /* y */
651				  64, /* width */
652				  64, /* height */
653				  GL_RGBA_INTEGER, GL_UNSIGNED_INT, buffer);
654	GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() failed for depth data download pass");
655
656	/* Verify the rendered data */
657	const float epsilon = 1.0f / 64.0f + (float)1e-5;
658
659	for (int y = 0; y < 64 /* height */; ++y)
660	{
661		/* NOTE: data_y is used to take the bottom-top orientation of the data downloaded
662		 *       by glReadPixels() into account.
663		 */
664		const int data_y	 = (64 /* height */ - y - 1 /* counting starts from 0 */);
665		const int pixel_size = 4; /* components */
666		const int row_width  = 64 /* width */ * pixel_size;
667		float*	row_ptr	= (float*)buffer + row_width * data_y;
668
669		for (int x = 0; x < 64 /* width */; ++x)
670		{
671			float* data_ptr			  = row_ptr + x * pixel_size;
672			float  depth			  = data_ptr[0];
673			float  expected_value_max = float(x) * float(data_y) / (64.0f * 64.0f) + epsilon;
674			float  expected_value_min = float(x) * float(data_y) / (64.0f * 64.0f) - epsilon;
675
676			if (!(depth >= expected_value_min && depth <= expected_value_max))
677			{
678				m_testCtx.getLog() << tcu::TestLog::Message << "Invalid data rendered at (" << x << ", " << y << "): "
679								   << "Expected value from " << expected_value_min << " to " << expected_value_max
680								   << ", "
681								   << "rendered: " << depth << tcu::TestLog::EndMessage;
682
683				TCU_FAIL("Invalid data rendered");
684			}
685		} /* for (all x argument values) */
686	}	 /* for (all y argument values) */
687
688	/* All done */
689	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
690
691	return STOP;
692}
693
694/** Constructor.
695 *
696 *  @param context CTS context handle.
697 **/
698MultisampleTextureFunctionalTestsBlittingMultisampledIntegerAttachmentTest::
699	MultisampleTextureFunctionalTestsBlittingMultisampledIntegerAttachmentTest(Context& context)
700	: TestCase(context, "blitting_multisampled_integer_attachment",
701			   "Verifies that blitting a multi-sampled integer attachment "
702			   "to a single-sampled integer attachment gives valid results")
703	, dst_to_id(0)
704	, fbo_draw_id(0)
705	, fbo_read_id(0)
706	, fs_id(0)
707	, po_id(0)
708	, src_to_id(0)
709	, vs_id(0)
710{
711	/* Left blank on purpose */
712}
713
714/** Deinitializes ES objects created during test execution */
715void MultisampleTextureFunctionalTestsBlittingMultisampledIntegerAttachmentTest::deinit()
716{
717	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
718
719	if (fbo_draw_id != 0)
720	{
721		gl.deleteFramebuffers(1, &fbo_draw_id);
722
723		fbo_draw_id = 0;
724	}
725
726	if (fbo_read_id != 0)
727	{
728		gl.deleteFramebuffers(1, &fbo_read_id);
729
730		fbo_read_id = 0;
731	}
732
733	if (dst_to_id != 0)
734	{
735		gl.deleteTextures(1, &dst_to_id);
736
737		dst_to_id = 0;
738	}
739
740	if (src_to_id != 0)
741	{
742		gl.deleteTextures(1, &src_to_id);
743
744		src_to_id = 0;
745	}
746
747	if (fs_id != 0)
748	{
749		gl.deleteShader(fs_id);
750
751		fs_id = 0;
752	}
753
754	if (po_id != 0)
755	{
756		gl.deleteProgram(po_id);
757
758		po_id = 0;
759	}
760
761	if (vs_id != 0)
762	{
763		gl.deleteShader(vs_id);
764
765		vs_id = 0;
766	}
767
768	/* Call base class' deinit() */
769	TestCase::deinit();
770}
771
772/** Executes test iteration.
773 *
774 *  @return Returns STOP when test has finished executing.
775 */
776tcu::TestNode::IterateResult MultisampleTextureFunctionalTestsBlittingMultisampledIntegerAttachmentTest::iterate()
777{
778	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
779
780	/* Make sure GL_MAX_INTEGER_SAMPLES is at least 2 */
781	glw::GLint gl_max_integer_samples_value = 0;
782
783	gl.getIntegerv(GL_MAX_INTEGER_SAMPLES, &gl_max_integer_samples_value);
784	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not query GL_MAX_INTEGER_SAMPLES pname value");
785
786	if (gl_max_integer_samples_value < 2)
787	{
788		throw tcu::NotSupportedError("GL_MAX_INTEGER_SAMPLES is lower than 2");
789	}
790
791	/* Retrieve maximum amount of samples for GL_R16UI internalformat */
792	glw::GLint r16ui_max_samples = 0;
793
794	gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_R16UI, GL_SAMPLES, 1 /* bufSize */, &r16ui_max_samples);
795	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInternalformativ() call failed.");
796
797	/* Set up texture objects */
798	gl.genTextures(1, &dst_to_id);
799	gl.genTextures(1, &src_to_id);
800
801	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up texture objects");
802
803	gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, src_to_id);
804	gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, r16ui_max_samples, GL_R16UI, 16, /* width */
805							   16,														   /* height */
806							   GL_FALSE);												   /* fixedsamplelocations */
807	GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2DMultisample() call failed for texture object src_to_id");
808
809	gl.bindTexture(GL_TEXTURE_2D, dst_to_id);
810	gl.texStorage2D(GL_TEXTURE_2D, 1, /* levels */
811					GL_R16UI, 16,	 /* width */
812					16);			  /* height */
813
814	GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed for texture object dst_to_id");
815
816	/* Create a program object */
817	po_id = gl.createProgram();
818	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed");
819
820	/* Create two shader objects */
821	fs_id = gl.createShader(GL_FRAGMENT_SHADER);
822	vs_id = gl.createShader(GL_VERTEX_SHADER);
823
824	GLU_EXPECT_NO_ERROR(gl.getError(), "Either of the glCreateShader() calls failed");
825
826	/* Set up framebuffer objects */
827	gl.genFramebuffers(1, &fbo_draw_id);
828	gl.genFramebuffers(1, &fbo_read_id);
829	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_draw_id);
830	gl.bindFramebuffer(GL_READ_FRAMEBUFFER, fbo_read_id);
831
832	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up framebuffer objects");
833
834	/* Set up draw FBO's color attachment. */
835	gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, src_to_id,
836							0); /* level */
837
838	GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed");
839
840	/* Set up shader objects.
841	 *
842	 * NOTE: Original test spec specified an invalid case 3 for the vertex shader.
843	 * NOTE: Original test case used a float output value. This would not be valid,
844	 *       as the color buffer's attachment uses GL_R16UI format.
845	 */
846	glw::GLint		   compile_status = GL_FALSE;
847	static const char* fs_body		  = "#version 310 es\n"
848								 "\n"
849								 "precision highp float;\n"
850								 "\n"
851								 "uniform uint  n_sample;\n"
852								 "uniform uint  n_max_samples;\n"
853								 "uniform highp uvec2 x1y1;\n"
854								 "out     uint  result;\n"
855								 "\n"
856								 "void main()\n"
857								 "{\n"
858								 "    uint row_index    = x1y1.y;\n"
859								 "    uint column_index = x1y1.x;\n"
860								 "\n"
861								 "    if (n_sample < n_max_samples / 2u)\n"
862								 "    {\n"
863								 "        result = row_index * 16u + column_index;\n"
864								 "    }\n"
865								 "    else\n"
866								 "    {\n"
867								 "        result = row_index * 16u + column_index + 1u;\n"
868								 "    }\n"
869								 "}\n";
870	static const char* vs_body = "#version 310 es\n"
871								 "\n"
872								 "uniform uvec2 x1y1;\n"
873								 "\n"
874								 "void main()\n"
875								 "{\n"
876								 "    switch (gl_VertexID)\n"
877								 "    {\n"
878								 "        case 0: gl_Position = vec4( (float(x1y1.x) + 0.0 - 8.0)/8.0, (float(x1y1.y) "
879								 "+ 0.0 - 8.0)/8.0, 0.0, 1.0); break;\n"
880								 "        case 1: gl_Position = vec4( (float(x1y1.x) + 1.0 - 8.0)/8.0, (float(x1y1.y) "
881								 "+ 0.0 - 8.0)/8.0, 0.0, 1.0); break;\n"
882								 "        case 2: gl_Position = vec4( (float(x1y1.x) + 1.0 - 8.0)/8.0, (float(x1y1.y) "
883								 "+ 1.0 - 8.0)/8.0, 0.0, 1.0); break;\n"
884								 "        case 3: gl_Position = vec4( (float(x1y1.x) + 0.0 - 8.0)/8.0, (float(x1y1.y) "
885								 "+ 1.0 - 8.0)/8.0, 0.0, 1.0); break;\n"
886								 "    }\n"
887								 "}\n";
888
889	gl.attachShader(po_id, fs_id);
890	gl.attachShader(po_id, vs_id);
891	GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed.");
892
893	gl.shaderSource(fs_id, 1 /* count */, &fs_body, NULL);
894	gl.shaderSource(vs_id, 1 /* count */, &vs_body, NULL);
895	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call(s) failed.");
896
897	gl.compileShader(fs_id);
898	gl.compileShader(vs_id);
899	GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call(s) failed.");
900
901	gl.getShaderiv(fs_id, GL_COMPILE_STATUS, &compile_status);
902	if (compile_status != GL_TRUE)
903	{
904		TCU_FAIL("Could not compile fragment shader");
905	}
906
907	gl.getShaderiv(vs_id, GL_COMPILE_STATUS, &compile_status);
908	if (compile_status != GL_TRUE)
909	{
910		/* Retrieve and dump compilation fail reason */
911		char		 infoLog[1024];
912		glw::GLsizei length = 0;
913
914		gl.getShaderInfoLog(vs_id, 1024, &length, infoLog);
915
916		m_testCtx.getLog() << tcu::TestLog::Message << "Vertex shader compilation failed, infoLog: " << infoLog
917						   << tcu::TestLog::EndMessage;
918
919		TCU_FAIL("Could not compile vertex shader");
920	}
921
922	/* Link the program object */
923	glw::GLint link_status = GL_FALSE;
924
925	gl.linkProgram(po_id);
926	GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() failed");
927
928	gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status);
929	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
930
931	if (link_status != GL_TRUE)
932	{
933		TCU_FAIL("Could not link program object");
934	}
935
936	/* Enable GL_SAMPLE_MASK mode */
937	gl.enable(GL_SAMPLE_MASK);
938
939	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_SAMPLE_MASK) call generated an unexpected error");
940
941	/* Prepare for rendering */
942	glw::GLint n_max_samples_uniform_location = gl.getUniformLocation(po_id, "n_max_samples");
943	glw::GLint n_sample_uniform_location	  = gl.getUniformLocation(po_id, "n_sample");
944	glw::GLint x1y1_uniform_location		  = gl.getUniformLocation(po_id, "x1y1");
945
946	if (n_max_samples_uniform_location == -1)
947	{
948		TCU_FAIL("n_max_samples is not considered an active uniform.");
949	}
950
951	if (n_sample_uniform_location == -1)
952	{
953		TCU_FAIL("n_sample is not considered an active uniform.");
954	}
955
956	if (x1y1_uniform_location == -1)
957	{
958		TCU_FAIL("x1y1 is not considered an active uniform.");
959	}
960
961	gl.viewport(0 /* x */, 0 /* y */, 16 /* width */, 16 /* height */);
962	GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed");
963
964	gl.useProgram(po_id);
965	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
966
967	gl.uniform1ui(n_max_samples_uniform_location, r16ui_max_samples);
968	GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1ui() call failed");
969
970	/* Clear color buffer before drawing to it, not strictly neccesary
971	 * but helps debugging */
972	glw::GLuint clear_color_src[] = { 11, 22, 33, 44 };
973
974	gl.clearBufferuiv(GL_COLOR, 0, clear_color_src);
975	GLU_EXPECT_NO_ERROR(gl.getError(), "glClearBufferiv() call failed");
976
977	/* Render */
978	for (int x = 0; x < 16 /* width */; ++x)
979	{
980		for (int y = 0; y < 16 /* height */; ++y)
981		{
982			for (int n_sample = 0; n_sample < r16ui_max_samples; ++n_sample)
983			{
984				gl.uniform1ui(n_sample_uniform_location, n_sample);
985				GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1ui() call failed");
986
987				gl.uniform2ui(x1y1_uniform_location, x, y);
988				GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform2f() call failed");
989
990				gl.sampleMaski(n_sample / 32, 1 << (n_sample % 32));
991				GLU_EXPECT_NO_ERROR(gl.getError(), "glSampleMaski() call failed.");
992
993				gl.drawArrays(GL_TRIANGLE_FAN, 0 /* first */, 4 /* count */);
994				GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
995			} /* for (all n_sample values) */
996		}	 /* for (all y values) */
997	}		  /* for (all x values) */
998
999	/* Now, configure the framebuffer binding points for the blitting operation */
1000	gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_to_id, 0); /* level */
1001	gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, src_to_id,
1002							0); /* level */
1003	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up framebuffer objects for the blitting operation");
1004
1005	/* Clear color buffer before drawing to it, not strictly neccesary
1006	 * but helps debugging */
1007	glw::GLuint clear_color_dst[] = { 55, 66, 77, 88 };
1008
1009	gl.clearBufferuiv(GL_COLOR, 0, clear_color_dst);
1010	GLU_EXPECT_NO_ERROR(gl.getError(), "glClearBufferiv() call failed");
1011
1012	/* Blit the data.
1013	 *
1014	 * NOTE: Original test spec specified GL_LINEAR filter which would not have worked
1015	 *       because the read buffer contains integer data.
1016	 **/
1017	gl.blitFramebuffer(0,  /* srcX0 */
1018					   0,  /* srcY0 */
1019					   16, /* srcX1 */
1020					   16, /* srcY1 */
1021					   0,  /* dstX0 */
1022					   0,  /* dstY0 */
1023					   16, /* dstX1 */
1024					   16, /* dstY1 */
1025					   GL_COLOR_BUFFER_BIT, GL_NEAREST);
1026	GLU_EXPECT_NO_ERROR(gl.getError(), "glBlitFramebuffer() call failed.");
1027
1028	/* Configure the read framebuffer for upcoming glReadPixels() call */
1029	gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_to_id, 0); /* level */
1030	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not configure the read framebuffer");
1031
1032	/* Allocate a buffer to hold the result data and then download the result texture's
1033	 * contents */
1034	unsigned int* buffer = new unsigned int[16 /* width */ * 16 /* height */ * 4 /* components */];
1035
1036	gl.readPixels(0,  /* x */
1037				  0,  /* y */
1038				  16, /* width */
1039				  16, /* height */
1040				  GL_RGBA_INTEGER, GL_UNSIGNED_INT, buffer);
1041	GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed");
1042
1043	/* Verify the downloaded contents */
1044	int has_test_fail = 0;
1045	int pixel_size	= sizeof(unsigned int) * 4 /* components */;
1046	int row_width	 = pixel_size * 16 /* width */;
1047
1048	for (unsigned int y = 0; y < 16 /* height */; ++y)
1049	{
1050		/* NOTE: Vertical flipping should not be needed, but we cannot confirm this at the moment.
1051		 *       Should it be the case, please change data_y to 15 - y */
1052		/* TODO: Remove NOTE above when verified on actual ES3.1 implementation */
1053		unsigned int		data_y  = y;
1054		const unsigned int* row_ptr = (unsigned int*)((char*)buffer + data_y * row_width);
1055
1056		for (unsigned int x = 0; x < 16 /* width */; ++x)
1057		{
1058			const unsigned int* data_ptr   = (unsigned int*)((char*)row_ptr + x * pixel_size);
1059			const unsigned int  r		   = data_ptr[0];
1060			const unsigned int  g		   = data_ptr[1];
1061			const unsigned int  b		   = data_ptr[2];
1062			const unsigned int  a		   = data_ptr[3];
1063			bool				is_r_valid = (r == (data_y * 16 + x)) || (r == (data_y * 16 + x + 1));
1064			bool				is_g_valid = (g == 0);
1065			bool				is_b_valid = (b == 0);
1066			bool				is_a_valid = (a == 1);
1067
1068			if (!is_r_valid || !is_g_valid || !is_b_valid || !is_a_valid)
1069			{
1070				m_testCtx.getLog() << tcu::TestLog::Message << "Invalid texture data at (" << x << ", " << y << "):"
1071								   << " Expected (" << (data_y * 16 + x) << ", 0, 0, 1)"
1072								   << " or (" << (data_y * 16 + x + 1) << ", 0, 0, 1)"
1073								   << ", found (" << r << ", " << g << ", " << b << ", " << a << ")."
1074								   << tcu::TestLog::EndMessage;
1075
1076				has_test_fail++;
1077			}
1078		} /* for (all x values) */
1079	}	 /* for (all y values) */
1080
1081	if (has_test_fail)
1082	{
1083		TCU_FAIL("Invalid texture data");
1084	}
1085
1086	/* All done */
1087	if (buffer != NULL)
1088	{
1089		delete[] buffer;
1090		buffer = NULL;
1091	}
1092
1093	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1094
1095	return STOP;
1096}
1097
1098/** Constructor.
1099 *
1100 *  @param context CTS context handle.
1101 **/
1102MultisampleTextureFunctionalTestsBlittingToMultisampledFBOIsForbiddenTest::
1103	MultisampleTextureFunctionalTestsBlittingToMultisampledFBOIsForbiddenTest(Context& context)
1104	: TestCase(context, "blitting_to_multisampled_fbo_is_forbidden",
1105			   "Verifies that blitting to a multisampled framebuffer "
1106			   "object results in a GL_INVALID_OPERATION error.")
1107	, dst_to_id(0)
1108	, fbo_draw_id(0)
1109	, fbo_read_id(0)
1110	, src_to_id(0)
1111{
1112	/* Left blank on purpose */
1113}
1114
1115/** Deinitializes ES objects created during test execution */
1116void MultisampleTextureFunctionalTestsBlittingToMultisampledFBOIsForbiddenTest::deinit()
1117{
1118	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1119
1120	if (fbo_draw_id != 0)
1121	{
1122		gl.deleteFramebuffers(1, &fbo_draw_id);
1123
1124		fbo_draw_id = 0;
1125	}
1126
1127	if (fbo_read_id != 0)
1128	{
1129		gl.deleteFramebuffers(1, &fbo_read_id);
1130
1131		fbo_read_id = 0;
1132	}
1133
1134	if (dst_to_id != 0)
1135	{
1136		gl.deleteTextures(1, &dst_to_id);
1137
1138		dst_to_id = 0;
1139	}
1140
1141	if (src_to_id != 0)
1142	{
1143		gl.deleteTextures(1, &src_to_id);
1144
1145		src_to_id = 0;
1146	}
1147
1148	/* Call base class' deinit() */
1149	TestCase::deinit();
1150}
1151
1152/** Executes test iteration.
1153 *
1154 *  @return Returns STOP when test has finished executing.
1155 */
1156tcu::TestNode::IterateResult MultisampleTextureFunctionalTestsBlittingToMultisampledFBOIsForbiddenTest::iterate()
1157{
1158	const std::vector<std::string>& exts = m_context.getContextInfo().getExtensions();
1159	const bool has_NV_framebuffer_blit   = std::find(exts.begin(), exts.end(), "GL_NV_framebuffer_blit") != exts.end();
1160	const glw::Functions& gl			 = m_context.getRenderContext().getFunctions();
1161
1162	/* Set up texture objects */
1163	gl.genTextures(1, &dst_to_id);
1164	gl.genTextures(1, &src_to_id);
1165
1166	gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, dst_to_id);
1167	gl.bindTexture(GL_TEXTURE_2D, src_to_id);
1168
1169	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up texture objects");
1170
1171	gl.texStorage2D(GL_TEXTURE_2D, 2, /* levels */
1172					GL_RGB10_A2, 64,  /* width */
1173					64);			  /* height */
1174
1175	GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed for GL_TEXTURE_2D texture target");
1176
1177	gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 2, /* samples */
1178							   GL_RGB10_A2, 64,				 /* width */
1179							   64,							 /* height */
1180							   GL_FALSE);					 /* fixedsamplelocations */
1181
1182	GLU_EXPECT_NO_ERROR(gl.getError(),
1183						"gl.texStorage2DMultisample() call failed for GL_TEXTURE_2D_MULTISAMPLE texture target");
1184
1185	/* Set up framebuffer objects */
1186	gl.genFramebuffers(1, &fbo_draw_id);
1187	gl.genFramebuffers(1, &fbo_read_id);
1188	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_draw_id);
1189	gl.bindFramebuffer(GL_READ_FRAMEBUFFER, fbo_read_id);
1190
1191	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up framebuffer objects");
1192
1193	/* Set up FBO attachments.
1194	 *
1195	 * NOTE: The draw/read FBO configuration in original test spec was the other
1196	 *       way around which was wrong.
1197	 */
1198	gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, src_to_id, 0); /* level */
1199
1200	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up read framebuffer's attachments");
1201
1202	gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,
1203							dst_to_id, /* texture */
1204							0);		   /* layer */
1205
1206	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up draw framebuffer's attachments");
1207
1208	/* Try to perform blitting operations. */
1209	const glw::GLenum  filters[] = { GL_NEAREST, GL_LINEAR };
1210	const unsigned int n_filters = sizeof(filters) / sizeof(filters[0]);
1211
1212	for (unsigned int n_filter = 0; n_filter < n_filters; ++n_filter)
1213	{
1214		glw::GLenum filter = filters[n_filter];
1215
1216		// This blit would be supported by NV_framebuffer_blit if sizes match.
1217		// Alter the size of destination if extension is present to make it invalid.
1218		int dstY1 = has_NV_framebuffer_blit ? 63 : 64;
1219		gl.blitFramebuffer(0,	 /* srcX0 */
1220						   0,	 /* srcY0 */
1221						   64,	/* srcX1 */
1222						   64,	/* srcY1 */
1223						   0,	 /* dstX0 */
1224						   0,	 /* dstY0 */
1225						   64,	/* dstX1 */
1226						   dstY1, /* dstY1 */
1227						   GL_COLOR_BUFFER_BIT, filter);
1228
1229		/* Verify GL_INVALID_OPERATION was returned */
1230		glw::GLenum error_code = gl.getError();
1231
1232		if (error_code != GL_INVALID_OPERATION)
1233		{
1234			m_testCtx.getLog() << tcu::TestLog::Message << "Invalid glBlitFramebuffer() call for filter argument ["
1235							   << filter << "]"
1236											"should have generated a GL_INVALID_OPERATION error. Instead, "
1237											"["
1238							   << error_code << "] error was reported." << tcu::TestLog::EndMessage;
1239
1240			TCU_FAIL("GL_INVALID_OPERATION was not returned by invalid glBlitFramebuffer() call.");
1241		}
1242	} /* for (all valid filter argument values) */
1243
1244	/* All done */
1245	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1246
1247	return STOP;
1248}
1249
1250/** Constructor.
1251 *
1252 *  @param context Rendering context handle.
1253 **/
1254MultisampleTextureFunctionalTestsSampleMaskingForNonIntegerColorRenderableTexturesTest::
1255	MultisampleTextureFunctionalTestsSampleMaskingForNonIntegerColorRenderableTexturesTest(Context& context)
1256	: TestCase(context, "verify_sample_masking_for_non_integer_color_renderable_internalformats",
1257			   "Verifies sample masking mechanism for non-integer color-renderable "
1258			   "internalformats used for 2D multisample textures")
1259	, bo_id(0)
1260	, fbo_id(0)
1261	, fs_draw_id(0)
1262	, po_draw_id(0)
1263	, po_verify_id(0)
1264	, tfo_id(0)
1265	, to_2d_multisample_id(0)
1266	, vs_draw_id(0)
1267	, vs_verify_id(0)
1268{
1269	/* Left blank on purpose */
1270}
1271
1272/** Deinitializes ES objects created during test execution */
1273void MultisampleTextureFunctionalTestsSampleMaskingForNonIntegerColorRenderableTexturesTest::deinit()
1274{
1275	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1276
1277	/* Unset used program */
1278	gl.useProgram(0);
1279
1280	/* Unbind transform feedback object bound to GL_TRANSFORM_FEEDBACK target */
1281	gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
1282
1283	/* Unbind buffer object bound to GL_TRANSFORM_FEEDBACK_BUFFER target */
1284	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
1285
1286	/* Unbind framebuffer object bound to GL_DRAW_FRAMEBUFFER target */
1287	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1288
1289	/* Unbind texture object bound to GL_TEXTURE_2D_MULTISAMPLE texture target */
1290	gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
1291
1292	/* Delete a 2D multisample texture object of id to_2d_multisample_id */
1293	if (to_2d_multisample_id != 0)
1294	{
1295		gl.deleteTextures(1, &to_2d_multisample_id);
1296
1297		to_2d_multisample_id = 0;
1298	}
1299
1300	/* Delete a buffer object of id bo_id */
1301	if (bo_id != 0)
1302	{
1303		gl.deleteBuffers(1, &bo_id);
1304
1305		bo_id = 0;
1306	}
1307
1308	/* Delete a framebuffer object of id fbo_id */
1309	if (fbo_id != 0)
1310	{
1311		gl.deleteFramebuffers(1, &fbo_id);
1312
1313		fbo_id = 0;
1314	}
1315
1316	/* Delete a transform feedback object of id tfo_id */
1317	if (tfo_id != 0)
1318	{
1319		gl.deleteTransformFeedbacks(1, &tfo_id);
1320
1321		tfo_id = 0;
1322	}
1323
1324	/* Delete fs_draw_id shader */
1325	if (fs_draw_id != 0)
1326	{
1327		gl.deleteShader(fs_draw_id);
1328
1329		fs_draw_id = 0;
1330	}
1331
1332	/* Delete vs_verify_id shader */
1333	if (vs_verify_id != 0)
1334	{
1335		gl.deleteShader(vs_verify_id);
1336
1337		vs_verify_id = 0;
1338	}
1339
1340	/* Delete vs_draw_id shader */
1341	if (vs_draw_id != 0)
1342	{
1343		gl.deleteShader(vs_draw_id);
1344
1345		vs_draw_id = 0;
1346	}
1347
1348	/* Delete program objects po_verify_id */
1349	if (po_verify_id != 0)
1350	{
1351		gl.deleteProgram(po_verify_id);
1352
1353		po_verify_id = 0;
1354	}
1355
1356	/* Delete program objects po_draw_id */
1357	if (po_draw_id != 0)
1358	{
1359		gl.deleteProgram(po_draw_id);
1360
1361		po_draw_id = 0;
1362	}
1363
1364	/* Call base class' deinit() */
1365	TestCase::deinit();
1366}
1367
1368/** Initializes test-specific ES objects */
1369void MultisampleTextureFunctionalTestsSampleMaskingForNonIntegerColorRenderableTexturesTest::initInternals()
1370{
1371	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1372
1373	/* Generate a 2D multisample texture object of id to_2d_multisample_id */
1374	gl.genTextures(1, &to_2d_multisample_id);
1375
1376	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed");
1377
1378	if (to_2d_multisample_id == 0)
1379	{
1380		TCU_FAIL("Texture object has not been generated properly");
1381	}
1382
1383	/* Generate a buffer object of id bo_id */
1384	gl.genBuffers(1, &bo_id);
1385
1386	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed");
1387
1388	if (bo_id == 0)
1389	{
1390		TCU_FAIL("Buffer object has not been generated properly");
1391	}
1392
1393	/* Generate a framebuffer object of id fbo_id */
1394	gl.genFramebuffers(1, &fbo_id);
1395
1396	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed");
1397
1398	if (fbo_id == 0)
1399	{
1400		TCU_FAIL("Framebuffer object has not been generated properly");
1401	}
1402
1403	/* Generate a transform feedback object of id tfo_id */
1404	gl.genTransformFeedbacks(1, &tfo_id);
1405
1406	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTransformFeedbacks() call failed");
1407
1408	if (tfo_id == 0)
1409	{
1410		TCU_FAIL("Transform feedback object has not been generated properly");
1411	}
1412
1413	/* Create a vertex shader vs_draw_id */
1414	vs_draw_id = gl.createShader(GL_VERTEX_SHADER);
1415
1416	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed for vs_draw_id");
1417
1418	/* Create a vertex shader vs_verify_id */
1419	vs_verify_id = gl.createShader(GL_VERTEX_SHADER);
1420
1421	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed for vs_verify_id");
1422
1423	/* Create a fragment shader fs_draw_id */
1424	fs_draw_id = gl.createShader(GL_FRAGMENT_SHADER);
1425
1426	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed for fs_draw_id");
1427
1428	/* Create program objects po_draw_id */
1429	po_draw_id = gl.createProgram();
1430
1431	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed for po_draw_id");
1432
1433	/* Create program objects po_verify_id */
1434	po_verify_id = gl.createProgram();
1435
1436	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed for po_verify_id");
1437}
1438
1439/** Executes test iteration.
1440 *
1441 *  @return Always STOP.
1442 */
1443tcu::TestNode::IterateResult MultisampleTextureFunctionalTestsSampleMaskingForNonIntegerColorRenderableTexturesTest::
1444	iterate()
1445{
1446	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1447
1448	initInternals();
1449
1450	/* Constants */
1451	const glw::GLfloat epsilon		  = 1e-5f;
1452	const glw::GLfloat expected_value = 1.0f;
1453	const glw::GLchar* fs_draw_body   = "#version 310 es\n"
1454									  "\n"
1455									  "precision highp float;\n"
1456									  "\n"
1457									  "out vec4 out_color;\n"
1458									  "\n"
1459									  "void main()\n"
1460									  "{\n"
1461									  "    out_color = vec4(1, 1, 1, 1);\n"
1462									  "}\n";
1463
1464	const glw::GLchar* vs_draw_body = "#version 310 es\n"
1465									  "\n"
1466									  "precision highp float;\n"
1467									  "\n"
1468									  "void main()\n"
1469									  "{\n"
1470									  "    switch (gl_VertexID)\n"
1471									  "    {\n"
1472									  "        case 0: gl_Position = vec4(-1,  1, 0, 1); break;\n"
1473									  "        case 1: gl_Position = vec4( 1,  1, 0, 1); break;\n"
1474									  "        case 2: gl_Position = vec4( 1, -1, 0, 1); break;\n"
1475									  "        case 3: gl_Position = vec4(-1, -1, 0, 1); break;\n"
1476									  "    }\n"
1477									  "}\n";
1478
1479	const glw::GLchar* vs_verify_body = "#version 310 es\n"
1480										"\n"
1481										"precision highp float;\n"
1482										"\n"
1483										"uniform uint              n_bit_on;\n"
1484										"uniform uint              n_bits;\n"
1485										"uniform highp sampler2DMS sampler;\n"
1486										"\n"
1487										"out float result;\n"
1488										"\n"
1489										"void main()\n"
1490										"{\n"
1491										"    vec4 one  = vec4(1);\n"
1492										"    vec4 zero = vec4(0.0, 0.0, 0.0, 1.0);\n"
1493										"\n"
1494										"    result = 1.0;\n"
1495										"\n"
1496										"    for (uint n_current_bit = 0u; n_current_bit < n_bits; n_current_bit++)\n"
1497										"    {\n"
1498										"        vec4 value = texelFetch(sampler, ivec2(0), int(n_current_bit));\n"
1499										"\n"
1500										"        if (n_bit_on == n_current_bit)\n"
1501										"        {\n"
1502										"            if (any(notEqual(value, one)))\n"
1503										"            {\n"
1504										"                result = 0.1 + float(n_current_bit)/1000.0;\n"
1505										"                break;\n"
1506										"            }\n"
1507										"        }\n"
1508										"        else\n"
1509										"        {\n"
1510										"            if (any(notEqual(value, zero)))\n"
1511										"            {\n"
1512										"                result = 0.2 + float(n_current_bit)/1000.0;\n"
1513										"                break;\n"
1514										"            }\n"
1515										"        }\n"
1516										"    }\n"
1517										"}\n";
1518
1519	/* Configure the vertex shader vs_draw_id */
1520	compileShader(vs_draw_id, vs_draw_body);
1521
1522	/* Configure the vertex shader vs_verify_id */
1523	compileShader(vs_verify_id, vs_verify_body);
1524
1525	/* Configure the fragment shader fs_draw_id */
1526	compileShader(fs_draw_id, fs_draw_body);
1527
1528	/* Attach the shaders vs_draw_id and fs_draw_id to program object po_draw_id */
1529	gl.attachShader(po_draw_id, vs_draw_id);
1530	gl.attachShader(po_draw_id, fs_draw_id);
1531
1532	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not configure po_draw_id program object");
1533
1534	/* Attach the shaders vs_verify_id and fs_draw_id to program object po_verify_id */
1535	gl.attachShader(po_verify_id, vs_verify_id);
1536	gl.attachShader(po_verify_id, fs_draw_id);
1537
1538	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not configure po_verify_id program object");
1539
1540	/* Configure vs_verify_id for transform feedback - our varying of choice is result and we're happy to use either of the TF modes since we'll be outputting a single float anyway. */
1541	const glw::GLchar* vs_verify_varying_name = "result";
1542
1543	gl.transformFeedbackVaryings(po_verify_id, 1, &vs_verify_varying_name, GL_SEPARATE_ATTRIBS);
1544
1545	/* Link the program objects po_draw_id */
1546	linkProgram(po_draw_id);
1547
1548	/* Link the program objects po_verify_id */
1549	linkProgram(po_verify_id);
1550
1551	/* Retrieve uniform locations */
1552	glw::GLuint n_bits_location   = gl.getUniformLocation(po_verify_id, "n_bits");
1553	glw::GLuint n_bit_on_location = gl.getUniformLocation(po_verify_id, "n_bit_on");
1554
1555	/* Bind the to_2d_multisample_id texture object to GL_TEXTURE_2D_MULTISAMPLE texture target */
1556	gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, to_2d_multisample_id);
1557
1558	/* Bind the fbo_id framebuffer object to GL_DRAW_FRAMEBUFFER target */
1559	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_id);
1560
1561	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up a framebuffer object");
1562
1563	/* Bind the bo_id buffer object to GL_TRANSFORM_FEEDBACK_BUFFER generic target */
1564	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, bo_id);
1565
1566	/* Bind the tfo_id transform feedback object go GL_TRANSFORM_FEEDBACK target */
1567	gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfo_id);
1568
1569	/* Bind the bo_id buffer object to zeroth binding point of GL_TRANSFORM_FEEDBACK_BUFFER */
1570	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, bo_id);
1571
1572	/* Initialize buffer object's storage to hold a total of 4 bytes (sizeof(float) );*/
1573	gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(glw::GLfloat), NULL, GL_STATIC_DRAW);
1574
1575	/* Attach the 2D multisample texture object to the framebuffer object's zeroth color attachment */
1576	gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, to_2d_multisample_id,
1577							0); /* level */
1578
1579	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up zeroth color attachment");
1580
1581	/* Enable GL_SAMPLE_MASK mode */
1582	gl.enable(GL_SAMPLE_MASK);
1583
1584	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_SAMPLE_MASK) call generated an unexpected error");
1585
1586	/* Color-renderable internalformats to test, note that GL_R8 will not work since sampling from
1587	 * such format will never return {1,1,1,1} or {0,0,0,1} which current shader uses for sample validation */
1588	const glw::GLenum internalformat_list[]		= { GL_RGBA8, GL_RGB565, GL_SRGB8_ALPHA8 };
1589	const int		  internalformat_list_count = sizeof(internalformat_list) / sizeof(internalformat_list[0]);
1590
1591	/* Get GL_MAX_SAMPLES value */
1592	glw::GLint gl_max_samples_value = 0;
1593
1594	gl.getIntegerv(GL_MAX_SAMPLES, &gl_max_samples_value);
1595
1596	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to retrieve GL_MAX_SAMPLES value");
1597
1598	if (gl_max_samples_value > 32)
1599	{
1600		m_testCtx.getLog() << tcu::TestLog::Message << "The test case checks only first 32 samples out of "
1601						   << gl_max_samples_value << " reported by GL_MAX_SAMPLES." << tcu::TestLog::EndMessage;
1602	}
1603
1604	/* Work with no more than 32 bits of mask's first word */
1605	const glw::GLint mask_bits_to_check = de::min(gl_max_samples_value, 32);
1606
1607	/* Keep the results but continue running all cases */
1608	bool test_fail = false;
1609
1610	/* Iterate through all internal formats test case should check */
1611	for (int internalformat_index = 0; internalformat_index < internalformat_list_count; internalformat_index++)
1612	{
1613		/* Configure the texture object storage */
1614		gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, mask_bits_to_check, /* samples */
1615								   internalformat_list[internalformat_index], 1,  /* width */
1616								   1,											  /* height */
1617								   GL_TRUE);									  /* fixedsamplelocations */
1618
1619		/* Make sure no errors were reported. The framebuffer should be considered complete at this moment. */
1620		GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2DMultisample() call failed");
1621
1622		/* Following code does not affect test method. Just checks if FBO is complete
1623		 To catch errors earlier */
1624
1625		glw::GLenum fbo_completeness_status = gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER);
1626
1627		if (fbo_completeness_status != GL_FRAMEBUFFER_COMPLETE)
1628		{
1629			m_testCtx.getLog() << tcu::TestLog::Message
1630							   << "Draw FBO completeness status is: " << fbo_completeness_status
1631							   << ", expected: GL_FRAMEBUFFER_COMPLETE" << tcu::TestLog::EndMessage;
1632
1633			TCU_FAIL("Draw FBO is considered incomplete which is invalid");
1634		}
1635
1636		/* For all values of n_bit from range <0, GL_MAX_SAMPLES pname value) */
1637		for (int n_bit = 0; n_bit < mask_bits_to_check; n_bit++)
1638		{
1639
1640			/* We need to clear render buffer, otherwise masked samples will have undefined values */
1641			glw::GLfloat clear_color_src[] = { 0.0f, 0.0f, 0.0f, 1.0f };
1642
1643			gl.clearBufferfv(GL_COLOR, 0, clear_color_src);
1644			GLU_EXPECT_NO_ERROR(gl.getError(), "clearBufferfv() call failed");
1645
1646			/* Use program object po_draw_id */
1647			gl.useProgram(po_draw_id);
1648
1649			/* Configure sample mask to only render n_bit-th sample using glSampleMaski() function */
1650			gl.sampleMaski(0, 1 << n_bit);
1651
1652			/* Draw a triangle fan of 4 vertices. This fills to_2d_id with multisampled data.
1653			 * However, due to active GL_SAMPLE_MASK and the way we configured it, only one sample should have been rendered.
1654			 * The only way we can check if this is the case is by using a special shader,
1655			 * because we have no way of downloading multisampled data to process space in ES3.0+.
1656			 */
1657			gl.drawArrays(GL_TRIANGLE_FAN, 0, /* first */
1658						  4 /* count */);
1659
1660			/* Unbind fbo_id before sourcing from the texture attached to it */
1661			gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1662
1663			/* Enable GL_RASTERIZER_DISCARD mode */
1664			gl.enable(GL_RASTERIZER_DISCARD);
1665			{
1666				/* Use program object po_verify_id */
1667				gl.useProgram(po_verify_id);
1668
1669				/* Specify input arguments for vertex shader */
1670				gl.uniform1ui(n_bits_location, mask_bits_to_check);
1671				gl.uniform1ui(n_bit_on_location, n_bit);
1672
1673				/* Bind to_2d_multisample_id to GL_TEXTURE_2D_MULTISAMPLE texture target. Current texture unit is GL_TEXTURE0 */
1674				gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, to_2d_multisample_id);
1675
1676				/* Begin transform feedback (primitiveMode: GL_POINTS) */
1677				gl.beginTransformFeedback(GL_POINTS);
1678				{
1679					/* Draw a single point. This will fill our transform feedback buffer with result */
1680					gl.drawArrays(GL_POINTS, 0, 1);
1681				}
1682				/* End transform feedback */
1683				gl.endTransformFeedback();
1684			}
1685			/* Disable GL_RASTERIZER_DISCARD mode */
1686			gl.disable(GL_RASTERIZER_DISCARD);
1687
1688			/* Make sure no errors were generated */
1689			GLU_EXPECT_NO_ERROR(gl.getError(), "Transform feedback failed");
1690
1691			/* Rebind the fbo_id framebuffer object to GL_DRAW_FRAMEBUFFER target */
1692			gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_id);
1693
1694			/* Map buffer object bo_id's contents to user-space */
1695			const glw::GLfloat* mapped_bo =
1696				(glw::GLfloat*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 4, GL_MAP_READ_BIT);
1697
1698			GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed");
1699
1700			/* Copy result from buffer */
1701			glw::GLfloat result = *mapped_bo;
1702
1703			/* Unmap the buffer object */
1704			gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1705
1706			GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed");
1707
1708			/* Verify the value stored by verification program is not 0. If it is 0, the test has failed. */
1709			if (de::abs(result - expected_value) > epsilon)
1710			{
1711				m_testCtx.getLog() << tcu::TestLog::Message << "Unexpected value stored by verification program: ["
1712								   << result << "],"
1713								   << "Format index: " << internalformat_index << ", "
1714								   << "Bit to check: [" << n_bit << "." << tcu::TestLog::EndMessage;
1715				/* Notice test failure */
1716				test_fail = true;
1717			}
1718		}
1719
1720		/* Delete the 2D multisample texture object with glDeleteTextures() call and re-bind the object to a GL_TEXTURE_2D_MULTISAMPLE texture target with a glBindTexture() call */
1721		gl.deleteTextures(1, &to_2d_multisample_id);
1722
1723		to_2d_multisample_id = 0;
1724
1725		/* Recreate to_2d_multisample_id texture object. */
1726		/* Generate a 2D multisample texture object of id to_2d_multisample_id */
1727		gl.genTextures(1, &to_2d_multisample_id);
1728
1729		GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed");
1730
1731		if (to_2d_multisample_id == 0)
1732		{
1733			TCU_FAIL("Texture object has not been generated properly");
1734		}
1735
1736		/* Bind the to_2d_id texture object to GL_TEXTURE_2D_MULTISAMPLE texture target */
1737		gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, to_2d_multisample_id);
1738
1739		/* Attach the 2D multisample texture object to the framebuffer object's zeroth color attachment */
1740		gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,
1741								to_2d_multisample_id, 0); /* level */
1742
1743		GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up zeroth color attachment");
1744	}
1745
1746	if (test_fail)
1747	{
1748		TCU_FAIL("Value stored by verification program is not 1.0. Test has failed.");
1749	}
1750
1751	/* Test case passed */
1752	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1753
1754	return STOP;
1755}
1756
1757/** Links a program object. Shaders should be attached to program id before call.
1758 *  If an error reported throws an exception.
1759 *
1760 *  @param id Program id
1761 */
1762void MultisampleTextureFunctionalTestsSampleMaskingForNonIntegerColorRenderableTexturesTest::linkProgram(glw::GLuint id)
1763{
1764	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1765
1766	/* Link the test program object */
1767	glw::GLint link_status = GL_FALSE;
1768
1769	gl.linkProgram(id);
1770	GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed");
1771
1772	gl.getProgramiv(id, GL_LINK_STATUS, &link_status);
1773
1774	if (link_status != GL_TRUE)
1775	{
1776		TCU_FAIL("Program linking failed");
1777	}
1778}
1779
1780/** Compiles the shader. Should the shader not compile, a TestError exception will be thrown.
1781 *
1782 *  @param id     Generated shader id
1783 *  @param source NULL-terminated shader source code string
1784 */
1785void MultisampleTextureFunctionalTestsSampleMaskingForNonIntegerColorRenderableTexturesTest::compileShader(
1786	glw::GLuint id, const glw::GLchar* source)
1787{
1788	glw::GLint			  compile_status = GL_FALSE;
1789	const glw::Functions& gl			 = m_context.getRenderContext().getFunctions();
1790
1791	gl.shaderSource(id, 1, &source, NULL);
1792	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed");
1793
1794	gl.compileShader(id);
1795	GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed");
1796
1797	gl.getShaderiv(id, GL_COMPILE_STATUS, &compile_status);
1798
1799	if (compile_status != GL_TRUE)
1800	{
1801		/* Retrieve adn dump compliation fail reason */
1802		char		 infoLog[1024];
1803		glw::GLsizei length = 0;
1804
1805		gl.getShaderInfoLog(id, 1024, &length, infoLog);
1806
1807		m_testCtx.getLog() << tcu::TestLog::Message << "Shader compilation failed, shader id=" << id
1808						   << ", infoLog: " << infoLog << tcu::TestLog::EndMessage;
1809
1810		TCU_FAIL("Shader compilation failed");
1811	}
1812}
1813
1814/** Constructor.
1815 *
1816 *  @param context Rendering context handle.
1817 **/
1818MultisampleTextureFunctionalTestsSampleMaskingTexturesTest::MultisampleTextureFunctionalTestsSampleMaskingTexturesTest(
1819	Context& context)
1820	: TestCase(context, "verify_sample_masking_textures",
1821			   "Verifies sample masking mechanism for non-integer, integer/unsigned, "
1822			   "integer/signed color-renderable internalformats and "
1823			   "depth-renderable internalformats. All internalformats "
1824			   "are used for 2D multisample textures.")
1825	, bo_id(0)
1826	, fbo_id(0)
1827	, fs_draw_id(0)
1828	, po_draw_id(0)
1829	, po_verify_id(0)
1830	, tfo_id(0)
1831	, to_2d_multisample_id(0)
1832	, vs_draw_id(0)
1833	, vs_verify_id(0)
1834{
1835	/* Left blank on purpose */
1836}
1837
1838/** Deinitializes ES objects created during test execution */
1839void MultisampleTextureFunctionalTestsSampleMaskingTexturesTest::deinit()
1840{
1841	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1842
1843	/* Unset used program */
1844	gl.useProgram(0);
1845
1846	/* Unbind transform feedback object bound to GL_TRANSFORM_FEEDBACK target */
1847	gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
1848
1849	/* Unbind buffer object bound to GL_TRANSFORM_FEEDBACK_BUFFER target */
1850	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
1851
1852	/* Unbind framebuffer object bound to GL_DRAW_FRAMEBUFFER target */
1853	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1854
1855	/* Unbind texture object bound to GL_TEXTURE_2D_MULTISAMPLE texture target */
1856	gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
1857
1858	/* Delete a 2D multisample texture object of id to_2d_multisample_id */
1859	if (to_2d_multisample_id != 0)
1860	{
1861		gl.deleteTextures(1, &to_2d_multisample_id);
1862
1863		to_2d_multisample_id = 0;
1864	}
1865
1866	/* Delete a buffer object of id bo_id */
1867	if (bo_id != 0)
1868	{
1869		gl.deleteBuffers(1, &bo_id);
1870
1871		bo_id = 0;
1872	}
1873
1874	/* Delete a framebuffer object of id fbo_id */
1875	if (fbo_id != 0)
1876	{
1877		gl.deleteFramebuffers(1, &fbo_id);
1878
1879		fbo_id = 0;
1880	}
1881
1882	/* Delete a transform feedback object of id tfo_id */
1883	if (tfo_id != 0)
1884	{
1885		gl.deleteTransformFeedbacks(1, &tfo_id);
1886
1887		tfo_id = 0;
1888	}
1889
1890	/* Delete fs_draw_id shader */
1891	if (fs_draw_id != 0)
1892	{
1893		gl.deleteShader(fs_draw_id);
1894
1895		fs_draw_id = 0;
1896	}
1897
1898	/* Delete vs_verify_id shader */
1899	if (vs_verify_id != 0)
1900	{
1901		gl.deleteShader(vs_verify_id);
1902
1903		vs_verify_id = 0;
1904	}
1905
1906	/* Delete vs_draw_id shader */
1907	if (vs_draw_id != 0)
1908	{
1909		gl.deleteShader(vs_draw_id);
1910
1911		vs_draw_id = 0;
1912	}
1913
1914	/* Delete program objects po_verify_id */
1915	if (po_verify_id != 0)
1916	{
1917		gl.deleteProgram(po_verify_id);
1918
1919		po_verify_id = 0;
1920	}
1921
1922	/* Delete program objects po_draw_id */
1923	if (po_draw_id != 0)
1924	{
1925		gl.deleteProgram(po_draw_id);
1926
1927		po_draw_id = 0;
1928	}
1929
1930	/* Call base class' deinit() */
1931	TestCase::deinit();
1932}
1933
1934/** Initializes test-specific ES objects */
1935void MultisampleTextureFunctionalTestsSampleMaskingTexturesTest::initInternals()
1936{
1937	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1938
1939	/* Generate a 2D multisample texture object of id to_2d_multisample_id */
1940	gl.genTextures(1, &to_2d_multisample_id);
1941
1942	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed");
1943
1944	if (to_2d_multisample_id == 0)
1945	{
1946		TCU_FAIL("Texture object has not been generated properly");
1947	}
1948
1949	/* Generate a buffer object of id bo_id */
1950	gl.genBuffers(1, &bo_id);
1951
1952	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed");
1953
1954	if (bo_id == 0)
1955	{
1956		TCU_FAIL("Buffer object has not been generated properly");
1957	}
1958
1959	/* Generate a framebuffer object of id fbo_id */
1960	gl.genFramebuffers(1, &fbo_id);
1961
1962	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed");
1963
1964	if (fbo_id == 0)
1965	{
1966		TCU_FAIL("Framebuffer object has not been generated properly");
1967	}
1968
1969	/* Generate a transform feedback object of id tfo_id */
1970	gl.genTransformFeedbacks(1, &tfo_id);
1971
1972	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTransformFeedbacks() call failed");
1973
1974	if (tfo_id == 0)
1975	{
1976		TCU_FAIL("Transform feedback object has not been generated properly");
1977	}
1978
1979	/* Create a vertex shader vs_draw_id */
1980	vs_draw_id = gl.createShader(GL_VERTEX_SHADER);
1981
1982	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed for vs_draw_id");
1983
1984	/* Create a vertex shader vs_verify_id */
1985	vs_verify_id = gl.createShader(GL_VERTEX_SHADER);
1986
1987	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed for vs_verify_id");
1988
1989	/* Create a fragment shader fs_draw_id */
1990	fs_draw_id = gl.createShader(GL_FRAGMENT_SHADER);
1991
1992	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed for fs_draw_id");
1993
1994	/* Create program objects po_draw_id */
1995	po_draw_id = gl.createProgram();
1996
1997	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed for po_draw_id");
1998
1999	/* Create program objects po_verify_id */
2000	po_verify_id = gl.createProgram();
2001
2002	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed for po_verify_id");
2003}
2004
2005/** Executes test iteration.
2006 *
2007 *  @return Always STOP.
2008 */
2009tcu::TestNode::IterateResult MultisampleTextureFunctionalTestsSampleMaskingTexturesTest::iterate()
2010{
2011	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2012
2013	initInternals();
2014
2015	/* Constants */
2016	const glw::GLfloat epsilon		= 1e-5f;
2017	const glw::GLchar* fs_draw_body = "#version 310 es\n"
2018									  "\n"
2019									  "out vec4 out_color;\n"
2020									  "\n"
2021									  "void main()\n"
2022									  "{\n"
2023									  "    out_color = vec4(1, 1, 1, 1);\n"
2024									  "}\n";
2025
2026	const glw::GLchar* vs_draw_body = "#version 310 es\n"
2027									  "\n"
2028									  "void main()\n"
2029									  "{\n"
2030									  "    switch (gl_VertexID)\n"
2031									  "    {\n"
2032									  "        case 0: gl_Position = vec4(-1,  1, 0, 1); break;\n"
2033									  "        case 1: gl_Position = vec4( 1,  1, 0, 1); break;\n"
2034									  "        case 2: gl_Position = vec4( 1, -1, 0, 1); break;\n"
2035									  "        case 3: gl_Position = vec4(-1, -1, 0, 1); break;\n"
2036									  "    }\n"
2037									  "}\n";
2038
2039	const glw::GLchar* vs_verify_body = "#version 310 es\n"
2040										"\n"
2041										"precision highp float;\n"
2042										"\n"
2043										"uniform uint              n_bit_on;\n"
2044										"uniform uint              n_bits;\n"
2045										"uniform highp sampler2DMS sampler;\n"
2046										"\n"
2047										"out float result;\n"
2048										"\n"
2049										"void main()\n"
2050										"{\n"
2051										"    vec4 one  = vec4(1);\n"
2052										"    vec4 zero = vec4(0);\n"
2053										"\n"
2054										"    result = 1.0;\n"
2055										"\n"
2056										"    for (uint n_current_bit = 0u; n_current_bit < n_bits; n_current_bit++)\n"
2057										"    {\n"
2058										"        vec4 value = texelFetch(sampler, ivec2(0), int(n_current_bit));\n"
2059										"\n"
2060										"        if (n_bit_on == n_current_bit)\n"
2061										"        {\n"
2062										"            if (any(notEqual(value, one)))\n"
2063										"            {\n"
2064										"                result = 0.0;\n"
2065										"            }\n"
2066										"        }\n"
2067										"        else\n"
2068										"        {\n"
2069										"            if (any(notEqual(value, zero)))\n"
2070										"            {\n"
2071										"                result = 0.0;\n"
2072										"            }\n"
2073										"        }\n"
2074										"    }\n"
2075										"}\n";
2076
2077	/* Configure the vertex shader vs_draw_id */
2078	compileShader(vs_draw_id, vs_draw_body);
2079
2080	/* Configure the vertex shader vs_verify_id */
2081	compileShader(vs_verify_id, vs_verify_body);
2082
2083	/* Configure the fragment shader fs_draw_id */
2084	compileShader(fs_draw_id, fs_draw_body);
2085
2086	/* Attach the shaders vs_draw_id and fs_draw_id to program object po_draw_id */
2087	gl.attachShader(po_draw_id, vs_draw_id);
2088	gl.attachShader(po_draw_id, fs_draw_id);
2089
2090	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not configure po_draw_id program object");
2091
2092	/* Attach the shaders vs_verify_id and fs_draw_id to program object po_verify_id */
2093	gl.attachShader(po_verify_id, vs_verify_id);
2094	gl.attachShader(po_verify_id, fs_draw_id);
2095
2096	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not configure po_verify_id program object");
2097
2098	/* Configure vs_verify_id for transform feedback - our varying of choice is result and we're happy to use either of the TF modes since we'll be outputting a single float anyway. */
2099	const glw::GLchar* vs_verify_varying_name = "result";
2100
2101	gl.transformFeedbackVaryings(po_verify_id, 1, &vs_verify_varying_name, GL_SEPARATE_ATTRIBS);
2102
2103	/* Link the program objects po_draw_id */
2104	linkProgram(po_draw_id);
2105
2106	/* Link the program objects po_verify_id */
2107	linkProgram(po_verify_id);
2108
2109	/* Retrieve uniform locations */
2110	glw::GLuint n_bits_location   = gl.getUniformLocation(po_verify_id, "n_bits");
2111	glw::GLuint n_bit_on_location = gl.getUniformLocation(po_verify_id, "n_bit_on");
2112
2113	/* Bind the to_2d_multisample_id texture object to GL_TEXTURE_2D_MULTISAMPLE texture target */
2114	gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, to_2d_multisample_id);
2115
2116	/* Bind the fbo_id framebuffer object to GL_DRAW_FRAMEBUFFER target */
2117	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_id);
2118
2119	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up a framebuffer object");
2120
2121	/* Bind the bo_id buffer object to GL_TRANSFORM_FEEDBACK_BUFFER generic target */
2122	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, bo_id);
2123
2124	/* Bind the bo_id buffer object to zeroth binding point of GL_TRANSFORM_FEEDBACK_BUFFER */
2125	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, bo_id);
2126
2127	/* Bind the tfo_id transform feedback object go GL_TRANSFORM_FEEDBACK target */
2128	gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfo_id);
2129
2130	/* Initialize buffer object's storage to hold a total of 4 bytes (sizeof(float) );*/
2131	gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(glw::GLfloat), NULL, GL_STATIC_DRAW);
2132
2133	/* Attach the 2D multisample texture object to the framebuffer object's zeroth color attachment */
2134	gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, to_2d_multisample_id,
2135							0); /* level */
2136
2137	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up zeroth color attachment");
2138
2139	/* Enable GL_SAMPLE_MASK mode */
2140	gl.enable(GL_SAMPLE_MASK);
2141
2142	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_SAMPLE_MASK) call generated an unexpected error");
2143
2144	/* Iterate through color-normalized-, color-unsigned-integer-, color-signed-integer- and depth-renderable internalformats */
2145	const glw::GLenum  normalized_color_internalformats[] = { GL_R8, GL_RGB565, GL_SRGB8_ALPHA8 };
2146	const glw::GLenum  unsigned_color_internalformats[]   = { GL_RGBA32UI, GL_RG16UI };
2147	const glw::GLenum  signed_color_internalformats[]	 = { GL_RGBA32I, GL_RG16I };
2148	const glw::GLenum  depth_internalformats[]			  = { GL_DEPTH_COMPONENT32F };
2149	const unsigned int n_normalized_color_internalformats =
2150		sizeof(normalized_color_internalformats) / sizeof(normalized_color_internalformats[0]);
2151	const unsigned int n_unsigned_color_internalformats =
2152		sizeof(unsigned_color_internalformats) / sizeof(unsigned_color_internalformats[0]);
2153	const unsigned int n_signed_color_internalformats =
2154		sizeof(signed_color_internalformats) / sizeof(signed_color_internalformats[0]);
2155	const unsigned int n_depth_internalformats = sizeof(depth_internalformats) / sizeof(depth_internalformats[0]);
2156
2157	for (unsigned int n_iteration = 0; n_iteration < 4 /* normalized/unsigned/signed/depth */; ++n_iteration)
2158	{
2159		glw::GLenum		   attachment		 = 0;
2160		const glw::GLenum* internalformats   = NULL;
2161		unsigned int	   n_internalformats = 0;
2162
2163		switch (n_iteration)
2164		{
2165		case 0:
2166		{
2167			attachment		  = GL_COLOR_ATTACHMENT0;
2168			internalformats   = normalized_color_internalformats;
2169			n_internalformats = n_normalized_color_internalformats;
2170
2171			break;
2172		}
2173
2174		case 1:
2175		{
2176			attachment		  = GL_COLOR_ATTACHMENT0;
2177			internalformats   = unsigned_color_internalformats;
2178			n_internalformats = n_unsigned_color_internalformats;
2179
2180			break;
2181		}
2182
2183		case 2:
2184		{
2185			attachment		  = GL_COLOR_ATTACHMENT0;
2186			internalformats   = signed_color_internalformats;
2187			n_internalformats = n_signed_color_internalformats;
2188
2189			break;
2190		}
2191
2192		case 3:
2193		{
2194			attachment		  = GL_DEPTH_ATTACHMENT;
2195			internalformats   = depth_internalformats;
2196			n_internalformats = n_depth_internalformats;
2197
2198			break;
2199		}
2200
2201		default:
2202		{
2203			TCU_FAIL("Unrecognized iteration index");
2204		}
2205		} /* switch (n_iteration) */
2206
2207		/* Iterate through internalformats */
2208		for (unsigned int n_internalformat = 0; n_internalformat < n_internalformats; ++n_internalformat)
2209		{
2210			glw::GLenum internalformat			   = internalformats[n_internalformat];
2211			glw::GLint  internalformat_max_samples = 0;
2212
2213			/* Retrieve internalformat-specific GL_MAX_SAMPLES value */
2214			gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE,	 /* target */
2215								   internalformat, GL_SAMPLES, 1, /* bufSize */
2216								   &internalformat_max_samples);
2217
2218			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInternalformativ() failed");
2219
2220			if (internalformat_max_samples > 32)
2221			{
2222				m_testCtx.getLog() << tcu::TestLog::Message << "The test case checks only first 32 samples out of "
2223								   << internalformat_max_samples
2224								   << " reported by GL_SAMPLES reported by getInternalformativ() "
2225								   << "for internalformat " << internalformat << "." << tcu::TestLog::EndMessage;
2226			}
2227
2228			/* Work with no more than 32 bits of mask's first word */
2229			const glw::GLint mask_bits_to_check = de::min(internalformat_max_samples, 32);
2230
2231			/* Recreate to_2d_multisample_id texture object. */
2232			if (to_2d_multisample_id == 0)
2233			{
2234				/* Generate a 2D multisample texture object of id to_2d_multisample_id */
2235				gl.genTextures(1, &to_2d_multisample_id);
2236
2237				GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed");
2238
2239				if (to_2d_multisample_id == 0)
2240				{
2241					TCU_FAIL("Texture object has not been generated properly");
2242				}
2243
2244				/* Bind the to_2d_id texture object to GL_TEXTURE_2D_MULTISAMPLE texture target */
2245				gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, to_2d_multisample_id);
2246
2247				/* Attach the 2D multisample texture object to the framebuffer object's attachment */
2248				gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, GL_TEXTURE_2D_MULTISAMPLE,
2249										to_2d_multisample_id, 0); /* level */
2250
2251				GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up attachment");
2252			}
2253
2254			/* Configure the texture object storage */
2255			gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, internalformat_max_samples, /* samples */
2256									   internalformat, 1,									  /* width */
2257									   1,													  /* height */
2258									   GL_TRUE);											  /* fixedsamplelocations */
2259
2260			/* Make sure no errors were reported. The framebuffer should be considered complete at this moment. */
2261			GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2DMultisample() call failed");
2262
2263			/* For all values of n_bit from range <0, GL_MAX_SAMPLES pname value) */
2264			for (int n_bit = 0; n_bit < mask_bits_to_check; n_bit++)
2265			{
2266				/* Use program object po_draw_id */
2267				gl.useProgram(po_draw_id);
2268
2269				/* Configure sample mask to only render n_bit-th sample using glSampleMaski() function */
2270				gl.sampleMaski(0, 1 << n_bit);
2271
2272				/* Draw a triangle fan of 4 vertices. This fills to_2d_id with multisampled data.
2273				 * However, due to active GL_SAMPLE_MASK and the way we configured it, only one sample should have been rendered.
2274				 * The only way we can check if this is the case is by using a special shader,
2275				 * because we have no way of downloading multisampled data to process space in ES3.0+.
2276				 */
2277				gl.drawArrays(GL_TRIANGLE_FAN, 0, /* first */
2278							  4 /* count */);
2279
2280				/* Enable GL_RASTERIZER_DISCARD mode */
2281				gl.enable(GL_RASTERIZER_DISCARD);
2282				{
2283					/* Use program object po_verify_id */
2284					gl.useProgram(po_verify_id);
2285
2286					/* Specify input arguments for vertex shader */
2287					gl.uniform1i(n_bits_location, mask_bits_to_check);
2288					gl.uniform1i(n_bit_on_location, n_bit);
2289
2290					/* Bind to_2d_multisample_id to GL_TEXTURE_2D_MULTISAMPLE texture target. Current texture unit is GL_TEXTURE0 */
2291					gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, to_2d_multisample_id);
2292
2293					/* Begin transform feedback (primitiveMode: GL_POINTS) */
2294					gl.beginTransformFeedback(GL_POINTS);
2295					{
2296						/* Draw a single point. This will fill our transform feedback buffer with result */
2297						gl.drawArrays(GL_POINTS, 0, 1);
2298					}
2299					/* End transform feedback */
2300					gl.endTransformFeedback();
2301				}
2302				/* Disable GL_RASTERIZER_DISCARD mode */
2303				gl.disable(GL_RASTERIZER_DISCARD);
2304
2305				/* Make sure no errors were generated */
2306				GLU_EXPECT_NO_ERROR(gl.getError(), "Transform feedback failed");
2307
2308				/* Map buffer object bo_id's contents to user-space */
2309				const glw::GLfloat* mapped_bo = (glw::GLfloat*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
2310
2311				GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer() call failed");
2312
2313				/* Copy result from buffer */
2314				glw::GLfloat result = *mapped_bo;
2315
2316				/* Unmap the buffer object */
2317				gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
2318
2319				GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed");
2320
2321				/* Verify the value stored by verification program is not 0. If it is 0, the test has failed. */
2322				if (de::abs(result) < epsilon)
2323				{
2324					TCU_FAIL("Value stored by verification program is zero. Test has failed.");
2325				}
2326			}
2327
2328			/* Delete the 2D multisample texture object with glDeleteTextures() call and re-bind the object to a GL_TEXTURE_2D_MULTISAMPLE texture target with a glBindTexture() call */
2329			gl.deleteTextures(1, &to_2d_multisample_id);
2330
2331			to_2d_multisample_id = 0;
2332		} /* for (all renderable internalformats) */
2333	}	 /* for (all iterations) */
2334
2335	/* Test case passed */
2336	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2337
2338	return STOP;
2339}
2340
2341/** Links a program object. Shaders should be attached to program id before call.
2342 *  If an error reported throws an exception.
2343 *
2344 *  @param id Program id
2345 */
2346void MultisampleTextureFunctionalTestsSampleMaskingTexturesTest::linkProgram(glw::GLuint id)
2347{
2348	/* Link the test program object */
2349	const glw::Functions& gl		  = m_context.getRenderContext().getFunctions();
2350	glw::GLint			  link_status = GL_FALSE;
2351
2352	gl.linkProgram(id);
2353	GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed");
2354
2355	gl.getProgramiv(id, GL_LINK_STATUS, &link_status);
2356
2357	if (link_status != GL_TRUE)
2358	{
2359		TCU_FAIL("Program linking failed");
2360	}
2361}
2362
2363/** Compiles the shader. Should the shader not compile, a TestError exception will be thrown.
2364 *
2365 *  @param id     Generated shader id
2366 *  @param source NULL-terminated shader source code string
2367 */
2368void MultisampleTextureFunctionalTestsSampleMaskingTexturesTest::compileShader(glw::GLuint		  id,
2369																			   const glw::GLchar* source)
2370{
2371	glw::GLint			  compile_status = GL_FALSE;
2372	const glw::Functions& gl			 = m_context.getRenderContext().getFunctions();
2373
2374	gl.shaderSource(id, 1, &source, NULL);
2375	GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed");
2376
2377	gl.compileShader(id);
2378	GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed");
2379
2380	gl.getShaderiv(id, GL_COMPILE_STATUS, &compile_status);
2381
2382	if (compile_status != GL_TRUE)
2383	{
2384		TCU_FAIL("Shader compilation failed");
2385	}
2386}
2387
2388/** Constructor.
2389 *
2390 *  @param context CTS context handle.
2391 **/
2392MultisampleTextureFunctionalTestsTextureSizeFragmentShadersTest::
2393	MultisampleTextureFunctionalTestsTextureSizeFragmentShadersTest(Context& context)
2394	: TestCase(context, "texture_size_in_fragment_shaders",
2395			   "Verifies textureSize() works for multisample textures when used in fragment shaders")
2396	, fbo_id(0)
2397	, fs_id(0)
2398	, po_id(0)
2399	, to_2d_multisample_id(0)
2400	, to_2d_multisample_array_id(0)
2401	, vs_id(0)
2402{
2403	/* Left blank on purpose */
2404}
2405
2406/** Deinitializes ES objects created during test execution */
2407void MultisampleTextureFunctionalTestsTextureSizeFragmentShadersTest::deinit()
2408{
2409	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2410
2411	if (fbo_id != 0)
2412	{
2413		gl.deleteFramebuffers(1, &fbo_id);
2414
2415		fbo_id = 0;
2416	}
2417
2418	if (fs_id != 0)
2419	{
2420		gl.deleteShader(fs_id);
2421
2422		fs_id = 0;
2423	}
2424
2425	if (po_id != 0)
2426	{
2427		gl.deleteProgram(po_id);
2428
2429		po_id = 0;
2430	}
2431
2432	if (to_2d_multisample_id != 0)
2433	{
2434		gl.deleteTextures(1, &to_2d_multisample_id);
2435
2436		to_2d_multisample_id = 0;
2437	}
2438
2439	if (to_2d_multisample_array_id != 0)
2440	{
2441		gl.deleteTextures(1, &to_2d_multisample_array_id);
2442
2443		to_2d_multisample_array_id = 0;
2444	}
2445
2446	if (vs_id != 0)
2447	{
2448		gl.deleteShader(vs_id);
2449
2450		vs_id = 0;
2451	}
2452
2453	/* Call base class' deinit() */
2454	TestCase::deinit();
2455}
2456
2457/** Executes test iteration.
2458 *
2459 *  @return Returns STOP when test has finished executing.
2460 */
2461tcu::TestNode::IterateResult MultisampleTextureFunctionalTestsTextureSizeFragmentShadersTest::iterate()
2462{
2463	bool are_2d_array_ms_tos_supported =
2464		m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array");
2465	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2466
2467	/* Set up texture objects */
2468	if (are_2d_array_ms_tos_supported)
2469	{
2470		gl.genTextures(1, &to_2d_multisample_array_id);
2471	}
2472
2473	gl.genTextures(1, &to_2d_multisample_id);
2474
2475	if (are_2d_array_ms_tos_supported)
2476	{
2477		gl.activeTexture(GL_TEXTURE0);
2478		gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES, to_2d_multisample_array_id);
2479		gl.texStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES, 2, /* samples */
2480								   GL_RGBA8, 16,						   /* width */
2481								   32,									   /* height */
2482								   8,									   /* depth */
2483								   GL_TRUE);							   /* fixedsamplelocations */
2484
2485		GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up 2D multisample array texture storage");
2486	}
2487
2488	gl.activeTexture(GL_TEXTURE1);
2489	gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, to_2d_multisample_id);
2490	gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 2, /* samples */
2491							   GL_RGBA8, 16,				 /* width */
2492							   32,							 /* height */
2493							   GL_TRUE);
2494
2495	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up 2D multisample texture storage");
2496
2497	/* Set up a fragment shader */
2498	static const char* fs_body =
2499		"#version 310 es\n"
2500		"\n"
2501		"#ifdef GL_OES_texture_storage_multisample_2d_array\n"
2502		"    #extension GL_OES_texture_storage_multisample_2d_array : enable\n"
2503		"#endif\n"
2504		"\n"
2505		"precision highp float;\n"
2506		"\n"
2507		"uniform highp sampler2DMS sampler_2d;\n"
2508		"\n"
2509		"#ifdef GL_OES_texture_storage_multisample_2d_array\n"
2510		"    uniform highp sampler2DMSArray sampler_2d_array;\n"
2511		"#endif"
2512		"\n"
2513		"out vec4 result;\n"
2514		"\n"
2515		"void main()\n"
2516		"{\n"
2517		"    #ifdef GL_OES_texture_storage_multisample_2d_array\n"
2518		"        ivec3 sampler_2d_array_size = textureSize(sampler_2d_array);\n"
2519		"    #else\n"
2520		"        ivec3 sampler_2d_array_size = ivec3(16, 32, 8);\n"
2521		"    #endif\n"
2522		"\n"
2523		"    ivec2 sampler_2d_size = textureSize(sampler_2d);\n"
2524		"\n"
2525		"    if (sampler_2d_size.x       == 16 && sampler_2d_size.y       == 32 &&\n"
2526		"        sampler_2d_array_size.x == 16 && sampler_2d_array_size.y == 32 && sampler_2d_array_size.z == 8)\n"
2527		"    {\n"
2528		"        result = vec4(0, 1, 0, 0);\n"
2529		"    }\n"
2530		"    else\n"
2531		"    {\n"
2532		"        result = vec4(1, 0, 0, 0);\n"
2533		"    }\n"
2534		"}\n";
2535	glw::GLint compile_status = GL_FALSE;
2536
2537	fs_id = gl.createShader(GL_FRAGMENT_SHADER);
2538
2539	gl.shaderSource(fs_id, 1 /* count */, &fs_body, NULL);
2540	gl.compileShader(fs_id);
2541	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up a fragment shader");
2542
2543	gl.getShaderiv(fs_id, GL_COMPILE_STATUS, &compile_status);
2544	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not query fragment shader's compile status");
2545
2546	if (compile_status == GL_FALSE)
2547	{
2548		TCU_FAIL("Could not compile fragment shader");
2549	}
2550
2551	/* Set up a vertex shader for 2D multisample texture case */
2552	static const char* vs_body = "#version 310 es\n"
2553								 "\n"
2554								 "precision highp float;\n"
2555								 "\n"
2556								 "void main()\n"
2557								 "{\n"
2558								 "   switch (gl_VertexID)\n"
2559								 "   {\n"
2560								 "       case 0: gl_Position = vec4(-1, -1, 0, 1); break;\n"
2561								 "       case 1: gl_Position = vec4(-1,  1, 0, 1); break;\n"
2562								 "       case 2: gl_Position = vec4( 1,  1, 0, 1); break;\n"
2563								 "       case 3: gl_Position = vec4( 1, -1, 0, 1); break;\n"
2564								 "   }\n"
2565								 "}\n";
2566
2567	vs_id = gl.createShader(GL_VERTEX_SHADER);
2568
2569	gl.shaderSource(vs_id, 1 /* count */, &vs_body, NULL);
2570	gl.compileShader(vs_id);
2571	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up a vertex shader");
2572
2573	gl.getShaderiv(vs_id, GL_COMPILE_STATUS, &compile_status);
2574	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not query vertex shader's compile status");
2575
2576	if (compile_status == GL_FALSE)
2577	{
2578		TCU_FAIL("Could not compile vertex shader");
2579	}
2580
2581	/* Set up a program object */
2582	po_id = gl.createProgram();
2583
2584	gl.attachShader(po_id, fs_id);
2585	gl.attachShader(po_id, vs_id);
2586
2587	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up a program object");
2588
2589	/* Link the program object */
2590	glw::GLint link_status = GL_FALSE;
2591
2592	gl.linkProgram(po_id);
2593	GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
2594
2595	gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status);
2596	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
2597
2598	if (link_status != GL_TRUE)
2599	{
2600		TCU_FAIL("Program object linking failed");
2601	}
2602
2603	/* Set up uniforms */
2604	glw::GLint sampler_2d_array_location = gl.getUniformLocation(po_id, "sampler_2d_array");
2605	glw::GLint sampler_2d_location		 = gl.getUniformLocation(po_id, "sampler_2d");
2606
2607	if ((sampler_2d_array_location == -1 && are_2d_array_ms_tos_supported) || sampler_2d_location == -1)
2608	{
2609		TCU_FAIL("At least one of the required uniforms is not considered active");
2610	}
2611
2612	gl.useProgram(po_id);
2613	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
2614
2615	gl.uniform1i(sampler_2d_array_location, 0);
2616	gl.uniform1i(sampler_2d_location, 1);
2617	GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i() call(s) failed.");
2618
2619	/* Render a full-screen quad */
2620	gl.drawArrays(GL_TRIANGLE_FAN, 0 /* first */, 4 /* count */);
2621	GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed");
2622
2623	/* Verify the results */
2624	const tcu::RenderTarget& rt = m_context.getRenderContext().getRenderTarget();
2625
2626	unsigned char* buffer		 = NULL;
2627	unsigned char* data_ptr		 = NULL;
2628	int			   rt_bits_alpha = 0;
2629	int			   rt_bits_blue  = 0;
2630	int			   rt_bits_green = 0;
2631	int			   rt_bits_red   = 0;
2632	int			   rt_height	 = rt.getHeight();
2633	int			   rt_width		 = rt.getWidth();
2634	const int	  row_width	 = 4 /* RGBA */ * rt_width;
2635
2636	gl.getIntegerv(GL_ALPHA_BITS, &rt_bits_alpha);
2637	gl.getIntegerv(GL_BLUE_BITS, &rt_bits_blue);
2638	gl.getIntegerv(GL_GREEN_BITS, &rt_bits_green);
2639	gl.getIntegerv(GL_RED_BITS, &rt_bits_red);
2640
2641	buffer = new unsigned char[rt_height * rt_width * 4];
2642
2643	gl.readPixels(0, 0, rt_width, rt_height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
2644	GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed");
2645
2646	data_ptr = buffer + row_width * (rt_height / 2) + rt_width / 2 * 4;
2647
2648	if (((data_ptr[0] != 0) && (rt_bits_red != 0)) || ((data_ptr[1] != 255) && (rt_bits_green != 0)) ||
2649		((data_ptr[2] != 0) && (rt_bits_blue != 0)) || ((data_ptr[3] != 0) && (rt_bits_alpha != 0)))
2650	{
2651		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid data rendered: expected:(0, 255, 0, 0) rendered:"
2652						   << "(" << data_ptr[0] << ", " << data_ptr[1] << ", " << data_ptr[2] << ", " << data_ptr[3]
2653						   << ")" << tcu::TestLog::EndMessage;
2654
2655		delete[] buffer;
2656		buffer = NULL;
2657
2658		TCU_FAIL("Invalid data rendered");
2659	}
2660
2661	if (buffer != NULL)
2662	{
2663		delete[] buffer;
2664		buffer = NULL;
2665	}
2666
2667	/* All done */
2668	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2669
2670	return STOP;
2671}
2672
2673/** Constructor.
2674 *
2675 *  @param context CTS context handle.
2676 **/
2677MultisampleTextureFunctionalTestsTextureSizeVertexShadersTest::
2678	MultisampleTextureFunctionalTestsTextureSizeVertexShadersTest(Context& context)
2679	: TestCase(context, "texture_size_in_vertex_shaders",
2680			   "Verifies textureSize() works for multisample textures when used in vertex shaders")
2681	, bo_id(0)
2682	, fbo_id(0)
2683	, fs_id(0)
2684	, po_id(0)
2685	, tfo_id(0)
2686	, to_2d_multisample_id(0)
2687	, to_2d_multisample_array_id(0)
2688	, vs_2d_array_id(0)
2689	, vs_2d_id(0)
2690{
2691	/* Left blank on purpose */
2692}
2693
2694/** Deinitializes ES objects created during test execution */
2695void MultisampleTextureFunctionalTestsTextureSizeVertexShadersTest::deinit()
2696{
2697	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2698
2699	if (bo_id != 0)
2700	{
2701		gl.deleteBuffers(1, &bo_id);
2702
2703		bo_id = 0;
2704	}
2705
2706	if (fbo_id != 0)
2707	{
2708		gl.deleteFramebuffers(1, &fbo_id);
2709
2710		fbo_id = 0;
2711	}
2712
2713	if (fs_id != 0)
2714	{
2715		gl.deleteShader(fs_id);
2716
2717		fs_id = 0;
2718	}
2719
2720	if (po_id != 0)
2721	{
2722		gl.deleteProgram(po_id);
2723
2724		po_id = 0;
2725	}
2726
2727	if (tfo_id != 0)
2728	{
2729		gl.deleteTransformFeedbacks(1, &tfo_id);
2730
2731		tfo_id = 0;
2732	}
2733
2734	if (to_2d_multisample_id != 0)
2735	{
2736		gl.deleteTextures(1, &to_2d_multisample_id);
2737
2738		to_2d_multisample_id = 0;
2739	}
2740
2741	if (to_2d_multisample_array_id != 0)
2742	{
2743		gl.deleteTextures(1, &to_2d_multisample_array_id);
2744
2745		to_2d_multisample_array_id = 0;
2746	}
2747
2748	if (vs_2d_id != 0)
2749	{
2750		gl.deleteShader(vs_2d_id);
2751
2752		vs_2d_id = 0;
2753	}
2754
2755	if (vs_2d_array_id != 0)
2756	{
2757		gl.deleteShader(vs_2d_array_id);
2758
2759		vs_2d_array_id = 0;
2760	}
2761
2762	/* Call base class' deinit() */
2763	TestCase::deinit();
2764}
2765
2766/** Executes test iteration.
2767 *
2768 *  @return Returns STOP when test has finished executing.
2769 */
2770tcu::TestNode::IterateResult MultisampleTextureFunctionalTestsTextureSizeVertexShadersTest::iterate()
2771{
2772	bool are_multisample_2d_array_tos_supported =
2773		m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array");
2774	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2775
2776	/* Set up a TFO */
2777	gl.genTransformFeedbacks(1, &tfo_id);
2778	gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfo_id);
2779
2780	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up a transform feedback object");
2781
2782	/* Set up a buffer object */
2783	gl.genBuffers(1, &bo_id);
2784	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, bo_id);
2785	gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float), NULL, GL_STATIC_READ);
2786
2787	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up a buffer object");
2788
2789	/* Set up texture objects */
2790	if (are_multisample_2d_array_tos_supported)
2791	{
2792		gl.genTextures(1, &to_2d_multisample_array_id);
2793	}
2794
2795	gl.genTextures(1, &to_2d_multisample_id);
2796
2797	/* NOTE: Since we're binding the textures to zero texture unit,
2798	 *       we don't need to do glUniform1i() calls to configure
2799	 *       the texture samplers in the vertex shaders later on.
2800	 */
2801	if (are_multisample_2d_array_tos_supported)
2802	{
2803		gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES, to_2d_multisample_array_id);
2804	}
2805
2806	gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, to_2d_multisample_id);
2807
2808	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up texture objects");
2809
2810	gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 2, /* samples */
2811							   GL_RGBA8, 16,				 /* width */
2812							   32,							 /* height */
2813							   GL_TRUE);
2814	GLU_EXPECT_NO_ERROR(gl.getError(),
2815						"glTexStorage2DMultisample() call failed for GL_TEXTURE_2D_MULTISAMPLE texture target");
2816
2817	if (are_multisample_2d_array_tos_supported)
2818	{
2819		gl.texStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES, 2, /* samples */
2820								   GL_RGBA8, 16,						   /* width */
2821								   32,									   /* height */
2822								   8,									   /* depth */
2823								   GL_TRUE);							   /* fixedsamplelocations */
2824		GLU_EXPECT_NO_ERROR(
2825			gl.getError(),
2826			"gltexStorage3DMultisample() call failed for GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES texture target");
2827	}
2828
2829	/* Set up a fragment shader */
2830	glw::GLint		   compile_status = GL_FALSE;
2831	static const char* fs_body		  = "#version 310 es\n"
2832								 "\n"
2833								 "void main()\n"
2834								 "{\n"
2835								 "}\n";
2836
2837	fs_id = gl.createShader(GL_FRAGMENT_SHADER);
2838
2839	gl.shaderSource(fs_id, 1 /* count */, &fs_body, NULL);
2840	gl.compileShader(fs_id);
2841	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up a fragment shader");
2842
2843	gl.getShaderiv(fs_id, GL_COMPILE_STATUS, &compile_status);
2844	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not query fragment shader's compile status");
2845
2846	if (compile_status == GL_FALSE)
2847	{
2848		TCU_FAIL("Could not compile fragment shader");
2849	}
2850
2851	/* Set up a vertex shader for 2D multisample texture case */
2852	static const char* vs_2d_body = "#version 310 es\n"
2853									"\n"
2854									"precision highp float;\n"
2855									"\n"
2856									"uniform highp sampler2DMS sampler;\n"
2857									"out           float       is_size_correct;\n"
2858									"\n"
2859									"void main()\n"
2860									"{\n"
2861									"    ivec2 size = textureSize(sampler);\n"
2862									"\n"
2863									"    if (size.x == 16 && size.y == 32)\n"
2864									"    {\n"
2865									"        is_size_correct = 1.0f;\n"
2866									"    }\n"
2867									"    else\n"
2868									"    {\n"
2869									"        is_size_correct = 0.0f;\n"
2870									"    }\n"
2871									"}\n";
2872
2873	vs_2d_id = gl.createShader(GL_VERTEX_SHADER);
2874
2875	gl.shaderSource(vs_2d_id, 1 /* count */, &vs_2d_body, NULL);
2876	gl.compileShader(vs_2d_id);
2877	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up a vertex shader for 2D multisample texture case");
2878
2879	gl.getShaderiv(vs_2d_id, GL_COMPILE_STATUS, &compile_status);
2880	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not query 2D multisample texture vertex shader's compile status");
2881
2882	if (compile_status == GL_FALSE)
2883	{
2884		TCU_FAIL("Could not compile vertex shader for 2D multisample texture");
2885	}
2886
2887	/* Set up a vertex shader for 2D multisample array texture case */
2888	if (are_multisample_2d_array_tos_supported)
2889	{
2890		static const char* vs_2d_array_body = "#version 310 es\n"
2891											  "\n"
2892											  "#extension GL_OES_texture_storage_multisample_2d_array : enable\n"
2893											  "precision highp float;\n"
2894											  "\n"
2895											  "uniform highp sampler2DMSArray sampler;\n"
2896											  "out           float            is_size_correct;\n"
2897											  "\n"
2898											  "void main()\n"
2899											  "{\n"
2900											  "    ivec3 size = textureSize(sampler);\n"
2901											  "\n"
2902											  "    if (size.x == 16 && size.y == 32 && size.z == 8)\n"
2903											  "    {\n"
2904											  "        is_size_correct = 1.0f;\n"
2905											  "    }\n"
2906											  "    else\n"
2907											  "    {\n"
2908											  "        is_size_correct = 0.0f;\n"
2909											  "    }\n"
2910											  "}\n";
2911
2912		vs_2d_array_id = gl.createShader(GL_VERTEX_SHADER);
2913
2914		gl.shaderSource(vs_2d_array_id, 1 /* count */, &vs_2d_array_body, NULL);
2915		gl.compileShader(vs_2d_array_id);
2916		GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up a vertex shader for 2D multisample array texture case");
2917
2918		gl.getShaderiv(vs_2d_array_id, GL_COMPILE_STATUS, &compile_status);
2919		GLU_EXPECT_NO_ERROR(gl.getError(),
2920							"Could not query 2D multisample array texture vertex shader's compile status");
2921
2922		if (compile_status == GL_FALSE)
2923		{
2924			TCU_FAIL("Could not compile vertex shader for 2D multisample array texture");
2925		}
2926	}
2927
2928	/* Execute two iterations:
2929	 *
2930	 * a) Create a program object using fs and vs_2d shaders;
2931	 * b) Create a program object using fs and vs_2d_array shaders.
2932	 *
2933	 * Case b) should only be executed if 2D Array MS textures are
2934	 * supported.
2935	 */
2936	for (int n_iteration = 0; n_iteration < 2 /* iterations */; ++n_iteration)
2937	{
2938		if (n_iteration == 1 && !are_multisample_2d_array_tos_supported)
2939		{
2940			/* Skip the iteration */
2941			continue;
2942		}
2943
2944		if (po_id != 0)
2945		{
2946			gl.deleteProgram(po_id);
2947
2948			po_id = 0;
2949		}
2950
2951		po_id = gl.createProgram();
2952
2953		/* Attach iteration-specific shaders */
2954		switch (n_iteration)
2955		{
2956		case 0:
2957		{
2958			gl.attachShader(po_id, fs_id);
2959			gl.attachShader(po_id, vs_2d_id);
2960
2961			break;
2962		}
2963
2964		case 1:
2965		{
2966			gl.attachShader(po_id, fs_id);
2967			gl.attachShader(po_id, vs_2d_array_id);
2968
2969			break;
2970		}
2971
2972		default:
2973			TCU_FAIL("Unrecognized iteration index");
2974		}
2975
2976		GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed.");
2977
2978		/* Configure the program object for XFB */
2979		const char* varying_name = "is_size_correct";
2980
2981		gl.transformFeedbackVaryings(po_id, 1 /* count */, &varying_name, GL_INTERLEAVED_ATTRIBS);
2982		GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed.");
2983
2984		/* Link the program object */
2985		glw::GLint link_status = GL_FALSE;
2986
2987		gl.linkProgram(po_id);
2988		GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
2989
2990		gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status);
2991		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
2992
2993		if (link_status != GL_TRUE)
2994		{
2995			m_testCtx.getLog() << tcu::TestLog::Message << "Linking failed for program object in iteration "
2996							   << n_iteration << tcu::TestLog::EndMessage;
2997
2998			TCU_FAIL("Program object linking failed");
2999		}
3000
3001		/* Render a point using the program */
3002		gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, bo_id);
3003		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed");
3004
3005		gl.useProgram(po_id);
3006		GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
3007
3008		gl.beginTransformFeedback(GL_POINTS);
3009		{
3010			gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
3011		}
3012		gl.endTransformFeedback();
3013
3014		GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed");
3015
3016		/* Read the captured data. Reset the contents of the BO before the buffer
3017		 * object is unmapped.
3018		 */
3019		void*		data_ptr = NULL;
3020		const float epsilon  = (float)1e-5;
3021		float		result   = 0.0f;
3022
3023		data_ptr = gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* offset */, sizeof(float) /* size */,
3024									 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
3025		GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed");
3026
3027		result = *((const float*)data_ptr);
3028		memset(data_ptr, 0, sizeof(float));
3029
3030		gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
3031		GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed");
3032
3033		if (de::abs(result - 1.0f) > epsilon)
3034		{
3035			m_testCtx.getLog() << tcu::TestLog::Message << "Retrieved value: " << result << ", expected: 1.0"
3036							   << tcu::TestLog::EndMessage;
3037
3038			TCU_FAIL("Invalid value reported.");
3039		}
3040	}
3041
3042	/* All done */
3043	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3044
3045	return STOP;
3046}
3047} /* glcts namespace */
3048