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