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 63 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 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 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 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 171 bool SsboArgs::getMemberReorder (void) const 172 { 173 return m_memberReorder; 174 } 175 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 182 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 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 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 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 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 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 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