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