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