xref: /aosp_15_r20/external/deqp/modules/gles3/stress/es3sSpecialFloatTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.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 "es3sSpecialFloatTests.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 gles3
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 uint32_t s_specialFloats[] = {
58     0x00000000, //          zero
59     0x80000000, // negative zero
60     0x3F800000, //          one
61     0xBF800000, // negative one
62     0x00800000, // minimum positive normalized value
63     0x80800000, // maximum negative normalized value
64     0x00000001, // minimum positive denorm value
65     0x80000001, // maximum negative denorm value
66     0x7F7FFFFF, // maximum finite value.
67     0xFF7FFFFF, // minimum finite value.
68     0x7F800000, //  inf
69     0xFF800000, // -inf
70     0x34000000, //          epsilon
71     0xB4000000, // negative epsilon
72     0x7FC00000, //          quiet_NaN
73     0xFFC00000, // negative quiet_NaN
74     0x7FC00001, //          signaling_NaN
75     0xFFC00001, // negative signaling_NaN
76     0x7FEAAAAA, //          quiet payloaded NaN        (payload of repeated pattern of 101010...)
77     0xFFEAAAAA, // negative quiet payloaded NaN        ( .. )
78     0x7FAAAAAA, //          signaling payloaded NaN    ( .. )
79     0xFFAAAAAA, // negative signaling payloaded NaN    ( .. )
80 };
81 
82 static const char *const s_colorPassthroughFragmentShaderSource = "#version 300 es\n"
83                                                                   "layout(location = 0) out mediump vec4 fragColor;\n"
84                                                                   "in mediump vec4 v_out;\n"
85                                                                   "void main ()\n"
86                                                                   "{\n"
87                                                                   "    fragColor = v_out;\n"
88                                                                   "}\n";
89 static const char *const s_attrPassthroughVertexShaderSource    = "#version 300 es\n"
90                                                                   "in highp vec4 a_pos;\n"
91                                                                   "in highp vec4 a_attr;\n"
92                                                                   "out highp vec4 v_attr;\n"
93                                                                   "void main ()\n"
94                                                                   "{\n"
95                                                                   "    v_attr = a_attr;\n"
96                                                                   "    gl_Position = a_pos;\n"
97                                                                   "}\n";
98 
99 class RenderCase : public TestCase
100 {
101 public:
102     enum RenderTargetType
103     {
104         RENDERTARGETTYPE_SCREEN,
105         RENDERTARGETTYPE_FBO
106     };
107 
108     RenderCase(Context &context, const char *name, const char *desc,
109                RenderTargetType renderTargetType = RENDERTARGETTYPE_SCREEN);
110     virtual ~RenderCase(void);
111 
112     virtual void init(void);
113     virtual void deinit(void);
114 
115 protected:
116     bool checkResultImage(const tcu::Surface &result);
117     bool drawTestPattern(bool useTexture);
118 
119     virtual std::string genVertexSource(void) const   = 0;
120     virtual std::string genFragmentSource(void) const = 0;
121 
122     const glu::ShaderProgram *m_program;
123     const RenderTargetType m_renderTargetType;
124 };
125 
RenderCase(Context & context,const char * name,const char * desc,RenderTargetType renderTargetType)126 RenderCase::RenderCase(Context &context, const char *name, const char *desc, RenderTargetType renderTargetType)
127     : TestCase(context, name, desc)
128     , m_program(DE_NULL)
129     , m_renderTargetType(renderTargetType)
130 {
131 }
132 
~RenderCase(void)133 RenderCase::~RenderCase(void)
134 {
135     deinit();
136 }
137 
init(void)138 void RenderCase::init(void)
139 {
140     const int width  = m_context.getRenderTarget().getWidth();
141     const int height = m_context.getRenderTarget().getHeight();
142 
143     // check target size
144     if (m_renderTargetType == RENDERTARGETTYPE_SCREEN)
145     {
146         if (width < TEST_CANVAS_SIZE || height < TEST_CANVAS_SIZE)
147             throw tcu::NotSupportedError(std::string("Render target size must be at least ") +
148                                          de::toString(TEST_CANVAS_SIZE) + "x" + de::toString(TEST_CANVAS_SIZE));
149     }
150     else if (m_renderTargetType == RENDERTARGETTYPE_FBO)
151     {
152         GLint maxTexSize = 0;
153         m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
154 
155         if (maxTexSize < TEST_CANVAS_SIZE)
156             throw tcu::NotSupportedError(std::string("GL_MAX_TEXTURE_SIZE must be at least ") +
157                                          de::toString(TEST_CANVAS_SIZE));
158     }
159     else
160         DE_ASSERT(false);
161 
162     // gen shader
163 
164     m_testCtx.getLog() << tcu::TestLog::Message << "Creating test shader." << tcu::TestLog::EndMessage;
165 
166     m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
167                                                                          << glu::VertexSource(genVertexSource())
168                                                                          << glu::FragmentSource(genFragmentSource()));
169     m_testCtx.getLog() << *m_program;
170 
171     if (!m_program->isOk())
172         throw tcu::TestError("shader compile failed");
173 }
174 
deinit(void)175 void RenderCase::deinit(void)
176 {
177     if (m_program)
178     {
179         delete m_program;
180         m_program = DE_NULL;
181     }
182 }
183 
checkResultImage(const tcu::Surface & result)184 bool RenderCase::checkResultImage(const tcu::Surface &result)
185 {
186     tcu::Surface errorMask(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
187     bool error = false;
188 
189     m_testCtx.getLog() << tcu::TestLog::Message << "Verifying output image." << tcu::TestLog::EndMessage;
190 
191     for (int y = 0; y < TEST_CANVAS_SIZE; ++y)
192         for (int x = 0; x < TEST_CANVAS_SIZE; ++x)
193         {
194             const tcu::RGBA col = result.getPixel(x, y);
195 
196             if (col.getGreen() == 255)
197                 errorMask.setPixel(x, y, tcu::RGBA::green());
198             else
199             {
200                 errorMask.setPixel(x, y, tcu::RGBA::red());
201                 error = true;
202             }
203         }
204 
205     if (error)
206     {
207         m_testCtx.getLog() << tcu::TestLog::Message << "Result image has missing or invalid pixels"
208                            << tcu::TestLog::EndMessage;
209         m_testCtx.getLog() << tcu::TestLog::ImageSet("Results", "Result verification")
210                            << tcu::TestLog::Image("Result", "Result", result)
211                            << tcu::TestLog::Image("Error mask", "Error mask", errorMask) << tcu::TestLog::EndImageSet;
212     }
213     else
214     {
215         m_testCtx.getLog() << tcu::TestLog::ImageSet("Results", "Result verification")
216                            << tcu::TestLog::Image("Result", "Result", result) << tcu::TestLog::EndImageSet;
217     }
218 
219     return !error;
220 }
221 
drawTestPattern(bool useTexture)222 bool RenderCase::drawTestPattern(bool useTexture)
223 {
224     static const tcu::Vec4 fullscreenQuad[4] = {
225         tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
226         tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
227         tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f),
228         tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f),
229     };
230     const char *const vertexSource        = "#version 300 es\n"
231                                             "in highp vec4 a_pos;\n"
232                                             "out mediump vec4 v_position;\n"
233                                             "void main ()\n"
234                                             "{\n"
235                                             "    v_position = a_pos;\n"
236                                             "    gl_Position = a_pos;\n"
237                                             "}\n";
238     const char *const fragmentSourceNoTex = "#version 300 es\n"
239                                             "layout(location = 0) out mediump vec4 fragColor;\n"
240                                             "in mediump vec4 v_position;\n"
241                                             "void main ()\n"
242                                             "{\n"
243                                             "    fragColor = vec4((v_position.x + 1.0) * 0.5, 1.0, 1.0, 1.0);\n"
244                                             "}\n";
245     const char *const fragmentSourceTex   = "#version 300 es\n"
246                                             "layout(location = 0) out mediump vec4 fragColor;\n"
247                                             "uniform mediump sampler2D u_sampler;\n"
248                                             "in mediump vec4 v_position;\n"
249                                             "void main ()\n"
250                                             "{\n"
251                                             "    fragColor = texture(u_sampler, v_position.xy);\n"
252                                             "}\n";
253     const char *const fragmentSource      = (useTexture) ? (fragmentSourceTex) : (fragmentSourceNoTex);
254     const tcu::RGBA formatThreshold       = m_context.getRenderTarget().getPixelFormat().getColorThreshold();
255 
256     tcu::Surface resultImage(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
257     tcu::Surface errorMask(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
258     bool error = false;
259 
260     m_testCtx.getLog() << tcu::TestLog::Message << "Drawing a test pattern to detect "
261                        << ((useTexture) ? ("texture sampling") : ("")) << " side-effects." << tcu::TestLog::EndMessage;
262 
263     // draw pattern
264     {
265         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
266         const glu::ShaderProgram patternProgram(m_context.getRenderContext(),
267                                                 glu::ProgramSources() << glu::VertexSource(vertexSource)
268                                                                       << glu::FragmentSource(fragmentSource));
269         const GLint positionLoc = gl.getAttribLocation(patternProgram.getProgram(), "a_pos");
270         GLuint textureID        = 0;
271 
272         if (useTexture)
273         {
274             const int textureSize = 32;
275             std::vector<tcu::Vector<uint8_t, 4>> buffer(textureSize * textureSize);
276 
277             for (int x = 0; x < textureSize; ++x)
278                 for (int y = 0; y < textureSize; ++y)
279                 {
280                     // sum of two axis aligned gradients. Each gradient is 127 at the edges and 0 at the center.
281                     // pattern is symmetric (x and y) => no discontinuity near boundary => no need to worry of results with LINEAR filtering near boundaries
282                     const uint8_t redComponent =
283                         (uint8_t)de::clamp(de::abs((float)x / (float)textureSize - 0.5f) * 255.0f +
284                                                de::abs((float)y / (float)textureSize - 0.5f) * 255.0f,
285                                            0.0f, 255.0f);
286 
287                     buffer[x * textureSize + y] = tcu::Vector<uint8_t, 4>(redComponent, 255, 255, 255);
288                 }
289 
290             gl.genTextures(1, &textureID);
291             gl.bindTexture(GL_TEXTURE_2D, textureID);
292             gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, textureSize, textureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
293                           buffer[0].getPtr());
294             gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
295             gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
296         }
297 
298         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
299         gl.clear(GL_COLOR_BUFFER_BIT);
300         gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
301         gl.useProgram(patternProgram.getProgram());
302 
303         if (useTexture)
304             gl.uniform1i(gl.getUniformLocation(patternProgram.getProgram(), "u_sampler"), 0);
305 
306         gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &fullscreenQuad[0]);
307 
308         gl.enableVertexAttribArray(positionLoc);
309         gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
310         gl.disableVertexAttribArray(positionLoc);
311 
312         gl.useProgram(0);
313         gl.finish();
314         GLU_EXPECT_NO_ERROR(gl.getError(), "RenderCase::drawTestPattern");
315 
316         if (textureID)
317             gl.deleteTextures(1, &textureID);
318 
319         glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
320     }
321 
322     // verify pattern
323     for (int y = 0; y < TEST_CANVAS_SIZE; ++y)
324         for (int x = 0; x < TEST_CANVAS_SIZE; ++x)
325         {
326             const float texGradientPosX   = deFloatFrac((float)x * 2.0f / (float)TEST_CANVAS_SIZE);
327             const float texGradientPosY   = deFloatFrac((float)y * 2.0f / (float)TEST_CANVAS_SIZE);
328             const uint8_t texRedComponent = (uint8_t)de::clamp(
329                 de::abs(texGradientPosX - 0.5f) * 255.0f + de::abs(texGradientPosY - 0.5f) * 255.0f, 0.0f, 255.0f);
330 
331             const tcu::RGBA refColTexture = tcu::RGBA(texRedComponent, 255, 255, 255);
332             const tcu::RGBA refColGradient =
333                 tcu::RGBA((int)((float)x / (float)TEST_CANVAS_SIZE * 255.0f), 255, 255, 255);
334             const tcu::RGBA &refCol = (useTexture) ? (refColTexture) : (refColGradient);
335 
336             const int colorThreshold   = 10;
337             const tcu::RGBA col        = resultImage.getPixel(x, y);
338             const tcu::IVec4 colorDiff = tcu::abs(col.toIVec() - refCol.toIVec());
339 
340             if (colorDiff.x() > formatThreshold.getRed() + colorThreshold ||
341                 colorDiff.y() > formatThreshold.getGreen() + colorThreshold ||
342                 colorDiff.z() > formatThreshold.getBlue() + colorThreshold)
343             {
344                 errorMask.setPixel(x, y, tcu::RGBA::red());
345                 error = true;
346             }
347             else
348                 errorMask.setPixel(x, y, tcu::RGBA::green());
349         }
350 
351     // report error
352     if (error)
353     {
354         m_testCtx.getLog() << tcu::TestLog::Message << "Test pattern has missing/invalid pixels"
355                            << tcu::TestLog::EndMessage;
356         m_testCtx.getLog() << tcu::TestLog::ImageSet("Results", "Result verification")
357                            << tcu::TestLog::Image("Result", "Result", resultImage)
358                            << tcu::TestLog::Image("Error mask", "Error mask", errorMask) << tcu::TestLog::EndImageSet;
359     }
360     else
361         m_testCtx.getLog() << tcu::TestLog::Message << "No side-effects found." << tcu::TestLog::EndMessage;
362 
363     return !error;
364 }
365 
366 class FramebufferRenderCase : public RenderCase
367 {
368 public:
369     enum FrameBufferType
370     {
371         FBO_DEFAULT = 0,
372         FBO_RGBA4,
373         FBO_RGB5_A1,
374         FBO_RGB565,
375         FBO_RGBA8,
376         FBO_RGB10_A2,
377         FBO_RGBA_FLOAT16,
378         FBO_RGBA_FLOAT32,
379 
380         FBO_LAST
381     };
382 
383     FramebufferRenderCase(Context &context, const char *name, const char *desc, FrameBufferType fboType);
384     virtual ~FramebufferRenderCase(void);
385 
386     virtual void init(void);
387     virtual void deinit(void);
388     IterateResult iterate(void);
389 
390     virtual void testFBO(void) = DE_NULL;
391 
392 protected:
393     const FrameBufferType m_fboType;
394 
395 private:
396     GLuint m_texID;
397     GLuint m_fboID;
398 };
399 
FramebufferRenderCase(Context & context,const char * name,const char * desc,FrameBufferType fboType)400 FramebufferRenderCase::FramebufferRenderCase(Context &context, const char *name, const char *desc,
401                                              FrameBufferType fboType)
402     : RenderCase(context, name, desc, (fboType == FBO_DEFAULT) ? (RENDERTARGETTYPE_SCREEN) : (RENDERTARGETTYPE_FBO))
403     , m_fboType(fboType)
404     , m_texID(0)
405     , m_fboID(0)
406 {
407     DE_ASSERT(m_fboType < FBO_LAST);
408 }
409 
~FramebufferRenderCase(void)410 FramebufferRenderCase::~FramebufferRenderCase(void)
411 {
412     deinit();
413 }
414 
init(void)415 void FramebufferRenderCase::init(void)
416 {
417     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
418 
419     // check requirements
420     if (m_fboType == FBO_RGBA_FLOAT16)
421     {
422         if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_color_buffer_half_float") &&
423             !m_context.getContextInfo().isExtensionSupported("GL_EXT_color_buffer_float"))
424             throw tcu::NotSupportedError("Color renderable half float texture required.");
425     }
426     else if (m_fboType == FBO_RGBA_FLOAT32)
427     {
428         if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_color_buffer_float"))
429             throw tcu::NotSupportedError("Color renderable float texture required.");
430     }
431 
432     // gen shader
433     RenderCase::init();
434 
435     // create render target
436     if (m_fboType == FBO_DEFAULT)
437     {
438         m_testCtx.getLog() << tcu::TestLog::Message << "Using default framebuffer." << tcu::TestLog::EndMessage;
439     }
440     else
441     {
442         GLuint internalFormat = 0;
443         GLuint format         = 0;
444         GLuint type           = 0;
445 
446         switch (m_fboType)
447         {
448         case FBO_RGBA4:
449             internalFormat = GL_RGBA4;
450             format         = GL_RGBA;
451             type           = GL_UNSIGNED_SHORT_4_4_4_4;
452             break;
453         case FBO_RGB5_A1:
454             internalFormat = GL_RGB5_A1;
455             format         = GL_RGBA;
456             type           = GL_UNSIGNED_SHORT_5_5_5_1;
457             break;
458         case FBO_RGB565:
459             internalFormat = GL_RGB565;
460             format         = GL_RGB;
461             type           = GL_UNSIGNED_SHORT_5_6_5;
462             break;
463         case FBO_RGBA8:
464             internalFormat = GL_RGBA8;
465             format         = GL_RGBA;
466             type           = GL_UNSIGNED_BYTE;
467             break;
468         case FBO_RGB10_A2:
469             internalFormat = GL_RGB10_A2;
470             format         = GL_RGBA;
471             type           = GL_UNSIGNED_INT_2_10_10_10_REV;
472             break;
473         case FBO_RGBA_FLOAT16:
474             internalFormat = GL_RGBA16F;
475             format         = GL_RGBA;
476             type           = GL_HALF_FLOAT;
477             break;
478         case FBO_RGBA_FLOAT32:
479             internalFormat = GL_RGBA32F;
480             format         = GL_RGBA;
481             type           = GL_FLOAT;
482             break;
483 
484         default:
485             DE_ASSERT(false);
486             break;
487         }
488 
489         m_testCtx.getLog() << tcu::TestLog::Message
490                            << "Creating fbo. Texture internalFormat = " << glu::getTextureFormatStr(internalFormat)
491                            << ", format = " << glu::getTextureFormatStr(format) << ", type = " << glu::getTypeStr(type)
492                            << tcu::TestLog::EndMessage;
493 
494         // gen texture
495         gl.genTextures(1, &m_texID);
496         gl.bindTexture(GL_TEXTURE_2D, m_texID);
497         gl.texImage2D(GL_TEXTURE_2D, 0, internalFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE, 0, format, type, DE_NULL);
498         GLU_EXPECT_NO_ERROR(gl.getError(), "texture init");
499 
500         // gen fbo
501         gl.genFramebuffers(1, &m_fboID);
502         gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
503         gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texID, 0);
504         GLU_EXPECT_NO_ERROR(gl.getError(), "fbo init");
505 
506         if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
507             throw tcu::NotSupportedError("could not create fbo for testing.");
508     }
509 }
510 
deinit(void)511 void FramebufferRenderCase::deinit(void)
512 {
513     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
514 
515     if (m_texID)
516     {
517         gl.deleteTextures(1, &m_texID);
518         m_texID = 0;
519     }
520 
521     if (m_fboID)
522     {
523         gl.deleteFramebuffers(1, &m_fboID);
524         m_fboID = 0;
525     }
526 }
527 
iterate(void)528 FramebufferRenderCase::IterateResult FramebufferRenderCase::iterate(void)
529 {
530     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
531 
532     // bind fbo (or don't if we are using default)
533     if (m_fboID)
534         gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
535 
536     // do something with special floats
537     testFBO();
538 
539     return STOP;
540 }
541 
542 /*--------------------------------------------------------------------*//*!
543  * \brief Tests special floats as vertex attributes
544  *
545  * Tests that special floats transferred to the shader using vertex
546  * attributes do not change the results of normal floating point
547  * calculations. Special floats are put to 4-vector's x and y components and
548  * value 1.0 is put to z and w. The resulting fragment's green channel
549  * should be 1.0 everywhere.
550  *
551  * After the calculation test a test pattern is drawn to detect possible
552  * floating point operation anomalies.
553  *//*--------------------------------------------------------------------*/
554 class VertexAttributeCase : public RenderCase
555 {
556 public:
557     enum Storage
558     {
559         STORAGE_BUFFER = 0,
560         STORAGE_CLIENT,
561 
562         STORAGE_LAST
563     };
564     enum ShaderType
565     {
566         TYPE_VERTEX = 0,
567         TYPE_FRAGMENT,
568 
569         TYPE_LAST
570     };
571 
572     VertexAttributeCase(Context &context, const char *name, const char *desc, Storage storage, ShaderType type);
573     ~VertexAttributeCase(void);
574 
575     void init(void);
576     void deinit(void);
577     IterateResult iterate(void);
578 
579 private:
580     std::string genVertexSource(void) const;
581     std::string genFragmentSource(void) const;
582 
583     const Storage m_storage;
584     const ShaderType m_type;
585     GLuint m_positionVboID;
586     GLuint m_attribVboID;
587     GLuint m_elementVboID;
588 };
589 
VertexAttributeCase(Context & context,const char * name,const char * desc,Storage storage,ShaderType type)590 VertexAttributeCase::VertexAttributeCase(Context &context, const char *name, const char *desc, Storage storage,
591                                          ShaderType type)
592     : RenderCase(context, name, desc)
593     , m_storage(storage)
594     , m_type(type)
595     , m_positionVboID(0)
596     , m_attribVboID(0)
597     , m_elementVboID(0)
598 {
599     DE_ASSERT(storage < STORAGE_LAST);
600     DE_ASSERT(type < TYPE_LAST);
601 }
602 
~VertexAttributeCase(void)603 VertexAttributeCase::~VertexAttributeCase(void)
604 {
605     deinit();
606 }
607 
init(void)608 void VertexAttributeCase::init(void)
609 {
610     RenderCase::init();
611 
612     // init gl resources
613     if (m_storage == STORAGE_BUFFER)
614     {
615         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
616 
617         gl.genBuffers(1, &m_positionVboID);
618         gl.genBuffers(1, &m_attribVboID);
619         gl.genBuffers(1, &m_elementVboID);
620     }
621 }
622 
deinit(void)623 void VertexAttributeCase::deinit(void)
624 {
625     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
626 
627     RenderCase::deinit();
628 
629     if (m_attribVboID)
630     {
631         gl.deleteBuffers(1, &m_attribVboID);
632         m_attribVboID = 0;
633     }
634 
635     if (m_positionVboID)
636     {
637         gl.deleteBuffers(1, &m_positionVboID);
638         m_positionVboID = 0;
639     }
640 
641     if (m_elementVboID)
642     {
643         gl.deleteBuffers(1, &m_elementVboID);
644         m_elementVboID = 0;
645     }
646 }
647 
iterate(void)648 VertexAttributeCase::IterateResult VertexAttributeCase::iterate(void)
649 {
650     // Create a [s_specialFloats] X [s_specialFloats] grid of vertices with each vertex having 2 [s_specialFloats] values
651     // and calculate some basic operations with the floating point values. If all goes well, nothing special should happen
652 
653     std::vector<tcu::Vec4> gridVertices(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
654     std::vector<tcu::UVec4> gridAttributes(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
655     std::vector<uint16_t> indices((DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) *
656                                   (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * 6);
657     tcu::Surface resultImage(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
658 
659     // vertices
660     for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
661         for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
662         {
663             const uint32_t one = 0x3F800000;
664             const float posX   = (float)x / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f -
665                                1.0f; // map from [0, len(s_specialFloats) - 1] to [-1, 1]
666             const float posY = (float)y / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f;
667 
668             gridVertices[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
669             gridAttributes[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y] =
670                 tcu::UVec4(s_specialFloats[x], s_specialFloats[y], one, one);
671         }
672 
673     // tiles
674     for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++x)
675         for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++y)
676         {
677             const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) + y) * 6;
678 
679             indices[baseNdx + 0] = (uint16_t)((x + 0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 0));
680             indices[baseNdx + 1] = (uint16_t)((x + 1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 1));
681             indices[baseNdx + 2] = (uint16_t)((x + 1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 0));
682 
683             indices[baseNdx + 3] = (uint16_t)((x + 0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 0));
684             indices[baseNdx + 4] = (uint16_t)((x + 1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 1));
685             indices[baseNdx + 5] = (uint16_t)((x + 0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 1));
686         }
687 
688     m_testCtx.getLog() << tcu::TestLog::Message
689                        << "Drawing a grid with the shader. Setting a_attr for each vertex to (special, special, 1, 1)."
690                        << tcu::TestLog::EndMessage;
691 
692     // Draw grid
693     {
694         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
695         const GLint positionLoc  = gl.getAttribLocation(m_program->getProgram(), "a_pos");
696         const GLint attribLoc    = gl.getAttribLocation(m_program->getProgram(), "a_attr");
697 
698         if (m_storage == STORAGE_BUFFER)
699         {
700             gl.bindBuffer(GL_ARRAY_BUFFER, m_positionVboID);
701             gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(gridVertices.size() * sizeof(tcu::Vec4)), &gridVertices[0],
702                           GL_STATIC_DRAW);
703             GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
704 
705             gl.bindBuffer(GL_ARRAY_BUFFER, m_attribVboID);
706             gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(gridAttributes.size() * sizeof(tcu::UVec4)),
707                           &gridAttributes[0], GL_STATIC_DRAW);
708             GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
709 
710             gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementVboID);
711             gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(indices.size() * sizeof(uint16_t)), &indices[0],
712                           GL_STATIC_DRAW);
713             GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
714         }
715 
716         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
717         gl.clear(GL_COLOR_BUFFER_BIT);
718         gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
719         gl.useProgram(m_program->getProgram());
720 
721         if (m_storage == STORAGE_BUFFER)
722         {
723             gl.bindBuffer(GL_ARRAY_BUFFER, m_positionVboID);
724             gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
725 
726             gl.bindBuffer(GL_ARRAY_BUFFER, m_attribVboID);
727             gl.vertexAttribPointer(attribLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
728 
729             gl.enableVertexAttribArray(positionLoc);
730             gl.enableVertexAttribArray(attribLoc);
731             gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, DE_NULL);
732             gl.disableVertexAttribArray(positionLoc);
733             gl.disableVertexAttribArray(attribLoc);
734 
735             gl.bindBuffer(GL_ARRAY_BUFFER, 0);
736             gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
737         }
738         else if (m_storage == STORAGE_CLIENT)
739         {
740             gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
741             gl.vertexAttribPointer(attribLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridAttributes[0]);
742 
743             gl.enableVertexAttribArray(positionLoc);
744             gl.enableVertexAttribArray(attribLoc);
745             gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, &indices[0]);
746             gl.disableVertexAttribArray(positionLoc);
747             gl.disableVertexAttribArray(attribLoc);
748         }
749         else
750             DE_ASSERT(false);
751 
752         gl.useProgram(0);
753         gl.finish();
754         GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttributeCase::iterate");
755 
756         glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
757     }
758 
759     // verify everywhere was drawn (all pixels have Green = 255)
760     if (!checkResultImage(resultImage))
761     {
762         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments");
763         return STOP;
764     }
765 
766     // test drawing still works
767     if (!drawTestPattern(false))
768     {
769         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed");
770         return STOP;
771     }
772 
773     // all ok
774     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
775     return STOP;
776 }
777 
genVertexSource(void) const778 std::string VertexAttributeCase::genVertexSource(void) const
779 {
780     if (m_type == TYPE_VERTEX)
781         return "#version 300 es\n"
782                "in highp vec4 a_pos;\n"
783                "in highp vec4 a_attr;\n"
784                "out mediump vec4 v_out;\n"
785                "void main ()\n"
786                "{\n"
787                "    highp vec2 a1 = a_attr.xz + a_attr.yw; // add\n"
788                "    highp vec2 a2 = a_attr.xz - a_attr.yw; // sub\n"
789                "    highp vec2 a3 = a_attr.xz * a_attr.yw; // mul\n"
790                "    highp vec2 a4 = a_attr.xz / a_attr.yw; // div\n"
791                "    highp vec2 a5 = a_attr.xz + a_attr.yw * a_attr.xz; // fma\n"
792                "\n"
793                "    highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y) - 6.0);\n"
794                "    v_out = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x, 1.0);\n"
795                "    gl_Position = a_pos;\n"
796                "}\n";
797     else
798         return s_attrPassthroughVertexShaderSource;
799 }
800 
genFragmentSource(void) const801 std::string VertexAttributeCase::genFragmentSource(void) const
802 {
803     if (m_type == TYPE_VERTEX)
804         return s_colorPassthroughFragmentShaderSource;
805     else
806         return "#version 300 es\n"
807                "layout(location = 0) out mediump vec4 fragColor;\n"
808                "in highp vec4 v_attr;\n"
809                "void main ()\n"
810                "{\n"
811                "    highp vec2 a1 = v_attr.xz + v_attr.yw; // add\n"
812                "    highp vec2 a2 = v_attr.xz - v_attr.yw; // sub\n"
813                "    highp vec2 a3 = v_attr.xz * v_attr.yw; // mul\n"
814                "    highp vec2 a4 = v_attr.xz / v_attr.yw; // div\n"
815                "    highp vec2 a5 = v_attr.xz + v_attr.yw * v_attr.xz; // fma\n"
816                "    highp vec2 a6 = dFdx(v_attr.xz);\n"
817                "\n"
818                "    highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y + a6.y) - 6.0);\n"
819                "    fragColor = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x+a6.x, 1.0);\n"
820                "}\n";
821 }
822 
823 /*--------------------------------------------------------------------*//*!
824  * \brief Tests special floats as uniforms
825  *
826  * Tests that special floats transferred to the shader as uniforms do
827  * not change the results of normal floating point calculations. Special
828  * floats are put to 4-vector's x and y components and value 1.0 is put to
829  * z and w. The resulting fragment's green channel should be 1.0
830  * everywhere.
831  *
832  * After the calculation test a test pattern is drawn to detect possible
833  * floating point operation anomalies.
834  *//*--------------------------------------------------------------------*/
835 class UniformCase : public RenderCase
836 {
837 public:
838     enum ShaderType
839     {
840         TYPE_VERTEX = 0,
841         TYPE_FRAGMENT,
842     };
843 
844     UniformCase(Context &context, const char *name, const char *desc, ShaderType type);
845     ~UniformCase(void);
846 
847     void init(void);
848     void deinit(void);
849     IterateResult iterate(void);
850 
851 private:
852     std::string genVertexSource(void) const;
853     std::string genFragmentSource(void) const;
854 
855     const ShaderType m_type;
856 };
857 
UniformCase(Context & context,const char * name,const char * desc,ShaderType type)858 UniformCase::UniformCase(Context &context, const char *name, const char *desc, ShaderType type)
859     : RenderCase(context, name, desc)
860     , m_type(type)
861 {
862 }
863 
~UniformCase(void)864 UniformCase::~UniformCase(void)
865 {
866     deinit();
867 }
868 
init(void)869 void UniformCase::init(void)
870 {
871     RenderCase::init();
872 }
873 
deinit(void)874 void UniformCase::deinit(void)
875 {
876     RenderCase::deinit();
877 }
878 
iterate(void)879 UniformCase::IterateResult UniformCase::iterate(void)
880 {
881     // Create a [s_specialFloats] X [s_specialFloats] grid of tile with each tile having 2 [s_specialFloats] values
882     // and calculate some basic operations with the floating point values. If all goes well, nothing special should happen
883 
884     std::vector<tcu::Vec4> gridVertices((DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) *
885                                         (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1));
886     std::vector<uint16_t> indices(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats) * 6);
887     tcu::Surface resultImage(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
888 
889     // vertices
890     for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++x)
891         for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++y)
892         {
893             const float posX = (float)x / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f -
894                                1.0f; // map from [0, len(s_specialFloats) ] to [-1, 1]
895             const float posY = (float)y / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f - 1.0f;
896 
897             gridVertices[x * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + y] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
898         }
899 
900     // tiles
901     for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
902         for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
903         {
904             const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats)) + y) * 6;
905 
906             indices[baseNdx + 0] = (uint16_t)((x + 0) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y + 0));
907             indices[baseNdx + 1] = (uint16_t)((x + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y + 1));
908             indices[baseNdx + 2] = (uint16_t)((x + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y + 0));
909 
910             indices[baseNdx + 3] = (uint16_t)((x + 0) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y + 0));
911             indices[baseNdx + 4] = (uint16_t)((x + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y + 1));
912             indices[baseNdx + 5] = (uint16_t)((x + 0) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) + (y + 1));
913         }
914 
915     m_testCtx.getLog()
916         << tcu::TestLog::Message
917         << "Drawing a grid with the shader. Setting u_special for vertex each tile to (special, special, 1, 1)."
918         << tcu::TestLog::EndMessage;
919 
920     // Draw grid
921     {
922         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
923         const GLint positionLoc  = gl.getAttribLocation(m_program->getProgram(), "a_pos");
924         const GLint specialLoc   = gl.getUniformLocation(m_program->getProgram(), "u_special");
925 
926         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
927         gl.clear(GL_COLOR_BUFFER_BIT);
928         gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
929         gl.useProgram(m_program->getProgram());
930 
931         gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
932         gl.enableVertexAttribArray(positionLoc);
933 
934         for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
935             for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
936             {
937                 const uint32_t one            = 0x3F800000;
938                 const tcu::UVec4 uniformValue = tcu::UVec4(s_specialFloats[x], s_specialFloats[y], one, one);
939                 const int indexIndex          = (x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y) * 6;
940 
941                 gl.uniform4fv(specialLoc, 1, (const float *)uniformValue.getPtr());
942                 gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[indexIndex]);
943             }
944 
945         gl.disableVertexAttribArray(positionLoc);
946 
947         gl.useProgram(0);
948         gl.finish();
949         GLU_EXPECT_NO_ERROR(gl.getError(), "UniformCase::iterate");
950 
951         glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
952     }
953 
954     // verify everywhere was drawn (all pixels have Green = 255)
955     if (!checkResultImage(resultImage))
956     {
957         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments");
958         return STOP;
959     }
960 
961     // test drawing still works
962     if (!drawTestPattern(false))
963     {
964         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed");
965         return STOP;
966     }
967 
968     // all ok
969     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
970     return STOP;
971 }
972 
genVertexSource(void) const973 std::string UniformCase::genVertexSource(void) const
974 {
975     if (m_type == TYPE_VERTEX)
976         return "#version 300 es\n"
977                "in highp vec4 a_pos;\n"
978                "uniform highp vec4 u_special;\n"
979                "out mediump vec4 v_out;\n"
980                "void main ()\n"
981                "{\n"
982                "    highp vec2 a1 = u_special.xz + u_special.yw; // add\n"
983                "    highp vec2 a2 = u_special.xz - u_special.yw; // sub\n"
984                "    highp vec2 a3 = u_special.xz * u_special.yw; // mul\n"
985                "    highp vec2 a4 = u_special.xz / u_special.yw; // div\n"
986                "    highp vec2 a5 = u_special.xz + u_special.yw * u_special.xz; // fma\n"
987                "\n"
988                "    highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y) - 6.0);\n"
989                "    v_out = vec4(a1.x*a3.x + a2.x*a4.x, green, a5.x, 1.0);\n"
990                "    gl_Position = a_pos;\n"
991                "}\n";
992     else
993         return "#version 300 es\n"
994                "in highp vec4 a_pos;\n"
995                "void main ()\n"
996                "{\n"
997                "    gl_Position = a_pos;\n"
998                "}\n";
999 }
1000 
genFragmentSource(void) const1001 std::string UniformCase::genFragmentSource(void) const
1002 {
1003     if (m_type == TYPE_VERTEX)
1004         return s_colorPassthroughFragmentShaderSource;
1005     else
1006         return "#version 300 es\n"
1007                "layout(location = 0) out mediump vec4 fragColor;\n"
1008                "uniform highp vec4 u_special;\n"
1009                "void main ()\n"
1010                "{\n"
1011                "    highp vec2 a1 = u_special.xz + u_special.yw; // add\n"
1012                "    highp vec2 a2 = u_special.xz - u_special.yw; // sub\n"
1013                "    highp vec2 a3 = u_special.xz * u_special.yw; // mul\n"
1014                "    highp vec2 a4 = u_special.xz / u_special.yw; // div\n"
1015                "    highp vec2 a5 = u_special.xz + u_special.yw * u_special.xz; // fma\n"
1016                "    highp vec2 a6 = mod(u_special.xz, u_special.yw);\n"
1017                "    highp vec2 a7 = mix(u_special.xz, u_special.yw, a6);\n"
1018                "\n"
1019                "    highp float green = 1.0 - abs((a1.y + a2.y + a3.y + a4.y + a5.y + a6.y + a7.y) - 7.0);\n"
1020                "    fragColor = vec4(a1.x*a3.x, green, a5.x*a4.x + a2.x*a7.x, 1.0);\n"
1021                "}\n";
1022 }
1023 
1024 /*--------------------------------------------------------------------*//*!
1025  * \brief Tests special floats in floating point textures
1026  *
1027  * Tests that sampling special floats from a floating point texture
1028  * does not affect the values of other color components of the sample. Test
1029  * samples a RG texture with R channel filled with special floats and G
1030  * channel filled with test values.
1031  *
1032  * Tests that linear sampling using compare mode = COMPARE_REF_TO_TEXTURE
1033  * of a floating point depth texture containing special floating point
1034  * values does not produce values outside the [0, 1] range.
1035  *
1036  * After the calculation test a test pattern is drawn to detect possible
1037  * texture sampling anomalies.
1038  *//*--------------------------------------------------------------------*/
1039 class TextureCase : public RenderCase
1040 {
1041 public:
1042     enum ShaderType
1043     {
1044         TYPE_VERTEX = 0,
1045         TYPE_FRAGMENT,
1046 
1047         TYPE_LAST
1048     };
1049     enum TextureType
1050     {
1051         TEXTURE_FLOAT = 0,
1052         TEXTURE_DEPTH,
1053 
1054         TEXTURE_LAST
1055     };
1056     enum UploadType
1057     {
1058         UPLOAD_CLIENT = 0,
1059         UPLOAD_PBO,
1060 
1061         UPLOAD_LAST
1062     };
1063 
1064     TextureCase(Context &context, const char *name, const char *desc, ShaderType type, TextureType texType,
1065                 UploadType uploadType);
1066     ~TextureCase(void);
1067 
1068     void init(void);
1069     void deinit(void);
1070     IterateResult iterate(void);
1071 
1072 private:
1073     std::string genVertexSource(void) const;
1074     std::string genFragmentSource(void) const;
1075 
1076     const ShaderType m_type;
1077     const TextureType m_textureType;
1078     const UploadType m_uploadType;
1079     GLuint m_textureID;
1080     GLuint m_pboID;
1081 };
1082 
TextureCase(Context & context,const char * name,const char * desc,ShaderType type,TextureType texType,UploadType uploadType)1083 TextureCase::TextureCase(Context &context, const char *name, const char *desc, ShaderType type, TextureType texType,
1084                          UploadType uploadType)
1085     : RenderCase(context, name, desc)
1086     , m_type(type)
1087     , m_textureType(texType)
1088     , m_uploadType(uploadType)
1089     , m_textureID(0)
1090     , m_pboID(0)
1091 {
1092     DE_ASSERT(type < TYPE_LAST);
1093     DE_ASSERT(texType < TEXTURE_LAST);
1094     DE_ASSERT(uploadType < UPLOAD_LAST);
1095 }
1096 
~TextureCase(void)1097 TextureCase::~TextureCase(void)
1098 {
1099     deinit();
1100 }
1101 
init(void)1102 void TextureCase::init(void)
1103 {
1104     // requirements
1105     {
1106         GLint maxTextureSize = 0;
1107         m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
1108         if (maxTextureSize < TEST_TEXTURE_SIZE)
1109             throw tcu::NotSupportedError(std::string("GL_MAX_TEXTURE_SIZE must be at least ") +
1110                                          de::toString(TEST_TEXTURE_SIZE));
1111     }
1112 
1113     RenderCase::init();
1114 
1115     // gen texture
1116     {
1117         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1118         de::Random rnd(12345);
1119 
1120         gl.genTextures(1, &m_textureID);
1121         gl.bindTexture(GL_TEXTURE_2D, m_textureID);
1122 
1123         if (m_uploadType == UPLOAD_PBO)
1124         {
1125             gl.genBuffers(1, &m_pboID);
1126             gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, m_pboID);
1127             GLU_EXPECT_NO_ERROR(gl.getError(), "TextureCase::init");
1128         }
1129 
1130         if (m_textureType == TEXTURE_FLOAT)
1131         {
1132             std::vector<uint32_t> texData(TEST_TEXTURE_SIZE * TEST_TEXTURE_SIZE * 2);
1133             const uint32_t *dataPtr = (m_uploadType == UPLOAD_CLIENT) ? (&texData[0]) : (DE_NULL);
1134 
1135             m_testCtx.getLog() << tcu::TestLog::Message
1136                                << "Creating a 2D 2-component float texture. Pixel contents are of form (special, 1)."
1137                                << tcu::TestLog::EndMessage;
1138 
1139             // set green channel to 1.0
1140             for (int x = 0; x < TEST_TEXTURE_SIZE; ++x)
1141                 for (int y = 0; y < TEST_TEXTURE_SIZE; ++y)
1142                 {
1143                     texData[(x * TEST_TEXTURE_SIZE + y) * 2 + 0] =
1144                         rnd.choose<uint32_t>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
1145                     texData[(x * TEST_TEXTURE_SIZE + y) * 2 + 1] = 0x3F800000; // one
1146                 }
1147 
1148             if (m_uploadType == UPLOAD_PBO)
1149                 gl.bufferData(GL_PIXEL_UNPACK_BUFFER, (glw::GLsizeiptr)(texData.size() * sizeof(uint32_t)), &texData[0],
1150                               GL_STATIC_DRAW);
1151 
1152             gl.texImage2D(GL_TEXTURE_2D, 0, GL_RG32F, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, 0, GL_RG, GL_FLOAT,
1153                           dataPtr);
1154             gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1155             gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1156             GLU_EXPECT_NO_ERROR(gl.getError(), "TextureCase::init");
1157         }
1158         else if (m_textureType == TEXTURE_DEPTH)
1159         {
1160             std::vector<uint32_t> texData(TEST_TEXTURE_SIZE * TEST_TEXTURE_SIZE);
1161             const uint32_t *dataPtr = (m_uploadType == UPLOAD_CLIENT) ? (&texData[0]) : (DE_NULL);
1162 
1163             m_testCtx.getLog() << tcu::TestLog::Message
1164                                << "Creating a 2D depth texture and filling it with special floating point values.\n"
1165                                << "  TEXTURE_COMPARE_MODE = COMPARE_REF_TO_TEXTURE" << tcu::TestLog::EndMessage;
1166 
1167             for (int x = 0; x < TEST_TEXTURE_SIZE; ++x)
1168                 for (int y = 0; y < TEST_TEXTURE_SIZE; ++y)
1169                     texData[x * TEST_TEXTURE_SIZE + y] =
1170                         rnd.choose<uint32_t>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
1171 
1172             if (m_uploadType == UPLOAD_PBO)
1173                 gl.bufferData(GL_PIXEL_UNPACK_BUFFER, (glw::GLsizeiptr)(texData.size() * sizeof(uint32_t)), &texData[0],
1174                               GL_STATIC_DRAW);
1175 
1176             gl.texImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, 0,
1177                           GL_DEPTH_COMPONENT, GL_FLOAT, dataPtr);
1178             gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
1179             gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
1180             gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1181             gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1182             GLU_EXPECT_NO_ERROR(gl.getError(), "TextureCase::init");
1183         }
1184         else
1185             DE_ASSERT(false);
1186 
1187         if (m_uploadType == UPLOAD_PBO)
1188         {
1189             m_testCtx.getLog() << tcu::TestLog::Message << "PBO used for image upload." << tcu::TestLog::EndMessage;
1190 
1191             gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1192             gl.deleteBuffers(1, &m_pboID);
1193             m_pboID = 0;
1194         }
1195     }
1196 }
1197 
deinit(void)1198 void TextureCase::deinit(void)
1199 {
1200     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1201 
1202     RenderCase::deinit();
1203 
1204     if (m_textureID)
1205     {
1206         gl.deleteTextures(1, &m_textureID);
1207         m_textureID = 0;
1208     }
1209     if (m_pboID)
1210     {
1211         gl.deleteBuffers(1, &m_pboID);
1212         m_pboID = 0;
1213     }
1214 }
1215 
iterate(void)1216 TextureCase::IterateResult TextureCase::iterate(void)
1217 {
1218     // Draw a grid and texture it with a floating point texture containing special values. If all goes well, nothing special should happen
1219 
1220     const int gridSize = 16;
1221     std::vector<tcu::Vec4> gridVertices(gridSize * gridSize);
1222     std::vector<tcu::Vec2> gridTexCoords(gridSize * gridSize);
1223     std::vector<uint16_t> indices((gridSize - 1) * (gridSize - 1) * 6);
1224     tcu::Surface resultImage(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1225 
1226     // vertices
1227     for (int x = 0; x < gridSize; ++x)
1228         for (int y = 0; y < gridSize; ++y)
1229         {
1230             const float posX =
1231                 (float)x / ((float)gridSize - 1.0f) * 2.0f - 1.0f; // map from [0, gridSize - 1] to [-1, 1]
1232             const float posY      = (float)y / ((float)gridSize - 1.0f) * 2.0f - 1.0f;
1233             const float texCoordX = deFloatPow(2.0f, (float)x - (float)gridSize / 2.0f);
1234             const float texCoordY = deFloatPow(2.0f, (float)y - (float)gridSize / 2.0f);
1235 
1236             gridVertices[x * gridSize + y]  = tcu::Vec4(posX, posY, 0.0f, 1.0f);
1237             gridTexCoords[x * gridSize + y] = tcu::Vec2(texCoordX, texCoordY);
1238         }
1239 
1240     // tiles
1241     for (int x = 0; x < gridSize - 1; ++x)
1242         for (int y = 0; y < gridSize - 1; ++y)
1243         {
1244             const int baseNdx = (x * (gridSize - 1) + y) * 6;
1245 
1246             indices[baseNdx + 0] = (uint16_t)((x + 0) * gridSize + (y + 0));
1247             indices[baseNdx + 1] = (uint16_t)((x + 1) * gridSize + (y + 1));
1248             indices[baseNdx + 2] = (uint16_t)((x + 1) * gridSize + (y + 0));
1249 
1250             indices[baseNdx + 3] = (uint16_t)((x + 0) * gridSize + (y + 0));
1251             indices[baseNdx + 4] = (uint16_t)((x + 1) * gridSize + (y + 1));
1252             indices[baseNdx + 5] = (uint16_t)((x + 0) * gridSize + (y + 1));
1253         }
1254 
1255     m_testCtx.getLog() << tcu::TestLog::Message << "Drawing a textured grid with the shader."
1256                        << tcu::TestLog::EndMessage;
1257 
1258     // Draw grid
1259     {
1260         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1261         const GLint positionLoc  = gl.getAttribLocation(m_program->getProgram(), "a_pos");
1262         const GLint texCoordLoc  = gl.getAttribLocation(m_program->getProgram(), "a_attr");
1263         const GLint samplerLoc   = gl.getUniformLocation(m_program->getProgram(), "u_sampler");
1264 
1265         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1266         gl.clear(GL_COLOR_BUFFER_BIT);
1267         gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1268         gl.useProgram(m_program->getProgram());
1269 
1270         gl.uniform1i(samplerLoc, 0);
1271         gl.bindTexture(GL_TEXTURE_2D, m_textureID);
1272 
1273         gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
1274         gl.vertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, &gridTexCoords[0]);
1275 
1276         gl.enableVertexAttribArray(positionLoc);
1277         gl.enableVertexAttribArray(texCoordLoc);
1278         gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, &indices[0]);
1279         gl.disableVertexAttribArray(positionLoc);
1280         gl.disableVertexAttribArray(texCoordLoc);
1281 
1282         gl.useProgram(0);
1283         gl.finish();
1284         GLU_EXPECT_NO_ERROR(gl.getError(), "TextureCase::iterate");
1285 
1286         glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
1287     }
1288 
1289     // verify everywhere was drawn (all pixels have Green = 255)
1290     if (!checkResultImage(resultImage))
1291     {
1292         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments");
1293         return STOP;
1294     }
1295 
1296     // test drawing and textures still works
1297     if (!drawTestPattern(true))
1298     {
1299         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed");
1300         return STOP;
1301     }
1302 
1303     // all ok
1304     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1305     return STOP;
1306 }
1307 
genVertexSource(void) const1308 std::string TextureCase::genVertexSource(void) const
1309 {
1310     // vertex shader is passthrough, fragment does the calculations
1311     if (m_type == TYPE_FRAGMENT)
1312         return s_attrPassthroughVertexShaderSource;
1313 
1314     // vertex shader does the calculations
1315     std::ostringstream buf;
1316     buf << "#version 300 es\n"
1317            "in highp vec4 a_pos;\n"
1318            "in highp vec2 a_attr;\n"
1319            "out mediump vec4 v_out;\n";
1320 
1321     if (m_textureType == TEXTURE_FLOAT)
1322         buf << "uniform highp sampler2D u_sampler;\n";
1323     else if (m_textureType == TEXTURE_DEPTH)
1324         buf << "uniform highp sampler2DShadow u_sampler;\n";
1325     else
1326         DE_ASSERT(false);
1327 
1328     buf << "void main ()\n"
1329            "{\n";
1330 
1331     if (m_textureType == TEXTURE_FLOAT)
1332         buf << "    v_out = vec4(textureLod(u_sampler, a_attr, 0.0).rg, 1.0, 1.0);\n";
1333     else if (m_textureType == TEXTURE_DEPTH)
1334         buf << "    highp float a1 = textureLod(u_sampler, vec3(a_attr, 0.0), 0.0);\n"
1335                "    v_out = vec4(a1, (a1 > 1.0 || a1 < 0.0) ? (0.0) : (1.0), 1.0, 1.0);\n";
1336     else
1337         DE_ASSERT(false);
1338 
1339     buf << "    gl_Position = a_pos;\n"
1340            "}\n";
1341     return buf.str();
1342 }
1343 
genFragmentSource(void) const1344 std::string TextureCase::genFragmentSource(void) const
1345 {
1346     // fragment shader is passthrough
1347     if (m_type == TYPE_VERTEX)
1348         return s_colorPassthroughFragmentShaderSource;
1349 
1350     // fragment shader does the calculations
1351     std::ostringstream buf;
1352     buf << "#version 300 es\n"
1353            "layout(location = 0) out mediump vec4 fragColor;\n";
1354 
1355     if (m_textureType == TEXTURE_FLOAT)
1356         buf << "uniform highp sampler2D u_sampler;\n";
1357     else if (m_textureType == TEXTURE_DEPTH)
1358         buf << "uniform highp sampler2DShadow u_sampler;\n";
1359     else
1360         DE_ASSERT(false);
1361 
1362     buf << "in highp vec4 v_attr;\n"
1363            "void main ()\n"
1364            "{\n";
1365 
1366     if (m_textureType == TEXTURE_FLOAT)
1367         buf << "    highp vec2 a1 = texture(u_sampler, v_attr.xy).rg;\n"
1368                "    fragColor = vec4(a1.x, a1.y, 1.0, 1.0);\n";
1369     else if (m_textureType == TEXTURE_DEPTH)
1370         buf << "    highp float a1 = texture(u_sampler, vec3(v_attr.xy, 0.0));\n"
1371                "    fragColor = vec4(a1, (a1 > 1.0 || a1 < 0.0) ? (0.0) : (1.0), 1.0, 1.0);\n";
1372     else
1373         DE_ASSERT(false);
1374 
1375     buf << "}\n";
1376     return buf.str();
1377 }
1378 
1379 /*--------------------------------------------------------------------*//*!
1380  * \brief Tests special floats as texture samping arguments
1381  *
1382  * Tests that special floats given as texture coordinates or LOD levels
1383  * to sampling functions do not return invalid values (values not in the
1384  * texture). Every texel's green component is 1.0.
1385  *
1386  * After the calculation test a test pattern is drawn to detect possible
1387  * texture sampling anomalies.
1388  *//*--------------------------------------------------------------------*/
1389 class TextureSamplerCase : public RenderCase
1390 {
1391 public:
1392     enum ShaderType
1393     {
1394         TYPE_VERTEX = 0,
1395         TYPE_FRAGMENT,
1396 
1397         TYPE_LAST
1398     };
1399     enum TestType
1400     {
1401         TEST_TEX_COORD = 0,
1402         TEST_LOD,
1403         TEST_GRAD,
1404         TEST_TEX_COORD_CUBE,
1405 
1406         TEST_LAST
1407     };
1408 
1409     TextureSamplerCase(Context &context, const char *name, const char *desc, ShaderType type, TestType testType);
1410     ~TextureSamplerCase(void);
1411 
1412     void init(void);
1413     void deinit(void);
1414     IterateResult iterate(void);
1415 
1416 private:
1417     std::string genVertexSource(void) const;
1418     std::string genFragmentSource(void) const;
1419 
1420     const ShaderType m_type;
1421     const TestType m_testType;
1422     GLuint m_textureID;
1423 };
1424 
TextureSamplerCase(Context & context,const char * name,const char * desc,ShaderType type,TestType testType)1425 TextureSamplerCase::TextureSamplerCase(Context &context, const char *name, const char *desc, ShaderType type,
1426                                        TestType testType)
1427     : RenderCase(context, name, desc)
1428     , m_type(type)
1429     , m_testType(testType)
1430     , m_textureID(0)
1431 {
1432     DE_ASSERT(type < TYPE_LAST);
1433     DE_ASSERT(testType < TEST_LAST);
1434 }
1435 
~TextureSamplerCase(void)1436 TextureSamplerCase::~TextureSamplerCase(void)
1437 {
1438     deinit();
1439 }
1440 
init(void)1441 void TextureSamplerCase::init(void)
1442 {
1443     // requirements
1444     {
1445         GLint maxTextureSize = 0;
1446         m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
1447         if (maxTextureSize < TEST_TEXTURE_SIZE)
1448             throw tcu::NotSupportedError(std::string("GL_MAX_TEXTURE_SIZE must be at least ") +
1449                                          de::toString(TEST_TEXTURE_SIZE));
1450     }
1451 
1452     RenderCase::init();
1453 
1454     // gen texture
1455     {
1456         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1457         std::vector<uint8_t> texData(TEST_TEXTURE_SIZE * TEST_TEXTURE_SIZE * 4);
1458         de::Random rnd(12345);
1459 
1460         gl.genTextures(1, &m_textureID);
1461 
1462         for (int x = 0; x < TEST_TEXTURE_SIZE; ++x)
1463             for (int y = 0; y < TEST_TEXTURE_SIZE; ++y)
1464             {
1465                 // RGBA8, green and alpha channel are always 255 for verification
1466                 texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 0] = rnd.getUint32() & 0xFF;
1467                 texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 1] = 0xFF;
1468                 texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 2] = rnd.getUint32() & 0xFF;
1469                 texData[(x * TEST_TEXTURE_SIZE + y) * 4 + 3] = 0xFF;
1470             }
1471 
1472         if (m_testType == TEST_TEX_COORD)
1473         {
1474             m_testCtx.getLog() << tcu::TestLog::Message << "Creating a 2D texture with a test pattern."
1475                                << tcu::TestLog::EndMessage;
1476 
1477             gl.bindTexture(GL_TEXTURE_2D, m_textureID);
1478             gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, TEST_TEXTURE_SIZE, TEST_TEXTURE_SIZE, 0, GL_RGBA,
1479                           GL_UNSIGNED_BYTE, &texData[0]);
1480             gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1481             gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1482             GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init");
1483         }
1484         else if (m_testType == TEST_LOD || m_testType == TEST_GRAD)
1485         {
1486             m_testCtx.getLog() << tcu::TestLog::Message << "Creating a mipmapped 2D texture with a test pattern."
1487                                << tcu::TestLog::EndMessage;
1488 
1489             gl.bindTexture(GL_TEXTURE_2D, m_textureID);
1490 
1491             for (int level = 0; (TEST_TEXTURE_SIZE >> level); ++level)
1492                 gl.texImage2D(GL_TEXTURE_2D, level, GL_RGBA8, TEST_TEXTURE_SIZE >> level, TEST_TEXTURE_SIZE >> level, 0,
1493                               GL_RGBA, GL_UNSIGNED_BYTE, &texData[0]);
1494 
1495             gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1496             gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
1497             GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init");
1498         }
1499         else if (m_testType == TEST_TEX_COORD_CUBE)
1500         {
1501             DE_STATIC_ASSERT(TEST_TEXTURE_CUBE_SIZE <= TEST_TEXTURE_SIZE);
1502 
1503             static const GLenum faces[] = {
1504                 GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
1505                 GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
1506             };
1507 
1508             m_testCtx.getLog() << tcu::TestLog::Message << "Creating a cube map with a test pattern."
1509                                << tcu::TestLog::EndMessage;
1510 
1511             gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textureID);
1512 
1513             for (int faceNdx = 0; faceNdx < DE_LENGTH_OF_ARRAY(faces); ++faceNdx)
1514                 gl.texImage2D(faces[faceNdx], 0, GL_RGBA8, TEST_TEXTURE_CUBE_SIZE, TEST_TEXTURE_CUBE_SIZE, 0, GL_RGBA,
1515                               GL_UNSIGNED_BYTE, &texData[0]);
1516 
1517             gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1518             gl.texParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1519             GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::init");
1520         }
1521         else
1522             DE_ASSERT(false);
1523     }
1524 }
1525 
deinit(void)1526 void TextureSamplerCase::deinit(void)
1527 {
1528     RenderCase::deinit();
1529 
1530     if (m_textureID)
1531     {
1532         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1533 
1534         gl.deleteTextures(1, &m_textureID);
1535         m_textureID = 0;
1536     }
1537 }
1538 
iterate(void)1539 TextureSamplerCase::IterateResult TextureSamplerCase::iterate(void)
1540 {
1541     // 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.
1542 
1543     std::vector<tcu::Vec4> gridVertices(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
1544     std::vector<tcu::UVec2> gridTexCoords(DE_LENGTH_OF_ARRAY(s_specialFloats) * DE_LENGTH_OF_ARRAY(s_specialFloats));
1545     std::vector<uint16_t> indices((DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) *
1546                                   (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) * 6);
1547     tcu::Surface resultImage(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1548 
1549     // vertices
1550     for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
1551         for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
1552         {
1553             const float posX = (float)x / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f -
1554                                1.0f; // map from [0, len(s_specialFloats) - 1] to [-1, 1]
1555             const float posY = (float)y / ((float)DE_LENGTH_OF_ARRAY(s_specialFloats) - 1.0f) * 2.0f - 1.0f;
1556 
1557             gridVertices[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
1558             gridTexCoords[x * DE_LENGTH_OF_ARRAY(s_specialFloats) + y] =
1559                 tcu::UVec2(s_specialFloats[x], s_specialFloats[y]);
1560         }
1561 
1562     // tiles
1563     for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++x)
1564         for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) - 1; ++y)
1565         {
1566             const int baseNdx = (x * (DE_LENGTH_OF_ARRAY(s_specialFloats) - 1) + y) * 6;
1567 
1568             indices[baseNdx + 0] = (uint16_t)((x + 0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 0));
1569             indices[baseNdx + 1] = (uint16_t)((x + 1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 1));
1570             indices[baseNdx + 2] = (uint16_t)((x + 1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 0));
1571 
1572             indices[baseNdx + 3] = (uint16_t)((x + 0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 0));
1573             indices[baseNdx + 4] = (uint16_t)((x + 1) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 1));
1574             indices[baseNdx + 5] = (uint16_t)((x + 0) * DE_LENGTH_OF_ARRAY(s_specialFloats) + (y + 1));
1575         }
1576 
1577     m_testCtx.getLog()
1578         << tcu::TestLog::Message
1579         << "Drawing a textured grid with the shader. Sampling from the texture using special floating point values."
1580         << tcu::TestLog::EndMessage;
1581 
1582     // Draw grid
1583     {
1584         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1585         const GLint positionLoc  = gl.getAttribLocation(m_program->getProgram(), "a_pos");
1586         const GLint texCoordLoc  = gl.getAttribLocation(m_program->getProgram(), "a_attr");
1587         const GLint samplerLoc   = gl.getUniformLocation(m_program->getProgram(), "u_sampler");
1588 
1589         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1590         gl.clear(GL_COLOR_BUFFER_BIT);
1591         gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1592         gl.useProgram(m_program->getProgram());
1593 
1594         gl.uniform1i(samplerLoc, 0);
1595         if (m_testType != TEST_TEX_COORD_CUBE)
1596             gl.bindTexture(GL_TEXTURE_2D, m_textureID);
1597         else
1598             gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_textureID);
1599 
1600         gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
1601         gl.vertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, &gridTexCoords[0]);
1602 
1603         gl.enableVertexAttribArray(positionLoc);
1604         gl.enableVertexAttribArray(texCoordLoc);
1605         gl.drawElements(GL_TRIANGLES, (glw::GLsizei)(indices.size()), GL_UNSIGNED_SHORT, &indices[0]);
1606         gl.disableVertexAttribArray(positionLoc);
1607         gl.disableVertexAttribArray(texCoordLoc);
1608 
1609         gl.useProgram(0);
1610         gl.finish();
1611         GLU_EXPECT_NO_ERROR(gl.getError(), "TextureSamplerCase::iterate");
1612 
1613         glu::readPixels(m_context.getRenderContext(), 0, 0, resultImage.getAccess());
1614     }
1615 
1616     // verify everywhere was drawn and samples were from the texture (all pixels have Green = 255)
1617     if (!checkResultImage(resultImage))
1618     {
1619         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "missing or invalid fragments");
1620         return STOP;
1621     }
1622 
1623     // test drawing and textures still works
1624     if (!drawTestPattern(true))
1625     {
1626         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "test pattern failed");
1627         return STOP;
1628     }
1629 
1630     // all ok
1631     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1632     return STOP;
1633 }
1634 
genVertexSource(void) const1635 std::string TextureSamplerCase::genVertexSource(void) const
1636 {
1637     // vertex shader is passthrough, fragment does the calculations
1638     if (m_type == TYPE_FRAGMENT)
1639         return s_attrPassthroughVertexShaderSource;
1640 
1641     // vertex shader does the calculations
1642     std::ostringstream buf;
1643     buf << "#version 300 es\n"
1644            "in highp vec4 a_pos;\n"
1645            "in highp vec2 a_attr;\n";
1646 
1647     if (m_testType != TEST_TEX_COORD_CUBE)
1648         buf << "uniform highp sampler2D u_sampler;\n";
1649     else
1650         buf << "uniform highp samplerCube u_sampler;\n";
1651 
1652     buf << "out mediump vec4 v_out;\n"
1653            "void main ()\n"
1654            "{\n";
1655 
1656     if (m_testType == TEST_TEX_COORD)
1657         buf << "    v_out = textureLod(u_sampler, a_attr, 0.0);\n";
1658     else if (m_testType == TEST_LOD)
1659         buf << "    v_out = textureLod(u_sampler, a_attr, a_attr.x);\n";
1660     else if (m_testType == TEST_GRAD)
1661         buf << "    v_out = textureGrad(u_sampler, a_attr, a_attr, a_attr.yx);\n";
1662     else if (m_testType == TEST_TEX_COORD_CUBE)
1663         buf << "    v_out = textureLod(u_sampler, vec3(a_attr, a_attr.x + a_attr.y), 0.0);\n";
1664     else
1665         DE_ASSERT(false);
1666 
1667     buf << "\n"
1668            "    gl_Position = a_pos;\n"
1669            "}\n";
1670 
1671     return buf.str();
1672 }
1673 
genFragmentSource(void) const1674 std::string TextureSamplerCase::genFragmentSource(void) const
1675 {
1676     // fragment shader is passthrough
1677     if (m_type == TYPE_VERTEX)
1678         return s_colorPassthroughFragmentShaderSource;
1679 
1680     // fragment shader does the calculations
1681     std::ostringstream buf;
1682     buf << "#version 300 es\n"
1683            "layout(location = 0) out mediump vec4 fragColor;\n";
1684 
1685     if (m_testType != TEST_TEX_COORD_CUBE)
1686         buf << "uniform highp sampler2D u_sampler;\n";
1687     else
1688         buf << "uniform highp samplerCube u_sampler;\n";
1689 
1690     buf << "in highp vec4 v_attr;\n"
1691            "void main ()\n"
1692            "{\n";
1693 
1694     if (m_testType == TEST_TEX_COORD)
1695         buf << "    fragColor = texture(u_sampler, v_attr.xy);\n";
1696     else if (m_testType == TEST_LOD)
1697         buf << "    fragColor = texture(u_sampler, v_attr.xy, v_attr.x);\n";
1698     else if (m_testType == TEST_GRAD)
1699         buf << "    fragColor = textureGrad(u_sampler, v_attr.xy, v_attr.xy, v_attr.yx);\n";
1700     else if (m_testType == TEST_TEX_COORD_CUBE)
1701         buf << "    fragColor = texture(u_sampler, vec3(v_attr.xy,v_attr.x + v_attr.y));\n";
1702     else
1703         DE_ASSERT(false);
1704 
1705     buf << "}\n";
1706 
1707     return buf.str();
1708 }
1709 
1710 /*--------------------------------------------------------------------*//*!
1711  * \brief Tests special floats as fragment shader outputs
1712  *
1713  * Tests that outputting special floats from a fragment shader does not change
1714  * the normal floating point values of outputted from a fragment shader. Special
1715  * floats are outputted in the green component, normal floating point values
1716  * in the red and blue component. Potential changes are tested by rendering
1717  * test pattern two times with different floating point values. The resulting
1718  * images' red and blue channels should be equal.
1719  *//*--------------------------------------------------------------------*/
1720 class OutputCase : public FramebufferRenderCase
1721 {
1722 public:
1723     OutputCase(Context &context, const char *name, const char *desc, FramebufferRenderCase::FrameBufferType type);
1724     ~OutputCase(void);
1725 
1726     void testFBO(void);
1727 
1728 private:
1729     std::string genVertexSource(void) const;
1730     std::string genFragmentSource(void) const;
1731 };
1732 
OutputCase(Context & context,const char * name,const char * desc,FramebufferRenderCase::FrameBufferType type)1733 OutputCase::OutputCase(Context &context, const char *name, const char *desc,
1734                        FramebufferRenderCase::FrameBufferType type)
1735     : FramebufferRenderCase(context, name, desc, type)
1736 {
1737 }
1738 
~OutputCase(void)1739 OutputCase::~OutputCase(void)
1740 {
1741     deinit();
1742 }
1743 
testFBO(void)1744 void OutputCase::testFBO(void)
1745 {
1746     // Create a 1 X [s_specialFloats] grid of tiles (stripes).
1747     std::vector<tcu::Vec4> gridVertices((DE_LENGTH_OF_ARRAY(s_specialFloats) + 1) * 2);
1748     std::vector<uint16_t> indices(DE_LENGTH_OF_ARRAY(s_specialFloats) * 6);
1749     tcu::TextureFormat textureFormat(tcu::TextureFormat::RGBA,
1750                                      (m_fboType == FBO_RGBA_FLOAT16 || m_fboType == FBO_RGBA_FLOAT32) ?
1751                                          (tcu::TextureFormat::FLOAT) :
1752                                          (tcu::TextureFormat::UNORM_INT8));
1753     tcu::TextureLevel specialImage(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1754     tcu::TextureLevel normalImage(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1755 
1756     // vertices
1757     for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++y)
1758     {
1759         const float posY = (float)y / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f -
1760                            1.0f; // map from [0, len(s_specialFloats) ] to [-1, 1]
1761 
1762         gridVertices[y * 2 + 0] = tcu::Vec4(-1.0, posY, 0.0f, 1.0f);
1763         gridVertices[y * 2 + 1] = tcu::Vec4(1.0, posY, 0.0f, 1.0f);
1764     }
1765 
1766     // tiles
1767     for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
1768     {
1769         const int baseNdx = y * 6;
1770 
1771         indices[baseNdx + 0] = (uint16_t)((y + 0) * 2);
1772         indices[baseNdx + 1] = (uint16_t)((y + 1) * 2);
1773         indices[baseNdx + 2] = (uint16_t)((y + 1) * 2 + 1);
1774 
1775         indices[baseNdx + 3] = (uint16_t)((y + 0) * 2);
1776         indices[baseNdx + 4] = (uint16_t)((y + 1) * 2 + 1);
1777         indices[baseNdx + 5] = (uint16_t)((y + 0) * 2 + 1);
1778     }
1779 
1780     // Draw grids
1781     {
1782         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1783         const GLint positionLoc  = gl.getAttribLocation(m_program->getProgram(), "a_pos");
1784         const GLint specialLoc   = gl.getUniformLocation(m_program->getProgram(), "u_special");
1785 
1786         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1787         gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1788         gl.useProgram(m_program->getProgram());
1789         GLU_EXPECT_NO_ERROR(gl.getError(), "pre-draw");
1790 
1791         gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
1792         gl.enableVertexAttribArray(positionLoc);
1793 
1794         // draw 2 passes. Special and normal.
1795         for (int passNdx = 0; passNdx < 2; ++passNdx)
1796         {
1797             const bool specialPass = (passNdx == 0);
1798 
1799             m_testCtx.getLog() << tcu::TestLog::Message << "Pass " << passNdx
1800                                << ": Drawing stripes with the shader. Setting u_special for each stripe to ("
1801                                << ((specialPass) ? ("special") : ("1.0")) << ")." << tcu::TestLog::EndMessage;
1802 
1803             // draw stripes
1804             gl.clear(GL_COLOR_BUFFER_BIT);
1805             for (int y = 0; y < DE_LENGTH_OF_ARRAY(s_specialFloats); ++y)
1806             {
1807                 const uint32_t one          = 0x3F800000;
1808                 const uint32_t special      = s_specialFloats[y];
1809                 const uint32_t uniformValue = (specialPass) ? (special) : (one);
1810                 const int indexIndex        = y * 6;
1811 
1812                 gl.uniform1fv(specialLoc, 1, (const float *)&uniformValue);
1813                 gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[indexIndex]);
1814             }
1815 
1816             gl.finish();
1817             glu::readPixels(m_context.getRenderContext(), 0, 0,
1818                             ((specialPass) ? (specialImage) : (normalImage)).getAccess());
1819         }
1820 
1821         gl.disableVertexAttribArray(positionLoc);
1822         gl.useProgram(0);
1823         GLU_EXPECT_NO_ERROR(gl.getError(), "OutputCase::iterate");
1824     }
1825 
1826     // Check results
1827     {
1828         tcu::Surface errorMask(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1829         const tcu::RGBA badPixelColor = tcu::RGBA::red();
1830         const tcu::RGBA okPixelColor  = tcu::RGBA::green();
1831         int badPixels                 = 0;
1832 
1833         m_testCtx.getLog() << tcu::TestLog::Message
1834                            << "Checking passes have identical red and blue channels and the green channel is correct "
1835                               "in the constant pass."
1836                            << tcu::TestLog::EndMessage;
1837 
1838         for (int y = 0; y < specialImage.getHeight(); ++y)
1839             for (int x = 0; x < specialImage.getWidth(); ++x)
1840             {
1841                 const float greenThreshold = 0.1f;
1842                 const tcu::Vec4 cNormal    = normalImage.getAccess().getPixel(x, y);
1843                 const tcu::Vec4 cSpecial   = specialImage.getAccess().getPixel(x, y);
1844 
1845                 if (cNormal.x() != cSpecial.x() || cNormal.z() != cSpecial.z() || cNormal.y() < 1.0f - greenThreshold)
1846                 {
1847                     ++badPixels;
1848                     errorMask.setPixel(x, y, badPixelColor);
1849                 }
1850                 else
1851                     errorMask.setPixel(x, y, okPixelColor);
1852             }
1853 
1854         m_testCtx.getLog() << tcu::TestLog::Message << "Found " << badPixels << " invalid pixel(s)."
1855                            << tcu::TestLog::EndMessage;
1856 
1857         if (badPixels)
1858         {
1859             m_testCtx.getLog() << tcu::TestLog::ImageSet("Results", "Result verification")
1860                                << tcu::TestLog::Image("Image with special green channel",
1861                                                       "Image with special green channel", specialImage)
1862                                << tcu::TestLog::Image("Image with constant green channel",
1863                                                       "Image with constant green channel", normalImage)
1864                                << tcu::TestLog::Image("Error Mask", "Error Mask", errorMask)
1865                                << tcu::TestLog::EndImageSet;
1866 
1867             // all ok?
1868             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1869         }
1870         else
1871             m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1872     }
1873 }
1874 
genVertexSource(void) const1875 std::string OutputCase::genVertexSource(void) const
1876 {
1877     return "#version 300 es\n"
1878            "in highp vec4 a_pos;\n"
1879            "out highp vec2 v_pos;\n"
1880            "void main ()\n"
1881            "{\n"
1882            "    gl_Position = a_pos;\n"
1883            "    v_pos = a_pos.xy;\n"
1884            "}\n";
1885 }
1886 
genFragmentSource(void) const1887 std::string OutputCase::genFragmentSource(void) const
1888 {
1889     return "#version 300 es\n"
1890            "layout(location = 0) out highp vec4 fragColor;\n"
1891            "uniform highp float u_special;\n"
1892            "in highp vec2 v_pos;\n"
1893            "void main ()\n"
1894            "{\n"
1895            "    fragColor = vec4((v_pos.x + 1.0) * 0.5, u_special, (v_pos.y + 1.0) * 0.5, 1.0);\n"
1896            "}\n";
1897 }
1898 
1899 /*--------------------------------------------------------------------*//*!
1900  * \brief Tests special floats in blending
1901  *
1902  * Tests special floats as alpha and color components with various blending
1903  * modes. Test draws a test pattern and then does various blend operations
1904  * with special float values. After the blending test another test pattern
1905  * is drawn to detect possible blending anomalies. Test patterns should be
1906  * identical.
1907  *//*--------------------------------------------------------------------*/
1908 class BlendingCase : public FramebufferRenderCase
1909 {
1910 public:
1911     BlendingCase(Context &context, const char *name, const char *desc, FramebufferRenderCase::FrameBufferType type);
1912     ~BlendingCase(void);
1913 
1914     void testFBO(void);
1915 
1916 private:
1917     void drawTestImage(tcu::PixelBufferAccess dst, GLuint uColorLoc, int maxVertexIndex);
1918 
1919     std::string genVertexSource(void) const;
1920     std::string genFragmentSource(void) const;
1921 };
1922 
BlendingCase(Context & context,const char * name,const char * desc,FramebufferRenderCase::FrameBufferType type)1923 BlendingCase::BlendingCase(Context &context, const char *name, const char *desc,
1924                            FramebufferRenderCase::FrameBufferType type)
1925     : FramebufferRenderCase(context, name, desc, type)
1926 {
1927 }
1928 
~BlendingCase(void)1929 BlendingCase::~BlendingCase(void)
1930 {
1931     deinit();
1932 }
1933 
testFBO(void)1934 void BlendingCase::testFBO(void)
1935 {
1936     static const GLenum equations[] = {GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT, GL_MIN, GL_MAX};
1937     static const GLenum functions[] = {
1938         GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1939     };
1940 
1941     // Create a [BlendFuncs] X [s_specialFloats] grid of tiles. ( BlendFuncs = equations x functions )
1942 
1943     const int numBlendFuncs = DE_LENGTH_OF_ARRAY(equations) * DE_LENGTH_OF_ARRAY(functions);
1944     std::vector<tcu::Vec4> gridVertices((numBlendFuncs + 1) * (DE_LENGTH_OF_ARRAY(s_specialFloats) + 1));
1945     std::vector<uint16_t> indices(numBlendFuncs * DE_LENGTH_OF_ARRAY(s_specialFloats) * 6);
1946     tcu::TextureFormat textureFormat(tcu::TextureFormat::RGBA,
1947                                      (m_fboType == FBO_RGBA_FLOAT16 || m_fboType == FBO_RGBA_FLOAT32) ?
1948                                          (tcu::TextureFormat::FLOAT) :
1949                                          (tcu::TextureFormat::UNORM_INT8));
1950     tcu::TextureLevel beforeImage(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1951     tcu::TextureLevel afterImage(textureFormat, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1952 
1953     // vertices
1954     for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats) + 1; ++x)
1955         for (int y = 0; y < numBlendFuncs + 1; ++y)
1956         {
1957             const float posX = (float)x / (float)DE_LENGTH_OF_ARRAY(s_specialFloats) * 2.0f -
1958                                1.0f; // map from [0, len(s_specialFloats)] to [-1, 1]
1959             const float posY = (float)y / (float)numBlendFuncs * 2.0f - 1.0f;
1960 
1961             gridVertices[x * (numBlendFuncs + 1) + y] = tcu::Vec4(posX, posY, 0.0f, 1.0f);
1962         }
1963 
1964     // tiles
1965     for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
1966         for (int y = 0; y < numBlendFuncs; ++y)
1967         {
1968             const int baseNdx = (x * numBlendFuncs + y) * 6;
1969 
1970             indices[baseNdx + 0] = (uint16_t)((x + 0) * (numBlendFuncs + 1) + (y + 0));
1971             indices[baseNdx + 1] = (uint16_t)((x + 1) * (numBlendFuncs + 1) + (y + 1));
1972             indices[baseNdx + 2] = (uint16_t)((x + 1) * (numBlendFuncs + 1) + (y + 0));
1973 
1974             indices[baseNdx + 3] = (uint16_t)((x + 0) * (numBlendFuncs + 1) + (y + 0));
1975             indices[baseNdx + 4] = (uint16_t)((x + 1) * (numBlendFuncs + 1) + (y + 1));
1976             indices[baseNdx + 5] = (uint16_t)((x + 0) * (numBlendFuncs + 1) + (y + 1));
1977         }
1978 
1979     // Draw tiles
1980     {
1981         const int numPasses      = 5;
1982         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1983         const GLint positionLoc  = gl.getAttribLocation(m_program->getProgram(), "a_pos");
1984         const GLint specialLoc   = gl.getUniformLocation(m_program->getProgram(), "u_special");
1985 
1986         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1987         gl.clear(GL_COLOR_BUFFER_BIT);
1988         gl.viewport(0, 0, TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
1989         gl.useProgram(m_program->getProgram());
1990         gl.enable(GL_BLEND);
1991         GLU_EXPECT_NO_ERROR(gl.getError(), "pre-draw");
1992 
1993         gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &gridVertices[0]);
1994         gl.enableVertexAttribArray(positionLoc);
1995 
1996         // draw "before" image
1997         m_testCtx.getLog() << tcu::TestLog::Message << "Drawing pre-draw pattern." << tcu::TestLog::EndMessage;
1998         drawTestImage(beforeImage.getAccess(), specialLoc, (int)gridVertices.size() - 1);
1999         GLU_EXPECT_NO_ERROR(gl.getError(), "pre-draw pattern");
2000 
2001         // draw multiple passes with special floats
2002         gl.clear(GL_COLOR_BUFFER_BIT);
2003         for (int passNdx = 0; passNdx < numPasses; ++passNdx)
2004         {
2005             de::Random rnd(123 + 567 * passNdx);
2006 
2007             m_testCtx.getLog() << tcu::TestLog::Message << "Pass " << passNdx << ": Drawing tiles with the shader.\n"
2008                                << "\tVarying u_special for each tile.\n"
2009                                << "\tVarying blend function and blend equation for each tile.\n"
2010                                << tcu::TestLog::EndMessage;
2011 
2012             // draw tiles
2013             for (int x = 0; x < DE_LENGTH_OF_ARRAY(s_specialFloats); ++x)
2014                 for (int y = 0; y < numBlendFuncs; ++y)
2015                 {
2016                     const GLenum blendEquation = equations[y % DE_LENGTH_OF_ARRAY(equations)];
2017                     const GLenum blendFunction = functions[y / DE_LENGTH_OF_ARRAY(equations)];
2018                     const GLenum blendFunctionDst =
2019                         rnd.choose<GLenum>(DE_ARRAY_BEGIN(functions), DE_ARRAY_END(functions));
2020                     const int indexIndex = (x * numBlendFuncs + y) * 6;
2021 
2022                     // "rnd.get"s are run in a deterministic order
2023                     const uint32_t componentR =
2024                         rnd.choose<uint32_t>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
2025                     const uint32_t componentG =
2026                         rnd.choose<uint32_t>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
2027                     const uint32_t componentB =
2028                         rnd.choose<uint32_t>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
2029                     const uint32_t componentA =
2030                         rnd.choose<uint32_t>(DE_ARRAY_BEGIN(s_specialFloats), DE_ARRAY_END(s_specialFloats));
2031                     const tcu::UVec4 uniformValue = tcu::UVec4(componentR, componentG, componentB, componentA);
2032 
2033                     gl.uniform4fv(specialLoc, 1, (const float *)uniformValue.getPtr());
2034                     gl.blendEquation(blendEquation);
2035                     gl.blendFunc(blendFunction, blendFunctionDst);
2036                     gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[indexIndex]);
2037                 }
2038         }
2039         GLU_EXPECT_NO_ERROR(gl.getError(), "special passes");
2040 
2041         // draw "after" image
2042         m_testCtx.getLog() << tcu::TestLog::Message << "Drawing post-draw pattern." << tcu::TestLog::EndMessage;
2043         drawTestImage(afterImage.getAccess(), specialLoc, (int)gridVertices.size() - 1);
2044         GLU_EXPECT_NO_ERROR(gl.getError(), "post-draw pattern");
2045 
2046         gl.disableVertexAttribArray(positionLoc);
2047         gl.useProgram(0);
2048         GLU_EXPECT_NO_ERROR(gl.getError(), "OutputCase::iterate");
2049     }
2050 
2051     // Check results
2052     {
2053         tcu::Surface errorMask(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE);
2054         const tcu::RGBA badPixelColor = tcu::RGBA::red();
2055         const tcu::RGBA okPixelColor  = tcu::RGBA::green();
2056         int badPixels                 = 0;
2057 
2058         m_testCtx.getLog() << tcu::TestLog::Message << "Checking patterns are identical." << tcu::TestLog::EndMessage;
2059 
2060         for (int y = 0; y < beforeImage.getHeight(); ++y)
2061             for (int x = 0; x < beforeImage.getWidth(); ++x)
2062             {
2063                 const tcu::Vec4 cBefore = beforeImage.getAccess().getPixel(x, y);
2064                 const tcu::Vec4 cAfter  = afterImage.getAccess().getPixel(x, y);
2065 
2066                 if (cBefore != cAfter)
2067                 {
2068                     ++badPixels;
2069                     errorMask.setPixel(x, y, badPixelColor);
2070                 }
2071                 else
2072                     errorMask.setPixel(x, y, okPixelColor);
2073             }
2074 
2075         m_testCtx.getLog() << tcu::TestLog::Message << "Found " << badPixels << " invalid pixel(s)."
2076                            << tcu::TestLog::EndMessage;
2077 
2078         if (badPixels)
2079         {
2080             m_testCtx.getLog() << tcu::TestLog::ImageSet("Results", "Result verification")
2081                                << tcu::TestLog::Image("Pattern drawn before special float blending",
2082                                                       "Pattern drawn before special float blending", beforeImage)
2083                                << tcu::TestLog::Image("Pattern drawn after special float blending",
2084                                                       "Pattern drawn after special float blending", afterImage)
2085                                << tcu::TestLog::EndImageSet;
2086 
2087             // all ok?
2088             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
2089         }
2090         else
2091             m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2092     }
2093 }
2094 
drawTestImage(tcu::PixelBufferAccess dst,GLuint uColorLoc,int maxVertexIndex)2095 void BlendingCase::drawTestImage(tcu::PixelBufferAccess dst, GLuint uColorLoc, int maxVertexIndex)
2096 {
2097     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2098     de::Random rnd(123);
2099 
2100     gl.clear(GL_COLOR_BUFFER_BIT);
2101     gl.blendEquation(GL_FUNC_ADD);
2102     gl.blendFunc(GL_ONE, GL_ONE);
2103 
2104     for (int tri = 0; tri < 20; ++tri)
2105     {
2106         tcu::Vec4 color;
2107         color.x() = rnd.getFloat();
2108         color.y() = rnd.getFloat();
2109         color.z() = rnd.getFloat();
2110         color.w() = rnd.getFloat();
2111         gl.uniform4fv(uColorLoc, 1, color.getPtr());
2112 
2113         uint16_t indices[3];
2114         indices[0] = (uint16_t)rnd.getInt(0, maxVertexIndex);
2115         indices[1] = (uint16_t)rnd.getInt(0, maxVertexIndex);
2116         indices[2] = (uint16_t)rnd.getInt(0, maxVertexIndex);
2117 
2118         gl.drawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, indices);
2119     }
2120 
2121     gl.finish();
2122     glu::readPixels(m_context.getRenderContext(), 0, 0, dst);
2123 }
2124 
genVertexSource(void) const2125 std::string BlendingCase::genVertexSource(void) const
2126 {
2127     return "#version 300 es\n"
2128            "in highp vec4 a_pos;\n"
2129            "void main ()\n"
2130            "{\n"
2131            "    gl_Position = a_pos;\n"
2132            "}\n";
2133 }
2134 
genFragmentSource(void) const2135 std::string BlendingCase::genFragmentSource(void) const
2136 {
2137     return "#version 300 es\n"
2138            "layout(location = 0) out highp vec4 fragColor;\n"
2139            "uniform highp vec4 u_special;\n"
2140            "void main ()\n"
2141            "{\n"
2142            "    fragColor = u_special;\n"
2143            "}\n";
2144 }
2145 
2146 } // namespace
2147 
SpecialFloatTests(Context & context)2148 SpecialFloatTests::SpecialFloatTests(Context &context) : TestCaseGroup(context, "special_float", "Special float tests")
2149 {
2150 }
2151 
~SpecialFloatTests(void)2152 SpecialFloatTests::~SpecialFloatTests(void)
2153 {
2154 }
2155 
init(void)2156 void SpecialFloatTests::init(void)
2157 {
2158     tcu::TestCaseGroup *const vertexGroup =
2159         new tcu::TestCaseGroup(m_testCtx, "vertex", "Run vertex shader with special float values");
2160     tcu::TestCaseGroup *const fragmentGroup =
2161         new tcu::TestCaseGroup(m_testCtx, "fragment", "Run fragment shader with special float values");
2162     tcu::TestCaseGroup *const framebufferGroup =
2163         new tcu::TestCaseGroup(m_testCtx, "framebuffer", "Test framebuffers containing special float values");
2164 
2165     // .vertex
2166     {
2167         vertexGroup->addChild(
2168             new VertexAttributeCase(m_context, "attribute_buffer", "special attribute values in a buffer",
2169                                     VertexAttributeCase::STORAGE_BUFFER, VertexAttributeCase::TYPE_VERTEX));
2170         vertexGroup->addChild(
2171             new VertexAttributeCase(m_context, "attribute_client", "special attribute values in a client storage",
2172                                     VertexAttributeCase::STORAGE_CLIENT, VertexAttributeCase::TYPE_VERTEX));
2173         vertexGroup->addChild(
2174             new UniformCase(m_context, "uniform", "special uniform values", UniformCase::TYPE_VERTEX));
2175         vertexGroup->addChild(new TextureCase(m_context, "texture", "texture with special floating point values",
2176                                               TextureCase::TYPE_VERTEX, TextureCase::TEXTURE_FLOAT,
2177                                               TextureCase::UPLOAD_CLIENT));
2178         vertexGroup->addChild(
2179             new TextureCase(m_context, "texture_pbo", "texture (via pbo) with special floating point values",
2180                             TextureCase::TYPE_VERTEX, TextureCase::TEXTURE_FLOAT, TextureCase::UPLOAD_PBO));
2181         vertexGroup->addChild(
2182             new TextureCase(m_context, "texture_shadow", "shadow texture with special floating point values",
2183                             TextureCase::TYPE_VERTEX, TextureCase::TEXTURE_DEPTH, TextureCase::UPLOAD_CLIENT));
2184         vertexGroup->addChild(new TextureSamplerCase(m_context, "sampler_tex_coord", "special texture coords",
2185                                                      TextureSamplerCase::TYPE_VERTEX,
2186                                                      TextureSamplerCase::TEST_TEX_COORD));
2187         vertexGroup->addChild(
2188             new TextureSamplerCase(m_context, "sampler_tex_coord_cube", "special texture coords to cubemap",
2189                                    TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_TEX_COORD_CUBE));
2190         vertexGroup->addChild(new TextureSamplerCase(m_context, "sampler_lod", "special texture lod",
2191                                                      TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_LOD));
2192         vertexGroup->addChild(new TextureSamplerCase(m_context, "sampler_grad", "special texture grad",
2193                                                      TextureSamplerCase::TYPE_VERTEX, TextureSamplerCase::TEST_GRAD));
2194 
2195         addChild(vertexGroup);
2196     }
2197 
2198     // .fragment
2199     {
2200         fragmentGroup->addChild(
2201             new VertexAttributeCase(m_context, "attribute_buffer", "special attribute values in a buffer",
2202                                     VertexAttributeCase::STORAGE_BUFFER, VertexAttributeCase::TYPE_FRAGMENT));
2203         fragmentGroup->addChild(
2204             new VertexAttributeCase(m_context, "attribute_client", "special attribute values in a client storage",
2205                                     VertexAttributeCase::STORAGE_CLIENT, VertexAttributeCase::TYPE_FRAGMENT));
2206         fragmentGroup->addChild(
2207             new UniformCase(m_context, "uniform", "special uniform values", UniformCase::TYPE_FRAGMENT));
2208         fragmentGroup->addChild(new TextureCase(m_context, "texture", "texture with special floating point values",
2209                                                 TextureCase::TYPE_FRAGMENT, TextureCase::TEXTURE_FLOAT,
2210                                                 TextureCase::UPLOAD_CLIENT));
2211         fragmentGroup->addChild(
2212             new TextureCase(m_context, "texture_pbo", "texture (via pbo) with special floating point values",
2213                             TextureCase::TYPE_FRAGMENT, TextureCase::TEXTURE_FLOAT, TextureCase::UPLOAD_PBO));
2214         fragmentGroup->addChild(
2215             new TextureCase(m_context, "texture_shadow", "shadow texture with special floating point values",
2216                             TextureCase::TYPE_FRAGMENT, TextureCase::TEXTURE_DEPTH, TextureCase::UPLOAD_CLIENT));
2217         fragmentGroup->addChild(new TextureSamplerCase(m_context, "sampler_tex_coord", "special texture coords",
2218                                                        TextureSamplerCase::TYPE_FRAGMENT,
2219                                                        TextureSamplerCase::TEST_TEX_COORD));
2220         fragmentGroup->addChild(
2221             new TextureSamplerCase(m_context, "sampler_tex_coord_cube", "special texture coords to cubemap",
2222                                    TextureSamplerCase::TYPE_FRAGMENT, TextureSamplerCase::TEST_TEX_COORD_CUBE));
2223         fragmentGroup->addChild(new TextureSamplerCase(m_context, "sampler_lod", "special texture lod",
2224                                                        TextureSamplerCase::TYPE_FRAGMENT,
2225                                                        TextureSamplerCase::TEST_LOD));
2226         fragmentGroup->addChild(new TextureSamplerCase(m_context, "sampler_grad", "special texture grad",
2227                                                        TextureSamplerCase::TYPE_FRAGMENT,
2228                                                        TextureSamplerCase::TEST_GRAD));
2229 
2230         addChild(fragmentGroup);
2231     }
2232 
2233     // .framebuffer
2234     {
2235         framebufferGroup->addChild(new OutputCase(m_context, "write_default",
2236                                                   "write special floating point values to default framebuffer",
2237                                                   FramebufferRenderCase::FBO_DEFAULT));
2238         framebufferGroup->addChild(new OutputCase(m_context, "write_rgba4",
2239                                                   "write special floating point values to RGBA4 framebuffer",
2240                                                   FramebufferRenderCase::FBO_RGBA4));
2241         framebufferGroup->addChild(new OutputCase(m_context, "write_rgb5_a1",
2242                                                   "write special floating point values to RGB5_A1 framebuffer",
2243                                                   FramebufferRenderCase::FBO_RGB5_A1));
2244         framebufferGroup->addChild(new OutputCase(m_context, "write_rgb565",
2245                                                   "write special floating point values to RGB565 framebuffer",
2246                                                   FramebufferRenderCase::FBO_RGB565));
2247         framebufferGroup->addChild(new OutputCase(m_context, "write_rgba8",
2248                                                   "write special floating point values to RGBA8 framebuffer",
2249                                                   FramebufferRenderCase::FBO_RGBA8));
2250         framebufferGroup->addChild(new OutputCase(m_context, "write_rgb10_a2",
2251                                                   "write special floating point values to RGB10_A2 framebuffer",
2252                                                   FramebufferRenderCase::FBO_RGB10_A2));
2253         framebufferGroup->addChild(new OutputCase(m_context, "write_float16",
2254                                                   "write special floating point values to float16 framebuffer",
2255                                                   FramebufferRenderCase::FBO_RGBA_FLOAT16));
2256         framebufferGroup->addChild(new OutputCase(m_context, "write_float32",
2257                                                   "write special floating point values to float32 framebuffer",
2258                                                   FramebufferRenderCase::FBO_RGBA_FLOAT32));
2259 
2260         framebufferGroup->addChild(new BlendingCase(m_context, "blend_default",
2261                                                     "blend special floating point values in a default framebuffer",
2262                                                     FramebufferRenderCase::FBO_DEFAULT));
2263         framebufferGroup->addChild(new BlendingCase(m_context, "blend_rgba8",
2264                                                     "blend special floating point values in a RGBA8 framebuffer",
2265                                                     FramebufferRenderCase::FBO_RGBA8));
2266         framebufferGroup->addChild(new BlendingCase(m_context, "blend_float16",
2267                                                     "blend special floating point values in a float16 framebuffer",
2268                                                     FramebufferRenderCase::FBO_RGBA_FLOAT16));
2269 
2270         addChild(framebufferGroup);
2271     }
2272 }
2273 
2274 } // namespace Stress
2275 } // namespace gles3
2276 } // namespace deqp
2277