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 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 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 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 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 180 const std::string& SsboArgs::getContextVersion (void) const 181 { 182 return m_negativeContextVersion; 183 } 184 185 const std::string& SsboArgs::getStdFormat (void) const 186 { 187 return m_stdFormat; 188 } 189 190 const std::string& SsboArgs::getBindingPoint (void) const 191 { 192 return m_bindingPoint; 193 } 194 195 const std::string& SsboArgs::getMatrixOrder (void) const 196 { 197 return m_matrixOrder; 198 } 199 200 const std::string& SsboArgs::getMemberType (void) const 201 { 202 return m_memberType; 203 } 204 205 const std::string& SsboArgs::getMemberName (void) const 206 { 207 return m_memberName; 208 } 209 210 const std::string& SsboArgs::getMemberFixedArrayName (void) const 211 { 212 return m_memberFixedArrayerName; 213 } 214 215 const std::string& SsboArgs::getMemberVariableArray (void) const 216 { 217 return m_memberVariableArray; 218 } 219 220 bool SsboArgs::getMemberReorder (void) const 221 { 222 return m_memberReorder; 223 } 224 225 int SsboArgs::getNumberMembers (void) const 226 { 227 return m_numberMembers; 228 } 229 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 236 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 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 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 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 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 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 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