xref: /aosp_15_r20/external/deqp/modules/gles2/functional/es2fFboRenderTest.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 2.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
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 Framebuffer Object Tests.
22  *
23  * Notes:
24  *   + Like in API tests, tcu::sgl2s::Context class is used.
25  *   + ReferenceContext is used to generate reference images.
26  *   + API calls can be logged \todo [pyry] Implement.
27  *//*--------------------------------------------------------------------*/
28 
29 #include "es2fFboRenderTest.hpp"
30 #include "sglrContextUtil.hpp"
31 #include "sglrGLContext.hpp"
32 #include "sglrReferenceContext.hpp"
33 #include "tcuSurface.hpp"
34 #include "tcuTextureUtil.hpp"
35 #include "tcuImageCompare.hpp"
36 #include "tcuRenderTarget.hpp"
37 #include "gluPixelTransfer.hpp"
38 #include "gluTextureUtil.hpp"
39 #include "gluStrUtil.hpp"
40 #include "deRandom.hpp"
41 #include "deString.h"
42 
43 #include "glwFunctions.hpp"
44 #include "glwEnums.hpp"
45 
46 using std::string;
47 using std::vector;
48 using tcu::RGBA;
49 using tcu::Surface;
50 using tcu::Vec2;
51 using tcu::Vec3;
52 using tcu::Vec4;
53 using namespace glw; // GL types
54 
55 namespace deqp
56 {
57 namespace gles2
58 {
59 namespace Functional
60 {
61 
62 // Shaders.
63 
64 class FlatColorShader : public sglr::ShaderProgram
65 {
66 public:
FlatColorShader(void)67     FlatColorShader(void)
68         : sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
69                               << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
70                               << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
71                               << sglr::pdec::Uniform("u_color", glu::TYPE_FLOAT_VEC4)
72                               << sglr::pdec::VertexSource("attribute highp vec4 a_position;\n"
73                                                           "void main (void)\n"
74                                                           "{\n"
75                                                           "    gl_Position = a_position;\n"
76                                                           "}\n")
77                               << sglr::pdec::FragmentSource("uniform mediump vec4 u_color;\n"
78                                                             "void main (void)\n"
79                                                             "{\n"
80                                                             "    gl_FragColor = u_color;\n"
81                                                             "}\n"))
82     {
83     }
84 
setColor(sglr::Context & gl,uint32_t program,const tcu::Vec4 & color)85     void setColor(sglr::Context &gl, uint32_t program, const tcu::Vec4 &color)
86     {
87         gl.useProgram(program);
88         gl.uniform4fv(gl.getUniformLocation(program, "u_color"), 1, color.getPtr());
89     }
90 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const91     void shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets, const int numPackets) const
92     {
93         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
94             packets[packetNdx]->position =
95                 rr::readVertexAttribFloat(inputs[0], packets[packetNdx]->instanceNdx, packets[packetNdx]->vertexNdx);
96     }
97 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const98     void shadeFragments(rr::FragmentPacket *packets, const int numPackets,
99                         const rr::FragmentShadingContext &context) const
100     {
101         const tcu::Vec4 color(m_uniforms[0].value.f4);
102 
103         DE_UNREF(packets);
104 
105         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
106             for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
107                 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
108     }
109 };
110 
111 class SingleTex2DShader : public sglr::ShaderProgram
112 {
113 public:
SingleTex2DShader(void)114     SingleTex2DShader(void)
115         : sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
116                               << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
117                               << sglr::pdec::VertexAttribute("a_coord", rr::GENERICVECTYPE_FLOAT)
118                               << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
119                               << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
120                               << sglr::pdec::Uniform("u_sampler0", glu::TYPE_SAMPLER_2D)
121                               << sglr::pdec::VertexSource("attribute highp vec4 a_position;\n"
122                                                           "attribute mediump vec2 a_coord;\n"
123                                                           "varying mediump vec2 v_coord;\n"
124                                                           "void main (void)\n"
125                                                           "{\n"
126                                                           "    gl_Position = a_position;\n"
127                                                           "    v_coord = a_coord;\n"
128                                                           "}\n")
129                               << sglr::pdec::FragmentSource("uniform sampler2D u_sampler0;\n"
130                                                             "varying mediump vec2 v_coord;\n"
131                                                             "void main (void)\n"
132                                                             "{\n"
133                                                             "    gl_FragColor = texture2D(u_sampler0, v_coord);\n"
134                                                             "}\n"))
135     {
136     }
137 
setUnit(sglr::Context & gl,uint32_t program,int unitNdx)138     void setUnit(sglr::Context &gl, uint32_t program, int unitNdx)
139     {
140         gl.useProgram(program);
141         gl.uniform1i(gl.getUniformLocation(program, "u_sampler0"), unitNdx);
142     }
143 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const144     void shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets, const int numPackets) const
145     {
146         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
147         {
148             rr::VertexPacket &packet = *packets[packetNdx];
149 
150             packet.position   = rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
151             packet.outputs[0] = rr::readVertexAttribFloat(inputs[1], packet.instanceNdx, packet.vertexNdx);
152         }
153     }
154 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const155     void shadeFragments(rr::FragmentPacket *packets, const int numPackets,
156                         const rr::FragmentShadingContext &context) const
157     {
158         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
159             for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
160             {
161                 const tcu::Vec4 v_coord = rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx);
162                 const float lod         = 0.0f;
163 
164                 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0,
165                                         this->m_uniforms[0].sampler.tex2D->sample(v_coord.x(), v_coord.y(), lod));
166             }
167     }
168 };
169 
170 class MixTexturesShader : public sglr::ShaderProgram
171 {
172 public:
MixTexturesShader(void)173     MixTexturesShader(void)
174         : sglr::ShaderProgram(
175               sglr::pdec::ShaderProgramDeclaration()
176               << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
177               << sglr::pdec::VertexAttribute("a_coord", rr::GENERICVECTYPE_FLOAT)
178               << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
179               << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
180               << sglr::pdec::Uniform("u_sampler0", glu::TYPE_SAMPLER_2D)
181               << sglr::pdec::Uniform("u_sampler1", glu::TYPE_SAMPLER_2D)
182               << sglr::pdec::VertexSource("attribute highp vec4 a_position;\n"
183                                           "attribute mediump vec2 a_coord;\n"
184                                           "varying mediump vec2 v_coord;\n"
185                                           "void main (void)\n"
186                                           "{\n"
187                                           "    gl_Position = a_position;\n"
188                                           "    v_coord = a_coord;\n"
189                                           "}\n")
190               << sglr::pdec::FragmentSource(
191                      "uniform sampler2D u_sampler0;\n"
192                      "uniform sampler2D u_sampler1;\n"
193                      "varying mediump vec2 v_coord;\n"
194                      "void main (void)\n"
195                      "{\n"
196                      "    gl_FragColor = texture2D(u_sampler0, v_coord)*0.5 + texture2D(u_sampler1, v_coord)*0.5;\n"
197                      "}\n"))
198     {
199     }
200 
setUnits(sglr::Context & gl,uint32_t program,int unit0,int unit1)201     void setUnits(sglr::Context &gl, uint32_t program, int unit0, int unit1)
202     {
203         gl.useProgram(program);
204         gl.uniform1i(gl.getUniformLocation(program, "u_sampler0"), unit0);
205         gl.uniform1i(gl.getUniformLocation(program, "u_sampler1"), unit1);
206     }
207 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const208     void shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets, const int numPackets) const
209     {
210         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
211         {
212             rr::VertexPacket &packet = *packets[packetNdx];
213 
214             packet.position   = rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
215             packet.outputs[0] = rr::readVertexAttribFloat(inputs[1], packet.instanceNdx, packet.vertexNdx);
216         }
217     }
218 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const219     void shadeFragments(rr::FragmentPacket *packets, const int numPackets,
220                         const rr::FragmentShadingContext &context) const
221     {
222         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
223             for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
224             {
225                 const tcu::Vec4 v_coord = rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx);
226                 const float lod         = 0.0f;
227 
228                 rr::writeFragmentOutput(
229                     context, packetNdx, fragNdx, 0,
230                     this->m_uniforms[0].sampler.tex2D->sample(v_coord.x(), v_coord.y(), lod) * 0.5f +
231                         this->m_uniforms[1].sampler.tex2D->sample(v_coord.x(), v_coord.y(), lod) * 0.5f);
232             }
233     }
234 };
235 
236 // Framebuffer config.
237 
238 class FboConfig
239 {
240 public:
FboConfig(void)241     FboConfig(void)
242         : colorbufferType(GL_NONE)
243         , colorbufferFormat(GL_NONE)
244         , depthbufferType(GL_NONE)
245         , depthbufferFormat(GL_NONE)
246         , stencilbufferType(GL_NONE)
247         , stencilbufferFormat(GL_NONE)
248     {
249     }
250 
251     std::string getName(void) const;
252 
253     GLenum colorbufferType;   //!< GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP, GL_RENDERBUFFER
254     GLenum colorbufferFormat; //!< Internal format for color buffer texture or renderbuffer
255 
256     GLenum depthbufferType; //!< GL_RENDERBUFFER
257     GLenum depthbufferFormat;
258 
259     GLenum stencilbufferType; //!< GL_RENDERBUFFER
260     GLenum stencilbufferFormat;
261 
262 private:
263     static const char *getFormatName(GLenum format);
264 };
265 
getFormatName(GLenum format)266 const char *FboConfig::getFormatName(GLenum format)
267 {
268     switch (format)
269     {
270     case GL_RGB:
271         return "rgb";
272     case GL_RGBA:
273         return "rgba";
274     case GL_ALPHA:
275         return "alpha";
276     case GL_LUMINANCE:
277         return "luminance";
278     case GL_LUMINANCE_ALPHA:
279         return "luminance_alpha";
280     case GL_RGB565:
281         return "rgb565";
282     case GL_RGB5_A1:
283         return "rgb5_a1";
284     case GL_RGBA4:
285         return "rgba4";
286     case GL_RGBA16F:
287         return "rgba16f";
288     case GL_RGB16F:
289         return "rgb16f";
290     case GL_DEPTH_COMPONENT16:
291         return "depth_component16";
292     case GL_STENCIL_INDEX8:
293         return "stencil_index8";
294     default:
295         DE_ASSERT(false);
296         return DE_NULL;
297     }
298 }
299 
getName(void) const300 std::string FboConfig::getName(void) const
301 {
302     std::string name = "";
303 
304     if (colorbufferType != GL_NONE)
305     {
306         switch (colorbufferType)
307         {
308         case GL_TEXTURE_2D:
309             name += "tex2d_";
310             break;
311         case GL_TEXTURE_CUBE_MAP:
312             name += "texcube_";
313             break;
314         case GL_RENDERBUFFER:
315             name += "rbo_";
316             break;
317         default:
318             DE_ASSERT(false);
319             break;
320         }
321         name += getFormatName(colorbufferFormat);
322     }
323 
324     if (depthbufferType != GL_NONE)
325     {
326         DE_ASSERT(depthbufferType == GL_RENDERBUFFER);
327         if (name.length() > 0)
328             name += "_";
329         name += getFormatName(depthbufferFormat);
330     }
331 
332     if (stencilbufferType != GL_NONE)
333     {
334         DE_ASSERT(stencilbufferType == GL_RENDERBUFFER);
335         if (name.length() > 0)
336             name += "_";
337         name += getFormatName(stencilbufferFormat);
338     }
339 
340     return name;
341 }
342 
343 class FboIncompleteException : public tcu::TestError
344 {
345 public:
346     FboIncompleteException(const FboConfig &config, GLenum reason, const char *file, int line);
~FboIncompleteException(void)347     virtual ~FboIncompleteException(void) throw()
348     {
349     }
350 
getConfig(void) const351     const FboConfig &getConfig(void) const
352     {
353         return m_config;
354     }
getReason(void) const355     GLenum getReason(void) const
356     {
357         return m_reason;
358     }
359 
360 private:
361     FboConfig m_config;
362     GLenum m_reason;
363 };
364 
getFboIncompleteReasonName(GLenum reason)365 static const char *getFboIncompleteReasonName(GLenum reason)
366 {
367     switch (reason)
368     {
369     case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
370         return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
371     case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
372         return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
373     case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
374         return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
375     case GL_FRAMEBUFFER_UNSUPPORTED:
376         return "GL_FRAMEBUFFER_UNSUPPORTED";
377     case GL_FRAMEBUFFER_COMPLETE:
378         return "GL_FRAMEBUFFER_COMPLETE";
379     default:
380         return "UNKNOWN";
381     }
382 }
383 
FboIncompleteException(const FboConfig & config,GLenum reason,const char * file,int line)384 FboIncompleteException::FboIncompleteException(const FboConfig &config, GLenum reason, const char *file, int line)
385     : TestError("Framebuffer is not complete", getFboIncompleteReasonName(reason), file, line)
386     , m_config(config)
387     , m_reason(reason)
388 {
389 }
390 
391 class Framebuffer
392 {
393 public:
394     Framebuffer(sglr::Context &context, const FboConfig &config, int width, int height, uint32_t fbo = 0,
395                 uint32_t colorbuffer = 0, uint32_t depthbuffer = 0, uint32_t stencilbuffer = 0);
396     ~Framebuffer(void);
397 
getConfig(void) const398     const FboConfig &getConfig(void) const
399     {
400         return m_config;
401     }
getFramebuffer(void) const402     uint32_t getFramebuffer(void) const
403     {
404         return m_framebuffer;
405     }
getColorbuffer(void) const406     uint32_t getColorbuffer(void) const
407     {
408         return m_colorbuffer;
409     }
getDepthbuffer(void) const410     uint32_t getDepthbuffer(void) const
411     {
412         return m_depthbuffer;
413     }
getStencilbuffer(void) const414     uint32_t getStencilbuffer(void) const
415     {
416         return m_stencilbuffer;
417     }
418 
419     void checkCompleteness(void);
420 
421 private:
422     void createRbo(uint32_t &name, GLenum format, int width, int height);
423     void destroyBuffer(uint32_t name, GLenum type);
424 
425     FboConfig m_config;
426     sglr::Context &m_context;
427     uint32_t m_framebuffer;
428     uint32_t m_colorbuffer;
429     uint32_t m_depthbuffer;
430     uint32_t m_stencilbuffer;
431 };
432 
isExtensionSupported(sglr::Context & context,const char * name)433 static bool isExtensionSupported(sglr::Context &context, const char *name)
434 {
435     std::istringstream extensions(context.getString(GL_EXTENSIONS));
436     std::string extension;
437 
438     while (std::getline(extensions, extension, ' '))
439     {
440         if (extension == name)
441             return true;
442     }
443 
444     return false;
445 }
446 
checkColorFormatSupport(sglr::Context & context,uint32_t sizedFormat)447 static void checkColorFormatSupport(sglr::Context &context, uint32_t sizedFormat)
448 {
449     switch (sizedFormat)
450     {
451     case GL_RGBA16F:
452     case GL_RGB16F:
453     case GL_RG16F:
454     case GL_R16F:
455         if (!isExtensionSupported(context, "GL_EXT_color_buffer_half_float"))
456             throw tcu::NotSupportedError("GL_EXT_color_buffer_half_float is not supported");
457 
458     default:
459         break;
460     }
461 }
462 
Framebuffer(sglr::Context & context,const FboConfig & config,int width,int height,uint32_t fbo,uint32_t colorbuffer,uint32_t depthbuffer,uint32_t stencilbuffer)463 Framebuffer::Framebuffer(sglr::Context &context, const FboConfig &config, int width, int height, uint32_t fbo,
464                          uint32_t colorbuffer, uint32_t depthbuffer, uint32_t stencilbuffer)
465     : m_config(config)
466     , m_context(context)
467     , m_framebuffer(fbo)
468     , m_colorbuffer(colorbuffer)
469     , m_depthbuffer(depthbuffer)
470     , m_stencilbuffer(stencilbuffer)
471 {
472     // Verify that color format is supported
473     checkColorFormatSupport(context, config.colorbufferFormat);
474 
475     if (m_framebuffer == 0)
476         context.genFramebuffers(1, &m_framebuffer);
477     context.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
478 
479     switch (m_config.colorbufferType)
480     {
481     case GL_TEXTURE_2D:
482         if (m_colorbuffer == 0)
483             context.genTextures(1, &m_colorbuffer);
484         context.bindTexture(GL_TEXTURE_2D, m_colorbuffer);
485         context.texImage2D(GL_TEXTURE_2D, 0, m_config.colorbufferFormat, width, height);
486         context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
487 
488         if (!deIsPowerOfTwo32(width) || !deIsPowerOfTwo32(height))
489         {
490             // Set wrap mode to clamp for NPOT FBOs
491             context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
492             context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
493         }
494 
495         context.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorbuffer, 0);
496         break;
497 
498     case GL_TEXTURE_CUBE_MAP:
499         DE_FATAL("TODO");
500         break;
501 
502     case GL_RENDERBUFFER:
503         createRbo(m_colorbuffer, m_config.colorbufferFormat, width, height);
504         context.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorbuffer);
505         break;
506 
507     default:
508         DE_ASSERT(m_config.colorbufferType == GL_NONE);
509         break;
510     }
511 
512     if (m_config.depthbufferType == GL_RENDERBUFFER)
513     {
514         createRbo(m_depthbuffer, m_config.depthbufferFormat, width, height);
515         context.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthbuffer);
516     }
517     else
518         DE_ASSERT(m_config.depthbufferType == GL_NONE);
519 
520     if (m_config.stencilbufferType == GL_RENDERBUFFER)
521     {
522         createRbo(m_stencilbuffer, m_config.stencilbufferFormat, width, height);
523         context.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_stencilbuffer);
524     }
525     else
526         DE_ASSERT(m_config.stencilbufferType == GL_NONE);
527 
528     context.bindFramebuffer(GL_FRAMEBUFFER, 0);
529 }
530 
~Framebuffer(void)531 Framebuffer::~Framebuffer(void)
532 {
533     m_context.deleteFramebuffers(1, &m_framebuffer);
534     destroyBuffer(m_colorbuffer, m_config.colorbufferType);
535     destroyBuffer(m_depthbuffer, m_config.depthbufferType);
536     destroyBuffer(m_stencilbuffer, m_config.stencilbufferType);
537 }
538 
checkCompleteness(void)539 void Framebuffer::checkCompleteness(void)
540 {
541     m_context.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
542     GLenum status = m_context.checkFramebufferStatus(GL_FRAMEBUFFER);
543     m_context.bindFramebuffer(GL_FRAMEBUFFER, 0);
544     if (status != GL_FRAMEBUFFER_COMPLETE)
545         throw FboIncompleteException(m_config, status, __FILE__, __LINE__);
546 }
547 
createRbo(uint32_t & name,GLenum format,int width,int height)548 void Framebuffer::createRbo(uint32_t &name, GLenum format, int width, int height)
549 {
550     if (name == 0)
551         m_context.genRenderbuffers(1, &name);
552     m_context.bindRenderbuffer(GL_RENDERBUFFER, name);
553     m_context.renderbufferStorage(GL_RENDERBUFFER, format, width, height);
554 }
555 
destroyBuffer(uint32_t name,GLenum type)556 void Framebuffer::destroyBuffer(uint32_t name, GLenum type)
557 {
558     if (type == GL_TEXTURE_2D || type == GL_TEXTURE_CUBE_MAP)
559         m_context.deleteTextures(1, &name);
560     else if (type == GL_RENDERBUFFER)
561         m_context.deleteRenderbuffers(1, &name);
562     else
563         DE_ASSERT(type == GL_NONE);
564 }
565 
createMetaballsTex2D(sglr::Context & context,uint32_t name,GLenum format,GLenum dataType,int width,int height)566 static void createMetaballsTex2D(sglr::Context &context, uint32_t name, GLenum format, GLenum dataType, int width,
567                                  int height)
568 {
569     tcu::TextureFormat texFormat = glu::mapGLTransferFormat(format, dataType);
570     tcu::TextureLevel level(texFormat, width, height);
571 
572     tcu::fillWithMetaballs(level.getAccess(), 5, name ^ width ^ height);
573 
574     context.bindTexture(GL_TEXTURE_2D, name);
575     context.texImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, dataType, level.getAccess().getDataPtr());
576     context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
577 }
578 
createQuadsTex2D(sglr::Context & context,uint32_t name,GLenum format,GLenum dataType,int width,int height)579 static void createQuadsTex2D(sglr::Context &context, uint32_t name, GLenum format, GLenum dataType, int width,
580                              int height)
581 {
582     tcu::TextureFormat texFormat = glu::mapGLTransferFormat(format, dataType);
583     tcu::TextureLevel level(texFormat, width, height);
584 
585     tcu::fillWithRGBAQuads(level.getAccess());
586 
587     context.bindTexture(GL_TEXTURE_2D, name);
588     context.texImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, dataType, level.getAccess().getDataPtr());
589     context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
590 }
591 
592 class FboRenderCase : public TestCase
593 {
594 public:
595     FboRenderCase(Context &context, const char *name, const char *description, const FboConfig &config);
~FboRenderCase(void)596     virtual ~FboRenderCase(void)
597     {
598     }
599 
600     virtual IterateResult iterate(void);
601     virtual void render(sglr::Context &fboContext, Surface &dst) = DE_NULL;
602 
getConfig(void) const603     const FboConfig &getConfig(void) const
604     {
605         return m_config;
606     }
607 
isConfigSupported(const FboConfig & config)608     static bool isConfigSupported(const FboConfig &config)
609     {
610         DE_UNREF(config);
611         return true;
612     }
613 
614 private:
615     FboConfig m_config;
616 };
617 
FboRenderCase(Context & context,const char * name,const char * description,const FboConfig & config)618 FboRenderCase::FboRenderCase(Context &context, const char *name, const char *description, const FboConfig &config)
619     : TestCase(context, name, description)
620     , m_config(config)
621 {
622 }
623 
iterate(void)624 TestCase::IterateResult FboRenderCase::iterate(void)
625 {
626     Vec4 clearColor(0.125f, 0.25f, 0.5f, 1.0f);
627     glu::RenderContext &renderCtx         = m_context.getRenderContext();
628     const tcu::RenderTarget &renderTarget = m_context.getRenderTarget();
629     tcu::TestLog &log                     = m_testCtx.getLog();
630     const char *failReason                = DE_NULL;
631 
632     // Position & size for context
633     deRandom rnd;
634     deRandom_init(&rnd, deStringHash(getName()));
635 
636     int width  = deMin32(renderTarget.getWidth(), 128);
637     int height = deMin32(renderTarget.getHeight(), 128);
638     int xMax   = renderTarget.getWidth() - width + 1;
639     int yMax   = renderTarget.getHeight() - height + 1;
640     int x      = deRandom_getUint32(&rnd) % xMax;
641     int y      = deRandom_getUint32(&rnd) % yMax;
642 
643     tcu::Surface gles2Frame(width, height);
644     tcu::Surface refFrame(width, height);
645     GLenum gles2Error;
646     GLenum refError;
647 
648     // Render using GLES2
649     try
650     {
651         sglr::GLContext context(renderCtx, log, sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(x, y, width, height));
652 
653         context.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
654         context.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
655 
656         render(context, gles2Frame); // Call actual render func
657         gles2Error = context.getError();
658     }
659     catch (const FboIncompleteException &e)
660     {
661         if (e.getReason() == GL_FRAMEBUFFER_UNSUPPORTED)
662         {
663             // Mark test case as unsupported
664             log << e;
665             m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported");
666             return STOP;
667         }
668         else
669             throw; // Propagate error
670     }
671 
672     // Render reference image
673     {
674         sglr::ReferenceContextBuffers buffers(
675             tcu::PixelFormat(8, 8, 8, renderTarget.getPixelFormat().alphaBits ? 8 : 0), renderTarget.getDepthBits(),
676             renderTarget.getStencilBits(), width, height);
677         sglr::ReferenceContext context(sglr::ReferenceContextLimits(renderCtx), buffers.getColorbuffer(),
678                                        buffers.getDepthbuffer(), buffers.getStencilbuffer());
679 
680         context.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
681         context.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
682 
683         render(context, refFrame);
684         refError = context.getError();
685     }
686 
687     // Compare error codes
688     bool errorCodesOk = (gles2Error == refError);
689 
690     if (!errorCodesOk)
691     {
692         log << tcu::TestLog::Message << "Error code mismatch: got " << glu::getErrorStr(gles2Error) << ", expected "
693             << glu::getErrorStr(refError) << tcu::TestLog::EndMessage;
694         failReason = "Got unexpected error";
695     }
696 
697     // Compare images
698     const float threshold = 0.05f;
699     bool imagesOk         = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refFrame, gles2Frame,
700                                               threshold, tcu::COMPARE_LOG_RESULT);
701 
702     if (!imagesOk && !failReason)
703         failReason = "Image comparison failed";
704 
705     // Store test result
706     bool isOk = errorCodesOk && imagesOk;
707     m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : failReason);
708 
709     return STOP;
710 }
711 
712 namespace FboCases
713 {
714 
715 class ColorClearsTest : public FboRenderCase
716 {
717 public:
718     ColorClearsTest(Context &context, const FboConfig &config);
~ColorClearsTest(void)719     ~ColorClearsTest(void)
720     {
721     }
722 
723     void render(sglr::Context &context, Surface &dst);
724 };
725 
ColorClearsTest(Context & context,const FboConfig & config)726 ColorClearsTest::ColorClearsTest(Context &context, const FboConfig &config)
727     : FboRenderCase(context, config.getName().c_str(), "Color buffer clears", config)
728 {
729 }
730 
render(sglr::Context & context,Surface & dst)731 void ColorClearsTest::render(sglr::Context &context, Surface &dst)
732 {
733     int width  = 128;
734     int height = 128;
735     deRandom rnd;
736 
737     deRandom_init(&rnd, 0);
738 
739     // Create framebuffer
740     Framebuffer fbo(context, getConfig(), width, height);
741     fbo.checkCompleteness();
742 
743     // Clear fbo
744     context.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
745     context.viewport(0, 0, width, height);
746     context.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
747     context.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
748 
749     // Enable scissor test.
750     context.enable(GL_SCISSOR_TEST);
751 
752     // Do 10 random color clears
753     for (int i = 0; i < 15; i++)
754     {
755         int cX      = (int)(deRandom_getUint32(&rnd) & 0x7fffffff) % width;
756         int cY      = (int)(deRandom_getUint32(&rnd) & 0x7fffffff) % height;
757         int cWidth  = (int)(deRandom_getUint32(&rnd) & 0x7fffffff) % (width - cX);
758         int cHeight = (int)(deRandom_getUint32(&rnd) & 0x7fffffff) % (height - cY);
759         Vec4 color  = RGBA(deRandom_getUint32(&rnd)).toVec();
760 
761         context.scissor(cX, cY, cWidth, cHeight);
762         context.clearColor(color.x(), color.y(), color.z(), color.w());
763         context.clear(GL_COLOR_BUFFER_BIT);
764     }
765 
766     // Disable scissor.
767     context.disable(GL_SCISSOR_TEST);
768 
769     if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D)
770     {
771         // Unbind fbo
772         context.bindFramebuffer(GL_FRAMEBUFFER, 0);
773 
774         // Draw to screen
775         SingleTex2DShader shader;
776         uint32_t shaderID = context.createProgram(&shader);
777 
778         shader.setUnit(context, shaderID, 0);
779 
780         context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
781         context.viewport(0, 0, context.getWidth(), context.getHeight());
782         sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
783 
784         // Read from screen
785         context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
786     }
787     else
788     {
789         // clear alpha channel for GL_RGB5_A1 format because test
790         // thresholds for the alpha channel do not account for dithering
791         if (getConfig().colorbufferFormat == GL_RGB5_A1)
792         {
793             context.colorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
794             context.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
795             context.clear(GL_COLOR_BUFFER_BIT);
796             context.colorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
797         }
798 
799         // Read from fbo
800         context.readPixels(dst, 0, 0, width, height);
801     }
802 }
803 
804 class IntersectingQuadsTest : public FboRenderCase
805 {
806 public:
807     IntersectingQuadsTest(Context &context, const FboConfig &config, bool npot = false);
~IntersectingQuadsTest(void)808     virtual ~IntersectingQuadsTest(void)
809     {
810     }
811 
812     virtual void render(sglr::Context &context, Surface &dst);
813 
814     static bool isConfigSupported(const FboConfig &config);
815 
816 private:
817     int m_fboWidth;
818     int m_fboHeight;
819 };
820 
821 class IntersectingQuadsNpotTest : public IntersectingQuadsTest
822 {
823 public:
IntersectingQuadsNpotTest(Context & context,const FboConfig & config)824     IntersectingQuadsNpotTest(Context &context, const FboConfig &config) : IntersectingQuadsTest(context, config, true)
825     {
826     }
827 };
828 
IntersectingQuadsTest(Context & context,const FboConfig & config,bool npot)829 IntersectingQuadsTest::IntersectingQuadsTest(Context &context, const FboConfig &config, bool npot)
830     : FboRenderCase(context, (string(npot ? "npot_" : "") + config.getName()).c_str(), "Intersecting textured quads",
831                     config)
832     , m_fboWidth(npot ? 127 : 128)
833     , m_fboHeight(npot ? 95 : 128)
834 {
835 }
836 
isConfigSupported(const FboConfig & config)837 bool IntersectingQuadsTest::isConfigSupported(const FboConfig &config)
838 {
839     // \note Disabled for stencil configurations since doesn't exercise stencil buffer
840     return config.depthbufferType != GL_NONE && config.stencilbufferType == GL_NONE;
841 }
842 
render(sglr::Context & ctx,Surface & dst)843 void IntersectingQuadsTest::render(sglr::Context &ctx, Surface &dst)
844 {
845     SingleTex2DShader texShader;
846     uint32_t texShaderID = ctx.createProgram(&texShader);
847 
848     uint32_t metaballsTex = 1;
849     uint32_t quadsTex     = 2;
850 
851     createMetaballsTex2D(ctx, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
852     createQuadsTex2D(ctx, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
853 
854     int width  = m_fboWidth;
855     int height = m_fboHeight;
856     Framebuffer fbo(ctx, getConfig(), width, height);
857     fbo.checkCompleteness();
858 
859     // Setup shaders
860     texShader.setUnit(ctx, texShaderID, 0);
861 
862     // Draw scene
863     ctx.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
864     ctx.viewport(0, 0, width, height);
865     ctx.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
866     ctx.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
867 
868     ctx.enable(GL_DEPTH_TEST);
869 
870     ctx.bindTexture(GL_TEXTURE_2D, metaballsTex);
871     sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(1.0f, 1.0f, 1.0f));
872 
873     ctx.bindTexture(GL_TEXTURE_2D, quadsTex);
874     sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 1.0f), Vec3(1.0f, 1.0f, -1.0f));
875 
876     ctx.disable(GL_DEPTH_TEST);
877 
878     if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D)
879     {
880         // Unbind fbo
881         ctx.bindFramebuffer(GL_FRAMEBUFFER, 0);
882 
883         // Draw to screen
884         ctx.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
885         ctx.viewport(0, 0, ctx.getWidth(), ctx.getHeight());
886         sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
887 
888         // Read from screen
889         ctx.readPixels(dst, 0, 0, ctx.getWidth(), ctx.getHeight());
890     }
891     else
892     {
893         // Read from fbo
894         ctx.readPixels(dst, 0, 0, width, height);
895     }
896 }
897 
898 class MixTest : public FboRenderCase
899 {
900 public:
901     MixTest(Context &context, const FboConfig &config, bool npot = false);
~MixTest(void)902     virtual ~MixTest(void)
903     {
904     }
905 
906     void render(sglr::Context &context, Surface &dst);
907 
908     static bool isConfigSupported(const FboConfig &config);
909 
910 private:
911     int m_fboAWidth;
912     int m_fboAHeight;
913     int m_fboBWidth;
914     int m_fboBHeight;
915 };
916 
917 class MixNpotTest : public MixTest
918 {
919 public:
MixNpotTest(Context & context,const FboConfig & config)920     MixNpotTest(Context &context, const FboConfig &config) : MixTest(context, config, true)
921     {
922     }
923 };
924 
MixTest(Context & context,const FboConfig & config,bool npot)925 MixTest::MixTest(Context &context, const FboConfig &config, bool npot)
926     : FboRenderCase(context, (string(npot ? "mix_npot_" : "mix_") + config.getName()).c_str(),
927                     "Use two fbos as sources in draw operation", config)
928     , m_fboAWidth(npot ? 127 : 128)
929     , m_fboAHeight(npot ? 95 : 128)
930     , m_fboBWidth(npot ? 55 : 64)
931     , m_fboBHeight(npot ? 63 : 64)
932 {
933 }
934 
isConfigSupported(const FboConfig & config)935 bool MixTest::isConfigSupported(const FboConfig &config)
936 {
937     // \note Disabled for stencil configurations since doesn't exercise stencil buffer
938     return config.colorbufferType == GL_TEXTURE_2D && config.stencilbufferType == GL_NONE;
939 }
940 
render(sglr::Context & context,Surface & dst)941 void MixTest::render(sglr::Context &context, Surface &dst)
942 {
943     SingleTex2DShader singleTexShader;
944     MixTexturesShader mixShader;
945 
946     uint32_t singleTexShaderID = context.createProgram(&singleTexShader);
947     uint32_t mixShaderID       = context.createProgram(&mixShader);
948 
949     // Texture with metaballs
950     uint32_t metaballsTex = 1;
951     context.pixelStorei(GL_UNPACK_ALIGNMENT, 1);
952     createMetaballsTex2D(context, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
953 
954     // Setup shaders
955     singleTexShader.setUnit(context, singleTexShaderID, 0);
956     mixShader.setUnits(context, mixShaderID, 0, 1);
957 
958     // Fbo, quad with metaballs texture
959     Framebuffer fboA(context, getConfig(), m_fboAWidth, m_fboAHeight);
960     fboA.checkCompleteness();
961     context.bindFramebuffer(GL_FRAMEBUFFER, fboA.getFramebuffer());
962     context.viewport(0, 0, m_fboAWidth, m_fboAHeight);
963     context.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
964     context.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
965     context.bindTexture(GL_TEXTURE_2D, metaballsTex);
966     sglr::drawQuad(context, singleTexShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
967 
968     // Fbo, color clears
969     Framebuffer fboB(context, getConfig(), m_fboBWidth, m_fboBHeight);
970     fboB.checkCompleteness();
971     context.bindFramebuffer(GL_FRAMEBUFFER, fboB.getFramebuffer());
972     context.viewport(0, 0, m_fboBWidth, m_fboBHeight);
973     context.enable(GL_SCISSOR_TEST);
974     context.scissor(0, 0, 32, 64);
975     context.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
976     context.clear(GL_COLOR_BUFFER_BIT);
977     context.scissor(32, 0, 32, 64);
978     context.clearColor(0.0f, 1.0f, 0.0f, 1.0f);
979     context.clear(GL_COLOR_BUFFER_BIT);
980     context.disable(GL_SCISSOR_TEST);
981 
982     // Final mix op
983     context.activeTexture(GL_TEXTURE0);
984     context.bindTexture(GL_TEXTURE_2D, fboA.getColorbuffer());
985     context.activeTexture(GL_TEXTURE1);
986     context.bindTexture(GL_TEXTURE_2D, fboB.getColorbuffer());
987     context.bindFramebuffer(GL_FRAMEBUFFER, 0);
988     context.viewport(0, 0, context.getWidth(), context.getHeight());
989     sglr::drawQuad(context, mixShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
990 
991     context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
992 }
993 
994 class BlendTest : public FboRenderCase
995 {
996 public:
997     BlendTest(Context &context, const FboConfig &config, bool npot = false);
~BlendTest(void)998     virtual ~BlendTest(void)
999     {
1000     }
1001 
1002     void render(sglr::Context &context, Surface &dst);
1003 
1004     static bool isConfigSupported(const FboConfig &config);
1005 
1006 private:
1007     int m_fboWidth;
1008     int m_fboHeight;
1009 };
1010 
1011 class BlendNpotTest : public BlendTest
1012 {
1013 public:
BlendNpotTest(Context & context,const FboConfig & config)1014     BlendNpotTest(Context &context, const FboConfig &config) : BlendTest(context, config, true)
1015     {
1016     }
1017 };
1018 
BlendTest(Context & context,const FboConfig & config,bool npot)1019 BlendTest::BlendTest(Context &context, const FboConfig &config, bool npot)
1020     : FboRenderCase(context, (string(npot ? "blend_npot_" : "blend_") + config.getName()).c_str(), "Blend to fbo",
1021                     config)
1022     , m_fboWidth(npot ? 111 : 128)
1023     , m_fboHeight(npot ? 122 : 128)
1024 {
1025 }
1026 
isConfigSupported(const FboConfig & config)1027 bool BlendTest::isConfigSupported(const FboConfig &config)
1028 {
1029     // \note Disabled for stencil configurations since doesn't exercise stencil buffer
1030     return config.stencilbufferType == GL_NONE;
1031 }
1032 
render(sglr::Context & context,Surface & dst)1033 void BlendTest::render(sglr::Context &context, Surface &dst)
1034 {
1035     SingleTex2DShader shader;
1036     uint32_t shaderID     = context.createProgram(&shader);
1037     int width             = m_fboWidth;
1038     int height            = m_fboHeight;
1039     uint32_t metaballsTex = 1;
1040 
1041     createMetaballsTex2D(context, metaballsTex, GL_RGBA, GL_UNSIGNED_BYTE, 64, 64);
1042 
1043     Framebuffer fbo(context, getConfig(), width, height);
1044     fbo.checkCompleteness();
1045 
1046     shader.setUnit(context, shaderID, 0);
1047 
1048     context.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
1049     context.viewport(0, 0, width, height);
1050     context.bindTexture(GL_TEXTURE_2D, metaballsTex);
1051     context.clearColor(0.6f, 0.0f, 0.6f, 1.0f);
1052     context.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1053 
1054     context.enable(GL_BLEND);
1055     context.blendEquation(GL_FUNC_ADD);
1056     context.blendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
1057     sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1058     context.disable(GL_BLEND);
1059 
1060     if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D)
1061     {
1062         context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1063         context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
1064         context.viewport(0, 0, context.getWidth(), context.getHeight());
1065         sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1066         context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1067     }
1068     else
1069         context.readPixels(dst, 0, 0, width, height);
1070 }
1071 
1072 class StencilClearsTest : public FboRenderCase
1073 {
1074 public:
1075     StencilClearsTest(Context &context, const FboConfig &config);
~StencilClearsTest(void)1076     virtual ~StencilClearsTest(void)
1077     {
1078     }
1079 
1080     void render(sglr::Context &context, Surface &dst);
1081 
1082     static bool isConfigSupported(const FboConfig &config);
1083 };
1084 
StencilClearsTest(Context & context,const FboConfig & config)1085 StencilClearsTest::StencilClearsTest(Context &context, const FboConfig &config)
1086     : FboRenderCase(context, config.getName().c_str(), "Stencil clears", config)
1087 {
1088 }
1089 
render(sglr::Context & context,Surface & dst)1090 void StencilClearsTest::render(sglr::Context &context, Surface &dst)
1091 {
1092     SingleTex2DShader shader;
1093     uint32_t shaderID     = context.createProgram(&shader);
1094     int width             = 128;
1095     int height            = 128;
1096     uint32_t quadsTex     = 1;
1097     uint32_t metaballsTex = 2;
1098 
1099     createQuadsTex2D(context, quadsTex, GL_RGBA, GL_UNSIGNED_BYTE, width, height);
1100     createMetaballsTex2D(context, metaballsTex, GL_RGBA, GL_UNSIGNED_BYTE, width, height);
1101 
1102     Framebuffer fbo(context, getConfig(), width, height);
1103     fbo.checkCompleteness();
1104 
1105     // Bind framebuffer and clear
1106     context.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
1107     context.viewport(0, 0, width, height);
1108     context.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1109     context.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1110 
1111     // Do stencil clears
1112     context.enable(GL_SCISSOR_TEST);
1113     context.scissor(10, 16, 32, 120);
1114     context.clearStencil(1);
1115     context.clear(GL_STENCIL_BUFFER_BIT);
1116     context.scissor(16, 32, 100, 64);
1117     context.clearStencil(2);
1118     context.clear(GL_STENCIL_BUFFER_BIT);
1119     context.disable(GL_SCISSOR_TEST);
1120 
1121     // Draw 2 textures with stecil tests
1122     context.activeTexture(GL_TEXTURE0);
1123     context.bindTexture(GL_TEXTURE_2D, quadsTex);
1124     context.activeTexture(GL_TEXTURE1);
1125     context.bindTexture(GL_TEXTURE_2D, metaballsTex);
1126 
1127     context.enable(GL_STENCIL_TEST);
1128     context.stencilFunc(GL_EQUAL, 1, 0xffffffffu);
1129     shader.setUnit(context, shaderID, 0);
1130     sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1131 
1132     context.stencilFunc(GL_EQUAL, 2, 0xffffffffu);
1133     shader.setUnit(context, shaderID, 1);
1134     sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1135 
1136     context.disable(GL_STENCIL_TEST);
1137 
1138     if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D)
1139     {
1140         context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1141         context.activeTexture(GL_TEXTURE0);
1142         context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
1143         context.viewport(0, 0, context.getWidth(), context.getHeight());
1144         shader.setUnit(context, shaderID, 0);
1145         sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1146         context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1147     }
1148     else
1149     {
1150         // clear alpha channel for GL_RGB5_A1 format because test
1151         // thresholds for the alpha channel do not account for dithering
1152         if (getConfig().colorbufferFormat == GL_RGB5_A1)
1153         {
1154             context.colorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
1155             context.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1156             context.clear(GL_COLOR_BUFFER_BIT);
1157             context.colorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1158         }
1159 
1160         context.readPixels(dst, 0, 0, width, height);
1161     }
1162 }
1163 
isConfigSupported(const FboConfig & config)1164 bool StencilClearsTest::isConfigSupported(const FboConfig &config)
1165 {
1166     return config.stencilbufferType != GL_NONE;
1167 }
1168 
1169 class StencilTest : public FboRenderCase
1170 {
1171 public:
1172     StencilTest(Context &context, const FboConfig &config, bool npot = false);
~StencilTest(void)1173     virtual ~StencilTest(void)
1174     {
1175     }
1176 
1177     void render(sglr::Context &context, Surface &dst);
1178 
1179     static bool isConfigSupported(const FboConfig &config);
1180 
1181 private:
1182     int m_fboWidth;
1183     int m_fboHeight;
1184 };
1185 
1186 class StencilNpotTest : public StencilTest
1187 {
1188 public:
StencilNpotTest(Context & context,const FboConfig & config)1189     StencilNpotTest(Context &context, const FboConfig &config) : StencilTest(context, config, true)
1190     {
1191     }
1192 };
1193 
StencilTest(Context & context,const FboConfig & config,bool npot)1194 StencilTest::StencilTest(Context &context, const FboConfig &config, bool npot)
1195     : FboRenderCase(context, (string(npot ? "npot_" : "") + config.getName()).c_str(), "Stencil ops", config)
1196     , m_fboWidth(npot ? 99 : 128)
1197     , m_fboHeight(npot ? 110 : 128)
1198 {
1199 }
1200 
isConfigSupported(const FboConfig & config)1201 bool StencilTest::isConfigSupported(const FboConfig &config)
1202 {
1203     return config.stencilbufferType != GL_NONE;
1204 }
1205 
render(sglr::Context & ctx,Surface & dst)1206 void StencilTest::render(sglr::Context &ctx, Surface &dst)
1207 {
1208     FlatColorShader colorShader;
1209     SingleTex2DShader texShader;
1210     uint32_t colorShaderID = ctx.createProgram(&colorShader);
1211     uint32_t texShaderID   = ctx.createProgram(&texShader);
1212     int width              = m_fboWidth;
1213     int height             = m_fboHeight;
1214     int texWidth           = 64;
1215     int texHeight          = 64;
1216     uint32_t quadsTex      = 1;
1217     uint32_t metaballsTex  = 2;
1218     bool depth             = getConfig().depthbufferType != GL_NONE;
1219 
1220     createQuadsTex2D(ctx, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, texWidth, texHeight);
1221     createMetaballsTex2D(ctx, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, texWidth, texHeight);
1222 
1223     Framebuffer fbo(ctx, getConfig(), width, height);
1224     fbo.checkCompleteness();
1225 
1226     // Bind framebuffer and clear
1227     ctx.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
1228     ctx.viewport(0, 0, width, height);
1229     ctx.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1230     ctx.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1231 
1232     // Render intersecting quads - increment stencil on depth pass
1233     ctx.enable(GL_DEPTH_TEST);
1234     ctx.enable(GL_STENCIL_TEST);
1235     ctx.stencilFunc(GL_ALWAYS, 0, 0xffu);
1236     ctx.stencilOp(GL_KEEP, GL_KEEP, GL_INCR);
1237 
1238     colorShader.setColor(ctx, colorShaderID, Vec4(0.0f, 0.0f, 1.0f, 1.0f));
1239     sglr::drawQuad(ctx, colorShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f));
1240 
1241     ctx.bindTexture(GL_TEXTURE_2D, quadsTex);
1242     texShader.setUnit(ctx, texShaderID, 0);
1243     sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(+1.0f, +1.0f, +1.0f));
1244 
1245     // Draw quad with stencil test (stencil == 1 or 2 depending on depth) - decrement on stencil failure
1246     ctx.disable(GL_DEPTH_TEST);
1247     ctx.stencilFunc(GL_EQUAL, depth ? 2 : 1, 0xffu);
1248     ctx.stencilOp(GL_DECR, GL_KEEP, GL_KEEP);
1249     colorShader.setColor(ctx, colorShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0f));
1250     sglr::drawQuad(ctx, colorShaderID, Vec3(-0.5f, -0.5f, 0.0f), Vec3(+0.5f, +0.5f, 0.0f));
1251 
1252     // Draw metaballs with stencil test where stencil > 1 or 2 depending on depth buffer
1253     ctx.bindTexture(GL_TEXTURE_2D, metaballsTex);
1254     ctx.stencilFunc(GL_GREATER, depth ? 1 : 2, 0xffu);
1255     ctx.stencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1256     sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f));
1257 
1258     ctx.disable(GL_STENCIL_TEST);
1259 
1260     if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D)
1261     {
1262         ctx.bindFramebuffer(GL_FRAMEBUFFER, 0);
1263         ctx.activeTexture(GL_TEXTURE0);
1264         ctx.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
1265         ctx.viewport(0, 0, ctx.getWidth(), ctx.getHeight());
1266         sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1267         ctx.readPixels(dst, 0, 0, ctx.getWidth(), ctx.getHeight());
1268     }
1269     else
1270         ctx.readPixels(dst, 0, 0, width, height);
1271 }
1272 
1273 class SharedColorbufferTest : public FboRenderCase
1274 {
1275 public:
1276     SharedColorbufferTest(Context &context, const FboConfig &config);
~SharedColorbufferTest(void)1277     virtual ~SharedColorbufferTest(void)
1278     {
1279     }
1280 
1281     void render(sglr::Context &context, Surface &dst);
1282 };
1283 
SharedColorbufferTest(Context & context,const FboConfig & config)1284 SharedColorbufferTest::SharedColorbufferTest(Context &context, const FboConfig &config)
1285     : FboRenderCase(context, config.getName().c_str(), "Shared colorbuffer", config)
1286 {
1287 }
1288 
render(sglr::Context & context,Surface & dst)1289 void SharedColorbufferTest::render(sglr::Context &context, Surface &dst)
1290 {
1291     SingleTex2DShader shader;
1292     uint32_t shaderID = context.createProgram(&shader);
1293     int width         = 128;
1294     int height        = 128;
1295     // bool depth = getConfig().depthbufferFormat != GL_NONE;
1296     bool stencil = getConfig().stencilbufferFormat != GL_NONE;
1297 
1298     // Textures
1299     uint32_t quadsTex     = 1;
1300     uint32_t metaballsTex = 2;
1301     createQuadsTex2D(context, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
1302     createMetaballsTex2D(context, metaballsTex, GL_RGBA, GL_UNSIGNED_BYTE, 64, 64);
1303 
1304     context.viewport(0, 0, width, height);
1305 
1306     shader.setUnit(context, shaderID, 0);
1307 
1308     // Fbo A
1309     Framebuffer fboA(context, getConfig(), width, height);
1310     fboA.checkCompleteness();
1311 
1312     // Fbo B - don't create colorbuffer
1313     FboConfig cfg         = getConfig();
1314     cfg.colorbufferType   = GL_NONE;
1315     cfg.colorbufferFormat = GL_NONE;
1316     Framebuffer fboB(context, cfg, width, height);
1317 
1318     // Attach color buffer from fbo A
1319     context.bindFramebuffer(GL_FRAMEBUFFER, fboB.getFramebuffer());
1320     switch (getConfig().colorbufferType)
1321     {
1322     case GL_TEXTURE_2D:
1323         context.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboA.getColorbuffer(), 0);
1324         break;
1325 
1326     case GL_RENDERBUFFER:
1327         context.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fboA.getColorbuffer());
1328         break;
1329 
1330     default:
1331         DE_ASSERT(false);
1332     }
1333 
1334     // Clear depth and stencil in fbo B
1335     context.clear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1336 
1337     // Render quads to fbo 1, with depth 0.0
1338     context.bindFramebuffer(GL_FRAMEBUFFER, fboA.getFramebuffer());
1339     context.bindTexture(GL_TEXTURE_2D, quadsTex);
1340     context.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1341     context.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1342 
1343     if (stencil)
1344     {
1345         // Stencil to 1 in fbo A
1346         context.clearStencil(1);
1347         context.clear(GL_STENCIL_BUFFER_BIT);
1348     }
1349 
1350     context.enable(GL_DEPTH_TEST);
1351     sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1352     context.disable(GL_DEPTH_TEST);
1353 
1354     // Blend metaballs to fbo 2
1355     context.bindFramebuffer(GL_FRAMEBUFFER, fboB.getFramebuffer());
1356     context.bindTexture(GL_TEXTURE_2D, metaballsTex);
1357     context.enable(GL_BLEND);
1358     context.blendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
1359     sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1360 
1361     // Render small quad that is only visible if depth buffer is not shared with fbo A - or there is no depth bits
1362     context.bindTexture(GL_TEXTURE_2D, quadsTex);
1363     context.enable(GL_DEPTH_TEST);
1364     sglr::drawQuad(context, shaderID, Vec3(0.5f, 0.5f, 0.5f), Vec3(1.0f, 1.0f, 0.5f));
1365     context.disable(GL_DEPTH_TEST);
1366 
1367     if (stencil)
1368     {
1369         FlatColorShader flatShader;
1370         uint32_t flatShaderID = context.createProgram(&flatShader);
1371 
1372         flatShader.setColor(context, flatShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0f));
1373 
1374         // Clear subset of stencil buffer to 1
1375         context.enable(GL_SCISSOR_TEST);
1376         context.scissor(10, 10, 12, 25);
1377         context.clearStencil(1);
1378         context.clear(GL_STENCIL_BUFFER_BIT);
1379         context.disable(GL_SCISSOR_TEST);
1380 
1381         // Render quad with stencil mask == 1
1382         context.enable(GL_STENCIL_TEST);
1383         context.stencilFunc(GL_EQUAL, 1, 0xffu);
1384         sglr::drawQuad(context, flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1385         context.disable(GL_STENCIL_TEST);
1386     }
1387 
1388     // Get results
1389     if (fboA.getConfig().colorbufferType == GL_TEXTURE_2D)
1390     {
1391         context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1392         context.bindTexture(GL_TEXTURE_2D, fboA.getColorbuffer());
1393         context.viewport(0, 0, context.getWidth(), context.getHeight());
1394         sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1395         context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1396     }
1397     else
1398         context.readPixels(dst, 0, 0, width, height);
1399 }
1400 
1401 class SharedColorbufferClearsTest : public FboRenderCase
1402 {
1403 public:
1404     SharedColorbufferClearsTest(Context &context, const FboConfig &config);
~SharedColorbufferClearsTest(void)1405     virtual ~SharedColorbufferClearsTest(void)
1406     {
1407     }
1408 
1409     static bool isConfigSupported(const FboConfig &config);
1410     void render(sglr::Context &context, Surface &dst);
1411 };
1412 
SharedColorbufferClearsTest(Context & context,const FboConfig & config)1413 SharedColorbufferClearsTest::SharedColorbufferClearsTest(Context &context, const FboConfig &config)
1414     : FboRenderCase(context, config.getName().c_str(), "Shared colorbuffer clears", config)
1415 {
1416 }
1417 
isConfigSupported(const FboConfig & config)1418 bool SharedColorbufferClearsTest::isConfigSupported(const FboConfig &config)
1419 {
1420     return config.colorbufferType != GL_NONE && config.depthbufferType == GL_NONE &&
1421            config.stencilbufferType == GL_NONE;
1422 }
1423 
render(sglr::Context & context,Surface & dst)1424 void SharedColorbufferClearsTest::render(sglr::Context &context, Surface &dst)
1425 {
1426     int width            = 128;
1427     int height           = 128;
1428     uint32_t colorbuffer = 1;
1429 
1430     checkColorFormatSupport(context, getConfig().colorbufferFormat);
1431 
1432     // Single colorbuffer
1433     if (getConfig().colorbufferType == GL_TEXTURE_2D)
1434     {
1435         context.bindTexture(GL_TEXTURE_2D, colorbuffer);
1436         context.texImage2D(GL_TEXTURE_2D, 0, getConfig().colorbufferFormat, width, height);
1437         context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1438     }
1439     else
1440     {
1441         DE_ASSERT(getConfig().colorbufferType == GL_RENDERBUFFER);
1442         context.bindRenderbuffer(GL_RENDERBUFFER, colorbuffer);
1443         context.renderbufferStorage(GL_RENDERBUFFER, getConfig().colorbufferFormat, width, height);
1444     }
1445 
1446     // Multiple framebuffers sharing the colorbuffer
1447     for (int fbo = 1; fbo <= 3; fbo++)
1448     {
1449         context.bindFramebuffer(GL_FRAMEBUFFER, fbo);
1450 
1451         if (getConfig().colorbufferType == GL_TEXTURE_2D)
1452             context.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer, 0);
1453         else
1454             context.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer);
1455     }
1456 
1457     context.bindFramebuffer(GL_FRAMEBUFFER, 1);
1458 
1459     // Check completeness
1460     {
1461         GLenum status = context.checkFramebufferStatus(GL_FRAMEBUFFER);
1462         if (status != GL_FRAMEBUFFER_COMPLETE)
1463             throw FboIncompleteException(getConfig(), status, __FILE__, __LINE__);
1464     }
1465 
1466     // Render to them
1467     context.viewport(0, 0, width, height);
1468     context.clearColor(0.0f, 0.0f, 1.0f, 1.0f);
1469     context.clear(GL_COLOR_BUFFER_BIT);
1470 
1471     context.enable(GL_SCISSOR_TEST);
1472 
1473     context.bindFramebuffer(GL_FRAMEBUFFER, 2);
1474     context.clearColor(0.6f, 0.0f, 0.0f, 1.0f);
1475     context.scissor(10, 10, 64, 64);
1476     context.clear(GL_COLOR_BUFFER_BIT);
1477     context.clearColor(0.0f, 0.6f, 0.0f, 1.0f);
1478     context.scissor(60, 60, 40, 20);
1479     context.clear(GL_COLOR_BUFFER_BIT);
1480 
1481     context.bindFramebuffer(GL_FRAMEBUFFER, 3);
1482     context.clearColor(0.0f, 0.0f, 0.6f, 1.0f);
1483     context.scissor(20, 20, 100, 10);
1484     context.clear(GL_COLOR_BUFFER_BIT);
1485 
1486     context.bindFramebuffer(GL_FRAMEBUFFER, 1);
1487     context.clearColor(0.6f, 0.0f, 0.6f, 1.0f);
1488     context.scissor(20, 20, 5, 100);
1489     context.clear(GL_COLOR_BUFFER_BIT);
1490 
1491     context.disable(GL_SCISSOR_TEST);
1492 
1493     if (getConfig().colorbufferType == GL_TEXTURE_2D)
1494     {
1495         SingleTex2DShader shader;
1496         uint32_t shaderID = context.createProgram(&shader);
1497 
1498         shader.setUnit(context, shaderID, 0);
1499 
1500         context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1501         context.viewport(0, 0, context.getWidth(), context.getHeight());
1502         sglr::drawQuad(context, shaderID, Vec3(-0.9f, -0.9f, 0.0f), Vec3(0.9f, 0.9f, 0.0f));
1503         context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1504     }
1505     else
1506         context.readPixels(dst, 0, 0, width, height);
1507 }
1508 
1509 class SharedDepthbufferTest : public FboRenderCase
1510 {
1511 public:
1512     SharedDepthbufferTest(Context &context, const FboConfig &config);
~SharedDepthbufferTest(void)1513     virtual ~SharedDepthbufferTest(void)
1514     {
1515     }
1516 
1517     static bool isConfigSupported(const FboConfig &config);
1518     void render(sglr::Context &context, Surface &dst);
1519 };
1520 
SharedDepthbufferTest(Context & context,const FboConfig & config)1521 SharedDepthbufferTest::SharedDepthbufferTest(Context &context, const FboConfig &config)
1522     : FboRenderCase(context, config.getName().c_str(), "Shared depthbuffer", config)
1523 {
1524 }
1525 
isConfigSupported(const FboConfig & config)1526 bool SharedDepthbufferTest::isConfigSupported(const FboConfig &config)
1527 {
1528     return config.depthbufferType == GL_RENDERBUFFER;
1529 }
1530 
render(sglr::Context & context,Surface & dst)1531 void SharedDepthbufferTest::render(sglr::Context &context, Surface &dst)
1532 {
1533     SingleTex2DShader texShader;
1534     FlatColorShader colorShader;
1535     uint32_t texShaderID   = context.createProgram(&texShader);
1536     uint32_t colorShaderID = context.createProgram(&colorShader);
1537     int width              = 128;
1538     int height             = 128;
1539     bool stencil           = getConfig().stencilbufferType != GL_NONE;
1540 
1541     // Setup shaders
1542     texShader.setUnit(context, texShaderID, 0);
1543     colorShader.setColor(context, colorShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0f));
1544 
1545     // Textures
1546     uint32_t metaballsTex = 5;
1547     uint32_t quadsTex     = 6;
1548     createMetaballsTex2D(context, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
1549     createQuadsTex2D(context, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
1550 
1551     context.viewport(0, 0, width, height);
1552 
1553     // Fbo A
1554     Framebuffer fboA(context, getConfig(), width, height);
1555     fboA.checkCompleteness();
1556 
1557     // Fbo B
1558     FboConfig cfg         = getConfig();
1559     cfg.depthbufferType   = GL_NONE;
1560     cfg.depthbufferFormat = GL_NONE;
1561     Framebuffer fboB(context, cfg, width, height);
1562 
1563     // Bind depth buffer from fbo A to fbo B
1564     DE_ASSERT(fboA.getConfig().depthbufferType == GL_RENDERBUFFER);
1565     context.bindFramebuffer(GL_FRAMEBUFFER, fboB.getFramebuffer());
1566     context.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fboA.getDepthbuffer());
1567 
1568     // Clear fbo B color to red and stencil to 1
1569     context.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
1570     context.clearStencil(1);
1571     context.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1572 
1573     // Enable depth test.
1574     context.enable(GL_DEPTH_TEST);
1575 
1576     // Render quad to fbo A
1577     context.bindFramebuffer(GL_FRAMEBUFFER, fboA.getFramebuffer());
1578     context.bindTexture(GL_TEXTURE_2D, quadsTex);
1579     context.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1580     context.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1581     sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1582 
1583     // Render metaballs to fbo B
1584     context.bindFramebuffer(GL_FRAMEBUFFER, fboB.getFramebuffer());
1585     context.bindTexture(GL_TEXTURE_2D, metaballsTex);
1586     sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(1.0f, 1.0f, 1.0f));
1587 
1588     context.disable(GL_DEPTH_TEST);
1589 
1590     if (stencil)
1591     {
1592         // Clear subset of stencil buffer to 0
1593         context.enable(GL_SCISSOR_TEST);
1594         context.scissor(10, 10, 12, 25);
1595         context.clearStencil(0);
1596         context.clear(GL_STENCIL_BUFFER_BIT);
1597         context.disable(GL_SCISSOR_TEST);
1598 
1599         // Render quad with stencil mask == 0
1600         context.enable(GL_STENCIL_TEST);
1601         context.stencilFunc(GL_EQUAL, 0, 0xffu);
1602         sglr::drawQuad(context, colorShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1603         context.disable(GL_STENCIL_TEST);
1604     }
1605 
1606     if (getConfig().colorbufferType == GL_TEXTURE_2D)
1607     {
1608         // Render both to screen
1609         context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1610         context.viewport(0, 0, context.getWidth(), context.getHeight());
1611         context.bindTexture(GL_TEXTURE_2D, fboA.getColorbuffer());
1612         sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(0.0f, 1.0f, 0.0f));
1613         context.bindTexture(GL_TEXTURE_2D, fboB.getColorbuffer());
1614         sglr::drawQuad(context, texShaderID, Vec3(0.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1615 
1616         context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1617     }
1618     else
1619     {
1620         // Read results from fbo B
1621         context.readPixels(dst, 0, 0, width, height);
1622     }
1623 }
1624 
1625 class TexSubImageAfterRenderTest : public FboRenderCase
1626 {
1627 public:
1628     TexSubImageAfterRenderTest(Context &context, const FboConfig &config);
~TexSubImageAfterRenderTest(void)1629     virtual ~TexSubImageAfterRenderTest(void)
1630     {
1631     }
1632 
1633     static bool isConfigSupported(const FboConfig &config);
1634     void render(sglr::Context &context, Surface &dst);
1635 };
1636 
TexSubImageAfterRenderTest(Context & context,const FboConfig & config)1637 TexSubImageAfterRenderTest::TexSubImageAfterRenderTest(Context &context, const FboConfig &config)
1638     : FboRenderCase(context, (string("after_render_") + config.getName()).c_str(),
1639                     "TexSubImage after rendering to texture", config)
1640 {
1641 }
1642 
isConfigSupported(const FboConfig & config)1643 bool TexSubImageAfterRenderTest::isConfigSupported(const FboConfig &config)
1644 {
1645     return config.colorbufferType == GL_TEXTURE_2D &&
1646            (config.colorbufferFormat == GL_RGB || config.colorbufferFormat == GL_RGBA) &&
1647            config.depthbufferType == GL_NONE && config.stencilbufferType == GL_NONE;
1648 }
1649 
render(sglr::Context & context,Surface & dst)1650 void TexSubImageAfterRenderTest::render(sglr::Context &context, Surface &dst)
1651 {
1652     SingleTex2DShader shader;
1653     uint32_t shaderID = context.createProgram(&shader);
1654     bool isRGBA       = getConfig().colorbufferFormat == GL_RGBA;
1655 
1656     tcu::TextureLevel fourQuads(tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), 64, 64);
1657     tcu::fillWithRGBAQuads(fourQuads.getAccess());
1658 
1659     tcu::TextureLevel metaballs(
1660         tcu::TextureFormat(isRGBA ? tcu::TextureFormat::RGBA : tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8),
1661         64, 64);
1662     tcu::fillWithMetaballs(metaballs.getAccess(), 5, 3);
1663 
1664     shader.setUnit(context, shaderID, 0);
1665 
1666     uint32_t fourQuadsTex = 1;
1667     context.bindTexture(GL_TEXTURE_2D, fourQuadsTex);
1668     context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1669     context.texImage2D(GL_TEXTURE_2D, 0, GL_RGB, 64, 64, 0, GL_RGB, GL_UNSIGNED_BYTE,
1670                        fourQuads.getAccess().getDataPtr());
1671 
1672     context.bindFramebuffer(GL_FRAMEBUFFER, 1);
1673 
1674     uint32_t fboTex = 2;
1675     context.bindTexture(GL_TEXTURE_2D, fboTex);
1676     context.texImage2D(GL_TEXTURE_2D, 0, isRGBA ? GL_RGBA : GL_RGB, 128, 128);
1677     context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1678     context.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTex, 0);
1679 
1680     // Render to fbo
1681     context.viewport(0, 0, 128, 128);
1682     context.bindTexture(GL_TEXTURE_2D, fourQuadsTex);
1683     sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1684 
1685     // Update texture using TexSubImage2D
1686     context.bindTexture(GL_TEXTURE_2D, fboTex);
1687     context.texSubImage2D(GL_TEXTURE_2D, 0, 32, 32, 64, 64, isRGBA ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE,
1688                           metaballs.getAccess().getDataPtr());
1689 
1690     // Draw to screen
1691     context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1692     context.viewport(0, 0, context.getWidth(), context.getHeight());
1693     sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1694     context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1695 }
1696 
1697 class TexSubImageBetweenRenderTest : public FboRenderCase
1698 {
1699 public:
1700     TexSubImageBetweenRenderTest(Context &context, const FboConfig &config);
~TexSubImageBetweenRenderTest(void)1701     virtual ~TexSubImageBetweenRenderTest(void)
1702     {
1703     }
1704 
1705     static bool isConfigSupported(const FboConfig &config);
1706     void render(sglr::Context &context, Surface &dst);
1707 };
1708 
TexSubImageBetweenRenderTest(Context & context,const FboConfig & config)1709 TexSubImageBetweenRenderTest::TexSubImageBetweenRenderTest(Context &context, const FboConfig &config)
1710     : FboRenderCase(context, (string("between_render_") + config.getName()).c_str(),
1711                     "TexSubImage between rendering calls", config)
1712 {
1713 }
1714 
isConfigSupported(const FboConfig & config)1715 bool TexSubImageBetweenRenderTest::isConfigSupported(const FboConfig &config)
1716 {
1717     return config.colorbufferType == GL_TEXTURE_2D &&
1718            (config.colorbufferFormat == GL_RGB || config.colorbufferFormat == GL_RGBA) &&
1719            config.depthbufferType == GL_NONE && config.stencilbufferType == GL_NONE;
1720 }
1721 
render(sglr::Context & context,Surface & dst)1722 void TexSubImageBetweenRenderTest::render(sglr::Context &context, Surface &dst)
1723 {
1724     SingleTex2DShader shader;
1725     uint32_t shaderID = context.createProgram(&shader);
1726     bool isRGBA       = getConfig().colorbufferFormat == GL_RGBA;
1727 
1728     tcu::TextureLevel fourQuads(tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), 64, 64);
1729     tcu::fillWithRGBAQuads(fourQuads.getAccess());
1730 
1731     tcu::TextureLevel metaballs(
1732         tcu::TextureFormat(isRGBA ? tcu::TextureFormat::RGBA : tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8),
1733         64, 64);
1734     tcu::fillWithMetaballs(metaballs.getAccess(), 5, 3);
1735 
1736     tcu::TextureLevel metaballs2(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 64, 64);
1737     tcu::fillWithMetaballs(metaballs2.getAccess(), 5, 4);
1738 
1739     uint32_t metaballsTex = 3;
1740     context.bindTexture(GL_TEXTURE_2D, metaballsTex);
1741     context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1742     context.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1743                        metaballs2.getAccess().getDataPtr());
1744 
1745     uint32_t fourQuadsTex = 1;
1746     context.bindTexture(GL_TEXTURE_2D, fourQuadsTex);
1747     context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1748     context.texImage2D(GL_TEXTURE_2D, 0, GL_RGB, 64, 64, 0, GL_RGB, GL_UNSIGNED_BYTE,
1749                        fourQuads.getAccess().getDataPtr());
1750 
1751     context.bindFramebuffer(GL_FRAMEBUFFER, 1);
1752 
1753     uint32_t fboTex = 2;
1754     context.bindTexture(GL_TEXTURE_2D, fboTex);
1755     context.texImage2D(GL_TEXTURE_2D, 0, isRGBA ? GL_RGBA : GL_RGB, 128, 128);
1756     context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1757     context.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTex, 0);
1758 
1759     shader.setUnit(context, shaderID, 0);
1760 
1761     // Render to fbo
1762     context.viewport(0, 0, 128, 128);
1763     context.bindTexture(GL_TEXTURE_2D, fourQuadsTex);
1764     sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1765 
1766     // Update texture using TexSubImage2D
1767     context.bindTexture(GL_TEXTURE_2D, fboTex);
1768     context.texSubImage2D(GL_TEXTURE_2D, 0, 32, 32, 64, 64, isRGBA ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE,
1769                           metaballs.getAccess().getDataPtr());
1770 
1771     // Render again to fbo
1772     context.bindTexture(GL_TEXTURE_2D, metaballsTex);
1773     context.enable(GL_BLEND);
1774     context.blendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
1775     sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1776     context.disable(GL_BLEND);
1777 
1778     // Draw to screen
1779     context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1780     context.viewport(0, 0, context.getWidth(), context.getHeight());
1781     context.bindTexture(GL_TEXTURE_2D, fboTex);
1782     sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1783 
1784     context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1785 }
1786 
1787 class ResizeTest : public FboRenderCase
1788 {
1789 public:
1790     ResizeTest(Context &context, const FboConfig &config);
~ResizeTest(void)1791     virtual ~ResizeTest(void)
1792     {
1793     }
1794 
1795     void render(sglr::Context &context, Surface &dst);
1796 };
1797 
ResizeTest(Context & context,const FboConfig & config)1798 ResizeTest::ResizeTest(Context &context, const FboConfig &config)
1799     : FboRenderCase(context, config.getName().c_str(), "Resize framebuffer", config)
1800 {
1801 }
1802 
render(sglr::Context & context,Surface & dst)1803 void ResizeTest::render(sglr::Context &context, Surface &dst)
1804 {
1805     SingleTex2DShader texShader;
1806     FlatColorShader colorShader;
1807     uint32_t texShaderID   = context.createProgram(&texShader);
1808     uint32_t colorShaderID = context.createProgram(&colorShader);
1809     uint32_t quadsTex      = 1;
1810     uint32_t metaballsTex  = 2;
1811     bool depth             = getConfig().depthbufferType != GL_NONE;
1812     bool stencil           = getConfig().stencilbufferType != GL_NONE;
1813 
1814     createQuadsTex2D(context, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
1815     createMetaballsTex2D(context, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, 32, 32);
1816 
1817     Framebuffer fbo(context, getConfig(), 128, 128);
1818     fbo.checkCompleteness();
1819 
1820     // Setup shaders
1821     texShader.setUnit(context, texShaderID, 0);
1822     colorShader.setColor(context, colorShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0f));
1823 
1824     // Render quads
1825     context.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
1826     context.viewport(0, 0, 128, 128);
1827     context.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1828     context.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1829     context.bindTexture(GL_TEXTURE_2D, quadsTex);
1830     sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1831 
1832     if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D)
1833     {
1834         // Render fbo to screen
1835         context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1836         context.viewport(0, 0, context.getWidth(), context.getHeight());
1837         context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
1838         sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
1839 
1840         // Restore binding
1841         context.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
1842     }
1843 
1844     int newWidth  = 64;
1845     int newHeight = 32;
1846 
1847     // Resize buffers
1848     switch (fbo.getConfig().colorbufferType)
1849     {
1850     case GL_TEXTURE_2D:
1851         context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
1852         context.texImage2D(GL_TEXTURE_2D, 0, fbo.getConfig().colorbufferFormat, newWidth, newHeight);
1853         break;
1854 
1855     case GL_RENDERBUFFER:
1856         context.bindRenderbuffer(GL_RENDERBUFFER, fbo.getColorbuffer());
1857         context.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().colorbufferFormat, newWidth, newHeight);
1858         break;
1859 
1860     default:
1861         DE_ASSERT(false);
1862     }
1863 
1864     if (depth)
1865     {
1866         DE_ASSERT(fbo.getConfig().depthbufferType == GL_RENDERBUFFER);
1867         context.bindRenderbuffer(GL_RENDERBUFFER, fbo.getDepthbuffer());
1868         context.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().depthbufferFormat, newWidth, newHeight);
1869     }
1870 
1871     if (stencil)
1872     {
1873         DE_ASSERT(fbo.getConfig().stencilbufferType == GL_RENDERBUFFER);
1874         context.bindRenderbuffer(GL_RENDERBUFFER, fbo.getStencilbuffer());
1875         context.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().stencilbufferFormat, newWidth, newHeight);
1876     }
1877 
1878     // Render to resized fbo
1879     context.viewport(0, 0, newWidth, newHeight);
1880     context.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
1881     context.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1882 
1883     context.enable(GL_DEPTH_TEST);
1884 
1885     context.bindTexture(GL_TEXTURE_2D, metaballsTex);
1886     sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f));
1887 
1888     context.bindTexture(GL_TEXTURE_2D, quadsTex);
1889     sglr::drawQuad(context, texShaderID, Vec3(0.0f, 0.0f, -1.0f), Vec3(+1.0f, +1.0f, 1.0f));
1890 
1891     context.disable(GL_DEPTH_TEST);
1892 
1893     if (stencil)
1894     {
1895         context.enable(GL_SCISSOR_TEST);
1896         context.scissor(10, 10, 5, 15);
1897         context.clearStencil(1);
1898         context.clear(GL_STENCIL_BUFFER_BIT);
1899         context.disable(GL_SCISSOR_TEST);
1900 
1901         context.enable(GL_STENCIL_TEST);
1902         context.stencilFunc(GL_EQUAL, 1, 0xffu);
1903         sglr::drawQuad(context, colorShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f));
1904         context.disable(GL_STENCIL_TEST);
1905     }
1906 
1907     if (getConfig().colorbufferType == GL_TEXTURE_2D)
1908     {
1909         context.bindFramebuffer(GL_FRAMEBUFFER, 0);
1910         context.viewport(0, 0, context.getWidth(), context.getHeight());
1911         context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer());
1912         sglr::drawQuad(context, texShaderID, Vec3(-0.5f, -0.5f, 0.0f), Vec3(0.5f, 0.5f, 0.0f));
1913         context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight());
1914     }
1915     else
1916         context.readPixels(dst, 0, 0, newWidth, newHeight);
1917 }
1918 
1919 template <GLenum Buffers>
1920 class RecreateBuffersTest : public FboRenderCase
1921 {
1922 public:
1923     RecreateBuffersTest(Context &context, const FboConfig &config, bool rebind);
~RecreateBuffersTest(void)1924     virtual ~RecreateBuffersTest(void)
1925     {
1926     }
1927 
1928     static bool isConfigSupported(const FboConfig &config);
1929     void render(sglr::Context &context, Surface &dst);
1930 
1931 private:
1932     bool m_rebind;
1933 };
1934 
1935 template <GLenum Buffers>
1936 class RecreateBuffersNoRebindTest : public RecreateBuffersTest<Buffers>
1937 {
1938 public:
RecreateBuffersNoRebindTest(Context & context,const FboConfig & config)1939     RecreateBuffersNoRebindTest(Context &context, const FboConfig &config)
1940         : RecreateBuffersTest<Buffers>(context, config, false)
1941     {
1942     }
1943 };
1944 
1945 template <GLenum Buffers>
1946 class RecreateBuffersRebindTest : public RecreateBuffersTest<Buffers>
1947 {
1948 public:
RecreateBuffersRebindTest(Context & context,const FboConfig & config)1949     RecreateBuffersRebindTest(Context &context, const FboConfig &config)
1950         : RecreateBuffersTest<Buffers>(context, config, true)
1951     {
1952     }
1953 };
1954 
1955 template <GLenum Buffers>
RecreateBuffersTest(Context & context,const FboConfig & config,bool rebind)1956 RecreateBuffersTest<Buffers>::RecreateBuffersTest(Context &context, const FboConfig &config, bool rebind)
1957     : FboRenderCase(context, (string(rebind ? "rebind_" : "no_rebind_") + config.getName()).c_str(), "Recreate buffers",
1958                     config)
1959     , m_rebind(rebind)
1960 {
1961 }
1962 
1963 template <GLenum Buffers>
isConfigSupported(const FboConfig & config)1964 bool RecreateBuffersTest<Buffers>::isConfigSupported(const FboConfig &config)
1965 {
1966     if ((Buffers & GL_COLOR_BUFFER_BIT) && config.colorbufferType == GL_NONE)
1967         return false;
1968     if ((Buffers & GL_DEPTH_BUFFER_BIT) && config.depthbufferType == GL_NONE)
1969         return false;
1970     if ((Buffers & GL_STENCIL_BUFFER_BIT) && config.stencilbufferType == GL_NONE)
1971         return false;
1972     return true;
1973 }
1974 
1975 template <GLenum Buffers>
render(sglr::Context & ctx,Surface & dst)1976 void RecreateBuffersTest<Buffers>::render(sglr::Context &ctx, Surface &dst)
1977 {
1978     SingleTex2DShader texShader;
1979     uint32_t texShaderID  = ctx.createProgram(&texShader);
1980     int width             = 128;
1981     int height            = 128;
1982     uint32_t metaballsTex = 1;
1983     uint32_t quadsTex     = 2;
1984     bool stencil          = getConfig().stencilbufferType != GL_NONE;
1985 
1986     createQuadsTex2D(ctx, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
1987     createMetaballsTex2D(ctx, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64);
1988 
1989     Framebuffer fbo(ctx, getConfig(), width, height);
1990     fbo.checkCompleteness();
1991 
1992     // Setup shader
1993     texShader.setUnit(ctx, texShaderID, 0);
1994 
1995     // Draw scene
1996     ctx.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
1997     ctx.viewport(0, 0, width, height);
1998     ctx.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
1999     ctx.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2000 
2001     ctx.enable(GL_DEPTH_TEST);
2002 
2003     ctx.bindTexture(GL_TEXTURE_2D, quadsTex);
2004     sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
2005 
2006     if (stencil)
2007     {
2008         ctx.enable(GL_SCISSOR_TEST);
2009         ctx.scissor(width / 4, height / 4, width / 2, height / 2);
2010         ctx.clearStencil(1);
2011         ctx.clear(GL_STENCIL_BUFFER_BIT);
2012         ctx.disable(GL_SCISSOR_TEST);
2013     }
2014 
2015     // Recreate buffers
2016     if (!m_rebind)
2017         ctx.bindFramebuffer(GL_FRAMEBUFFER, 0);
2018 
2019     if (Buffers & GL_COLOR_BUFFER_BIT)
2020     {
2021         uint32_t colorbuf = fbo.getColorbuffer();
2022         switch (fbo.getConfig().colorbufferType)
2023         {
2024         case GL_TEXTURE_2D:
2025             ctx.deleteTextures(1, &colorbuf);
2026             ctx.bindTexture(GL_TEXTURE_2D, colorbuf);
2027             ctx.texImage2D(GL_TEXTURE_2D, 0, fbo.getConfig().colorbufferFormat, width, height);
2028             ctx.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2029 
2030             if (m_rebind)
2031                 ctx.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuf, 0);
2032             break;
2033 
2034         case GL_RENDERBUFFER:
2035             ctx.deleteRenderbuffers(1, &colorbuf);
2036             ctx.bindRenderbuffer(GL_RENDERBUFFER, colorbuf);
2037             ctx.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().colorbufferFormat, width, height);
2038 
2039             if (m_rebind)
2040                 ctx.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuf);
2041             break;
2042 
2043         default:
2044             DE_ASSERT(false);
2045         }
2046     }
2047 
2048     if (Buffers & GL_DEPTH_BUFFER_BIT)
2049     {
2050         uint32_t depthbuf = fbo.getDepthbuffer();
2051         DE_ASSERT(fbo.getConfig().depthbufferType == GL_RENDERBUFFER);
2052 
2053         ctx.deleteRenderbuffers(1, &depthbuf);
2054         ctx.bindRenderbuffer(GL_RENDERBUFFER, depthbuf);
2055         ctx.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().depthbufferFormat, width, height);
2056 
2057         if (m_rebind)
2058             ctx.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthbuf);
2059     }
2060 
2061     if (Buffers & GL_STENCIL_BUFFER_BIT)
2062     {
2063         uint32_t stencilbuf = fbo.getStencilbuffer();
2064         DE_ASSERT(fbo.getConfig().stencilbufferType == GL_RENDERBUFFER);
2065 
2066         ctx.deleteRenderbuffers(1, &stencilbuf);
2067         ctx.bindRenderbuffer(GL_RENDERBUFFER, stencilbuf);
2068         ctx.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().stencilbufferFormat, width, height);
2069 
2070         if (m_rebind)
2071             ctx.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencilbuf);
2072     }
2073 
2074     if (!m_rebind)
2075         ctx.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer());
2076 
2077     ctx.clearColor(0.0f, 0.0f, 1.0f, 0.0f);
2078     ctx.clearStencil(0);
2079     ctx.clear(Buffers); // \note Clear only buffers that were re-created
2080 
2081     if (stencil)
2082     {
2083         // \note Stencil test enabled only if we have stencil buffer
2084         ctx.enable(GL_STENCIL_TEST);
2085         ctx.stencilFunc(GL_EQUAL, 0, 0xffu);
2086     }
2087     ctx.bindTexture(GL_TEXTURE_2D, metaballsTex);
2088     sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 1.0f), Vec3(1.0f, 1.0f, -1.0f));
2089     if (stencil)
2090         ctx.disable(GL_STENCIL_TEST);
2091 
2092     ctx.disable(GL_DEPTH_TEST);
2093 
2094     // Read from fbo
2095     ctx.readPixels(dst, 0, 0, width, height);
2096 }
2097 
2098 class RepeatedClearCase : public FboRenderCase
2099 {
2100 private:
makeConfig(uint32_t format)2101     static FboConfig makeConfig(uint32_t format)
2102     {
2103         FboConfig cfg;
2104         cfg.colorbufferType   = GL_TEXTURE_2D;
2105         cfg.colorbufferFormat = format;
2106         cfg.depthbufferType   = GL_NONE;
2107         cfg.stencilbufferType = GL_NONE;
2108         return cfg;
2109     }
2110 
2111 public:
RepeatedClearCase(Context & context,uint32_t format)2112     RepeatedClearCase(Context &context, uint32_t format)
2113         : FboRenderCase(context, makeConfig(format).getName().c_str(), "Repeated clears", makeConfig(format))
2114     {
2115     }
2116 
2117 protected:
render(sglr::Context & ctx,Surface & dst)2118     void render(sglr::Context &ctx, Surface &dst)
2119     {
2120         const int numRowsCols = 4;
2121         const int cellSize    = 16;
2122         const int fboSizes[]  = {cellSize, cellSize * numRowsCols};
2123 
2124         SingleTex2DShader fboBlitShader;
2125         const uint32_t fboBlitShaderID = ctx.createProgram(&fboBlitShader);
2126 
2127         de::Random rnd(18169662);
2128         uint32_t fbos[]     = {0, 0};
2129         uint32_t textures[] = {0, 0};
2130 
2131         ctx.genFramebuffers(2, &fbos[0]);
2132         ctx.genTextures(2, &textures[0]);
2133 
2134         for (int fboNdx = 0; fboNdx < DE_LENGTH_OF_ARRAY(fbos); fboNdx++)
2135         {
2136             ctx.bindTexture(GL_TEXTURE_2D, textures[fboNdx]);
2137             ctx.texImage2D(GL_TEXTURE_2D, 0, getConfig().colorbufferFormat, fboSizes[fboNdx], fboSizes[fboNdx], 0,
2138                            getConfig().colorbufferFormat, GL_UNSIGNED_BYTE, DE_NULL);
2139             ctx.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2140             ctx.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2141             ctx.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2142             ctx.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2143 
2144             ctx.bindFramebuffer(GL_FRAMEBUFFER, fbos[fboNdx]);
2145             ctx.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[fboNdx], 0);
2146 
2147             {
2148                 const GLenum status = ctx.checkFramebufferStatus(GL_FRAMEBUFFER);
2149                 if (status != GL_FRAMEBUFFER_COMPLETE)
2150                     throw FboIncompleteException(getConfig(), status, __FILE__, __LINE__);
2151             }
2152         }
2153 
2154         // larger fbo bound -- clear to transparent black
2155         ctx.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
2156         ctx.clear(GL_COLOR_BUFFER_BIT);
2157 
2158         fboBlitShader.setUnit(ctx, fboBlitShaderID, 0);
2159         ctx.bindTexture(GL_TEXTURE_2D, textures[0]);
2160 
2161         for (int cellY = 0; cellY < numRowsCols; cellY++)
2162             for (int cellX = 0; cellX < numRowsCols; cellX++)
2163             {
2164                 const float r = rnd.getFloat();
2165                 const float g = rnd.getFloat();
2166                 const float b = rnd.getFloat();
2167                 const float a = rnd.getFloat();
2168 
2169                 ctx.bindFramebuffer(GL_FRAMEBUFFER, fbos[0]);
2170                 ctx.clearColor(r, g, b, a);
2171                 ctx.clear(GL_COLOR_BUFFER_BIT);
2172 
2173                 ctx.bindFramebuffer(GL_FRAMEBUFFER, fbos[1]);
2174                 ctx.viewport(cellX * cellSize, cellY * cellSize, cellSize, cellSize);
2175                 sglr::drawQuad(ctx, fboBlitShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
2176             }
2177 
2178         ctx.readPixels(dst, 0, 0, fboSizes[1], fboSizes[1]);
2179     }
2180 };
2181 
2182 } // namespace FboCases
2183 
FboRenderTestGroup(Context & context)2184 FboRenderTestGroup::FboRenderTestGroup(Context &context) : TestCaseGroup(context, "render", "Rendering Tests")
2185 {
2186 }
2187 
~FboRenderTestGroup(void)2188 FboRenderTestGroup::~FboRenderTestGroup(void)
2189 {
2190 }
2191 
2192 namespace
2193 {
2194 
2195 struct TypeFormatPair
2196 {
2197     GLenum type;
2198     GLenum format;
2199 };
2200 
2201 template <typename CaseType>
addChildVariants(deqp::gles2::TestCaseGroup * group)2202 void addChildVariants(deqp::gles2::TestCaseGroup *group)
2203 {
2204     TypeFormatPair colorbufferConfigs[] = {
2205         //        { GL_TEXTURE_2D, GL_ALPHA },
2206         //        { GL_TEXTURE_2D, GL_LUMINANCE },
2207         //        { GL_TEXTURE_2D, GL_LUMINANCE_ALPHA },
2208         {GL_TEXTURE_2D, GL_RGB},       {GL_TEXTURE_2D, GL_RGBA},    {GL_RENDERBUFFER, GL_RGB565},
2209         {GL_RENDERBUFFER, GL_RGB5_A1}, {GL_RENDERBUFFER, GL_RGBA4},
2210         //        { GL_RENDERBUFFER, GL_RGBA16F },
2211         //        { GL_RENDERBUFFER, GL_RGB16F }
2212     };
2213     TypeFormatPair depthbufferConfigs[]   = {{GL_NONE, GL_NONE}, {GL_RENDERBUFFER, GL_DEPTH_COMPONENT16}};
2214     TypeFormatPair stencilbufferConfigs[] = {{GL_NONE, GL_NONE}, {GL_RENDERBUFFER, GL_STENCIL_INDEX8}};
2215 
2216     for (int colorbufferNdx = 0; colorbufferNdx < DE_LENGTH_OF_ARRAY(colorbufferConfigs); colorbufferNdx++)
2217         for (int depthbufferNdx = 0; depthbufferNdx < DE_LENGTH_OF_ARRAY(depthbufferConfigs); depthbufferNdx++)
2218             for (int stencilbufferNdx = 0; stencilbufferNdx < DE_LENGTH_OF_ARRAY(stencilbufferConfigs);
2219                  stencilbufferNdx++)
2220             {
2221                 FboConfig config;
2222                 config.colorbufferType     = colorbufferConfigs[colorbufferNdx].type;
2223                 config.colorbufferFormat   = colorbufferConfigs[colorbufferNdx].format;
2224                 config.depthbufferType     = depthbufferConfigs[depthbufferNdx].type;
2225                 config.depthbufferFormat   = depthbufferConfigs[depthbufferNdx].format;
2226                 config.stencilbufferType   = stencilbufferConfigs[stencilbufferNdx].type;
2227                 config.stencilbufferFormat = stencilbufferConfigs[stencilbufferNdx].format;
2228 
2229                 if (CaseType::isConfigSupported(config))
2230                     group->addChild(new CaseType(group->getContext(), config));
2231             }
2232 }
2233 
2234 template <typename CaseType>
createChildGroup(deqp::gles2::TestCaseGroup * parent,const char * name,const char * description)2235 void createChildGroup(deqp::gles2::TestCaseGroup *parent, const char *name, const char *description)
2236 {
2237     deqp::gles2::TestCaseGroup *tmpGroup = new deqp::gles2::TestCaseGroup(parent->getContext(), name, description);
2238     parent->addChild(tmpGroup);
2239     addChildVariants<CaseType>(tmpGroup);
2240 }
2241 
2242 template <GLbitfield Buffers>
createRecreateBuffersGroup(deqp::gles2::TestCaseGroup * parent,const char * name,const char * description)2243 void createRecreateBuffersGroup(deqp::gles2::TestCaseGroup *parent, const char *name, const char *description)
2244 {
2245     deqp::gles2::TestCaseGroup *tmpGroup = new deqp::gles2::TestCaseGroup(parent->getContext(), name, description);
2246     parent->addChild(tmpGroup);
2247     addChildVariants<FboCases::RecreateBuffersRebindTest<Buffers>>(tmpGroup);
2248     addChildVariants<FboCases::RecreateBuffersNoRebindTest<Buffers>>(tmpGroup);
2249 }
2250 
2251 } // namespace
2252 
init(void)2253 void FboRenderTestGroup::init(void)
2254 {
2255     createChildGroup<FboCases::ColorClearsTest>(this, "color_clear", "Color buffer clears");
2256     createChildGroup<FboCases::StencilClearsTest>(this, "stencil_clear", "Stencil buffer clears");
2257 
2258     deqp::gles2::TestCaseGroup *colorGroup = new deqp::gles2::TestCaseGroup(m_context, "color", "Color buffer tests");
2259     addChild(colorGroup);
2260     addChildVariants<FboCases::MixTest>(colorGroup);
2261     addChildVariants<FboCases::MixNpotTest>(colorGroup);
2262     addChildVariants<FboCases::BlendTest>(colorGroup);
2263     addChildVariants<FboCases::BlendNpotTest>(colorGroup);
2264 
2265     deqp::gles2::TestCaseGroup *depthGroup = new deqp::gles2::TestCaseGroup(m_context, "depth", "Depth bufer tests");
2266     addChild(depthGroup);
2267     addChildVariants<FboCases::IntersectingQuadsTest>(depthGroup);
2268     addChildVariants<FboCases::IntersectingQuadsNpotTest>(depthGroup);
2269 
2270     deqp::gles2::TestCaseGroup *stencilGroup =
2271         new deqp::gles2::TestCaseGroup(m_context, "stencil", "Stencil buffer tests");
2272     addChild(stencilGroup);
2273     addChildVariants<FboCases::StencilTest>(stencilGroup);
2274     addChildVariants<FboCases::StencilNpotTest>(stencilGroup);
2275 
2276     createChildGroup<FboCases::SharedColorbufferClearsTest>(this, "shared_colorbuffer_clear",
2277                                                             "Shared colorbuffer clears");
2278     createChildGroup<FboCases::SharedColorbufferTest>(this, "shared_colorbuffer", "Shared colorbuffer tests");
2279     createChildGroup<FboCases::SharedDepthbufferTest>(this, "shared_depthbuffer", "Shared depthbuffer tests");
2280     createChildGroup<FboCases::ResizeTest>(this, "resize", "FBO resize tests");
2281 
2282     createRecreateBuffersGroup<GL_COLOR_BUFFER_BIT>(this, "recreate_colorbuffer", "Recreate colorbuffer tests");
2283     createRecreateBuffersGroup<GL_DEPTH_BUFFER_BIT>(this, "recreate_depthbuffer", "Recreate depthbuffer tests");
2284     createRecreateBuffersGroup<GL_STENCIL_BUFFER_BIT>(this, "recreate_stencilbuffer", "Recreate stencilbuffer tests");
2285 
2286     deqp::gles2::TestCaseGroup *texSubImageGroup =
2287         new deqp::gles2::TestCaseGroup(m_context, "texsubimage", "TexSubImage interop with FBO colorbuffer texture");
2288     addChild(texSubImageGroup);
2289     addChildVariants<FboCases::TexSubImageAfterRenderTest>(texSubImageGroup);
2290     addChildVariants<FboCases::TexSubImageBetweenRenderTest>(texSubImageGroup);
2291 
2292     {
2293         tcu::TestCaseGroup *const repeatedClearGroup =
2294             new tcu::TestCaseGroup(m_testCtx, "repeated_clear", "Repeated FBO clears");
2295         addChild(repeatedClearGroup);
2296 
2297         repeatedClearGroup->addChild(new FboCases::RepeatedClearCase(m_context, GL_RGB));
2298         repeatedClearGroup->addChild(new FboCases::RepeatedClearCase(m_context, GL_RGBA));
2299     }
2300 }
2301 
2302 } // namespace Functional
2303 } // namespace gles2
2304 } // namespace deqp
2305