Add new compute negative coverage tests am: db4a886f3f
[platform/upstream/VK-GL-CTS.git] / modules / gles2 / stress / es2sSpecialFloatTests.cpp
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 Special float stress tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es2sSpecialFloatTests.hpp"
25 #include "gluRenderContext.hpp"
26 #include "gluShaderProgram.hpp"
27 #include "gluPixelTransfer.hpp"
28 #include "gluStrUtil.hpp"
29 #include "gluContextInfo.hpp"
30 #include "glwEnums.hpp"
31 #include "glwFunctions.hpp"
32 #include "tcuRenderTarget.hpp"
33 #include "tcuSurface.hpp"
34 #include "tcuTestLog.hpp"
35 #include "tcuVectorUtil.hpp"
36 #include "deStringUtil.hpp"
37 #include "deMath.h"
38 #include "deRandom.hpp"
39
40 #include <limits>
41 #include <sstream>
42
43 using namespace glw;
44
45 namespace deqp
46 {
47 namespace gles2
48 {
49 namespace Stress
50 {
51 namespace
52 {
53
54 static const int                TEST_CANVAS_SIZE                = 256;
55 static const int                TEST_TEXTURE_SIZE               = 128;
56 static const int                TEST_TEXTURE_CUBE_SIZE  = 32;
57 static const deUint32   s_specialFloats[]               =
58 {
59         0x00000000,     //          zero
60         0x80000000,     // negative zero
61         0x3F800000,     //          one
62         0xBF800000,     // negative one
63         0x00800000,     // minimum positive normalized value
64         0x80800000,     // maximum negative normalized value
65         0x00000001,     // minimum positive denorm value
66         0x80000001,     // maximum negative denorm value
67         0x7F7FFFFF,     // maximum finite value.
68         0xFF7FFFFF,     // minimum finite value.
69         0x7F800000,     //  inf
70         0xFF800000,     // -inf
71         0x34000000,     //          epsilon
72         0xB4000000,     // negative epsilon
73         0x7FC00000,     //          quiet_NaN
74         0xFFC00000,     // negative quiet_NaN
75         0x7FC00001,     //          signaling_NaN
76         0xFFC00001,     // negative signaling_NaN
77         0x7FEAAAAA,     //          quiet payloaded NaN         (payload of repeated pattern of 101010...)
78         0xFFEAAAAA,     // negative quiet payloaded NaN         ( .. )
79         0x7FAAAAAA,     //          signaling payloaded NaN     ( .. )
80         0xFFAAAAAA,     // negative signaling payloaded NaN     ( .. )
81 };
82
83 static const char* const s_colorPassthroughFragmentShaderSource =       "varying mediump vec4 v_out;\n"
84                                                                                                                                         "void main ()\n"
85                                                                                                                                         "{\n"
86                                                                                                                                         "       gl_FragColor = v_out;\n"
87                                                                                                                                         "}\n";
88 static const char* const s_attrPassthroughVertexShaderSource    =       "attribute highp vec4 a_pos;\n"
89                                                                                                                                         "attribute highp vec4 a_attr;\n"
90                                                                                                                                         "varying mediump vec4 v_attr;\n"
91                                                                                                                                         "void main ()\n"
92                                                                                                                                         "{\n"
93                                                                                                                                         "       v_attr = a_attr;\n"
94                                                                                                                                         "       gl_Position = a_pos;\n"
95                                                                                                                                         "}\n";
96
97 class RenderCase : public TestCase
98 {
99 public:
100         enum RenderTargetType
101         {
102                 RENDERTARGETTYPE_SCREEN,
103                 RENDERTARGETTYPE_FBO
104         };
105
106                                                                 RenderCase                      (Context& context, const char* name, const char* desc, RenderTargetType renderTargetType = RENDERTARGETTYPE_SCREEN);
107         virtual                                         ~RenderCase                     (void);
108
109         virtual void                            init                            (void);
110         virtual void                            deinit                          (void);
111
112 protected:
113         bool                                            checkResultImage        (const tcu::Surface& result);
114         bool                                            drawTestPattern         (bool useTexture);
115
116         virtual std::string                     genVertexSource         (void) const = 0;
117         virtual std::string                     genFragmentSource       (void) const = 0;
118
119         const glu::ShaderProgram*       m_program;
120         const RenderTargetType          m_renderTargetType;
121 };
122
123 RenderCase::RenderCase (Context& context, const char* name, const char* desc, RenderTargetType renderTargetType)
124         : TestCase                              (context, name, desc)
125         , m_program                             (DE_NULL)
126         , m_renderTargetType    (renderTargetType)
127 {
128 }
129
130 RenderCase::~RenderCase (void)
131 {
132         deinit();
133 }
134
135 void RenderCase::init (void)
136 {
137         const int width  = m_context.getRenderTarget().getWidth();
138         const int height = m_context.getRenderTarget().getHeight();
139
140         // check target size
141         if (m_renderTargetType == RENDERTARGETTYPE_SCREEN)
142         {
143                 if (width < TEST_CANVAS_SIZE || height < TEST_CANVAS_SIZE)
144                         throw tcu::NotSupportedError(std::string("Render target size must be at least ") + de::toString(TEST_CANVAS_SIZE) + "x" + de::toString(TEST_CANVAS_SIZE));
145         }
146         else if (m_renderTargetType == RENDERTARGETTYPE_FBO)
147         {
148                 GLint maxTexSize = 0;
149                 m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
150
151                 if (maxTexSize < TEST_CANVAS_SIZE)
152                         throw tcu::NotSupportedError(std::string("GL_MAX_TEXTURE_SIZE must be at least ") + de::toString(TEST_CANVAS_SIZE));
153         }
154         else
155                 DE_ASSERT(false);
156
157         // gen shader
158
159         m_testCtx.getLog() << tcu::TestLog::Message << "Creating test shader." << tcu::TestLog::EndMessage;
160
161         m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(genVertexSource()) << glu::FragmentSource(genFragmentSource()));
162         m_testCtx.getLog() << *m_program;
163
164         if (!m_program->isOk())
165                 throw tcu::TestError("shader compile failed");
166 }
167
168 void RenderCase::deinit (void)
169 {
170         if (m_program)
171         {
172                 delete m_program;
173                 m_program = DE_NULL;
174         }
175 }
176
177 bool RenderCase::checkResultImage (const tcu::Surface& result)
178 {
179         tcu::Surface    errorMask       (TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
180         bool                    error           = false;
181
182         m_testCtx.getLog() << tcu::TestLog::Message << "Verifying output image." << tcu::TestLog::EndMessage;
183
184         for (int y = 0; y < TEST_CANVAS_SIZE; ++y)
185         for (int x = 0; x < TEST_CANVAS_SIZE; ++x)
186         {
187                 const tcu::RGBA col = result.getPixel(x, y);
188
189                 if (col.getGreen() == 255)
190                         errorMask.setPixel(x, y, tcu::RGBA::green());
191                 else
192                 {
193                         errorMask.setPixel(x, y, tcu::RGBA::red());
194                         error = true;
195                 }
196         }
197
198         if (error)
199         {
200                 m_testCtx.getLog() << tcu::TestLog::Message << "Result image has missing or invalid pixels" << tcu::TestLog::EndMessage;
201                 m_testCtx.getLog()
202                         << tcu::TestLog::ImageSet("Results", "Result verification")
203                         << tcu::TestLog::Image("Result",                "Result",               result)
204                         << tcu::TestLog::Image("Error mask",    "Error mask",   errorMask)
205                         << tcu::TestLog::EndImageSet;
206         }
207         else
208         {
209                 m_testCtx.getLog()
210                         << tcu::TestLog::ImageSet("Results", "Result verification")
211                         << tcu::TestLog::Image("Result", "Result", result)
212                         << tcu::TestLog::EndImageSet;
213         }
214
215         return !error;
216 }
217
218 bool RenderCase::drawTestPattern (bool useTexture)
219 {
220         static const tcu::Vec4 fullscreenQuad[4] =
221         {
222                 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
223                 tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
224                 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
225                 tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f),
226         };
227         const char* const       vertexSource            =       "attribute highp vec4 a_pos;\n"
228                                                                                                 "varying mediump vec4 v_position;\n"
229                                                                                                 "void main ()\n"
230                                                                                                 "{\n"
231                                                                                                 "       v_position = a_pos;\n"
232                                                                                                 "       gl_Position = a_pos;\n"
233                                                                                                 "}\n";
234         const char* const       fragmentSourceNoTex     =       "varying mediump vec4 v_position;\n"
235                                                                                                 "void main ()\n"
236                                                                                                 "{\n"
237                                                                                                 "       gl_FragColor = vec4((v_position.x + 1.0) * 0.5, 1.0, 1.0, 1.0);\n"
238                                                                                                 "}\n";
239         const char* const       fragmentSourceTex       =       "uniform mediump sampler2D u_sampler;\n"
240                                                                                                 "varying mediump vec4 v_position;\n"
241                                                                                                 "void main ()\n"
242                                                                                                 "{\n"
243                                                                                                 "       gl_FragColor = texture2D(u_sampler, v_position.xy);\n"
244                                                                                                 "}\n";
245         const char* const       fragmentSource          =       (useTexture) ? (fragmentSourceTex) : (fragmentSourceNoTex);
246         const tcu::RGBA         formatThreshold         = m_context.getRenderTarget().getPixelFormat().getColorThreshold();
247
248         tcu::Surface            resultImage                     (TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
249         tcu::Surface            errorMask                       (TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
250         bool                            error                           =       false;
251
252         m_testCtx.getLog() << tcu::TestLog::Message << "Drawing a test pattern to detect " << ((useTexture) ? ("texture sampling") : ("")) << " side-effects." << tcu::TestLog::EndMessage;
253
254         // draw pattern
255         {
256                 const glw::Functions&           gl                              = m_context.getRenderContext().getFunctions();
257                 const glu::ShaderProgram        patternProgram  (m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vertexSource) << glu::FragmentSource(fragmentSource));
258                 const GLint                                     positionLoc             = gl.getAttribLocation(patternProgram.getProgram(), "a_pos");
259                 GLuint                                          textureID               = 0;
260
261                 if (useTexture)
262                 {
263                         const int textureSize = 32;
264                         std::vector<tcu::Vector<deUint8, 4> > buffer(textureSize*textureSize);
265
266                         for (int x = 0; x < textureSize; ++x)
267                         for (int y = 0; y < textureSize; ++y)
268                         {
269                                 // sum of two axis aligned gradients. Each gradient is 127 at the edges and 0 at the center.
270                                 // pattern is symmetric (x and y) => no discontinuity near boundary => no need to worry of results with LINEAR filtering near boundaries
271                                 const deUint8 redComponent = (deUint8)de::clamp(de::abs((float)x / (float)textureSize - 0.5f) * 255.0f + de::abs((float)y / (float)textureSize - 0.5f) * 255.0f, 0.0f, 255.0f);
272
273                                 buffer[x * textureSize + y] = tcu::Vector<deUint8, 4>(redComponent, 255, 255, 255);
274                         }
275
276                         gl.genTextures(1, &textureID);
277                         gl.bindTexture(GL_TEXTURE_2D, textureID);
278                         gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureSize, textureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer[0].getPtr());
279                         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
280                         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
281                 }
282
283                 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
284                 gl.clear(GL_COLOR_BUFFER_BIT);
285                 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
286                 gl.useProgram(patternProgram.getProgram());
287
288                 if (useTexture)
289                         gl.uniform1i(gl.getUniformLocation(patternProgram.getProgram(), "u_sampler"), 0);
290
291                 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &fullscreenQuad[0]);
292
293                 gl.enableVertexAttribArray(positionLoc);
294                 gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
295                 gl.disableVertexAttribArray(positionLoc);
296
297                 gl.useProgram(0);
298                 gl.finish();
299                 GLU_EXPECT_NO_ERROR(gl.getError(), "RenderCase::drawTestPattern");
300
301                 if (textureID)
302                         gl.deleteTextures(1, &textureID);
303
304                 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
305         }
306
307         // verify pattern
308         for (int y = 0; y < TEST_CANVAS_SIZE; ++y)
309         for (int x = 0; x < TEST_CANVAS_SIZE; ++x)
310         {
311                 const float                     texGradientPosX = deFloatFrac((float)x * 2.0f / (float)TEST_CANVAS_SIZE);
312                 const float                     texGradientPosY = deFloatFrac((float)y * 2.0f / (float)TEST_CANVAS_SIZE);
313                 const deUint8           texRedComponent = (deUint8)de::clamp(de::abs(texGradientPosX - 0.5f) * 255.0f + de::abs(texGradientPosY - 0.5f) * 255.0f, 0.0f, 255.0f);
314
315                 const tcu::RGBA         refColTexture   = tcu::RGBA(texRedComponent, 255, 255, 255);
316                 const tcu::RGBA         refColGradient  = tcu::RGBA((int)((float)x / (float)TEST_CANVAS_SIZE * 255.0f), 255, 255, 255);
317                 const tcu::RGBA&        refCol                  = (useTexture) ? (refColTexture) : (refColGradient);
318
319                 const int                       colorThreshold  = 10;
320                 const tcu::RGBA         col                             = resultImage.getPixel(x, y);
321                 const tcu::IVec4        colorDiff               = tcu::abs(col.toIVec() - refCol.toIVec());
322
323                 if (colorDiff.x() > formatThreshold.getRed()   + colorThreshold ||
324                         colorDiff.y() > formatThreshold.getGreen() + colorThreshold ||
325                         colorDiff.z() > formatThreshold.getBlue()  + colorThreshold)
326                 {
327                         errorMask.setPixel(x, y, tcu::RGBA::red());
328                         error = true;
329                 }
330                 else
331                         errorMask.setPixel(x, y, tcu::RGBA::green());
332         }
333
334         // report error
335         if (error)
336         {
337                 m_testCtx.getLog() << tcu::TestLog::Message << "Test pattern has missing/invalid pixels" << tcu::TestLog::EndMessage;
338                 m_testCtx.getLog()
339                         << tcu::TestLog::ImageSet("Results", "Result verification")
340                         << tcu::TestLog::Image("Result",                "Result",               resultImage)
341                         << tcu::TestLog::Image("Error mask",    "Error mask",   errorMask)
342                         << tcu::TestLog::EndImageSet;
343         }
344         else
345                 m_testCtx.getLog() << tcu::TestLog::Message << "No side-effects found." << tcu::TestLog::EndMessage;
346
347         return !error;
348 }
349
350 class FramebufferRenderCase : public RenderCase
351 {
352 public:
353         enum FrameBufferType
354         {
355                 FBO_DEFAULT = 0,
356                 FBO_RGBA,
357                 FBO_RGBA4,
358                 FBO_RGB5_A1,
359                 FBO_RGB565,
360                 FBO_RGBA_FLOAT16,
361
362                 FBO_LAST
363         };
364
365                                                         FramebufferRenderCase   (Context& context, const char* name, const char* desc, FrameBufferType fboType);
366         virtual                                 ~FramebufferRenderCase  (void);
367
368         virtual void                    init                                    (void);
369         virtual void                    deinit                                  (void);
370         IterateResult                   iterate                                 (void);
371
372         virtual void                    testFBO                                 (void) = DE_NULL;
373
374 protected:
375         const FrameBufferType   m_fboType;
376
377 private:
378         GLuint                                  m_texID;
379         GLuint                                  m_fboID;
380 };
381
382 FramebufferRenderCase::FramebufferRenderCase (Context& context, const char* name, const char* desc, FrameBufferType fboType)
383         : RenderCase    (context, name, desc, (fboType == FBO_DEFAULT) ? (RENDERTARGETTYPE_SCREEN) : (RENDERTARGETTYPE_FBO))
384         , m_fboType             (fboType)
385         , m_texID               (0)
386         , m_fboID               (0)
387 {
388         DE_ASSERT(m_fboType < FBO_LAST);
389 }
390
391 FramebufferRenderCase::~FramebufferRenderCase (void)
392 {
393         deinit();
394 }
395
396 void FramebufferRenderCase::init (void)
397 {
398         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
399
400         // check requirements
401         if (m_fboType == FBO_RGBA_FLOAT16)
402         {
403                 // half float texture is allowed (OES_texture_half_float) and it is color renderable (EXT_color_buffer_half_float)
404                 if (!m_context.getContextInfo().isExtensionSupported("GL_OES_texture_half_float") ||
405                         !m_context.getContextInfo().isExtensionSupported("GL_EXT_color_buffer_half_float"))
406                         throw tcu::NotSupportedError("Color renderable half float texture required.");
407         }
408
409         // gen shader
410         RenderCase::init();
411
412         // create render target
413         if (m_fboType == FBO_DEFAULT)
414         {
415                 m_testCtx.getLog() << tcu::TestLog::Message << "Using default framebuffer." << tcu::TestLog::EndMessage;
416         }
417         else
418         {
419                 GLuint internalFormat   = 0;
420                 GLuint format                   = 0;
421                 GLuint type                             = 0;
422
423 #if !defined(GL_HALF_FLOAT_OES)
424 #       define  GL_HALF_FLOAT_OES 0x8D61
425 #endif
426
427                 switch (m_fboType)
428                 {
429                         case FBO_RGBA:                  internalFormat = GL_RGBA;       format = GL_RGBA;       type = GL_UNSIGNED_BYTE;                                break;
430                         case FBO_RGBA4:                 internalFormat = GL_RGBA;       format = GL_RGBA;       type = GL_UNSIGNED_SHORT_4_4_4_4;               break;
431                         case FBO_RGB5_A1:               internalFormat = GL_RGBA;       format = GL_RGBA;       type = GL_UNSIGNED_SHORT_5_5_5_1;               break;
432                         case FBO_RGB565:                internalFormat = GL_RGB;        format = GL_RGB;        type = GL_UNSIGNED_SHORT_5_6_5;                 break;
433                         case FBO_RGBA_FLOAT16:  internalFormat = GL_RGBA;       format = GL_RGBA;       type = GL_HALF_FLOAT_OES;                               break;
434
435                         default:
436                                 DE_ASSERT(false);
437                                 break;
438                 }
439
440                 m_testCtx.getLog() << tcu::TestLog::Message
441                         << "Creating fbo. Texture internalFormat = " << glu::getTextureFormatStr(internalFormat)
442                         << ", format = " << glu::getTextureFormatStr(format)
443                         << ", type = " << glu::getTypeStr(type)
444                         << tcu::TestLog::EndMessage;
445
446                 // gen texture
447                 gl.genTextures(1, &m_texID);
448                 gl.bindTexture(GL_TEXTURE_2D, m_texID);
449                 gl.texImage2D(GL_TEXTURE_2D, 0, internalFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE, 0, format, type, DE_NULL);
450                 GLU_EXPECT_NO_ERROR(gl.getError(), "texture init");
451
452                 // gen fbo
453                 gl.genFramebuffers(1, &m_fboID);
454                 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
455                 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texID, 0);
456                 GLU_EXPECT_NO_ERROR(gl.getError(), "fbo init");
457
458                 if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
459                         throw tcu::NotSupportedError("could not create fbo for testing.");
460         }
461 }
462
463 void FramebufferRenderCase::deinit (void)
464 {
465         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
466
467         if (m_texID)
468         {
469                 gl.deleteTextures(1, &m_texID);
470                 m_texID = 0;
471         }
472
473         if (m_fboID)
474         {
475                 gl.deleteFramebuffers(1, &m_fboID);
476                 m_fboID = 0;
477         }
478 }
479
480 FramebufferRenderCase::IterateResult FramebufferRenderCase::iterate (void)
481 {
482         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
483
484         // bind fbo (or don't if we are using default)
485         if (m_fboID)
486                 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
487
488         // do something with special floats
489         testFBO();
490
491         return STOP;
492 }
493
494 /*--------------------------------------------------------------------*//*!
495  * \brief Tests special floats as vertex attributes
496  *
497  * Tests that special floats transferred to the shader using vertex
498  * attributes do not change the results of normal floating point
499  * calculations. Special floats are put to 4-vector's x and y components and
500  * value 1.0 is put to z and w. The resulting fragment's green channel
501  * should be 1.0 everywhere.
502  *
503  * After the calculation test a test pattern is drawn to detect possible
504  * floating point operation anomalies.
505  *//*--------------------------------------------------------------------*/
506 class VertexAttributeCase : public RenderCase
507 {
508 public:
509         enum Storage
510         {
511                 STORAGE_BUFFER = 0,
512                 STORAGE_CLIENT,
513
514                 STORAGE_LAST
515         };
516         enum ShaderType
517         {
518                 TYPE_VERTEX = 0,
519                 TYPE_FRAGMENT,
520
521                 TYPE_LAST
522         };
523
524                                                 VertexAttributeCase                     (Context& context, const char* name, const char* desc, Storage storage, ShaderType type);
525                                                 ~VertexAttributeCase            (void);
526
527         void                            init                                            (void);
528         void                            deinit                                          (void);
529         IterateResult           iterate                                         (void);
530
531 private:
532         std::string                     genVertexSource                         (void) const;
533         std::string                     genFragmentSource                       (void) const;
534
535         const Storage           m_storage;
536         const ShaderType        m_type;
537         GLuint                          m_positionVboID;
538         GLuint                          m_attribVboID;
539         GLuint                          m_elementVboID;
540 };
541
542 VertexAttributeCase::VertexAttributeCase (Context& context, const char* name, const char* desc, Storage storage, ShaderType type)
543         : RenderCase                    (context, name, desc)
544         , m_storage                             (storage)
545         , m_type                                (type)
546         , m_positionVboID               (0)
547         , m_attribVboID                 (0)
548         , m_elementVboID                (0)
549 {
550         DE_ASSERT(storage < STORAGE_LAST);
551         DE_ASSERT(type < TYPE_LAST);
552 }
553
554 VertexAttributeCase::~VertexAttributeCase (void)
555 {
556         deinit();
557 }
558
559 void VertexAttributeCase::init (void)
560 {
561         RenderCase::init();
562
563         // init gl resources
564         if (m_storage == STORAGE_BUFFER)
565         {
566                 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
567
568                 gl.genBuffers(1, &m_positionVboID);
569                 gl.genBuffers(1, &m_attribVboID);
570                 gl.genBuffers(1, &m_elementVboID);
571         }
572 }
573
574 void VertexAttributeCase::deinit (void)
575 {
576         const glw::Functions& gl = m_context.getRenderContext().getFunctions();
577
578         RenderCase::deinit();
579
580         if (m_attribVboID)
581         {
582                 gl.deleteBuffers(1, &m_attribVboID);
583                 m_attribVboID = 0;
584         }
585
586         if (m_positionVboID)
587         {
588                 gl.deleteBuffers(1, &m_positionVboID);
589                 m_positionVboID = 0;
590         }
591
592         if (m_elementVboID)
593         {
594                 gl.deleteBuffers(1, &m_elementVboID);
595                 m_elementVboID = 0;
596         }
597 }
598
599 VertexAttributeCase::IterateResult VertexAttributeCase::iterate (void)
600 {
601         // Create a [s_specialFloats] X [s_specialFloats] grid of vertices with each vertex having 2 [s_specialFloats] values
602         // and calculate some basic operations with the floating point values. If all goes well, nothing special should happen
603
604         std::vector<tcu::Vec4>  gridVertices    (DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
605         std::vector<tcu::UVec4> gridAttributes  (DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
606         std::vector<deUint16>   indices                 ((DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * 6);
607         tcu::Surface                    resultImage             (TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
608
609         // vertices
610         for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
611         for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
612         {
613                 const deUint32  one             = 0x3F800000;
614                 const float             posX    = (float)x / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f; // map from [0, len(s_specialFloats) - 1] to [-1, 1]
615                 const float             posY    = (float)y / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f;
616
617                 gridVertices[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y]       = tcu::Vec4(posX, posY, 0.0f, 1.0f);
618                 gridAttributes[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y]     = tcu::UVec4(s_specialFloats[x], s_specialFloats[y], one, one);
619         }
620
621         // tiles
622         for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++x)
623         for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++y)
624         {
625                 const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) + y) * 6;
626
627                 indices[baseNdx + 0] = (deUint16)((x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0));
628                 indices[baseNdx + 1] = (deUint16)((x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1));
629                 indices[baseNdx + 2] = (deUint16)((x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0));
630
631                 indices[baseNdx + 3] = (deUint16)((x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0));
632                 indices[baseNdx + 4] = (deUint16)((x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1));
633                 indices[baseNdx + 5] = (deUint16)((x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1));
634         }
635
636         m_testCtx.getLog() << tcu::TestLog::Message << "Drawing a grid with the shader. Setting a_attr for each vertex to (special, special, 1, 1)." << tcu::TestLog::EndMessage;
637
638         // Draw grid
639         {
640                 const glw::Functions&   gl                      = m_context.getRenderContext().getFunctions();
641                 const GLint                             positionLoc     = gl.getAttribLocation(m_program->getProgram(), "a_pos");
642                 const GLint                             attribLoc       = gl.getAttribLocation(m_program->getProgram(), "a_attr");
643
644                 if (m_storage == STORAGE_BUFFER)
645                 {
646                         gl.bindBuffer(GL_ARRAY_BUFFER, m_positionVboID);
647                         gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(gridVertices.size() * sizeof(tcu::Vec4)), &gridVertices[0], GL_STATIC_DRAW);
648                         GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
649
650                         gl.bindBuffer(GL_ARRAY_BUFFER, m_attribVboID);
651                         gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(gridAttributes.size() * sizeof(tcu::UVec4)), &gridAttributes[0], GL_STATIC_DRAW);
652                         GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
653
654                         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementVboID);
655                         gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(indices.size() * sizeof(deUint16)), &indices[0], GL_STATIC_DRAW);
656                         GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
657                 }
658
659                 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
660                 gl.clear(GL_COLOR_BUFFER_BIT);
661                 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
662                 gl.useProgram(m_program->getProgram());
663
664                 if (m_storage == STORAGE_BUFFER)
665                 {
666                         gl.bindBuffer(GL_ARRAY_BUFFER, m_positionVboID);
667                         gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
668
669                         gl.bindBuffer(GL_ARRAY_BUFFER, m_attribVboID);
670                         gl.vertexAttribPointer(attribLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
671
672                         gl.enableVertexAttribArray(positionLoc);
673                         gl.enableVertexAttribArray(attribLoc);
674                         gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, DE_NULL);
675                         gl.disableVertexAttribArray(positionLoc);
676                         gl.disableVertexAttribArray(attribLoc);
677
678                         gl.bindBuffer(GL_ARRAY_BUFFER, 0);
679                         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
680                 }
681                 else if (m_storage == STORAGE_CLIENT)
682                 {
683                         gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
684                         gl.vertexAttribPointer(attribLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridAttributes[0]);
685
686                         gl.enableVertexAttribArray(positionLoc);
687                         gl.enableVertexAttribArray(attribLoc);
688                         gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, &indices[0]);
689                         gl.disableVertexAttribArray(positionLoc);
690                         gl.disableVertexAttribArray(attribLoc);
691                 }
692                 else
693                         DE_ASSERT(false);
694
695                 gl.useProgram(0);
696                 gl.finish();
697                 GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
698
699                 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
700         }
701
702         // verify everywhere was drawn (all pixels have Green = 255)
703         if (!checkResultImage(resultImage))
704         {
705                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments");
706                 return STOP;
707         }
708
709         // test drawing still works
710         if (!drawTestPattern(false))
711         {
712                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed");
713                 return STOP;
714         }
715
716         // all ok
717         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
718         return STOP;
719 }
720
721 std::string VertexAttributeCase::genVertexSource (void) const
722 {
723         if (m_type == TYPE_VERTEX)
724                 return
725                         "attribute highp vec4 a_pos;\n"
726                         "attribute highp vec4 a_attr;\n"
727                         "varying mediump vec4 v_out;\n"
728                         "void main ()\n"
729                         "{\n"
730                         "       highp vec2 a1 = a_attr.xz + a_attr.yw; // add\n"
731                         "       highp vec2 a2 = a_attr.xz - a_attr.yw; // sub\n"
732                         "       highp vec2 a3 = a_attr.xz * a_attr.yw; // mul\n"
733                         "       highp vec2 a4 = a_attr.xz / a_attr.yw; // div\n"
734                         "       highp vec2 a5 = a_attr.xz + a_attr.yw * a_attr.xz; // fma\n"
735                         "\n"
736                         "       highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y) - 6.0);\n"
737                         "       v_out = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x, 1.0);\n"
738                         "       gl_Position = a_pos;\n"
739                         "}\n";
740         else
741                 return s_attrPassthroughVertexShaderSource;
742 }
743
744 std::string VertexAttributeCase::genFragmentSource (void) const
745 {
746         if (m_type == TYPE_VERTEX)
747                 return s_colorPassthroughFragmentShaderSource;
748         else
749                 return
750                         "varying mediump vec4 v_attr;\n"
751                         "void main ()\n"
752                         "{\n"
753                         "       mediump vec2 a1 = v_attr.xz + v_attr.yw; // add\n"
754                         "       mediump vec2 a2 = v_attr.xz - v_attr.yw; // sub\n"
755                         "       mediump vec2 a3 = v_attr.xz * v_attr.yw; // mul\n"
756                         "       mediump vec2 a4 = v_attr.xz / v_attr.yw; // div\n"
757                         "       mediump vec2 a5 = v_attr.xz + v_attr.yw * v_attr.xz; // fma\n"
758                         "\n"
759                         "       const mediump float epsilon = 0.1; // allow small differences. To results to be wrong they must be more wrong than that.\n"
760                         "       mediump float green = 1.0 + epsilon - abs((a1.y + a2.y + a3.y + a4.y + a5.y) - 6.0);\n"
761                         "       gl_FragColor = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x, 1.0);\n"
762                         "}\n";
763 }
764
765 /*--------------------------------------------------------------------*//*!
766  * \brief Tests special floats as uniforms
767  *
768  * Tests that special floats transferred to the shader as uniforms do
769  * not change the results of normal floating point calculations. Special
770  * floats are put to 4-vector's x and y components and value 1.0 is put to
771  * z and w. The resulting fragment's green channel should be 1.0
772  * everywhere.
773  *
774  * After the calculation test a test pattern is drawn to detect possible
775  * floating point operation anomalies.
776  *//*--------------------------------------------------------------------*/
777 class UniformCase : public RenderCase
778 {
779 public:
780         enum ShaderType
781         {
782                 TYPE_VERTEX = 0,
783                 TYPE_FRAGMENT,
784         };
785
786                                                 UniformCase                                     (Context& context, const char* name, const char* desc, ShaderType type);
787                                                 ~UniformCase                            (void);
788
789         void                            init                                            (void);
790         void                            deinit                                          (void);
791         IterateResult           iterate                                         (void);
792
793 private:
794         std::string                     genVertexSource                         (void) const;
795         std::string                     genFragmentSource                       (void) const;
796
797         const ShaderType        m_type;
798 };
799
800 UniformCase::UniformCase (Context& context, const char* name, const char* desc, ShaderType type)
801         : RenderCase    (context, name, desc)
802         , m_type                (type)
803 {
804 }
805
806 UniformCase::~UniformCase (void)
807 {
808         deinit();
809 }
810
811 void UniformCase::init (void)
812 {
813         RenderCase::init();
814 }
815
816 void UniformCase::deinit (void)
817 {
818         RenderCase::deinit();
819 }
820
821 UniformCase::IterateResult UniformCase::iterate (void)
822 {
823         // Create a [s_specialFloats] X [s_specialFloats] grid of tile with each tile having 2 [s_specialFloats] values
824         // and calculate some basic operations with the floating point values. If all goes well, nothing special should happen
825
826         std::vector<tcu::Vec4>  gridVertices    ((DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1));
827         std::vector<deUint16>   indices                 (DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats) * 6);
828         tcu::Surface                    resultImage             (TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
829
830         // vertices
831         for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++x)
832         for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++y)
833         {
834                 const float             posX    = (float)x / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f - 1.0f; // map from [0, len(s_specialFloats) ] to [-1, 1]
835                 const float             posY    = (float)y / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f - 1.0f;
836
837                 gridVertices[x * (DE_LENGTH_OF_ARRAY(s_specialFloats)+1) + y] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
838         }
839
840         // tiles
841         for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
842         for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
843         {
844                 const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats)) + y) * 6;
845
846                 indices[baseNdx + 0] = (deUint16)((x+0) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+0));
847                 indices[baseNdx + 1] = (deUint16)((x+1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+1));
848                 indices[baseNdx + 2] = (deUint16)((x+1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+0));
849
850                 indices[baseNdx + 3] = (deUint16)((x+0) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+0));
851                 indices[baseNdx + 4] = (deUint16)((x+1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+1));
852                 indices[baseNdx + 5] = (deUint16)((x+0) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y+1));
853         }
854
855         m_testCtx.getLog() << tcu::TestLog::Message << "Drawing a grid with the shader. Setting u_special for vertex each tile to (special, special, 1, 1)." << tcu::TestLog::EndMessage;
856
857         // Draw grid
858         {
859                 const glw::Functions&   gl                      = m_context.getRenderContext().getFunctions();
860                 const GLint                             positionLoc     = gl.getAttribLocation(m_program->getProgram(), "a_pos");
861                 const GLint                             specialLoc      = gl.getUniformLocation(m_program->getProgram(), "u_special");
862
863                 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
864                 gl.clear(GL_COLOR_BUFFER_BIT);
865                 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
866                 gl.useProgram(m_program->getProgram());
867
868                 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
869                 gl.enableVertexAttribArray(positionLoc);
870
871                 for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
872                 for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
873                 {
874                         const deUint32          one                             = 0x3F800000;
875                         const tcu::UVec4        uniformValue    = tcu::UVec4(s_specialFloats[x], s_specialFloats[y], one, one);
876                         const int                       indexIndex              = (x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y) * 6;
877
878                         gl.uniform4fv(specialLoc, 1, (const float*)uniformValue.getPtr());
879                         gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[indexIndex]);
880                 }
881
882                 gl.disableVertexAttribArray(positionLoc);
883
884                 gl.useProgram(0);
885                 gl.finish();
886                 GLU_EXPECT_NO_ERROR(gl.getError(), "UniformCase::iterate");
887
888                 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
889         }
890
891         // verify everywhere was drawn (all pixels have Green = 255)
892         if (!checkResultImage(resultImage))
893         {
894                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments");
895                 return STOP;
896         }
897
898         // test drawing still works
899         if (!drawTestPattern(false))
900         {
901                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed");
902                 return STOP;
903         }
904
905         // all ok
906         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
907         return STOP;
908 }
909
910 std::string UniformCase::genVertexSource (void) const
911 {
912         if (m_type == TYPE_VERTEX)
913                 return
914                         "attribute highp vec4 a_pos;\n"
915                         "uniform highp vec4 u_special;\n"
916                         "varying mediump vec4 v_out;\n"
917                         "void main ()\n"
918                         "{\n"
919                         "       highp vec2 a1 = u_special.xz + u_special.yw; // add\n"
920                         "       highp vec2 a2 = u_special.xz - u_special.yw; // sub\n"
921                         "       highp vec2 a3 = u_special.xz * u_special.yw; // mul\n"
922                         "       highp vec2 a4 = u_special.xz / u_special.yw; // div\n"
923                         "       highp vec2 a5 = u_special.xz + u_special.yw * u_special.xz; // fma\n"
924                         "\n"
925                         "       highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y) - 6.0);\n"
926                         "       v_out = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x, 1.0);\n"
927                         "       gl_Position = a_pos;\n"
928                         "}\n";
929         else
930                 return
931                         "attribute highp vec4 a_pos;\n"
932                         "void main ()\n"
933                         "{\n"
934                         "       gl_Position = a_pos;\n"
935                         "}\n";
936 }
937
938 std::string UniformCase::genFragmentSource (void) const
939 {
940         if (m_type == TYPE_VERTEX)
941                 return s_colorPassthroughFragmentShaderSource;
942         else
943                 return
944                         "uniform mediump vec4 u_special;\n"
945                         "void main ()\n"
946                         "{\n"
947                         "       mediump vec2 a1 = u_special.xz + u_special.yw; // add\n"
948                         "       mediump vec2 a2 = u_special.xz - u_special.yw; // sub\n"
949                         "       mediump vec2 a3 = u_special.xz * u_special.yw; // mul\n"
950                         "       mediump vec2 a4 = u_special.xz / u_special.yw; // div\n"
951                         "       mediump vec2 a5 = u_special.xz + u_special.yw * u_special.xz; // fma\n"
952                         "       mediump vec2 a6 = mod(u_special.xz, u_special.yw);\n"
953                         "       mediump vec2 a7 = mix(u_special.xz, u_special.yw, a6);\n"
954                         "\n"
955                         "       mediump float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y + a6.y + a7.y) - 7.0);\n"
956                         "       gl_FragColor = vec4(a1.x*a3.x, green, a5.x*a4.x + a2.x*a7.x, 1.0);\n"
957                         "}\n";
958 }
959
960 /*--------------------------------------------------------------------*//*!
961  * \brief Tests special floats as texture samping arguments
962  *
963  * Tests that special floats given as texture coordinates or LOD levels
964  * to sampling functions do not return invalid values (values not in the
965  * texture). Every texel's green component is 1.0.
966  *
967  * After the calculation test a test pattern is drawn to detect possible
968  * texture sampling anomalies.
969  *//*--------------------------------------------------------------------*/
970 class TextureSamplerCase : public RenderCase
971 {
972 public:
973         enum ShaderType
974         {
975                 TYPE_VERTEX = 0,
976                 TYPE_FRAGMENT,
977
978                 TYPE_LAST
979         };
980         enum TestType
981         {
982                 TEST_TEX_COORD = 0,
983                 TEST_LOD,
984                 TEST_TEX_COORD_CUBE,
985
986                 TEST_LAST
987         };
988
989                                                 TextureSamplerCase                      (Context& context, const char* name, const char* desc, ShaderType type, TestType testType);
990                                                 ~TextureSamplerCase                     (void);
991
992         void                            init                                            (void);
993         void                            deinit                                          (void);
994         IterateResult           iterate                                         (void);
995
996 private:
997         std::string                     genVertexSource                         (void) const;
998         std::string                     genFragmentSource                       (void) const;
999
1000         const ShaderType        m_type;
1001         const TestType          m_testType;
1002         GLuint                          m_textureID;
1003 };
1004
1005 TextureSamplerCase::TextureSamplerCase (Context& context, const char* name, const char* desc, ShaderType type, TestType testType)
1006         : RenderCase    (context, name, desc)
1007         , m_type                (type)
1008         , m_testType    (testType)
1009         , m_textureID   (0)
1010 {
1011         DE_ASSERT(type < TYPE_LAST);
1012         DE_ASSERT(testType < TEST_LAST);
1013 }
1014
1015 TextureSamplerCase::~TextureSamplerCase (void)
1016 {
1017         deinit();
1018 }
1019
1020 void TextureSamplerCase::init (void)
1021 {
1022         // requirements
1023         {
1024                 GLint maxTextureSize = 0;
1025                 m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
1026                 if (maxTextureSize < TEST_TEXTURE_SIZE)
1027                         throw tcu::NotSupportedError(std::string("GL_MAX_TEXTURE_SIZE must be at least ") + de::toString(TEST_TEXTURE_SIZE));
1028         }
1029
1030         // vertex shader supports textures?
1031         if (m_type == TYPE_VERTEX)
1032         {
1033                 GLint maxVertexTexUnits = 0;
1034                 m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTexUnits);
1035                 if (maxVertexTexUnits < 1)
1036                         throw tcu::NotSupportedError("GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS must be at least 1");
1037         }
1038
1039         RenderCase::init();
1040
1041         // gen texture
1042         {
1043                 const glw::Functions&   gl              = m_context.getRenderContext().getFunctions();
1044                 std::vector<deUint8>    texData (TEST_TEXTURE_SIZE*TEST_TEXTURE_SIZE*4);
1045                 de::Random                              rnd             (12345);
1046
1047                 gl.genTextures(1, &m_textureID);
1048
1049                 for (int x = 0; x < TEST_TEXTURE_SIZE; ++x)
1050                 for (int y = 0; y < TEST_TEXTURE_SIZE; ++y)
1051                 {
1052                         // RGBA8, green and alpha channel are always 255 for verification
1053                         texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 0] = rnd.getUint32() & 0xFF;
1054                         texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 1] = 0xFF;
1055                         texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 2] = rnd.getUint32() & 0xFF;
1056                         texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 3] = 0xFF;
1057                 }
1058
1059                 if (m_testType == TEST_TEX_COORD)
1060                 {
1061                         m_testCtx.getLog() << tcu::TestLog::Message << "Creating a 2D texture with a test pattern." << tcu::TestLog::EndMessage;
1062
1063                         gl.bindTexture(GL_TEXTURE_2D, m_textureID);
1064                         gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, &texData[0]);
1065                         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1066                         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1067                         GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init");
1068                 }
1069                 else if (m_testType == TEST_LOD)
1070                 {
1071                         m_testCtx.getLog() << tcu::TestLog::Message << "Creating a mipmapped 2D texture with a test pattern." << tcu::TestLog::EndMessage;
1072
1073                         gl.bindTexture(GL_TEXTURE_2D, m_textureID);
1074
1075                         for (int level = 0; (TEST_TEXTURE_SIZE >> level); ++level)
1076                                 gl.texImage2D(GL_TEXTURE_2D, level, GL_RGBA, TEST_TEXTURE_SIZE >> level, TEST_TEXTURE_SIZE >> level, 0, GL_RGBA, GL_UNSIGNED_BYTE, &texData[0]);
1077
1078                         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1079                         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
1080                         GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init");
1081                 }
1082                 else if (m_testType == TEST_TEX_COORD_CUBE)
1083                 {
1084                         DE_STATIC_ASSERT(TEST_TEXTURE_CUBE_SIZE <= TEST_TEXTURE_SIZE);
1085
1086                         static const GLenum faces[] =
1087                         {
1088                                 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
1089                                 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
1090                                 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
1091                                 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
1092                                 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
1093                                 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
1094                         };
1095
1096                         m_testCtx.getLog() << tcu::TestLog::Message << "Creating a cube map with a test pattern." << tcu::TestLog::EndMessage;
1097
1098                         gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textureID);
1099
1100                         for (int faceNdx = 0; faceNdx < DE_LENGTH_OF_ARRAY(faces); ++faceNdx)
1101                                 gl.texImage2D(faces[faceNdx], 0, GL_RGBA, TEST_TEXTURE_CUBE_SIZE, TEST_TEXTURE_CUBE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, &texData[0]);
1102
1103                         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1104                         gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1105                         GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init");
1106                 }
1107                 else
1108                         DE_ASSERT(DE_FALSE);
1109         }
1110 }
1111
1112 void TextureSamplerCase::deinit (void)
1113 {
1114         RenderCase::deinit();
1115
1116         if (m_textureID)
1117         {
1118                 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1119
1120                 gl.deleteTextures(1, &m_textureID);
1121                 m_textureID = 0;
1122         }
1123 }
1124
1125 TextureSamplerCase::IterateResult TextureSamplerCase::iterate (void)
1126 {
1127         // Draw a grid and texture it with a texture and sample it using special special values. The result samples should all have the green channel at 255 as per the test image.
1128
1129         std::vector<tcu::Vec4>  gridVertices    (DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
1130         std::vector<tcu::UVec2> gridTexCoords   (DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
1131         std::vector<deUint16>   indices                 ((DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * 6);
1132         tcu::Surface                    resultImage             (TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1133
1134         // vertices
1135         for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
1136         for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
1137         {
1138                 const float posX = (float)x / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f; // map from [0, len(s_specialFloats) - 1] to [-1, 1]
1139                 const float posY = (float)y / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f;
1140
1141                 gridVertices[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y]       = tcu::Vec4(posX, posY, 0.0f, 1.0f);
1142                 gridTexCoords[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y]      = tcu::UVec2(s_specialFloats[x], s_specialFloats[y]);
1143         }
1144
1145         // tiles
1146         for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++x)
1147         for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++y)
1148         {
1149                 const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) + y) * 6;
1150
1151                 indices[baseNdx + 0] = (deUint16)((x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0));
1152                 indices[baseNdx + 1] = (deUint16)((x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1));
1153                 indices[baseNdx + 2] = (deUint16)((x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0));
1154
1155                 indices[baseNdx + 3] = (deUint16)((x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+0));
1156                 indices[baseNdx + 4] = (deUint16)((x+1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1));
1157                 indices[baseNdx + 5] = (deUint16)((x+0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y+1));
1158         }
1159
1160         m_testCtx.getLog() << tcu::TestLog::Message << "Drawing a textured grid with the shader. Sampling from the texture using special floating point values." << tcu::TestLog::EndMessage;
1161
1162         // Draw grid
1163         {
1164                 const glw::Functions&   gl                      = m_context.getRenderContext().getFunctions();
1165                 const GLint                             positionLoc     = gl.getAttribLocation(m_program->getProgram(), "a_pos");
1166                 const GLint                             texCoordLoc     = gl.getAttribLocation(m_program->getProgram(), "a_attr");
1167                 const GLint                             samplerLoc      = gl.getUniformLocation(m_program->getProgram(), "u_sampler");
1168
1169                 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1170                 gl.clear(GL_COLOR_BUFFER_BIT);
1171                 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1172                 gl.useProgram(m_program->getProgram());
1173
1174                 gl.uniform1i(samplerLoc, 0);
1175                 if (m_testType != TEST_TEX_COORD_CUBE)
1176                         gl.bindTexture(GL_TEXTURE_2D, m_textureID);
1177                 else
1178                         gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textureID);
1179
1180                 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
1181                 gl.vertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, &gridTexCoords[0]);
1182
1183                 gl.enableVertexAttribArray(positionLoc);
1184                 gl.enableVertexAttribArray(texCoordLoc);
1185                 gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, &indices[0]);
1186                 gl.disableVertexAttribArray(positionLoc);
1187                 gl.disableVertexAttribArray(texCoordLoc);
1188
1189                 gl.useProgram(0);
1190                 gl.finish();
1191                 GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::iterate");
1192
1193                 glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
1194         }
1195
1196         // verify everywhere was drawn and samples were from the texture (all pixels have Green = 255)
1197         if (!checkResultImage(resultImage))
1198         {
1199                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments");
1200                 return STOP;
1201         }
1202
1203         // test drawing and textures still works
1204         if (!drawTestPattern(true))
1205         {
1206                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed");
1207                 return STOP;
1208         }
1209
1210         // all ok
1211         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1212         return STOP;
1213 }
1214
1215 std::string TextureSamplerCase::genVertexSource (void) const
1216 {
1217         // vertex shader is passthrough, fragment does the calculations
1218         if (m_type == TYPE_FRAGMENT)
1219                 return s_attrPassthroughVertexShaderSource;
1220
1221         // vertex shader does the calculations
1222         std::ostringstream buf;
1223         buf <<  "attribute highp vec4 a_pos;\n"
1224                         "attribute highp vec2 a_attr;\n";
1225
1226         if (m_testType != TEST_TEX_COORD_CUBE)
1227                 buf <<  "uniform highp sampler2D u_sampler;\n";
1228         else
1229                 buf <<  "uniform highp samplerCube u_sampler;\n";
1230
1231         buf <<  "varying mediump vec4 v_out;\n"
1232                         "void main ()\n"
1233                         "{\n";
1234
1235         if (m_testType == TEST_TEX_COORD)
1236                 buf <<  "       v_out = texture2DLod(u_sampler, a_attr, 0.0);\n";
1237         else if (m_testType == TEST_LOD)
1238                 buf <<  "       v_out = texture2DLod(u_sampler, a_attr, a_attr.x);\n";
1239         else if (m_testType == TEST_TEX_COORD_CUBE)
1240                 buf <<  "       v_out = textureCubeLod(u_sampler, vec3(a_attr, a_attr.x+a_attr.y), 0.0);\n";
1241         else
1242                 DE_ASSERT(DE_FALSE);
1243
1244         buf <<  "\n"
1245                         "       gl_Position = a_pos;\n"
1246                         "}\n";
1247
1248         return buf.str();
1249 }
1250
1251 std::string TextureSamplerCase::genFragmentSource (void) const
1252 {
1253         // fragment shader is passthrough
1254         if (m_type == TYPE_VERTEX)
1255                 return s_colorPassthroughFragmentShaderSource;
1256
1257         // fragment shader does the calculations
1258         std::ostringstream buf;
1259         if (m_testType != TEST_TEX_COORD_CUBE)
1260                 buf <<  "uniform mediump sampler2D u_sampler;\n";
1261         else
1262                 buf <<  "uniform mediump samplerCube u_sampler;\n";
1263
1264         buf <<  "varying mediump vec4 v_attr;\n"
1265                         "void main ()\n"
1266                         "{\n";
1267
1268         if (m_testType == TEST_TEX_COORD)
1269                 buf << "        gl_FragColor = texture2D(u_sampler, v_attr.xy);\n";
1270         else if (m_testType == TEST_LOD)
1271                 buf << "        gl_FragColor = texture2D(u_sampler, v_attr.xy, v_attr.x);\n";
1272         else if (m_testType == TEST_TEX_COORD_CUBE)
1273                 buf <<  "       gl_FragColor = textureCube(u_sampler, vec3(v_attr.xy, v_attr.x + v_attr.y));\n";
1274         else
1275                 DE_ASSERT(DE_FALSE);
1276
1277         buf <<  "}\n";
1278
1279         return buf.str();
1280 }
1281
1282 /*--------------------------------------------------------------------*//*!
1283  * \brief Tests special floats as fragment shader outputs
1284  *
1285  * Tests that outputting special floats from a fragment shader does not change
1286  * the normal floating point values of outputted from a fragment shader. Special
1287  * floats are outputted in the green component, normal floating point values
1288  * in the red and blue component. Potential changes are tested by rendering
1289  * test pattern two times with different floating point values. The resulting
1290  * images' red and blue channels should be equal.
1291  *//*--------------------------------------------------------------------*/
1292 class OutputCase : public FramebufferRenderCase
1293 {
1294 public:
1295                                                 OutputCase                              (Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type);
1296                                                 ~OutputCase                             (void);
1297
1298         void                            testFBO                                 (void);
1299
1300 private:
1301         std::string                     genVertexSource                 (void) const;
1302         std::string                     genFragmentSource               (void) const;
1303 };
1304
1305 OutputCase::OutputCase (Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type)
1306         : FramebufferRenderCase (context, name, desc, type)
1307 {
1308 }
1309
1310 OutputCase::~OutputCase (void)
1311 {
1312         deinit();
1313 }
1314
1315 void OutputCase::testFBO (void)
1316 {
1317         // Create a 1 X [s_specialFloats] grid of tiles (stripes).
1318         std::vector<tcu::Vec4>  gridVertices    ((DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) * 2);
1319         std::vector<deUint16>   indices                 (DE_LENGTH_OF_ARRAY(s_specialFloats) * 6);
1320         tcu::TextureFormat              textureFormat   (tcu::TextureFormat::RGBA, (m_fboType == FBO_RGBA_FLOAT16) ? (tcu::TextureFormat::FLOAT) : (tcu::TextureFormat::UNORM_INT8));
1321         tcu::TextureLevel               specialImage    (textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1322         tcu::TextureLevel               normalImage             (textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1323
1324         // vertices
1325         for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++y)
1326         {
1327                 const float posY = (float)y / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f - 1.0f; // map from [0, len(s_specialFloats) ] to [-1, 1]
1328
1329                 gridVertices[y * 2 + 0] = tcu::Vec4(-1.0, posY, 0.0f, 1.0f);
1330                 gridVertices[y * 2 + 1] = tcu::Vec4( 1.0, posY, 0.0f, 1.0f);
1331         }
1332
1333         // tiles
1334         for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
1335         {
1336                 const int baseNdx = y * 6;
1337
1338                 indices[baseNdx + 0] = (deUint16)((y + 0) * 2);
1339                 indices[baseNdx + 1] = (deUint16)((y + 1) * 2);
1340                 indices[baseNdx + 2] = (deUint16)((y + 1) * 2 + 1);
1341
1342                 indices[baseNdx + 3] = (deUint16)((y + 0) * 2);
1343                 indices[baseNdx + 4] = (deUint16)((y + 1) * 2 + 1);
1344                 indices[baseNdx + 5] = (deUint16)((y + 0) * 2 + 1);
1345         }
1346
1347         // Draw grids
1348         {
1349                 const glw::Functions&   gl                      = m_context.getRenderContext().getFunctions();
1350                 const GLint                             positionLoc     = gl.getAttribLocation(m_program->getProgram(), "a_pos");
1351                 const GLint                             specialLoc      = gl.getUniformLocation(m_program->getProgram(), "u_special");
1352
1353                 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1354                 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1355                 gl.useProgram(m_program->getProgram());
1356                 GLU_EXPECT_NO_ERROR(gl.getError(), "pre-draw");
1357
1358                 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
1359                 gl.enableVertexAttribArray(positionLoc);
1360
1361                 // draw 2 passes. Special and normal.
1362                 for (int passNdx = 0; passNdx < 2; ++passNdx)
1363                 {
1364                         const bool specialPass  = (passNdx == 0);
1365
1366                         m_testCtx.getLog() << tcu::TestLog::Message << "Pass " << passNdx << ": Drawing stripes with the shader. Setting u_special for each stripe to (" << ((specialPass) ? ("special") : ("1.0")) << ")." << tcu::TestLog::EndMessage;
1367
1368                         // draw stripes
1369                         gl.clear(GL_COLOR_BUFFER_BIT);
1370                         for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
1371                         {
1372                                 const deUint32  one                             = 0x3F800000;
1373                                 const deUint32  special                 = s_specialFloats[y];
1374                                 const deUint32  uniformValue    = (specialPass) ? (special) : (one);
1375                                 const int               indexIndex              = y * 6;
1376
1377                                 gl.uniform1fv(specialLoc, 1, (const float*)&uniformValue);
1378                                 gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[indexIndex]);
1379                         }
1380
1381                         gl.finish();
1382                         glu::readPixels(m_context.getRenderContext(), 0, 0, ((specialPass) ? (specialImage) : (normalImage)).getAccess());
1383                 }
1384
1385                 gl.disableVertexAttribArray(positionLoc);
1386                 gl.useProgram(0);
1387                 GLU_EXPECT_NO_ERROR(gl.getError(), "OutputCase::iterate");
1388         }
1389
1390         // Check results
1391         {
1392                 tcu::Surface            errorMask               (TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1393                 const tcu::RGBA         badPixelColor   = tcu::RGBA::red();
1394                 const tcu::RGBA         okPixelColor    = tcu::RGBA::green();
1395                 int                                     badPixels               = 0;
1396
1397                 m_testCtx.getLog() << tcu::TestLog::Message << "Checking passes have identical red and blue channels and the green channel is correct in the constant pass." << tcu::TestLog::EndMessage;
1398
1399                 for (int y = 0; y < specialImage.getHeight(); ++y)
1400                 for (int x = 0; x < specialImage.getWidth(); ++x)
1401                 {
1402                         const float             greenThreshold  = 0.1f;
1403                         const tcu::Vec4 cNormal                 = normalImage.getAccess().getPixel(x, y);
1404                         const tcu::Vec4 cSpecial                = specialImage.getAccess().getPixel(x, y);
1405
1406                         if (cNormal.x() != cSpecial.x() || cNormal.z() != cSpecial.z() || cNormal.y() < 1.0f - greenThreshold)
1407                         {
1408                                 ++badPixels;
1409                                 errorMask.setPixel(x, y, badPixelColor);
1410                         }
1411                         else
1412                                 errorMask.setPixel(x, y, okPixelColor);
1413                 }
1414
1415                 m_testCtx.getLog() << tcu::TestLog::Message << "Found " << badPixels << " invalid pixel(s)." << tcu::TestLog::EndMessage;
1416
1417                 if (badPixels)
1418                 {
1419                         m_testCtx.getLog()
1420                                         << tcu::TestLog::ImageSet("Results", "Result verification")
1421                                         << tcu::TestLog::Image("Image with special green channel",      "Image with special green channel",             specialImage)
1422                                         << tcu::TestLog::Image("Image with constant green channel",     "Image with constant green channel",    normalImage)
1423                                         << tcu::TestLog::Image("Error Mask",                                            "Error Mask",                                                   errorMask)
1424                                         << tcu::TestLog::EndImageSet;
1425
1426                         // all ok?
1427                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1428                 }
1429                 else
1430                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1431         }
1432 }
1433
1434 std::string OutputCase::genVertexSource (void) const
1435 {
1436         return
1437                 "attribute highp vec4 a_pos;\n"
1438                 "varying mediump vec2 v_pos;\n"
1439                 "void main ()\n"
1440                 "{\n"
1441                 "       gl_Position = a_pos;\n"
1442                 "       v_pos = a_pos.xy;\n"
1443                 "}\n";
1444 }
1445
1446 std::string OutputCase::genFragmentSource (void) const
1447 {
1448         return
1449                 "uniform mediump float u_special;\n"
1450                 "varying mediump vec2 v_pos;\n"
1451                 "void main ()\n"
1452                 "{\n"
1453                 "       gl_FragColor = vec4((v_pos.x + 1.0) * 0.5, u_special, (v_pos.y + 1.0) * 0.5, 1.0);\n"
1454                 "}\n";
1455 }
1456
1457 /*--------------------------------------------------------------------*//*!
1458  * \brief Tests special floats in blending
1459  *
1460  * Tests special floats as alpha and color components with various blending
1461  * modes. Test draws a test pattern and then does various blend operations
1462  * with special float values. After the blending test another test pattern
1463  * is drawn to detect possible blending anomalies. Test patterns should be
1464  * identical.
1465  *//*--------------------------------------------------------------------*/
1466 class BlendingCase : public FramebufferRenderCase
1467 {
1468 public:
1469                                                 BlendingCase                    (Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type);
1470                                                 ~BlendingCase                   (void);
1471
1472         void                            testFBO                                 (void);
1473
1474 private:
1475         void                            drawTestImage                   (tcu::PixelBufferAccess dst, GLuint uColorLoc, int maxVertexIndex);
1476
1477         std::string                     genVertexSource                 (void) const;
1478         std::string                     genFragmentSource               (void) const;
1479 };
1480
1481 BlendingCase::BlendingCase (Context& context, const char* name, const char* desc, FramebufferRenderCase::FrameBufferType type)
1482         : FramebufferRenderCase (context, name, desc, type)
1483 {
1484 }
1485
1486 BlendingCase::~BlendingCase (void)
1487 {
1488         deinit();
1489 }
1490
1491 void BlendingCase::testFBO (void)
1492 {
1493         static const GLenum equations[] =
1494         {
1495                 GL_FUNC_ADD,
1496                 GL_FUNC_SUBTRACT,
1497                 GL_FUNC_REVERSE_SUBTRACT,
1498         };
1499         static const GLenum functions[] =
1500         {
1501                 GL_ZERO,
1502                 GL_ONE,
1503                 GL_SRC_COLOR,
1504                 GL_ONE_MINUS_SRC_COLOR,
1505                 GL_SRC_ALPHA,
1506                 GL_ONE_MINUS_SRC_ALPHA,
1507         };
1508
1509         // Create a [BlendFuncs] X [s_specialFloats] grid of tiles. ( BlendFuncs = equations x functions )
1510
1511         const int                                               numBlendFuncs   = DE_LENGTH_OF_ARRAY(equations) * DE_LENGTH_OF_ARRAY(functions);
1512         std::vector<tcu::Vec4>                  gridVertices    ((numBlendFuncs + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1));
1513         std::vector<deUint16>                   indices                 (numBlendFuncs * DE_LENGTH_OF_ARRAY(s_specialFloats) * 6);
1514         tcu::TextureFormat                              textureFormat   (tcu::TextureFormat::RGBA, (m_fboType == FBO_RGBA_FLOAT16) ? (tcu::TextureFormat::FLOAT) : (tcu::TextureFormat::UNORM_INT8));
1515         tcu::TextureLevel                               beforeImage             (textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1516         tcu::TextureLevel                               afterImage              (textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1517
1518         // vertices
1519         for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++x)
1520         for (int y = 0; y < numBlendFuncs + 1; ++y)
1521         {
1522                 const float             posX    = (float)x / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f - 1.0f; // map from [0, len(s_specialFloats)] to [-1, 1]
1523                 const float             posY    = (float)y / (float)numBlendFuncs * 2.0f - 1.0f;
1524
1525                 gridVertices[x * (numBlendFuncs + 1) + y]       = tcu::Vec4(posX, posY, 0.0f, 1.0f);
1526         }
1527
1528         // tiles
1529         for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
1530         for (int y = 0; y < numBlendFuncs; ++y)
1531         {
1532                 const int baseNdx = (x * numBlendFuncs + y) * 6;
1533
1534                 indices[baseNdx + 0] = (deUint16)((x+0) * (numBlendFuncs + 1) + (y+0));
1535                 indices[baseNdx + 1] = (deUint16)((x+1) * (numBlendFuncs + 1) + (y+1));
1536                 indices[baseNdx + 2] = (deUint16)((x+1) * (numBlendFuncs + 1) + (y+0));
1537
1538                 indices[baseNdx + 3] = (deUint16)((x+0) * (numBlendFuncs + 1) + (y+0));
1539                 indices[baseNdx + 4] = (deUint16)((x+1) * (numBlendFuncs + 1) + (y+1));
1540                 indices[baseNdx + 5] = (deUint16)((x+0) * (numBlendFuncs + 1) + (y+1));
1541         }
1542
1543         // Draw tiles
1544         {
1545                 const int                               numPasses       = 5;
1546                 const glw::Functions&   gl                      = m_context.getRenderContext().getFunctions();
1547                 const GLint                             positionLoc     = gl.getAttribLocation(m_program->getProgram(), "a_pos");
1548                 const GLint                             specialLoc      = gl.getUniformLocation(m_program->getProgram(), "u_special");
1549
1550                 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1551                 gl.clear(GL_COLOR_BUFFER_BIT);
1552                 gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1553                 gl.useProgram(m_program->getProgram());
1554                 gl.enable(GL_BLEND);
1555                 GLU_EXPECT_NO_ERROR(gl.getError(), "pre-draw");
1556
1557                 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
1558                 gl.enableVertexAttribArray(positionLoc);
1559
1560                 // draw "before" image
1561                 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing pre-draw pattern." << tcu::TestLog::EndMessage;
1562                 drawTestImage(beforeImage.getAccess(), specialLoc, (int)gridVertices.size() - 1);
1563                 GLU_EXPECT_NO_ERROR(gl.getError(), "pre-draw pattern");
1564
1565                 // draw multiple passes with special floats
1566                 gl.clear(GL_COLOR_BUFFER_BIT);
1567                 for (int passNdx = 0; passNdx < numPasses; ++passNdx)
1568                 {
1569                         de::Random rnd(123 + 567 * passNdx);
1570
1571                         m_testCtx.getLog()
1572                                 << tcu::TestLog::Message
1573                                 << "Pass " << passNdx << ": Drawing tiles with the shader.\n"
1574                                 << "\tVarying u_special for each tile.\n"
1575                                 << "\tVarying blend function and blend equation for each tile.\n"
1576                                 << tcu::TestLog::EndMessage;
1577
1578                         // draw tiles
1579                         for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
1580                         for (int y = 0; y < numBlendFuncs; ++y)
1581                         {
1582                                 const GLenum            blendEquation           = equations[y % DE_LENGTH_OF_ARRAY(equations)];
1583                                 const GLenum            blendFunction           = functions[y / DE_LENGTH_OF_ARRAY(equations)];
1584                                 const GLenum            blendFunctionDst        = rnd.choose<GLenum>(DE_ARRAY_BEGIN(functions), DE_ARRAY_END(functions));
1585                                 const int                       indexIndex                      = (x * numBlendFuncs + y) * 6;
1586
1587                                 // "rnd.get"s are run in a deterministic order
1588                                 const deUint32          componentR                      = rnd.choose<deUint32>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
1589                                 const deUint32          componentG                      = rnd.choose<deUint32>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
1590                                 const deUint32          componentB                      = rnd.choose<deUint32>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
1591                                 const deUint32          componentA                      = rnd.choose<deUint32>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
1592                                 const tcu::UVec4        uniformValue            = tcu::UVec4(componentR, componentG, componentB, componentA);
1593
1594                                 gl.uniform4fv(specialLoc, 1, (const float*)uniformValue.getPtr());
1595                                 gl.blendEquation(blendEquation);
1596                                 gl.blendFunc(blendFunction, blendFunctionDst);
1597                                 gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[indexIndex]);
1598                         }
1599                 }
1600                 GLU_EXPECT_NO_ERROR(gl.getError(), "special passes");
1601
1602                 // draw "after" image
1603                 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing post-draw pattern." << tcu::TestLog::EndMessage;
1604                 drawTestImage(afterImage.getAccess(), specialLoc, (int)gridVertices.size() - 1);
1605                 GLU_EXPECT_NO_ERROR(gl.getError(), "post-draw pattern");
1606
1607                 gl.disableVertexAttribArray(positionLoc);
1608                 gl.useProgram(0);
1609                 GLU_EXPECT_NO_ERROR(gl.getError(), "OutputCase::iterate");
1610         }
1611
1612         // Check results
1613         {
1614                 tcu::Surface            errorMask               (TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1615                 const tcu::RGBA         badPixelColor   = tcu::RGBA::red();
1616                 const tcu::RGBA         okPixelColor    = tcu::RGBA::green();
1617                 int                                     badPixels               = 0;
1618
1619                 m_testCtx.getLog() << tcu::TestLog::Message << "Checking patterns are identical." << tcu::TestLog::EndMessage;
1620
1621                 for (int y = 0; y < beforeImage.getHeight(); ++y)
1622                 for (int x = 0; x < beforeImage.getWidth(); ++x)
1623                 {
1624                         const tcu::Vec4 cBefore = beforeImage.getAccess().getPixel(x, y);
1625                         const tcu::Vec4 cAfter  = afterImage.getAccess().getPixel(x, y);
1626
1627                         if (cBefore != cAfter)
1628                         {
1629                                 ++badPixels;
1630                                 errorMask.setPixel(x, y, badPixelColor);
1631                         }
1632                         else
1633                                 errorMask.setPixel(x, y, okPixelColor);
1634                 }
1635
1636                 m_testCtx.getLog() << tcu::TestLog::Message << "Found " << badPixels << " invalid pixel(s)." << tcu::TestLog::EndMessage;
1637
1638                 if (badPixels)
1639                 {
1640                         m_testCtx.getLog()
1641                                         << tcu::TestLog::ImageSet("Results", "Result verification")
1642                                         << tcu::TestLog::Image("Pattern drawn before special float blending",   "Pattern drawn before special float blending",          beforeImage)
1643                                         << tcu::TestLog::Image("Pattern drawn after special float blending",    "Pattern drawn after special float blending",           afterImage)
1644                                         << tcu::TestLog::EndImageSet;
1645
1646                         // all ok?
1647                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1648                 }
1649                 else
1650                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1651         }
1652 }
1653
1654 void BlendingCase::drawTestImage (tcu::PixelBufferAccess dst, GLuint uColorLoc, int maxVertexIndex)
1655 {
1656         const glw::Functions&   gl      = m_context.getRenderContext().getFunctions();
1657         de::Random                              rnd     (123);
1658
1659         gl.clear(GL_COLOR_BUFFER_BIT);
1660         gl.blendEquation(GL_FUNC_ADD);
1661         gl.blendFunc(GL_ONE, GL_ONE);
1662
1663         for (int tri = 0; tri < 20; ++tri)
1664         {
1665                 tcu::Vec4 color;
1666                 color.x() = rnd.getFloat();
1667                 color.y() = rnd.getFloat();
1668                 color.z() = rnd.getFloat();
1669                 color.w() = rnd.getFloat();
1670                 gl.uniform4fv(uColorLoc, 1, color.getPtr());
1671
1672                 deUint16 indices[3];
1673                 indices[0] = (deUint16)rnd.getInt(0, maxVertexIndex);
1674                 indices[1] = (deUint16)rnd.getInt(0, maxVertexIndex);
1675                 indices[2] = (deUint16)rnd.getInt(0, maxVertexIndex);
1676
1677                 gl.drawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, indices);
1678         }
1679
1680         gl.finish();
1681         glu::readPixels(m_context.getRenderContext(), 0, 0, dst);
1682 }
1683
1684 std::string BlendingCase::genVertexSource (void) const
1685 {
1686         return
1687                 "attribute highp vec4 a_pos;\n"
1688                 "void main ()\n"
1689                 "{\n"
1690                 "       gl_Position = a_pos;\n"
1691                 "}\n";
1692 }
1693
1694 std::string BlendingCase::genFragmentSource (void) const
1695 {
1696         return
1697                 "uniform mediump vec4 u_special;\n"
1698                 "void main ()\n"
1699                 "{\n"
1700                 "       gl_FragColor = u_special;\n"
1701                 "}\n";
1702 }
1703
1704 } //anonymous
1705
1706 SpecialFloatTests::SpecialFloatTests (Context& context)
1707         : TestCaseGroup(context, "special_float", "Special float tests")
1708 {
1709 }
1710
1711 SpecialFloatTests::~SpecialFloatTests (void)
1712 {
1713 }
1714
1715 void SpecialFloatTests::init (void)
1716 {
1717         tcu::TestCaseGroup* const vertexGroup   = new tcu::TestCaseGroup(m_testCtx, "vertex",   "Run vertex shader with special float values");
1718         tcu::TestCaseGroup* const fragmentGroup = new tcu::TestCaseGroup(m_testCtx, "fragment", "Run fragment shader with special float values");
1719         tcu::TestCaseGroup* const framebufferGroup      = new tcu::TestCaseGroup(m_testCtx, "framebuffer",      "Test framebuffers containing special float values");
1720
1721         // .vertex
1722         {
1723                 vertexGroup->addChild(new VertexAttributeCase   (m_context, "attribute_buffer",                 "special attribute values in a buffer",                                 VertexAttributeCase::STORAGE_BUFFER, VertexAttributeCase::TYPE_VERTEX));
1724                 vertexGroup->addChild(new VertexAttributeCase   (m_context, "attribute_client",                 "special attribute values in a client storage",                 VertexAttributeCase::STORAGE_CLIENT, VertexAttributeCase::TYPE_VERTEX));
1725                 vertexGroup->addChild(new UniformCase                   (m_context, "uniform",                                  "special uniform values",                                                               UniformCase::TYPE_VERTEX));
1726                 vertexGroup->addChild(new TextureSamplerCase    (m_context, "sampler_tex_coord",                "special texture coords",                                                               TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_TEX_COORD));
1727                 vertexGroup->addChild(new TextureSamplerCase    (m_context, "sampler_tex_coord_cube",   "special texture coords to cubemap",                                    TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_TEX_COORD_CUBE));
1728                 vertexGroup->addChild(new TextureSamplerCase    (m_context, "sampler_lod",                              "special texture lod",                                                                  TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_LOD));
1729
1730                 addChild(vertexGroup);
1731         }
1732
1733         // .fragment
1734         {
1735                 fragmentGroup->addChild(new VertexAttributeCase (m_context, "attribute_buffer",                 "special attribute values in a buffer",                                 VertexAttributeCase::STORAGE_BUFFER, VertexAttributeCase::TYPE_FRAGMENT));
1736                 fragmentGroup->addChild(new VertexAttributeCase (m_context, "attribute_client",                 "special attribute values in a client storage",                 VertexAttributeCase::STORAGE_CLIENT, VertexAttributeCase::TYPE_FRAGMENT));
1737                 fragmentGroup->addChild(new UniformCase                 (m_context, "uniform",                                  "special uniform values",                                                               UniformCase::TYPE_FRAGMENT));
1738                 fragmentGroup->addChild(new TextureSamplerCase  (m_context, "sampler_tex_coord",                "special texture coords",                                                               TextureSamplerCase::TYPE_FRAGMENT, TextureSamplerCase::TEST_TEX_COORD));
1739                 fragmentGroup->addChild(new TextureSamplerCase  (m_context, "sampler_tex_coord_cube",   "special texture coords to cubemap",                                    TextureSamplerCase::TYPE_FRAGMENT, TextureSamplerCase::TEST_TEX_COORD_CUBE));
1740                 fragmentGroup->addChild(new TextureSamplerCase  (m_context, "sampler_lod",                              "special texture lod",                                                                  TextureSamplerCase::TYPE_FRAGMENT, TextureSamplerCase::TEST_LOD));
1741
1742                 addChild(fragmentGroup);
1743         }
1744
1745         // .framebuffer
1746         {
1747                 framebufferGroup->addChild(new OutputCase               (m_context, "write_default",                    "write special floating point values to default framebuffer",   FramebufferRenderCase::FBO_DEFAULT));
1748                 framebufferGroup->addChild(new OutputCase               (m_context, "write_rgba",                               "write special floating point values to RGBA framebuffer",              FramebufferRenderCase::FBO_RGBA));
1749                 framebufferGroup->addChild(new OutputCase               (m_context, "write_rgba4",                              "write special floating point values to RGBA4 framebuffer",             FramebufferRenderCase::FBO_RGBA4));
1750                 framebufferGroup->addChild(new OutputCase               (m_context, "write_rgb5_a1",                    "write special floating point values to RGB5_A1 framebuffer",   FramebufferRenderCase::FBO_RGB5_A1));
1751                 framebufferGroup->addChild(new OutputCase               (m_context, "write_rgb565",                             "write special floating point values to RGB565 framebuffer",    FramebufferRenderCase::FBO_RGB565));
1752                 framebufferGroup->addChild(new OutputCase               (m_context, "write_float16",                    "write special floating point values to float16 framebuffer",   FramebufferRenderCase::FBO_RGBA_FLOAT16));
1753
1754                 framebufferGroup->addChild(new BlendingCase             (m_context, "blend_default",                    "blend special floating point values in a default framebuffer", FramebufferRenderCase::FBO_DEFAULT));
1755                 framebufferGroup->addChild(new BlendingCase             (m_context, "blend_rgba",                               "blend special floating point values in a RGBA framebuffer",    FramebufferRenderCase::FBO_RGBA));
1756                 framebufferGroup->addChild(new BlendingCase             (m_context, "blend_float16",                    "blend special floating point values in a float16 framebuffer", FramebufferRenderCase::FBO_RGBA_FLOAT16));
1757
1758                 addChild(framebufferGroup);
1759         }
1760 }
1761
1762 } // Stress
1763 } // gles2
1764 } // deqp