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