xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fShaderApiTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Shader API tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es3fShaderApiTests.hpp"
25 #include "es3fApiCase.hpp"
26 #include "tcuTestLog.hpp"
27 
28 #include "gluRenderContext.hpp"
29 #include "gluShaderProgram.hpp"
30 #include "gluShaderUtil.hpp"
31 #include "gluDrawUtil.hpp"
32 #include "gluContextInfo.hpp"
33 #include "gluCallLogWrapper.hpp"
34 
35 #include "glwFunctions.hpp"
36 #include "glwDefs.hpp"
37 #include "glwEnums.hpp"
38 
39 #include "deString.h"
40 
41 #include "deRandom.hpp"
42 #include "deStringUtil.hpp"
43 
44 #include <string>
45 #include <sstream>
46 #include <vector>
47 #include <map>
48 
49 using namespace glw; // GL types
50 
51 namespace deqp
52 {
53 namespace gles3
54 {
55 namespace Functional
56 {
57 
58 using tcu::TestLog;
59 
60 namespace
61 {
62 
63 enum ShaderSourceCaseFlags
64 {
65     CASE_EXPLICIT_SOURCE_LENGTHS = 1,
66     CASE_RANDOM_NULL_TERMINATED  = 2
67 };
68 
69 struct ShaderSources
70 {
71     std::vector<std::string> strings;
72     std::vector<int> lengths;
73 };
74 
75 // Simple shaders
76 
getSimpleShaderSource(const glu::ShaderType shaderType)77 const char *getSimpleShaderSource(const glu::ShaderType shaderType)
78 {
79     const char *simpleVertexShaderSource = "#version 300 es\n"
80                                            "void main (void)\n"
81                                            "{\n"
82                                            "    gl_Position = vec4(0.0);\n"
83                                            "}\n";
84 
85     const char *simpleFragmentShaderSource = "#version 300 es\n"
86                                              "layout(location = 0) out mediump vec4 o_fragColor;\n"
87                                              "void main (void)\n"
88                                              "{\n"
89                                              "    o_fragColor = vec4(0.0);\n"
90                                              "}\n";
91 
92     switch (shaderType)
93     {
94     case glu::SHADERTYPE_VERTEX:
95         return simpleVertexShaderSource;
96     case glu::SHADERTYPE_FRAGMENT:
97         return simpleFragmentShaderSource;
98     default:
99         DE_ASSERT(false);
100     }
101 
102     return 0;
103 }
104 
setShaderSources(glu::Shader & shader,const ShaderSources & sources)105 void setShaderSources(glu::Shader &shader, const ShaderSources &sources)
106 {
107     std::vector<const char *> cStrings(sources.strings.size(), 0);
108 
109     for (size_t ndx = 0; ndx < sources.strings.size(); ndx++)
110         cStrings[ndx] = sources.strings[ndx].c_str();
111 
112     if (sources.lengths.size() > 0)
113         shader.setSources((int)cStrings.size(), &cStrings[0], &sources.lengths[0]);
114     else
115         shader.setSources((int)cStrings.size(), &cStrings[0], 0);
116 }
117 
sliceSourceString(const std::string & in,ShaderSources & out,const int numSlices,const size_t paddingLength=0)118 void sliceSourceString(const std::string &in, ShaderSources &out, const int numSlices, const size_t paddingLength = 0)
119 {
120     DE_ASSERT(numSlices > 0);
121 
122     const size_t sliceSize          = in.length() / numSlices;
123     const size_t sliceSizeRemainder = in.length() - (sliceSize * numSlices);
124     const std::string padding(paddingLength, 'E');
125 
126     for (int ndx = 0; ndx < numSlices; ndx++)
127     {
128         out.strings.push_back(in.substr(ndx * sliceSize, sliceSize) + padding);
129 
130         if (paddingLength > 0)
131             out.lengths.push_back((int)sliceSize);
132     }
133 
134     if (sliceSizeRemainder > 0)
135     {
136         const std::string lastString = in.substr(numSlices * sliceSize);
137         const int lastStringLength   = (int)lastString.length();
138 
139         out.strings.push_back(lastString + padding);
140 
141         if (paddingLength > 0)
142             out.lengths.push_back(lastStringLength);
143     }
144 }
145 
queryShaderInfo(glu::RenderContext & renderCtx,uint32_t shader,glu::ShaderInfo & info)146 void queryShaderInfo(glu::RenderContext &renderCtx, uint32_t shader, glu::ShaderInfo &info)
147 {
148     const glw::Functions &gl = renderCtx.getFunctions();
149 
150     info.compileOk     = false;
151     info.compileTimeUs = 0;
152     info.infoLog.clear();
153 
154     // Query source, status & log.
155     {
156         int compileStatus = 0;
157         int sourceLen     = 0;
158         int infoLogLen    = 0;
159         int unusedLen;
160 
161         gl.getShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
162         gl.getShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &sourceLen);
163         gl.getShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLen);
164         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv()");
165 
166         info.compileOk = compileStatus != GL_FALSE;
167 
168         if (sourceLen > 0)
169         {
170             std::vector<char> source(sourceLen);
171             gl.getShaderSource(shader, (int)source.size(), &unusedLen, &source[0]);
172             info.source = std::string(&source[0], sourceLen);
173         }
174 
175         if (infoLogLen > 0)
176         {
177             std::vector<char> infoLog(infoLogLen);
178             gl.getShaderInfoLog(shader, (int)infoLog.size(), &unusedLen, &infoLog[0]);
179             info.infoLog = std::string(&infoLog[0], infoLogLen);
180         }
181     }
182 }
183 
184 // Draw test quad
185 
drawWithProgram(glu::RenderContext & renderCtx,uint32_t program)186 void drawWithProgram(glu::RenderContext &renderCtx, uint32_t program)
187 {
188     const glw::Functions &gl = renderCtx.getFunctions();
189 
190     const float position[]       = {-1.0f, -1.0f, 0.0f, 1.0f, -1.0f, +1.0f, 0.0f, 1.0f,
191                                     +1.0f, -1.0f, 0.0f, 1.0f, +1.0f, +1.0f, 0.0f, 1.0f};
192     const uint16_t quadIndices[] = {0, 1, 2, 2, 1, 3};
193 
194     gl.useProgram(program);
195 
196     {
197         glu::VertexArrayBinding vertexArrays[] = {glu::va::Float("a_position", 4, 4, 0, &position[0])};
198         glu::draw(renderCtx, program, DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
199                   glu::pr::Triangles(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0]));
200     }
201 
202     GLU_EXPECT_NO_ERROR(gl.getError(), "Draw test quad");
203 }
204 
205 // Shader source generator
206 
207 class SourceGenerator
208 {
209 public:
~SourceGenerator(void)210     virtual ~SourceGenerator(void)
211     {
212     }
213 
214     virtual std::string next(const glu::ShaderType shaderType)    = 0;
215     virtual bool finished(const glu::ShaderType shaderType) const = 0;
216 };
217 
218 class ConstantShaderGenerator : public SourceGenerator
219 {
220 public:
ConstantShaderGenerator(de::Random & rnd)221     ConstantShaderGenerator(de::Random &rnd) : m_rnd(rnd)
222     {
223     }
~ConstantShaderGenerator(void)224     ~ConstantShaderGenerator(void)
225     {
226     }
227 
finished(const glu::ShaderType shaderType) const228     bool finished(const glu::ShaderType shaderType) const
229     {
230         DE_UNREF(shaderType);
231         return false;
232     }
233 
234     std::string next(const glu::ShaderType shaderType);
235 
236 private:
237     de::Random m_rnd;
238 };
239 
next(const glu::ShaderType shaderType)240 std::string ConstantShaderGenerator::next(const glu::ShaderType shaderType)
241 {
242     DE_ASSERT(shaderType == glu::SHADERTYPE_VERTEX || shaderType == glu::SHADERTYPE_FRAGMENT);
243 
244     const float value             = m_rnd.getFloat(0.0f, 1.0f);
245     const std::string valueString = de::toString(value);
246     const std::string outputName  = (shaderType == glu::SHADERTYPE_VERTEX) ? "gl_Position" : "o_fragColor";
247 
248     std::ostringstream out;
249 
250     out << "#version 300 es\n";
251 
252     if (shaderType == glu::SHADERTYPE_FRAGMENT)
253         out << "layout(location = 0) out mediump vec4 o_fragColor;\n";
254 
255     out << "void main (void)\n";
256     out << "{\n";
257     out << "    " << outputName << " = vec4(" << valueString << ");\n";
258     out << "}\n";
259 
260     return out.str();
261 }
262 
263 // Shader allocation utility
264 
265 class ShaderAllocator
266 {
267 public:
268     ShaderAllocator(glu::RenderContext &context, SourceGenerator &generator);
269     ~ShaderAllocator(void);
270 
271     bool hasShader(const glu::ShaderType shaderType);
272 
273     void setSource(const glu::ShaderType shaderType);
274 
275     glu::Shader &createShader(const glu::ShaderType shaderType);
276     void deleteShader(const glu::ShaderType shaderType);
277 
get(const glu::ShaderType shaderType)278     glu::Shader &get(const glu::ShaderType shaderType)
279     {
280         DE_ASSERT(hasShader(shaderType));
281         return *m_shaders[shaderType];
282     }
283 
284 private:
285     const glu::RenderContext &m_context;
286     SourceGenerator &m_srcGen;
287     std::map<glu::ShaderType, glu::Shader *> m_shaders;
288 };
289 
ShaderAllocator(glu::RenderContext & context,SourceGenerator & generator)290 ShaderAllocator::ShaderAllocator(glu::RenderContext &context, SourceGenerator &generator)
291     : m_context(context)
292     , m_srcGen(generator)
293 {
294 }
295 
~ShaderAllocator(void)296 ShaderAllocator::~ShaderAllocator(void)
297 {
298     for (std::map<glu::ShaderType, glu::Shader *>::iterator shaderIter = m_shaders.begin();
299          shaderIter != m_shaders.end(); shaderIter++)
300         delete shaderIter->second;
301     m_shaders.clear();
302 }
303 
hasShader(const glu::ShaderType shaderType)304 bool ShaderAllocator::hasShader(const glu::ShaderType shaderType)
305 {
306     if (m_shaders.find(shaderType) != m_shaders.end())
307         return true;
308     else
309         return false;
310 }
311 
createShader(const glu::ShaderType shaderType)312 glu::Shader &ShaderAllocator::createShader(const glu::ShaderType shaderType)
313 {
314     DE_ASSERT(!this->hasShader(shaderType));
315 
316     glu::Shader *const shader = new glu::Shader(m_context, shaderType);
317 
318     m_shaders[shaderType] = shader;
319     this->setSource(shaderType);
320 
321     return *shader;
322 }
323 
deleteShader(const glu::ShaderType shaderType)324 void ShaderAllocator::deleteShader(const glu::ShaderType shaderType)
325 {
326     DE_ASSERT(this->hasShader(shaderType));
327 
328     delete m_shaders[shaderType];
329     m_shaders.erase(shaderType);
330 }
331 
setSource(const glu::ShaderType shaderType)332 void ShaderAllocator::setSource(const glu::ShaderType shaderType)
333 {
334     DE_ASSERT(this->hasShader(shaderType));
335     DE_ASSERT(!m_srcGen.finished(shaderType));
336 
337     const std::string source  = m_srcGen.next(shaderType);
338     const char *const cSource = source.c_str();
339 
340     m_shaders[shaderType]->setSources(1, &cSource, 0);
341 }
342 
343 // Logging utilities
344 
logShader(TestLog & log,glu::RenderContext & renderCtx,glu::Shader & shader)345 void logShader(TestLog &log, glu::RenderContext &renderCtx, glu::Shader &shader)
346 {
347     glu::ShaderInfo info;
348 
349     queryShaderInfo(renderCtx, shader.getShader(), info);
350 
351     log << TestLog::Shader(getLogShaderType(shader.getType()), info.source, info.compileOk, info.infoLog);
352 }
353 
logProgram(TestLog & log,glu::RenderContext & renderCtx,glu::Program & program,ShaderAllocator & shaders)354 void logProgram(TestLog &log, glu::RenderContext &renderCtx, glu::Program &program, ShaderAllocator &shaders)
355 {
356     log << TestLog::ShaderProgram(program.getLinkStatus(), program.getInfoLog());
357 
358     for (int shaderTypeInt = 0; shaderTypeInt < glu::SHADERTYPE_LAST; shaderTypeInt++)
359     {
360         const glu::ShaderType shaderType = (glu::ShaderType)shaderTypeInt;
361 
362         if (shaders.hasShader(shaderType))
363             logShader(log, renderCtx, shaders.get(shaderType));
364     }
365 
366     log << TestLog::EndShaderProgram;
367 }
368 
logVertexFragmentProgram(TestLog & log,glu::RenderContext & renderCtx,glu::Program & program,glu::Shader & vertShader,glu::Shader & fragShader)369 void logVertexFragmentProgram(TestLog &log, glu::RenderContext &renderCtx, glu::Program &program,
370                               glu::Shader &vertShader, glu::Shader &fragShader)
371 {
372     DE_ASSERT(vertShader.getType() == glu::SHADERTYPE_VERTEX && fragShader.getType() == glu::SHADERTYPE_FRAGMENT);
373 
374     log << TestLog::ShaderProgram(program.getLinkStatus(), program.getInfoLog());
375 
376     logShader(log, renderCtx, vertShader);
377     logShader(log, renderCtx, fragShader);
378 
379     log << TestLog::EndShaderProgram;
380 }
381 
382 } // namespace
383 
384 // Simple glCreateShader() case
385 
386 class CreateShaderCase : public ApiCase
387 {
388 public:
CreateShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)389     CreateShaderCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType)
390         : ApiCase(context, name, desc)
391         , m_shaderType(shaderType)
392     {
393     }
394 
test(void)395     void test(void)
396     {
397         const GLuint shaderObject = glCreateShader(glu::getGLShaderType(m_shaderType));
398 
399         TCU_CHECK(shaderObject != 0);
400 
401         glDeleteShader(shaderObject);
402     }
403 
404 private:
405     const glu::ShaderType m_shaderType;
406 };
407 
408 // Simple glCompileShader() case
409 
410 class CompileShaderCase : public ApiCase
411 {
412 public:
CompileShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)413     CompileShaderCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType)
414         : ApiCase(context, name, desc)
415         , m_shaderType(shaderType)
416     {
417     }
418 
checkCompileStatus(const GLuint shaderObject)419     bool checkCompileStatus(const GLuint shaderObject)
420     {
421         GLint compileStatus = -1;
422         glGetShaderiv(shaderObject, GL_COMPILE_STATUS, &compileStatus);
423         GLU_CHECK();
424 
425         return (compileStatus == GL_TRUE);
426     }
427 
test(void)428     void test(void)
429     {
430         const char *shaderSource  = getSimpleShaderSource(m_shaderType);
431         const GLuint shaderObject = glCreateShader(glu::getGLShaderType(m_shaderType));
432 
433         TCU_CHECK(shaderObject != 0);
434 
435         glShaderSource(shaderObject, 1, &shaderSource, 0);
436         glCompileShader(shaderObject);
437 
438         TCU_CHECK(checkCompileStatus(shaderObject));
439 
440         glDeleteShader(shaderObject);
441     }
442 
443 private:
444     const glu::ShaderType m_shaderType;
445 };
446 
447 // Base class for simple program API tests
448 
449 class SimpleProgramCase : public ApiCase
450 {
451 public:
SimpleProgramCase(Context & context,const char * name,const char * desc)452     SimpleProgramCase(Context &context, const char *name, const char *desc)
453         : ApiCase(context, name, desc)
454         , m_vertShader(0)
455         , m_fragShader(0)
456         , m_program(0)
457     {
458     }
459 
~SimpleProgramCase(void)460     virtual ~SimpleProgramCase(void)
461     {
462     }
463 
compileShaders(void)464     virtual void compileShaders(void)
465     {
466         const char *vertSource = getSimpleShaderSource(glu::SHADERTYPE_VERTEX);
467         const char *fragSource = getSimpleShaderSource(glu::SHADERTYPE_FRAGMENT);
468 
469         const GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
470         const GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
471 
472         TCU_CHECK(vertShader != 0);
473         TCU_CHECK(fragShader != 0);
474 
475         glShaderSource(vertShader, 1, &vertSource, 0);
476         glCompileShader(vertShader);
477 
478         glShaderSource(fragShader, 1, &fragSource, 0);
479         glCompileShader(fragShader);
480 
481         GLU_CHECK();
482 
483         m_vertShader = vertShader;
484         m_fragShader = fragShader;
485     }
486 
linkProgram(void)487     void linkProgram(void)
488     {
489         const GLuint program = glCreateProgram();
490 
491         TCU_CHECK(program != 0);
492 
493         glAttachShader(program, m_vertShader);
494         glAttachShader(program, m_fragShader);
495         GLU_CHECK();
496 
497         glLinkProgram(program);
498 
499         m_program = program;
500     }
501 
cleanup(void)502     void cleanup(void)
503     {
504         glDeleteShader(m_vertShader);
505         glDeleteShader(m_fragShader);
506         glDeleteProgram(m_program);
507     }
508 
509 protected:
510     GLuint m_vertShader;
511     GLuint m_fragShader;
512     GLuint m_program;
513 };
514 
515 // glDeleteShader() case
516 
517 class DeleteShaderCase : public SimpleProgramCase
518 {
519 public:
DeleteShaderCase(Context & context,const char * name,const char * desc)520     DeleteShaderCase(Context &context, const char *name, const char *desc) : SimpleProgramCase(context, name, desc)
521     {
522     }
523 
checkDeleteStatus(GLuint shader)524     bool checkDeleteStatus(GLuint shader)
525     {
526         GLint deleteStatus = -1;
527         glGetShaderiv(shader, GL_DELETE_STATUS, &deleteStatus);
528         GLU_CHECK();
529 
530         return (deleteStatus == GL_TRUE);
531     }
532 
deleteShaders(void)533     void deleteShaders(void)
534     {
535         glDeleteShader(m_vertShader);
536         glDeleteShader(m_fragShader);
537         GLU_CHECK();
538     }
539 
test(void)540     void test(void)
541     {
542         compileShaders();
543         linkProgram();
544         GLU_CHECK();
545 
546         deleteShaders();
547 
548         TCU_CHECK(checkDeleteStatus(m_vertShader) && checkDeleteStatus(m_fragShader));
549 
550         glDeleteProgram(m_program);
551 
552         TCU_CHECK(!(glIsShader(m_vertShader) || glIsShader(m_fragShader)));
553     }
554 };
555 
556 // Simple glLinkProgram() case
557 
558 class LinkVertexFragmentCase : public SimpleProgramCase
559 {
560 public:
LinkVertexFragmentCase(Context & context,const char * name,const char * desc)561     LinkVertexFragmentCase(Context &context, const char *name, const char *desc)
562         : SimpleProgramCase(context, name, desc)
563     {
564     }
565 
checkLinkStatus(const GLuint programObject)566     bool checkLinkStatus(const GLuint programObject)
567     {
568         GLint linkStatus = -1;
569         glGetProgramiv(programObject, GL_LINK_STATUS, &linkStatus);
570         GLU_CHECK();
571 
572         return (linkStatus == GL_TRUE);
573     }
574 
test(void)575     void test(void)
576     {
577         compileShaders();
578         linkProgram();
579 
580         GLU_CHECK_MSG("Linking failed.");
581         TCU_CHECK_MSG(checkLinkStatus(m_program), "Fail, expected LINK_STATUS to be TRUE.");
582 
583         cleanup();
584     }
585 };
586 
587 class ShaderSourceReplaceCase : public ApiCase
588 {
589 public:
ShaderSourceReplaceCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)590     ShaderSourceReplaceCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType)
591         : ApiCase(context, name, desc)
592         , m_shaderType(shaderType)
593     {
594     }
595 
generateFirstSource(void)596     std::string generateFirstSource(void)
597     {
598         return getSimpleShaderSource(m_shaderType);
599     }
600 
generateSecondSource(void)601     std::string generateSecondSource(void)
602     {
603         std::ostringstream out;
604 
605         out << "#version 300 es\n";
606         out << "precision mediump float;\n";
607 
608         if (m_shaderType == glu::SHADERTYPE_FRAGMENT)
609             out << "layout(location = 0) out mediump vec4 o_fragColor;\n";
610 
611         out << "void main()\n";
612         out << "{\n";
613         out << "    float variable = 1.0f;\n";
614 
615         if (m_shaderType == glu::SHADERTYPE_VERTEX)
616             out << "    gl_Position = vec4(variable);\n";
617         else if (m_shaderType == glu::SHADERTYPE_FRAGMENT)
618             out << "    o_fragColor = vec4(variable);\n";
619 
620         out << "}\n";
621 
622         return out.str();
623     }
624 
getSourceLength(glu::Shader & shader)625     GLint getSourceLength(glu::Shader &shader)
626     {
627         GLint sourceLength = 0;
628         glGetShaderiv(shader.getShader(), GL_SHADER_SOURCE_LENGTH, &sourceLength);
629         GLU_CHECK();
630 
631         return sourceLength;
632     }
633 
readSource(glu::Shader & shader)634     std::string readSource(glu::Shader &shader)
635     {
636         const GLint sourceLength = getSourceLength(shader);
637         std::vector<char> sourceBuffer(sourceLength + 1);
638 
639         glGetShaderSource(shader.getShader(), (GLsizei)sourceBuffer.size(), 0, &sourceBuffer[0]);
640 
641         return std::string(&sourceBuffer[0]);
642     }
643 
verifyShaderSourceReplaced(glu::Shader & shader,const std::string & firstSource,const std::string & secondSource)644     void verifyShaderSourceReplaced(glu::Shader &shader, const std::string &firstSource,
645                                     const std::string &secondSource)
646     {
647         TestLog &log             = m_testCtx.getLog();
648         const std::string result = readSource(shader);
649 
650         if (result == firstSource)
651         {
652             log << TestLog::Message << "Fail, source was not replaced." << TestLog::EndMessage;
653             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader source nor replaced");
654         }
655         else if (result != secondSource)
656         {
657             log << TestLog::Message << "Fail, invalid shader source." << TestLog::EndMessage;
658             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid source");
659         }
660     }
661 
test(void)662     void test(void)
663     {
664         TestLog &log = m_testCtx.getLog();
665 
666         glu::Shader shader(m_context.getRenderContext(), m_shaderType);
667 
668         const std::string firstSourceStr  = generateFirstSource();
669         const std::string secondSourceStr = generateSecondSource();
670 
671         const char *firstSource  = firstSourceStr.c_str();
672         const char *secondSource = secondSourceStr.c_str();
673 
674         log << TestLog::Message << "Setting shader source." << TestLog::EndMessage;
675 
676         shader.setSources(1, &firstSource, 0);
677         GLU_CHECK();
678 
679         log << TestLog::Message << "Replacing shader source." << TestLog::EndMessage;
680 
681         shader.setSources(1, &secondSource, 0);
682         GLU_CHECK();
683 
684         verifyShaderSourceReplaced(shader, firstSourceStr, secondSourceStr);
685     }
686 
687 private:
688     glu::ShaderType m_shaderType;
689 };
690 
691 // glShaderSource() split source case
692 
693 class ShaderSourceSplitCase : public ApiCase
694 {
695 public:
ShaderSourceSplitCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType,const int numSlices,const uint32_t flags=0)696     ShaderSourceSplitCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType,
697                           const int numSlices, const uint32_t flags = 0)
698         : ApiCase(context, name, desc)
699         , m_rnd(deStringHash(getName()) ^ 0x4fb2337d)
700         , m_shaderType(shaderType)
701         , m_numSlices(numSlices)
702         , m_explicitLengths((flags & CASE_EXPLICIT_SOURCE_LENGTHS) != 0)
703         , m_randomNullTerm((flags & CASE_RANDOM_NULL_TERMINATED) != 0)
704     {
705         DE_ASSERT(m_shaderType == glu::SHADERTYPE_VERTEX || m_shaderType == glu::SHADERTYPE_FRAGMENT);
706     }
707 
~ShaderSourceSplitCase(void)708     virtual ~ShaderSourceSplitCase(void)
709     {
710     }
711 
generateFullSource(void)712     std::string generateFullSource(void)
713     {
714         std::ostringstream out;
715 
716         out << "#version 300 es\n";
717         out << "precision mediump float;\n";
718 
719         if (m_shaderType == glu::SHADERTYPE_FRAGMENT)
720             out << "layout(location = 0) out mediump vec4 o_fragColor;\n";
721 
722         out << "void main()\n";
723         out << "{\n";
724         out << "    float variable = 1.0f;\n";
725 
726         if (m_shaderType == glu::SHADERTYPE_VERTEX)
727             out << "    gl_Position = vec4(variable);\n";
728         else if (m_shaderType == glu::SHADERTYPE_FRAGMENT)
729             out << "    o_fragColor = vec4(variable);\n";
730 
731         out << "}\n";
732 
733         return out.str();
734     }
735 
insertRandomNullTermStrings(ShaderSources & sources)736     void insertRandomNullTermStrings(ShaderSources &sources)
737     {
738         const int numInserts = de::max(m_numSlices >> 2, 1);
739         std::vector<int> indices(sources.strings.size(), 0);
740 
741         DE_ASSERT(sources.lengths.size() > 0);
742         DE_ASSERT(sources.lengths.size() == sources.strings.size());
743 
744         for (int i = 0; i < (int)sources.strings.size(); i++)
745             indices[i] = i;
746 
747         m_rnd.shuffle(indices.begin(), indices.end());
748 
749         for (int i = 0; i < numInserts; i++)
750         {
751             const int ndx                    = indices[i];
752             const int unpaddedLength         = sources.lengths[ndx];
753             const std::string unpaddedString = sources.strings[ndx].substr(0, unpaddedLength);
754 
755             sources.strings[ndx] = unpaddedString;
756             sources.lengths[ndx] = m_rnd.getInt(-10, -1);
757         }
758     }
759 
generateSources(ShaderSources & sources)760     void generateSources(ShaderSources &sources)
761     {
762         const size_t paddingLength = (m_explicitLengths ? 10 : 0);
763         std::string str            = generateFullSource();
764 
765         sliceSourceString(str, sources, m_numSlices, paddingLength);
766 
767         if (m_randomNullTerm)
768             insertRandomNullTermStrings(sources);
769     }
770 
buildProgram(glu::Shader & shader)771     void buildProgram(glu::Shader &shader)
772     {
773         TestLog &log                  = m_testCtx.getLog();
774         glu::RenderContext &renderCtx = m_context.getRenderContext();
775 
776         const glu::ShaderType supportShaderType =
777             (m_shaderType == glu::SHADERTYPE_FRAGMENT ? glu::SHADERTYPE_VERTEX : glu::SHADERTYPE_FRAGMENT);
778         const char *supportShaderSource = getSimpleShaderSource(supportShaderType);
779         glu::Shader supportShader(renderCtx, supportShaderType);
780 
781         glu::Program program(renderCtx);
782 
783         supportShader.setSources(1, &supportShaderSource, 0);
784         supportShader.compile();
785 
786         program.attachShader(shader.getShader());
787         program.attachShader(supportShader.getShader());
788 
789         program.link();
790 
791         if (m_shaderType == glu::SHADERTYPE_VERTEX)
792             logVertexFragmentProgram(log, renderCtx, program, shader, supportShader);
793         else
794             logVertexFragmentProgram(log, renderCtx, program, supportShader, shader);
795     }
796 
test(void)797     void test(void)
798     {
799         TestLog &log                  = m_testCtx.getLog();
800         glu::RenderContext &renderCtx = m_context.getRenderContext();
801 
802         ShaderSources sources;
803         glu::Shader shader(renderCtx, m_shaderType);
804 
805         generateSources(sources);
806         setShaderSources(shader, sources);
807         shader.compile();
808 
809         buildProgram(shader);
810 
811         if (!shader.getCompileStatus())
812         {
813             log << TestLog::Message << "Compilation failed." << TestLog::EndMessage;
814             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed");
815         }
816     }
817 
818 private:
819     de::Random m_rnd;
820 
821     const glu::ShaderType m_shaderType;
822     const int m_numSlices;
823 
824     const bool m_explicitLengths;
825     const bool m_randomNullTerm;
826 };
827 
828 // Base class for program state persistence cases
829 
830 class ProgramStateCase : public ApiCase
831 {
832 public:
833     ProgramStateCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType);
~ProgramStateCase(void)834     virtual ~ProgramStateCase(void)
835     {
836     }
837 
838     void buildProgram(glu::Program &program, ShaderAllocator &shaders);
839     void verify(glu::Program &program, const glu::ProgramInfo &reference);
840 
841     void test(void);
842 
843     virtual void executeForProgram(glu::Program &program, ShaderAllocator &shaders) = 0;
844 
845 protected:
846     de::Random m_rnd;
847     const glu::ShaderType m_shaderType;
848 };
849 
ProgramStateCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)850 ProgramStateCase::ProgramStateCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType)
851     : ApiCase(context, name, desc)
852     , m_rnd(deStringHash(name) ^ 0x713de0ca)
853     , m_shaderType(shaderType)
854 {
855     DE_ASSERT(m_shaderType == glu::SHADERTYPE_VERTEX || m_shaderType == glu::SHADERTYPE_FRAGMENT);
856 }
857 
buildProgram(glu::Program & program,ShaderAllocator & shaders)858 void ProgramStateCase::buildProgram(glu::Program &program, ShaderAllocator &shaders)
859 {
860     TestLog &log = m_testCtx.getLog();
861 
862     glu::Shader &vertShader = shaders.createShader(glu::SHADERTYPE_VERTEX);
863     glu::Shader &fragShader = shaders.createShader(glu::SHADERTYPE_FRAGMENT);
864 
865     vertShader.compile();
866     fragShader.compile();
867 
868     program.attachShader(vertShader.getShader());
869     program.attachShader(fragShader.getShader());
870     program.link();
871 
872     logProgram(log, m_context.getRenderContext(), program, shaders);
873 }
874 
verify(glu::Program & program,const glu::ProgramInfo & reference)875 void ProgramStateCase::verify(glu::Program &program, const glu::ProgramInfo &reference)
876 {
877     TestLog &log                        = m_testCtx.getLog();
878     const glu::ProgramInfo &programInfo = program.getInfo();
879 
880     if (!programInfo.linkOk)
881     {
882         log << TestLog::Message
883             << "Fail, link status may only change as a result of linking or loading a program binary."
884             << TestLog::EndMessage;
885         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Link status changed");
886     }
887 
888     if (programInfo.linkTimeUs != reference.linkTimeUs)
889     {
890         log << TestLog::Message << "Fail, reported link time changed." << TestLog::EndMessage;
891         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Link time changed");
892     }
893 
894     if (programInfo.infoLog != reference.infoLog)
895     {
896         log << TestLog::Message << "Fail, program infolog changed." << TestLog::EndMessage;
897         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Infolog changed");
898     }
899 }
900 
test(void)901 void ProgramStateCase::test(void)
902 {
903     TestLog &log                  = m_testCtx.getLog();
904     glu::RenderContext &renderCtx = m_context.getRenderContext();
905 
906     ConstantShaderGenerator sourceGen(m_rnd);
907 
908     ShaderAllocator shaders(renderCtx, sourceGen);
909     glu::Program program(renderCtx);
910 
911     buildProgram(program, shaders);
912 
913     if (program.getLinkStatus())
914     {
915         glu::ProgramInfo programInfo = program.getInfo();
916 
917         executeForProgram(program, shaders);
918 
919         verify(program, programInfo);
920 
921         logProgram(log, renderCtx, program, shaders);
922     }
923     else
924     {
925         log << TestLog::Message << "Fail, couldn't link program." << TestLog::EndMessage;
926         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Linking failed");
927     }
928 }
929 
930 // Program state case utilities
931 
932 namespace
933 {
934 
935 template <class T>
addProgramStateCase(TestCaseGroup * group,Context & context,const std::string & name,const std::string & desc)936 void addProgramStateCase(TestCaseGroup *group, Context &context, const std::string &name, const std::string &desc)
937 {
938     for (int shaderTypeInt = 0; shaderTypeInt < 2; shaderTypeInt++)
939     {
940         const glu::ShaderType shaderType = (shaderTypeInt == 1) ? glu::SHADERTYPE_FRAGMENT : glu::SHADERTYPE_VERTEX;
941         const std::string shaderTypeName = getShaderTypeName(shaderType);
942 
943         const std::string caseName = name + "_" + shaderTypeName;
944         const std::string caseDesc = "Build program, " + desc + ", for " + shaderTypeName + " shader.";
945 
946         group->addChild(new T(context, caseName.c_str(), caseDesc.c_str(), shaderType));
947     }
948 }
949 
950 } // namespace
951 
952 // Specialized program state cases
953 
954 class ProgramStateDetachShaderCase : public ProgramStateCase
955 {
956 public:
ProgramStateDetachShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)957     ProgramStateDetachShaderCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType)
958         : ProgramStateCase(context, name, desc, shaderType)
959     {
960     }
961 
~ProgramStateDetachShaderCase(void)962     virtual ~ProgramStateDetachShaderCase(void)
963     {
964     }
965 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)966     void executeForProgram(glu::Program &program, ShaderAllocator &shaders)
967     {
968         TestLog &log            = m_testCtx.getLog();
969         glu::Shader &caseShader = shaders.get(m_shaderType);
970 
971         log << TestLog::Message << "Detaching " + std::string(getShaderTypeName(m_shaderType)) + " shader"
972             << TestLog::EndMessage;
973         program.detachShader(caseShader.getShader());
974     }
975 };
976 
977 class ProgramStateReattachShaderCase : public ProgramStateCase
978 {
979 public:
ProgramStateReattachShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)980     ProgramStateReattachShaderCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType)
981         : ProgramStateCase(context, name, desc, shaderType)
982     {
983     }
984 
~ProgramStateReattachShaderCase(void)985     virtual ~ProgramStateReattachShaderCase(void)
986     {
987     }
988 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)989     void executeForProgram(glu::Program &program, ShaderAllocator &shaders)
990     {
991         TestLog &log            = m_testCtx.getLog();
992         glu::Shader &caseShader = shaders.get(m_shaderType);
993 
994         log << TestLog::Message << "Reattaching " + std::string(getShaderTypeName(m_shaderType)) + " shader"
995             << TestLog::EndMessage;
996         program.detachShader(caseShader.getShader());
997         program.attachShader(caseShader.getShader());
998     }
999 };
1000 
1001 class ProgramStateDeleteShaderCase : public ProgramStateCase
1002 {
1003 public:
ProgramStateDeleteShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1004     ProgramStateDeleteShaderCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType)
1005         : ProgramStateCase(context, name, desc, shaderType)
1006     {
1007     }
1008 
~ProgramStateDeleteShaderCase(void)1009     virtual ~ProgramStateDeleteShaderCase(void)
1010     {
1011     }
1012 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)1013     void executeForProgram(glu::Program &program, ShaderAllocator &shaders)
1014     {
1015         TestLog &log            = m_testCtx.getLog();
1016         glu::Shader &caseShader = shaders.get(m_shaderType);
1017 
1018         log << TestLog::Message << "Deleting " + std::string(getShaderTypeName(m_shaderType)) + " shader"
1019             << TestLog::EndMessage;
1020         program.detachShader(caseShader.getShader());
1021         shaders.deleteShader(m_shaderType);
1022     }
1023 };
1024 
1025 class ProgramStateReplaceShaderCase : public ProgramStateCase
1026 {
1027 public:
ProgramStateReplaceShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1028     ProgramStateReplaceShaderCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType)
1029         : ProgramStateCase(context, name, desc, shaderType)
1030     {
1031     }
1032 
~ProgramStateReplaceShaderCase(void)1033     virtual ~ProgramStateReplaceShaderCase(void)
1034     {
1035     }
1036 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)1037     void executeForProgram(glu::Program &program, ShaderAllocator &shaders)
1038     {
1039         TestLog &log            = m_testCtx.getLog();
1040         glu::Shader &caseShader = shaders.get(m_shaderType);
1041 
1042         log << TestLog::Message << "Deleting and replacing " + std::string(getShaderTypeName(m_shaderType)) + " shader"
1043             << TestLog::EndMessage;
1044         program.detachShader(caseShader.getShader());
1045         shaders.deleteShader(m_shaderType);
1046         program.attachShader(shaders.createShader(m_shaderType).getShader());
1047     }
1048 };
1049 
1050 class ProgramStateRecompileShaderCase : public ProgramStateCase
1051 {
1052 public:
ProgramStateRecompileShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1053     ProgramStateRecompileShaderCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType)
1054         : ProgramStateCase(context, name, desc, shaderType)
1055     {
1056     }
1057 
~ProgramStateRecompileShaderCase(void)1058     virtual ~ProgramStateRecompileShaderCase(void)
1059     {
1060     }
1061 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)1062     void executeForProgram(glu::Program &program, ShaderAllocator &shaders)
1063     {
1064         TestLog &log            = m_testCtx.getLog();
1065         glu::Shader &caseShader = shaders.get(m_shaderType);
1066 
1067         log << TestLog::Message << "Recompiling " + std::string(getShaderTypeName(m_shaderType)) + " shader"
1068             << TestLog::EndMessage;
1069         caseShader.compile();
1070         DE_UNREF(program);
1071     }
1072 };
1073 
1074 class ProgramStateReplaceSourceCase : public ProgramStateCase
1075 {
1076 public:
ProgramStateReplaceSourceCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1077     ProgramStateReplaceSourceCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType)
1078         : ProgramStateCase(context, name, desc, shaderType)
1079     {
1080     }
1081 
~ProgramStateReplaceSourceCase(void)1082     virtual ~ProgramStateReplaceSourceCase(void)
1083     {
1084     }
1085 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)1086     void executeForProgram(glu::Program &program, ShaderAllocator &shaders)
1087     {
1088         TestLog &log            = m_testCtx.getLog();
1089         glu::Shader &caseShader = shaders.get(m_shaderType);
1090 
1091         log << TestLog::Message
1092             << "Replacing " + std::string(getShaderTypeName(m_shaderType)) + " shader source and recompiling"
1093             << TestLog::EndMessage;
1094         shaders.setSource(m_shaderType);
1095         caseShader.compile();
1096         DE_UNREF(program);
1097     }
1098 };
1099 
1100 // Program binary utilities
1101 
1102 namespace
1103 {
1104 
1105 struct ProgramBinary
1106 {
1107     GLenum format;
1108     std::vector<uint8_t> data;
1109 };
1110 
programBinariesEqual(const ProgramBinary & first,const ProgramBinary & second)1111 bool programBinariesEqual(const ProgramBinary &first, const ProgramBinary &second)
1112 {
1113     if ((first.format != second.format) || (first.data.size() != second.data.size()))
1114         return false;
1115 
1116     return std::equal(first.data.begin(), first.data.end(), second.data.begin());
1117 }
1118 
1119 } // namespace
1120 
1121 // Base class for program binary cases
1122 
1123 class ProgramBinaryCase : public TestCase, protected glu::CallLogWrapper
1124 {
1125 public:
1126     ProgramBinaryCase(Context &context, const char *name, const char *desc);
1127     virtual ~ProgramBinaryCase(void);
1128 
1129     void getBinaryFormats(std::vector<GLenum> &out);
1130     bool isFormatSupported(const glw::GLenum format) const;
1131 
1132     void getProgramBinary(ProgramBinary &out, GLuint program);
1133     void loadProgramBinary(ProgramBinary &binary, GLuint program);
1134 
1135     void verifyProgramBinary(ProgramBinary &binary);
1136 
1137     void init(void);
1138     IterateResult iterate(void);
1139 
1140     virtual void test(void) = 0;
1141 
1142 protected:
1143     std::vector<GLenum> m_formats;
1144 };
1145 
ProgramBinaryCase(Context & context,const char * name,const char * desc)1146 ProgramBinaryCase::ProgramBinaryCase(Context &context, const char *name, const char *desc)
1147     : TestCase(context, name, desc)
1148     , CallLogWrapper(context.getRenderContext().getFunctions(), context.getTestContext().getLog())
1149 {
1150 }
1151 
~ProgramBinaryCase(void)1152 ProgramBinaryCase::~ProgramBinaryCase(void)
1153 {
1154 }
1155 
getBinaryFormats(std::vector<GLenum> & out)1156 void ProgramBinaryCase::getBinaryFormats(std::vector<GLenum> &out)
1157 {
1158     GLint numFormats = -1;
1159     glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &numFormats);
1160 
1161     out.clear();
1162 
1163     if (numFormats > 0)
1164     {
1165         out.resize(numFormats, 0);
1166 
1167         glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, (GLint *)&out[0]);
1168     }
1169 }
1170 
isFormatSupported(const glw::GLenum format) const1171 bool ProgramBinaryCase::isFormatSupported(const glw::GLenum format) const
1172 {
1173     return (std::find(m_formats.begin(), m_formats.end(), format) != m_formats.end());
1174 }
1175 
getProgramBinary(ProgramBinary & out,GLuint program)1176 void ProgramBinaryCase::getProgramBinary(ProgramBinary &out, GLuint program)
1177 {
1178     GLint binaryLength = -1;
1179     glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
1180 
1181     if (binaryLength > 0)
1182     {
1183         GLsizei actualLength;
1184         GLenum format;
1185 
1186         out.data.clear();
1187         out.data.resize(binaryLength, 0);
1188 
1189         GLU_CHECK_CALL(glGetProgramBinary(program, (GLsizei)out.data.size(), &actualLength, &format, &(out.data[0])));
1190 
1191         TCU_CHECK(actualLength == binaryLength);
1192 
1193         out.format = format;
1194     }
1195 }
1196 
loadProgramBinary(ProgramBinary & binary,GLuint program)1197 void ProgramBinaryCase::loadProgramBinary(ProgramBinary &binary, GLuint program)
1198 {
1199     glProgramBinary(program, binary.format, &binary.data[0], (GLsizei)binary.data.size());
1200     GLU_CHECK_MSG("Failed to load program binary.");
1201 }
1202 
verifyProgramBinary(ProgramBinary & binary)1203 void ProgramBinaryCase::verifyProgramBinary(ProgramBinary &binary)
1204 {
1205     TestLog &log = m_testCtx.getLog();
1206 
1207     if (!isFormatSupported(binary.format))
1208     {
1209         log << TestLog::Message << "Program binary format " << binary.format
1210             << " is not among the supported formats reported by the platform." << TestLog::EndMessage;
1211 
1212         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid format");
1213     }
1214 }
1215 
init(void)1216 void ProgramBinaryCase::init(void)
1217 {
1218     getBinaryFormats(m_formats);
1219 }
1220 
iterate(void)1221 tcu::TestNode::IterateResult ProgramBinaryCase::iterate(void)
1222 {
1223     TestLog &log = m_testCtx.getLog();
1224 
1225     if (m_formats.empty())
1226     {
1227         log << TestLog::Message << "No program binary formats are supported." << TestLog::EndMessage;
1228 
1229         m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported");
1230     }
1231     else
1232     {
1233         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1234 
1235         enableLogging(true);
1236         test();
1237     }
1238 
1239     return STOP;
1240 }
1241 
1242 // Simple program binary case
1243 
1244 class ProgramBinarySimpleCase : public ProgramBinaryCase
1245 {
1246 public:
ProgramBinarySimpleCase(Context & context,const char * name,const char * desc)1247     ProgramBinarySimpleCase(Context &context, const char *name, const char *desc)
1248         : ProgramBinaryCase(context, name, desc)
1249     {
1250     }
1251 
~ProgramBinarySimpleCase(void)1252     virtual ~ProgramBinarySimpleCase(void)
1253     {
1254     }
1255 
test(void)1256     void test(void)
1257     {
1258         const std::string vertSrc = getSimpleShaderSource(glu::SHADERTYPE_VERTEX);
1259         const std::string fragSrc = getSimpleShaderSource(glu::SHADERTYPE_FRAGMENT);
1260 
1261         const glu::ProgramSources sources = glu::makeVtxFragSources(vertSrc, fragSrc);
1262 
1263         glu::ShaderProgram program(m_context.getRenderContext(), sources);
1264 
1265         if (program.isOk())
1266         {
1267             ProgramBinary binary;
1268 
1269             getProgramBinary(binary, program.getProgram());
1270             verifyProgramBinary(binary);
1271         }
1272     }
1273 };
1274 
1275 // Program binary uniform reset case
1276 
1277 class ProgramBinaryUniformResetCase : public ProgramBinaryCase
1278 {
1279 public:
ProgramBinaryUniformResetCase(Context & context,const char * name,const char * desc)1280     ProgramBinaryUniformResetCase(Context &context, const char *name, const char *desc)
1281         : ProgramBinaryCase(context, name, desc)
1282         , m_rnd(deStringHash(name) ^ 0xf2b48c6a)
1283     {
1284     }
1285 
~ProgramBinaryUniformResetCase(void)1286     virtual ~ProgramBinaryUniformResetCase(void)
1287     {
1288     }
1289 
getShaderSource(const glu::ShaderType shaderType) const1290     std::string getShaderSource(const glu::ShaderType shaderType) const
1291     {
1292         const char *vertSrc = "#version 300 es\n"
1293                               "uniform bool u_boolVar;\n"
1294                               "uniform highp int u_intVar;\n"
1295                               "uniform highp float u_floatVar;\n\n"
1296                               "in highp vec4 a_position;\n\n"
1297                               "void main (void)\n"
1298                               "{\n"
1299                               "    gl_Position = a_position;\n"
1300                               "}\n";
1301         const char *fragSrc = "#version 300 es\n"
1302                               "uniform bool u_boolVar;\n"
1303                               "uniform highp int u_intVar;\n"
1304                               "uniform highp float u_floatVar;\n\n"
1305                               "layout(location = 0) out mediump vec4 o_fragColor;\n\n"
1306                               "void main (void)\n"
1307                               "{\n"
1308                               "    mediump float refAll = float(u_boolVar) + float(u_intVar) + u_floatVar;\n"
1309                               "    o_fragColor = vec4(refAll);\n"
1310                               "}\n";
1311 
1312         DE_ASSERT(shaderType == glu::SHADERTYPE_VERTEX || shaderType == glu::SHADERTYPE_FRAGMENT);
1313 
1314         return (shaderType == glu::SHADERTYPE_VERTEX) ? vertSrc : fragSrc;
1315     }
1316 
setUniformsRandom(glu::ShaderProgram & program)1317     void setUniformsRandom(glu::ShaderProgram &program)
1318     {
1319         TestLog &log          = m_testCtx.getLog();
1320         const uint32_t glProg = program.getProgram();
1321 
1322         log << TestLog::Message << "Setting uniforms to random non-zero values." << TestLog::EndMessage;
1323 
1324         glUseProgram(glProg);
1325 
1326         {
1327             const GLint boolLoc  = glGetUniformLocation(glProg, "u_boolVar");
1328             const GLint intLoc   = glGetUniformLocation(glProg, "u_intVar");
1329             const GLint floatLoc = glGetUniformLocation(glProg, "u_floatVar");
1330 
1331             const int32_t intVal = m_rnd.getInt(1, 1000);
1332             const float floatVal = m_rnd.getFloat(1.0, 1000.0);
1333 
1334             glUniform1i(boolLoc, GL_TRUE);
1335             glUniform1f(floatLoc, floatVal);
1336             glUniform1i(intLoc, intVal);
1337         }
1338     }
1339 
verifyUniformInt(glu::ShaderProgram & program,const std::string & name)1340     void verifyUniformInt(glu::ShaderProgram &program, const std::string &name)
1341     {
1342         const GLint intLoc = glGetUniformLocation(program.getProgram(), name.c_str());
1343         GLint intVar       = -1;
1344 
1345         glGetUniformiv(program.getProgram(), intLoc, &intVar);
1346 
1347         if (intVar != 0)
1348         {
1349             m_testCtx.getLog() << TestLog::Message << "Fail, expected zero value for " << name
1350                                << ", received: " << intVar << TestLog::EndMessage;
1351             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Uniform value not reset");
1352         }
1353     }
1354 
verifyUniformFloat(glu::ShaderProgram & program,const std::string & name)1355     void verifyUniformFloat(glu::ShaderProgram &program, const std::string &name)
1356     {
1357         const GLint floatLoc = glGetUniformLocation(program.getProgram(), name.c_str());
1358         GLfloat floatVar     = -1;
1359 
1360         glGetUniformfv(program.getProgram(), floatLoc, &floatVar);
1361 
1362         if (floatVar != 0.0f)
1363         {
1364             m_testCtx.getLog() << TestLog::Message << "Fail, expected zero value for " << name
1365                                << ", received: " << de::toString(floatVar) << TestLog::EndMessage;
1366             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Uniform value not reset");
1367         }
1368     }
1369 
verifyUniformsReset(glu::ShaderProgram & program)1370     void verifyUniformsReset(glu::ShaderProgram &program)
1371     {
1372         m_testCtx.getLog() << TestLog::Message << "Verifying uniform reset to 0/false." << TestLog::EndMessage;
1373 
1374         verifyUniformInt(program, "u_boolVar");
1375         verifyUniformInt(program, "u_intVar");
1376         verifyUniformFloat(program, "u_floatVar");
1377     }
1378 
test(void)1379     void test(void)
1380     {
1381         TestLog &log = m_testCtx.getLog();
1382 
1383         const std::string vertSrc = getShaderSource(glu::SHADERTYPE_VERTEX);
1384         const std::string fragSrc = getShaderSource(glu::SHADERTYPE_FRAGMENT);
1385 
1386         const glu::ProgramSources sources = glu::makeVtxFragSources(vertSrc, fragSrc);
1387 
1388         glu::ShaderProgram program(m_context.getRenderContext(), sources);
1389 
1390         log << program;
1391 
1392         TCU_CHECK_MSG(program.isOk(), "Couldn't build program");
1393 
1394         {
1395             ProgramBinary binary;
1396 
1397             getProgramBinary(binary, program.getProgram());
1398             verifyProgramBinary(binary);
1399 
1400             setUniformsRandom(program);
1401 
1402             log << TestLog::Message << "Rendering test image and reloading binary" << TestLog::EndMessage;
1403 
1404             drawWithProgram(m_context.getRenderContext(), program.getProgram());
1405             loadProgramBinary(binary, program.getProgram());
1406 
1407             verifyUniformsReset(program);
1408         }
1409     }
1410 
1411 private:
1412     de::Random m_rnd;
1413 };
1414 
1415 // Base class for program state persistence cases
1416 
1417 class ProgramBinaryPersistenceCase : public ProgramBinaryCase
1418 {
1419 public:
1420     ProgramBinaryPersistenceCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType);
~ProgramBinaryPersistenceCase(void)1421     virtual ~ProgramBinaryPersistenceCase(void)
1422     {
1423     }
1424 
1425     void buildProgram(glu::Program &program, ShaderAllocator &shaders);
1426 
1427     void test(void);
1428 
1429     virtual void executeForProgram(glu::Program &program, ShaderAllocator &shaders) = 0;
1430     virtual void verify(glu::Program &program, const ProgramBinary &binary);
1431 
1432 protected:
1433     de::Random m_rnd;
1434     const glu::ShaderType m_shaderType;
1435 };
1436 
ProgramBinaryPersistenceCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1437 ProgramBinaryPersistenceCase::ProgramBinaryPersistenceCase(Context &context, const char *name, const char *desc,
1438                                                            glu::ShaderType shaderType)
1439     : ProgramBinaryCase(context, name, desc)
1440     , m_rnd(deStringHash(name) ^ 0x713de0ca)
1441     , m_shaderType(shaderType)
1442 {
1443     DE_ASSERT(m_shaderType == glu::SHADERTYPE_VERTEX || m_shaderType == glu::SHADERTYPE_FRAGMENT);
1444 }
1445 
buildProgram(glu::Program & program,ShaderAllocator & shaders)1446 void ProgramBinaryPersistenceCase::buildProgram(glu::Program &program, ShaderAllocator &shaders)
1447 {
1448     TestLog &log = m_testCtx.getLog();
1449 
1450     glu::Shader &vertShader = shaders.createShader(glu::SHADERTYPE_VERTEX);
1451     glu::Shader &fragShader = shaders.createShader(glu::SHADERTYPE_FRAGMENT);
1452 
1453     vertShader.compile();
1454     fragShader.compile();
1455 
1456     program.attachShader(vertShader.getShader());
1457     program.attachShader(fragShader.getShader());
1458     program.link();
1459 
1460     logProgram(log, m_context.getRenderContext(), program, shaders);
1461 }
1462 
verify(glu::Program & program,const ProgramBinary & binary)1463 void ProgramBinaryPersistenceCase::verify(glu::Program &program, const ProgramBinary &binary)
1464 {
1465     TestLog &log = m_testCtx.getLog();
1466     ProgramBinary currentBinary;
1467 
1468     getProgramBinary(currentBinary, program.getProgram());
1469 
1470     if (!programBinariesEqual(binary, currentBinary))
1471     {
1472         log << TestLog::Message << "Fail, program binary may only change as a result of linking or loading."
1473             << TestLog::EndMessage;
1474         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Program binary changed");
1475     }
1476 }
1477 
test(void)1478 void ProgramBinaryPersistenceCase::test(void)
1479 {
1480     TestLog &log                  = m_testCtx.getLog();
1481     glu::RenderContext &renderCtx = m_context.getRenderContext();
1482 
1483     ConstantShaderGenerator sourceGen(m_rnd);
1484 
1485     ShaderAllocator shaders(renderCtx, sourceGen);
1486     glu::Program program(renderCtx);
1487 
1488     buildProgram(program, shaders);
1489 
1490     if (program.getLinkStatus())
1491     {
1492         ProgramBinary binary;
1493         getProgramBinary(binary, program.getProgram());
1494 
1495         executeForProgram(program, shaders);
1496 
1497         verify(program, binary);
1498 
1499         logProgram(log, renderCtx, program, shaders);
1500     }
1501     else
1502     {
1503         log << TestLog::Message << "Fail, couldn't link program." << TestLog::EndMessage;
1504         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Linking failed");
1505     }
1506 }
1507 
1508 // Program state case utilities
1509 
1510 namespace
1511 {
1512 
1513 template <class T>
addProgramBinaryPersistenceCase(TestCaseGroup * group,Context & context,const std::string & name,const std::string & desc)1514 void addProgramBinaryPersistenceCase(TestCaseGroup *group, Context &context, const std::string &name,
1515                                      const std::string &desc)
1516 {
1517     for (int shaderTypeInt = 0; shaderTypeInt < 2; shaderTypeInt++)
1518     {
1519         const glu::ShaderType shaderType = (shaderTypeInt == 1) ? glu::SHADERTYPE_FRAGMENT : glu::SHADERTYPE_VERTEX;
1520         const std::string shaderTypeName = getShaderTypeName(shaderType);
1521 
1522         const std::string caseName = name + "_" + shaderTypeName;
1523         const std::string caseDesc = "Build program, " + desc + ", for " + shaderTypeName + " shader.";
1524 
1525         group->addChild(new T(context, caseName.c_str(), caseDesc.c_str(), shaderType));
1526     }
1527 }
1528 
1529 } // namespace
1530 
1531 // Specialized program state cases
1532 
1533 class ProgramBinaryPersistenceDetachShaderCase : public ProgramBinaryPersistenceCase
1534 {
1535 public:
ProgramBinaryPersistenceDetachShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1536     ProgramBinaryPersistenceDetachShaderCase(Context &context, const char *name, const char *desc,
1537                                              glu::ShaderType shaderType)
1538         : ProgramBinaryPersistenceCase(context, name, desc, shaderType)
1539     {
1540     }
1541 
~ProgramBinaryPersistenceDetachShaderCase(void)1542     virtual ~ProgramBinaryPersistenceDetachShaderCase(void)
1543     {
1544     }
1545 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)1546     void executeForProgram(glu::Program &program, ShaderAllocator &shaders)
1547     {
1548         TestLog &log            = m_testCtx.getLog();
1549         glu::Shader &caseShader = shaders.get(m_shaderType);
1550 
1551         log << TestLog::Message << "Detaching " + std::string(getShaderTypeName(m_shaderType)) + " shader"
1552             << TestLog::EndMessage;
1553         program.detachShader(caseShader.getShader());
1554     }
1555 };
1556 
1557 class ProgramBinaryPersistenceReattachShaderCase : public ProgramBinaryPersistenceCase
1558 {
1559 public:
ProgramBinaryPersistenceReattachShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1560     ProgramBinaryPersistenceReattachShaderCase(Context &context, const char *name, const char *desc,
1561                                                glu::ShaderType shaderType)
1562         : ProgramBinaryPersistenceCase(context, name, desc, shaderType)
1563     {
1564     }
1565 
~ProgramBinaryPersistenceReattachShaderCase(void)1566     virtual ~ProgramBinaryPersistenceReattachShaderCase(void)
1567     {
1568     }
1569 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)1570     void executeForProgram(glu::Program &program, ShaderAllocator &shaders)
1571     {
1572         TestLog &log            = m_testCtx.getLog();
1573         glu::Shader &caseShader = shaders.get(m_shaderType);
1574 
1575         log << TestLog::Message << "Reattaching " + std::string(getShaderTypeName(m_shaderType)) + " shader"
1576             << TestLog::EndMessage;
1577         program.detachShader(caseShader.getShader());
1578         program.attachShader(caseShader.getShader());
1579     }
1580 };
1581 
1582 class ProgramBinaryPersistenceDeleteShaderCase : public ProgramBinaryPersistenceCase
1583 {
1584 public:
ProgramBinaryPersistenceDeleteShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1585     ProgramBinaryPersistenceDeleteShaderCase(Context &context, const char *name, const char *desc,
1586                                              glu::ShaderType shaderType)
1587         : ProgramBinaryPersistenceCase(context, name, desc, shaderType)
1588     {
1589     }
1590 
~ProgramBinaryPersistenceDeleteShaderCase(void)1591     virtual ~ProgramBinaryPersistenceDeleteShaderCase(void)
1592     {
1593     }
1594 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)1595     void executeForProgram(glu::Program &program, ShaderAllocator &shaders)
1596     {
1597         TestLog &log            = m_testCtx.getLog();
1598         glu::Shader &caseShader = shaders.get(m_shaderType);
1599 
1600         log << TestLog::Message << "Deleting " + std::string(getShaderTypeName(m_shaderType)) + " shader"
1601             << TestLog::EndMessage;
1602         program.detachShader(caseShader.getShader());
1603         shaders.deleteShader(m_shaderType);
1604     }
1605 };
1606 
1607 class ProgramBinaryPersistenceReplaceShaderCase : public ProgramBinaryPersistenceCase
1608 {
1609 public:
ProgramBinaryPersistenceReplaceShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1610     ProgramBinaryPersistenceReplaceShaderCase(Context &context, const char *name, const char *desc,
1611                                               glu::ShaderType shaderType)
1612         : ProgramBinaryPersistenceCase(context, name, desc, shaderType)
1613     {
1614     }
1615 
~ProgramBinaryPersistenceReplaceShaderCase(void)1616     virtual ~ProgramBinaryPersistenceReplaceShaderCase(void)
1617     {
1618     }
1619 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)1620     void executeForProgram(glu::Program &program, ShaderAllocator &shaders)
1621     {
1622         TestLog &log            = m_testCtx.getLog();
1623         glu::Shader &caseShader = shaders.get(m_shaderType);
1624 
1625         log << TestLog::Message << "Deleting and replacing " + std::string(getShaderTypeName(m_shaderType)) + " shader"
1626             << TestLog::EndMessage;
1627         program.detachShader(caseShader.getShader());
1628         shaders.deleteShader(m_shaderType);
1629         program.attachShader(shaders.createShader(m_shaderType).getShader());
1630     }
1631 };
1632 
1633 class ProgramBinaryPersistenceRecompileShaderCase : public ProgramBinaryPersistenceCase
1634 {
1635 public:
ProgramBinaryPersistenceRecompileShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1636     ProgramBinaryPersistenceRecompileShaderCase(Context &context, const char *name, const char *desc,
1637                                                 glu::ShaderType shaderType)
1638         : ProgramBinaryPersistenceCase(context, name, desc, shaderType)
1639     {
1640     }
1641 
~ProgramBinaryPersistenceRecompileShaderCase(void)1642     virtual ~ProgramBinaryPersistenceRecompileShaderCase(void)
1643     {
1644     }
1645 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)1646     void executeForProgram(glu::Program &program, ShaderAllocator &shaders)
1647     {
1648         TestLog &log            = m_testCtx.getLog();
1649         glu::Shader &caseShader = shaders.get(m_shaderType);
1650 
1651         log << TestLog::Message << "Recompiling " + std::string(getShaderTypeName(m_shaderType)) + " shader"
1652             << TestLog::EndMessage;
1653         caseShader.compile();
1654         DE_UNREF(program);
1655     }
1656 };
1657 
1658 class ProgramBinaryPersistenceReplaceSourceCase : public ProgramBinaryPersistenceCase
1659 {
1660 public:
ProgramBinaryPersistenceReplaceSourceCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1661     ProgramBinaryPersistenceReplaceSourceCase(Context &context, const char *name, const char *desc,
1662                                               glu::ShaderType shaderType)
1663         : ProgramBinaryPersistenceCase(context, name, desc, shaderType)
1664     {
1665     }
1666 
~ProgramBinaryPersistenceReplaceSourceCase(void)1667     virtual ~ProgramBinaryPersistenceReplaceSourceCase(void)
1668     {
1669     }
1670 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)1671     void executeForProgram(glu::Program &program, ShaderAllocator &shaders)
1672     {
1673         TestLog &log            = m_testCtx.getLog();
1674         glu::Shader &caseShader = shaders.get(m_shaderType);
1675 
1676         log << TestLog::Message
1677             << "Replacing " + std::string(getShaderTypeName(m_shaderType)) + " shader source and recompiling"
1678             << TestLog::EndMessage;
1679         shaders.setSource(m_shaderType);
1680         caseShader.compile();
1681         DE_UNREF(program);
1682     }
1683 };
1684 
1685 // Test group
1686 
ShaderApiTests(Context & context)1687 ShaderApiTests::ShaderApiTests(Context &context) : TestCaseGroup(context, "shader_api", "Shader API Cases")
1688 {
1689 }
1690 
~ShaderApiTests(void)1691 ShaderApiTests::~ShaderApiTests(void)
1692 {
1693 }
1694 
init(void)1695 void ShaderApiTests::init(void)
1696 {
1697     // create and delete shaders
1698     {
1699         TestCaseGroup *createDeleteGroup = new TestCaseGroup(m_context, "create_delete", "glCreateShader() tests");
1700         addChild(createDeleteGroup);
1701 
1702         createDeleteGroup->addChild(new CreateShaderCase(m_context, "create_vertex_shader",
1703                                                          "Create vertex shader object", glu::SHADERTYPE_VERTEX));
1704         createDeleteGroup->addChild(new CreateShaderCase(m_context, "create_fragment_shader",
1705                                                          "Create fragment shader object", glu::SHADERTYPE_FRAGMENT));
1706 
1707         createDeleteGroup->addChild(
1708             new DeleteShaderCase(m_context, "delete_vertex_fragment", "Delete vertex shader and fragment shader"));
1709     }
1710 
1711     // compile and link
1712     {
1713         TestCaseGroup *compileLinkGroup = new TestCaseGroup(m_context, "compile_link", "Compile and link tests");
1714         addChild(compileLinkGroup);
1715 
1716         compileLinkGroup->addChild(
1717             new CompileShaderCase(m_context, "compile_vertex_shader", "Compile vertex shader", glu::SHADERTYPE_VERTEX));
1718         compileLinkGroup->addChild(new CompileShaderCase(m_context, "compile_fragment_shader",
1719                                                          "Compile fragment shader", glu::SHADERTYPE_FRAGMENT));
1720 
1721         compileLinkGroup->addChild(
1722             new LinkVertexFragmentCase(m_context, "link_vertex_fragment", "Link vertex and fragment shaders"));
1723     }
1724 
1725     // shader source
1726     {
1727         TestCaseGroup *shaderSourceGroup = new TestCaseGroup(m_context, "shader_source", "glShaderSource() tests");
1728         addChild(shaderSourceGroup);
1729 
1730         for (int shaderTypeInt = 0; shaderTypeInt < 2; shaderTypeInt++)
1731         {
1732             const glu::ShaderType shaderType = (shaderTypeInt == 1) ? glu::SHADERTYPE_FRAGMENT : glu::SHADERTYPE_VERTEX;
1733             const std::string shaderTypeName = getShaderTypeName(shaderType);
1734 
1735             const std::string caseName = std::string("replace_source_") + shaderTypeName;
1736             const std::string caseDesc = std::string("Replace source code of ") + shaderTypeName + " shader.";
1737 
1738             shaderSourceGroup->addChild(
1739                 new ShaderSourceReplaceCase(m_context, caseName.c_str(), caseDesc.c_str(), shaderType));
1740         }
1741 
1742         for (int stringLengthsInt = 0; stringLengthsInt < 3; stringLengthsInt++)
1743             for (int caseNdx = 1; caseNdx <= 3; caseNdx++)
1744                 for (int shaderTypeInt = 0; shaderTypeInt < 2; shaderTypeInt++)
1745                 {
1746                     const int numSlices = 1 << caseNdx;
1747                     const glu::ShaderType shaderType =
1748                         (shaderTypeInt == 1) ? glu::SHADERTYPE_FRAGMENT : glu::SHADERTYPE_VERTEX;
1749 
1750                     const bool explicitLengths = (stringLengthsInt != 0);
1751                     const bool randomNullTerm  = (stringLengthsInt == 2);
1752 
1753                     const uint32_t flags = (explicitLengths ? CASE_EXPLICIT_SOURCE_LENGTHS : 0) |
1754                                            (randomNullTerm ? CASE_RANDOM_NULL_TERMINATED : 0);
1755 
1756                     const std::string caseName =
1757                         "split_source_" + de::toString(numSlices) +
1758                         (randomNullTerm ? "_random_negative_length" :
1759                                           (explicitLengths ? "_specify_lengths" : "_null_terminated")) +
1760                         ((shaderType == glu::SHADERTYPE_FRAGMENT) ? "_fragment" : "_vertex");
1761 
1762                     const std::string caseDesc =
1763                         std::string((shaderType == glu::SHADERTYPE_FRAGMENT) ? "Fragment" : "Vertex") +
1764                         " shader source split into " + de::toString(numSlices) + " pieces" +
1765                         (explicitLengths ? ", using explicitly specified string lengths" : "") +
1766                         (randomNullTerm ? " with random negative length values" : "");
1767 
1768                     shaderSourceGroup->addChild(new ShaderSourceSplitCase(m_context, caseName.c_str(), caseDesc.c_str(),
1769                                                                           shaderType, numSlices, flags));
1770                 }
1771     }
1772 
1773     // link status and infolog
1774     {
1775         TestCaseGroup *linkStatusGroup =
1776             new TestCaseGroup(m_context, "program_state", "Program state persistence tests");
1777         addChild(linkStatusGroup);
1778 
1779         addProgramStateCase<ProgramStateDetachShaderCase>(linkStatusGroup, m_context, "detach_shader", "detach shader");
1780         addProgramStateCase<ProgramStateReattachShaderCase>(linkStatusGroup, m_context, "reattach_shader",
1781                                                             "reattach shader");
1782         addProgramStateCase<ProgramStateDeleteShaderCase>(linkStatusGroup, m_context, "delete_shader", "delete shader");
1783         addProgramStateCase<ProgramStateReplaceShaderCase>(linkStatusGroup, m_context, "replace_shader",
1784                                                            "replace shader object");
1785         addProgramStateCase<ProgramStateRecompileShaderCase>(linkStatusGroup, m_context, "recompile_shader",
1786                                                              "recompile shader");
1787         addProgramStateCase<ProgramStateReplaceSourceCase>(linkStatusGroup, m_context, "replace_source",
1788                                                            "replace shader source");
1789     }
1790 
1791     // program binary
1792     {
1793         TestCaseGroup *programBinaryGroup = new TestCaseGroup(m_context, "program_binary", "Program binary API tests");
1794         addChild(programBinaryGroup);
1795 
1796         {
1797             TestCaseGroup *simpleCaseGroup = new TestCaseGroup(m_context, "simple", "Simple API tests");
1798             programBinaryGroup->addChild(simpleCaseGroup);
1799 
1800             simpleCaseGroup->addChild(new ProgramBinarySimpleCase(m_context, "get_program_binary_vertex_fragment",
1801                                                                   "Get vertex and fragment shader program binary"));
1802             simpleCaseGroup->addChild(
1803                 new ProgramBinaryUniformResetCase(m_context, "uniform_reset_on_binary_load",
1804                                                   "Verify uniform reset on successful load of program binary"));
1805         }
1806 
1807         {
1808             TestCaseGroup *binaryPersistenceGroup =
1809                 new TestCaseGroup(m_context, "binary_persistence", "Program binary persistence tests");
1810             programBinaryGroup->addChild(binaryPersistenceGroup);
1811 
1812             addProgramBinaryPersistenceCase<ProgramBinaryPersistenceDetachShaderCase>(binaryPersistenceGroup, m_context,
1813                                                                                       "detach_shader", "detach shader");
1814             addProgramBinaryPersistenceCase<ProgramBinaryPersistenceReattachShaderCase>(
1815                 binaryPersistenceGroup, m_context, "reattach_shader", "reattach shader");
1816             addProgramBinaryPersistenceCase<ProgramBinaryPersistenceDeleteShaderCase>(binaryPersistenceGroup, m_context,
1817                                                                                       "delete_shader", "delete shader");
1818             addProgramBinaryPersistenceCase<ProgramBinaryPersistenceReplaceShaderCase>(
1819                 binaryPersistenceGroup, m_context, "replace_shader", "replace shader object");
1820             addProgramBinaryPersistenceCase<ProgramBinaryPersistenceRecompileShaderCase>(
1821                 binaryPersistenceGroup, m_context, "recompile_shader", "recompile shader");
1822             addProgramBinaryPersistenceCase<ProgramBinaryPersistenceReplaceSourceCase>(
1823                 binaryPersistenceGroup, m_context, "replace_source", "replace shader source");
1824         }
1825     }
1826 }
1827 
1828 } // namespace Functional
1829 } // namespace gles3
1830 } // namespace deqp
1831