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