xref: /aosp_15_r20/external/deqp/modules/gles2/functional/es2fShaderApiTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 2.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 "es2fShaderApiTests.hpp"
25 #include "es2fApiCase.hpp"
26 #include "tcuTestLog.hpp"
27 
28 #include "gluRenderContext.hpp"
29 #include "gluShaderProgram.hpp"
30 #include "gluContextInfo.hpp"
31 #include "glwFunctions.hpp"
32 #include "glwDefs.hpp"
33 #include "glwEnums.hpp"
34 
35 #include "deString.h"
36 
37 #include "deRandom.hpp"
38 #include "deStringUtil.hpp"
39 
40 #include <string>
41 #include <vector>
42 #include <map>
43 
44 using namespace glw; // GL types
45 
46 namespace deqp
47 {
48 namespace gles2
49 {
50 namespace Functional
51 {
52 
53 using tcu::TestLog;
54 
55 namespace
56 {
57 
58 enum ShaderSourceCaseFlags
59 {
60     CASE_EXPLICIT_SOURCE_LENGTHS = 1,
61     CASE_RANDOM_NULL_TERMINATED  = 2
62 };
63 
64 struct ShaderSources
65 {
66     std::vector<std::string> strings;
67     std::vector<int> lengths;
68 };
69 
70 // Simple shaders
71 
getSimpleShaderSource(const glu::ShaderType shaderType)72 const char *getSimpleShaderSource(const glu::ShaderType shaderType)
73 {
74     const char *simpleVertexShaderSource   = "void main (void) { gl_Position = vec4(0.0); }\n";
75     const char *simpleFragmentShaderSource = "void main (void) { gl_FragColor = vec4(0.0); }\n";
76 
77     switch (shaderType)
78     {
79     case glu::SHADERTYPE_VERTEX:
80         return simpleVertexShaderSource;
81     case glu::SHADERTYPE_FRAGMENT:
82         return simpleFragmentShaderSource;
83     default:
84         DE_ASSERT(false);
85     }
86 
87     return 0;
88 }
89 
setShaderSources(glu::Shader & shader,const ShaderSources & sources)90 void setShaderSources(glu::Shader &shader, const ShaderSources &sources)
91 {
92     std::vector<const char *> cStrings(sources.strings.size(), 0);
93 
94     for (size_t ndx = 0; ndx < sources.strings.size(); ndx++)
95         cStrings[ndx] = sources.strings[ndx].c_str();
96 
97     if (sources.lengths.size() > 0)
98         shader.setSources((int)cStrings.size(), &cStrings[0], &sources.lengths[0]);
99     else
100         shader.setSources((int)cStrings.size(), &cStrings[0], 0);
101 }
102 
sliceSourceString(const std::string & in,ShaderSources & out,const int numSlices,const size_t paddingLength=0)103 void sliceSourceString(const std::string &in, ShaderSources &out, const int numSlices, const size_t paddingLength = 0)
104 {
105     DE_ASSERT(numSlices > 0);
106 
107     const size_t sliceSize          = in.length() / numSlices;
108     const size_t sliceSizeRemainder = in.length() - (sliceSize * numSlices);
109     const std::string padding(paddingLength, 'E');
110 
111     for (int i = 0; i < numSlices; i++)
112     {
113         out.strings.push_back(in.substr(i * sliceSize, sliceSize) + padding);
114 
115         if (paddingLength > 0)
116             out.lengths.push_back((int)sliceSize);
117     }
118 
119     if (sliceSizeRemainder > 0)
120     {
121         const std::string lastString = in.substr(numSlices * sliceSize);
122         const int lastStringLength   = (int)lastString.length();
123 
124         out.strings.push_back(lastString + padding);
125 
126         if (paddingLength > 0)
127             out.lengths.push_back(lastStringLength);
128     }
129 }
130 
queryShaderInfo(glu::RenderContext & renderCtx,uint32_t shader,glu::ShaderInfo & info)131 void queryShaderInfo(glu::RenderContext &renderCtx, uint32_t shader, glu::ShaderInfo &info)
132 {
133     const glw::Functions &gl = renderCtx.getFunctions();
134 
135     info.compileOk     = false;
136     info.compileTimeUs = 0;
137     info.infoLog.clear();
138 
139     // Query source, status & log.
140     {
141         int compileStatus = 0;
142         int sourceLen     = 0;
143         int infoLogLen    = 0;
144         int unusedLen;
145 
146         gl.getShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
147         gl.getShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &sourceLen);
148         gl.getShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLen);
149         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv()");
150 
151         info.compileOk = compileStatus != GL_FALSE;
152 
153         if (sourceLen > 0)
154         {
155             std::vector<char> source(sourceLen);
156             gl.getShaderSource(shader, (int)source.size(), &unusedLen, &source[0]);
157             info.source = std::string(&source[0], sourceLen);
158         }
159 
160         if (infoLogLen > 0)
161         {
162             std::vector<char> infoLog(infoLogLen);
163             gl.getShaderInfoLog(shader, (int)infoLog.size(), &unusedLen, &infoLog[0]);
164             info.infoLog = std::string(&infoLog[0], infoLogLen);
165         }
166     }
167 }
168 
169 // Shader source generator
170 
171 class SourceGenerator
172 {
173 public:
~SourceGenerator(void)174     virtual ~SourceGenerator(void)
175     {
176     }
177 
178     virtual std::string next(const glu::ShaderType shaderType)    = 0;
179     virtual bool finished(const glu::ShaderType shaderType) const = 0;
180 };
181 
182 class ConstantShaderGenerator : public SourceGenerator
183 {
184 public:
ConstantShaderGenerator(de::Random & rnd)185     ConstantShaderGenerator(de::Random &rnd) : m_rnd(rnd)
186     {
187     }
~ConstantShaderGenerator(void)188     ~ConstantShaderGenerator(void)
189     {
190     }
191 
finished(const glu::ShaderType shaderType) const192     bool finished(const glu::ShaderType shaderType) const
193     {
194         DE_UNREF(shaderType);
195         return false;
196     }
197 
198     std::string next(const glu::ShaderType shaderType);
199 
200 private:
201     de::Random m_rnd;
202 };
203 
next(const glu::ShaderType shaderType)204 std::string ConstantShaderGenerator::next(const glu::ShaderType shaderType)
205 {
206     DE_ASSERT(shaderType == glu::SHADERTYPE_VERTEX || shaderType == glu::SHADERTYPE_FRAGMENT);
207 
208     const float value             = m_rnd.getFloat(0.0f, 1.0f);
209     const std::string valueString = de::toString(value);
210     const std::string outputName  = (shaderType == glu::SHADERTYPE_VERTEX) ? "gl_Position" : "gl_FragColor";
211 
212     std::string source = "#version 100\n"
213                          "void main (void) { " +
214                          outputName + " = vec4(" + valueString + "); }\n";
215 
216     return source;
217 }
218 
219 // Shader allocation utility
220 
221 class ShaderAllocator
222 {
223 public:
224     ShaderAllocator(glu::RenderContext &context, SourceGenerator &generator);
225     ~ShaderAllocator(void);
226 
227     bool hasShader(const glu::ShaderType shaderType);
228 
229     void setSource(const glu::ShaderType shaderType);
230 
231     glu::Shader &createShader(const glu::ShaderType shaderType);
232     void deleteShader(const glu::ShaderType shaderType);
233 
get(const glu::ShaderType shaderType)234     glu::Shader &get(const glu::ShaderType shaderType)
235     {
236         DE_ASSERT(hasShader(shaderType));
237         return *m_shaders[shaderType];
238     }
239 
240 private:
241     const glu::RenderContext &m_context;
242     SourceGenerator &m_srcGen;
243     std::map<glu::ShaderType, glu::Shader *> m_shaders;
244 };
245 
ShaderAllocator(glu::RenderContext & context,SourceGenerator & generator)246 ShaderAllocator::ShaderAllocator(glu::RenderContext &context, SourceGenerator &generator)
247     : m_context(context)
248     , m_srcGen(generator)
249 {
250 }
251 
~ShaderAllocator(void)252 ShaderAllocator::~ShaderAllocator(void)
253 {
254     for (std::map<glu::ShaderType, glu::Shader *>::iterator shaderIter = m_shaders.begin();
255          shaderIter != m_shaders.end(); shaderIter++)
256         delete shaderIter->second;
257     m_shaders.clear();
258 }
259 
hasShader(const glu::ShaderType shaderType)260 bool ShaderAllocator::hasShader(const glu::ShaderType shaderType)
261 {
262     if (m_shaders.find(shaderType) != m_shaders.end())
263         return true;
264     else
265         return false;
266 }
267 
createShader(const glu::ShaderType shaderType)268 glu::Shader &ShaderAllocator::createShader(const glu::ShaderType shaderType)
269 {
270     DE_ASSERT(!this->hasShader(shaderType));
271 
272     glu::Shader *const shader = new glu::Shader(m_context, shaderType);
273 
274     m_shaders[shaderType] = shader;
275     this->setSource(shaderType);
276 
277     return *shader;
278 }
279 
deleteShader(const glu::ShaderType shaderType)280 void ShaderAllocator::deleteShader(const glu::ShaderType shaderType)
281 {
282     DE_ASSERT(this->hasShader(shaderType));
283 
284     delete m_shaders[shaderType];
285     m_shaders.erase(shaderType);
286 }
287 
setSource(const glu::ShaderType shaderType)288 void ShaderAllocator::setSource(const glu::ShaderType shaderType)
289 {
290     DE_ASSERT(this->hasShader(shaderType));
291     DE_ASSERT(!m_srcGen.finished(shaderType));
292 
293     const std::string source  = m_srcGen.next(shaderType);
294     const char *const cSource = source.c_str();
295 
296     m_shaders[shaderType]->setSources(1, &cSource, 0);
297 }
298 
299 // Logging utilities
300 
logShader(TestLog & log,glu::RenderContext & renderCtx,glu::Shader & shader)301 void logShader(TestLog &log, glu::RenderContext &renderCtx, glu::Shader &shader)
302 {
303     glu::ShaderInfo info;
304     queryShaderInfo(renderCtx, shader.getShader(), info);
305 
306     log << TestLog::Shader(getLogShaderType(shader.getType()), info.source, info.compileOk, info.infoLog);
307 }
308 
logProgram(TestLog & log,glu::RenderContext & renderCtx,glu::Program & program,ShaderAllocator & shaders)309 void logProgram(TestLog &log, glu::RenderContext &renderCtx, glu::Program &program, ShaderAllocator &shaders)
310 {
311     log << TestLog::ShaderProgram(program.getLinkStatus(), program.getInfoLog());
312 
313     for (int shaderTypeInt = 0; shaderTypeInt < glu::SHADERTYPE_LAST; shaderTypeInt++)
314     {
315         const glu::ShaderType shaderType = (glu::ShaderType)shaderTypeInt;
316 
317         if (shaders.hasShader(shaderType))
318             logShader(log, renderCtx, shaders.get(shaderType));
319     }
320 
321     log << TestLog::EndShaderProgram;
322 }
323 
logVertexFragmentProgram(TestLog & log,glu::RenderContext & renderCtx,glu::Program & program,glu::Shader & vertShader,glu::Shader & fragShader)324 void logVertexFragmentProgram(TestLog &log, glu::RenderContext &renderCtx, glu::Program &program,
325                               glu::Shader &vertShader, glu::Shader &fragShader)
326 {
327     DE_ASSERT(vertShader.getType() == glu::SHADERTYPE_VERTEX && fragShader.getType() == glu::SHADERTYPE_FRAGMENT);
328 
329     log << TestLog::ShaderProgram(program.getLinkStatus(), program.getInfoLog());
330 
331     logShader(log, renderCtx, vertShader);
332     logShader(log, renderCtx, fragShader);
333 
334     log << TestLog::EndShaderProgram;
335 }
336 
337 } // namespace
338 
339 // Simple glCreateShader() case
340 
341 class CreateShaderCase : public ApiCase
342 {
343 public:
CreateShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)344     CreateShaderCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType)
345         : ApiCase(context, name, desc)
346         , m_shaderType(shaderType)
347     {
348     }
349 
test(void)350     void test(void)
351     {
352         const GLuint shaderObject = glCreateShader(glu::getGLShaderType(m_shaderType));
353 
354         TCU_CHECK(shaderObject != 0);
355 
356         glDeleteShader(shaderObject);
357     }
358 
359 private:
360     const glu::ShaderType m_shaderType;
361 };
362 
363 // Simple glCompileShader() case
364 
365 class CompileShaderCase : public ApiCase
366 {
367 public:
CompileShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)368     CompileShaderCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType)
369         : ApiCase(context, name, desc)
370         , m_shaderType(shaderType)
371     {
372     }
373 
checkCompileStatus(const GLuint shaderObject)374     bool checkCompileStatus(const GLuint shaderObject)
375     {
376         GLint compileStatus = -1;
377         glGetShaderiv(shaderObject, GL_COMPILE_STATUS, &compileStatus);
378         GLU_CHECK();
379 
380         return (compileStatus == GL_TRUE);
381     }
382 
test(void)383     void test(void)
384     {
385         const char *shaderSource  = getSimpleShaderSource(m_shaderType);
386         const GLuint shaderObject = glCreateShader(glu::getGLShaderType(m_shaderType));
387 
388         TCU_CHECK(shaderObject != 0);
389 
390         glShaderSource(shaderObject, 1, &shaderSource, 0);
391         glCompileShader(shaderObject);
392 
393         TCU_CHECK(checkCompileStatus(shaderObject));
394 
395         glDeleteShader(shaderObject);
396     }
397 
398 private:
399     const glu::ShaderType m_shaderType;
400 };
401 
402 // Base class for simple program API tests
403 
404 class SimpleProgramCase : public ApiCase
405 {
406 public:
SimpleProgramCase(Context & context,const char * name,const char * desc)407     SimpleProgramCase(Context &context, const char *name, const char *desc)
408         : ApiCase(context, name, desc)
409         , m_vertShader(0)
410         , m_fragShader(0)
411         , m_program(0)
412     {
413     }
414 
~SimpleProgramCase(void)415     virtual ~SimpleProgramCase(void)
416     {
417     }
418 
compileShaders(void)419     virtual void compileShaders(void)
420     {
421         const char *vertSource = getSimpleShaderSource(glu::SHADERTYPE_VERTEX);
422         const char *fragSource = getSimpleShaderSource(glu::SHADERTYPE_FRAGMENT);
423 
424         const GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
425         const GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
426 
427         TCU_CHECK(vertShader != 0);
428         TCU_CHECK(fragShader != 0);
429 
430         glShaderSource(vertShader, 1, &vertSource, 0);
431         glCompileShader(vertShader);
432 
433         glShaderSource(fragShader, 1, &fragSource, 0);
434         glCompileShader(fragShader);
435 
436         GLU_CHECK();
437 
438         m_vertShader = vertShader;
439         m_fragShader = fragShader;
440     }
441 
linkProgram(void)442     void linkProgram(void)
443     {
444         const GLuint program = glCreateProgram();
445 
446         TCU_CHECK(program != 0);
447 
448         glAttachShader(program, m_vertShader);
449         glAttachShader(program, m_fragShader);
450         GLU_CHECK();
451 
452         glLinkProgram(program);
453 
454         m_program = program;
455     }
456 
cleanup(void)457     void cleanup(void)
458     {
459         glDeleteShader(m_vertShader);
460         glDeleteShader(m_fragShader);
461         glDeleteProgram(m_program);
462     }
463 
464 protected:
465     GLuint m_vertShader;
466     GLuint m_fragShader;
467     GLuint m_program;
468 };
469 
470 // glDeleteShader() case
471 
472 class DeleteShaderCase : public SimpleProgramCase
473 {
474 public:
DeleteShaderCase(Context & context,const char * name,const char * desc)475     DeleteShaderCase(Context &context, const char *name, const char *desc) : SimpleProgramCase(context, name, desc)
476     {
477     }
478 
checkDeleteStatus(GLuint shader)479     bool checkDeleteStatus(GLuint shader)
480     {
481         GLint deleteStatus = -1;
482         glGetShaderiv(shader, GL_DELETE_STATUS, &deleteStatus);
483         GLU_CHECK();
484 
485         return (deleteStatus == GL_TRUE);
486     }
487 
deleteShaders(void)488     void deleteShaders(void)
489     {
490         glDeleteShader(m_vertShader);
491         glDeleteShader(m_fragShader);
492         GLU_CHECK();
493     }
494 
test(void)495     void test(void)
496     {
497         compileShaders();
498         linkProgram();
499         GLU_CHECK();
500 
501         deleteShaders();
502 
503         TCU_CHECK(checkDeleteStatus(m_vertShader) && checkDeleteStatus(m_fragShader));
504 
505         glDeleteProgram(m_program);
506 
507         TCU_CHECK(!(glIsShader(m_vertShader) || glIsShader(m_fragShader)));
508     }
509 };
510 
511 // Simple glLinkProgram() case
512 
513 class LinkVertexFragmentCase : public SimpleProgramCase
514 {
515 public:
LinkVertexFragmentCase(Context & context,const char * name,const char * desc)516     LinkVertexFragmentCase(Context &context, const char *name, const char *desc)
517         : SimpleProgramCase(context, name, desc)
518     {
519     }
520 
checkLinkStatus(const GLuint programObject)521     bool checkLinkStatus(const GLuint programObject)
522     {
523         GLint linkStatus = -1;
524         glGetProgramiv(programObject, GL_LINK_STATUS, &linkStatus);
525         GLU_CHECK();
526 
527         return (linkStatus == GL_TRUE);
528     }
529 
test(void)530     void test(void)
531     {
532         compileShaders();
533         linkProgram();
534 
535         GLU_CHECK_MSG("Linking failed.");
536         TCU_CHECK_MSG(checkLinkStatus(m_program), "Fail, expected LINK_STATUS to be TRUE.");
537 
538         cleanup();
539     }
540 };
541 
542 class ShaderSourceReplaceCase : public ApiCase
543 {
544 public:
ShaderSourceReplaceCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)545     ShaderSourceReplaceCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType)
546         : ApiCase(context, name, desc)
547         , m_shaderType(shaderType)
548     {
549     }
550 
generateFirstSource(void)551     std::string generateFirstSource(void)
552     {
553         return getSimpleShaderSource(m_shaderType);
554     }
555 
generateSecondSource(void)556     std::string generateSecondSource(void)
557     {
558         std::string str;
559 
560         str = "#version 100\n";
561         str += "precision highp float;\n\n";
562 
563         str += "void main()\n";
564         str += "{\n";
565         str += "    float variable = 1.0;\n";
566 
567         if (m_shaderType == glu::SHADERTYPE_VERTEX)
568             str += "    gl_Position = vec4(variable);\n";
569         else if (m_shaderType == glu::SHADERTYPE_FRAGMENT)
570             str += "    gl_FragColor = vec4(variable);\n";
571 
572         str += "}\n";
573 
574         return str;
575     }
576 
getSourceLength(glu::Shader & shader)577     GLint getSourceLength(glu::Shader &shader)
578     {
579         GLint sourceLength = 0;
580         glGetShaderiv(shader.getShader(), GL_SHADER_SOURCE_LENGTH, &sourceLength);
581         GLU_CHECK();
582 
583         return sourceLength;
584     }
585 
readSource(glu::Shader & shader)586     std::string readSource(glu::Shader &shader)
587     {
588         const GLint sourceLength = getSourceLength(shader);
589         std::vector<char> sourceBuffer(sourceLength + 1);
590 
591         glGetShaderSource(shader.getShader(), (GLsizei)sourceBuffer.size(), 0, &sourceBuffer[0]);
592 
593         return std::string(&sourceBuffer[0]);
594     }
595 
verifyShaderSourceReplaced(glu::Shader & shader,const std::string & firstSource,const std::string & secondSource)596     void verifyShaderSourceReplaced(glu::Shader &shader, const std::string &firstSource,
597                                     const std::string &secondSource)
598     {
599         TestLog &log             = m_testCtx.getLog();
600         const std::string result = readSource(shader);
601 
602         if (result == firstSource)
603         {
604             log << TestLog::Message << "Fail, source was not replaced." << TestLog::EndMessage;
605             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader source nor replaced");
606         }
607         else if (result != secondSource)
608         {
609             log << TestLog::Message << "Fail, invalid shader source." << TestLog::EndMessage;
610             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid source");
611         }
612     }
613 
test(void)614     void test(void)
615     {
616         TestLog &log = m_testCtx.getLog();
617 
618         glu::Shader shader(m_context.getRenderContext(), m_shaderType);
619 
620         const std::string firstSourceStr  = generateFirstSource();
621         const std::string secondSourceStr = generateSecondSource();
622 
623         const char *firstSource  = firstSourceStr.c_str();
624         const char *secondSource = secondSourceStr.c_str();
625 
626         log << TestLog::Message << "Setting shader source." << TestLog::EndMessage;
627 
628         shader.setSources(1, &firstSource, 0);
629         GLU_CHECK();
630 
631         log << TestLog::Message << "Replacing shader source." << TestLog::EndMessage;
632 
633         shader.setSources(1, &secondSource, 0);
634         GLU_CHECK();
635 
636         verifyShaderSourceReplaced(shader, firstSourceStr, secondSourceStr);
637     }
638 
639 private:
640     glu::ShaderType m_shaderType;
641 };
642 
643 // glShaderSource() split source case
644 
645 class ShaderSourceSplitCase : public ApiCase
646 {
647 public:
ShaderSourceSplitCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType,const int numSlices,const uint32_t flags=0)648     ShaderSourceSplitCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType,
649                           const int numSlices, const uint32_t flags = 0)
650         : ApiCase(context, name, desc)
651         , m_rnd(deStringHash(getName()) ^ 0x4fb2337d)
652         , m_shaderType(shaderType)
653         , m_numSlices(numSlices)
654         , m_explicitLengths((flags & CASE_EXPLICIT_SOURCE_LENGTHS) != 0)
655         , m_randomNullTerm((flags & CASE_RANDOM_NULL_TERMINATED) != 0)
656     {
657         DE_ASSERT(m_shaderType == glu::SHADERTYPE_VERTEX || m_shaderType == glu::SHADERTYPE_FRAGMENT);
658     }
659 
~ShaderSourceSplitCase(void)660     virtual ~ShaderSourceSplitCase(void)
661     {
662     }
663 
generateFullSource(void)664     std::string generateFullSource(void)
665     {
666         std::string str;
667 
668         str = "#version 100\n";
669         str += "precision highp float;\n\n";
670 
671         str += "void main()\n";
672         str += "{\n";
673         str += "    float variable = 1.0;\n";
674 
675         if (m_shaderType == glu::SHADERTYPE_VERTEX)
676             str += "    gl_Position = vec4(variable);\n";
677         else if (m_shaderType == glu::SHADERTYPE_FRAGMENT)
678             str += "    gl_FragColor = vec4(variable);\n";
679 
680         str += "}\n";
681 
682         return str;
683     }
684 
insertRandomNullTermStrings(ShaderSources & sources)685     void insertRandomNullTermStrings(ShaderSources &sources)
686     {
687         const int numInserts = de::max(m_numSlices >> 2, 1);
688         std::vector<int> indices(sources.strings.size(), 0);
689 
690         DE_ASSERT(sources.lengths.size() > 0);
691         DE_ASSERT(sources.lengths.size() == sources.strings.size());
692 
693         for (int i = 0; i < (int)sources.strings.size(); i++)
694             indices[i] = i;
695 
696         m_rnd.shuffle(indices.begin(), indices.end());
697 
698         for (int i = 0; i < numInserts; i++)
699         {
700             const int ndx                    = indices[i];
701             const int unpaddedLength         = sources.lengths[ndx];
702             const std::string unpaddedString = sources.strings[ndx].substr(0, unpaddedLength);
703 
704             sources.strings[ndx] = unpaddedString;
705             sources.lengths[ndx] = m_rnd.getInt(-10, -1);
706         }
707     }
708 
generateSources(ShaderSources & sources)709     void generateSources(ShaderSources &sources)
710     {
711         const size_t paddingLength = (m_explicitLengths ? 10 : 0);
712         std::string str            = generateFullSource();
713 
714         sliceSourceString(str, sources, m_numSlices, paddingLength);
715 
716         if (m_randomNullTerm)
717             insertRandomNullTermStrings(sources);
718     }
719 
buildProgram(glu::Shader & shader)720     void buildProgram(glu::Shader &shader)
721     {
722         TestLog &log                  = m_testCtx.getLog();
723         glu::RenderContext &renderCtx = m_context.getRenderContext();
724 
725         const glu::ShaderType supportShaderType =
726             (m_shaderType == glu::SHADERTYPE_FRAGMENT ? glu::SHADERTYPE_VERTEX : glu::SHADERTYPE_FRAGMENT);
727         const char *supportShaderSource = getSimpleShaderSource(supportShaderType);
728         glu::Shader supportShader(renderCtx, supportShaderType);
729 
730         glu::Program program(renderCtx);
731 
732         supportShader.setSources(1, &supportShaderSource, 0);
733         supportShader.compile();
734 
735         program.attachShader(shader.getShader());
736         program.attachShader(supportShader.getShader());
737 
738         program.link();
739 
740         if (m_shaderType == glu::SHADERTYPE_VERTEX)
741             logVertexFragmentProgram(log, renderCtx, program, shader, supportShader);
742         else
743             logVertexFragmentProgram(log, renderCtx, program, supportShader, shader);
744     }
745 
test(void)746     void test(void)
747     {
748         TestLog &log                  = m_testCtx.getLog();
749         glu::RenderContext &renderCtx = m_context.getRenderContext();
750 
751         ShaderSources sources;
752         glu::Shader shader(renderCtx, m_shaderType);
753 
754         generateSources(sources);
755         setShaderSources(shader, sources);
756         shader.compile();
757 
758         buildProgram(shader);
759 
760         if (!shader.getCompileStatus())
761         {
762             log << TestLog::Message << "Compilation failed." << TestLog::EndMessage;
763             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed");
764         }
765     }
766 
767 private:
768     de::Random m_rnd;
769 
770     glu::ShaderType m_shaderType;
771     const int m_numSlices;
772 
773     const bool m_explicitLengths;
774     const bool m_randomNullTerm;
775 };
776 
777 // Base class for program state persistence cases
778 
779 class ProgramStateCase : public ApiCase
780 {
781 public:
782     ProgramStateCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType);
~ProgramStateCase(void)783     virtual ~ProgramStateCase(void)
784     {
785     }
786 
787     void buildProgram(glu::Program &program, ShaderAllocator &shaders);
788     void verify(glu::Program &program, const glu::ProgramInfo &reference);
789 
790     void test(void);
791 
792     virtual void executeForProgram(glu::Program &program, ShaderAllocator &shaders) = 0;
793 
794 protected:
795     de::Random m_rnd;
796     const glu::ShaderType m_shaderType;
797 };
798 
ProgramStateCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)799 ProgramStateCase::ProgramStateCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType)
800     : ApiCase(context, name, desc)
801     , m_rnd(deStringHash(name) ^ 0x713de0ca)
802     , m_shaderType(shaderType)
803 {
804     DE_ASSERT(m_shaderType == glu::SHADERTYPE_VERTEX || m_shaderType == glu::SHADERTYPE_FRAGMENT);
805 }
806 
buildProgram(glu::Program & program,ShaderAllocator & shaders)807 void ProgramStateCase::buildProgram(glu::Program &program, ShaderAllocator &shaders)
808 {
809     TestLog &log = m_testCtx.getLog();
810 
811     glu::Shader &vertShader = shaders.createShader(glu::SHADERTYPE_VERTEX);
812     glu::Shader &fragShader = shaders.createShader(glu::SHADERTYPE_FRAGMENT);
813 
814     vertShader.compile();
815     fragShader.compile();
816 
817     program.attachShader(vertShader.getShader());
818     program.attachShader(fragShader.getShader());
819     program.link();
820 
821     logProgram(log, m_context.getRenderContext(), program, shaders);
822 }
823 
verify(glu::Program & program,const glu::ProgramInfo & reference)824 void ProgramStateCase::verify(glu::Program &program, const glu::ProgramInfo &reference)
825 {
826     TestLog &log                        = m_testCtx.getLog();
827     const glu::ProgramInfo &programInfo = program.getInfo();
828 
829     if (!programInfo.linkOk)
830     {
831         log << TestLog::Message
832             << "Fail, link status may only change as a result of linking or loading a program binary."
833             << TestLog::EndMessage;
834         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Link status changed");
835     }
836 
837     if (programInfo.linkTimeUs != reference.linkTimeUs)
838     {
839         log << TestLog::Message << "Fail, reported link time changed." << TestLog::EndMessage;
840         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Link time changed");
841     }
842 
843     if (programInfo.infoLog != reference.infoLog)
844     {
845         log << TestLog::Message << "Fail, program infolog changed." << TestLog::EndMessage;
846         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Infolog changed");
847     }
848 }
849 
test(void)850 void ProgramStateCase::test(void)
851 {
852     TestLog &log                  = m_testCtx.getLog();
853     glu::RenderContext &renderCtx = m_context.getRenderContext();
854 
855     ConstantShaderGenerator sourceGen(m_rnd);
856 
857     ShaderAllocator shaders(renderCtx, sourceGen);
858     glu::Program program(renderCtx);
859 
860     buildProgram(program, shaders);
861 
862     if (program.getLinkStatus())
863     {
864         glu::ProgramInfo programInfo = program.getInfo();
865 
866         executeForProgram(program, shaders);
867 
868         verify(program, programInfo);
869 
870         logProgram(log, renderCtx, program, shaders);
871     }
872     else
873     {
874         log << TestLog::Message << "Fail, couldn't link program." << TestLog::EndMessage;
875         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Linking failed");
876     }
877 }
878 
879 // Program state case utilities
880 
881 namespace
882 {
883 
884 template <class T>
addProgramStateCase(TestCaseGroup * group,Context & context,const std::string & name,const std::string & desc)885 void addProgramStateCase(TestCaseGroup *group, Context &context, const std::string &name, const std::string &desc)
886 {
887     for (int shaderTypeInt = 0; shaderTypeInt < 2; shaderTypeInt++)
888     {
889         const glu::ShaderType shaderType = (shaderTypeInt == 1) ? glu::SHADERTYPE_FRAGMENT : glu::SHADERTYPE_VERTEX;
890         const std::string shaderTypeName = getShaderTypeName(shaderType);
891 
892         const std::string caseName = name + "_" + shaderTypeName;
893         const std::string caseDesc = "Build program, " + desc + ", for " + shaderTypeName + " shader.";
894 
895         group->addChild(new T(context, caseName.c_str(), caseDesc.c_str(), shaderType));
896     }
897 }
898 
899 } // namespace
900 
901 // Specialized program state cases
902 
903 class ProgramStateDetachShaderCase : public ProgramStateCase
904 {
905 public:
ProgramStateDetachShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)906     ProgramStateDetachShaderCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType)
907         : ProgramStateCase(context, name, desc, shaderType)
908     {
909     }
910 
~ProgramStateDetachShaderCase(void)911     virtual ~ProgramStateDetachShaderCase(void)
912     {
913     }
914 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)915     void executeForProgram(glu::Program &program, ShaderAllocator &shaders)
916     {
917         TestLog &log            = m_testCtx.getLog();
918         glu::Shader &caseShader = shaders.get(m_shaderType);
919 
920         log << TestLog::Message << "Detaching " + std::string(getShaderTypeName(m_shaderType)) + " shader"
921             << TestLog::EndMessage;
922         program.detachShader(caseShader.getShader());
923     }
924 };
925 
926 class ProgramStateReattachShaderCase : public ProgramStateCase
927 {
928 public:
ProgramStateReattachShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)929     ProgramStateReattachShaderCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType)
930         : ProgramStateCase(context, name, desc, shaderType)
931     {
932     }
933 
~ProgramStateReattachShaderCase(void)934     virtual ~ProgramStateReattachShaderCase(void)
935     {
936     }
937 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)938     void executeForProgram(glu::Program &program, ShaderAllocator &shaders)
939     {
940         TestLog &log            = m_testCtx.getLog();
941         glu::Shader &caseShader = shaders.get(m_shaderType);
942 
943         log << TestLog::Message << "Reattaching " + std::string(getShaderTypeName(m_shaderType)) + " shader"
944             << TestLog::EndMessage;
945         program.detachShader(caseShader.getShader());
946         program.attachShader(caseShader.getShader());
947     }
948 };
949 
950 class ProgramStateDeleteShaderCase : public ProgramStateCase
951 {
952 public:
ProgramStateDeleteShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)953     ProgramStateDeleteShaderCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType)
954         : ProgramStateCase(context, name, desc, shaderType)
955     {
956     }
957 
~ProgramStateDeleteShaderCase(void)958     virtual ~ProgramStateDeleteShaderCase(void)
959     {
960     }
961 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)962     void executeForProgram(glu::Program &program, ShaderAllocator &shaders)
963     {
964         TestLog &log            = m_testCtx.getLog();
965         glu::Shader &caseShader = shaders.get(m_shaderType);
966 
967         log << TestLog::Message << "Deleting " + std::string(getShaderTypeName(m_shaderType)) + " shader"
968             << TestLog::EndMessage;
969         program.detachShader(caseShader.getShader());
970         shaders.deleteShader(m_shaderType);
971     }
972 };
973 
974 class ProgramStateReplaceShaderCase : public ProgramStateCase
975 {
976 public:
ProgramStateReplaceShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)977     ProgramStateReplaceShaderCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType)
978         : ProgramStateCase(context, name, desc, shaderType)
979     {
980     }
981 
~ProgramStateReplaceShaderCase(void)982     virtual ~ProgramStateReplaceShaderCase(void)
983     {
984     }
985 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)986     void executeForProgram(glu::Program &program, ShaderAllocator &shaders)
987     {
988         TestLog &log            = m_testCtx.getLog();
989         glu::Shader &caseShader = shaders.get(m_shaderType);
990 
991         log << TestLog::Message << "Deleting and replacing " + std::string(getShaderTypeName(m_shaderType)) + " shader"
992             << TestLog::EndMessage;
993         program.detachShader(caseShader.getShader());
994         shaders.deleteShader(m_shaderType);
995         program.attachShader(shaders.createShader(m_shaderType).getShader());
996     }
997 };
998 
999 class ProgramStateRecompileShaderCase : public ProgramStateCase
1000 {
1001 public:
ProgramStateRecompileShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1002     ProgramStateRecompileShaderCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType)
1003         : ProgramStateCase(context, name, desc, shaderType)
1004     {
1005     }
1006 
~ProgramStateRecompileShaderCase(void)1007     virtual ~ProgramStateRecompileShaderCase(void)
1008     {
1009     }
1010 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)1011     void executeForProgram(glu::Program &program, ShaderAllocator &shaders)
1012     {
1013         TestLog &log            = m_testCtx.getLog();
1014         glu::Shader &caseShader = shaders.get(m_shaderType);
1015 
1016         log << TestLog::Message << "Recompiling " + std::string(getShaderTypeName(m_shaderType)) + " shader"
1017             << TestLog::EndMessage;
1018         caseShader.compile();
1019         DE_UNREF(program);
1020     }
1021 };
1022 
1023 class ProgramStateReplaceSourceCase : public ProgramStateCase
1024 {
1025 public:
ProgramStateReplaceSourceCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1026     ProgramStateReplaceSourceCase(Context &context, const char *name, const char *desc, glu::ShaderType shaderType)
1027         : ProgramStateCase(context, name, desc, shaderType)
1028     {
1029     }
1030 
~ProgramStateReplaceSourceCase(void)1031     virtual ~ProgramStateReplaceSourceCase(void)
1032     {
1033     }
1034 
executeForProgram(glu::Program & program,ShaderAllocator & shaders)1035     void executeForProgram(glu::Program &program, ShaderAllocator &shaders)
1036     {
1037         TestLog &log            = m_testCtx.getLog();
1038         glu::Shader &caseShader = shaders.get(m_shaderType);
1039 
1040         log << TestLog::Message
1041             << "Replacing " + std::string(getShaderTypeName(m_shaderType)) + " shader source and recompiling"
1042             << TestLog::EndMessage;
1043         shaders.setSource(m_shaderType);
1044         caseShader.compile();
1045         DE_UNREF(program);
1046     }
1047 };
1048 
1049 // Test group
1050 
ShaderApiTests(Context & context)1051 ShaderApiTests::ShaderApiTests(Context &context) : TestCaseGroup(context, "shader_api", "Shader API Cases")
1052 {
1053 }
1054 
~ShaderApiTests(void)1055 ShaderApiTests::~ShaderApiTests(void)
1056 {
1057 }
1058 
init(void)1059 void ShaderApiTests::init(void)
1060 {
1061     // create and delete shaders
1062     {
1063         TestCaseGroup *createDeleteGroup = new TestCaseGroup(m_context, "create_delete", "glCreateShader() tests");
1064         addChild(createDeleteGroup);
1065 
1066         createDeleteGroup->addChild(new CreateShaderCase(m_context, "create_vertex_shader",
1067                                                          "Create vertex shader object", glu::SHADERTYPE_VERTEX));
1068         createDeleteGroup->addChild(new CreateShaderCase(m_context, "create_fragment_shader",
1069                                                          "Create fragment shader object", glu::SHADERTYPE_FRAGMENT));
1070 
1071         createDeleteGroup->addChild(
1072             new DeleteShaderCase(m_context, "delete_vertex_fragment", "Delete vertex shader and fragment shader"));
1073     }
1074 
1075     // compile and link
1076     {
1077         TestCaseGroup *compileLinkGroup = new TestCaseGroup(m_context, "compile_link", "Compile and link tests");
1078         addChild(compileLinkGroup);
1079 
1080         compileLinkGroup->addChild(
1081             new CompileShaderCase(m_context, "compile_vertex_shader", "Compile vertex shader", glu::SHADERTYPE_VERTEX));
1082         compileLinkGroup->addChild(new CompileShaderCase(m_context, "compile_fragment_shader",
1083                                                          "Compile fragment shader", glu::SHADERTYPE_FRAGMENT));
1084 
1085         compileLinkGroup->addChild(
1086             new LinkVertexFragmentCase(m_context, "link_vertex_fragment", "Link vertex and fragment shaders"));
1087     }
1088 
1089     // shader source
1090     {
1091         TestCaseGroup *shaderSourceGroup = new TestCaseGroup(m_context, "shader_source", "glShaderSource() tests");
1092         addChild(shaderSourceGroup);
1093 
1094         for (int shaderTypeInt = 0; shaderTypeInt < 2; shaderTypeInt++)
1095         {
1096             const glu::ShaderType shaderType = (shaderTypeInt == 1) ? glu::SHADERTYPE_FRAGMENT : glu::SHADERTYPE_VERTEX;
1097 
1098             const std::string caseName =
1099                 std::string("replace_source") + ((shaderType == glu::SHADERTYPE_FRAGMENT) ? "_fragment" : "_vertex");
1100             const std::string caseDesc = std::string("Replace source code of ") +
1101                                          ((shaderType == glu::SHADERTYPE_FRAGMENT) ? "fragment" : "vertex") +
1102                                          " shader.";
1103 
1104             shaderSourceGroup->addChild(
1105                 new ShaderSourceReplaceCase(m_context, caseName.c_str(), caseDesc.c_str(), shaderType));
1106         }
1107 
1108         for (int stringLengthsInt = 0; stringLengthsInt < 3; stringLengthsInt++)
1109             for (int caseNdx = 1; caseNdx <= 3; caseNdx++)
1110                 for (int shaderTypeInt = 0; shaderTypeInt < 2; shaderTypeInt++)
1111                 {
1112                     const int numSlices = 1 << caseNdx;
1113                     const glu::ShaderType shaderType =
1114                         (shaderTypeInt == 1) ? glu::SHADERTYPE_FRAGMENT : glu::SHADERTYPE_VERTEX;
1115 
1116                     const bool explicitLengths = (stringLengthsInt != 0);
1117                     const bool randomNullTerm  = (stringLengthsInt == 2);
1118 
1119                     const uint32_t flags = (explicitLengths ? CASE_EXPLICIT_SOURCE_LENGTHS : 0) |
1120                                            (randomNullTerm ? CASE_RANDOM_NULL_TERMINATED : 0);
1121 
1122                     const std::string caseName =
1123                         "split_source_" + de::toString(numSlices) +
1124                         (randomNullTerm ? "_random_negative_length" :
1125                                           (explicitLengths ? "_specify_lengths" : "_null_terminated")) +
1126                         ((shaderType == glu::SHADERTYPE_FRAGMENT) ? "_fragment" : "_vertex");
1127 
1128                     const std::string caseDesc =
1129                         std::string((shaderType == glu::SHADERTYPE_FRAGMENT) ? "Fragment" : "Vertex") +
1130                         " shader source split into " + de::toString(numSlices) + " pieces" +
1131                         (explicitLengths ? ", using explicitly specified string lengths" : "") +
1132                         (randomNullTerm ? " with random negative length values" : "");
1133 
1134                     shaderSourceGroup->addChild(new ShaderSourceSplitCase(m_context, caseName.c_str(), caseDesc.c_str(),
1135                                                                           shaderType, numSlices, flags));
1136                 }
1137     }
1138 
1139     // link status and infolog
1140     {
1141         TestCaseGroup *linkStatusGroup =
1142             new TestCaseGroup(m_context, "program_state", "Program state persistence tests");
1143         addChild(linkStatusGroup);
1144 
1145         addProgramStateCase<ProgramStateDetachShaderCase>(linkStatusGroup, m_context, "detach_shader", "detach shader");
1146         addProgramStateCase<ProgramStateReattachShaderCase>(linkStatusGroup, m_context, "reattach_shader",
1147                                                             "reattach shader");
1148         addProgramStateCase<ProgramStateDeleteShaderCase>(linkStatusGroup, m_context, "delete_shader", "delete shader");
1149         addProgramStateCase<ProgramStateReplaceShaderCase>(linkStatusGroup, m_context, "replace_shader",
1150                                                            "replace shader object");
1151         addProgramStateCase<ProgramStateRecompileShaderCase>(linkStatusGroup, m_context, "recompile_shader",
1152                                                              "recompile shader");
1153         addProgramStateCase<ProgramStateReplaceSourceCase>(linkStatusGroup, m_context, "replace_source",
1154                                                            "replace shader source");
1155     }
1156 }
1157 
1158 } // namespace Functional
1159 } // namespace gles2
1160 } // namespace deqp
1161