• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "es31cFramebufferNoAttachmentsTests.hpp"
24 #include "gluContextInfo.hpp"
25 #include "gluDefs.hpp"
26 #include "gluStrUtil.hpp"
27 #include "glw.h"
28 #include "glwFunctions.hpp"
29 #include "tcuTestLog.hpp"
30 
31 namespace glcts
32 {
33 
34 using tcu::TestLog;
35 using std::string;
36 using std::vector;
37 using glcts::Context;
38 
39 // I tried to find something like this, but failed
checkErrorEqualsExpected(GLenum err,GLenum expected,const char * msg,const char * file,int line)40 void checkErrorEqualsExpected(GLenum err, GLenum expected, const char* msg, const char* file, int line)
41 {
42 	if (err != expected)
43 	{
44 		std::ostringstream msgStr;
45 		msgStr << "glGetError() returned " << glu::getErrorStr(err) << ", expected " << glu::getErrorStr(expected);
46 
47 		if (msg)
48 			msgStr << " in '" << msg << "'";
49 
50 		if (err == GL_OUT_OF_MEMORY)
51 			throw glu::OutOfMemoryError(msgStr.str().c_str(), "", file, line);
52 		else
53 			throw glu::Error(err, msgStr.str().c_str(), "", file, line);
54 	}
55 }
56 
57 #define GLU_EXPECT_ERROR(ERR, EXPECTED, MSG) checkErrorEqualsExpected((ERR), EXPECTED, MSG, __FILE__, __LINE__)
58 
59 // Contains expect_fbo_status()
60 class FramebufferNoAttachmentsBaseCase : public TestCase
61 {
62 public:
63 	FramebufferNoAttachmentsBaseCase(Context& context, const char* name, const char* description);
64 	~FramebufferNoAttachmentsBaseCase();
65 
66 protected:
67 	void expect_fbo_status(GLenum target, GLenum expected_status, const char* fail_message);
68 };
69 
FramebufferNoAttachmentsBaseCase(Context & context,const char * name,const char * description)70 FramebufferNoAttachmentsBaseCase::FramebufferNoAttachmentsBaseCase(Context& context, const char* name,
71 																   const char* description)
72 	: TestCase(context, name, description)
73 {
74 }
75 
~FramebufferNoAttachmentsBaseCase()76 FramebufferNoAttachmentsBaseCase::~FramebufferNoAttachmentsBaseCase()
77 {
78 }
79 
80 // API tests
81 class FramebufferNoAttachmentsApiCase : public FramebufferNoAttachmentsBaseCase
82 {
83 public:
84 	FramebufferNoAttachmentsApiCase(Context& context, const char* name, const char* description);
85 	~FramebufferNoAttachmentsApiCase();
86 
87 	IterateResult iterate();
88 
89 private:
90 	void begin_fbo_no_attachments(GLenum target);
91 	void begin_fbo_with_multisample_renderbuffer(GLenum target);
92 	void begin_fbo(GLenum target, unsigned test_case);
93 	void end_fbo(GLenum target);
94 
95 private:
96 	GLuint m_fbo;
97 	GLuint m_renderbuffer;
98 	GLuint m_texture;
99 };
100 
FramebufferNoAttachmentsApiCase(Context & context,const char * name,const char * description)101 FramebufferNoAttachmentsApiCase::FramebufferNoAttachmentsApiCase(Context& context, const char* name,
102 																 const char* description)
103 	: FramebufferNoAttachmentsBaseCase(context, name, description), m_fbo(0), m_renderbuffer(0), m_texture(0)
104 {
105 }
106 
~FramebufferNoAttachmentsApiCase()107 FramebufferNoAttachmentsApiCase::~FramebufferNoAttachmentsApiCase()
108 {
109 }
110 
expect_fbo_status(GLenum target,GLenum expected_status,const char * fail_message)111 void FramebufferNoAttachmentsBaseCase::expect_fbo_status(GLenum target, GLenum expected_status,
112 														 const char* fail_message)
113 {
114 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
115 	GLenum				  error;
116 
117 	error = gl.getError();
118 	if (error != GL_NO_ERROR)
119 	{
120 		std::ostringstream msgStr;
121 		msgStr << "Error before glCheckFramebufferStatus() for '" << fail_message << "'\n";
122 
123 		GLU_EXPECT_NO_ERROR(error, "Error before glCheckFramebufferStatus()");
124 	}
125 
126 	TCU_CHECK_MSG(gl.checkFramebufferStatus(target) == expected_status, fail_message);
127 
128 	error = gl.getError();
129 	if (error != GL_NO_ERROR)
130 	{
131 		std::ostringstream msgStr;
132 		msgStr << "Error after glCheckFramebufferStatus() for '" << fail_message << "'\n";
133 
134 		GLU_EXPECT_NO_ERROR(error, "Error after glCheckFramebufferStatus()");
135 	}
136 }
137 
begin_fbo_no_attachments(GLenum target)138 void FramebufferNoAttachmentsApiCase::begin_fbo_no_attachments(GLenum target)
139 {
140 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
141 
142 	gl.genFramebuffers(1, &m_fbo);
143 	gl.bindFramebuffer(target, m_fbo);
144 
145 	// A freshly created framebuffer with no attachment is expected to be incomplete
146 	// until default width and height is set.
147 	expect_fbo_status(target, GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT,
148 					  "error setting up framebuffer with multisample attachment");
149 }
150 
begin_fbo_with_multisample_renderbuffer(GLenum target)151 void FramebufferNoAttachmentsApiCase::begin_fbo_with_multisample_renderbuffer(GLenum target)
152 {
153 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
154 
155 	gl.genFramebuffers(1, &m_fbo);
156 	gl.bindFramebuffer(target, m_fbo);
157 	gl.genRenderbuffers(1, &m_renderbuffer);
158 	gl.bindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
159 	gl.renderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, 101, 102);
160 	gl.framebufferRenderbuffer(target, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_renderbuffer);
161 	expect_fbo_status(target, GL_FRAMEBUFFER_COMPLETE, "framebuffer with an attachment should be complete");
162 }
163 
begin_fbo(GLenum target,unsigned test_case)164 void FramebufferNoAttachmentsApiCase::begin_fbo(GLenum target, unsigned test_case)
165 {
166 	switch (test_case)
167 	{
168 	case 0:
169 		begin_fbo_no_attachments(target);
170 		break;
171 	case 1:
172 		begin_fbo_with_multisample_renderbuffer(target);
173 		break;
174 	}
175 }
176 
end_fbo(GLenum target)177 void FramebufferNoAttachmentsApiCase::end_fbo(GLenum target)
178 {
179 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
180 
181 	gl.bindFramebuffer(target, 0);
182 	gl.deleteFramebuffers(1, &m_fbo);
183 	gl.deleteRenderbuffers(1, &m_renderbuffer);
184 	gl.deleteTextures(1, &m_texture);
185 	GLU_EXPECT_NO_ERROR(gl.getError(), "error deleting framebuffer / renderbuffer / texture");
186 	m_fbo		   = 0;
187 	m_renderbuffer = 0;
188 	m_texture	  = 0;
189 }
190 
iterate()191 FramebufferNoAttachmentsApiCase::IterateResult FramebufferNoAttachmentsApiCase::iterate()
192 {
193 	const glw::Functions& gl   = m_context.getRenderContext().getFunctions();
194 	bool				  isOk = true;
195 	GLint				  binding;
196 
197 	GLenum targets[] = {
198 		GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER,
199 		GL_FRAMEBUFFER // equivalent to DRAW_FRAMEBUFFER
200 	};
201 	GLenum bindings[] = {
202 		GL_DRAW_FRAMEBUFFER_BINDING, GL_READ_FRAMEBUFFER_BINDING,
203 		GL_FRAMEBUFFER_BINDING // equivalent to DRAW_FRAMEBUFFER_BINDING
204 	};
205 	GLenum pnames[] = { GL_FRAMEBUFFER_DEFAULT_WIDTH, GL_FRAMEBUFFER_DEFAULT_HEIGHT, GL_FRAMEBUFFER_DEFAULT_SAMPLES,
206 						GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS };
207 	GLenum enums_invalid_list[] = { GL_NOTEQUAL,
208 									GL_FRONT_FACE,
209 									GL_PACK_ROW_LENGTH,
210 									GL_FIXED,
211 									GL_LINEAR_MIPMAP_NEAREST,
212 									GL_RGBA4,
213 									GL_TEXTURE_MAX_LOD,
214 									GL_RG32F,
215 									GL_ALIASED_POINT_SIZE_RANGE,
216 									GL_VERTEX_ATTRIB_ARRAY_TYPE,
217 									GL_DRAW_BUFFER7,
218 									GL_MAX_COMBINED_UNIFORM_BLOCKS,
219 									GL_MAX_VARYING_COMPONENTS,
220 									GL_SRGB,
221 									GL_RGB8UI,
222 									GL_IMAGE_BINDING_NAME,
223 									GL_TEXTURE_2D_MULTISAMPLE,
224 									GL_COMPRESSED_R11_EAC,
225 									GL_BUFFER_DATA_SIZE };
226 
227 	GLint default_values[] = { 0, 0, 0, GL_FALSE };
228 	GLint valid_values[]   = { 103, 104, 4, GL_TRUE };
229 	GLint min_values[]	 = { 0, 0, 0, -1 }; // Skip min_value test for boolean
230 	GLint max_values[]	 = { 0, 0, 0, -1 }; // Skip max_value test for boolean.
231 
232 	unsigned num_targets			= sizeof(targets) / sizeof(GLenum);
233 	unsigned num_pnames				= sizeof(pnames) / sizeof(GLenum);
234 	unsigned num_enums_invalid_list = sizeof(enums_invalid_list) / sizeof(GLenum);
235 
236 	// Check for extra pnames allowed from supported extensions.
237 	vector<GLenum> pnames_ext;
238 	if (m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader") ||
239 		m_context.getContextInfo().isExtensionSupported("GL_OES_geometry_shader"))
240 	{
241 		pnames_ext.push_back(GL_FRAMEBUFFER_DEFAULT_LAYERS);
242 	}
243 
244 	// "Random" invalid enums distributed roughly evenly throughout 16bit enum number range.
245 	vector<GLenum> enums_invalid;
246 	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader") &&
247 		!m_context.getContextInfo().isExtensionSupported("GL_OES_geometry_shader"))
248 	{
249 		enums_invalid.push_back(GL_FRAMEBUFFER_DEFAULT_LAYERS);
250 	}
251 	for (unsigned i = 0; i < num_enums_invalid_list; ++i)
252 	{
253 		enums_invalid.push_back(enums_invalid_list[i]);
254 	}
255 
256 	gl.getIntegerv(GL_MAX_FRAMEBUFFER_WIDTH, &max_values[0]);
257 	gl.getIntegerv(GL_MAX_FRAMEBUFFER_HEIGHT, &max_values[1]);
258 	gl.getIntegerv(GL_MAX_FRAMEBUFFER_SAMPLES, &max_values[2]);
259 	GLU_EXPECT_NO_ERROR(
260 		gl.getError(),
261 		"Querying GL_MAX_FRAMEBUFFER_WIDTH / GL_MAX_FRAMEBUFFER_HEIGHT / GL_MAX_FRAMEBUFFER_SAMPLES failed");
262 
263 	TCU_CHECK_MSG(max_values[0] >= 2048, "GL_MAX_FRAMEBUFFER_WIDTH does not meet minimum requirements");
264 
265 	TCU_CHECK_MSG(max_values[1] >= 2048, "GL_MAX_FRAMEBUFFER_HEIGHT does not meet minimum requirements");
266 
267 	TCU_CHECK_MSG(max_values[2] >= 4, "GL_MAX_FRAMEBUFFER_SAMPLES does not meet minimum requirements");
268 
269 	// It is valid to ask for number of samples > 0 and get
270 	// implementation defined value which is above the requested
271 	// value. We can use simple equality comparison by using
272 	// reported maximum number of samples in our valid value
273 	// set and get test.
274 	valid_values[2] = max_values[2];
275 
276 	// Invalid target
277 	for (unsigned i = 0; i < enums_invalid.size(); ++i)
278 	{
279 		GLenum target   = enums_invalid[i];
280 		bool   is_valid = false;
281 		for (unsigned j = 0; j < num_targets; ++j)
282 		{
283 			if (target == targets[j])
284 			{
285 				is_valid = true;
286 				break;
287 			}
288 		}
289 
290 		if (is_valid)
291 			continue;
292 
293 		for (unsigned j = 0; j < num_pnames; ++j)
294 		{
295 			gl.framebufferParameteri(target, pnames[j], valid_values[j]);
296 			GLU_EXPECT_ERROR(gl.getError(), GL_INVALID_ENUM,
297 							 "Using glFramebufferParameteri() with invalid target should set GL_INVALID_ENUM");
298 		}
299 	}
300 
301 	// For all valid targets
302 	for (unsigned i = 0; i < num_targets; ++i)
303 	{
304 		GLenum target = targets[i];
305 
306 		glGetIntegerv(bindings[i], &binding);
307 		GLU_EXPECT_NO_ERROR(gl.getError(), "Valid call to glGetIntegerv() "
308 										   "should not set GL error");
309 
310 		// Using default framebuffer - GL_INVALID_OPERATION
311 		for (unsigned j = 0; j < num_pnames; ++j)
312 		{
313 			GLint  get_value = ~0;
314 			GLenum pname	 = pnames[j];
315 
316 			gl.framebufferParameteri(target, pname, valid_values[j]);
317 			if (binding == 0)
318 			{
319 				GLU_EXPECT_ERROR(gl.getError(), GL_INVALID_OPERATION,
320 								 "Using glFramebufferParameteri() on default framebuffer "
321 								 "should set GL_INVALID_OPERATION");
322 			}
323 			else
324 			{
325 				GLU_EXPECT_NO_ERROR(gl.getError(), "Valid call to glGetFramebufferParameteriv() "
326 												   "should not set GL error");
327 			}
328 
329 			gl.getFramebufferParameteriv(target, pname, &get_value);
330 
331 			if (binding == 0)
332 			{
333 				GLU_EXPECT_ERROR(gl.getError(), GL_INVALID_OPERATION,
334 								 "Using glGetFramebufferParameteriv() on default framebuffer "
335 								 "should set GL_INVALID_OPERATION");
336 				TCU_CHECK_MSG(get_value == ~0, "failed call to glGetFramebufferParameteriv() "
337 											   "should not modify params");
338 			}
339 			else
340 			{
341 				GLU_EXPECT_NO_ERROR(gl.getError(), "Valid call to glGetFramebufferParameteriv() "
342 												   "should not set GL error");
343 			}
344 		}
345 
346 		// j == 0 : fbo without attachments
347 		// j == 1 : fbo with a multisample attachment
348 		for (unsigned j = 0; j < 2; ++j)
349 		{
350 			glGetIntegerv(bindings[i], &binding);
351 			GLU_EXPECT_NO_ERROR(gl.getError(), "Valid call to glGetIntegerv() "
352 											   "should not set GL error");
353 
354 			if (binding == 0)
355 			{
356 				//  Check FBO status of default framebuffer
357 				//  TODO Check presence of default framebuffer - default framebuffer is complete
358 				//       only if it exists
359 				expect_fbo_status(target, GL_FRAMEBUFFER_COMPLETE, "Default framebuffer should be complete");
360 			}
361 
362 			//  Invalid pname - GL_INVALID_VALUE
363 			begin_fbo(target, j);
364 			for (unsigned k = 0; k < enums_invalid.size(); ++k)
365 			{
366 				GLenum pname	= enums_invalid[k];
367 				bool   is_valid = false;
368 				for (unsigned m = 0; m < num_pnames; ++m)
369 				{
370 					if (pname == pnames[m])
371 					{
372 						is_valid = true;
373 						break;
374 					}
375 				}
376 
377 				// Ignore any pnames that are added by extensions.
378 				for (unsigned m = 0; m < pnames_ext.size(); ++m)
379 				{
380 					if (pname == pnames_ext[m])
381 					{
382 						is_valid = true;
383 						break;
384 					}
385 				}
386 
387 				if (is_valid)
388 					continue;
389 
390 				GLint get_value = ~0;
391 
392 				gl.framebufferParameteri(target, pname, 0);
393 				GLU_EXPECT_ERROR(gl.getError(), GL_INVALID_ENUM, "Calling glFramebufferParameteri() with invalid pname "
394 																 "should set GL_INVALID_ENUM");
395 
396 				gl.getFramebufferParameteriv(target, pname, &get_value);
397 				GLU_EXPECT_ERROR(gl.getError(), GL_INVALID_ENUM,
398 								 "Calling glGetFramebufferParameteriv() with invalid pname "
399 								 "should set GL_INVALID_ENUM");
400 
401 				TCU_CHECK_MSG(get_value == ~0, "Calling glGetFramebufferParameteriv() with invalid pname "
402 											   "should not modify params");
403 			}
404 			end_fbo(target);
405 
406 			//  Valid set and get
407 			begin_fbo(target, j);
408 			{
409 				for (unsigned k = 0; k < num_pnames; ++k)
410 				{
411 					GLint get_value = ~0;
412 
413 					gl.framebufferParameteri(target, pnames[k], valid_values[k]);
414 					GLU_EXPECT_NO_ERROR(gl.getError(), "Valid call to glFramebufferParameteri() "
415 													   "should not set GL error");
416 
417 					gl.getFramebufferParameteriv(target, pnames[k], &get_value);
418 					GLU_EXPECT_NO_ERROR(gl.getError(), "Valid call to glGetFramebufferParameteriv() "
419 													   "should not set GL error");
420 
421 					TCU_CHECK_MSG(get_value == valid_values[k],
422 								  "glGetFramebufferParameteriv() "
423 								  "should have returned the value set with glFramebufferParameteri()");
424 				}
425 
426 				//  After valid set, check FBO status of user FBO
427 				expect_fbo_status(target, GL_FRAMEBUFFER_COMPLETE,
428 								  "Framebuffer should be complete after setting valid valid");
429 			}
430 			end_fbo(target);
431 
432 			//  Negative or too large values - GL_INVALID_VALUE
433 			//  Also check for correct default values
434 			begin_fbo(target, j);
435 			for (unsigned k = 0; k < num_pnames; ++k)
436 			{
437 				GLint  get_value = ~0;
438 				GLenum pname	 = pnames[k];
439 
440 				if (min_values[k] >= 0)
441 				{
442 					gl.framebufferParameteri(target, pname, min_values[k] - 1);
443 					GLU_EXPECT_ERROR(gl.getError(), GL_INVALID_VALUE,
444 									 "Calling glFramebufferParameteri() with negative value "
445 									 "should set GL_INVALID_VALUE");
446 				}
447 
448 				gl.getFramebufferParameteriv(target, pname, &get_value);
449 				GLU_EXPECT_NO_ERROR(gl.getError(), "Valid call to glGetFramebufferParameteriv() "
450 												   "should not set GL error");
451 
452 				TCU_CHECK_MSG(get_value == default_values[k], "glGetFramebufferParameteriv() "
453 															  "did not return a valid default value");
454 
455 				get_value = ~0;
456 				if (max_values[k] >= 0)
457 				{
458 					gl.framebufferParameteri(target, pname, max_values[k] + 1);
459 					GLU_EXPECT_ERROR(gl.getError(), GL_INVALID_VALUE,
460 									 "Calling glFramebufferParameteri() too large value "
461 									 "should set GL_INVALID_VALUE");
462 				}
463 
464 				gl.getFramebufferParameteriv(target, pname, &get_value);
465 				GLU_EXPECT_NO_ERROR(gl.getError(), "Valid call to glGetFramebufferParameteriv() "
466 												   "should not set GL error");
467 
468 				TCU_CHECK_MSG(get_value == default_values[k], "glGetFramebufferParameteriv() "
469 															  "did not return a valid default value");
470 			}
471 			end_fbo(target);
472 		}
473 	}
474 
475 	m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : "Fail");
476 	return STOP;
477 }
478 
479 // Draw with imageStore, validate that framebuffer
480 // default width and height is respected.
481 class FramebufferNoAttachmentsRenderCase : public FramebufferNoAttachmentsBaseCase
482 {
483 public:
484 	FramebufferNoAttachmentsRenderCase(Context& context, const char* name, const char* description);
485 
486 	IterateResult iterate();
487 	void		  deinit(void);
488 
489 private:
490 	GLuint m_program;
491 	GLuint m_vertex_shader;
492 	GLuint m_fragment_shader;
493 	GLuint m_vao;
494 	GLuint m_framebuffer;
495 	GLuint m_texture;
496 };
497 
FramebufferNoAttachmentsRenderCase(Context & context,const char * name,const char * description)498 FramebufferNoAttachmentsRenderCase::FramebufferNoAttachmentsRenderCase(Context& context, const char* name,
499 																	   const char* description)
500 	: FramebufferNoAttachmentsBaseCase(context, name, description)
501 	, m_program(0)
502 	, m_vertex_shader(0)
503 	, m_fragment_shader(0)
504 	, m_vao(0)
505 	, m_framebuffer(0)
506 	, m_texture(0)
507 {
508 }
509 
deinit(void)510 void FramebufferNoAttachmentsRenderCase::deinit(void)
511 {
512 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
513 	gl.deleteShader(m_vertex_shader);
514 	gl.deleteShader(m_fragment_shader);
515 	gl.deleteProgram(m_program);
516 	gl.deleteVertexArrays(1, &m_vao);
517 	gl.deleteTextures(1, &m_texture);
518 	gl.deleteFramebuffers(1, &m_framebuffer);
519 }
520 
iterate()521 FramebufferNoAttachmentsRenderCase::IterateResult FramebufferNoAttachmentsRenderCase::iterate()
522 {
523 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
524 	int					  max_fragment_image_uniforms;
525 	bool				  isOk = true;
526 
527 	// Check GL_MAX_FRAGMENT_IMAGE_UNIFORMS, we need at least one
528 	glGetIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &max_fragment_image_uniforms);
529 	GLU_EXPECT_NO_ERROR(gl.getError(), "Querying GL_MAX_FRAGMENT_IMAGE_UNIFORMS");
530 
531 	if (max_fragment_image_uniforms < 1)
532 	{
533 		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_MAX_FRAGMENT_IMAGE_UNIFORMS<1");
534 		return STOP;
535 	}
536 
537 	// Create program and VAO
538 	{
539 		const char* vs_source = "#version 310 es\n"
540 								"void main()\n"
541 								"{\n"
542 								"   if      (gl_VertexID == 0) gl_Position = vec4(-1, -1, 0, 1);\n"
543 								"   else if (gl_VertexID == 1) gl_Position = vec4(-1,  1, 0, 1);\n"
544 								"   else if (gl_VertexID == 2) gl_Position = vec4( 1,  1, 0, 1);\n"
545 								"   else                       gl_Position = vec4( 1, -1, 0, 1);\n"
546 								"}\n";
547 
548 		const char* fs_source = "#version 310 es\n"
549 								"precision highp uimage2D;\n"
550 								"layout(r32ui) uniform uimage2D data;\n"
551 								"void main()\n"
552 								"{\n"
553 								"   ivec2 image_info = ivec2(gl_FragCoord.xy);\n"
554 								"   imageStore(data, image_info, uvec4(1, 2, 3, 4));\n"
555 								"}\n";
556 
557 		m_program		  = gl.createProgram();
558 		m_vertex_shader   = gl.createShader(GL_VERTEX_SHADER);
559 		m_fragment_shader = gl.createShader(GL_FRAGMENT_SHADER);
560 		gl.shaderSource(m_vertex_shader, 1, &vs_source, NULL);
561 		gl.compileShader(m_vertex_shader);
562 		gl.attachShader(m_program, m_vertex_shader);
563 		gl.shaderSource(m_fragment_shader, 1, &fs_source, NULL);
564 		gl.compileShader(m_fragment_shader);
565 		gl.attachShader(m_program, m_fragment_shader);
566 		gl.linkProgram(m_program);
567 		gl.useProgram(m_program);
568 		gl.genVertexArrays(1, &m_vao);
569 		gl.bindVertexArray(m_vao);
570 		GLU_EXPECT_NO_ERROR(gl.getError(), "Creating program and VAO");
571 	}
572 
573 	// Create framebuffer with no attachments
574 	gl.genFramebuffers(1, &m_framebuffer);
575 	gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_framebuffer);
576 	gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH, 32);
577 	gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT, 32);
578 	expect_fbo_status(GL_READ_FRAMEBUFFER, GL_FRAMEBUFFER_COMPLETE, "Creating framebuffer with no attachments");
579 
580 	// Create texture and clear it, temporarily attaching to FBO
581 	{
582 		GLuint zero[] = { 0, 0, 0, 0 };
583 		gl.genTextures(1, &m_texture);
584 		gl.bindTexture(GL_TEXTURE_2D, m_texture);
585 		gl.texStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 64, 64);
586 		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
587 		gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
588 		gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0);
589 		gl.viewport(0, 0, 64, 64);
590 		gl.clearBufferuiv(GL_COLOR, 0, zero);
591 		gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
592 		GLU_EXPECT_NO_ERROR(gl.getError(), "Creating and clearing texture");
593 	}
594 
595 	// Draw using storeImage
596 	gl.drawBuffers(0, NULL);
597 	gl.viewport(0, 0, 64, 64);
598 	gl.bindImageTexture(0, m_texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
599 	gl.drawArrays(GL_TRIANGLE_FAN, 0, 4);
600 	gl.memoryBarrier(GL_ALL_BARRIER_BITS);
601 	GLU_EXPECT_NO_ERROR(gl.getError(), "Draw with imageStore");
602 
603 	// Read and validate texture contents
604 	{
605 		GLuint pixels[64 * 64 * 4];
606 		gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
607 		gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_framebuffer);
608 		gl.framebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0);
609 		expect_fbo_status(GL_READ_FRAMEBUFFER, GL_FRAMEBUFFER_COMPLETE, "ReadPixels to texture for validation");
610 		gl.readPixels(0, 0, 64, 64, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]);
611 		GLU_EXPECT_NO_ERROR(gl.getError(), "ReadPixels");
612 
613 		for (unsigned y = 0; y < 64; ++y)
614 		{
615 			for (unsigned x = 0; x < 64; ++x)
616 			{
617 				GLuint expected_value = (x < 32) && (y < 32) ? 1 : 0;
618 				GLuint value		  = pixels[(y * 64 + x) * 4];
619 				TCU_CHECK_MSG(value == expected_value, "Validating draw with imageStore");
620 			}
621 		}
622 	}
623 
624 	m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : "Fail");
625 	return STOP;
626 }
627 
FramebufferNoAttachmentsTests(Context & context)628 FramebufferNoAttachmentsTests::FramebufferNoAttachmentsTests(Context& context)
629 	: TestCaseGroup(context, "framebuffer_no_attachments", "Framebuffer no attachments tests")
630 {
631 }
632 
~FramebufferNoAttachmentsTests(void)633 FramebufferNoAttachmentsTests::~FramebufferNoAttachmentsTests(void)
634 {
635 }
636 
init(void)637 void FramebufferNoAttachmentsTests::init(void)
638 {
639 	addChild(new FramebufferNoAttachmentsApiCase(m_context, "api", "Basic API verification"));
640 
641 	addChild(new FramebufferNoAttachmentsRenderCase(m_context, "render", "Rendering with imageStore"));
642 }
643 
644 } // glcts
645