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