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