1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Opaque type (sampler, buffer, atomic counter, ...) indexing tests.
22 *
23 * \todo [2014-03-05 pyry] Extend with following:
24 * + sampler: different filtering modes, multiple sizes, incomplete textures
25 * + SSBO: write, atomic op, unsized array .length()
26 *//*--------------------------------------------------------------------*/
27
28 #include "es31fOpaqueTypeIndexingTests.hpp"
29 #include "tcuTexture.hpp"
30 #include "tcuTestLog.hpp"
31 #include "tcuFormatUtil.hpp"
32 #include "tcuVectorUtil.hpp"
33 #include "gluShaderUtil.hpp"
34 #include "gluShaderProgram.hpp"
35 #include "gluObjectWrapper.hpp"
36 #include "gluTextureUtil.hpp"
37 #include "gluRenderContext.hpp"
38 #include "gluProgramInterfaceQuery.hpp"
39 #include "gluContextInfo.hpp"
40 #include "glsShaderExecUtil.hpp"
41 #include "glwFunctions.hpp"
42 #include "glwEnums.hpp"
43 #include "deUniquePtr.hpp"
44 #include "deStringUtil.hpp"
45 #include "deRandom.hpp"
46
47 #include <sstream>
48
49 namespace deqp
50 {
51 namespace gles31
52 {
53 namespace Functional
54 {
55
56 namespace
57 {
58
59 using namespace gls::ShaderExecUtil;
60 using namespace glu;
61 using std::string;
62 using std::vector;
63 using tcu::TextureFormat;
64 using tcu::TestLog;
65
66 typedef de::UniquePtr<ShaderExecutor> ShaderExecutorPtr;
67
68 enum IndexExprType
69 {
70 INDEX_EXPR_TYPE_CONST_LITERAL = 0,
71 INDEX_EXPR_TYPE_CONST_EXPRESSION,
72 INDEX_EXPR_TYPE_UNIFORM,
73 INDEX_EXPR_TYPE_DYNAMIC_UNIFORM,
74
75 INDEX_EXPR_TYPE_LAST
76 };
77
78 enum TextureType
79 {
80 TEXTURE_TYPE_1D = 0,
81 TEXTURE_TYPE_2D,
82 TEXTURE_TYPE_CUBE,
83 TEXTURE_TYPE_2D_ARRAY,
84 TEXTURE_TYPE_3D,
85
86 TEXTURE_TYPE_LAST
87 };
88
declareUniformIndexVars(std::ostream & str,const char * varPrefix,int numVars)89 static void declareUniformIndexVars (std::ostream& str, const char* varPrefix, int numVars)
90 {
91 for (int varNdx = 0; varNdx < numVars; varNdx++)
92 str << "uniform highp int " << varPrefix << varNdx << ";\n";
93 }
94
uploadUniformIndices(const glw::Functions & gl,deUint32 program,const char * varPrefix,int numIndices,const int * indices)95 static void uploadUniformIndices (const glw::Functions& gl, deUint32 program, const char* varPrefix, int numIndices, const int* indices)
96 {
97 for (int varNdx = 0; varNdx < numIndices; varNdx++)
98 {
99 const string varName = varPrefix + de::toString(varNdx);
100 const int loc = gl.getUniformLocation(program, varName.c_str());
101 TCU_CHECK_MSG(loc >= 0, ("No location assigned for uniform '" + varName + "'").c_str());
102
103 gl.uniform1i(loc, indices[varNdx]);
104 }
105 }
106
107 template<typename T>
maxElement(const std::vector<T> & elements)108 static T maxElement (const std::vector<T>& elements)
109 {
110 T maxElem = elements[0];
111
112 for (size_t ndx = 1; ndx < elements.size(); ndx++)
113 maxElem = de::max(maxElem, elements[ndx]);
114
115 return maxElem;
116 }
117
getTextureType(glu::DataType samplerType)118 static TextureType getTextureType (glu::DataType samplerType)
119 {
120 switch (samplerType)
121 {
122 case glu::TYPE_SAMPLER_1D:
123 case glu::TYPE_INT_SAMPLER_1D:
124 case glu::TYPE_UINT_SAMPLER_1D:
125 case glu::TYPE_SAMPLER_1D_SHADOW:
126 return TEXTURE_TYPE_1D;
127
128 case glu::TYPE_SAMPLER_2D:
129 case glu::TYPE_INT_SAMPLER_2D:
130 case glu::TYPE_UINT_SAMPLER_2D:
131 case glu::TYPE_SAMPLER_2D_SHADOW:
132 return TEXTURE_TYPE_2D;
133
134 case glu::TYPE_SAMPLER_CUBE:
135 case glu::TYPE_INT_SAMPLER_CUBE:
136 case glu::TYPE_UINT_SAMPLER_CUBE:
137 case glu::TYPE_SAMPLER_CUBE_SHADOW:
138 return TEXTURE_TYPE_CUBE;
139
140 case glu::TYPE_SAMPLER_2D_ARRAY:
141 case glu::TYPE_INT_SAMPLER_2D_ARRAY:
142 case glu::TYPE_UINT_SAMPLER_2D_ARRAY:
143 case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW:
144 return TEXTURE_TYPE_2D_ARRAY;
145
146 case glu::TYPE_SAMPLER_3D:
147 case glu::TYPE_INT_SAMPLER_3D:
148 case glu::TYPE_UINT_SAMPLER_3D:
149 return TEXTURE_TYPE_3D;
150
151 default:
152 throw tcu::InternalError("Invalid sampler type");
153 }
154 }
155
isShadowSampler(glu::DataType samplerType)156 static bool isShadowSampler (glu::DataType samplerType)
157 {
158 return samplerType == glu::TYPE_SAMPLER_1D_SHADOW ||
159 samplerType == glu::TYPE_SAMPLER_2D_SHADOW ||
160 samplerType == glu::TYPE_SAMPLER_2D_ARRAY_SHADOW ||
161 samplerType == glu::TYPE_SAMPLER_CUBE_SHADOW;
162 }
163
getSamplerOutputType(glu::DataType samplerType)164 static glu::DataType getSamplerOutputType (glu::DataType samplerType)
165 {
166 switch (samplerType)
167 {
168 case glu::TYPE_SAMPLER_1D:
169 case glu::TYPE_SAMPLER_2D:
170 case glu::TYPE_SAMPLER_CUBE:
171 case glu::TYPE_SAMPLER_2D_ARRAY:
172 case glu::TYPE_SAMPLER_3D:
173 return glu::TYPE_FLOAT_VEC4;
174
175 case glu::TYPE_SAMPLER_1D_SHADOW:
176 case glu::TYPE_SAMPLER_2D_SHADOW:
177 case glu::TYPE_SAMPLER_CUBE_SHADOW:
178 case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW:
179 return glu::TYPE_FLOAT;
180
181 case glu::TYPE_INT_SAMPLER_1D:
182 case glu::TYPE_INT_SAMPLER_2D:
183 case glu::TYPE_INT_SAMPLER_CUBE:
184 case glu::TYPE_INT_SAMPLER_2D_ARRAY:
185 case glu::TYPE_INT_SAMPLER_3D:
186 return glu::TYPE_INT_VEC4;
187
188 case glu::TYPE_UINT_SAMPLER_1D:
189 case glu::TYPE_UINT_SAMPLER_2D:
190 case glu::TYPE_UINT_SAMPLER_CUBE:
191 case glu::TYPE_UINT_SAMPLER_2D_ARRAY:
192 case glu::TYPE_UINT_SAMPLER_3D:
193 return glu::TYPE_UINT_VEC4;
194
195 default:
196 throw tcu::InternalError("Invalid sampler type");
197 }
198 }
199
getSamplerTextureFormat(glu::DataType samplerType)200 static tcu::TextureFormat getSamplerTextureFormat (glu::DataType samplerType)
201 {
202 const glu::DataType outType = getSamplerOutputType(samplerType);
203 const glu::DataType outScalarType = glu::getDataTypeScalarType(outType);
204
205 switch (outScalarType)
206 {
207 case glu::TYPE_FLOAT:
208 if (isShadowSampler(samplerType))
209 return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16);
210 else
211 return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
212
213 case glu::TYPE_INT: return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT8);
214 case glu::TYPE_UINT: return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT8);
215
216 default:
217 throw tcu::InternalError("Invalid sampler type");
218 }
219 }
220
getSamplerCoordType(glu::DataType samplerType)221 static glu::DataType getSamplerCoordType (glu::DataType samplerType)
222 {
223 const TextureType texType = getTextureType(samplerType);
224 int numCoords = 0;
225
226 switch (texType)
227 {
228 case TEXTURE_TYPE_1D: numCoords = 1; break;
229 case TEXTURE_TYPE_2D: numCoords = 2; break;
230 case TEXTURE_TYPE_2D_ARRAY: numCoords = 3; break;
231 case TEXTURE_TYPE_CUBE: numCoords = 3; break;
232 case TEXTURE_TYPE_3D: numCoords = 3; break;
233 default:
234 DE_ASSERT(false);
235 }
236
237 if (isShadowSampler(samplerType))
238 numCoords += 1;
239
240 DE_ASSERT(de::inRange(numCoords, 1, 4));
241
242 return numCoords == 1 ? glu::TYPE_FLOAT : glu::getDataTypeFloatVec(numCoords);
243 }
244
getGLTextureTarget(TextureType texType)245 static deUint32 getGLTextureTarget (TextureType texType)
246 {
247 switch (texType)
248 {
249 case TEXTURE_TYPE_1D: return GL_TEXTURE_1D;
250 case TEXTURE_TYPE_2D: return GL_TEXTURE_2D;
251 case TEXTURE_TYPE_2D_ARRAY: return GL_TEXTURE_2D_ARRAY;
252 case TEXTURE_TYPE_CUBE: return GL_TEXTURE_CUBE_MAP;
253 case TEXTURE_TYPE_3D: return GL_TEXTURE_3D;
254 default:
255 DE_ASSERT(false);
256 return 0;
257 }
258 }
259
setupTexture(const glw::Functions & gl,deUint32 texture,glu::DataType samplerType,tcu::TextureFormat texFormat,const void * color)260 static void setupTexture (const glw::Functions& gl,
261 deUint32 texture,
262 glu::DataType samplerType,
263 tcu::TextureFormat texFormat,
264 const void* color)
265 {
266 const TextureType texType = getTextureType(samplerType);
267 const deUint32 texTarget = getGLTextureTarget(texType);
268 const deUint32 intFormat = glu::getInternalFormat(texFormat);
269 const glu::TransferFormat transferFmt = glu::getTransferFormat(texFormat);
270
271 // \todo [2014-03-04 pyry] Use larger than 1x1 textures?
272
273 gl.bindTexture(texTarget, texture);
274
275 switch (texType)
276 {
277 case TEXTURE_TYPE_1D:
278 gl.texStorage1D(texTarget, 1, intFormat, 1);
279 gl.texSubImage1D(texTarget, 0, 0, 1, transferFmt.format, transferFmt.dataType, color);
280 break;
281
282 case TEXTURE_TYPE_2D:
283 gl.texStorage2D(texTarget, 1, intFormat, 1, 1);
284 gl.texSubImage2D(texTarget, 0, 0, 0, 1, 1, transferFmt.format, transferFmt.dataType, color);
285 break;
286
287 case TEXTURE_TYPE_2D_ARRAY:
288 case TEXTURE_TYPE_3D:
289 gl.texStorage3D(texTarget, 1, intFormat, 1, 1, 1);
290 gl.texSubImage3D(texTarget, 0, 0, 0, 0, 1, 1, 1, transferFmt.format, transferFmt.dataType, color);
291 break;
292
293 case TEXTURE_TYPE_CUBE:
294 gl.texStorage2D(texTarget, 1, intFormat, 1, 1);
295 for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
296 gl.texSubImage2D(glu::getGLCubeFace((tcu::CubeFace)face), 0, 0, 0, 1, 1, transferFmt.format, transferFmt.dataType, color);
297 break;
298
299 default:
300 DE_ASSERT(false);
301 }
302
303 gl.texParameteri(texTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
304 gl.texParameteri(texTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
305
306 if (isShadowSampler(samplerType))
307 gl.texParameteri(texTarget, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
308
309 GLU_EXPECT_NO_ERROR(gl.getError(), "Texture setup failed");
310 }
311
312 class SamplerIndexingCase : public TestCase
313 {
314 public:
315 SamplerIndexingCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType, glu::DataType samplerType, IndexExprType indexExprType);
316 ~SamplerIndexingCase (void);
317
318 void init (void);
319 IterateResult iterate (void);
320
321 private:
322 SamplerIndexingCase (const SamplerIndexingCase&);
323 SamplerIndexingCase& operator= (const SamplerIndexingCase&);
324
325 void getShaderSpec (ShaderSpec* spec, int numSamplers, int numLookups, const int* lookupIndices) const;
326
327 const glu::ShaderType m_shaderType;
328 const glu::DataType m_samplerType;
329 const IndexExprType m_indexExprType;
330 };
331
SamplerIndexingCase(Context & context,const char * name,const char * description,glu::ShaderType shaderType,glu::DataType samplerType,IndexExprType indexExprType)332 SamplerIndexingCase::SamplerIndexingCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType, glu::DataType samplerType, IndexExprType indexExprType)
333 : TestCase (context, name, description)
334 , m_shaderType (shaderType)
335 , m_samplerType (samplerType)
336 , m_indexExprType (indexExprType)
337 {
338 }
339
~SamplerIndexingCase(void)340 SamplerIndexingCase::~SamplerIndexingCase (void)
341 {
342 }
343
init(void)344 void SamplerIndexingCase::init (void)
345 {
346 const char* extName = "GL_EXT_gpu_shader5";
347
348 if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL &&
349 !m_context.getContextInfo().isExtensionSupported(extName))
350 throw tcu::NotSupportedError(string(extName) + " extension is required for dynamic indexing of sampler arrays");
351 }
352
getShaderSpec(ShaderSpec * spec,int numSamplers,int numLookups,const int * lookupIndices) const353 void SamplerIndexingCase::getShaderSpec (ShaderSpec* spec, int numSamplers, int numLookups, const int* lookupIndices) const
354 {
355 const char* samplersName = "sampler";
356 const char* coordsName = "coords";
357 const char* indicesPrefix = "index";
358 const char* resultPrefix = "result";
359 const DataType coordType = getSamplerCoordType(m_samplerType);
360 const DataType outType = getSamplerOutputType(m_samplerType);
361 std::ostringstream global, code;
362
363 spec->inputs.push_back(Symbol(coordsName, VarType(coordType, PRECISION_HIGHP)));
364
365 if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL)
366 global << "#extension GL_EXT_gpu_shader5 : require\n";
367
368 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
369 global << "const highp int indexBase = 1;\n";
370
371 global <<
372 "uniform highp " << getDataTypeName(m_samplerType) << " " << samplersName << "[" << numSamplers << "];\n";
373
374 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
375 {
376 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
377 {
378 const string varName = indicesPrefix + de::toString(lookupNdx);
379 spec->inputs.push_back(Symbol(varName, VarType(TYPE_INT, PRECISION_HIGHP)));
380 }
381 }
382 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
383 declareUniformIndexVars(global, indicesPrefix, numLookups);
384
385 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
386 {
387 const string varName = resultPrefix + de::toString(lookupNdx);
388 spec->outputs.push_back(Symbol(varName, VarType(outType, PRECISION_HIGHP)));
389 }
390
391 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
392 {
393 code << resultPrefix << "" << lookupNdx << " = texture(" << samplersName << "[";
394
395 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL)
396 code << lookupIndices[lookupNdx];
397 else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
398 code << "indexBase + " << (lookupIndices[lookupNdx]-1);
399 else
400 code << indicesPrefix << lookupNdx;
401
402 code << "], " << coordsName << ");\n";
403 }
404
405 spec->version = GLSL_VERSION_310_ES;
406 spec->globalDeclarations = global.str();
407 spec->source = code.str();
408 }
409
fillTextureData(const tcu::PixelBufferAccess & access,de::Random & rnd)410 static void fillTextureData (const tcu::PixelBufferAccess& access, de::Random& rnd)
411 {
412 DE_ASSERT(access.getHeight() == 1 && access.getDepth() == 1);
413
414 if (access.getFormat().order == TextureFormat::D)
415 {
416 // \note Texture uses odd values, lookup even values to avoid precision issues.
417 const float values[] = { 0.1f, 0.3f, 0.5f, 0.7f, 0.9f };
418
419 for (int ndx = 0; ndx < access.getWidth(); ndx++)
420 access.setPixDepth(rnd.choose<float>(DE_ARRAY_BEGIN(values), DE_ARRAY_END(values)), ndx, 0);
421 }
422 else
423 {
424 TCU_CHECK_INTERNAL(access.getFormat().order == TextureFormat::RGBA && access.getFormat().getPixelSize() == 4);
425
426 for (int ndx = 0; ndx < access.getWidth(); ndx++)
427 *((deUint32*)access.getDataPtr() + ndx) = rnd.getUint32();
428 }
429 }
430
iterate(void)431 SamplerIndexingCase::IterateResult SamplerIndexingCase::iterate (void)
432 {
433 const int numInvocations = 64;
434 const int numSamplers = 8;
435 const int numLookups = 4;
436 const DataType coordType = getSamplerCoordType(m_samplerType);
437 const DataType outputType = getSamplerOutputType(m_samplerType);
438 const TextureFormat texFormat = getSamplerTextureFormat(m_samplerType);
439 const int outLookupStride = numInvocations*getDataTypeScalarSize(outputType);
440 vector<int> lookupIndices (numLookups);
441 vector<float> coords;
442 vector<deUint32> outData;
443 vector<deUint8> texData (numSamplers * texFormat.getPixelSize());
444 const tcu::PixelBufferAccess refTexAccess (texFormat, numSamplers, 1, 1, &texData[0]);
445 ShaderSpec shaderSpec;
446 de::Random rnd (deInt32Hash(m_samplerType) ^ deInt32Hash(m_shaderType) ^ deInt32Hash(m_indexExprType));
447
448 for (int ndx = 0; ndx < numLookups; ndx++)
449 lookupIndices[ndx] = rnd.getInt(0, numSamplers-1);
450
451 getShaderSpec(&shaderSpec, numSamplers, numLookups, &lookupIndices[0]);
452
453 coords.resize(numInvocations * getDataTypeScalarSize(coordType));
454
455 if (isShadowSampler(m_samplerType))
456 {
457 // Use different comparison value per invocation.
458 // \note Texture uses odd values, comparison even values.
459 const int numCoordComps = getDataTypeScalarSize(coordType);
460 const float cmpValues[] = { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f };
461
462 for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++)
463 coords[invocationNdx*numCoordComps + (numCoordComps-1)] = rnd.choose<float>(DE_ARRAY_BEGIN(cmpValues), DE_ARRAY_END(cmpValues));
464 }
465
466 fillTextureData(refTexAccess, rnd);
467
468 outData.resize(numLookups*outLookupStride);
469
470 {
471 const RenderContext& renderCtx = m_context.getRenderContext();
472 const glw::Functions& gl = renderCtx.getFunctions();
473 ShaderExecutorPtr executor (createExecutor(m_context.getRenderContext(), m_shaderType, shaderSpec));
474 TextureVector textures (renderCtx, numSamplers);
475 vector<void*> inputs;
476 vector<void*> outputs;
477 vector<int> expandedIndices;
478 const int maxIndex = maxElement(lookupIndices);
479
480 m_testCtx.getLog() << *executor;
481
482 if (!executor->isOk())
483 TCU_FAIL("Compile failed");
484
485 executor->useProgram();
486
487 // \todo [2014-03-05 pyry] Do we want to randomize tex unit assignments?
488 for (int samplerNdx = 0; samplerNdx < numSamplers; samplerNdx++)
489 {
490 const string samplerName = string("sampler[") + de::toString(samplerNdx) + "]";
491 const int samplerLoc = gl.getUniformLocation(executor->getProgram(), samplerName.c_str());
492
493 if (samplerNdx > maxIndex && samplerLoc < 0)
494 continue; // Unused uniform eliminated by compiler
495
496 TCU_CHECK_MSG(samplerLoc >= 0, (string("No location for uniform '") + samplerName + "' found").c_str());
497
498 gl.activeTexture(GL_TEXTURE0 + samplerNdx);
499 setupTexture(gl, textures[samplerNdx], m_samplerType, texFormat, &texData[samplerNdx*texFormat.getPixelSize()]);
500
501 gl.uniform1i(samplerLoc, samplerNdx);
502 }
503
504 inputs.push_back(&coords[0]);
505
506 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
507 {
508 expandedIndices.resize(numInvocations * lookupIndices.size());
509 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
510 {
511 for (int invNdx = 0; invNdx < numInvocations; invNdx++)
512 expandedIndices[lookupNdx*numInvocations + invNdx] = lookupIndices[lookupNdx];
513 }
514
515 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
516 inputs.push_back(&expandedIndices[lookupNdx*numInvocations]);
517 }
518 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
519 uploadUniformIndices(gl, executor->getProgram(), "index", numLookups, &lookupIndices[0]);
520
521 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
522 outputs.push_back(&outData[outLookupStride*lookupNdx]);
523
524 GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed");
525
526 executor->execute(numInvocations, &inputs[0], &outputs[0]);
527 }
528
529 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
530
531 if (isShadowSampler(m_samplerType))
532 {
533 const tcu::Sampler refSampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
534 tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0.0f, false /* non-normalized */,
535 tcu::Sampler::COMPAREMODE_LESS);
536 const int numCoordComps = getDataTypeScalarSize(coordType);
537
538 TCU_CHECK_INTERNAL(getDataTypeScalarSize(outputType) == 1);
539
540 // Each invocation may have different results.
541 for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++)
542 {
543 const float coord = coords[invocationNdx*numCoordComps + (numCoordComps-1)];
544
545 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
546 {
547 const int texNdx = lookupIndices[lookupNdx];
548 const float result = *((const float*)(const deUint8*)&outData[lookupNdx*outLookupStride + invocationNdx]);
549 const float reference = refTexAccess.sample2DCompare(refSampler, tcu::Sampler::NEAREST, coord, (float)texNdx, 0.0f, tcu::IVec3(0));
550
551 if (de::abs(result-reference) > 0.005f)
552 {
553 m_testCtx.getLog() << TestLog::Message << "ERROR: at invocation " << invocationNdx << ", lookup " << lookupNdx << ": expected "
554 << reference << ", got " << result
555 << TestLog::EndMessage;
556
557 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
558 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid lookup result");
559 }
560 }
561 }
562 }
563 else
564 {
565 TCU_CHECK_INTERNAL(getDataTypeScalarSize(outputType) == 4);
566
567 // Validate results from first invocation
568 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
569 {
570 const int texNdx = lookupIndices[lookupNdx];
571 const deUint8* resPtr = (const deUint8*)&outData[lookupNdx*outLookupStride];
572 bool isOk;
573
574 if (outputType == TYPE_FLOAT_VEC4)
575 {
576 const float threshold = 1.0f / 256.0f;
577 const tcu::Vec4 reference = refTexAccess.getPixel(texNdx, 0);
578 const float* floatPtr = (const float*)resPtr;
579 const tcu::Vec4 result (floatPtr[0], floatPtr[1], floatPtr[2], floatPtr[3]);
580
581 isOk = boolAll(lessThanEqual(abs(reference-result), tcu::Vec4(threshold)));
582
583 if (!isOk)
584 {
585 m_testCtx.getLog() << TestLog::Message << "ERROR: at lookup " << lookupNdx << ": expected "
586 << reference << ", got " << result
587 << TestLog::EndMessage;
588 }
589 }
590 else
591 {
592 const tcu::UVec4 reference = refTexAccess.getPixelUint(texNdx, 0);
593 const deUint32* uintPtr = (const deUint32*)resPtr;
594 const tcu::UVec4 result (uintPtr[0], uintPtr[1], uintPtr[2], uintPtr[3]);
595
596 isOk = boolAll(equal(reference, result));
597
598 if (!isOk)
599 {
600 m_testCtx.getLog() << TestLog::Message << "ERROR: at lookup " << lookupNdx << ": expected "
601 << reference << ", got " << result
602 << TestLog::EndMessage;
603 }
604 }
605
606 if (!isOk && m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
607 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid lookup result");
608 }
609
610 // Check results of other invocations against first one
611 for (int invocationNdx = 1; invocationNdx < numInvocations; invocationNdx++)
612 {
613 for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
614 {
615 const deUint32* refPtr = &outData[lookupNdx*outLookupStride];
616 const deUint32* resPtr = refPtr + invocationNdx*4;
617 bool isOk = true;
618
619 for (int ndx = 0; ndx < 4; ndx++)
620 isOk = isOk && (refPtr[ndx] == resPtr[ndx]);
621
622 if (!isOk)
623 {
624 m_testCtx.getLog() << TestLog::Message << "ERROR: invocation " << invocationNdx << " result "
625 << tcu::formatArray(tcu::Format::HexIterator<deUint32>(resPtr), tcu::Format::HexIterator<deUint32>(resPtr+4))
626 << " for lookup " << lookupNdx << " doesn't match result from first invocation "
627 << tcu::formatArray(tcu::Format::HexIterator<deUint32>(refPtr), tcu::Format::HexIterator<deUint32>(refPtr+4))
628 << TestLog::EndMessage;
629
630 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
631 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Inconsistent lookup results");
632 }
633 }
634 }
635 }
636
637 return STOP;
638 }
639
640 class BlockArrayIndexingCase : public TestCase
641 {
642 public:
643 enum BlockType
644 {
645 BLOCKTYPE_UNIFORM = 0,
646 BLOCKTYPE_BUFFER,
647
648 BLOCKTYPE_LAST
649 };
650 BlockArrayIndexingCase (Context& context, const char* name, const char* description, BlockType blockType, IndexExprType indexExprType, ShaderType shaderType);
651 ~BlockArrayIndexingCase (void);
652
653 void init (void);
654 IterateResult iterate (void);
655
656 private:
657 BlockArrayIndexingCase (const BlockArrayIndexingCase&);
658 BlockArrayIndexingCase& operator= (const BlockArrayIndexingCase&);
659
660 void getShaderSpec (ShaderSpec* spec, int numInstances, int numReads, const int* readIndices) const;
661
662 const BlockType m_blockType;
663 const IndexExprType m_indexExprType;
664 const ShaderType m_shaderType;
665
666 const int m_numInstances;
667 };
668
BlockArrayIndexingCase(Context & context,const char * name,const char * description,BlockType blockType,IndexExprType indexExprType,ShaderType shaderType)669 BlockArrayIndexingCase::BlockArrayIndexingCase (Context& context, const char* name, const char* description, BlockType blockType, IndexExprType indexExprType, ShaderType shaderType)
670 : TestCase (context, name, description)
671 , m_blockType (blockType)
672 , m_indexExprType (indexExprType)
673 , m_shaderType (shaderType)
674 , m_numInstances (4)
675 {
676 }
677
~BlockArrayIndexingCase(void)678 BlockArrayIndexingCase::~BlockArrayIndexingCase (void)
679 {
680 }
681
init(void)682 void BlockArrayIndexingCase::init (void)
683 {
684 const char* extName = "GL_EXT_gpu_shader5";
685
686 if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL &&
687 !m_context.getContextInfo().isExtensionSupported(extName))
688 throw tcu::NotSupportedError(string(extName) + " extension is required for dynamic indexing of interface blocks");
689
690 if (m_blockType == BLOCKTYPE_BUFFER)
691 {
692 const deUint32 limitPnames[] =
693 {
694 GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS,
695 GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS,
696 GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS,
697 GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS,
698 GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS,
699 GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS
700 };
701
702 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
703 int maxBlocks = 0;
704
705 gl.getIntegerv(limitPnames[m_shaderType], &maxBlocks);
706 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv()");
707
708 if (maxBlocks < m_numInstances)
709 throw tcu::NotSupportedError("Not enough shader storage blocks supported for shader type");
710 }
711 }
712
getShaderSpec(ShaderSpec * spec,int numInstances,int numReads,const int * readIndices) const713 void BlockArrayIndexingCase::getShaderSpec (ShaderSpec* spec, int numInstances, int numReads, const int* readIndices) const
714 {
715 const int binding = 2;
716 const char* blockName = "Block";
717 const char* instanceName = "block";
718 const char* indicesPrefix = "index";
719 const char* resultPrefix = "result";
720 const char* interfaceName = m_blockType == BLOCKTYPE_UNIFORM ? "uniform" : "buffer";
721 const char* layout = m_blockType == BLOCKTYPE_UNIFORM ? "std140" : "std430";
722 std::ostringstream global, code;
723
724 if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL)
725 global << "#extension GL_EXT_gpu_shader5 : require\n";
726
727 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
728 global << "const highp int indexBase = 1;\n";
729
730 global <<
731 "layout(" << layout << ", binding = " << binding << ") " << interfaceName << " " << blockName << "\n"
732 "{\n"
733 " uint value;\n"
734 "} " << instanceName << "[" << numInstances << "];\n";
735
736 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
737 {
738 for (int readNdx = 0; readNdx < numReads; readNdx++)
739 {
740 const string varName = indicesPrefix + de::toString(readNdx);
741 spec->inputs.push_back(Symbol(varName, VarType(TYPE_INT, PRECISION_HIGHP)));
742 }
743 }
744 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
745 declareUniformIndexVars(global, indicesPrefix, numReads);
746
747 for (int readNdx = 0; readNdx < numReads; readNdx++)
748 {
749 const string varName = resultPrefix + de::toString(readNdx);
750 spec->outputs.push_back(Symbol(varName, VarType(TYPE_UINT, PRECISION_HIGHP)));
751 }
752
753 for (int readNdx = 0; readNdx < numReads; readNdx++)
754 {
755 code << resultPrefix << readNdx << " = " << instanceName << "[";
756
757 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL)
758 code << readIndices[readNdx];
759 else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
760 code << "indexBase + " << (readIndices[readNdx]-1);
761 else
762 code << indicesPrefix << readNdx;
763
764 code << "].value;\n";
765 }
766
767 spec->version = GLSL_VERSION_310_ES;
768 spec->globalDeclarations = global.str();
769 spec->source = code.str();
770 }
771
iterate(void)772 BlockArrayIndexingCase::IterateResult BlockArrayIndexingCase::iterate (void)
773 {
774 const int numInvocations = 32;
775 const int numInstances = m_numInstances;
776 const int numReads = 4;
777 vector<int> readIndices (numReads);
778 vector<deUint32> inValues (numInstances);
779 vector<deUint32> outValues (numInvocations*numReads);
780 ShaderSpec shaderSpec;
781 de::Random rnd (deInt32Hash(m_shaderType) ^ deInt32Hash(m_blockType) ^ deInt32Hash(m_indexExprType));
782
783 for (int readNdx = 0; readNdx < numReads; readNdx++)
784 readIndices[readNdx] = rnd.getInt(0, numInstances-1);
785
786 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
787 inValues[instanceNdx] = rnd.getUint32();
788
789 getShaderSpec(&shaderSpec, numInstances, numReads, &readIndices[0]);
790
791 {
792 const RenderContext& renderCtx = m_context.getRenderContext();
793 const glw::Functions& gl = renderCtx.getFunctions();
794 const int baseBinding = 2;
795 const BufferVector buffers (renderCtx, numInstances);
796 const deUint32 bufTarget = m_blockType == BLOCKTYPE_BUFFER ? GL_SHADER_STORAGE_BUFFER : GL_UNIFORM_BUFFER;
797 ShaderExecutorPtr shaderExecutor (createExecutor(renderCtx, m_shaderType, shaderSpec));
798 vector<int> expandedIndices;
799 vector<void*> inputs;
800 vector<void*> outputs;
801
802 m_testCtx.getLog() << *shaderExecutor;
803
804 if (!shaderExecutor->isOk())
805 TCU_FAIL("Compile failed");
806
807 shaderExecutor->useProgram();
808
809 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
810 {
811 gl.bindBuffer(bufTarget, buffers[instanceNdx]);
812 gl.bufferData(bufTarget, (glw::GLsizeiptr)sizeof(deUint32), &inValues[instanceNdx], GL_STATIC_DRAW);
813 gl.bindBufferBase(bufTarget, baseBinding+instanceNdx, buffers[instanceNdx]);
814 }
815
816 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
817 {
818 expandedIndices.resize(numInvocations * readIndices.size());
819
820 for (int readNdx = 0; readNdx < numReads; readNdx++)
821 {
822 int* dst = &expandedIndices[numInvocations*readNdx];
823 std::fill(dst, dst+numInvocations, readIndices[readNdx]);
824 }
825
826 for (int readNdx = 0; readNdx < numReads; readNdx++)
827 inputs.push_back(&expandedIndices[readNdx*numInvocations]);
828 }
829 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
830 uploadUniformIndices(gl, shaderExecutor->getProgram(), "index", numReads, &readIndices[0]);
831
832 for (int readNdx = 0; readNdx < numReads; readNdx++)
833 outputs.push_back(&outValues[readNdx*numInvocations]);
834
835 GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed");
836
837 shaderExecutor->execute(numInvocations, inputs.empty() ? DE_NULL : &inputs[0], &outputs[0]);
838 }
839
840 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
841
842 for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++)
843 {
844 for (int readNdx = 0; readNdx < numReads; readNdx++)
845 {
846 const deUint32 refValue = inValues[readIndices[readNdx]];
847 const deUint32 resValue = outValues[readNdx*numInvocations + invocationNdx];
848
849 if (refValue != resValue)
850 {
851 m_testCtx.getLog() << TestLog::Message << "ERROR: at invocation " << invocationNdx
852 << ", read " << readNdx << ": expected "
853 << tcu::toHex(refValue) << ", got " << tcu::toHex(resValue)
854 << TestLog::EndMessage;
855
856 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
857 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid result value");
858 }
859 }
860 }
861
862 return STOP;
863 }
864
865 class AtomicCounterIndexingCase : public TestCase
866 {
867 public:
868 AtomicCounterIndexingCase (Context& context, const char* name, const char* description, IndexExprType indexExprType, ShaderType shaderType);
869 ~AtomicCounterIndexingCase (void);
870
871 void init (void);
872 IterateResult iterate (void);
873
874 private:
875 AtomicCounterIndexingCase (const AtomicCounterIndexingCase&);
876 AtomicCounterIndexingCase& operator= (const AtomicCounterIndexingCase&);
877
878 void getShaderSpec (ShaderSpec* spec, int numCounters, int numOps, const int* opIndices) const;
879
880 const IndexExprType m_indexExprType;
881 const glu::ShaderType m_shaderType;
882 };
883
AtomicCounterIndexingCase(Context & context,const char * name,const char * description,IndexExprType indexExprType,ShaderType shaderType)884 AtomicCounterIndexingCase::AtomicCounterIndexingCase (Context& context, const char* name, const char* description, IndexExprType indexExprType, ShaderType shaderType)
885 : TestCase (context, name, description)
886 , m_indexExprType (indexExprType)
887 , m_shaderType (shaderType)
888 {
889 }
890
~AtomicCounterIndexingCase(void)891 AtomicCounterIndexingCase::~AtomicCounterIndexingCase (void)
892 {
893 }
894
init(void)895 void AtomicCounterIndexingCase::init (void)
896 {
897 const char* extName = "GL_EXT_gpu_shader5";
898
899 if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL &&
900 !m_context.getContextInfo().isExtensionSupported(extName))
901 throw tcu::NotSupportedError(string(extName) + " extension is required for dynamic indexing of atomic counters");
902
903 if (m_shaderType == glu::SHADERTYPE_VERTEX || m_shaderType == glu::SHADERTYPE_FRAGMENT)
904 {
905 int numAtomicCounterBuffers = 0;
906 m_context.getRenderContext().getFunctions().getIntegerv(m_shaderType == glu::SHADERTYPE_VERTEX ? GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS
907 : GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS,
908 &numAtomicCounterBuffers);
909
910 if (numAtomicCounterBuffers == 0)
911 throw tcu::NotSupportedError(string("Atomic counters not supported in ") + glu::getShaderTypeName(m_shaderType) + " shader");
912 }
913 }
914
getShaderSpec(ShaderSpec * spec,int numCounters,int numOps,const int * opIndices) const915 void AtomicCounterIndexingCase::getShaderSpec (ShaderSpec* spec, int numCounters, int numOps, const int* opIndices) const
916 {
917 const char* indicesPrefix = "index";
918 const char* resultPrefix = "result";
919 std::ostringstream global, code;
920
921 if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL)
922 global << "#extension GL_EXT_gpu_shader5 : require\n";
923
924 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
925 global << "const highp int indexBase = 1;\n";
926
927 global <<
928 "layout(binding = 0) uniform atomic_uint counter[" << numCounters << "];\n";
929
930 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
931 {
932 for (int opNdx = 0; opNdx < numOps; opNdx++)
933 {
934 const string varName = indicesPrefix + de::toString(opNdx);
935 spec->inputs.push_back(Symbol(varName, VarType(TYPE_INT, PRECISION_HIGHP)));
936 }
937 }
938 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
939 declareUniformIndexVars(global, indicesPrefix, numOps);
940
941 for (int opNdx = 0; opNdx < numOps; opNdx++)
942 {
943 const string varName = resultPrefix + de::toString(opNdx);
944 spec->outputs.push_back(Symbol(varName, VarType(TYPE_UINT, PRECISION_HIGHP)));
945 }
946
947 for (int opNdx = 0; opNdx < numOps; opNdx++)
948 {
949 code << resultPrefix << opNdx << " = atomicCounterIncrement(counter[";
950
951 if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL)
952 code << opIndices[opNdx];
953 else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
954 code << "indexBase + " << (opIndices[opNdx]-1);
955 else
956 code << indicesPrefix << opNdx;
957
958 code << "]);\n";
959 }
960
961 spec->version = GLSL_VERSION_310_ES;
962 spec->globalDeclarations = global.str();
963 spec->source = code.str();
964 }
965
iterate(void)966 AtomicCounterIndexingCase::IterateResult AtomicCounterIndexingCase::iterate (void)
967 {
968 const RenderContext& renderCtx = m_context.getRenderContext();
969 const glw::Functions& gl = renderCtx.getFunctions();
970 const Buffer counterBuffer (renderCtx);
971
972 const int numInvocations = 32;
973 const int numCounters = 4;
974 const int numOps = 4;
975 vector<int> opIndices (numOps);
976 vector<deUint32> outValues (numInvocations*numOps);
977 ShaderSpec shaderSpec;
978 de::Random rnd (deInt32Hash(m_shaderType) ^ deInt32Hash(m_indexExprType));
979
980 for (int opNdx = 0; opNdx < numOps; opNdx++)
981 opIndices[opNdx] = rnd.getInt(0, numOps-1);
982
983 getShaderSpec(&shaderSpec, numCounters, numOps, &opIndices[0]);
984
985 {
986 const BufferVector buffers (renderCtx, numCounters);
987 ShaderExecutorPtr shaderExecutor (createExecutor(renderCtx, m_shaderType, shaderSpec));
988 vector<int> expandedIndices;
989 vector<void*> inputs;
990 vector<void*> outputs;
991
992 m_testCtx.getLog() << *shaderExecutor;
993
994 if (!shaderExecutor->isOk())
995 TCU_FAIL("Compile failed");
996
997 {
998 const int bufSize = getProgramResourceInt(gl, shaderExecutor->getProgram(), GL_ATOMIC_COUNTER_BUFFER, 0, GL_BUFFER_DATA_SIZE);
999 const int maxNdx = maxElement(opIndices);
1000 std::vector<deUint8> emptyData (numCounters*4, 0);
1001
1002 if (bufSize < (maxNdx+1)*4)
1003 TCU_FAIL((string("GL reported invalid buffer size " + de::toString(bufSize)).c_str()));
1004
1005 gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, *counterBuffer);
1006 gl.bufferData(GL_ATOMIC_COUNTER_BUFFER, (glw::GLsizeiptr)emptyData.size(), &emptyData[0], GL_STATIC_DRAW);
1007 gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, *counterBuffer);
1008 GLU_EXPECT_NO_ERROR(gl.getError(), "Atomic counter buffer initialization failed");
1009 }
1010
1011 shaderExecutor->useProgram();
1012
1013 if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
1014 {
1015 expandedIndices.resize(numInvocations * opIndices.size());
1016
1017 for (int opNdx = 0; opNdx < numOps; opNdx++)
1018 {
1019 int* dst = &expandedIndices[numInvocations*opNdx];
1020 std::fill(dst, dst+numInvocations, opIndices[opNdx]);
1021 }
1022
1023 for (int opNdx = 0; opNdx < numOps; opNdx++)
1024 inputs.push_back(&expandedIndices[opNdx*numInvocations]);
1025 }
1026 else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
1027 uploadUniformIndices(gl, shaderExecutor->getProgram(), "index", numOps, &opIndices[0]);
1028
1029 for (int opNdx = 0; opNdx < numOps; opNdx++)
1030 outputs.push_back(&outValues[opNdx*numInvocations]);
1031
1032 GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed");
1033
1034 shaderExecutor->execute(numInvocations, inputs.empty() ? DE_NULL : &inputs[0], &outputs[0]);
1035 }
1036
1037 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1038
1039 {
1040 vector<int> numHits (numCounters, 0); // Number of hits per counter.
1041 vector<deUint32> counterValues (numCounters);
1042 vector<vector<bool> > counterMasks (numCounters);
1043
1044 for (int opNdx = 0; opNdx < numOps; opNdx++)
1045 numHits[opIndices[opNdx]] += 1;
1046
1047 // Read counter values
1048 {
1049 const void* mapPtr = DE_NULL;
1050
1051 try
1052 {
1053 mapPtr = gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, numCounters*4, GL_MAP_READ_BIT);
1054 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER)");
1055 TCU_CHECK(mapPtr);
1056 std::copy((const deUint32*)mapPtr, (const deUint32*)mapPtr + numCounters, &counterValues[0]);
1057 gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1058 }
1059 catch (...)
1060 {
1061 if (mapPtr)
1062 gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1063 throw;
1064 }
1065 }
1066
1067 // Verify counter values
1068 for (int counterNdx = 0; counterNdx < numCounters; counterNdx++)
1069 {
1070 const deUint32 refCount = (deUint32)(numHits[counterNdx]*numInvocations);
1071 const deUint32 resCount = counterValues[counterNdx];
1072
1073 if (refCount != resCount)
1074 {
1075 m_testCtx.getLog() << TestLog::Message << "ERROR: atomic counter " << counterNdx << " has value " << resCount
1076 << ", expected " << refCount
1077 << TestLog::EndMessage;
1078
1079 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
1080 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid atomic counter value");
1081 }
1082 }
1083
1084 // Allocate bitmasks - one bit per each valid result value
1085 for (int counterNdx = 0; counterNdx < numCounters; counterNdx++)
1086 {
1087 const int counterValue = numHits[counterNdx]*numInvocations;
1088 counterMasks[counterNdx].resize(counterValue, false);
1089 }
1090
1091 // Verify result values from shaders
1092 for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++)
1093 {
1094 for (int opNdx = 0; opNdx < numOps; opNdx++)
1095 {
1096 const int counterNdx = opIndices[opNdx];
1097 const deUint32 resValue = outValues[opNdx*numInvocations + invocationNdx];
1098 const bool rangeOk = de::inBounds(resValue, 0u, (deUint32)counterMasks[counterNdx].size());
1099 const bool notSeen = rangeOk && !counterMasks[counterNdx][resValue];
1100 const bool isOk = rangeOk && notSeen;
1101
1102 if (!isOk)
1103 {
1104 m_testCtx.getLog() << TestLog::Message << "ERROR: at invocation " << invocationNdx
1105 << ", op " << opNdx << ": got invalid result value "
1106 << resValue
1107 << TestLog::EndMessage;
1108
1109 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
1110 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid result value");
1111 }
1112 else
1113 {
1114 // Mark as used - no other invocation should see this value from same counter.
1115 counterMasks[counterNdx][resValue] = true;
1116 }
1117 }
1118 }
1119
1120 if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
1121 {
1122 // Consistency check - all masks should be 1 now
1123 for (int counterNdx = 0; counterNdx < numCounters; counterNdx++)
1124 {
1125 for (vector<bool>::const_iterator i = counterMasks[counterNdx].begin(); i != counterMasks[counterNdx].end(); i++)
1126 TCU_CHECK_INTERNAL(*i);
1127 }
1128 }
1129 }
1130
1131 return STOP;
1132 }
1133
1134 } // anonymous
1135
OpaqueTypeIndexingTests(Context & context)1136 OpaqueTypeIndexingTests::OpaqueTypeIndexingTests (Context& context)
1137 : TestCaseGroup(context, "opaque_type_indexing", "Opaque Type Indexing Tests")
1138 {
1139 }
1140
~OpaqueTypeIndexingTests(void)1141 OpaqueTypeIndexingTests::~OpaqueTypeIndexingTests (void)
1142 {
1143 }
1144
init(void)1145 void OpaqueTypeIndexingTests::init (void)
1146 {
1147 static const struct
1148 {
1149 IndexExprType type;
1150 const char* name;
1151 const char* description;
1152 } indexingTypes[] =
1153 {
1154 { INDEX_EXPR_TYPE_CONST_LITERAL, "const_literal", "Indexing by constant literal" },
1155 { INDEX_EXPR_TYPE_CONST_EXPRESSION, "const_expression", "Indexing by constant expression" },
1156 { INDEX_EXPR_TYPE_UNIFORM, "uniform", "Indexing by uniform value" },
1157 { INDEX_EXPR_TYPE_DYNAMIC_UNIFORM, "dynamically_uniform", "Indexing by dynamically uniform expression" }
1158 };
1159
1160 static const struct
1161 {
1162 ShaderType type;
1163 const char* name;
1164 } shaderTypes[] =
1165 {
1166 { SHADERTYPE_VERTEX, "vertex" },
1167 { SHADERTYPE_FRAGMENT, "fragment" },
1168 { SHADERTYPE_COMPUTE, "compute" }
1169 };
1170
1171 // .sampler
1172 {
1173 static const DataType samplerTypes[] =
1174 {
1175 // \note 1D images will be added by a later extension.
1176 // TYPE_SAMPLER_1D,
1177 TYPE_SAMPLER_2D,
1178 TYPE_SAMPLER_CUBE,
1179 TYPE_SAMPLER_2D_ARRAY,
1180 TYPE_SAMPLER_3D,
1181 // TYPE_SAMPLER_1D_SHADOW,
1182 TYPE_SAMPLER_2D_SHADOW,
1183 TYPE_SAMPLER_CUBE_SHADOW,
1184 TYPE_SAMPLER_2D_ARRAY_SHADOW,
1185 // TYPE_INT_SAMPLER_1D,
1186 TYPE_INT_SAMPLER_2D,
1187 TYPE_INT_SAMPLER_CUBE,
1188 TYPE_INT_SAMPLER_2D_ARRAY,
1189 TYPE_INT_SAMPLER_3D,
1190 // TYPE_UINT_SAMPLER_1D,
1191 TYPE_UINT_SAMPLER_2D,
1192 TYPE_UINT_SAMPLER_CUBE,
1193 TYPE_UINT_SAMPLER_2D_ARRAY,
1194 TYPE_UINT_SAMPLER_3D,
1195 };
1196
1197 tcu::TestCaseGroup* const samplerGroup = new tcu::TestCaseGroup(m_testCtx, "sampler", "Sampler Array Indexing Tests");
1198 addChild(samplerGroup);
1199
1200 for (int indexTypeNdx = 0; indexTypeNdx < DE_LENGTH_OF_ARRAY(indexingTypes); indexTypeNdx++)
1201 {
1202 const IndexExprType indexExprType = indexingTypes[indexTypeNdx].type;
1203 tcu::TestCaseGroup* const indexGroup = new tcu::TestCaseGroup(m_testCtx, indexingTypes[indexTypeNdx].name, indexingTypes[indexTypeNdx].description);
1204 samplerGroup->addChild(indexGroup);
1205
1206 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(shaderTypes); shaderTypeNdx++)
1207 {
1208 const ShaderType shaderType = shaderTypes[shaderTypeNdx].type;
1209 tcu::TestCaseGroup* const shaderGroup = new tcu::TestCaseGroup(m_testCtx, shaderTypes[shaderTypeNdx].name, "");
1210 indexGroup->addChild(shaderGroup);
1211
1212 for (int samplerTypeNdx = 0; samplerTypeNdx < DE_LENGTH_OF_ARRAY(samplerTypes); samplerTypeNdx++)
1213 {
1214 const DataType samplerType = samplerTypes[samplerTypeNdx];
1215 const char* samplerName = getDataTypeName(samplerType);
1216 const string caseName = de::toLower(samplerName);
1217
1218 shaderGroup->addChild(new SamplerIndexingCase(m_context, caseName.c_str(), "", shaderType, samplerType, indexExprType));
1219 }
1220 }
1221 }
1222 }
1223
1224 // .ubo / .ssbo / .atomic_counter
1225 {
1226 tcu::TestCaseGroup* const uboGroup = new tcu::TestCaseGroup(m_testCtx, "ubo", "Uniform Block Instance Array Indexing Tests");
1227 tcu::TestCaseGroup* const ssboGroup = new tcu::TestCaseGroup(m_testCtx, "ssbo", "Buffer Block Instance Array Indexing Tests");
1228 tcu::TestCaseGroup* const acGroup = new tcu::TestCaseGroup(m_testCtx, "atomic_counter", "Atomic Counter Array Indexing Tests");
1229 addChild(uboGroup);
1230 addChild(ssboGroup);
1231 addChild(acGroup);
1232
1233 for (int indexTypeNdx = 0; indexTypeNdx < DE_LENGTH_OF_ARRAY(indexingTypes); indexTypeNdx++)
1234 {
1235 const IndexExprType indexExprType = indexingTypes[indexTypeNdx].type;
1236 const char* indexExprName = indexingTypes[indexTypeNdx].name;
1237 const char* indexExprDesc = indexingTypes[indexTypeNdx].description;
1238
1239 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(shaderTypes); shaderTypeNdx++)
1240 {
1241 const ShaderType shaderType = shaderTypes[shaderTypeNdx].type;
1242 const string name = string(indexExprName) + "_" + shaderTypes[shaderTypeNdx].name;
1243
1244 uboGroup->addChild (new BlockArrayIndexingCase (m_context, name.c_str(), indexExprDesc, BlockArrayIndexingCase::BLOCKTYPE_UNIFORM, indexExprType, shaderType));
1245 acGroup->addChild (new AtomicCounterIndexingCase (m_context, name.c_str(), indexExprDesc, indexExprType, shaderType));
1246
1247 if (indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL || indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
1248 ssboGroup->addChild (new BlockArrayIndexingCase (m_context, name.c_str(), indexExprDesc, BlockArrayIndexingCase::BLOCKTYPE_BUFFER, indexExprType, shaderType));
1249 }
1250 }
1251 }
1252 }
1253
1254 } // Functional
1255 } // gles31
1256 } // deqp
1257