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
31namespace glcts
32{
33
34using tcu::TestLog;
35using std::string;
36using std::vector;
37using glcts::Context;
38
39// I tried to find something like this, but failed
40void 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()
60class FramebufferNoAttachmentsBaseCase : public TestCase
61{
62public:
63	FramebufferNoAttachmentsBaseCase(Context& context, const char* name, const char* description);
64	~FramebufferNoAttachmentsBaseCase();
65
66protected:
67	void expect_fbo_status(GLenum target, GLenum expected_status, const char* fail_message);
68};
69
70FramebufferNoAttachmentsBaseCase::FramebufferNoAttachmentsBaseCase(Context& context, const char* name,
71																   const char* description)
72	: TestCase(context, name, description)
73{
74}
75
76FramebufferNoAttachmentsBaseCase::~FramebufferNoAttachmentsBaseCase()
77{
78}
79
80// API tests
81class FramebufferNoAttachmentsApiCase : public FramebufferNoAttachmentsBaseCase
82{
83public:
84	FramebufferNoAttachmentsApiCase(Context& context, const char* name, const char* description);
85	~FramebufferNoAttachmentsApiCase();
86
87	IterateResult iterate();
88
89private:
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
95private:
96	GLuint m_fbo;
97	GLuint m_renderbuffer;
98	GLuint m_texture;
99};
100
101FramebufferNoAttachmentsApiCase::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
107FramebufferNoAttachmentsApiCase::~FramebufferNoAttachmentsApiCase()
108{
109}
110
111void 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
138void 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
151void 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
164void 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
177void 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
191FramebufferNoAttachmentsApiCase::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.
481class FramebufferNoAttachmentsRenderCase : public FramebufferNoAttachmentsBaseCase
482{
483public:
484	FramebufferNoAttachmentsRenderCase(Context& context, const char* name, const char* description);
485
486	IterateResult iterate();
487	void		  deinit(void);
488
489private:
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
498FramebufferNoAttachmentsRenderCase::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
510void 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
521FramebufferNoAttachmentsRenderCase::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;
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
628FramebufferNoAttachmentsTests::FramebufferNoAttachmentsTests(Context& context)
629	: TestCaseGroup(context, "framebuffer_no_attachments", "Framebuffer no attachments tests")
630{
631}
632
633FramebufferNoAttachmentsTests::~FramebufferNoAttachmentsTests(void)
634{
635}
636
637void 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