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