Always apply flat qualifier to double inputs, same as int/uint
[platform/upstream/VK-GL-CTS.git] / external / openglcts / modules / common / glcShaderRenderCase.cpp
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2016 Google Inc.
6  * Copyright (c) 2016 The Khronos Group Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */ /*!
21  * \file
22  * \brief Shader execute test.
23  */ /*-------------------------------------------------------------------*/
24
25 #include "glcShaderRenderCase.hpp"
26
27 #include "tcuImageCompare.hpp"
28 #include "tcuRenderTarget.hpp"
29 #include "tcuSurface.hpp"
30 #include "tcuTestLog.hpp"
31 #include "tcuVector.hpp"
32
33 #include "gluDrawUtil.hpp"
34 #include "gluPixelTransfer.hpp"
35 #include "gluTexture.hpp"
36 #include "gluTextureUtil.hpp"
37
38 #include "glwEnums.hpp"
39 #include "glwFunctions.hpp"
40
41 #include "deMath.h"
42 #include "deMemory.h"
43 #include "deRandom.hpp"
44 #include "deString.h"
45 #include "deStringUtil.hpp"
46
47 #include <stdio.h>
48 #include <string>
49 #include <vector>
50
51 namespace deqp
52 {
53
54 using namespace std;
55 using namespace tcu;
56 using namespace glu;
57
58 static const int           GRID_SIZE               = 64;
59 static const int           MAX_RENDER_WIDTH     = 128;
60 static const int           MAX_RENDER_HEIGHT   = 112;
61 static const tcu::Vec4 DEFAULT_CLEAR_COLOR = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
62
63 inline RGBA toRGBA(const Vec4& a)
64 {
65         return RGBA(
66                 deClamp32(deRoundFloatToInt32(a.x() * 255.0f), 0, 255), deClamp32(deRoundFloatToInt32(a.y() * 255.0f), 0, 255),
67                 deClamp32(deRoundFloatToInt32(a.z() * 255.0f), 0, 255), deClamp32(deRoundFloatToInt32(a.w() * 255.0f), 0, 255));
68 }
69
70 inline tcu::Vec4 toVec(const RGBA& c)
71 {
72         return tcu::Vec4(static_cast<float>(c.getRed()) / 255.0f, static_cast<float>(c.getGreen()) / 255.0f,
73                                          static_cast<float>(c.getBlue()) / 255.0f, static_cast<float>(c.getAlpha()) / 255.0f);
74 }
75
76 // TextureBinding
77
78 TextureBinding::TextureBinding(const glu::Texture2D* tex2D, const tcu::Sampler& sampler)
79         : m_type(TYPE_2D), m_sampler(sampler)
80 {
81         m_binding.tex2D = tex2D;
82 }
83
84 TextureBinding::TextureBinding(const glu::TextureCube* texCube, const tcu::Sampler& sampler)
85         : m_type(TYPE_CUBE_MAP), m_sampler(sampler)
86 {
87         m_binding.texCube = texCube;
88 }
89
90 TextureBinding::TextureBinding(const glu::Texture2DArray* tex2DArray, const tcu::Sampler& sampler)
91         : m_type(TYPE_2D_ARRAY), m_sampler(sampler)
92 {
93         m_binding.tex2DArray = tex2DArray;
94 }
95
96 TextureBinding::TextureBinding(const glu::Texture3D* tex3D, const tcu::Sampler& sampler)
97         : m_type(TYPE_3D), m_sampler(sampler)
98 {
99         m_binding.tex3D = tex3D;
100 }
101
102 TextureBinding::TextureBinding(void) : m_type(TYPE_NONE)
103 {
104         m_binding.tex2D = DE_NULL;
105 }
106
107 void TextureBinding::setSampler(const tcu::Sampler& sampler)
108 {
109         m_sampler = sampler;
110 }
111
112 void TextureBinding::setTexture(const glu::Texture2D* tex2D)
113 {
114         m_type                  = TYPE_2D;
115         m_binding.tex2D = tex2D;
116 }
117
118 void TextureBinding::setTexture(const glu::TextureCube* texCube)
119 {
120         m_type                    = TYPE_CUBE_MAP;
121         m_binding.texCube = texCube;
122 }
123
124 void TextureBinding::setTexture(const glu::Texture2DArray* tex2DArray)
125 {
126         m_type                           = TYPE_2D_ARRAY;
127         m_binding.tex2DArray = tex2DArray;
128 }
129
130 void TextureBinding::setTexture(const glu::Texture3D* tex3D)
131 {
132         m_type                  = TYPE_3D;
133         m_binding.tex3D = tex3D;
134 }
135
136 // QuadGrid.
137
138 class QuadGrid
139 {
140 public:
141         QuadGrid(int gridSize, int screenWidth, int screenHeight, const Vec4& constCoords,
142                          const vector<Mat4>& userAttribTransforms, const vector<TextureBinding>& textures);
143         ~QuadGrid(void);
144
145         int getGridSize(void) const
146         {
147                 return m_gridSize;
148         }
149         int getNumVertices(void) const
150         {
151                 return m_numVertices;
152         }
153         int getNumTriangles(void) const
154         {
155                 return m_numTriangles;
156         }
157         const Vec4& getConstCoords(void) const
158         {
159                 return m_constCoords;
160         }
161         const vector<Mat4> getUserAttribTransforms(void) const
162         {
163                 return m_userAttribTransforms;
164         }
165         const vector<TextureBinding>& getTextures(void) const
166         {
167                 return m_textures;
168         }
169
170         const Vec4* getPositions(void) const
171         {
172                 return &m_positions[0];
173         }
174         const float* getAttribOne(void) const
175         {
176                 return &m_attribOne[0];
177         }
178         const Vec4* getCoords(void) const
179         {
180                 return &m_coords[0];
181         }
182         const Vec4* getUnitCoords(void) const
183         {
184                 return &m_unitCoords[0];
185         }
186         const Vec4* getUserAttrib(int attribNdx) const
187         {
188                 return &m_userAttribs[attribNdx][0];
189         }
190         const deUint16* getIndices(void) const
191         {
192                 return &m_indices[0];
193         }
194
195         Vec4 getCoords(float sx, float sy) const;
196         Vec4 getUnitCoords(float sx, float sy) const;
197
198         int getNumUserAttribs(void) const
199         {
200                 return (int)m_userAttribTransforms.size();
201         }
202         Vec4 getUserAttrib(int attribNdx, float sx, float sy) const;
203
204 private:
205         int                                        m_gridSize;
206         int                                        m_numVertices;
207         int                                        m_numTriangles;
208         Vec4                               m_constCoords;
209         vector<Mat4>               m_userAttribTransforms;
210         vector<TextureBinding> m_textures;
211
212         vector<Vec4>     m_screenPos;
213         vector<Vec4>     m_positions;
214         vector<Vec4>     m_coords;       //!< Near-unit coordinates, roughly [-2.0 .. 2.0].
215         vector<Vec4>     m_unitCoords; //!< Positive-only coordinates [0.0 .. 1.5].
216         vector<float>   m_attribOne;
217         vector<Vec4>     m_userAttribs[ShaderEvalContext::MAX_TEXTURES];
218         vector<deUint16> m_indices;
219 };
220
221 QuadGrid::QuadGrid(int gridSize, int width, int height, const Vec4& constCoords,
222                                    const vector<Mat4>& userAttribTransforms, const vector<TextureBinding>& textures)
223         : m_gridSize(gridSize)
224         , m_numVertices((gridSize + 1) * (gridSize + 1))
225         , m_numTriangles(gridSize * gridSize * 2)
226         , m_constCoords(constCoords)
227         , m_userAttribTransforms(userAttribTransforms)
228         , m_textures(textures)
229 {
230         Vec4 viewportScale = Vec4((float)width, (float)height, 0.0f, 0.0f);
231
232         // Compute vertices.
233         m_positions.resize(m_numVertices);
234         m_coords.resize(m_numVertices);
235         m_unitCoords.resize(m_numVertices);
236         m_attribOne.resize(m_numVertices);
237         m_screenPos.resize(m_numVertices);
238
239         // User attributes.
240         for (int i = 0; i < DE_LENGTH_OF_ARRAY(m_userAttribs); i++)
241                 m_userAttribs[i].resize(m_numVertices);
242
243         for (int y = 0; y < gridSize + 1; y++)
244                 for (int x = 0; x < gridSize + 1; x++)
245                 {
246                         float sx         = static_cast<float>(x) / static_cast<float>(gridSize);
247                         float sy         = static_cast<float>(y) / static_cast<float>(gridSize);
248                         float fx         = 2.0f * sx - 1.0f;
249                         float fy         = 2.0f * sy - 1.0f;
250                         int   vtxNdx = ((y * (gridSize + 1)) + x);
251
252                         m_positions[vtxNdx]  = Vec4(fx, fy, 0.0f, 1.0f);
253                         m_attribOne[vtxNdx]  = 1.0f;
254                         m_screenPos[vtxNdx]  = Vec4(sx, sy, 0.0f, 1.0f) * viewportScale;
255                         m_coords[vtxNdx]         = getCoords(sx, sy);
256                         m_unitCoords[vtxNdx] = getUnitCoords(sx, sy);
257
258                         for (int attribNdx                                       = 0; attribNdx < getNumUserAttribs(); attribNdx++)
259                                 m_userAttribs[attribNdx][vtxNdx] = getUserAttrib(attribNdx, sx, sy);
260                 }
261
262         // Compute indices.
263         m_indices.resize(3 * m_numTriangles);
264         for (int y = 0; y < gridSize; y++)
265                 for (int x = 0; x < gridSize; x++)
266                 {
267                         int stride = gridSize + 1;
268                         int v00 = (y * stride) + x;
269                         int v01 = (y * stride) + x + 1;
270                         int v10 = ((y + 1) * stride) + x;
271                         int v11 = ((y + 1) * stride) + x + 1;
272
273                         int baseNdx                        = ((y * gridSize) + x) * 6;
274                         m_indices[baseNdx + 0] = static_cast<deUint16>(v10);
275                         m_indices[baseNdx + 1] = static_cast<deUint16>(v00);
276                         m_indices[baseNdx + 2] = static_cast<deUint16>(v01);
277
278                         m_indices[baseNdx + 3] = static_cast<deUint16>(v10);
279                         m_indices[baseNdx + 4] = static_cast<deUint16>(v01);
280                         m_indices[baseNdx + 5] = static_cast<deUint16>(v11);
281                 }
282 }
283
284 QuadGrid::~QuadGrid(void)
285 {
286 }
287
288 inline Vec4 QuadGrid::getCoords(float sx, float sy) const
289 {
290         float fx = 2.0f * sx - 1.0f;
291         float fy = 2.0f * sy - 1.0f;
292         return Vec4(fx, fy, -fx + 0.33f * fy, -0.275f * fx - fy);
293 }
294
295 inline Vec4 QuadGrid::getUnitCoords(float sx, float sy) const
296 {
297         return Vec4(sx, sy, 0.33f * sx + 0.5f * sy, 0.5f * sx + 0.25f * sy);
298 }
299
300 inline Vec4 QuadGrid::getUserAttrib(int attribNdx, float sx, float sy) const
301 {
302         // homogeneous normalized screen-space coordinates
303         return m_userAttribTransforms[attribNdx] * Vec4(sx, sy, 0.0f, 1.0f);
304 }
305
306 // ShaderEvalContext.
307
308 ShaderEvalContext::ShaderEvalContext(const QuadGrid& quadGrid_)
309         : constCoords(quadGrid_.getConstCoords()), isDiscarded(false), quadGrid(quadGrid_)
310 {
311         const vector<TextureBinding>& bindings = quadGrid.getTextures();
312         DE_ASSERT((int)bindings.size() <= MAX_TEXTURES);
313
314         // Fill in texture array.
315         for (int ndx = 0; ndx < (int)bindings.size(); ndx++)
316         {
317                 const TextureBinding& binding = bindings[ndx];
318
319                 if (binding.getType() == TextureBinding::TYPE_NONE)
320                         continue;
321
322                 textures[ndx].sampler = binding.getSampler();
323
324                 switch (binding.getType())
325                 {
326                 case TextureBinding::TYPE_2D:
327                         textures[ndx].tex2D = &binding.get2D()->getRefTexture();
328                         break;
329                 case TextureBinding::TYPE_CUBE_MAP:
330                         textures[ndx].texCube = &binding.getCube()->getRefTexture();
331                         break;
332                 case TextureBinding::TYPE_2D_ARRAY:
333                         textures[ndx].tex2DArray = &binding.get2DArray()->getRefTexture();
334                         break;
335                 case TextureBinding::TYPE_3D:
336                         textures[ndx].tex3D = &binding.get3D()->getRefTexture();
337                         break;
338                 default:
339                         DE_ASSERT(DE_FALSE);
340                 }
341         }
342 }
343
344 ShaderEvalContext::~ShaderEvalContext(void)
345 {
346 }
347
348 void ShaderEvalContext::reset(float sx, float sy)
349 {
350         // Clear old values
351         color           = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
352         isDiscarded = false;
353
354         // Compute coords
355         coords   = quadGrid.getCoords(sx, sy);
356         unitCoords = quadGrid.getUnitCoords(sx, sy);
357
358         // Compute user attributes.
359         int numAttribs = quadGrid.getNumUserAttribs();
360         DE_ASSERT(numAttribs <= MAX_USER_ATTRIBS);
361         for (int attribNdx = 0; attribNdx < numAttribs; attribNdx++)
362                 in[attribNdx]  = quadGrid.getUserAttrib(attribNdx, sx, sy);
363 }
364
365 tcu::Vec4 ShaderEvalContext::texture2D(int unitNdx, const tcu::Vec2& texCoords)
366 {
367         if (textures[unitNdx].tex2D)
368                 return textures[unitNdx].tex2D->sample(textures[unitNdx].sampler, texCoords.x(), texCoords.y(), 0.0f);
369         else
370                 return tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
371 }
372
373 // ShaderEvaluator
374
375 ShaderEvaluator::ShaderEvaluator(void) : m_evalFunc(DE_NULL)
376 {
377 }
378
379 ShaderEvaluator::ShaderEvaluator(ShaderEvalFunc evalFunc) : m_evalFunc(evalFunc)
380 {
381 }
382
383 ShaderEvaluator::~ShaderEvaluator(void)
384 {
385 }
386
387 void ShaderEvaluator::evaluate(ShaderEvalContext& ctx)
388 {
389         DE_ASSERT(m_evalFunc);
390         m_evalFunc(ctx);
391 }
392
393 // ShaderRenderCase.
394
395 ShaderRenderCase::ShaderRenderCase(TestContext& testCtx, RenderContext& renderCtx, const ContextInfo& ctxInfo,
396                                                                    const char* name, const char* description, bool isVertexCase,
397                                                                    ShaderEvalFunc evalFunc)
398         : TestCase(testCtx, name, description)
399         , m_renderCtx(renderCtx)
400         , m_ctxInfo(ctxInfo)
401         , m_isVertexCase(isVertexCase)
402         , m_defaultEvaluator(evalFunc)
403         , m_evaluator(m_defaultEvaluator)
404         , m_clearColor(DEFAULT_CLEAR_COLOR)
405         , m_program(DE_NULL)
406 {
407 }
408
409 ShaderRenderCase::ShaderRenderCase(TestContext& testCtx, RenderContext& renderCtx, const ContextInfo& ctxInfo,
410                                                                    const char* name, const char* description, bool isVertexCase,
411                                                                    ShaderEvaluator& evaluator)
412         : TestCase(testCtx, name, description)
413         , m_renderCtx(renderCtx)
414         , m_ctxInfo(ctxInfo)
415         , m_isVertexCase(isVertexCase)
416         , m_defaultEvaluator(DE_NULL)
417         , m_evaluator(evaluator)
418         , m_clearColor(DEFAULT_CLEAR_COLOR)
419         , m_program(DE_NULL)
420 {
421 }
422
423 ShaderRenderCase::~ShaderRenderCase(void)
424 {
425         ShaderRenderCase::deinit();
426 }
427
428 void ShaderRenderCase::init(void)
429 {
430         TestLog&                          log = m_testCtx.getLog();
431         const glw::Functions& gl  = m_renderCtx.getFunctions();
432
433         GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderRenderCase::init() begin");
434
435         DE_ASSERT(!m_program);
436         m_program =
437                 new ShaderProgram(m_renderCtx, glu::makeVtxFragSources(m_vertShaderSource.c_str(), m_fragShaderSource.c_str()));
438
439         try
440         {
441                 log << *m_program; // Always log shader program.
442
443                 if (!m_program->isOk())
444                         TCU_FAIL("Failed to compile shader program");
445
446                 GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderRenderCase::init() end");
447         }
448         catch (const std::exception&)
449         {
450                 // Clean up.
451                 ShaderRenderCase::deinit();
452                 throw;
453         }
454 }
455
456 void ShaderRenderCase::deinit(void)
457 {
458         delete m_program;
459         m_program = DE_NULL;
460 }
461
462 tcu::IVec2 ShaderRenderCase::getViewportSize(void) const
463 {
464         return tcu::IVec2(de::min(m_renderCtx.getRenderTarget().getWidth(), MAX_RENDER_WIDTH),
465                                           de::min(m_renderCtx.getRenderTarget().getHeight(), MAX_RENDER_HEIGHT));
466 }
467
468 TestNode::IterateResult ShaderRenderCase::iterate(void)
469 {
470         const glw::Functions& gl = m_renderCtx.getFunctions();
471
472         GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderRenderCase::iterate() begin");
473
474         DE_ASSERT(m_program);
475         deUint32 programID = m_program->getProgram();
476         gl.useProgram(programID);
477
478         // Create quad grid.
479         IVec2 viewportSize = getViewportSize();
480         int   width                = viewportSize.x();
481         int   height       = viewportSize.y();
482
483         // \todo [petri] Better handling of constCoords (render in multiple chunks, vary coords).
484         QuadGrid quadGrid(m_isVertexCase ? GRID_SIZE : 4, width, height, Vec4(0.0f, 0.0f, 0.0f, 1.0f),
485                                           m_userAttribTransforms, m_textures);
486
487         // Render result.
488         Surface resImage(width, height);
489         render(resImage, programID, quadGrid);
490
491         // Compute reference.
492         Surface refImage(width, height);
493         if (m_isVertexCase)
494                 computeVertexReference(refImage, quadGrid);
495         else
496                 computeFragmentReference(refImage, quadGrid);
497
498         // Compare.
499         bool testOk = compareImages(resImage, refImage, 0.05f);
500
501         // De-initialize.
502         gl.useProgram(0);
503
504         m_testCtx.setTestResult(testOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, testOk ? "Pass" : "Fail");
505         return TestNode::STOP;
506 }
507
508 void ShaderRenderCase::setup(deUint32 programID)
509 {
510         DE_UNREF(programID);
511 }
512
513 void ShaderRenderCase::setupUniforms(deUint32 programID, const Vec4& constCoords)
514 {
515         DE_UNREF(programID);
516         DE_UNREF(constCoords);
517 }
518
519 void ShaderRenderCase::setupDefaultInputs(int programID)
520 {
521         const glw::Functions& gl = m_renderCtx.getFunctions();
522
523         // SETUP UNIFORMS.
524
525         setupDefaultUniforms(m_renderCtx, programID);
526
527         GLU_EXPECT_NO_ERROR(gl.getError(), "post uniform setup");
528
529         // SETUP TEXTURES.
530
531         for (int ndx = 0; ndx < (int)m_textures.size(); ndx++)
532         {
533                 const TextureBinding& tex               = m_textures[ndx];
534                 const tcu::Sampler&   sampler   = tex.getSampler();
535                 deUint32                          texTarget = GL_NONE;
536                 deUint32                          texObj        = 0;
537
538                 if (tex.getType() == TextureBinding::TYPE_NONE)
539                         continue;
540
541                 // Feature check.
542                 if (m_renderCtx.getType().getAPI() == glu::ApiType(2, 0, glu::PROFILE_ES))
543                 {
544                         if (tex.getType() == TextureBinding::TYPE_2D_ARRAY)
545                                 throw tcu::NotSupportedError("2D array texture binding is not supported");
546
547                         if (tex.getType() == TextureBinding::TYPE_3D)
548                                 throw tcu::NotSupportedError("3D texture binding is not supported");
549
550                         if (sampler.compare != tcu::Sampler::COMPAREMODE_NONE)
551                                 throw tcu::NotSupportedError("Shadow lookups are not supported");
552                 }
553
554                 switch (tex.getType())
555                 {
556                 case TextureBinding::TYPE_2D:
557                         texTarget = GL_TEXTURE_2D;
558                         texObj  = tex.get2D()->getGLTexture();
559                         break;
560                 case TextureBinding::TYPE_CUBE_MAP:
561                         texTarget = GL_TEXTURE_CUBE_MAP;
562                         texObj  = tex.getCube()->getGLTexture();
563                         break;
564                 case TextureBinding::TYPE_2D_ARRAY:
565                         texTarget = GL_TEXTURE_2D_ARRAY;
566                         texObj  = tex.get2DArray()->getGLTexture();
567                         break;
568                 case TextureBinding::TYPE_3D:
569                         texTarget = GL_TEXTURE_3D;
570                         texObj  = tex.get3D()->getGLTexture();
571                         break;
572                 default:
573                         DE_ASSERT(DE_FALSE);
574                 }
575
576                 gl.activeTexture(GL_TEXTURE0 + ndx);
577                 gl.bindTexture(texTarget, texObj);
578                 gl.texParameteri(texTarget, GL_TEXTURE_WRAP_S, glu::getGLWrapMode(sampler.wrapS));
579                 gl.texParameteri(texTarget, GL_TEXTURE_WRAP_T, glu::getGLWrapMode(sampler.wrapT));
580                 gl.texParameteri(texTarget, GL_TEXTURE_MIN_FILTER, glu::getGLFilterMode(sampler.minFilter));
581                 gl.texParameteri(texTarget, GL_TEXTURE_MAG_FILTER, glu::getGLFilterMode(sampler.magFilter));
582
583                 if (texTarget == GL_TEXTURE_3D)
584                         gl.texParameteri(texTarget, GL_TEXTURE_WRAP_R, glu::getGLWrapMode(sampler.wrapR));
585
586                 if (sampler.compare != tcu::Sampler::COMPAREMODE_NONE)
587                 {
588                         gl.texParameteri(texTarget, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
589                         gl.texParameteri(texTarget, GL_TEXTURE_COMPARE_FUNC, glu::getGLCompareFunc(sampler.compare));
590                 }
591         }
592
593         GLU_EXPECT_NO_ERROR(gl.getError(), "texture sampler setup");
594 }
595
596 static void getDefaultVertexArrays(const glw::Functions& gl, const QuadGrid& quadGrid, deUint32 program,
597                                                                    vector<VertexArrayBinding>& vertexArrays)
598 {
599         const int numElements = quadGrid.getNumVertices();
600
601         vertexArrays.push_back(va::Float("a_position", 4, numElements, 0, (const float*)quadGrid.getPositions()));
602         vertexArrays.push_back(va::Float("a_coords", 4, numElements, 0, (const float*)quadGrid.getCoords()));
603         vertexArrays.push_back(va::Float("a_unitCoords", 4, numElements, 0, (const float*)quadGrid.getUnitCoords()));
604         vertexArrays.push_back(va::Float("a_one", 1, numElements, 0, quadGrid.getAttribOne()));
605
606         // a_inN.
607         for (int userNdx = 0; userNdx < quadGrid.getNumUserAttribs(); userNdx++)
608         {
609                 string name = string("a_in") + de::toString(userNdx);
610                 vertexArrays.push_back(va::Float(name, 4, numElements, 0, (const float*)quadGrid.getUserAttrib(userNdx)));
611         }
612
613         // Matrix attributes - these are set by location
614         static const struct
615         {
616                 const char* name;
617                 int                     numCols;
618                 int                     numRows;
619         } matrices[] = { { "a_mat2", 2, 2 },   { "a_mat2x3", 2, 3 }, { "a_mat2x4", 2, 4 },
620                                          { "a_mat3x2", 3, 2 }, { "a_mat3", 3, 3 },   { "a_mat3x4", 3, 4 },
621                                          { "a_mat4x2", 4, 2 }, { "a_mat4x3", 4, 3 }, { "a_mat4", 4, 4 } };
622
623         for (int matNdx = 0; matNdx < DE_LENGTH_OF_ARRAY(matrices); matNdx++)
624         {
625                 int loc = gl.getAttribLocation(program, matrices[matNdx].name);
626
627                 if (loc < 0)
628                         continue; // Not used in shader.
629
630                 int numRows = matrices[matNdx].numRows;
631                 int numCols = matrices[matNdx].numCols;
632
633                 for (int colNdx = 0; colNdx < numCols; colNdx++)
634                         vertexArrays.push_back(va::Float(loc + colNdx, numRows, numElements, 4 * (int)sizeof(float),
635                                                                                          (const float*)quadGrid.getUserAttrib(colNdx)));
636         }
637 }
638
639 void ShaderRenderCase::render(Surface& result, int programID, const QuadGrid& quadGrid)
640 {
641         const glw::Functions& gl = m_renderCtx.getFunctions();
642
643         GLU_EXPECT_NO_ERROR(gl.getError(), "pre render");
644
645         // Buffer info.
646         int width  = result.getWidth();
647         int height = result.getHeight();
648
649         int xOffsetMax = m_renderCtx.getRenderTarget().getWidth() - width;
650         int yOffsetMax = m_renderCtx.getRenderTarget().getHeight() - height;
651
652         deUint32   hash = deStringHash(m_vertShaderSource.c_str()) + deStringHash(m_fragShaderSource.c_str());
653         de::Random rnd(hash);
654
655         int xOffset = rnd.getInt(0, xOffsetMax);
656         int yOffset = rnd.getInt(0, yOffsetMax);
657
658         gl.viewport(xOffset, yOffset, width, height);
659
660         // Setup program.
661         setupUniforms(programID, quadGrid.getConstCoords());
662         setupDefaultInputs(programID);
663
664         // Disable dither.
665         gl.disable(GL_DITHER);
666
667         // Clear.
668         gl.clearColor(m_clearColor.x(), m_clearColor.y(), m_clearColor.z(), m_clearColor.w());
669         gl.clear(GL_COLOR_BUFFER_BIT);
670
671         // Draw.
672         {
673                 std::vector<VertexArrayBinding> vertexArrays;
674                 const int                                               numElements = quadGrid.getNumTriangles() * 3;
675
676                 getDefaultVertexArrays(gl, quadGrid, programID, vertexArrays);
677                 draw(m_renderCtx, programID, (int)vertexArrays.size(), &vertexArrays[0],
678                          pr::Triangles(numElements, quadGrid.getIndices()));
679         }
680         GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
681
682         // Read back results.
683         glu::readPixels(m_renderCtx, xOffset, yOffset, result.getAccess());
684
685         GLU_EXPECT_NO_ERROR(gl.getError(), "post render");
686 }
687
688 void ShaderRenderCase::computeVertexReference(Surface& result, const QuadGrid& quadGrid)
689 {
690         // Buffer info.
691         int                               width = result.getWidth();
692         int                               height   = result.getHeight();
693         int                               gridSize = quadGrid.getGridSize();
694         int                               stride   = gridSize + 1;
695         bool                      hasAlpha = m_renderCtx.getRenderTarget().getPixelFormat().alphaBits > 0;
696         ShaderEvalContext evalCtx(quadGrid);
697
698         // Evaluate color for each vertex.
699         vector<Vec4> colors((gridSize + 1) * (gridSize + 1));
700         for (int y = 0; y < gridSize + 1; y++)
701                 for (int x = 0; x < gridSize + 1; x++)
702                 {
703                         float sx         = static_cast<float>(x) / static_cast<float>(gridSize);
704                         float sy         = static_cast<float>(y) / static_cast<float>(gridSize);
705                         int   vtxNdx = ((y * (gridSize + 1)) + x);
706
707                         evalCtx.reset(sx, sy);
708                         m_evaluator.evaluate(evalCtx);
709                         DE_ASSERT(!evalCtx.isDiscarded); // Discard is not available in vertex shader.
710                         Vec4 color = evalCtx.color;
711
712                         if (!hasAlpha)
713                                 color.w() = 1.0f;
714
715                         colors[vtxNdx] = color;
716                 }
717
718         // Render quads.
719         for (int y = 0; y < gridSize; y++)
720                 for (int x = 0; x < gridSize; x++)
721                 {
722                         float x0 = static_cast<float>(x) / static_cast<float>(gridSize);
723                         float x1 = static_cast<float>(x + 1) / static_cast<float>(gridSize);
724                         float y0 = static_cast<float>(y) / static_cast<float>(gridSize);
725                         float y1 = static_cast<float>(y + 1) / static_cast<float>(gridSize);
726
727                         float sx0  = x0 * (float)width;
728                         float sx1  = x1 * (float)width;
729                         float sy0  = y0 * (float)height;
730                         float sy1  = y1 * (float)height;
731                         float oosx = 1.0f / (sx1 - sx0);
732                         float oosy = 1.0f / (sy1 - sy0);
733
734                         int ix0 = deCeilFloatToInt32(sx0 - 0.5f);
735                         int ix1 = deCeilFloatToInt32(sx1 - 0.5f);
736                         int iy0 = deCeilFloatToInt32(sy0 - 0.5f);
737                         int iy1 = deCeilFloatToInt32(sy1 - 0.5f);
738
739                         int  v00 = (y * stride) + x;
740                         int  v01 = (y * stride) + x + 1;
741                         int  v10 = ((y + 1) * stride) + x;
742                         int  v11 = ((y + 1) * stride) + x + 1;
743                         Vec4 c00 = colors[v00];
744                         Vec4 c01 = colors[v01];
745                         Vec4 c10 = colors[v10];
746                         Vec4 c11 = colors[v11];
747
748                         //printf("(%d,%d) -> (%f..%f, %f..%f) (%d..%d, %d..%d)\n", x, y, sx0, sx1, sy0, sy1, ix0, ix1, iy0, iy1);
749
750                         for (int iy = iy0; iy < iy1; iy++)
751                                 for (int ix = ix0; ix < ix1; ix++)
752                                 {
753                                         DE_ASSERT(deInBounds32(ix, 0, width));
754                                         DE_ASSERT(deInBounds32(iy, 0, height));
755
756                                         float sfx = (float)ix + 0.5f;
757                                         float sfy = (float)iy + 0.5f;
758                                         float fx1 = deFloatClamp((sfx - sx0) * oosx, 0.0f, 1.0f);
759                                         float fy1 = deFloatClamp((sfy - sy0) * oosy, 0.0f, 1.0f);
760
761                                         // Triangle quad interpolation.
762                                         bool            tri   = fx1 + fy1 <= 1.0f;
763                                         float           tx      = tri ? fx1 : (1.0f - fx1);
764                                         float           ty      = tri ? fy1 : (1.0f - fy1);
765                                         const Vec4& t0  = tri ? c00 : c11;
766                                         const Vec4& t1  = tri ? c01 : c10;
767                                         const Vec4& t2  = tri ? c10 : c01;
768                                         Vec4            color = t0 + (t1 - t0) * tx + (t2 - t0) * ty;
769
770                                         // Quantizing for 1-bit alpha
771                                         if ((m_renderCtx.getRenderTarget().getPixelFormat().alphaBits) == 1)
772                                                 color.w() = deFloatRound(color.w());
773
774                                         result.setPixel(ix, iy, toRGBA(color));
775                                 }
776                 }
777 }
778
779 void ShaderRenderCase::computeFragmentReference(Surface& result, const QuadGrid& quadGrid)
780 {
781         // Buffer info.
782         int                               width = result.getWidth();
783         int                               height   = result.getHeight();
784         bool                      hasAlpha = m_renderCtx.getRenderTarget().getPixelFormat().alphaBits > 0;
785         ShaderEvalContext evalCtx(quadGrid);
786
787         // Render.
788         for (int y = 0; y < height; y++)
789                 for (int x = 0; x < width; x++)
790                 {
791                         float sx = ((float)x + 0.5f) / (float)width;
792                         float sy = ((float)y + 0.5f) / (float)height;
793
794                         evalCtx.reset(sx, sy);
795                         m_evaluator.evaluate(evalCtx);
796                         // Select either clear color or computed color based on discarded bit.
797                         Vec4 color = evalCtx.isDiscarded ? m_clearColor : evalCtx.color;
798
799                         if (!hasAlpha)
800                                 color.w() = 1.0f;
801
802                         // Quantizing for 1-bit alpha
803                         if ((m_renderCtx.getRenderTarget().getPixelFormat().alphaBits) == 1)
804                                 color.w() = deFloatRound(color.w());
805
806                         result.setPixel(x, y, toRGBA(color));
807                 }
808 }
809
810 bool ShaderRenderCase::compareImages(const Surface& resImage, const Surface& refImage, float errorThreshold)
811 {
812         return tcu::fuzzyCompare(m_testCtx.getLog(), "ComparisonResult", "Image comparison result", refImage, resImage,
813                                                          errorThreshold, tcu::COMPARE_LOG_RESULT);
814 }
815
816 // Uniform name helpers.
817
818 const char* getIntUniformName(int number)
819 {
820         switch (number)
821         {
822         case 0:
823                 return "ui_zero";
824         case 1:
825                 return "ui_one";
826         case 2:
827                 return "ui_two";
828         case 3:
829                 return "ui_three";
830         case 4:
831                 return "ui_four";
832         case 5:
833                 return "ui_five";
834         case 6:
835                 return "ui_six";
836         case 7:
837                 return "ui_seven";
838         case 8:
839                 return "ui_eight";
840         case 101:
841                 return "ui_oneHundredOne";
842         default:
843                 DE_ASSERT(false);
844                 return "";
845         }
846 }
847
848 const char* getFloatUniformName(int number)
849 {
850         switch (number)
851         {
852         case 0:
853                 return "uf_zero";
854         case 1:
855                 return "uf_one";
856         case 2:
857                 return "uf_two";
858         case 3:
859                 return "uf_three";
860         case 4:
861                 return "uf_four";
862         case 5:
863                 return "uf_five";
864         case 6:
865                 return "uf_six";
866         case 7:
867                 return "uf_seven";
868         case 8:
869                 return "uf_eight";
870         default:
871                 DE_ASSERT(false);
872                 return "";
873         }
874 }
875
876 const char* getFloatFractionUniformName(int number)
877 {
878         switch (number)
879         {
880         case 1:
881                 return "uf_one";
882         case 2:
883                 return "uf_half";
884         case 3:
885                 return "uf_third";
886         case 4:
887                 return "uf_fourth";
888         case 5:
889                 return "uf_fifth";
890         case 6:
891                 return "uf_sixth";
892         case 7:
893                 return "uf_seventh";
894         case 8:
895                 return "uf_eighth";
896         default:
897                 DE_ASSERT(false);
898                 return "";
899         }
900 }
901
902 void setupDefaultUniforms(const glu::RenderContext& context, deUint32 programID)
903 {
904         const glw::Functions& gl = context.getFunctions();
905
906         // Bool.
907         struct BoolUniform
908         {
909                 const char* name;
910                 bool            value;
911         };
912         static const BoolUniform s_boolUniforms[] = {
913                 { "ub_true", true }, { "ub_false", false },
914         };
915
916         for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_boolUniforms); i++)
917         {
918                 int uniLoc = gl.getUniformLocation(programID, s_boolUniforms[i].name);
919                 if (uniLoc != -1)
920                         gl.uniform1i(uniLoc, s_boolUniforms[i].value);
921         }
922
923         // BVec4.
924         struct BVec4Uniform
925         {
926                 const char* name;
927                 BVec4           value;
928         };
929         static const BVec4Uniform s_bvec4Uniforms[] = {
930                 { "ub4_true", BVec4(true) }, { "ub4_false", BVec4(false) },
931         };
932
933         for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_bvec4Uniforms); i++)
934         {
935                 const BVec4Uniform& uni = s_bvec4Uniforms[i];
936                 int                                     arr[4];
937                 arr[0]   = (int)uni.value.x();
938                 arr[1]   = (int)uni.value.y();
939                 arr[2]   = (int)uni.value.z();
940                 arr[3]   = (int)uni.value.w();
941                 int uniLoc = gl.getUniformLocation(programID, uni.name);
942                 if (uniLoc != -1)
943                         gl.uniform4iv(uniLoc, 1, &arr[0]);
944         }
945
946         // Int.
947         struct IntUniform
948         {
949                 const char* name;
950                 int                     value;
951         };
952         static const IntUniform s_intUniforms[] = {
953                 { "ui_minusOne", -1 },          { "ui_zero", 0 }, { "ui_one", 1 }, { "ui_two", 2 },   { "ui_three", 3 },
954                 { "ui_four", 4 },                       { "ui_five", 5 }, { "ui_six", 6 }, { "ui_seven", 7 }, { "ui_eight", 8 },
955                 { "ui_oneHundredOne", 101 }
956         };
957
958         for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_intUniforms); i++)
959         {
960                 int uniLoc = gl.getUniformLocation(programID, s_intUniforms[i].name);
961                 if (uniLoc != -1)
962                         gl.uniform1i(uniLoc, s_intUniforms[i].value);
963         }
964
965         // IVec2.
966         struct IVec2Uniform
967         {
968                 const char* name;
969                 IVec2           value;
970         };
971         static const IVec2Uniform s_ivec2Uniforms[] = { { "ui2_minusOne", IVec2(-1) }, { "ui2_zero", IVec2(0) },
972                                                                                                         { "ui2_one", IVec2(1) },           { "ui2_two", IVec2(2) },
973                                                                                                         { "ui2_four", IVec2(4) },         { "ui2_five", IVec2(5) } };
974
975         for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_ivec2Uniforms); i++)
976         {
977                 int uniLoc = gl.getUniformLocation(programID, s_ivec2Uniforms[i].name);
978                 if (uniLoc != -1)
979                         gl.uniform2iv(uniLoc, 1, s_ivec2Uniforms[i].value.getPtr());
980         }
981
982         // IVec3.
983         struct IVec3Uniform
984         {
985                 const char* name;
986                 IVec3           value;
987         };
988         static const IVec3Uniform s_ivec3Uniforms[] = { { "ui3_minusOne", IVec3(-1) }, { "ui3_zero", IVec3(0) },
989                                                                                                         { "ui3_one", IVec3(1) },           { "ui3_two", IVec3(2) },
990                                                                                                         { "ui3_four", IVec3(4) },         { "ui3_five", IVec3(5) } };
991
992         for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_ivec3Uniforms); i++)
993         {
994                 int uniLoc = gl.getUniformLocation(programID, s_ivec3Uniforms[i].name);
995                 if (uniLoc != -1)
996                         gl.uniform3iv(uniLoc, 1, s_ivec3Uniforms[i].value.getPtr());
997         }
998
999         // IVec4.
1000         struct IVec4Uniform
1001         {
1002                 const char* name;
1003                 IVec4           value;
1004         };
1005         static const IVec4Uniform s_ivec4Uniforms[] = { { "ui4_minusOne", IVec4(-1) }, { "ui4_zero", IVec4(0) },
1006                                                                                                         { "ui4_one", IVec4(1) },           { "ui4_two", IVec4(2) },
1007                                                                                                         { "ui4_four", IVec4(4) },         { "ui4_five", IVec4(5) } };
1008
1009         for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_ivec4Uniforms); i++)
1010         {
1011                 int uniLoc = gl.getUniformLocation(programID, s_ivec4Uniforms[i].name);
1012                 if (uniLoc != -1)
1013                         gl.uniform4iv(uniLoc, 1, s_ivec4Uniforms[i].value.getPtr());
1014         }
1015
1016         // Float.
1017         struct FloatUniform
1018         {
1019                 const char* name;
1020                 float           value;
1021         };
1022         static const FloatUniform s_floatUniforms[] = {
1023                 { "uf_zero", 0.0f },             { "uf_one", 1.0f },              { "uf_two", 2.0f },
1024                 { "uf_three", 3.0f },            { "uf_four", 4.0f },             { "uf_five", 5.0f },
1025                 { "uf_six", 6.0f },                      { "uf_seven", 7.0f },            { "uf_eight", 8.0f },
1026                 { "uf_half", 1.0f / 2.0f },  { "uf_third", 1.0f / 3.0f }, { "uf_fourth", 1.0f / 4.0f },
1027                 { "uf_fifth", 1.0f / 5.0f }, { "uf_sixth", 1.0f / 6.0f }, { "uf_seventh", 1.0f / 7.0f },
1028                 { "uf_eighth", 1.0f / 8.0f }
1029         };
1030
1031         for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_floatUniforms); i++)
1032         {
1033                 int uniLoc = gl.getUniformLocation(programID, s_floatUniforms[i].name);
1034                 if (uniLoc != -1)
1035                         gl.uniform1f(uniLoc, s_floatUniforms[i].value);
1036         }
1037
1038         // Vec2.
1039         struct Vec2Uniform
1040         {
1041                 const char* name;
1042                 Vec2            value;
1043         };
1044         static const Vec2Uniform s_vec2Uniforms[] = {
1045                 { "uv2_minusOne", Vec2(-1.0f) }, { "uv2_zero", Vec2(0.0f) }, { "uv2_half", Vec2(0.5f) },
1046                 { "uv2_one", Vec2(1.0f) },               { "uv2_two", Vec2(2.0f) },
1047         };
1048
1049         for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_vec2Uniforms); i++)
1050         {
1051                 int uniLoc = gl.getUniformLocation(programID, s_vec2Uniforms[i].name);
1052                 if (uniLoc != -1)
1053                         gl.uniform2fv(uniLoc, 1, s_vec2Uniforms[i].value.getPtr());
1054         }
1055
1056         // Vec3.
1057         struct Vec3Uniform
1058         {
1059                 const char* name;
1060                 Vec3            value;
1061         };
1062         static const Vec3Uniform s_vec3Uniforms[] = {
1063                 { "uv3_minusOne", Vec3(-1.0f) }, { "uv3_zero", Vec3(0.0f) }, { "uv3_half", Vec3(0.5f) },
1064                 { "uv3_one", Vec3(1.0f) },               { "uv3_two", Vec3(2.0f) },
1065         };
1066
1067         for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_vec3Uniforms); i++)
1068         {
1069                 int uniLoc = gl.getUniformLocation(programID, s_vec3Uniforms[i].name);
1070                 if (uniLoc != -1)
1071                         gl.uniform3fv(uniLoc, 1, s_vec3Uniforms[i].value.getPtr());
1072         }
1073
1074         // Vec4.
1075         struct Vec4Uniform
1076         {
1077                 const char* name;
1078                 Vec4            value;
1079         };
1080         static const Vec4Uniform s_vec4Uniforms[] = {
1081                 { "uv4_minusOne", Vec4(-1.0f) },
1082                 { "uv4_zero", Vec4(0.0f) },
1083                 { "uv4_half", Vec4(0.5f) },
1084                 { "uv4_one", Vec4(1.0f) },
1085                 { "uv4_two", Vec4(2.0f) },
1086                 { "uv4_black", Vec4(0.0f, 0.0f, 0.0f, 1.0f) },
1087                 { "uv4_gray", Vec4(0.5f, 0.5f, 0.5f, 1.0f) },
1088                 { "uv4_white", Vec4(1.0f, 1.0f, 1.0f, 1.0f) },
1089         };
1090
1091         for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_vec4Uniforms); i++)
1092         {
1093                 int uniLoc = gl.getUniformLocation(programID, s_vec4Uniforms[i].name);
1094                 if (uniLoc != -1)
1095                         gl.uniform4fv(uniLoc, 1, s_vec4Uniforms[i].value.getPtr());
1096         }
1097 }
1098
1099 } // deqp