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