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