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