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