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