xref: /aosp_15_r20/external/deqp/modules/gles31/functional/es31fNegativeSSBOBlockTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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 glu::CallLogWrapper;
41 using tcu::TestLog;
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::__anonf37e7ea30111::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 } // namespace 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(
378         argDataArrayFrag, argDataArrayFrag + sizeof(argDataArrayFrag) / sizeof(argDataArrayFrag[0]));
379 
380     // create default vertex shader
381     shaderVertexString  = generateVaryingSSBOShader(GL_VERTEX_SHADER, ssboArgs, log);
382     shaderVertexCharPtr = shaderVertexString.c_str();
383     shaderVertexGL      = ctx.glCreateShader(GL_VERTEX_SHADER);
384 
385     // log
386     message = shaderVertexString;
387     log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
388 
389     // compile
390     ctx.glShaderSource(shaderVertexGL, 1, &shaderVertexCharPtr, DE_NULL);
391     ctx.glCompileShader(shaderVertexGL);
392 
393     for (std::size_t idx = 0; idx < argDataVectorFrag.size(); ++idx)
394     {
395         GLint linkStatus = -1;
396         GLint program;
397         GLint shaderFragmentGL;
398         std::string shaderFragmentString;
399         const char *shaderFragmentCharPtr;
400 
401         ctx.beginSection("Multiple shaders created using SSBO's sharing the same name but not matching layouts");
402 
403         program = ctx.glCreateProgram();
404 
405         // reset args to default and make a single change
406         ssboArgs.resetValues();
407         ssboArgs.setSingleValue(argDataVectorFrag[idx]);
408 
409         // create fragment shader
410         shaderFragmentString  = generateVaryingSSBOShader(GL_FRAGMENT_SHADER, ssboArgs, log);
411         shaderFragmentCharPtr = shaderFragmentString.c_str();
412         shaderFragmentGL      = ctx.glCreateShader(GL_FRAGMENT_SHADER);
413 
414         // log
415         message = shaderFragmentString;
416         log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
417 
418         // compile
419         ctx.glShaderSource(shaderFragmentGL, 1, &shaderFragmentCharPtr, DE_NULL);
420         ctx.glCompileShader(shaderFragmentGL);
421 
422         // attach shaders to program and attempt to link
423         ctx.glAttachShader(program, shaderVertexGL);
424         ctx.glAttachShader(program, shaderFragmentGL);
425         ctx.glLinkProgram(program);
426         ctx.glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
427 
428         logProgramInfo(ctx, program);
429 
430         if (linkStatus == GL_TRUE)
431         {
432             ctx.fail("Program should not have linked");
433         }
434 
435         // clean up resources
436         ctx.glDeleteShader(shaderFragmentGL);
437         ctx.glDeleteProgram(program);
438 
439         ctx.endSection();
440     }
441 
442     // clean up default resources
443     ctx.glDeleteShader(shaderVertexGL);
444 }
445 
ssbo_block_shared_qualifier(NegativeTestContext & ctx)446 void ssbo_block_shared_qualifier(NegativeTestContext &ctx)
447 {
448     const bool isES32              = contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
449     const glu::GLSLVersion version = isES32 ? glu::GLSL_VERSION_320_ES : glu::GLSL_VERSION_310_ES;
450     tcu::TestLog &log              = ctx.getLog();
451     std::string message;
452     std::string versionString(glu::getGLSLVersionDeclaration(version));
453     args::SsboArgs ssboArgs(versionString, log);
454     bool result;
455     GLint shaderVertexGL;
456     std::string shaderVertexString;
457     const char *shaderVertexCharPtr;
458 
459     // default args used in vertex shader ssbo
460     const args::SsboArgData argDataArrayVert[] = {args::SsboArgData(args::ARGMEMBER_FORMAT, "shared"),
461                                                   args::SsboArgData(args::ARGMEMBER_BINDING_POINT, "0"),
462                                                   args::SsboArgData(args::ARGMEMBER_MATRIX_ORDER, "column_major"),
463                                                   args::SsboArgData(args::ARGMEMBER_FIXED_ARRAY, "10"),
464                                                   args::SsboArgData(args::ARGMEMBER_VARIABLE_ARRAY, "10"),
465                                                   args::SsboArgData(args::ARGMEMBER_REORDER, "false")};
466     std::vector<args::SsboArgData> argDataVectorVert(
467         argDataArrayVert, argDataArrayVert + sizeof(argDataArrayVert) / sizeof(argDataArrayVert[0]));
468 
469     // args changed in fragment shader ssbo
470     const args::SsboArgData argDataArrayFrag[] = {args::SsboArgData(args::ARGMEMBER_MATRIX_ORDER, "row_major"),
471                                                   args::SsboArgData(args::ARGMEMBER_VARIABLE_ARRAY, ""),
472                                                   args::SsboArgData(args::ARGMEMBER_FIXED_ARRAY, "20")};
473     std::vector<args::SsboArgData> argDataVectorFrag(
474         argDataArrayFrag, argDataArrayFrag + sizeof(argDataArrayFrag) / sizeof(argDataArrayFrag[0]));
475 
476     // set default vertex ssbo args
477     result = ssboArgs.setAllValues(argDataVectorVert);
478 
479     if (result == false)
480     {
481         message = "Invalid use of args.setAllValues()";
482         log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
483         return;
484     }
485 
486     // create default vertex shader
487     shaderVertexString  = generateVaryingSSBOShader(GL_VERTEX_SHADER, ssboArgs, log);
488     shaderVertexCharPtr = shaderVertexString.c_str();
489     shaderVertexGL      = ctx.glCreateShader(GL_VERTEX_SHADER);
490 
491     // log
492     message = shaderVertexString;
493     log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
494 
495     // compile
496     ctx.glShaderSource(shaderVertexGL, 1, &shaderVertexCharPtr, DE_NULL);
497     ctx.glCompileShader(shaderVertexGL);
498 
499     for (std::size_t idx = 0; idx < argDataVectorFrag.size(); idx++)
500     {
501         GLint linkStatus = -1;
502         GLint program;
503         GLint shaderFragmentGL;
504         std::string shaderFragmentString;
505         const char *shaderFragmentCharPtr;
506 
507         ctx.beginSection("Multiple shaders created using SSBO's sharing the same name but not matching layouts");
508 
509         program = ctx.glCreateProgram();
510 
511         // reset args to default and make a single change
512         ssboArgs.setAllValues(argDataVectorVert);
513         ssboArgs.setSingleValue(argDataVectorFrag[idx]);
514 
515         // create fragment shader
516         shaderFragmentString  = generateVaryingSSBOShader(GL_FRAGMENT_SHADER, ssboArgs, log);
517         shaderFragmentCharPtr = shaderFragmentString.c_str();
518         shaderFragmentGL      = ctx.glCreateShader(GL_FRAGMENT_SHADER);
519 
520         // log
521         message = shaderFragmentString;
522         log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
523 
524         // compile
525         ctx.glShaderSource(shaderFragmentGL, 1, &shaderFragmentCharPtr, DE_NULL);
526         ctx.glCompileShader(shaderFragmentGL);
527 
528         // attach shaders to the program and attempt to link
529         ctx.glAttachShader(program, shaderVertexGL);
530         ctx.glAttachShader(program, shaderFragmentGL);
531         ctx.glLinkProgram(program);
532         ctx.glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
533 
534         logProgramInfo(ctx, program);
535 
536         if (linkStatus == GL_TRUE)
537         {
538             ctx.fail("Program should not have linked");
539         }
540 
541         // clean up resources
542         ctx.glDeleteShader(shaderFragmentGL);
543         ctx.glDeleteProgram(program);
544 
545         ctx.endSection();
546     }
547 
548     // clean up default resources
549     ctx.glDeleteShader(shaderVertexGL);
550 }
551 } // namespace
552 
getNegativeSSBOBlockTestFunctions(void)553 std::vector<FunctionContainer> getNegativeSSBOBlockTestFunctions(void)
554 {
555     const FunctionContainer funcs[] = {
556         {ssbo_block_matching, "ssbo_block_interface_matching_tests", "Invalid Shader Linkage"},
557         {ssbo_block_shared_qualifier, "ssbo_using_shared_qualifier_tests", "Invalid Shader Linkage"},
558     };
559 
560     return std::vector<FunctionContainer>(DE_ARRAY_BEGIN(funcs), DE_ARRAY_END(funcs));
561 }
562 } // namespace NegativeTestShared
563 } // namespace Functional
564 } // namespace gles31
565 } // namespace deqp
566