xref: /aosp_15_r20/external/deqp/external/openglcts/modules/gles31/es31cLayoutBindingTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2014-2016 The Khronos Group Inc.
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
22  */ /*-------------------------------------------------------------------*/
23 #include "es31cLayoutBindingTests.hpp"
24 
25 #include "tcuRenderTarget.hpp"
26 #include "tcuStringTemplate.hpp"
27 #include "tcuSurface.hpp"
28 #include "tcuTestLog.hpp"
29 #include "tcuTexture.hpp"
30 #include "tcuTextureUtil.hpp"
31 
32 #include "deRandom.hpp"
33 #include "deStringUtil.hpp"
34 
35 #include "glwDefs.hpp"
36 #include "glwEnums.hpp"
37 #include "glwFunctions.hpp"
38 
39 #include "gluDrawUtil.hpp"
40 #include "gluPixelTransfer.hpp"
41 #include "gluShaderProgram.hpp"
42 #include "gluTexture.hpp"
43 #include "gluTextureUtil.hpp"
44 
45 namespace glcts
46 {
47 
48 //=========================================================================
49 //= typedefs
50 //=========================================================================
51 typedef std::string String;
52 typedef std::map<String, String> StringMap;
53 typedef std::map<String, glw::GLint> StringIntMap;
54 typedef std::map<glw::GLint, glw::GLint> IntIntMap;
55 typedef std::vector<String> StringVector;
56 typedef std::vector<int> IntVector;
57 
58 typedef std::map<int, glu::Texture2D *> Texture2DMap;
59 typedef std::map<int, glu::Texture2DArray *> Texture2DArrayMap;
60 typedef std::map<int, glu::Texture3D *> Texture3DMap;
61 
62 //=========================================================================
63 //= utility classes
64 //=========================================================================
65 
66 //= string stream that saves some typing
67 class StringStream : public std::ostringstream
68 {
69 public:
reset()70     void reset()
71     {
72         clear();
73         str("");
74     }
75 };
76 
77 class LayoutBindingProgram;
78 
79 class IProgramContextSupplier
80 {
81 public:
~IProgramContextSupplier()82     virtual ~IProgramContextSupplier()
83     {
84     }
85     virtual Context &getContext()                              = 0;
86     virtual const LayoutBindingParameters &getTestParameters() = 0;
87     virtual eStageType getStage()                              = 0;
88     virtual const String &getSource(eStageType stage)          = 0;
89     virtual LayoutBindingProgram *createProgram()              = 0;
90 };
91 
92 class LayoutBindingProgram
93 {
94 public:
LayoutBindingProgram(IProgramContextSupplier & contextSupplier)95     LayoutBindingProgram(IProgramContextSupplier &contextSupplier)
96         : m_contextSupplier(contextSupplier)
97         , m_context(contextSupplier.getContext().getRenderContext())
98         , m_stage(contextSupplier.getStage())
99         , m_testParams(contextSupplier.getTestParameters())
100         , m_gl(contextSupplier.getContext().getRenderContext().getFunctions())
101     {
102         if (getStage() != ComputeShader)
103             m_program = new glu::ShaderProgram(
104                 m_context, glu::makeVtxFragSources(m_contextSupplier.getSource(VertexShader).c_str(),
105                                                    m_contextSupplier.getSource(FragmentShader).c_str()));
106         else
107             m_program = new glu::ShaderProgram(m_context, glu::ProgramSources() << glu::ComputeSource(
108                                                               m_contextSupplier.getSource(ComputeShader).c_str()));
109     }
~LayoutBindingProgram()110     virtual ~LayoutBindingProgram()
111     {
112         delete m_program;
113     }
114 
115     class LayoutBindingProgramAutoPtr
116     {
117     public:
LayoutBindingProgramAutoPtr(IProgramContextSupplier & contextSupplier)118         LayoutBindingProgramAutoPtr(IProgramContextSupplier &contextSupplier)
119         {
120             m_program = contextSupplier.createProgram();
121         }
~LayoutBindingProgramAutoPtr()122         ~LayoutBindingProgramAutoPtr()
123         {
124             delete m_program;
125         }
operator ->()126         LayoutBindingProgram *operator->()
127         {
128             return m_program;
129         }
130 
131     private:
132         LayoutBindingProgram *m_program;
133     };
134 
getErrorLog(bool dumpShaders=false)135     String getErrorLog(bool dumpShaders = false)
136     {
137         StringStream errLog;
138 
139         if (getStage() != ComputeShader)
140         {
141             const glu::ShaderInfo &fragmentShaderInfo = m_program->getShaderInfo(glu::SHADERTYPE_FRAGMENT);
142             const glu::ShaderInfo &vertexShaderInfo   = m_program->getShaderInfo(glu::SHADERTYPE_VERTEX);
143 
144             if (!fragmentShaderInfo.compileOk || !m_program->getProgramInfo().linkOk || dumpShaders)
145             {
146                 errLog << "### dump of " << stageToName(FragmentShader) << "###\n";
147                 String msg((dumpShaders ? "Fragment shader should not have compiled" :
148                                           "Vertex shader compile failed while testing "));
149                 errLog << "Fragment shader compile failed while testing " << stageToName(getStage()) << ": "
150                        << fragmentShaderInfo.infoLog << "\n";
151                 errLog << m_contextSupplier.getSource(FragmentShader);
152             }
153             if (!vertexShaderInfo.compileOk || !m_program->getProgramInfo().linkOk || dumpShaders)
154             {
155                 errLog << "### dump of " << stageToName(VertexShader) << "###\n";
156                 String msg((dumpShaders ? "Vertex shader should not have compiled" :
157                                           "Vertex shader compile failed while testing "));
158                 errLog << msg << stageToName(getStage()) << ": " << vertexShaderInfo.infoLog << "\n";
159                 errLog << m_contextSupplier.getSource(VertexShader);
160             }
161         }
162         else
163         {
164             const glu::ShaderInfo &computeShaderInfo = m_program->getShaderInfo(glu::SHADERTYPE_COMPUTE);
165 
166             if (!computeShaderInfo.compileOk || !m_program->getProgramInfo().linkOk || dumpShaders)
167             {
168                 errLog << "### dump of " << stageToName(ComputeShader) << "###\n";
169                 String msg((dumpShaders ? "Compute shader should not have compiled" :
170                                           "Compute shader compile failed while testing "));
171                 errLog << msg << stageToName(ComputeShader) << ": " << computeShaderInfo.infoLog << "\n";
172                 errLog << m_contextSupplier.getSource(ComputeShader);
173             }
174         }
175         if (!m_program->getProgramInfo().linkOk)
176         {
177             getStage();
178             errLog << "Linking failed while testing " << stageToName(getStage()) << ": "
179                    << m_program->getProgramInfo().infoLog << "\n";
180             errLog << "### other stages ###\n";
181             switch (getStage())
182             {
183             case FragmentShader:
184                 errLog << "### dump of " << stageToName(VertexShader) << "###\n";
185                 errLog << m_contextSupplier.getSource(VertexShader);
186                 break;
187             case VertexShader:
188                 errLog << "### dump of " << stageToName(FragmentShader) << "###\n";
189                 errLog << stageToName(FragmentShader) << "\n";
190                 errLog << m_contextSupplier.getSource(FragmentShader);
191                 break;
192             case ComputeShader:
193                 errLog << "### dump of " << stageToName(ComputeShader) << "###\n";
194                 errLog << stageToName(ComputeShader) << "\n";
195                 errLog << m_contextSupplier.getSource(ComputeShader);
196                 break;
197             default:
198                 DE_ASSERT(0);
199                 break;
200             }
201         }
202         return errLog.str();
203     }
204 
205 private:
206     IProgramContextSupplier &m_contextSupplier;
207 
208     const glu::RenderContext &m_context;
209     const eStageType m_stage;                    // shader stage currently tested
210     const LayoutBindingParameters &m_testParams; // parameters for shader generation (table at end of file)
211     const glw::Functions &m_gl;
212 
213     glu::ShaderProgram *m_program;
214 
215 private:
getUniformLocations(StringVector args) const216     StringIntMap getUniformLocations(StringVector args) const
217     {
218         StringVector::iterator it;
219         StringIntMap locations;
220         bool passed = true;
221 
222         for (it = args.begin(); it != args.end(); it++)
223         {
224             const char *name    = (*it).c_str();
225             glw::GLint location = m_gl.getUniformLocation(getProgram(), name);
226             passed &= (0 <= location);
227             if (passed)
228             {
229                 locations[name] = location;
230             }
231         }
232 
233         return locations;
234     }
235 
236 public:
getProgram() const237     glw::GLint getProgram() const
238     {
239         return m_program->getProgram();
240     }
241 
gl() const242     const glw::Functions &gl() const
243     {
244         return m_gl;
245     }
246 
getStage() const247     virtual eStageType getStage() const
248     {
249         return m_stage;
250     }
251 
stageToName(eStageType stage) const252     String stageToName(eStageType stage) const
253     {
254         switch (stage)
255         {
256         case FragmentShader:
257             return "FragmentShader";
258         case VertexShader:
259             return "VertexShader";
260         case ComputeShader:
261             return "ComputeShader";
262         default:
263             DE_ASSERT(0);
264             break;
265         }
266         return String();
267     }
268 
error() const269     bool error() const
270     {
271         return (m_gl.getError() == GL_NO_ERROR);
272     }
273 
compiledAndLinked() const274     bool compiledAndLinked() const
275     {
276         if (getStage() != ComputeShader)
277             return m_program->getShaderInfo(glu::SHADERTYPE_FRAGMENT).compileOk &&
278                    m_program->getShaderInfo(glu::SHADERTYPE_VERTEX).compileOk && m_program->getProgramInfo().linkOk;
279 
280         return m_program->getShaderInfo(glu::SHADERTYPE_COMPUTE).compileOk && m_program->getProgramInfo().linkOk;
281     }
282 
getBindingPoints(StringVector args) const283     virtual StringIntMap getBindingPoints(StringVector args) const
284     {
285         StringIntMap bindingPoints;
286 
287         StringIntMap locations = getUniformLocations(args);
288         if (!locations.empty())
289         {
290             glw::GLint bindingPoint;
291             for (StringIntMap::iterator it = locations.begin(); it != locations.end(); it++)
292             {
293                 glw::GLint location = it->second;
294                 m_gl.getUniformiv(getProgram(), location, &bindingPoint);
295                 bool hasNoError = (GL_NO_ERROR == m_gl.getError());
296                 if (hasNoError)
297                 {
298                     bindingPoints[it->first] = bindingPoint;
299                 }
300             }
301         }
302         return bindingPoints;
303     }
304 
setBindingPoints(StringVector list,glw::GLint bindingPoint) const305     virtual bool setBindingPoints(StringVector list, glw::GLint bindingPoint) const
306     {
307         bool bNoError = true;
308 
309         StringIntMap locations = getUniformLocations(list);
310         if (!locations.empty())
311         {
312             for (StringIntMap::iterator it = locations.begin(); it != locations.end(); it++)
313             {
314                 m_gl.uniform1i(it->second, bindingPoint);
315                 bNoError &= (GL_NO_ERROR == m_gl.getError());
316             }
317         }
318         return bNoError;
319     }
320 
getOffsets(StringVector) const321     virtual StringIntMap getOffsets(StringVector /*args*/) const
322     {
323         return StringIntMap();
324     }
325 };
326 
327 class LayoutBindingTestResult
328 {
329 public:
LayoutBindingTestResult(bool passed=true,const String & reason=String (),bool notRunforThisContext=false)330     LayoutBindingTestResult(bool passed = true, const String &reason = String(), bool notRunforThisContext = false)
331         : m_passed(passed)
332         , m_notRunForThisContext(notRunforThisContext)
333         , m_reason(reason)
334     {
335     }
336 
337 public:
testPassed() const338     bool testPassed() const
339     {
340         return m_passed;
341     }
342 
getReason() const343     String getReason() const
344     {
345         return m_reason;
346     }
347 
runForThisContext() const348     bool runForThisContext() const
349     {
350         return !m_notRunForThisContext;
351     }
352 
353 private:
354     bool m_passed;
355     bool m_notRunForThisContext;
356     String m_reason;
357 };
358 
359 class IntegerConstant
360 {
361 public:
362     enum Literals
363     {
364         decimal = 0,
365         decimal_u,
366         decimal_U,
367         octal,
368         octal_u,
369         octal_U,
370         hex_x,
371         hex_X,
372         hex_u,
373         hex_u_X,
374         hex_U,
375         hex_U_X,
376         last
377     };
378 
379 public:
IntegerConstant(Literals lit,int ai)380     IntegerConstant(Literals lit, int ai) : asInt(ai)
381     {
382         StringStream s;
383         switch (lit)
384         {
385         case decimal:
386             s << asInt;
387             break;
388         case decimal_u:
389             s << asInt << "u";
390             break;
391         case decimal_U:
392             s << asInt << "U";
393             break;
394         case octal:
395             s << "0" << std::oct << asInt;
396             break;
397         case octal_u:
398             s << "0" << std::oct << asInt << "u";
399             break;
400         case octal_U:
401             s << "0" << std::oct << asInt << "U";
402             break;
403         case hex_x:
404             s << "0x" << std::hex << asInt;
405             break;
406         case hex_X:
407             s << "0X" << std::hex << asInt;
408             break;
409         case hex_u:
410             s << "0x" << std::hex << asInt << "u";
411             break;
412         case hex_u_X:
413             s << "0X" << std::hex << asInt << "u";
414             break;
415         case hex_U:
416             s << "0x" << std::hex << asInt << "U";
417             break;
418         case hex_U_X:
419             s << "0X" << std::hex << asInt << "U";
420             break;
421         case last:
422         default:
423             DE_ASSERT(0);
424         }
425 
426         asString = s.str();
427     }
428 
429 public:
430     String asString;
431     int asInt;
432 };
433 
434 //*****************************************************************************
435 class LayoutBindingBaseCase : public TestCase, public IProgramContextSupplier
436 {
437 public:
438     LayoutBindingBaseCase(Context &context, const char *name, const char *description, StageType stage,
439                           LayoutBindingParameters &samplerType, glu::GLSLVersion glslVersion);
440     virtual ~LayoutBindingBaseCase(void);
441 
442     IterateResult iterate(void);
443 
444     // overrideable subtests
445     virtual LayoutBindingTestResult binding_basic_default(void);
446     virtual LayoutBindingTestResult binding_basic_explicit(void);
447     virtual LayoutBindingTestResult binding_basic_multiple(void);
448     virtual LayoutBindingTestResult binding_basic_render(void);
449     virtual LayoutBindingTestResult binding_integer_constant(void);
450     virtual LayoutBindingTestResult binding_array_size(void);
451     virtual LayoutBindingTestResult binding_array_implicit(void);
452     virtual LayoutBindingTestResult binding_array_multiple(void);
453     virtual LayoutBindingTestResult binding_api_update(void);
454     virtual LayoutBindingTestResult binding_compilation_errors(void);
455     virtual LayoutBindingTestResult binding_link_errors(void);
456     virtual LayoutBindingTestResult binding_examples(void);
457     virtual LayoutBindingTestResult binding_mixed_order(void);
458 
459 private:
460     // drawTest normal vs. compute
461     typedef LayoutBindingTestResult (LayoutBindingBaseCase::*LayoutBindingDrawTestPtr)(glw::GLint program, int binding);
462 
463     LayoutBindingDrawTestPtr m_drawTest;
464 
465     // pointer type for subtests
466     typedef LayoutBindingTestResult (LayoutBindingBaseCase::*LayoutBindingSubTestPtr)();
467 
468     // test table entry
469     struct LayoutBindingSubTest
470     {
471         char const *name;
472         char const *description;
473         LayoutBindingSubTestPtr test;
474     };
475 
476     // IProgramContextSupplier interface
477 protected:
getTestParameters()478     const LayoutBindingParameters &getTestParameters()
479     {
480         return m_testParams;
481     }
482 
getRenderContext()483     const glu::RenderContext &getRenderContext()
484     {
485         return m_context.getRenderContext();
486     }
487 
getStage()488     virtual eStageType getStage()
489     {
490         return m_stage.type;
491     }
492 
getSource(eStageType stage)493     const String &getSource(eStageType stage)
494     {
495         return m_sources[stage];
496     }
497 
getContext()498     Context &getContext()
499     {
500         return m_context;
501     }
502 
gl()503     const glw::Functions &gl()
504     {
505         return m_context.getRenderContext().getFunctions();
506     }
507 
needsPrecision() const508     bool needsPrecision() const
509     {
510         if (isContextTypeES(m_context.getRenderContext().getType()) || m_glslVersion == glu::GLSL_VERSION_450)
511         {
512             return (m_testParams.surface_type != UniformBlock) && (m_testParams.surface_type != ShaderStorageBuffer);
513         }
514         else
515         {
516             return (m_testParams.surface_type != UniformBlock) && (m_testParams.surface_type != ShaderStorageBuffer) &&
517                    (m_testParams.surface_type != AtomicCounter) && (m_testParams.surface_type != Image);
518         }
519     }
520 
521 protected:
makeSparseRange(int maxElement,int minElement=0) const522     std::vector<int> makeSparseRange(int maxElement, int minElement = 0) const
523     {
524         static float rangeT[]            = {0.0f, 0.1f, 0.5f, 0.6f, 0.9f, 1.0f};
525         std::vector<float> rangeTemplate = makeVector(rangeT);
526         float max                        = rangeTemplate.back();
527         float range                      = (float)((maxElement - 1) - minElement);
528 
529         std::vector<int> result;
530         for (std::vector<float>::iterator it = rangeTemplate.begin(); it != rangeTemplate.end(); it++)
531         {
532             float e = *it;
533             e       = (e * range) / max;
534             result.insert(result.end(), minElement + (int)e);
535         }
536         return result;
537     }
538 
getGLSLVersion()539     glu::GLSLVersion getGLSLVersion()
540     {
541         return m_glslVersion;
542     }
543 
isStage(eStageType stage)544     bool isStage(eStageType stage)
545     {
546         return (stage == m_stage.type);
547     }
548 
setTemplateParam(eStageType stage,const char * param,const String & value)549     void setTemplateParam(eStageType stage, const char *param, const String &value)
550     {
551         m_templateParams[stage][param] = value.c_str();
552     }
553 
setTemplateParam(const char * param,const String & value)554     void setTemplateParam(const char *param, const String &value)
555     {
556         setTemplateParam(m_stage.type, param, value);
557     }
558 
updateTemplate(eStageType stage)559     void updateTemplate(eStageType stage)
560     {
561         m_sources[stage] = tcu::StringTemplate(m_templates[stage]).specialize(m_templateParams[stage]);
562     }
563 
updateTemplate()564     void updateTemplate()
565     {
566         updateTemplate(m_stage.type);
567     }
568 
569     template <class T0, class T1>
generateLog(const String & msg,T0 result,T1 expected)570     String generateLog(const String &msg, T0 result, T1 expected)
571     {
572         StringStream s;
573         s << msg << " expected: " << expected << " actual: " << result << "\n";
574         s << getSource(VertexShader) << "\n";
575         s << getSource(FragmentShader) << "\n";
576         return s.str();
577     }
578 
579 private:
580     std::vector<LayoutBindingSubTest> m_tests;
581 
init(void)582     void init(void)
583     {
584         m_drawTest =
585             (getStage() == ComputeShader) ? &LayoutBindingBaseCase::drawTestCompute : &LayoutBindingBaseCase::drawTest;
586 
587 #define MAKE_TEST_ENTRY(__subtest_name__) {#__subtest_name__, "", &LayoutBindingBaseCase::__subtest_name__}
588         LayoutBindingSubTest tests[] = {
589             MAKE_TEST_ENTRY(binding_basic_default),    MAKE_TEST_ENTRY(binding_basic_explicit),
590             MAKE_TEST_ENTRY(binding_basic_multiple),   MAKE_TEST_ENTRY(binding_basic_render),
591             MAKE_TEST_ENTRY(binding_integer_constant), MAKE_TEST_ENTRY(binding_array_size),
592             MAKE_TEST_ENTRY(binding_array_implicit),   MAKE_TEST_ENTRY(binding_array_multiple),
593             MAKE_TEST_ENTRY(binding_api_update),       MAKE_TEST_ENTRY(binding_compilation_errors),
594             MAKE_TEST_ENTRY(binding_link_errors),      MAKE_TEST_ENTRY(binding_examples),
595             MAKE_TEST_ENTRY(binding_mixed_order)};
596         m_tests = makeVector(tests);
597 
598         m_uniformDeclTemplate = "${LAYOUT}${KEYWORD}${UNIFORM_TYPE}${UNIFORM_BLOCK_NAME}${UNIFORM_BLOCK}${UNIFORM_"
599                                 "INSTANCE_NAME}${UNIFORM_ARRAY};\n";
600 
601         m_expectedColor = tcu::Vec4(0.0, 1.0f, 0.0f, 1.0f);
602 
603         switch (getTestParameters().texture_type)
604         {
605         case TwoD:
606         {
607             // 2D
608             glu::ImmutableTexture2D *texture2D =
609                 new glu::ImmutableTexture2D(getContext().getRenderContext(), GL_RGBA8, 2, 2);
610 
611             texture2D->getRefTexture().allocLevel(0);
612             tcu::clear(texture2D->getRefTexture().getLevel(0), m_expectedColor);
613             texture2D->upload();
614 
615             if (m_textures2D.find(0) != m_textures2D.end())
616             {
617                 delete m_textures2D[0];
618             }
619 
620             m_textures2D[0] = texture2D;
621         }
622         break;
623         case TwoDArray:
624         {
625             // 2DArray
626             glu::Texture2DArray *texture2DArray =
627                 new glu::Texture2DArray(getContext().getRenderContext(), GL_RGBA8, 2, 2, 1);
628 
629             texture2DArray->getRefTexture().allocLevel(0);
630             tcu::clear(texture2DArray->getRefTexture().getLevel(0), m_expectedColor);
631             texture2DArray->upload();
632 
633             if (m_textures2DArray.find(0) != m_textures2DArray.end())
634             {
635                 delete m_textures2DArray[0];
636             }
637 
638             m_textures2DArray[0] = texture2DArray;
639         }
640         break;
641         // 3D
642         case ThreeD:
643         {
644             glu::Texture3D *texture3D = new glu::Texture3D(getContext().getRenderContext(), GL_RGBA8, 2, 2, 1);
645 
646             texture3D->getRefTexture().allocLevel(0);
647             tcu::clear(texture3D->getRefTexture().getLevel(0), m_expectedColor);
648             texture3D->upload();
649 
650             if (m_textures3D.find(0) != m_textures3D.end())
651             {
652                 delete m_textures3D[0];
653             }
654 
655             m_textures3D[0] = texture3D;
656         }
657         break;
658         case None:
659             // test case where no texture allocation is needed
660             break;
661         default:
662             DE_ASSERT(0);
663             break;
664         }
665     }
666 
initDefaultVSContext()667     String initDefaultVSContext()
668     {
669         m_templates[VertexShader] = "${VERSION}"
670                                     "layout(location=0) in vec2 inPosition;\n"
671                                     "${UNIFORM_DECL}\n"
672                                     "flat out ${OUT_VAR_TYPE} fragColor;\n"
673                                     "${OPTIONAL_FUNCTION_BLOCK}\n"
674                                     "void main(void)\n"
675                                     "{\n"
676                                     "  ${OUT_ASSIGNMENT} ${UNIFORM_ACCESS}\n"
677                                     "  gl_Position = vec4(inPosition, 0.0, 1.0);\n"
678                                     "}\n";
679 
680         StringMap &args = m_templateParams[VertexShader];
681         // some samplers and all images don't have default precision qualifier (sampler3D)
682         // so append a precision default in all sampler and image cases.
683         StringStream s;
684         s << glu::getGLSLVersionDeclaration(m_glslVersion) << "\n";
685         s << "precision highp float;\n";
686         if (needsPrecision())
687         {
688             s << "precision highp " << getTestParameters().uniform_type << ";\n";
689         }
690 
691         args["VERSION"]                 = s.str();
692         args["UNIFORM_DECL"]            = "";
693         args["OPTIONAL_FUNCTION_BLOCK"] = "";
694         args["UNIFORM_ACCESS"]          = "";
695         args["OUT_ASSIGNMENT"]          = "fragColor =";
696         args["OUT_VAR_TYPE"]            = getTestParameters().vector_type;
697         args["OUT_VAR"]                 = "fragColor";
698         if (m_stage.type != VertexShader)
699         {
700             args["OUT_ASSIGNMENT"] = "";
701         }
702         return tcu::StringTemplate(m_templates[VertexShader]).specialize(args);
703     }
704 
initDefaultFSContext()705     String initDefaultFSContext()
706     {
707         // build fragment shader
708         m_templates[FragmentShader] = "${VERSION}"
709                                       "layout(location=0) out ${OUT_VAR_TYPE} ${OUT_VAR};\n"
710                                       "flat in ${OUT_VAR_TYPE} fragColor;\n"
711                                       "${UNIFORM_DECL}\n"
712                                       "${OPTIONAL_FUNCTION_BLOCK}\n"
713                                       "void main(void)\n"
714                                       "{\n"
715                                       "  ${OUT_ASSIGNMENT} ${UNIFORM_ACCESS}\n"
716                                       "}\n";
717 
718         StringMap &args = m_templateParams[FragmentShader];
719         // samplers and images don't have default precision qualifier
720         StringStream s;
721         s << glu::getGLSLVersionDeclaration(m_glslVersion) << "\n";
722         s << "precision highp float;\n";
723         if (needsPrecision())
724         {
725             s << "precision highp " << getTestParameters().uniform_type << ";\n";
726         }
727         args["VERSION"]                 = s.str();
728         args["OUT_VAR_TYPE"]            = getTestParameters().vector_type;
729         args["UNIFORM_ACCESS"]          = "vec4(0.0,0.0,0.0,0.0);";
730         args["UNIFORM_DECL"]            = "";
731         args["OPTIONAL_FUNCTION_BLOCK"] = "";
732         args["OUT_ASSIGNMENT"]          = "outColor =";
733         args["OUT_VAR"]                 = "outColor";
734         // must have a linkage between stage and fragment shader
735         // that the compiler can't optimize away
736         if (FragmentShader != m_stage.type)
737         {
738             args["UNIFORM_ACCESS"] = "fragColor;";
739         }
740         return tcu::StringTemplate(m_templates[FragmentShader]).specialize(args);
741     }
742 
initDefaultCSContext()743     String initDefaultCSContext()
744     {
745         // build compute shader
746         m_templates[ComputeShader] = "${VERSION}"
747                                      "${UNIFORM_DECL}\n"
748                                      "${OPTIONAL_FUNCTION_BLOCK}\n"
749                                      "void main(void)\n"
750                                      "{\n"
751                                      "  ${OUT_VAR_TYPE} tmp = ${UNIFORM_ACCESS}\n"
752                                      "  ${OUT_ASSIGNMENT} tmp ${OUT_END}\n"
753                                      "}\n";
754 
755         StringMap &args = m_templateParams[ComputeShader];
756         // images don't have default precision qualifier
757         StringStream s;
758         s << glu::getGLSLVersionDeclaration(m_glslVersion) << "\n";
759         s << "layout (local_size_x = 1) in;\n"
760              "precision highp float;\n";
761         if (needsPrecision())
762         {
763             s << "precision highp " << getTestParameters().uniform_type << ";\n";
764         }
765 
766         // bindings are per uniform type...
767         if (getTestParameters().surface_type == Image)
768         {
769             s << "layout(binding=0, std430) buffer outData {\n"
770                  "    "
771               << getTestParameters().vector_type
772               << " outColor;\n"
773                  "};\n";
774             args["OUT_ASSIGNMENT"] = "outColor =";
775             args["OUT_END"]        = ";";
776         }
777         else
778         {
779             s << "layout(binding=0, rgba8) uniform highp writeonly image2D outImage;\n";
780             args["OUT_ASSIGNMENT"] = "imageStore(outImage, ivec2(0), ";
781             args["OUT_END"]        = ");";
782         }
783         args["VERSION"]                 = s.str();
784         args["OUT_VAR_TYPE"]            = getTestParameters().vector_type;
785         args["UNIFORM_ACCESS"]          = "vec4(0.0,0.0,0.0,0.0);";
786         args["UNIFORM_DECL"]            = "";
787         args["OPTIONAL_FUNCTION_BLOCK"] = "";
788 
789         return tcu::StringTemplate(m_templates[ComputeShader]).specialize(args);
790     }
791 
792 protected:
buildUniformDecl(const String & keyword,const String & layout,const String & uniform_type,const String & uniform_block_name,const String & uniform_block,const String & uniform_instance,const String & uniform_array) const793     String buildUniformDecl(const String &keyword, const String &layout, const String &uniform_type,
794                             const String &uniform_block_name, const String &uniform_block,
795                             const String &uniform_instance, const String &uniform_array) const
796     {
797         StringMap args;
798         setArg(args["LAYOUT"], layout);
799         setArg(args["KEYWORD"], keyword);
800         if (uniform_block_name.empty())
801             setArg(args["UNIFORM_TYPE"], uniform_type);
802         else
803             args["UNIFORM_TYPE"] = "";
804         if (!uniform_instance.empty() && !uniform_block_name.empty())
805             setArg(args["UNIFORM_BLOCK_NAME"], uniform_block_name + "_block");
806         else
807             setArg(args["UNIFORM_BLOCK_NAME"], uniform_block_name);
808         setArg(args["UNIFORM_BLOCK"], uniform_block);
809         if ((uniform_block_name.empty() && uniform_block.empty()) || !uniform_array.empty())
810             args["UNIFORM_INSTANCE_NAME"] = uniform_instance;
811         else
812             args["UNIFORM_INSTANCE_NAME"] = "";
813         args["UNIFORM_ARRAY"] = uniform_array;
814         return tcu::StringTemplate(m_uniformDeclTemplate).specialize(args);
815     }
816 
getDefaultUniformName(int idx=0)817     virtual String getDefaultUniformName(int idx = 0)
818     {
819         StringStream s;
820         s << "uniform" << idx;
821         return s.str();
822     }
823 
buildUniformName(String & var)824     virtual String buildUniformName(String &var)
825     {
826         std::ostringstream s;
827         s << var;
828         return s.str();
829     }
830 
buildLayout(const String & binding)831     virtual String buildLayout(const String &binding)
832     {
833         std::ostringstream s;
834         if (!binding.empty())
835             s << "layout(binding=" << binding << ") ";
836         return s.str();
837     }
838 
buildLayout(int binding)839     virtual String buildLayout(int binding)
840     {
841         std::ostringstream bindingStr;
842         bindingStr << binding;
843         return buildLayout(bindingStr.str());
844     }
845 
buildAccess(const String & var)846     virtual String buildAccess(const String &var)
847     {
848         std::ostringstream s;
849         s << getTestParameters().access_function << "(" << var << "," << getTestParameters().coord_vector_type << "(0)"
850           << ")";
851         return s.str();
852     }
853 
buildBlockName(const String &)854     virtual String buildBlockName(const String & /*name*/)
855     {
856         return String();
857     }
858 
buildBlock(const String &,const String &=String ("float"))859     virtual String buildBlock(const String & /*name*/, const String & /*type*/ = String("float"))
860     {
861         return String();
862     }
863 
buildArray(int idx)864     virtual String buildArray(int idx)
865     {
866         StringStream s;
867         s << "[" << idx << "]";
868         return s.str();
869     }
870 
buildArrayAccess(int uniform,int idx)871     virtual String buildArrayAccess(int uniform, int idx)
872     {
873         StringStream s;
874         s << getDefaultUniformName(uniform) << buildArray(idx);
875         if (!buildBlockName(getDefaultUniformName()).empty())
876         {
877             s << "." << getDefaultUniformName(uniform);
878         }
879         return s.str();
880     }
881 
882     // return max. binding point allowed
maxBindings()883     virtual int maxBindings()
884     {
885         int units = 0;
886 
887         if (getTestParameters().surface_type == Image)
888         {
889             gl().getIntegerv(GL_MAX_IMAGE_UNITS, &units);
890         }
891         else
892         {
893             gl().getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &units);
894         }
895 
896         return units;
897     }
898 
899     // return max. array size allowed
maxArraySize()900     virtual int maxArraySize()
901     {
902         int units = 0;
903 
904         if (getTestParameters().surface_type == Image)
905         {
906             switch (m_stage.type)
907             {
908             case VertexShader:
909                 gl().getIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &units);
910                 break;
911             case FragmentShader:
912                 gl().getIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &units);
913                 break;
914             default:
915                 DE_ASSERT(0);
916                 break;
917             }
918         }
919         else
920         {
921             switch (m_stage.type)
922             {
923             case VertexShader:
924                 gl().getIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &units);
925                 break;
926             case FragmentShader:
927                 gl().getIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &units);
928                 break;
929             default:
930                 DE_ASSERT(0);
931                 break;
932             }
933         }
934 
935         return units;
936     }
937 
isSupported()938     virtual bool isSupported()
939     {
940         return (maxArraySize() > 0);
941     }
942 
bind(int binding)943     virtual void bind(int binding)
944     {
945         glw::GLint texTarget = 0;
946         glw::GLint texName   = 0;
947 
948         switch (getTestParameters().texture_type)
949         {
950         case TwoD:
951             texTarget = GL_TEXTURE_2D;
952             texName   = m_textures2D[0]->getGLTexture();
953             break;
954         case TwoDArray:
955             texTarget = GL_TEXTURE_2D_ARRAY;
956             texName   = m_textures2DArray[0]->getGLTexture();
957             break;
958         case ThreeD:
959             texTarget = GL_TEXTURE_3D;
960             texName   = m_textures3D[0]->getGLTexture();
961             break;
962         default:
963             DE_ASSERT(0);
964             break;
965         }
966 
967         switch (getTestParameters().surface_type)
968         {
969         case Texture:
970             gl().activeTexture(GL_TEXTURE0 + binding);
971             gl().bindTexture(texTarget, texName);
972             gl().texParameteri(texTarget, GL_TEXTURE_WRAP_S, glu::getGLWrapMode(tcu::Sampler::CLAMP_TO_EDGE));
973             gl().texParameteri(texTarget, GL_TEXTURE_WRAP_T, glu::getGLWrapMode(tcu::Sampler::CLAMP_TO_EDGE));
974             gl().texParameteri(texTarget, GL_TEXTURE_MIN_FILTER, glu::getGLFilterMode(tcu::Sampler::NEAREST));
975             gl().texParameteri(texTarget, GL_TEXTURE_MAG_FILTER, glu::getGLFilterMode(tcu::Sampler::NEAREST));
976             break;
977         case Image:
978             gl().bindImageTexture(binding, texName, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
979             break;
980         default:
981             DE_ASSERT(0);
982             break;
983         }
984     }
985 
unbind(int binding)986     virtual void unbind(int binding)
987     {
988         glw::GLint texTarget = 0;
989 
990         switch (getTestParameters().texture_type)
991         {
992         case TwoD:
993             texTarget = GL_TEXTURE_2D;
994             break;
995         case TwoDArray:
996             texTarget = GL_TEXTURE_2D_ARRAY;
997             break;
998         case ThreeD:
999             texTarget = GL_TEXTURE_3D;
1000             break;
1001         default:
1002             DE_ASSERT(0);
1003             break;
1004         }
1005 
1006         switch (getTestParameters().surface_type)
1007         {
1008         case Texture:
1009             gl().activeTexture(GL_TEXTURE0 + binding);
1010             gl().bindTexture(texTarget, 0);
1011             break;
1012         case Image:
1013             gl().bindImageTexture(binding, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32F);
1014             break;
1015         default:
1016             DE_ASSERT(0);
1017             break;
1018         }
1019     }
1020 
1021     virtual LayoutBindingTestResult drawTest(glw::GLint program, int binding);
1022     virtual LayoutBindingTestResult drawTestCompute(glw::GLint program, int binding);
1023 
1024     // allocate resources needed for all subtests, i.e. textures
setupTest()1025     virtual void setupTest()
1026     {
1027     }
1028 
1029     // cleanup resources needed for all subtests
teardownTest()1030     virtual void teardownTest()
1031     {
1032         for (Texture2DMap::iterator it = m_textures2D.begin(); it != m_textures2D.end(); it++)
1033         {
1034             delete it->second;
1035         }
1036         m_textures2D.clear();
1037 
1038         for (Texture2DArrayMap::iterator it = m_textures2DArray.begin(); it != m_textures2DArray.end(); it++)
1039         {
1040             delete it->second;
1041         }
1042         m_textures2DArray.clear();
1043 
1044         for (Texture3DMap::iterator it = m_textures3D.begin(); it != m_textures3D.end(); it++)
1045         {
1046             delete it->second;
1047         }
1048         m_textures3D.clear();
1049     }
1050 
1051 private:
1052     // appends a space to the argument (make shader source pretty)
setArg(String & arg,const String & value) const1053     void setArg(String &arg, const String &value) const
1054     {
1055         if (!value.empty())
1056             arg = value + String(" ");
1057         else
1058             arg = String();
1059     }
1060 
1061 private:
1062     LayoutBindingParameters m_testParams;
1063     StageType m_stage;
1064 
1065     std::map<eStageType, String> m_sources;
1066     std::map<eStageType, StringMap> m_templateParams;
1067     std::map<eStageType, const char *> m_templates;
1068 
1069     Texture2DMap m_textures2D;
1070     Texture2DArrayMap m_textures2DArray;
1071     Texture3DMap m_textures3D;
1072     tcu::Vec4 m_expectedColor;
1073 
1074     const char *m_uniformDeclTemplate;
1075 
1076     glu::GLSLVersion m_glslVersion;
1077 };
1078 
LayoutBindingBaseCase(Context & context,const char * name,const char * description,StageType stage,LayoutBindingParameters & samplerType,glu::GLSLVersion glslVersion)1079 LayoutBindingBaseCase::LayoutBindingBaseCase(Context &context, const char *name, const char *description,
1080                                              StageType stage, LayoutBindingParameters &samplerType,
1081                                              glu::GLSLVersion glslVersion)
1082     : TestCase(context, name, description)
1083     , m_drawTest(DE_NULL)
1084     , m_testParams(samplerType)
1085     , m_stage(stage)
1086     , m_uniformDeclTemplate(DE_NULL)
1087     , m_glslVersion(glslVersion)
1088 {
1089 }
1090 
~LayoutBindingBaseCase(void)1091 LayoutBindingBaseCase::~LayoutBindingBaseCase(void)
1092 {
1093     teardownTest();
1094 }
1095 
iterate(void)1096 LayoutBindingBaseCase::IterateResult LayoutBindingBaseCase::iterate(void)
1097 {
1098     tcu::TestLog &log = m_context.getTestContext().getLog();
1099     bool passed       = true;
1100 
1101     if (!isSupported())
1102     {
1103         log << tcu::TestLog::Section("NotSupported", "");
1104         log << tcu::TestLog::Message << "This test was not run as minimum requirements were not met."
1105             << tcu::TestLog::EndMessage;
1106         log << tcu::TestLog::EndSection;
1107         getContext().getTestContext().setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "NotSupported");
1108         return STOP;
1109     }
1110 
1111     // init test case (create shader templates and textures)
1112     init();
1113 
1114     // allocate resources for all subtests
1115     setupTest();
1116 
1117     for (std::vector<LayoutBindingSubTest>::iterator it = m_tests.begin(); it != m_tests.end(); it++)
1118     {
1119         // need to reset templates and their args to a clean state before every
1120         // test to avoid bleeding.
1121         m_sources[VertexShader]   = initDefaultVSContext();
1122         m_sources[FragmentShader] = initDefaultFSContext();
1123         m_sources[ComputeShader]  = initDefaultCSContext();
1124 
1125         LayoutBindingTestResult result = ((*this).*((*it).test))();
1126         if (!result.testPassed())
1127         {
1128             log << tcu::TestLog::Section((*it).name, (*it).description);
1129             log << tcu::TestLog::Message << result.getReason() << tcu::TestLog::EndMessage;
1130             log << tcu::TestLog::EndSection;
1131         }
1132         if (!result.runForThisContext())
1133         {
1134             log << tcu::TestLog::Section((*it).name, (*it).description);
1135             log << tcu::TestLog::Message << "This test was not run for this context as it does not apply."
1136                 << tcu::TestLog::EndMessage;
1137             log << tcu::TestLog::EndSection;
1138         }
1139         passed &= result.testPassed();
1140     }
1141 
1142     // cleanup resources
1143     teardownTest();
1144 
1145     /*=========================================================================
1146      TEST results
1147      =========================================================================*/
1148 
1149     getContext().getTestContext().setTestResult(passed ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
1150                                                 passed ? "Pass" : "Fail");
1151 
1152     return STOP;
1153 }
1154 
1155 /*=========================================================================
1156  // bind resource to specified binding point and program and
1157  // dispatch a computation, read back image at (0,0)
1158  =========================================================================*/
drawTestCompute(glw::GLint program,int binding)1159 LayoutBindingTestResult LayoutBindingBaseCase::drawTestCompute(glw::GLint program, int binding)
1160 {
1161     const glw::Functions &l_gl = getContext().getRenderContext().getFunctions();
1162     bool passed                = true;
1163 
1164     DE_TEST_ASSERT(getStage() == ComputeShader);
1165 
1166     l_gl.useProgram(program);
1167 
1168     uint32_t fb_or_ssb;
1169 
1170     if (getTestParameters().surface_type == Image)
1171     {
1172         bind(binding);
1173 
1174         glw::GLfloat buffer[4] = {0.1f, 0.2f, 0.3f, 0.4f};
1175         l_gl.genBuffers(1, &fb_or_ssb);
1176         l_gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, fb_or_ssb);
1177 
1178         l_gl.bufferData(GL_SHADER_STORAGE_BUFFER, 4 * sizeof(glw::GLfloat), buffer, GL_DYNAMIC_COPY);
1179 
1180         l_gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, fb_or_ssb);
1181 
1182         l_gl.dispatchCompute(1, 1, 1);
1183         l_gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1184 
1185         tcu::Vec4 pixel =
1186             *(tcu::Vec4 *)l_gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 4 * sizeof(glw::GLfloat), GL_MAP_READ_BIT);
1187         l_gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
1188 
1189         l_gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1190         l_gl.deleteBuffers(1, &fb_or_ssb);
1191 
1192         unbind(binding);
1193 
1194         tcu::Vec4 expected(0.0f, 1.0f, 0.0f, 1.0f);
1195         passed = (pixel == expected);
1196         if (!passed)
1197         {
1198             return LayoutBindingTestResult(passed, generateLog(String("drawTestCompute failed"), expected, pixel));
1199         }
1200     }
1201     else
1202     {
1203         uint32_t something = 0x01020304, tex;
1204 
1205         l_gl.genTextures(1, &tex);
1206         l_gl.bindTexture(GL_TEXTURE_2D, tex);
1207         l_gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1208         l_gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
1209         l_gl.texSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &something);
1210 
1211         bind(binding);
1212 
1213         l_gl.bindImageTexture(0, tex, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
1214 
1215         l_gl.dispatchCompute(1, 1, 1);
1216         l_gl.memoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1217 
1218         l_gl.bindImageTexture(0, 0, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
1219 
1220         l_gl.genFramebuffers(1, &fb_or_ssb);
1221         l_gl.bindFramebuffer(GL_FRAMEBUFFER, fb_or_ssb);
1222         l_gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
1223 
1224         l_gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &something);
1225 
1226         l_gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
1227         l_gl.deleteFramebuffers(1, &fb_or_ssb);
1228         l_gl.deleteTextures(1, &tex);
1229 
1230         unbind(binding);
1231 
1232         const uint32_t expected = 0xff00ff00;
1233         passed                  = (expected == something);
1234         if (!passed)
1235         {
1236             return LayoutBindingTestResult(
1237                 passed, generateLog(String("drawTestCompute failed"), tcu::RGBA(expected), tcu::RGBA(something)));
1238         }
1239     }
1240 
1241     return passed;
1242 }
1243 
1244 /*=========================================================================
1245  // bind resource to specified binding point and program and
1246  // return result of comparison of rendered pixel at (0,0) with expected
1247  =========================================================================*/
drawTest(glw::GLint program,int binding)1248 LayoutBindingTestResult LayoutBindingBaseCase::drawTest(glw::GLint program, int binding)
1249 {
1250     const glw::Functions &GL              = getContext().getRenderContext().getFunctions();
1251     const tcu::RenderTarget &renderTarget = getContext().getRenderContext().getRenderTarget();
1252     glw::GLuint viewportW                 = renderTarget.getWidth();
1253     glw::GLuint viewportH                 = renderTarget.getHeight();
1254     tcu::Surface renderedFrame(viewportW, viewportH);
1255     bool passed = true;
1256 
1257     DE_TEST_ASSERT(getStage() != ComputeShader);
1258 
1259     GL.viewport(0, 0, viewportW, viewportH);
1260     GL.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1261     GL.clear(GL_COLOR_BUFFER_BIT);
1262 
1263     static const float position[] = {
1264         -1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f,
1265     };
1266     static const uint16_t quadIndices[] = {0, 1, 2, 2, 1, 3};
1267 
1268     GL.useProgram(program);
1269 
1270     bind(binding);
1271 
1272     static const glu::VertexArrayBinding vertexArrays[] = {
1273         glu::va::Float("inPosition", 2, 4, 0, &position[0]),
1274     };
1275     glu::draw(getContext().getRenderContext(), program, DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
1276               glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0]));
1277 
1278     glu::readPixels(getContext().getRenderContext(), 0, 0, renderedFrame.getAccess());
1279 
1280     tcu::RGBA pixel = renderedFrame.getPixel(0, 0);
1281 
1282     passed = (pixel == tcu::RGBA(m_expectedColor));
1283 
1284     unbind(binding);
1285 
1286     if (!passed)
1287     {
1288         return LayoutBindingTestResult(passed,
1289                                        generateLog(String("drawTest failed"), m_expectedColor, pixel.getPacked()));
1290     }
1291 
1292     return true;
1293 }
1294 
1295 //== verify that binding point is default w/o layout binding
binding_basic_default()1296 LayoutBindingTestResult LayoutBindingBaseCase::binding_basic_default()
1297 {
1298     bool passed = true;
1299 
1300     StringStream s;
1301     s << buildAccess(getDefaultUniformName()) << ";\n";
1302     setTemplateParam("UNIFORM_ACCESS", s.str());
1303 
1304     String decl = buildUniformDecl(String(getTestParameters().keyword), buildLayout(String()),
1305                                    String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1306                                    buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1307     setTemplateParam("UNIFORM_DECL", decl);
1308     updateTemplate();
1309 
1310     LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1311     passed &= program->compiledAndLinked();
1312     if (!passed)
1313     {
1314         return LayoutBindingTestResult(passed, program->getErrorLog());
1315     }
1316 
1317     StringVector list;
1318     const String &u = buildBlockName(getDefaultUniformName());
1319     if (!u.empty())
1320         list.push_back(u + "_block");
1321     else
1322         list.push_back(getDefaultUniformName());
1323 
1324     StringIntMap bindingPoints = program->getBindingPoints(list);
1325 
1326     passed &= bindingPoints.size() == list.size() && (bindingPoints[u] == 0);
1327     if (!passed)
1328     {
1329         return LayoutBindingTestResult(passed,
1330                                        generateLog(String("binding point did not match default"), bindingPoints[u], 0));
1331     }
1332 
1333     return true;
1334 }
1335 
1336 //== verify that binding point has specified value
binding_basic_explicit()1337 LayoutBindingTestResult LayoutBindingBaseCase::binding_basic_explicit()
1338 {
1339     bool passed = true;
1340 
1341     {
1342         StringStream s;
1343         s << buildAccess(getDefaultUniformName()) << ";\n";
1344         setTemplateParam("UNIFORM_ACCESS", s.str());
1345     }
1346 
1347     std::vector<int> bindings = makeSparseRange(maxBindings());
1348     for (std::vector<int>::iterator it = bindings.begin(); it < bindings.end(); it++)
1349     {
1350         int binding = *it;
1351         String decl =
1352             buildUniformDecl(String(getTestParameters().keyword), buildLayout(binding),
1353                              String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1354                              buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1355         setTemplateParam("UNIFORM_DECL", decl);
1356         updateTemplate();
1357 
1358         LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1359         passed &= program->compiledAndLinked();
1360         if (!passed)
1361         {
1362             return LayoutBindingTestResult(passed, program->getErrorLog());
1363         }
1364 
1365         StringVector list;
1366         const String &s = buildBlockName(getDefaultUniformName());
1367         if (!s.empty())
1368             list.push_back(s + "_block");
1369         else
1370             list.push_back(getDefaultUniformName());
1371 
1372         StringIntMap bindingPoints = program->getBindingPoints(list);
1373         passed &= bindingPoints.size() == list.size() && (binding == bindingPoints[list[0]]);
1374         if (!passed)
1375         {
1376             return LayoutBindingTestResult(
1377                 passed, generateLog(String("binding point did not match default"), bindingPoints[list[0]], binding));
1378         }
1379     }
1380     return true;
1381 }
1382 
1383 //== verify that binding works with multiple samplers (same binding points)
binding_basic_multiple()1384 LayoutBindingTestResult LayoutBindingBaseCase::binding_basic_multiple()
1385 {
1386     bool passed = true;
1387 
1388     glw::GLint baseBindingPoint = maxBindings() - 1;
1389 
1390     String decl0 = buildUniformDecl(String(getTestParameters().keyword), buildLayout(baseBindingPoint),
1391                                     String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1392                                     buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1393     String decl1 = buildUniformDecl(String(getTestParameters().keyword), buildLayout(baseBindingPoint),
1394                                     String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName(1)),
1395                                     buildBlock(getDefaultUniformName(1)), getDefaultUniformName(1), String());
1396     setTemplateParam("UNIFORM_DECL", decl0 + decl1);
1397 
1398     StringStream s;
1399     s << buildAccess(getDefaultUniformName()) << " + " << buildAccess(getDefaultUniformName(1)) << ";\n";
1400     setTemplateParam("UNIFORM_ACCESS", s.str());
1401     updateTemplate();
1402 
1403     LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1404     passed &= program->compiledAndLinked();
1405     if (!passed)
1406     {
1407         return LayoutBindingTestResult(passed, program->getErrorLog());
1408     }
1409 
1410     StringVector list;
1411     String u = buildBlockName(getDefaultUniformName());
1412     if (!u.empty())
1413         list.push_back(u + "_block");
1414     else
1415         list.push_back(getDefaultUniformName());
1416 
1417     u = buildBlockName(getDefaultUniformName(1));
1418     if (!u.empty())
1419         list.push_back(u + "_block");
1420     else
1421         list.push_back(getDefaultUniformName(1));
1422 
1423     StringIntMap bindingPoints = program->getBindingPoints(list);
1424     passed &= (baseBindingPoint == bindingPoints[list[0]]) && (baseBindingPoint == bindingPoints[list[1]]);
1425     if (!passed)
1426     {
1427         String err;
1428         err = generateLog(String("binding point did not match default"), bindingPoints[list[0]], baseBindingPoint);
1429         err += generateLog(String("binding point did not match default"), bindingPoints[list[1]], baseBindingPoint);
1430         return LayoutBindingTestResult(passed, err);
1431     }
1432 
1433     return true;
1434 }
1435 
1436 //== verify that binding point has specified value
binding_basic_render()1437 LayoutBindingTestResult LayoutBindingBaseCase::binding_basic_render()
1438 {
1439     bool passed = true;
1440 
1441     StringStream s;
1442     s << buildAccess(getDefaultUniformName()) << ";\n";
1443     setTemplateParam("UNIFORM_ACCESS", s.str());
1444 
1445     std::vector<int> bindings = makeSparseRange(maxBindings());
1446     for (std::vector<int>::iterator it = bindings.begin(); it < bindings.end(); it++)
1447     {
1448         int binding = *it;
1449         String decl =
1450             buildUniformDecl(String(getTestParameters().keyword), buildLayout(binding),
1451                              String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1452                              buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1453         setTemplateParam("UNIFORM_DECL", decl);
1454         updateTemplate();
1455 
1456         LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1457         passed &= program->compiledAndLinked();
1458         if (!passed)
1459         {
1460             return LayoutBindingTestResult(passed, program->getErrorLog());
1461         }
1462 
1463         LayoutBindingTestResult drawTestResult = ((*this).*(m_drawTest))(program->getProgram(), binding);
1464         if (!drawTestResult.testPassed())
1465         {
1466             return LayoutBindingTestResult(drawTestResult.testPassed(), drawTestResult.getReason());
1467         }
1468     }
1469     return true;
1470 }
1471 
binding_integer_constant()1472 LayoutBindingTestResult LayoutBindingBaseCase::binding_integer_constant()
1473 {
1474     bool passed               = true;
1475     std::vector<int> integers = makeSparseRange(maxBindings(), 0);
1476 
1477     std::vector<IntegerConstant> integerConstants;
1478     for (int idx = 0; idx < IntegerConstant::last; idx++)
1479     {
1480         for (IntVector::iterator it = integers.begin(); it != integers.end(); it++)
1481         {
1482             integerConstants.push_back(IntegerConstant((IntegerConstant::Literals)idx, (*it)));
1483         }
1484     }
1485 
1486     //== verify that binding point can be set with integer constant
1487     for (std::vector<IntegerConstant>::iterator it = integerConstants.begin(); it != integerConstants.end(); it++)
1488     {
1489         String &intConst = (*it).asString;
1490 
1491         String decl =
1492             buildUniformDecl(String(getTestParameters().keyword), buildLayout(intConst),
1493                              String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1494                              buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1495         setTemplateParam("UNIFORM_DECL", decl);
1496 
1497         StringStream s;
1498         s << buildAccess(getDefaultUniformName()) << ";\n";
1499         setTemplateParam("UNIFORM_ACCESS", s.str());
1500         updateTemplate();
1501 
1502         LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1503         passed &= program->compiledAndLinked();
1504         if (!passed)
1505         {
1506             return LayoutBindingTestResult(passed, program->getErrorLog());
1507         }
1508 
1509         StringVector list;
1510         const String &u = buildBlockName(getDefaultUniformName());
1511         if (!u.empty())
1512             list.push_back(u + "_block");
1513         else
1514             list.push_back(getDefaultUniformName());
1515 
1516         StringIntMap bindingPoints = program->getBindingPoints(list);
1517         passed &= ((*it).asInt == bindingPoints[list[0]]);
1518         if (!passed)
1519         {
1520             return LayoutBindingTestResult(passed, generateLog(String("binding point did not match default"),
1521                                                                bindingPoints[list[0]], (*it).asInt));
1522         }
1523     }
1524 
1525     //== verify that binding point can be set with integer constant resulting from a preprocessor substitution
1526     for (std::vector<IntegerConstant>::iterator it = integerConstants.begin(); it != integerConstants.end(); it++)
1527     {
1528         String &intConst = (*it).asString;
1529 
1530         StringStream s;
1531         s << "#define INT_CONST " << intConst << std::endl;
1532 
1533         String decl =
1534             buildUniformDecl(String(getTestParameters().keyword), buildLayout(String("INT_CONST")),
1535                              String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1536                              buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1537         setTemplateParam("UNIFORM_DECL", s.str() + decl);
1538 
1539         s.reset();
1540         s << buildAccess(getDefaultUniformName()) << ";\n";
1541         setTemplateParam("UNIFORM_ACCESS", s.str());
1542         updateTemplate();
1543 
1544         LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1545         passed &= program->compiledAndLinked();
1546         if (!passed)
1547         {
1548             return LayoutBindingTestResult(passed, program->getErrorLog());
1549         }
1550 
1551         StringVector list;
1552         const String &u = buildBlockName(getDefaultUniformName());
1553         if (!u.empty())
1554             list.push_back(u + "_block");
1555         else
1556             list.push_back(getDefaultUniformName());
1557 
1558         StringIntMap bindingPoints = program->getBindingPoints(list);
1559         passed &= ((*it).asInt == bindingPoints[list[0]]);
1560         if (!passed)
1561         {
1562             return LayoutBindingTestResult(passed, generateLog(String("binding point did not match default"),
1563                                                                bindingPoints[list[0]], (*it).asInt));
1564         }
1565     }
1566 
1567     return true;
1568 }
1569 
1570 //== test different sized arrays
binding_array_size(void)1571 LayoutBindingTestResult LayoutBindingBaseCase::binding_array_size(void)
1572 {
1573     bool passed = true;
1574 
1575     std::vector<int> arraySizes = makeSparseRange(maxArraySize(), 1);
1576     for (std::vector<int>::iterator it = arraySizes.begin(); it < arraySizes.end(); it++)
1577     {
1578         int arraySize = *it;
1579         String decl =
1580             buildUniformDecl(String(getTestParameters().keyword), buildLayout(maxBindings() - arraySize - 1),
1581                              String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1582                              buildBlock(getDefaultUniformName()), getDefaultUniformName(), buildArray(arraySize));
1583         setTemplateParam("UNIFORM_DECL", decl);
1584 
1585         StringStream s;
1586         for (int idx = 0; idx < arraySize; idx++)
1587         {
1588             s << (idx ? " + " : "") << buildAccess(buildArrayAccess(0, idx));
1589         }
1590         s << ";\n";
1591         setTemplateParam("UNIFORM_ACCESS", s.str());
1592         updateTemplate();
1593 
1594         LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1595         passed &= program->compiledAndLinked();
1596         if (!passed)
1597         {
1598             return LayoutBindingTestResult(passed, program->getErrorLog());
1599         }
1600 
1601         StringVector list;
1602         for (int idx = 0; idx < arraySize; idx++)
1603         {
1604             std::ostringstream texUnitStr;
1605             texUnitStr << getDefaultUniformName();
1606             const String &u = buildBlockName(getDefaultUniformName());
1607             if (!u.empty())
1608                 texUnitStr << "_block";
1609             texUnitStr << buildArray(idx);
1610             list.push_back(texUnitStr.str());
1611         }
1612 
1613         StringIntMap bindingPoints = program->getBindingPoints(list);
1614         for (int idx = 0; idx < arraySize; idx++)
1615         {
1616             passed &= (((maxBindings() - arraySize - 1) + idx) == bindingPoints[list[idx]]);
1617             if (!passed)
1618             {
1619                 return LayoutBindingTestResult(passed, generateLog(String("binding point did not match default"),
1620                                                                    bindingPoints[list[idx]],
1621                                                                    (maxBindings() - arraySize - 1) + idx));
1622             }
1623         }
1624     }
1625 
1626     return LayoutBindingTestResult(passed, String());
1627 }
1628 
1629 //== verify first element takes binding point specified in binding and
1630 //== subsequent entries take the next consecutive units
binding_array_implicit(void)1631 LayoutBindingTestResult LayoutBindingBaseCase::binding_array_implicit(void)
1632 {
1633     bool passed = true;
1634 
1635     std::vector<int> bindings = makeSparseRange(maxBindings(), 0);
1636     for (std::vector<int>::iterator it = bindings.begin(); it < bindings.end(); it++)
1637     {
1638         int baseBindingPoint = *it;
1639         int arraySize        = std::min(maxBindings() - baseBindingPoint, 4);
1640 
1641         String decl =
1642             buildUniformDecl(String(getTestParameters().keyword), buildLayout(baseBindingPoint),
1643                              String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1644                              buildBlock(getDefaultUniformName()), getDefaultUniformName(), buildArray(arraySize));
1645         setTemplateParam("UNIFORM_DECL", decl);
1646 
1647         StringStream s;
1648         for (int idx = 0; idx < arraySize; idx++)
1649         {
1650             s << (idx ? " + " : "") << buildAccess(buildArrayAccess(0, idx));
1651         }
1652         s << ";\n";
1653         setTemplateParam("UNIFORM_ACCESS", s.str());
1654         updateTemplate();
1655 
1656         LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1657         passed &= program->compiledAndLinked();
1658         if (!passed)
1659         {
1660             return LayoutBindingTestResult(passed, program->getErrorLog());
1661         }
1662         StringVector list;
1663         for (int idx = 0; idx < arraySize; idx++)
1664         {
1665             std::ostringstream texUnitStr;
1666             texUnitStr << getDefaultUniformName();
1667             const String &u = buildBlockName(getDefaultUniformName());
1668             if (!u.empty())
1669                 texUnitStr << "_block";
1670             texUnitStr << buildArray(idx);
1671             list.push_back(texUnitStr.str());
1672         }
1673 
1674         StringIntMap bindingPoints = program->getBindingPoints(list);
1675         for (int idx = 0; idx < arraySize; idx++)
1676         {
1677             passed &= ((baseBindingPoint + idx) == bindingPoints[list[idx]]);
1678             if (!passed)
1679             {
1680                 return LayoutBindingTestResult(passed, generateLog(String("binding point did not match default"),
1681                                                                    bindingPoints[list[idx]], (baseBindingPoint + idx)));
1682             }
1683         }
1684     }
1685     return LayoutBindingTestResult(passed, String());
1686 }
1687 
1688 //== multiple arrays :verify first element takes binding point specified in binding and
1689 //== subsequent entries take the next consecutive units
binding_array_multiple(void)1690 LayoutBindingTestResult LayoutBindingBaseCase::binding_array_multiple(void)
1691 {
1692     bool passed = true;
1693 
1694     // two arrays, limit max. binding to one
1695     std::vector<int> bindings = makeSparseRange(maxBindings() - 2, 0);
1696     for (std::vector<int>::iterator it = bindings.begin(); it < bindings.end(); it++)
1697     {
1698         int baseBindingPoint = *it;
1699 
1700         // total distance from current binding point to end of binding range
1701         // split over two arrays, making sure that the array sizes don't
1702         // exceed max. array sizes per stage
1703         int arraySize = (maxBindings() - baseBindingPoint - 1) / 2;
1704         arraySize     = std::min(arraySize, maxArraySize() / 2);
1705 
1706         StringStream s;
1707         String decl =
1708             buildUniformDecl(String(getTestParameters().keyword), buildLayout(baseBindingPoint),
1709                              String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1710                              buildBlock(getDefaultUniformName()), getDefaultUniformName(), buildArray(arraySize));
1711         String another_decl =
1712             buildUniformDecl(String(getTestParameters().keyword), buildLayout(baseBindingPoint),
1713                              String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName(1)),
1714                              buildBlock(getDefaultUniformName(1)), getDefaultUniformName(1), buildArray(arraySize));
1715         setTemplateParam("UNIFORM_DECL", decl + another_decl);
1716 
1717         s.reset();
1718         for (int uniform = 0; uniform < 2; uniform++)
1719         {
1720             for (int idx = 0; idx < arraySize; idx++)
1721             {
1722                 s << ((idx | uniform) ? " + " : "") << buildAccess(buildArrayAccess(uniform, idx));
1723             }
1724         }
1725         s << ";\n";
1726         setTemplateParam("UNIFORM_ACCESS", s.str());
1727         updateTemplate();
1728 
1729         LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1730         passed &= program->compiledAndLinked();
1731         if (!passed)
1732         {
1733             return LayoutBindingTestResult(passed, program->getErrorLog());
1734         }
1735 
1736         StringVector list;
1737         for (int uniform = 0; uniform < 2; uniform++)
1738         {
1739             list.clear();
1740             for (int idx = 0; idx < arraySize; idx++)
1741             {
1742                 std::ostringstream texUnitStr;
1743                 texUnitStr << getDefaultUniformName(uniform);
1744                 const String &u = buildBlockName(getDefaultUniformName(uniform));
1745                 if (!u.empty())
1746                     texUnitStr << "_block";
1747                 texUnitStr << buildArray(idx);
1748                 list.push_back(texUnitStr.str());
1749             }
1750 
1751             StringIntMap bindingPoints = program->getBindingPoints(list);
1752             for (int idx = 0; idx < arraySize; idx++)
1753             {
1754                 passed &= ((baseBindingPoint + idx) == bindingPoints[list[idx]]);
1755                 if (!passed)
1756                 {
1757                     return LayoutBindingTestResult(passed,
1758                                                    generateLog(String("binding point did not match default"),
1759                                                                bindingPoints[list[idx]], (baseBindingPoint + idx)));
1760                 }
1761             }
1762         }
1763     }
1764     return LayoutBindingTestResult(passed, String());
1765 }
1766 
1767 //== verify that explicit binding point can be changed via API
binding_api_update(void)1768 LayoutBindingTestResult LayoutBindingBaseCase::binding_api_update(void)
1769 {
1770     bool passed = true;
1771 
1772     String decl = buildUniformDecl(String(getTestParameters().keyword), buildLayout(1),
1773                                    String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1774                                    buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1775     setTemplateParam("UNIFORM_DECL", decl);
1776 
1777     StringStream s;
1778     s << buildAccess(getDefaultUniformName()) << ";\n";
1779     setTemplateParam("UNIFORM_ACCESS", s.str());
1780     updateTemplate();
1781 
1782     LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1783     passed &= program->compiledAndLinked();
1784     if (!passed)
1785     {
1786         return LayoutBindingTestResult(passed, program->getErrorLog());
1787     }
1788 
1789     StringVector list;
1790     const String &u = buildBlockName(getDefaultUniformName());
1791     if (!u.empty())
1792         list.push_back(u + "_block");
1793     else
1794         list.push_back(getDefaultUniformName());
1795 
1796     StringIntMap bindingPoints = program->getBindingPoints(list);
1797 
1798     gl().useProgram(program->getProgram());
1799     program->setBindingPoints(list, maxBindings() - 1);
1800     gl().useProgram(0);
1801 
1802     bindingPoints = program->getBindingPoints(list);
1803 
1804     passed &= bindingPoints[list[0]] == (maxBindings() - 1);
1805     if (!passed)
1806     {
1807         return LayoutBindingTestResult(passed, generateLog(String("binding point did not match default"),
1808                                                            bindingPoints[list[0]], maxBindings() - 1));
1809     }
1810 
1811     return LayoutBindingTestResult(passed, String());
1812 }
1813 
binding_compilation_errors(void)1814 LayoutBindingTestResult LayoutBindingBaseCase::binding_compilation_errors(void)
1815 {
1816     bool passed = true;
1817     String decl;
1818 
1819     // verify "uniform float var;" doesn't compile
1820     {
1821         StringStream s;
1822         s << getTestParameters().vector_type << "(0.0);";
1823 
1824         setTemplateParam("UNIFORM_ACCESS", s.str());
1825         s.reset();
1826         s << "layout(binding=0) "
1827           << "uniform float tex0;";
1828         setTemplateParam("UNIFORM_DECL", s.str());
1829         updateTemplate();
1830 
1831         LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1832         passed &= !program->compiledAndLinked();
1833         if (!passed)
1834         {
1835             return LayoutBindingTestResult(passed, program->getErrorLog(true));
1836         }
1837     }
1838 
1839     // verify that non-constant integer expression in binding fails
1840     {
1841         decl = buildUniformDecl(String(getTestParameters().keyword), buildLayout(String("0.0")),
1842                                 String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1843                                 buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1844         setTemplateParam("UNIFORM_DECL", decl);
1845         updateTemplate();
1846 
1847         LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1848         passed &= !program->compiledAndLinked();
1849         if (!passed)
1850         {
1851             return LayoutBindingTestResult(passed, program->getErrorLog(true));
1852         }
1853     }
1854 
1855     {
1856         decl = buildUniformDecl(String(getTestParameters().keyword), buildLayout(String("-1")),
1857                                 String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1858                                 buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1859         setTemplateParam("UNIFORM_DECL", decl);
1860         updateTemplate();
1861 
1862         LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1863         passed &= !program->compiledAndLinked();
1864         if (!passed)
1865         {
1866             return LayoutBindingTestResult(passed, program->getErrorLog(true));
1867         }
1868     }
1869     {
1870         decl = buildUniformDecl(String(getTestParameters().keyword), buildLayout(maxBindings()),
1871                                 String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1872                                 buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1873         setTemplateParam("UNIFORM_DECL", decl);
1874         updateTemplate();
1875 
1876         LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1877         passed &= !program->compiledAndLinked();
1878         if (!passed)
1879         {
1880             return LayoutBindingTestResult(passed, program->getErrorLog(true));
1881         }
1882     }
1883     {
1884         decl = buildUniformDecl(String(getTestParameters().keyword), buildLayout(maxBindings()),
1885                                 String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1886                                 buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1887         setTemplateParam("UNIFORM_DECL", decl);
1888 
1889         StringStream s;
1890         s << "vec4(0.0);\n";
1891         setTemplateParam("UNIFORM_ACCESS", s.str());
1892         updateTemplate();
1893 
1894         LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1895         passed &= !program->compiledAndLinked();
1896         if (!passed)
1897         {
1898             return LayoutBindingTestResult(passed, program->getErrorLog(true));
1899         }
1900     }
1901     return LayoutBindingTestResult(passed, String());
1902 }
1903 
binding_link_errors(void)1904 LayoutBindingTestResult LayoutBindingBaseCase::binding_link_errors(void)
1905 {
1906     bool passed = true;
1907 
1908     // same sampler with different binding in two compilation units
1909     if (isStage(VertexShader))
1910     {
1911         String decl =
1912             buildUniformDecl(String(getTestParameters().keyword), buildLayout(1),
1913                              String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1914                              buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1915         setTemplateParam(VertexShader, "UNIFORM_DECL", decl);
1916 
1917         setTemplateParam(VertexShader, "OUT_ASSIGNMENT", String("fragColor ="));
1918 
1919         StringStream s;
1920         s << buildAccess(getDefaultUniformName()) << ";\n";
1921         setTemplateParam(VertexShader, "UNIFORM_ACCESS", s.str());
1922         updateTemplate(VertexShader);
1923 
1924         decl = buildUniformDecl(String(getTestParameters().keyword), buildLayout(3),
1925                                 String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
1926                                 buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
1927         setTemplateParam(FragmentShader, "UNIFORM_DECL", decl);
1928 
1929         s.reset();
1930         s << "fragColor + " << buildAccess(getDefaultUniformName()) << ";\n";
1931         setTemplateParam(FragmentShader, "UNIFORM_ACCESS", s.str());
1932         updateTemplate(FragmentShader);
1933 
1934         LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
1935         passed = !program->compiledAndLinked();
1936         if (!passed)
1937         {
1938             return LayoutBindingTestResult(passed, program->getErrorLog(true));
1939         }
1940     }
1941 
1942     return LayoutBindingTestResult(passed, String());
1943 }
1944 
1945 // this subtest is generically empty. Overwritten in test cases as needed.
binding_examples(void)1946 LayoutBindingTestResult LayoutBindingBaseCase::binding_examples(void)
1947 {
1948     return true;
1949 }
1950 
1951 // just for image and atomic counter cases
binding_mixed_order(void)1952 LayoutBindingTestResult LayoutBindingBaseCase::binding_mixed_order(void)
1953 {
1954     return true;
1955 }
1956 
1957 //=========================================================================
1958 // test case Sampler layout binding
1959 //=========================================================================
1960 class SamplerLayoutBindingCase : public LayoutBindingBaseCase
1961 
1962 {
1963 public:
1964     SamplerLayoutBindingCase(Context &context, const char *name, const char *description, StageType stage,
1965                              LayoutBindingParameters &samplerType, glu::GLSLVersion glslVersion);
1966     ~SamplerLayoutBindingCase(void);
1967 
1968 private:
1969     /*virtual*/
createProgram()1970     LayoutBindingProgram *createProgram()
1971     {
1972         return new LayoutBindingProgram(*this);
1973     }
1974 
1975     /*virtual*/
getDefaultUniformName(int idx=0)1976     String getDefaultUniformName(int idx = 0)
1977     {
1978         StringStream s;
1979 
1980         s << "sampler" << idx;
1981         return s.str();
1982     }
1983 
1984     /*virtual*/
buildLayout(const String & binding)1985     String buildLayout(const String &binding)
1986     {
1987         std::ostringstream s;
1988         if (!binding.empty())
1989             s << "layout(binding=" << binding << ") ";
1990         return s.str();
1991     }
1992 
maxBindings()1993     virtual int maxBindings()
1994     {
1995         int units = 0;
1996         gl().getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &units);
1997         return units;
1998     }
1999 
2000     // return max. array size allowed
maxArraySize()2001     virtual int maxArraySize()
2002     {
2003         int units = 0;
2004 
2005         switch (getStage())
2006         {
2007         case VertexShader:
2008             gl().getIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &units);
2009             break;
2010         case FragmentShader:
2011             gl().getIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &units);
2012             break;
2013         case ComputeShader:
2014             gl().getIntegerv(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, &units);
2015             break;
2016         default:
2017             DE_ASSERT(0);
2018             break;
2019         }
2020 
2021         return units;
2022     }
2023 };
2024 
SamplerLayoutBindingCase(Context & context,const char * name,const char * description,StageType stage,LayoutBindingParameters & samplerType,glu::GLSLVersion glslVersion)2025 SamplerLayoutBindingCase::SamplerLayoutBindingCase(Context &context, const char *name, const char *description,
2026                                                    StageType stage, LayoutBindingParameters &samplerType,
2027                                                    glu::GLSLVersion glslVersion)
2028     : LayoutBindingBaseCase(context, name, description, stage, samplerType, glslVersion)
2029 {
2030 }
2031 
~SamplerLayoutBindingCase(void)2032 SamplerLayoutBindingCase::~SamplerLayoutBindingCase(void)
2033 {
2034 }
2035 
2036 //=========================================================================
2037 // test case Image layout binding
2038 //=========================================================================
2039 class ImageLayoutBindingCase : public LayoutBindingBaseCase
2040 
2041 {
2042 public:
2043     ImageLayoutBindingCase(Context &context, const char *name, const char *description, StageType stage,
2044                            LayoutBindingParameters &samplerType, glu::GLSLVersion glslVersion);
2045     ~ImageLayoutBindingCase(void);
2046 
2047 private:
2048     class ImageLayoutBindingProgram : public LayoutBindingProgram
2049     {
2050     public:
ImageLayoutBindingProgram(IProgramContextSupplier & contextSupplier)2051         ImageLayoutBindingProgram(IProgramContextSupplier &contextSupplier) : LayoutBindingProgram(contextSupplier)
2052         {
2053         }
2054     };
2055 
2056 private:
2057     // IProgramContextSupplier
2058     /*virtual*/
createProgram()2059     LayoutBindingProgram *createProgram()
2060     {
2061         return new ImageLayoutBindingProgram(*this);
2062     }
2063 
2064 private:
2065     /*virtual*/
getDefaultUniformName(int idx=0)2066     String getDefaultUniformName(int idx = 0)
2067     {
2068         StringStream s;
2069         s << "image" << idx;
2070         return s.str();
2071     }
2072 
2073     /*virtual*/
buildLayout(const String & binding)2074     String buildLayout(const String &binding)
2075     {
2076         std::ostringstream s;
2077         if (!binding.empty())
2078             s << "layout(binding=" << binding << ", rgba8) readonly ";
2079         else
2080             s << "layout(rgba8) readonly ";
2081         return s.str();
2082     }
2083 
2084     /*virtual*/
maxBindings()2085     int maxBindings()
2086     {
2087         int units = 0;
2088         gl().getIntegerv(GL_MAX_IMAGE_UNITS, &units);
2089         return units;
2090     }
2091 
2092     /*virtual*/
maxArraySize()2093     int maxArraySize()
2094     {
2095         int units = 0;
2096         switch (getStage())
2097         {
2098         case VertexShader:
2099             gl().getIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &units);
2100             break;
2101         case FragmentShader:
2102             gl().getIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &units);
2103             break;
2104         case ComputeShader:
2105             gl().getIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, &units);
2106             break;
2107         default:
2108             DE_ASSERT(0);
2109             break;
2110         }
2111         return units;
2112     }
2113 
2114 private:
2115     //virtual LayoutBindingTestResult        binding_basic_default               (void);
2116     //virtual LayoutBindingTestResult        binding_basic_explicit              (void);
2117     //virtual LayoutBindingTestResult        binding_basic_multiple              (void);
2118     //virtual LayoutBindingTestResult        binding_basic_render                (void);
2119     //virtual LayoutBindingTestResult        binding_integer_constant            (void);
2120     //virtual LayoutBindingTestResult        binding_array_size                  (void);
2121     //virtual LayoutBindingTestResult        binding_array_implicit              (void);
2122     //virtual LayoutBindingTestResult        binding_array_multiple              (void);
2123     /*virtual*/
binding_api_update(void)2124     LayoutBindingTestResult binding_api_update(void)
2125     {
2126         // only for GL
2127         if (getGLSLVersion() == glu::GLSL_VERSION_310_ES)
2128             return LayoutBindingTestResult(true, String(), true);
2129 
2130         return LayoutBindingBaseCase::binding_api_update();
2131     }
2132     //virtual LayoutBindingTestResult        binding_compilation_errors          (void);
2133     //virtual LayoutBindingTestResult        binding_link_errors                 (void);
2134     //virtual LayoutBindingTestResult        binding_link_examples               (void);
2135     /*virtual*/
binding_mixed_order(void)2136     LayoutBindingTestResult binding_mixed_order(void)
2137     {
2138         bool passed = true;
2139 
2140         {
2141             StringStream s;
2142             s << buildAccess(getDefaultUniformName()) << ";\n";
2143             setTemplateParam("UNIFORM_ACCESS", s.str());
2144 
2145             String decl =
2146                 buildUniformDecl(String(getTestParameters().keyword), String("layout(binding=0, rgba8) readonly"),
2147                                  String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
2148                                  buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
2149             setTemplateParam("UNIFORM_DECL", decl);
2150             updateTemplate();
2151 
2152             LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2153             passed &= program->compiledAndLinked();
2154             if (!passed)
2155             {
2156                 return LayoutBindingTestResult(passed, program->getErrorLog());
2157             }
2158         }
2159         {
2160             String decl =
2161                 buildUniformDecl(String(getTestParameters().keyword), String("layout(r32f, binding=0) readonly"),
2162                                  String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
2163                                  buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
2164             setTemplateParam("UNIFORM_DECL", decl);
2165             updateTemplate();
2166 
2167             LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2168             passed &= program->compiledAndLinked();
2169             if (!passed)
2170             {
2171                 return LayoutBindingTestResult(passed, program->getErrorLog());
2172             }
2173         }
2174 
2175         return true;
2176     }
2177 };
2178 
ImageLayoutBindingCase(Context & context,const char * name,const char * description,StageType stage,LayoutBindingParameters & samplerType,glu::GLSLVersion glslVersion)2179 ImageLayoutBindingCase::ImageLayoutBindingCase(Context &context, const char *name, const char *description,
2180                                                StageType stage, LayoutBindingParameters &samplerType,
2181                                                glu::GLSLVersion glslVersion)
2182     : LayoutBindingBaseCase(context, name, description, stage, samplerType, glslVersion)
2183 {
2184 }
2185 
~ImageLayoutBindingCase(void)2186 ImageLayoutBindingCase::~ImageLayoutBindingCase(void)
2187 {
2188 }
2189 
2190 //=========================================================================
2191 // test case Atomic counter binding
2192 //=========================================================================
2193 class AtomicCounterLayoutBindingCase : public LayoutBindingBaseCase
2194 
2195 {
2196 public:
2197     AtomicCounterLayoutBindingCase(Context &context, const char *name, const char *description, StageType stage,
2198                                    LayoutBindingParameters &samplerType, glu::GLSLVersion glslVersion);
~AtomicCounterLayoutBindingCase(void)2199     ~AtomicCounterLayoutBindingCase(void)
2200     {
2201     }
2202 
2203 private:
2204     class AtomicCounterLayoutBindingProgram : public LayoutBindingProgram
2205     {
2206     public:
AtomicCounterLayoutBindingProgram(IProgramContextSupplier & contextSupplier)2207         AtomicCounterLayoutBindingProgram(IProgramContextSupplier &contextSupplier)
2208             : LayoutBindingProgram(contextSupplier)
2209         {
2210         }
2211 
2212     private:
2213         /*virtual*/
getBindingPoints(StringVector args) const2214         StringIntMap getBindingPoints(StringVector args) const
2215         {
2216             StringIntMap bindingPoints;
2217 
2218             for (StringVector::iterator it = args.begin(); it != args.end(); it++)
2219             {
2220                 glw::GLuint idx = gl().getProgramResourceIndex(getProgram(), GL_UNIFORM, (*it).c_str());
2221                 if (idx != GL_INVALID_INDEX)
2222                 {
2223                     glw::GLenum param                    = GL_ATOMIC_COUNTER_BUFFER_INDEX;
2224                     glw::GLint atomic_counter_buffer_idx = -1;
2225                     gl().getProgramResourceiv(getProgram(), GL_UNIFORM, idx, 1, &param, 1, NULL,
2226                                               &atomic_counter_buffer_idx);
2227                     bool hasNoError = (GL_NO_ERROR == gl().getError()) && (-1 != atomic_counter_buffer_idx);
2228                     if (!hasNoError)
2229                         continue;
2230 
2231                     param            = GL_BUFFER_BINDING;
2232                     glw::GLint value = -1;
2233                     gl().getProgramResourceiv(getProgram(), GL_ATOMIC_COUNTER_BUFFER, atomic_counter_buffer_idx, 1,
2234                                               &param, 1, NULL, &value);
2235                     hasNoError = (GL_NO_ERROR == gl().getError()) && (-1 != value);
2236                     if (!hasNoError)
2237                         continue;
2238 
2239                     bindingPoints[*it] = value;
2240                 }
2241             }
2242             return bindingPoints;
2243         }
2244 
2245         /*virtual*/
getOffsets(StringVector args) const2246         StringIntMap getOffsets(StringVector args) const
2247         {
2248             StringIntMap bindingPoints;
2249 
2250             for (StringVector::iterator it = args.begin(); it != args.end(); it++)
2251             {
2252                 glw::GLuint idx = gl().getProgramResourceIndex(getProgram(), GL_UNIFORM, (*it).c_str());
2253                 if (idx != GL_INVALID_INDEX)
2254                 {
2255                     glw::GLenum param = GL_OFFSET;
2256                     glw::GLint value  = -1;
2257                     gl().getProgramResourceiv(getProgram(), GL_UNIFORM, idx, 1, &param, 1, NULL, &value);
2258                     bool hasNoError = (GL_NO_ERROR == gl().getError());
2259                     if (hasNoError)
2260                     {
2261                         bindingPoints[*it] = value;
2262                     }
2263                 }
2264             }
2265             return bindingPoints;
2266         }
2267     };
2268 
2269 private:
2270     // IProgramContextSupplier
2271     /*virtual*/
createProgram()2272     LayoutBindingProgram *createProgram()
2273     {
2274         return new AtomicCounterLayoutBindingProgram(*this);
2275     }
2276 
2277 private:
2278     /*virtual*/
getDefaultUniformName(int idx=0)2279     String getDefaultUniformName(int idx = 0)
2280     {
2281         StringStream s;
2282         s << "atomic" << idx;
2283         return s.str();
2284     }
2285 
2286     /*virtual*/
buildAccess(const String & var)2287     String buildAccess(const String &var)
2288     {
2289         std::ostringstream s;
2290         s << "vec4(float(atomicCounter(" << var << ")), 1.0, 0.0, 1.0)";
2291         return s.str();
2292     }
2293 
maxBindings()2294     int maxBindings()
2295     {
2296         int units = 0;
2297         gl().getIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &units);
2298         return units;
2299     }
2300 
2301     // return max. array size allowed
maxArraySize()2302     int maxArraySize()
2303     {
2304         int units = 0;
2305         switch (getStage())
2306         {
2307         case FragmentShader:
2308             gl().getIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &units);
2309             break;
2310         case VertexShader:
2311             gl().getIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &units);
2312             break;
2313         case ComputeShader:
2314             gl().getIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS, &units);
2315             break;
2316         default:
2317             DE_ASSERT(0);
2318             break;
2319         }
2320         return units;
2321     }
2322 
2323     //=========================================================================
2324     // sub-tests overrides
2325     //=========================================================================
2326 private:
binding_basic_default(void)2327     LayoutBindingTestResult binding_basic_default(void)
2328     {
2329         return true;
2330     }
2331     //virtual LayoutBindingTestResult binding_basic_explicit          (void);
2332     //virtual LayoutBindingTestResult binding_basic_multiple          (void);
binding_basic_render(void)2333     LayoutBindingTestResult binding_basic_render(void)
2334     {
2335         return true;
2336     }
2337     //virtual LayoutBindingTestResult binding_integer_constant        (void);
2338     /*virtual*/
binding_array_size(void)2339     LayoutBindingTestResult binding_array_size(void)
2340     {
2341         bool passed = true;
2342 
2343         //== test different sized arrays
2344         std::vector<int> arraySizes = makeSparseRange(maxArraySize(), 1);
2345         for (std::vector<int>::iterator it = arraySizes.begin(); it < arraySizes.end(); it++)
2346         {
2347             int arraySize = *it;
2348             StringStream s;
2349             s << "[" << arraySize << "]";
2350             String decl =
2351                 buildUniformDecl(String(getTestParameters().keyword), buildLayout(0),
2352                                  String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
2353                                  buildBlock(getDefaultUniformName()), getDefaultUniformName(), buildArray(arraySize));
2354             setTemplateParam("UNIFORM_DECL", decl);
2355 
2356             s.reset();
2357             // build a function that accesses the whole array
2358             s << "float accumulate(void)\n";
2359             s << "{\n";
2360             s << "  float acc = 0.0;\n";
2361             s << "  for(int i=0; i < " << arraySize << " ; i++)\n";
2362             s << "    acc = float(atomicCounter(" << getDefaultUniformName() << "[i]));\n";
2363             s << "  return acc;\n";
2364             s << "}\n";
2365 
2366             setTemplateParam("OPTIONAL_FUNCTION_BLOCK", s.str());
2367 
2368             s.reset();
2369             s << "vec4(accumulate(), 1.0, 0.0, 1.0);\n";
2370             setTemplateParam("UNIFORM_ACCESS", s.str());
2371             updateTemplate();
2372 
2373             setTemplateParam("OPTIONAL_FUNCTION_BLOCK", String());
2374 
2375             LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2376             passed &= program->compiledAndLinked();
2377             if (!passed)
2378             {
2379                 return LayoutBindingTestResult(passed, program->getErrorLog());
2380             }
2381 
2382             StringVector list;
2383             std::ostringstream texUnitStr;
2384             texUnitStr << getDefaultUniformName() << "[0]";
2385             list.push_back(texUnitStr.str());
2386 
2387             StringIntMap bindingPoints = program->getBindingPoints(list);
2388             passed &= (0 == bindingPoints[list[0]]);
2389             if (!passed)
2390             {
2391                 return LayoutBindingTestResult(
2392                     passed, generateLog(String("binding point did not match default"), bindingPoints[list[0]], 1));
2393             }
2394         }
2395 
2396         return LayoutBindingTestResult(passed, String());
2397     }
binding_array_implicit(void)2398     LayoutBindingTestResult binding_array_implicit(void)
2399     {
2400         return true;
2401     }
binding_array_multiple(void)2402     LayoutBindingTestResult binding_array_multiple(void)
2403     {
2404         return true;
2405     }
binding_api_update(void)2406     LayoutBindingTestResult binding_api_update(void)
2407     {
2408         return true;
2409     }
2410     //virtual LayoutBindingTestResult binding_compilation_errors      (void);
2411     //virtual LayoutBindingTestResult binding_link_errors             (void);
2412 
binding_examples_many_bindings(void)2413     LayoutBindingTestResult binding_examples_many_bindings(void)
2414     {
2415         int max_bindings = 0;
2416 
2417         if (isStage(VertexShader))
2418         {
2419             gl().getIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, &max_bindings);
2420         }
2421         else if (isStage(FragmentShader))
2422         {
2423             gl().getIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &max_bindings);
2424         }
2425         else
2426         {
2427             gl().getIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, &max_bindings);
2428         }
2429 
2430         // example 1 in atomic counter CTS spec ac-binding-examples
2431         {
2432             bool passed = true;
2433             StringStream s;
2434             s << buildAccess(getDefaultUniformName()) << ";\n";
2435             setTemplateParam("UNIFORM_ACCESS", s.str());
2436 
2437             s.reset();
2438             s << "layout(binding=2, offset=4) uniform atomic_uint;\n";
2439             s << "layout(binding=2) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2440             setTemplateParam("UNIFORM_DECL", s.str());
2441             updateTemplate();
2442 
2443             LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2444             passed &= program->compiledAndLinked();
2445             if (!passed)
2446             {
2447                 return LayoutBindingTestResult(passed, program->getErrorLog());
2448             }
2449 
2450             StringVector list;
2451             list.push_back(getDefaultUniformName());
2452 
2453             StringIntMap offsets = program->getOffsets(list);
2454             passed &= (4 == offsets[list[0]]);
2455             if (!passed)
2456             {
2457                 return LayoutBindingTestResult(
2458                     passed, generateLog(String("offset did not match requested"), offsets[list[0]], 1));
2459             }
2460         }
2461 
2462         // example 2 in atomic counter CTS spec ac-binding-examples
2463         if (max_bindings >= 2)
2464         {
2465             bool passed = true;
2466             StringStream s;
2467             s << buildAccess(getDefaultUniformName()) << "\n";
2468             s << "+" << buildAccess(getDefaultUniformName(1)) << "\n";
2469             s << "+" << buildAccess(getDefaultUniformName(2)) << "\n";
2470             s << "+" << buildAccess(getDefaultUniformName(3)) << ";\n";
2471             setTemplateParam("UNIFORM_ACCESS", s.str());
2472 
2473             s.reset();
2474             s << "layout(binding=3, offset=4) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2475             s << "layout(binding=2) uniform atomic_uint " << getDefaultUniformName(1) << ";\n";
2476             s << "layout(binding=3) uniform atomic_uint " << getDefaultUniformName(2) << ";\n";
2477             s << "layout(binding=2) uniform atomic_uint " << getDefaultUniformName(3) << ";\n";
2478             setTemplateParam("UNIFORM_DECL", s.str());
2479             updateTemplate();
2480 
2481             LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2482             passed &= program->compiledAndLinked();
2483             if (!passed)
2484             {
2485                 return LayoutBindingTestResult(passed, program->getErrorLog());
2486             }
2487 
2488             StringVector list;
2489             list.push_back(getDefaultUniformName());
2490             list.push_back(getDefaultUniformName(1));
2491             list.push_back(getDefaultUniformName(2));
2492             list.push_back(getDefaultUniformName(3));
2493 
2494             StringIntMap offsets = program->getOffsets(list);
2495             IntVector expected;
2496             expected.insert(expected.end(), 4);
2497             expected.insert(expected.end(), 0);
2498             expected.insert(expected.end(), 8);
2499             expected.insert(expected.end(), 4);
2500             for (unsigned int idx = 0; idx < list.size(); idx++)
2501             {
2502                 passed &= (expected[idx] == offsets[list[idx]]);
2503                 if (!passed)
2504                 {
2505                     return LayoutBindingTestResult(
2506                         passed, generateLog(String("offset of") + String(list[idx]) + String("did not match requested"),
2507                                             offsets[list[idx]], 4));
2508                 }
2509             }
2510         }
2511 
2512         // example 3 in atomic counter CTS spec ac-binding-examples
2513         {
2514             bool passed = true;
2515             StringStream s;
2516             s << buildAccess(getDefaultUniformName()) << ";\n";
2517             setTemplateParam("UNIFORM_ACCESS", s.str());
2518 
2519             s.reset();
2520             s << "layout(binding=2, offset=4) uniform atomic_uint;\n";
2521             s << "layout(offset=8) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2522             setTemplateParam("UNIFORM_DECL", s.str());
2523             updateTemplate();
2524 
2525             LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2526             passed &= program->compiledAndLinked();
2527             if (passed)
2528             {
2529                 return LayoutBindingTestResult(!passed, String("should not compile"));
2530             }
2531         }
2532 
2533         // example 4 in atomic counter CTS spec ac-binding-examples
2534         {
2535             bool passed = true;
2536             StringStream s;
2537             s << buildAccess(getDefaultUniformName()) << ";\n";
2538             setTemplateParam("UNIFORM_ACCESS", s.str());
2539 
2540             s.reset();
2541             s << "layout(offset=4) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2542             setTemplateParam("UNIFORM_DECL", s.str());
2543             updateTemplate();
2544 
2545             LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2546             passed &= program->compiledAndLinked();
2547             if (passed)
2548             {
2549                 return LayoutBindingTestResult(!passed, String("should not compile"));
2550             }
2551         }
2552 
2553         // example 5 in atomic counter CTS spec ac-binding-examples
2554         // first check working example, then amend it with an error
2555         if (max_bindings >= 2)
2556         {
2557             for (int pass = 0; pass < 2; pass++)
2558             {
2559                 bool passed = true;
2560 
2561                 StringStream s;
2562                 s << buildAccess(getDefaultUniformName()) << "\n";
2563                 if (pass)
2564                 {
2565                     s << "+" << buildAccess(getDefaultUniformName(1)) << "\n";
2566                     s << "+" << buildAccess(getDefaultUniformName(2)) << ";\n";
2567                 }
2568                 else
2569                 {
2570                     s << "+" << buildAccess(getDefaultUniformName(1)) << ";\n";
2571                 }
2572                 setTemplateParam("UNIFORM_ACCESS", s.str());
2573 
2574                 s.reset();
2575                 s << "layout(binding=1, offset=0) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2576                 s << "layout(binding=2, offset=0) uniform atomic_uint " << getDefaultUniformName(1) << ";\n";
2577                 if (pass)
2578                     s << "layout(binding=1, offset=0) uniform atomic_uint " << getDefaultUniformName(2) << ";\n";
2579                 setTemplateParam("UNIFORM_DECL", s.str());
2580                 updateTemplate();
2581 
2582                 LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2583                 passed &= program->compiledAndLinked();
2584                 if (pass != 0)
2585                 {
2586                     if (passed)
2587                     {
2588                         return LayoutBindingTestResult(passed, program->getErrorLog());
2589                     }
2590                 }
2591                 else
2592                 {
2593                     if (!passed)
2594                     {
2595                         return LayoutBindingTestResult(passed, String("should not compile"));
2596                     }
2597                 }
2598             }
2599         }
2600 
2601         // example 6 in atomic counter CTS spec ac-binding-examples
2602         // first check working example, then amend it with an error
2603         if (max_bindings >= 2)
2604         {
2605             for (int pass = 0; pass < 2; pass++)
2606             {
2607                 bool passed = true;
2608 
2609                 StringStream s;
2610                 s << buildAccess(getDefaultUniformName()) << "\n";
2611                 if (pass)
2612                 {
2613                     s << "+" << buildAccess(getDefaultUniformName(1)) << "\n";
2614                     s << "+" << buildAccess(getDefaultUniformName(2)) << ";\n";
2615                 }
2616                 else
2617                 {
2618                     s << "+" << buildAccess(getDefaultUniformName(1)) << ";\n";
2619                 }
2620                 setTemplateParam("UNIFORM_ACCESS", s.str());
2621 
2622                 s.reset();
2623                 s << "layout(binding=1, offset=0) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2624                 s << "layout(binding=2, offset=0) uniform atomic_uint " << getDefaultUniformName(1) << ";\n";
2625                 if (pass)
2626                     s << "layout(binding=1, offset=2) uniform atomic_uint " << getDefaultUniformName(2) << ";\n";
2627                 setTemplateParam("UNIFORM_DECL", s.str());
2628                 updateTemplate();
2629 
2630                 LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2631                 passed &= program->compiledAndLinked();
2632                 if (pass != 0)
2633                 {
2634                     if (passed)
2635                     {
2636                         return LayoutBindingTestResult(passed, program->getErrorLog());
2637                     }
2638                 }
2639                 else
2640                 {
2641                     if (!passed)
2642                     {
2643                         return LayoutBindingTestResult(passed, String("should not compile"));
2644                     }
2645                 }
2646             }
2647         }
2648 
2649         return true;
2650     }
2651 
binding_examples_one_binding(void)2652     LayoutBindingTestResult binding_examples_one_binding(void)
2653     {
2654         // example 1 in atomic counter CTS spec ac-binding-examples
2655         {
2656             bool passed = true;
2657             StringStream s;
2658             s << buildAccess(getDefaultUniformName()) << ";\n";
2659             setTemplateParam("UNIFORM_ACCESS", s.str());
2660 
2661             s.reset();
2662             s << "layout(binding=0, offset=4) uniform atomic_uint;\n";
2663             s << "layout(binding=0) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2664             setTemplateParam("UNIFORM_DECL", s.str());
2665             updateTemplate();
2666 
2667             LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2668             passed &= program->compiledAndLinked();
2669             if (!passed)
2670             {
2671                 return LayoutBindingTestResult(passed, program->getErrorLog());
2672             }
2673 
2674             StringVector list;
2675             list.push_back(getDefaultUniformName());
2676 
2677             StringIntMap offsets = program->getOffsets(list);
2678             passed &= (4 == offsets[list[0]]);
2679             if (!passed)
2680             {
2681                 return LayoutBindingTestResult(
2682                     passed, generateLog(String("offset did not match requested"), offsets[list[0]], 1));
2683             }
2684         }
2685 
2686         // example 2 in atomic counter CTS spec ac-binding-examples
2687         {
2688             bool passed = true;
2689             StringStream s;
2690             s << buildAccess(getDefaultUniformName()) << "\n";
2691             s << "+" << buildAccess(getDefaultUniformName(1)) << "\n";
2692             s << "+" << buildAccess(getDefaultUniformName(2)) << "\n";
2693             s << "+" << buildAccess(getDefaultUniformName(3)) << ";\n";
2694             setTemplateParam("UNIFORM_ACCESS", s.str());
2695 
2696             s.reset();
2697             s << "layout(binding=0, offset=4) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2698             s << "layout(binding=0) uniform atomic_uint " << getDefaultUniformName(1) << ";\n";
2699             s << "layout(binding=0) uniform atomic_uint " << getDefaultUniformName(2) << ";\n";
2700             s << "layout(binding=0) uniform atomic_uint " << getDefaultUniformName(3) << ";\n";
2701             setTemplateParam("UNIFORM_DECL", s.str());
2702             updateTemplate();
2703 
2704             LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2705             passed &= program->compiledAndLinked();
2706             if (!passed)
2707             {
2708                 return LayoutBindingTestResult(passed, program->getErrorLog());
2709             }
2710 
2711             StringVector list;
2712             list.push_back(getDefaultUniformName());
2713             list.push_back(getDefaultUniformName(1));
2714             list.push_back(getDefaultUniformName(2));
2715             list.push_back(getDefaultUniformName(3));
2716 
2717             StringIntMap offsets = program->getOffsets(list);
2718             IntVector expected;
2719             expected.insert(expected.end(), 4);
2720             expected.insert(expected.end(), 8);
2721             expected.insert(expected.end(), 12);
2722             expected.insert(expected.end(), 16);
2723             for (unsigned int idx = 0; idx < list.size(); idx++)
2724             {
2725                 passed &= (expected[idx] == offsets[list[idx]]);
2726                 if (!passed)
2727                 {
2728                     return LayoutBindingTestResult(
2729                         passed, generateLog(String("offset of") + String(list[idx]) + String("did not match requested"),
2730                                             offsets[list[idx]], expected[idx]));
2731                 }
2732             }
2733         }
2734 
2735         // example 3 in atomic counter CTS spec ac-binding-examples
2736         {
2737             bool passed = true;
2738             StringStream s;
2739             s << buildAccess(getDefaultUniformName()) << ";\n";
2740             setTemplateParam("UNIFORM_ACCESS", s.str());
2741 
2742             s.reset();
2743             s << "layout(binding=0, offset=4) uniform atomic_uint;\n";
2744             s << "layout(offset=8) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2745             setTemplateParam("UNIFORM_DECL", s.str());
2746             updateTemplate();
2747 
2748             LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2749             passed &= program->compiledAndLinked();
2750             if (passed)
2751             {
2752                 return LayoutBindingTestResult(!passed, String("should not compile"));
2753             }
2754         }
2755 
2756         // example 4 in atomic counter CTS spec ac-binding-examples
2757         {
2758             bool passed = true;
2759             StringStream s;
2760             s << buildAccess(getDefaultUniformName()) << ";\n";
2761             setTemplateParam("UNIFORM_ACCESS", s.str());
2762 
2763             s.reset();
2764             s << "layout(offset=4) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2765             setTemplateParam("UNIFORM_DECL", s.str());
2766             updateTemplate();
2767 
2768             LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2769             passed &= program->compiledAndLinked();
2770             if (passed)
2771             {
2772                 return LayoutBindingTestResult(!passed, String("should not compile"));
2773             }
2774         }
2775 
2776         // example 5 in atomic counter CTS spec ac-binding-examples
2777         // first check working example, then amend it with an error
2778         for (int pass = 0; pass < 2; pass++)
2779         {
2780             bool passed = true;
2781 
2782             StringStream s;
2783 
2784             if (pass)
2785             {
2786                 s << buildAccess(getDefaultUniformName()) << "\n";
2787                 s << "+" << buildAccess(getDefaultUniformName(1)) << ";\n";
2788             }
2789             else
2790             {
2791                 s << buildAccess(getDefaultUniformName()) << ";\n";
2792             }
2793             setTemplateParam("UNIFORM_ACCESS", s.str());
2794 
2795             s.reset();
2796             s << "layout(binding=0, offset=0) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2797             if (pass)
2798                 s << "layout(binding=0, offset=0) uniform atomic_uint " << getDefaultUniformName(1) << ";\n";
2799             setTemplateParam("UNIFORM_DECL", s.str());
2800             updateTemplate();
2801 
2802             LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2803             passed &= program->compiledAndLinked();
2804             if (pass != 0)
2805             {
2806                 if (passed)
2807                 {
2808                     return LayoutBindingTestResult(passed, program->getErrorLog());
2809                 }
2810             }
2811             else
2812             {
2813                 if (!passed)
2814                 {
2815                     return LayoutBindingTestResult(passed, String("should not compile"));
2816                 }
2817             }
2818         }
2819 
2820         // example 6 in atomic counter CTS spec ac-binding-examples
2821         // first check working example, then amend it with an error
2822         for (int pass = 0; pass < 2; pass++)
2823         {
2824             bool passed = true;
2825 
2826             StringStream s;
2827             if (pass)
2828             {
2829                 s << buildAccess(getDefaultUniformName()) << "\n";
2830                 s << "+" << buildAccess(getDefaultUniformName(1)) << ";\n";
2831             }
2832             else
2833             {
2834                 s << buildAccess(getDefaultUniformName()) << ";\n";
2835             }
2836             setTemplateParam("UNIFORM_ACCESS", s.str());
2837 
2838             s.reset();
2839             s << "layout(binding=0, offset=0) uniform atomic_uint " << getDefaultUniformName() << ";\n";
2840             if (pass)
2841                 s << "layout(binding=0, offset=2) uniform atomic_uint " << getDefaultUniformName(1) << ";\n";
2842             setTemplateParam("UNIFORM_DECL", s.str());
2843             updateTemplate();
2844 
2845             LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2846             passed &= program->compiledAndLinked();
2847             if (pass != 0)
2848             {
2849                 if (passed)
2850                 {
2851                     return LayoutBindingTestResult(passed, program->getErrorLog());
2852                 }
2853             }
2854             else
2855             {
2856                 if (!passed)
2857                 {
2858                     return LayoutBindingTestResult(passed, String("should not compile"));
2859                 }
2860             }
2861         }
2862 
2863         return true;
2864     }
2865 
2866     /*virtual*/
binding_examples(void)2867     LayoutBindingTestResult binding_examples(void)
2868     {
2869         if (maxBindings() >= 4)
2870         {
2871             return binding_examples_many_bindings();
2872         }
2873         else
2874         {
2875             return binding_examples_one_binding();
2876         }
2877     }
2878 
2879     /*virtual*/
binding_mixed_order(void)2880     LayoutBindingTestResult binding_mixed_order(void)
2881     {
2882         bool passed = true;
2883 
2884         {
2885             StringStream s;
2886             s << buildAccess(getDefaultUniformName()) << ";\n";
2887             setTemplateParam("UNIFORM_ACCESS", s.str());
2888 
2889             String decl =
2890                 buildUniformDecl(String(getTestParameters().keyword), String("layout(binding=0, offset=0)"),
2891                                  String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
2892                                  buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
2893             setTemplateParam("UNIFORM_DECL", decl);
2894             updateTemplate();
2895 
2896             LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2897             passed &= program->compiledAndLinked();
2898             if (!passed)
2899             {
2900                 return LayoutBindingTestResult(passed, program->getErrorLog());
2901             }
2902         }
2903         {
2904             String decl =
2905                 buildUniformDecl(String(getTestParameters().keyword), String("layout(offset=0, binding=0)"),
2906                                  String(getTestParameters().uniform_type), buildBlockName(getDefaultUniformName()),
2907                                  buildBlock(getDefaultUniformName()), getDefaultUniformName(), String());
2908             setTemplateParam("UNIFORM_DECL", decl);
2909             updateTemplate();
2910 
2911             LayoutBindingProgram::LayoutBindingProgramAutoPtr program(*this);
2912             passed &= program->compiledAndLinked();
2913             if (!passed)
2914             {
2915                 return LayoutBindingTestResult(passed, program->getErrorLog());
2916             }
2917         }
2918 
2919         return true;
2920     }
2921 };
2922 
AtomicCounterLayoutBindingCase(Context & context,const char * name,const char * description,StageType stage,LayoutBindingParameters & samplerType,glu::GLSLVersion glslVersion)2923 AtomicCounterLayoutBindingCase::AtomicCounterLayoutBindingCase(Context &context, const char *name,
2924                                                                const char *description, StageType stage,
2925                                                                LayoutBindingParameters &samplerType,
2926                                                                glu::GLSLVersion glslVersion)
2927     : LayoutBindingBaseCase(context, name, description, stage, samplerType, glslVersion)
2928 {
2929 }
2930 
2931 //=========================================================================
2932 // test case Uniform blocks binding
2933 //=========================================================================
2934 class UniformBlocksLayoutBindingCase : public LayoutBindingBaseCase
2935 
2936 {
2937 public:
2938     UniformBlocksLayoutBindingCase(Context &context, const char *name, const char *description, StageType stage,
2939                                    LayoutBindingParameters &samplerType, glu::GLSLVersion glslVersion);
2940     ~UniformBlocksLayoutBindingCase(void);
2941 
2942 private:
2943     class UniformBlocksLayoutBindingProgram : public LayoutBindingProgram
2944     {
2945     public:
UniformBlocksLayoutBindingProgram(IProgramContextSupplier & contextSupplier)2946         UniformBlocksLayoutBindingProgram(IProgramContextSupplier &contextSupplier)
2947             : LayoutBindingProgram(contextSupplier)
2948         {
2949         }
2950 
~UniformBlocksLayoutBindingProgram()2951         ~UniformBlocksLayoutBindingProgram()
2952         {
2953         }
2954 
2955     private:
2956         /*virtual*/
getBindingPoints(StringVector args) const2957         StringIntMap getBindingPoints(StringVector args) const
2958         {
2959             StringIntMap bindingPoints;
2960 
2961             for (StringVector::iterator it = args.begin(); it != args.end(); it++)
2962             {
2963                 glw::GLuint idx = gl().getProgramResourceIndex(getProgram(), GL_UNIFORM_BLOCK, (*it).c_str());
2964                 if (idx != glw::GLuint(-1))
2965                 {
2966                     glw::GLenum param = GL_BUFFER_BINDING;
2967                     glw::GLint value  = -1;
2968                     gl().getProgramResourceiv(getProgram(), GL_UNIFORM_BLOCK, idx, 1, &param, 1, NULL, &value);
2969                     bool hasNoError = (GL_NO_ERROR == gl().getError());
2970                     if (hasNoError)
2971                     {
2972                         bindingPoints[*it] = value;
2973                     }
2974                 }
2975             }
2976 
2977             return bindingPoints;
2978         }
2979 
2980         /*virtual*/
setBindingPoints(StringVector list,glw::GLint bindingPoint) const2981         bool setBindingPoints(StringVector list, glw::GLint bindingPoint) const
2982         {
2983             bool bNoError = true;
2984 
2985             for (StringVector::iterator it = list.begin(); it != list.end(); it++)
2986             {
2987                 glw::GLuint blockIndex = gl().getUniformBlockIndex(getProgram(), (*it).c_str());
2988                 if (blockIndex == GL_INVALID_INDEX)
2989 
2990                 {
2991                     return false;
2992                 }
2993                 gl().uniformBlockBinding(getProgram(), blockIndex, bindingPoint);
2994             }
2995             return bNoError;
2996         }
2997     };
2998 
2999 private:
3000     // IProgramContextSupplier
3001     /*virtual*/
createProgram()3002     LayoutBindingProgram *createProgram()
3003     {
3004         return new UniformBlocksLayoutBindingProgram(*this);
3005     }
3006 
3007 private:
3008     /*virtual*/
buildBlockName(const String & name)3009     String buildBlockName(const String &name)
3010     {
3011 
3012         return name;
3013     }
3014 
3015     /*virtual*/
buildBlock(const String & name,const String & type)3016     String buildBlock(const String &name, const String &type)
3017     {
3018 
3019         std::ostringstream s;
3020         s << "{";
3021         s << type << " " << name << "_a; ";
3022         s << type << " " << name << "_b; ";
3023         s << "}";
3024         return s.str();
3025     }
3026 
3027     /*virtual*/
buildAccess(const String & var)3028     String buildAccess(const String &var)
3029     {
3030         std::ostringstream s;
3031         s << "vec4(0.0, " << var << "_a, 0.0, 1.0) + vec4(0.0, " << var << "_b, 0.0, 1.0)";
3032         return s.str();
3033     }
3034 
3035     /*virtual*/
buildLayout(const String & binding)3036     String buildLayout(const String &binding)
3037     {
3038         std::ostringstream s;
3039         if (!binding.empty())
3040             s << "layout(binding=" << binding << ", std140) ";
3041         else
3042             s << "layout(std140) ";
3043         return s.str();
3044     }
3045 
3046     /*virtual*/
maxBindings()3047     int maxBindings()
3048     {
3049         int units = 0;
3050         gl().getIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &units);
3051         return units;
3052     }
3053 
3054     // return max. array size allowed
3055     /*virtual*/
maxArraySize()3056     int maxArraySize()
3057     {
3058         int units = 0;
3059         switch (getStage())
3060         {
3061         case FragmentShader:
3062             gl().getIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &units);
3063             break;
3064         case VertexShader:
3065             gl().getIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS, &units);
3066             break;
3067         case ComputeShader:
3068             gl().getIntegerv(GL_MAX_COMPUTE_UNIFORM_BLOCKS, &units);
3069             break;
3070         default:
3071             DE_ASSERT(0);
3072             break;
3073         }
3074         return units;
3075     }
3076 
3077     /*virtual*/
bind(int binding)3078     void bind(int binding)
3079     {
3080         gl().bindBufferBase(GL_UNIFORM_BUFFER, binding, m_buffername);
3081     }
3082 
3083     /*virtual*/
unbind(int binding)3084     void unbind(int binding)
3085     {
3086         gl().bindBufferBase(GL_UNIFORM_BUFFER, binding, 0);
3087     }
3088 
3089     /*virtual*/
setupTest(void)3090     void setupTest(void)
3091     {
3092         const float f[2] = {0.25f, 0.75f};
3093         gl().genBuffers(1, &m_buffername);
3094         gl().bindBuffer(GL_UNIFORM_BUFFER, m_buffername);
3095         gl().bufferData(GL_UNIFORM_BUFFER, sizeof(f), f, GL_STATIC_DRAW);
3096     }
3097 
3098     /*virtual*/
teardownTest(void)3099     void teardownTest(void)
3100     {
3101         gl().bindBuffer(GL_UNIFORM_BUFFER, 0);
3102         gl().deleteBuffers(1, &m_buffername);
3103     }
3104 
3105 private:
3106     glw::GLuint m_buffername;
3107 };
3108 
UniformBlocksLayoutBindingCase(Context & context,const char * name,const char * description,StageType stage,LayoutBindingParameters & samplerType,glu::GLSLVersion glslVersion)3109 UniformBlocksLayoutBindingCase::UniformBlocksLayoutBindingCase(Context &context, const char *name,
3110                                                                const char *description, StageType stage,
3111                                                                LayoutBindingParameters &samplerType,
3112                                                                glu::GLSLVersion glslVersion)
3113     : LayoutBindingBaseCase(context, name, description, stage, samplerType, glslVersion)
3114     , m_buffername(0)
3115 {
3116 }
3117 
~UniformBlocksLayoutBindingCase()3118 UniformBlocksLayoutBindingCase::~UniformBlocksLayoutBindingCase()
3119 {
3120 }
3121 
3122 //*****************************************************************************
3123 
3124 //=========================================================================
3125 // test case Shader storage buffer binding
3126 //=========================================================================
3127 class ShaderStorageBufferLayoutBindingCase : public LayoutBindingBaseCase
3128 {
3129 public:
3130     ShaderStorageBufferLayoutBindingCase(Context &context, const char *name, const char *description, StageType stage,
3131                                          LayoutBindingParameters &samplerType, glu::GLSLVersion glslVersion);
3132     ~ShaderStorageBufferLayoutBindingCase(void);
3133 
3134 private:
3135     class ShaderStorageBufferLayoutBindingProgram : public LayoutBindingProgram
3136     {
3137     public:
ShaderStorageBufferLayoutBindingProgram(IProgramContextSupplier & contextSupplier)3138         ShaderStorageBufferLayoutBindingProgram(IProgramContextSupplier &contextSupplier)
3139             : LayoutBindingProgram(contextSupplier)
3140         {
3141         }
3142 
~ShaderStorageBufferLayoutBindingProgram()3143         ~ShaderStorageBufferLayoutBindingProgram()
3144         {
3145         }
3146         //*******************************************************************************
3147         // overwritten virtual methods
3148     private:
3149         /*virtual*/
getBindingPoints(StringVector args) const3150         StringIntMap getBindingPoints(StringVector args) const
3151         {
3152             StringIntMap bindingPoints;
3153 
3154             for (StringVector::iterator it = args.begin(); it != args.end(); it++)
3155             {
3156                 glw::GLuint idx = gl().getProgramResourceIndex(getProgram(), GL_SHADER_STORAGE_BLOCK, (*it).c_str());
3157                 if (idx != GL_INVALID_INDEX)
3158                 {
3159                     glw::GLenum param = GL_BUFFER_BINDING;
3160                     glw::GLint value  = -1;
3161                     gl().getProgramResourceiv(getProgram(), GL_SHADER_STORAGE_BLOCK, idx, 1, &param, 1, NULL, &value);
3162                     bool hasNoError = (GL_NO_ERROR == gl().getError());
3163                     if (hasNoError)
3164                     {
3165                         bindingPoints[*it] = value;
3166                     }
3167                 }
3168             }
3169 
3170             return bindingPoints;
3171         }
3172 
3173         /*virtual*/
setBindingPoints(StringVector list,glw::GLint bindingPoint) const3174         bool setBindingPoints(StringVector list, glw::GLint bindingPoint) const
3175         {
3176             for (StringVector::iterator it = list.begin(); it != list.end(); it++)
3177             {
3178                 glw::GLuint blockIndex =
3179                     gl().getProgramResourceIndex(getProgram(), GL_SHADER_STORAGE_BLOCK, (*it).c_str());
3180                 if (blockIndex == GL_INVALID_INDEX)
3181                 {
3182                     return false;
3183                 }
3184                 gl().shaderStorageBlockBinding(getProgram(), blockIndex, bindingPoint);
3185             }
3186             return true;
3187         }
3188     };
3189 
3190 private:
3191     // IProgramContextSupplier
3192     /*virtual*/
createProgram()3193     LayoutBindingProgram *createProgram()
3194     {
3195         return new ShaderStorageBufferLayoutBindingProgram(*this);
3196     }
3197 
3198 private:
3199     /*virtual*/
buildLayout(const String & binding)3200     String buildLayout(const String &binding)
3201     {
3202         std::ostringstream s;
3203         if (!binding.empty())
3204             s << "layout(binding=" << binding << ", std430) ";
3205         else
3206             s << "layout(std430) ";
3207         return s.str();
3208     }
3209 
3210     /*virtual*/
getDefaultUniformName(int idx=0)3211     String getDefaultUniformName(int idx = 0)
3212     {
3213         StringStream s;
3214 
3215         s << "buffer" << idx;
3216         return s.str();
3217     }
3218     /*virtual*/
buildBlockName(const String & name)3219     String buildBlockName(const String &name)
3220     {
3221         return name;
3222     }
3223 
3224     /*virtual*/
buildBlock(const String & name,const String & type)3225     String buildBlock(const String &name, const String &type)
3226     {
3227         std::ostringstream s;
3228         s << "{";
3229         s << type << " " << name << "_a[2];\n";
3230         s << "}";
3231         return s.str();
3232     }
3233 
3234     /*virtual*/
buildAccess(const String & var)3235     String buildAccess(const String &var)
3236     {
3237         std::ostringstream s;
3238         s << "vec4(0.0, " << var << "_a[0] + " << var << "_a[1], 0.0, 1.0)";
3239         return s.str();
3240     }
3241 
maxBindings()3242     int maxBindings()
3243     {
3244         int units = 0;
3245         gl().getIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &units);
3246         return units;
3247     }
3248 
3249     // return max. array size allowed
maxArraySize()3250     int maxArraySize()
3251     {
3252         int units = 0;
3253         switch (getStage())
3254         {
3255         case FragmentShader:
3256             gl().getIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &units);
3257             break;
3258         case VertexShader:
3259             gl().getIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &units);
3260             break;
3261         case ComputeShader:
3262             gl().getIntegerv(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, &units);
3263             break;
3264         default:
3265             DE_ASSERT(0);
3266             break;
3267         }
3268         return units;
3269     }
3270 
3271     /*virtual*/
bind(int binding)3272     void bind(int binding)
3273     {
3274         gl().bindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, m_buffername);
3275     }
3276 
3277     /*virtual*/
unbind(int binding)3278     void unbind(int binding)
3279     {
3280         gl().bindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, 0);
3281     }
3282 
3283     /*virtual*/
setupTest(void)3284     void setupTest(void)
3285     {
3286         const float f[2] = {0.25f, 0.75f};
3287         gl().genBuffers(1, &m_buffername);
3288         gl().bindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffername);
3289         gl().bufferData(GL_SHADER_STORAGE_BUFFER, sizeof(f), f, GL_STATIC_DRAW);
3290     }
3291 
3292     /*virtual*/
teardownTest(void)3293     void teardownTest(void)
3294     {
3295         gl().bindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3296         gl().deleteBuffers(1, &m_buffername);
3297     }
3298 
3299     //=========================================================================
3300     // sub-tests overrides
3301     //=========================================================================
3302 private:
3303 private:
3304     //virtual LayoutBindingTestResult        binding_basic_default               (void);
3305     //virtual LayoutBindingTestResult        binding_basic_explicit              (void);
3306     //virtual LayoutBindingTestResult        binding_basic_multiple              (void);
3307     //virtual LayoutBindingTestResult        binding_basic_render                (void);
3308     //virtual LayoutBindingTestResult        binding_integer_constant            (void);
3309     //virtual LayoutBindingTestResult        binding_array_size                  (void);
3310     //virtual LayoutBindingTestResult        binding_array_implicit              (void);
3311     //virtual LayoutBindingTestResult        binding_array_multiple              (void);
3312     /*virtual*/
binding_api_update(void)3313     LayoutBindingTestResult binding_api_update(void)
3314     {
3315         // only for GL
3316         if (getGLSLVersion() == glu::GLSL_VERSION_310_ES)
3317             return LayoutBindingTestResult(true, String(), true);
3318 
3319         return LayoutBindingBaseCase::binding_api_update();
3320     }
3321     //virtual LayoutBindingTestResult        binding_compilation_errors          (void);
3322     //virtual LayoutBindingTestResult        binding_link_errors                 (void);
3323     //virtual LayoutBindingTestResult        binding_examples                    (void);
3324 
3325 private:
3326     glw::GLuint m_buffername;
3327 };
3328 
ShaderStorageBufferLayoutBindingCase(Context & context,const char * name,const char * description,StageType stage,LayoutBindingParameters & samplerType,glu::GLSLVersion glslVersion)3329 ShaderStorageBufferLayoutBindingCase::ShaderStorageBufferLayoutBindingCase(Context &context, const char *name,
3330                                                                            const char *description, StageType stage,
3331                                                                            LayoutBindingParameters &samplerType,
3332                                                                            glu::GLSLVersion glslVersion)
3333     : LayoutBindingBaseCase(context, name, description, stage, samplerType, glslVersion)
3334     , m_buffername(0)
3335 {
3336 }
3337 
~ShaderStorageBufferLayoutBindingCase()3338 ShaderStorageBufferLayoutBindingCase::~ShaderStorageBufferLayoutBindingCase()
3339 {
3340 }
3341 
3342 //*****************************************************************************
3343 
LayoutBindingTests(Context & context,glu::GLSLVersion glslVersion)3344 LayoutBindingTests::LayoutBindingTests(Context &context, glu::GLSLVersion glslVersion)
3345     : TestCaseGroup(context, "layout_binding", "Layout Binding LayoutBindingSubTest")
3346     , m_glslVersion(glslVersion)
3347 {
3348 }
3349 
~LayoutBindingTests(void)3350 LayoutBindingTests::~LayoutBindingTests(void)
3351 {
3352 }
3353 
3354 StageType LayoutBindingTests::stageTypes[] = {
3355     {"ComputeShader", ComputeShader},
3356     {"FragmentShader", FragmentShader},
3357     {"VertexShader", VertexShader},
3358 };
3359 
3360 // uniform_type must match vector_type, i.e. isampler2D=>ivec4
3361 LayoutBindingParameters LayoutBindingTests::test_args[] = {
3362     {"uniform", Texture, TwoD, "vec4", "sampler2D", "vec2", "texture"},
3363     {"uniform", Texture, ThreeD, "vec4", "sampler3D", "vec3", "texture"},
3364     {"uniform", Texture, TwoDArray, "vec4", "sampler2DArray", "vec3", "texture"},
3365     {"uniform", Image, TwoD, "vec4", "image2D", "ivec2", "imageLoad"},
3366     {"uniform", AtomicCounter, TwoD, "vec4", "atomic_uint", "vec3", "atomic"},
3367     {"uniform", UniformBlock, None, "vec4", "block", "vec3", "block"},
3368     {"buffer", ShaderStorageBuffer, None, "vec4", "buffer", "vec3", "atomicAdd"},
3369 };
3370 
3371 // create test name which must be unique or dEQP framework will throw
3372 // example: sampler2D_layout_binding_vec4_texture_0
createTestName(const StageType & stageType,const LayoutBindingParameters & testArgs)3373 String LayoutBindingTests::createTestName(const StageType &stageType, const LayoutBindingParameters &testArgs)
3374 {
3375     StringStream s;
3376     s << testArgs.uniform_type;
3377     s << "_layout_binding_";
3378     s << testArgs.access_function << "_";
3379     s << stageType.name;
3380     return s.str();
3381 }
3382 
init(void)3383 void LayoutBindingTests::init(void)
3384 {
3385     std::vector<StageType> stages                 = makeVector(stageTypes);
3386     std::vector<LayoutBindingParameters> samplers = makeVector(test_args);
3387     for (std::vector<StageType>::iterator stagesIter = stages.begin(); stagesIter != stages.end(); stagesIter++)
3388     {
3389         for (std::vector<LayoutBindingParameters>::iterator testArgsIter = samplers.begin();
3390              testArgsIter != samplers.end(); testArgsIter++)
3391         {
3392             String testName = createTestName(*stagesIter, *testArgsIter);
3393             switch ((*testArgsIter).surface_type)
3394             {
3395             case Texture:
3396                 addChild(new SamplerLayoutBindingCase(m_context, testName.c_str(),
3397                                                       "test sampler layout binding functionality", *stagesIter,
3398                                                       *testArgsIter, m_glslVersion));
3399                 break;
3400             case Image:
3401                 addChild(new ImageLayoutBindingCase(m_context, testName.c_str(),
3402                                                     "test image layout binding functionality", *stagesIter,
3403                                                     *testArgsIter, m_glslVersion));
3404                 break;
3405             case AtomicCounter:
3406                 addChild(new AtomicCounterLayoutBindingCase(m_context, testName.c_str(),
3407                                                             "test atomic counters layout binding functionality",
3408                                                             *stagesIter, *testArgsIter, m_glslVersion));
3409                 break;
3410             case UniformBlock:
3411                 addChild(new UniformBlocksLayoutBindingCase(m_context, testName.c_str(),
3412                                                             "test uniform block layout binding functionality",
3413                                                             *stagesIter, *testArgsIter, m_glslVersion));
3414                 break;
3415             case ShaderStorageBuffer:
3416                 addChild(new ShaderStorageBufferLayoutBindingCase(
3417                     m_context, testName.c_str(), "test shader storage buffer layout binding functionality", *stagesIter,
3418                     *testArgsIter, m_glslVersion));
3419                 break;
3420             default:
3421                 DE_ASSERT(0);
3422                 break;
3423             }
3424         }
3425     }
3426 }
3427 
3428 } // namespace glcts
3429