1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2016 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 Negative Shader Storage Buffer Object (SSBO) tests.
22 *//*--------------------------------------------------------------------*/
23 #include "es31fNegativeSSBOBlockTests.hpp"
24 #include "glwDefs.hpp"
25 #include "glwEnums.hpp"
26 #include "tcuStringTemplate.hpp"
27 #include "gluShaderProgram.hpp"
28 #include <map>
29
30 namespace deqp
31 {
32 namespace gles31
33 {
34 namespace Functional
35 {
36 namespace NegativeTestShared
37 {
38 namespace
39 {
40 using tcu::TestLog;
41 using glu::CallLogWrapper;
42 using namespace glw;
43 namespace args
44 {
45 enum ArgMember
46 {
47 ARGMEMBER_FORMAT = 0,
48 ARGMEMBER_BINDING_POINT,
49 ARGMEMBER_MATRIX_ORDER,
50 ARGMEMBER_MEMBER_TYPE,
51 ARGMEMBER_NAME,
52 ARGMEMBER_FIXED_ARRAY,
53 ARGMEMBER_VARIABLE_ARRAY,
54 ARGMEMBER_REORDER
55 };
56
57 // key pair ssbo arg data
58 struct SsboArgData
59 {
60 ArgMember member;
61 std::string data;
62
SsboArgDatadeqp::gles31::Functional::NegativeTestShared::__anon48126c2d0111::args::SsboArgData63 SsboArgData(const ArgMember& member_, const std::string& data_)
64 {
65 member = member_;
66 data = data_;
67 }
68 };
69
70 // class which manages string based argument used to build varying ssbo interface blocks and members
71 class SsboArgs
72 {
73 public:
74 SsboArgs(const std::string version, tcu::TestLog& log);
75
76 void setSingleValue (const SsboArgData argData);
77 bool setAllValues (const std::vector<SsboArgData> argDataList);
78
79 const std::string& getContextVersion (void) const;
80 const std::string& getStdFormat (void) const;
81 const std::string& getBindingPoint (void) const;
82 const std::string& getMatrixOrder (void) const;
83 const std::string& getMemberType (void) const;
84 const std::string& getMemberName (void) const;
85 const std::string& getMemberFixedArrayName (void) const;
86 const std::string& getMemberVariableArray (void) const;
87 bool getMemberReorder (void) const;
88 int getNumberMembers (void) const;
89
90 void resetValues (void);
91
92 std::map<std::string, std::string> populateArgsMap (void) const;
93
94 private:
95 std::string m_negativeContextVersion;
96 std::string m_stdFormat;
97 std::string m_bindingPoint;
98 std::string m_matrixOrder;
99 std::string m_memberType;
100 std::string m_memberName;
101 std::string m_memberFixedArrayerName;
102 std::string m_memberVariableArray;
103 bool m_memberReorder;
104 int m_numberMembers;
105 tcu::TestLog& m_testLog;
106
107 void setDefaultValues (void);
108 };
109
110 //constructor which ensure a proper context is passed into the struct
SsboArgs(const std::string version,tcu::TestLog & log)111 SsboArgs::SsboArgs(const std::string version, tcu::TestLog& log)
112 : m_negativeContextVersion (version)
113 , m_numberMembers (8)
114 , m_testLog (log)
115 {
116 setDefaultValues();
117 }
118
setSingleValue(const SsboArgData argData)119 void SsboArgs::setSingleValue (const SsboArgData argData)
120 {
121 std::string message;
122
123 switch (argData.member)
124 {
125 case ARGMEMBER_FORMAT:
126 m_stdFormat = argData.data;
127 return;
128 case ARGMEMBER_BINDING_POINT:
129 m_bindingPoint = argData.data;
130 return;
131 case ARGMEMBER_MATRIX_ORDER:
132 m_matrixOrder = argData.data;
133 return;
134 case ARGMEMBER_MEMBER_TYPE:
135 m_memberType = argData.data;
136 return;
137 case ARGMEMBER_NAME:
138 m_memberName = argData.data;
139 return;
140 case ARGMEMBER_FIXED_ARRAY:
141 m_memberFixedArrayerName = argData.data;
142 return;
143 case ARGMEMBER_VARIABLE_ARRAY:
144 m_memberVariableArray = argData.data;
145 return;
146 case ARGMEMBER_REORDER:
147 if (argData.data == "true")
148 {
149 m_memberReorder = true;
150 }
151 return;
152 default:
153 message = "auto loop argument data member not recognised.";
154 m_testLog << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
155 }
156 }
157
setAllValues(const std::vector<SsboArgData> argDataList)158 bool SsboArgs::setAllValues (const std::vector<SsboArgData> argDataList)
159 {
160 std::string message;
161
162 if ((argDataList.size() == 0) || (argDataList.size() > (size_t)m_numberMembers))
163 {
164 message = "set of args does not match the number of args struct changeable members.";
165 m_testLog << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
166
167 return false;
168 }
169 else
170 {
171 for (unsigned int idx = 0; idx < argDataList.size(); idx++)
172 {
173 setSingleValue(argDataList[idx]);
174 }
175 }
176
177 return true;
178 }
179
getContextVersion(void) const180 const std::string& SsboArgs::getContextVersion (void) const
181 {
182 return m_negativeContextVersion;
183 }
184
getStdFormat(void) const185 const std::string& SsboArgs::getStdFormat (void) const
186 {
187 return m_stdFormat;
188 }
189
getBindingPoint(void) const190 const std::string& SsboArgs::getBindingPoint (void) const
191 {
192 return m_bindingPoint;
193 }
194
getMatrixOrder(void) const195 const std::string& SsboArgs::getMatrixOrder (void) const
196 {
197 return m_matrixOrder;
198 }
199
getMemberType(void) const200 const std::string& SsboArgs::getMemberType (void) const
201 {
202 return m_memberType;
203 }
204
getMemberName(void) const205 const std::string& SsboArgs::getMemberName (void) const
206 {
207 return m_memberName;
208 }
209
getMemberFixedArrayName(void) const210 const std::string& SsboArgs::getMemberFixedArrayName (void) const
211 {
212 return m_memberFixedArrayerName;
213 }
214
getMemberVariableArray(void) const215 const std::string& SsboArgs::getMemberVariableArray (void) const
216 {
217 return m_memberVariableArray;
218 }
219
getMemberReorder(void) const220 bool SsboArgs::getMemberReorder (void) const
221 {
222 return m_memberReorder;
223 }
224
getNumberMembers(void) const225 int SsboArgs::getNumberMembers (void) const
226 {
227 return m_numberMembers;
228 }
229
resetValues(void)230 void SsboArgs::resetValues (void)
231 {
232 setDefaultValues();
233 }
234
235 //converts SsboArgs member variable into a map object to be used by tcu::StringTemplate
populateArgsMap(void) const236 std::map<std::string, std::string> SsboArgs::populateArgsMap (void) const
237 {
238 std::map<std::string, std::string> argsMap;
239
240 // key placeholders located at specific points in the ssbo block
241 argsMap["NEGATIVE_CONTEXT_VERSION"] = m_negativeContextVersion;
242 argsMap["STD_FORMAT"] = m_stdFormat;
243 argsMap["BINDING_POINT"] = m_bindingPoint;
244 argsMap["MATRIX_ORDER"] = m_matrixOrder;
245 argsMap["MEMBER_TYPE"] = m_memberType;
246 argsMap["MEMBER_NAME"] = m_memberName;
247 argsMap["MEMBER_FIXED_ARRAY"] = m_memberFixedArrayerName;
248 argsMap["MEMBER_VARIABLE_ARRAY"] = m_memberVariableArray;
249
250 return argsMap;
251 }
252
253 // default values i.e. same shader template
setDefaultValues(void)254 void SsboArgs::setDefaultValues (void)
255 {
256 m_stdFormat = "std430";
257 m_bindingPoint = "0";
258 m_matrixOrder = "column_major";
259 m_memberType = "int";
260 m_memberName = "matrix";
261 m_memberFixedArrayerName = "10";
262 m_memberVariableArray = "";
263 m_memberReorder = false;
264 }
265 } // args
266
generateVaryingSSBOShader(const glw::GLenum shaderType,const args::SsboArgs & args,tcu::TestLog & log)267 std::string generateVaryingSSBOShader(const glw::GLenum shaderType, const args::SsboArgs& args, tcu::TestLog& log)
268 {
269 std::map<std::string, std::string> argsMap;
270 std::ostringstream source;
271 std::string sourceString;
272 std::stringstream ssboString;
273 std::string message;
274
275 if (args.getMemberReorder())
276 {
277 ssboString << " mediump vec4 array_1[${MEMBER_FIXED_ARRAY}];\n"
278 << " highp mat4 ${MEMBER_NAME};\n"
279 << " lowp ${MEMBER_TYPE} data;\n"
280 << " mediump float array_2[${MEMBER_VARIABLE_ARRAY}];\n";
281 }
282 else
283 {
284 ssboString << " lowp ${MEMBER_TYPE} data;\n"
285 << " highp mat4 ${MEMBER_NAME};\n"
286 << " mediump vec4 array_1[${MEMBER_FIXED_ARRAY}];\n"
287 << " mediump float array_2[${MEMBER_VARIABLE_ARRAY}];\n";
288 }
289
290 argsMap = args.populateArgsMap();
291
292 switch (shaderType)
293 {
294 case GL_VERTEX_SHADER:
295 {
296 source << "${NEGATIVE_CONTEXT_VERSION}\n"
297 << "layout (location = 0) in highp vec4 position;\n"
298 << "layout (location = 1) in mediump vec4 colour;\n"
299 << "out mediump vec4 vertex_colour;\n"
300 << "layout (${STD_FORMAT}, binding = ${BINDING_POINT}, ${MATRIX_ORDER}) buffer ssbo_block\n"
301 << "{\n";
302
303 source << ssboString.str();
304
305 source << "} ssbo;\n"
306 << "void main()\n"
307 << "{\n"
308 << " mediump vec4 variable;\n"
309 << " gl_Position = ssbo.${MEMBER_NAME} * position;\n"
310 << " for (int idx = 0; idx < ${MEMBER_FIXED_ARRAY}; idx++)\n"
311 << " {\n"
312 << " variable += ssbo.array_1[idx];\n"
313 << " }\n"
314 << " vertex_colour = colour + variable;\n"
315 << "}\n";
316
317 sourceString = source.str();
318 sourceString = tcu::StringTemplate(sourceString).specialize(argsMap);
319
320 return sourceString;
321 }
322
323 case GL_FRAGMENT_SHADER:
324 {
325 source << "${NEGATIVE_CONTEXT_VERSION}\n"
326 << "in mediump vec4 vertex_colour;\n"
327 << "layout (location = 0) out mediump vec4 fragment_colour;\n"
328 << "layout (${STD_FORMAT}, binding = ${BINDING_POINT}, ${MATRIX_ORDER}) buffer ssbo_block\n"
329 << "{\n";
330
331 source << ssboString.str();
332
333 source << "} ssbo;\n"
334 << "void main()\n"
335 << "{\n"
336 << " mediump vec4 variable;\n"
337 << " variable * ssbo.${MEMBER_NAME};\n"
338 << " for (int idx = 0; idx < ${MEMBER_FIXED_ARRAY}; idx++)\n"
339 << " {\n"
340 << " variable += ssbo.array_1[idx];\n"
341 << " }\n"
342 << " fragment_colour = vertex_colour + variable;\n"
343 << "}\n";
344
345 sourceString = source.str();
346 sourceString = tcu::StringTemplate(sourceString).specialize(argsMap);
347
348 return sourceString;
349 }
350
351 case GL_GEOMETRY_SHADER:
352 {
353 // TODO:
354 return sourceString;
355 }
356
357 case GL_TESS_CONTROL_SHADER:
358 {
359 // TODO:
360 return sourceString;
361 }
362
363 case GL_TESS_EVALUATION_SHADER:
364 {
365 // TODO:
366 return sourceString;
367 }
368
369 case GL_COMPUTE_SHADER:
370 {
371 // TODO:
372 return sourceString;
373 }
374
375 default:
376 {
377 message = "shader type not recognised.";
378 log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
379 }
380 }
381
382 return std::string();
383 }
384
logProgramInfo(NegativeTestContext & ctx,GLint program)385 void logProgramInfo(NegativeTestContext& ctx, GLint program)
386 {
387 GLint maxLength = 0;
388 std::string message;
389 tcu::TestLog& log = ctx.getLog();
390
391 ctx.glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
392
393 message = "Program log:";
394 log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
395
396 if (maxLength == 0)
397 {
398 message = "No available info log.";
399 log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
400 return;
401 }
402
403 std::vector<GLchar> infoLog(maxLength);
404 ctx.glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);
405
406 std::string programLogMessage(&infoLog[0], maxLength);
407 log << tcu::TestLog::Message << programLogMessage << tcu::TestLog::EndMessage;
408 }
409
ssbo_block_matching(NegativeTestContext & ctx)410 void ssbo_block_matching(NegativeTestContext& ctx)
411 {
412 const bool isES32 = contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
413 const glu::GLSLVersion version = isES32 ? glu::GLSL_VERSION_320_ES : glu::GLSL_VERSION_310_ES;
414 tcu::TestLog& log = ctx.getLog();
415 std::string message;
416 std::string versionString(glu::getGLSLVersionDeclaration(version));
417 args::SsboArgs ssboArgs(versionString, log);
418 GLint shaderVertexGL;
419 std::string shaderVertexString;
420 const char* shaderVertexCharPtr;
421
422 // List of arguments used to create varying ssbo objects in the fragment shader
423 const args::SsboArgData argDataArrayFrag[] = { args::SsboArgData(args::ARGMEMBER_FORMAT, "std140"),
424 args::SsboArgData(args::ARGMEMBER_BINDING_POINT, "10"),
425 args::SsboArgData(args::ARGMEMBER_MATRIX_ORDER, "row_major"),
426 args::SsboArgData(args::ARGMEMBER_MEMBER_TYPE, "vec2"),
427 args::SsboArgData(args::ARGMEMBER_NAME, "name_changed"),
428 args::SsboArgData(args::ARGMEMBER_FIXED_ARRAY, "20"),
429 args::SsboArgData(args::ARGMEMBER_VARIABLE_ARRAY, "5"),
430 args::SsboArgData(args::ARGMEMBER_REORDER, "true") };
431 std::vector<args::SsboArgData> argDataVectorFrag(argDataArrayFrag, argDataArrayFrag + sizeof(argDataArrayFrag) / sizeof(argDataArrayFrag[0]));
432
433 // create default vertex shader
434 shaderVertexString = generateVaryingSSBOShader(GL_VERTEX_SHADER, ssboArgs, log);
435 shaderVertexCharPtr = shaderVertexString.c_str();
436 shaderVertexGL = ctx.glCreateShader(GL_VERTEX_SHADER);
437
438 // log
439 message = shaderVertexString;
440 log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
441
442 // compile
443 ctx.glShaderSource(shaderVertexGL, 1, &shaderVertexCharPtr, DE_NULL);
444 ctx.glCompileShader(shaderVertexGL);
445
446 for (std::size_t idx = 0; idx < argDataVectorFrag.size(); ++idx)
447 {
448 GLint linkStatus = -1;
449 GLint program;
450 GLint shaderFragmentGL;
451 std::string shaderFragmentString;
452 const char* shaderFragmentCharPtr;
453
454 ctx.beginSection("Multiple shaders created using SSBO's sharing the same name but not matching layouts");
455
456 program = ctx.glCreateProgram();
457
458 // reset args to default and make a single change
459 ssboArgs.resetValues();
460 ssboArgs.setSingleValue(argDataVectorFrag[idx]);
461
462 // create fragment shader
463 shaderFragmentString = generateVaryingSSBOShader(GL_FRAGMENT_SHADER, ssboArgs, log);
464 shaderFragmentCharPtr = shaderFragmentString.c_str();
465 shaderFragmentGL = ctx.glCreateShader(GL_FRAGMENT_SHADER);
466
467 // log
468 message = shaderFragmentString;
469 log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
470
471 // compile
472 ctx.glShaderSource(shaderFragmentGL, 1, &shaderFragmentCharPtr, DE_NULL);
473 ctx.glCompileShader(shaderFragmentGL);
474
475 // attach shaders to program and attempt to link
476 ctx.glAttachShader(program, shaderVertexGL);
477 ctx.glAttachShader(program, shaderFragmentGL);
478 ctx.glLinkProgram(program);
479 ctx.glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
480
481 logProgramInfo(ctx, program);
482
483 if (linkStatus == GL_TRUE)
484 {
485 ctx.fail("Program should not have linked");
486 }
487
488 // clean up resources
489 ctx.glDeleteShader(shaderFragmentGL);
490 ctx.glDeleteProgram(program);
491
492 ctx.endSection();
493 }
494
495 // clean up default resources
496 ctx.glDeleteShader(shaderVertexGL);
497 }
498
ssbo_block_shared_qualifier(NegativeTestContext & ctx)499 void ssbo_block_shared_qualifier(NegativeTestContext& ctx)
500 {
501 const bool isES32 = contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
502 const glu::GLSLVersion version = isES32 ? glu::GLSL_VERSION_320_ES : glu::GLSL_VERSION_310_ES;
503 tcu::TestLog& log = ctx.getLog();
504 std::string message;
505 std::string versionString(glu::getGLSLVersionDeclaration(version));
506 args::SsboArgs ssboArgs(versionString, log);
507 bool result;
508 GLint shaderVertexGL;
509 std::string shaderVertexString;
510 const char* shaderVertexCharPtr;
511
512 // default args used in vertex shader ssbo
513 const args::SsboArgData argDataArrayVert[] = { args::SsboArgData(args::ARGMEMBER_FORMAT, "shared"),
514 args::SsboArgData(args::ARGMEMBER_BINDING_POINT, "0"),
515 args::SsboArgData(args::ARGMEMBER_MATRIX_ORDER, "column_major"),
516 args::SsboArgData(args::ARGMEMBER_FIXED_ARRAY, "10"),
517 args::SsboArgData(args::ARGMEMBER_VARIABLE_ARRAY, "10"),
518 args::SsboArgData(args::ARGMEMBER_REORDER, "false") };
519 std::vector<args::SsboArgData> argDataVectorVert(argDataArrayVert, argDataArrayVert + sizeof(argDataArrayVert) / sizeof(argDataArrayVert[0]));
520
521 // args changed in fragment shader ssbo
522 const args::SsboArgData argDataArrayFrag[] = { args::SsboArgData(args::ARGMEMBER_MATRIX_ORDER, "row_major"),
523 args::SsboArgData(args::ARGMEMBER_VARIABLE_ARRAY, ""),
524 args::SsboArgData(args::ARGMEMBER_FIXED_ARRAY, "20") };
525 std::vector<args::SsboArgData> argDataVectorFrag(argDataArrayFrag, argDataArrayFrag + sizeof(argDataArrayFrag) / sizeof(argDataArrayFrag[0]));
526
527 // set default vertex ssbo args
528 result = ssboArgs.setAllValues(argDataVectorVert);
529
530 if (result == false)
531 {
532 message = "Invalid use of args.setAllValues()";
533 log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
534 return;
535 }
536
537 // create default vertex shader
538 shaderVertexString = generateVaryingSSBOShader(GL_VERTEX_SHADER, ssboArgs, log);
539 shaderVertexCharPtr = shaderVertexString.c_str();
540 shaderVertexGL = ctx.glCreateShader(GL_VERTEX_SHADER);
541
542 // log
543 message = shaderVertexString;
544 log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
545
546 // compile
547 ctx.glShaderSource(shaderVertexGL, 1, &shaderVertexCharPtr, DE_NULL);
548 ctx.glCompileShader(shaderVertexGL);
549
550 for (std::size_t idx = 0; idx < argDataVectorFrag.size(); idx++)
551 {
552 GLint linkStatus = -1;
553 GLint program;
554 GLint shaderFragmentGL;
555 std::string shaderFragmentString;
556 const char* shaderFragmentCharPtr;
557
558 ctx.beginSection("Multiple shaders created using SSBO's sharing the same name but not matching layouts");
559
560 program = ctx.glCreateProgram();
561
562 // reset args to default and make a single change
563 ssboArgs.setAllValues(argDataVectorVert);
564 ssboArgs.setSingleValue(argDataVectorFrag[idx]);
565
566 // create fragment shader
567 shaderFragmentString = generateVaryingSSBOShader(GL_FRAGMENT_SHADER, ssboArgs, log);
568 shaderFragmentCharPtr = shaderFragmentString.c_str();
569 shaderFragmentGL = ctx.glCreateShader(GL_FRAGMENT_SHADER);
570
571 // log
572 message = shaderFragmentString;
573 log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
574
575 // compile
576 ctx.glShaderSource(shaderFragmentGL, 1, &shaderFragmentCharPtr, DE_NULL);
577 ctx.glCompileShader(shaderFragmentGL);
578
579 // attach shaders to the program and attempt to link
580 ctx.glAttachShader(program, shaderVertexGL);
581 ctx.glAttachShader(program, shaderFragmentGL);
582 ctx.glLinkProgram(program);
583 ctx.glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
584
585 logProgramInfo(ctx, program);
586
587 if (linkStatus == GL_TRUE)
588 {
589 ctx.fail("Program should not have linked");
590 }
591
592 // clean up resources
593 ctx.glDeleteShader(shaderFragmentGL);
594 ctx.glDeleteProgram(program);
595
596 ctx.endSection();
597 }
598
599 // clean up default resources
600 ctx.glDeleteShader(shaderVertexGL);
601 }
602 } // anonymous
603
getNegativeSSBOBlockTestFunctions(void)604 std::vector<FunctionContainer> getNegativeSSBOBlockTestFunctions (void)
605 {
606 const FunctionContainer funcs[] =
607 {
608 { ssbo_block_matching, "ssbo_block_interface_matching_tests", "Invalid Shader Linkage" },
609 { ssbo_block_shared_qualifier, "ssbo_using_shared_qualifier_tests", "Invalid Shader Linkage" },
610 };
611
612 return std::vector<FunctionContainer>(DE_ARRAY_BEGIN(funcs), DE_ARRAY_END(funcs));
613 }
614 } // NegativeTestShared
615 } //Functional
616 } //gles31
617 } //deqp
618