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