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 =
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
setShaderSources(glu::Shader & shader,const ShaderSources & sources)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
sliceSourceString(const std::string & in,ShaderSources & out,const int numSlices,const size_t paddingLength=0)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
queryShaderInfo(glu::RenderContext & renderCtx,deUint32 shader,glu::ShaderInfo & info)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
drawWithProgram(glu::RenderContext & renderCtx,deUint32 program)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:
~SourceGenerator(void)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:
ConstantShaderGenerator(de::Random & rnd)228 ConstantShaderGenerator (de::Random& rnd) : m_rnd(rnd) {}
~ConstantShaderGenerator(void)229 ~ConstantShaderGenerator (void) {}
230
finished(const glu::ShaderType shaderType) const231 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
next(const glu::ShaderType shaderType)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
get(const glu::ShaderType shaderType)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
ShaderAllocator(glu::RenderContext & context,SourceGenerator & generator)285 ShaderAllocator::ShaderAllocator (glu::RenderContext& context, SourceGenerator& generator)
286 : m_context (context)
287 , m_srcGen (generator)
288 {
289 }
290
~ShaderAllocator(void)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
hasShader(const glu::ShaderType shaderType)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
createShader(const glu::ShaderType shaderType)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
deleteShader(const glu::ShaderType shaderType)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
setSource(const glu::ShaderType shaderType)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
logShader(TestLog & log,glu::RenderContext & renderCtx,glu::Shader & shader)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
logProgram(TestLog & log,glu::RenderContext & renderCtx,glu::Program & program,ShaderAllocator & shaders)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
logVertexFragmentProgram(TestLog & log,glu::RenderContext & renderCtx,glu::Program & program,glu::Shader & vertShader,glu::Shader & fragShader)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:
CreateShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)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
test(void)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:
CompileShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)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
checkCompileStatus(const GLuint shaderObject)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
test(void)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:
SimpleProgramCase(Context & context,const char * name,const char * desc)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
~SimpleProgramCase(void)453 virtual ~SimpleProgramCase (void)
454 {
455 }
456
compileShaders(void)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
linkProgram(void)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
cleanup(void)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:
DeleteShaderCase(Context & context,const char * name,const char * desc)513 DeleteShaderCase (Context& context, const char* name, const char* desc)
514 : SimpleProgramCase (context, name, desc)
515 {
516 }
517
checkDeleteStatus(GLuint shader)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
deleteShaders(void)527 void deleteShaders (void)
528 {
529 glDeleteShader(m_vertShader);
530 glDeleteShader(m_fragShader);
531 GLU_CHECK();
532 }
533
test(void)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:
LinkVertexFragmentCase(Context & context,const char * name,const char * desc)555 LinkVertexFragmentCase (Context& context, const char* name, const char* desc)
556 : SimpleProgramCase (context, name, desc)
557 {
558 }
559
checkLinkStatus(const GLuint programObject)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
test(void)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:
ShaderSourceReplaceCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)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
generateFirstSource(void)590 std::string generateFirstSource (void)
591 {
592 return getSimpleShaderSource(m_shaderType);
593 }
594
generateSecondSource(void)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
getSourceLength(glu::Shader & shader)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
readSource(glu::Shader & shader)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
verifyShaderSourceReplaced(glu::Shader & shader,const std::string & firstSource,const std::string & secondSource)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
test(void)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:
ShaderSourceSplitCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType,const int numSlices,const deUint32 flags=0)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
~ShaderSourceSplitCase(void)698 virtual ~ShaderSourceSplitCase (void)
699 {
700 }
701
generateFullSource(void)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
insertRandomNullTermStrings(ShaderSources & sources)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
generateSources(ShaderSources & sources)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
buildProgram(glu::Shader & shader)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
test(void)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);
~ProgramStateCase(void)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
ProgramStateCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)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
buildProgram(glu::Program & program,ShaderAllocator & shaders)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
verify(glu::Program & program,const glu::ProgramInfo & reference)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
test(void)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>
addProgramStateCase(TestCaseGroup * group,Context & context,const std::string & name,const std::string & desc)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:
ProgramStateDetachShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)940 ProgramStateDetachShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
941 : ProgramStateCase (context, name, desc, shaderType)
942 {
943 }
944
~ProgramStateDetachShaderCase(void)945 virtual ~ProgramStateDetachShaderCase (void)
946 {
947 }
948
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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:
ProgramStateReattachShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)962 ProgramStateReattachShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
963 : ProgramStateCase (context, name, desc, shaderType)
964 {
965 }
966
~ProgramStateReattachShaderCase(void)967 virtual ~ProgramStateReattachShaderCase (void)
968 {
969 }
970
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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:
ProgramStateDeleteShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)985 ProgramStateDeleteShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
986 : ProgramStateCase (context, name, desc, shaderType)
987 {
988 }
989
~ProgramStateDeleteShaderCase(void)990 virtual ~ProgramStateDeleteShaderCase (void)
991 {
992 }
993
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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:
ProgramStateReplaceShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1008 ProgramStateReplaceShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
1009 : ProgramStateCase (context, name, desc, shaderType)
1010 {
1011 }
1012
~ProgramStateReplaceShaderCase(void)1013 virtual ~ProgramStateReplaceShaderCase (void)
1014 {
1015 }
1016
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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:
ProgramStateRecompileShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1032 ProgramStateRecompileShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
1033 : ProgramStateCase (context, name, desc, shaderType)
1034 {
1035 }
1036
~ProgramStateRecompileShaderCase(void)1037 virtual ~ProgramStateRecompileShaderCase (void)
1038 {
1039 }
1040
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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:
ProgramStateReplaceSourceCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1055 ProgramStateReplaceSourceCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
1056 : ProgramStateCase (context, name, desc, shaderType)
1057 {
1058 }
1059
~ProgramStateReplaceSourceCase(void)1060 virtual ~ProgramStateReplaceSourceCase (void)
1061 {
1062 }
1063
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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
programBinariesEqual(const ProgramBinary & first,const ProgramBinary & second)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
ProgramBinaryCase(Context & context,const char * name,const char * desc)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
~ProgramBinaryCase(void)1128 ProgramBinaryCase::~ProgramBinaryCase (void)
1129 {
1130 }
1131
getBinaryFormats(std::vector<GLenum> & out)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
isFormatSupported(const glw::GLenum format) const1147 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
getProgramBinary(ProgramBinary & out,GLuint program)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
loadProgramBinary(ProgramBinary & binary,GLuint program)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
verifyProgramBinary(ProgramBinary & binary)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
init(void)1191 void ProgramBinaryCase::init (void)
1192 {
1193 getBinaryFormats(m_formats);
1194 }
1195
iterate(void)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:
ProgramBinarySimpleCase(Context & context,const char * name,const char * desc)1222 ProgramBinarySimpleCase (Context& context, const char* name, const char* desc)
1223 : ProgramBinaryCase(context, name, desc)
1224 {
1225 }
1226
~ProgramBinarySimpleCase(void)1227 virtual ~ProgramBinarySimpleCase (void)
1228 {
1229 }
1230
test(void)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:
ProgramBinaryUniformResetCase(Context & context,const char * name,const char * desc)1255 ProgramBinaryUniformResetCase (Context& context, const char* name, const char* desc)
1256 : ProgramBinaryCase (context, name, desc)
1257 , m_rnd (deStringHash(name) ^ 0xf2b48c6a)
1258 {
1259 }
1260
~ProgramBinaryUniformResetCase(void)1261 virtual ~ProgramBinaryUniformResetCase (void)
1262 {
1263 }
1264
getShaderSource(const glu::ShaderType shaderType) const1265 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
setUniformsRandom(glu::ShaderProgram & program)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
verifyUniformInt(glu::ShaderProgram & program,const std::string & name)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
verifyUniformFloat(glu::ShaderProgram & program,const std::string & name)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
verifyUniformsReset(glu::ShaderProgram & program)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
test(void)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);
~ProgramBinaryPersistenceCase(void)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
ProgramBinaryPersistenceCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)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
buildProgram(glu::Program & program,ShaderAllocator & shaders)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
verify(glu::Program & program,const ProgramBinary & binary)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
test(void)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>
addProgramBinaryPersistenceCase(TestCaseGroup * group,Context & context,const std::string & name,const std::string & desc)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:
ProgramBinaryPersistenceDetachShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1505 ProgramBinaryPersistenceDetachShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
1506 : ProgramBinaryPersistenceCase (context, name, desc, shaderType)
1507 {
1508 }
1509
~ProgramBinaryPersistenceDetachShaderCase(void)1510 virtual ~ProgramBinaryPersistenceDetachShaderCase (void)
1511 {
1512 }
1513
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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:
ProgramBinaryPersistenceReattachShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1527 ProgramBinaryPersistenceReattachShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
1528 : ProgramBinaryPersistenceCase (context, name, desc, shaderType)
1529 {
1530 }
1531
~ProgramBinaryPersistenceReattachShaderCase(void)1532 virtual ~ProgramBinaryPersistenceReattachShaderCase (void)
1533 {
1534 }
1535
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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:
ProgramBinaryPersistenceDeleteShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1550 ProgramBinaryPersistenceDeleteShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
1551 : ProgramBinaryPersistenceCase (context, name, desc, shaderType)
1552 {
1553 }
1554
~ProgramBinaryPersistenceDeleteShaderCase(void)1555 virtual ~ProgramBinaryPersistenceDeleteShaderCase (void)
1556 {
1557 }
1558
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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:
ProgramBinaryPersistenceReplaceShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1573 ProgramBinaryPersistenceReplaceShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
1574 : ProgramBinaryPersistenceCase (context, name, desc, shaderType)
1575 {
1576 }
1577
~ProgramBinaryPersistenceReplaceShaderCase(void)1578 virtual ~ProgramBinaryPersistenceReplaceShaderCase (void)
1579 {
1580 }
1581
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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:
ProgramBinaryPersistenceRecompileShaderCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1597 ProgramBinaryPersistenceRecompileShaderCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
1598 : ProgramBinaryPersistenceCase (context, name, desc, shaderType)
1599 {
1600 }
1601
~ProgramBinaryPersistenceRecompileShaderCase(void)1602 virtual ~ProgramBinaryPersistenceRecompileShaderCase (void)
1603 {
1604 }
1605
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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:
ProgramBinaryPersistenceReplaceSourceCase(Context & context,const char * name,const char * desc,glu::ShaderType shaderType)1620 ProgramBinaryPersistenceReplaceSourceCase (Context& context, const char* name, const char* desc, glu::ShaderType shaderType)
1621 : ProgramBinaryPersistenceCase (context, name, desc, shaderType)
1622 {
1623 }
1624
~ProgramBinaryPersistenceReplaceSourceCase(void)1625 virtual ~ProgramBinaryPersistenceReplaceSourceCase (void)
1626 {
1627 }
1628
executeForProgram(glu::Program & program,ShaderAllocator & shaders)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
ShaderApiTests(Context & context)1643 ShaderApiTests::ShaderApiTests (Context& context)
1644 : TestCaseGroup(context, "shader_api", "Shader API Cases")
1645 {
1646 }
1647
~ShaderApiTests(void)1648 ShaderApiTests::~ShaderApiTests (void)
1649 {
1650 }
1651
init(void)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
1764