1 /* 2 * Copyright (c) 2015-2016 The Khronos Group Inc. 3 * Copyright (c) 2015-2016 Valve Corporation 4 * Copyright (c) 2015-2016 LunarG, Inc. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * Author: Chia-I Wu <olvaffe (at) gmail.com> 19 * Author: Courtney Goeltzenleuchter <courtney (at) LunarG.com> 20 * Author: Tony Barbour <tony (at) LunarG.com> 21 */ 22 23 #include "vktestframework.h" 24 #include "vkrenderframework.h" 25 // TODO FIXME remove this once glslang doesn't define this 26 #undef BadValue 27 #include "SPIRV/GlslangToSpv.h" 28 #include "SPIRV/SPVRemapper.h" 29 #include <limits.h> 30 #include <math.h> 31 32 #if defined(PATH_MAX) && !defined(MAX_PATH) 33 #define MAX_PATH PATH_MAX 34 #endif 35 36 #ifdef _WIN32 37 #define ERR_EXIT(err_msg, err_class) \ 38 do { \ 39 MessageBox(NULL, err_msg, err_class, MB_OK); \ 40 exit(1); \ 41 } while (0) 42 #else // _WIN32 43 44 #define ERR_EXIT(err_msg, err_class) \ 45 do { \ 46 printf(err_msg); \ 47 fflush(stdout); \ 48 exit(1); \ 49 } while (0) 50 #endif // _WIN32 51 52 #define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \ 53 { \ 54 m_fp##entrypoint = (PFN_vk##entrypoint)vkGetInstanceProcAddr(inst, "vk" #entrypoint); \ 55 if (m_fp##entrypoint == NULL) { \ 56 ERR_EXIT("vkGetInstanceProcAddr failed to find vk" #entrypoint, "vkGetInstanceProcAddr Failure"); \ 57 } \ 58 } 59 60 #define GET_DEVICE_PROC_ADDR(dev, entrypoint) \ 61 { \ 62 m_fp##entrypoint = (PFN_vk##entrypoint)vkGetDeviceProcAddr(dev, "vk" #entrypoint); \ 63 if (m_fp##entrypoint == NULL) { \ 64 ERR_EXIT("vkGetDeviceProcAddr failed to find vk" #entrypoint, "vkGetDeviceProcAddr Failure"); \ 65 } \ 66 } 67 68 // Command-line options 69 enum TOptions { 70 EOptionNone = 0x000, 71 EOptionIntermediate = 0x001, 72 EOptionSuppressInfolog = 0x002, 73 EOptionMemoryLeakMode = 0x004, 74 EOptionRelaxedErrors = 0x008, 75 EOptionGiveWarnings = 0x010, 76 EOptionLinkProgram = 0x020, 77 EOptionMultiThreaded = 0x040, 78 EOptionDumpConfig = 0x080, 79 EOptionDumpReflection = 0x100, 80 EOptionSuppressWarnings = 0x200, 81 EOptionDumpVersions = 0x400, 82 EOptionSpv = 0x800, 83 EOptionDefaultDesktop = 0x1000, 84 }; 85 86 struct SwapchainBuffers { 87 VkImage image; 88 VkCommandBuffer cmd; 89 VkImageView view; 90 }; 91 92 #ifndef _WIN32 93 94 #include <errno.h> 95 96 int fopen_s(FILE **pFile, const char *filename, const char *mode) { 97 if (!pFile || !filename || !mode) { 98 return EINVAL; 99 } 100 101 FILE *f = fopen(filename, mode); 102 if (!f) { 103 if (errno != 0) { 104 return errno; 105 } else { 106 return ENOENT; 107 } 108 } 109 *pFile = f; 110 111 return 0; 112 } 113 114 #endif 115 116 // Set up environment for GLSL compiler 117 // Must be done once per process 118 void TestEnvironment::SetUp() { 119 // Initialize GLSL to SPV compiler utility 120 glslang::InitializeProcess(); 121 122 vk_testing::set_error_callback(test_error_callback); 123 } 124 125 void TestEnvironment::TearDown() { glslang::FinalizeProcess(); } 126 127 VkTestFramework::VkTestFramework() : m_compile_options(0), m_num_shader_strings(0) {} 128 129 VkTestFramework::~VkTestFramework() {} 130 131 // Define all the static elements 132 bool VkTestFramework::m_use_glsl = false; 133 bool VkTestFramework::m_canonicalize_spv = false; 134 bool VkTestFramework::m_strip_spv = false; 135 bool VkTestFramework::m_do_everything_spv = false; 136 int VkTestFramework::m_width = 0; 137 int VkTestFramework::m_height = 0; 138 139 bool VkTestFramework::optionMatch(const char *option, char *optionLine) { 140 if (strncmp(option, optionLine, strlen(option)) == 0) 141 return true; 142 else 143 return false; 144 } 145 146 void VkTestFramework::InitArgs(int *argc, char *argv[]) { 147 int i, n; 148 149 for (i = 1, n = 1; i < *argc; i++) { 150 if (optionMatch("--no-SPV", argv[i])) 151 m_use_glsl = true; 152 else if (optionMatch("--strip-SPV", argv[i])) 153 m_strip_spv = true; 154 else if (optionMatch("--canonicalize-SPV", argv[i])) 155 m_canonicalize_spv = true; 156 else if (optionMatch("--help", argv[i]) || optionMatch("-h", argv[i])) { 157 printf("\nOther options:\n"); 158 printf("\t--show-images\n" 159 "\t\tDisplay test images in viewer after tests complete.\n"); 160 printf("\t--save-images\n" 161 "\t\tSave tests images as ppm files in current working " 162 "directory.\n" 163 "\t\tUsed to generate golden images for compare-images.\n"); 164 printf("\t--compare-images\n" 165 "\t\tCompare test images to 'golden' image in golden folder.\n" 166 "\t\tAlso saves the generated test image in current working\n" 167 "\t\t\tdirectory but only if the image is different from the " 168 "golden\n" 169 "\t\tSetting RENDERTEST_GOLDEN_DIR environment variable can " 170 "specify\n" 171 "\t\t\tdifferent directory for golden images\n" 172 "\t\tSignal test failure if different.\n"); 173 printf("\t--no-SPV\n" 174 "\t\tUse built-in GLSL compiler rather than SPV code path.\n"); 175 printf("\t--strip-SPV\n" 176 "\t\tStrip SPIR-V debug information (line numbers, names, " 177 "etc).\n"); 178 printf("\t--canonicalize-SPV\n" 179 "\t\tRemap SPIR-V ids before submission to aid compression.\n"); 180 exit(0); 181 } else { 182 printf("\nUnrecognized option: %s\n", argv[i]); 183 printf("\nUse --help or -h for option list.\n"); 184 exit(0); 185 } 186 187 /* 188 * Since the above "consume" inputs, update argv 189 * so that it contains the trimmed list of args for glutInit 190 */ 191 192 argv[n] = argv[i]; 193 n++; 194 } 195 } 196 197 VkFormat VkTestFramework::GetFormat(VkInstance instance, vk_testing::Device *device) { 198 VkFormatProperties format_props; 199 200 vkGetPhysicalDeviceFormatProperties(device->phy().handle(), VK_FORMAT_B8G8R8A8_UNORM, &format_props); 201 if (format_props.linearTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT || 202 format_props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) { 203 return VK_FORMAT_B8G8R8A8_UNORM; 204 } 205 vkGetPhysicalDeviceFormatProperties(device->phy().handle(), VK_FORMAT_R8G8B8A8_UNORM, &format_props); 206 if (format_props.linearTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT || 207 format_props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) { 208 return VK_FORMAT_R8G8B8A8_UNORM; 209 } 210 printf("Error - device does not support VK_FORMAT_B8G8R8A8_UNORM nor " 211 "VK_FORMAT_R8G8B8A8_UNORM - exiting\n"); 212 exit(1); 213 } 214 215 void VkTestFramework::Finish() {} 216 217 // 218 // These are the default resources for TBuiltInResources, used for both 219 // - parsing this string for the case where the user didn't supply one 220 // - dumping out a template for user construction of a config file 221 // 222 static const char *DefaultConfig = "MaxLights 32\n" 223 "MaxClipPlanes 6\n" 224 "MaxTextureUnits 32\n" 225 "MaxTextureCoords 32\n" 226 "MaxVertexAttribs 64\n" 227 "MaxVertexUniformComponents 4096\n" 228 "MaxVaryingFloats 64\n" 229 "MaxVertexTextureImageUnits 32\n" 230 "MaxCombinedTextureImageUnits 80\n" 231 "MaxTextureImageUnits 32\n" 232 "MaxFragmentUniformComponents 4096\n" 233 "MaxDrawBuffers 32\n" 234 "MaxVertexUniformVectors 128\n" 235 "MaxVaryingVectors 8\n" 236 "MaxFragmentUniformVectors 16\n" 237 "MaxVertexOutputVectors 16\n" 238 "MaxFragmentInputVectors 15\n" 239 "MinProgramTexelOffset -8\n" 240 "MaxProgramTexelOffset 7\n" 241 "MaxClipDistances 8\n" 242 "MaxComputeWorkGroupCountX 65535\n" 243 "MaxComputeWorkGroupCountY 65535\n" 244 "MaxComputeWorkGroupCountZ 65535\n" 245 "MaxComputeWorkGroupSizeX 1024\n" 246 "MaxComputeWorkGroupSizeY 1024\n" 247 "MaxComputeWorkGroupSizeZ 64\n" 248 "MaxComputeUniformComponents 1024\n" 249 "MaxComputeTextureImageUnits 16\n" 250 "MaxComputeImageUniforms 8\n" 251 "MaxComputeAtomicCounters 8\n" 252 "MaxComputeAtomicCounterBuffers 1\n" 253 "MaxVaryingComponents 60\n" 254 "MaxVertexOutputComponents 64\n" 255 "MaxGeometryInputComponents 64\n" 256 "MaxGeometryOutputComponents 128\n" 257 "MaxFragmentInputComponents 128\n" 258 "MaxImageUnits 8\n" 259 "MaxCombinedImageUnitsAndFragmentOutputs 8\n" 260 "MaxCombinedShaderOutputResources 8\n" 261 "MaxImageSamples 0\n" 262 "MaxVertexImageUniforms 0\n" 263 "MaxTessControlImageUniforms 0\n" 264 "MaxTessEvaluationImageUniforms 0\n" 265 "MaxGeometryImageUniforms 0\n" 266 "MaxFragmentImageUniforms 8\n" 267 "MaxCombinedImageUniforms 8\n" 268 "MaxGeometryTextureImageUnits 16\n" 269 "MaxGeometryOutputVertices 256\n" 270 "MaxGeometryTotalOutputComponents 1024\n" 271 "MaxGeometryUniformComponents 1024\n" 272 "MaxGeometryVaryingComponents 64\n" 273 "MaxTessControlInputComponents 128\n" 274 "MaxTessControlOutputComponents 128\n" 275 "MaxTessControlTextureImageUnits 16\n" 276 "MaxTessControlUniformComponents 1024\n" 277 "MaxTessControlTotalOutputComponents 4096\n" 278 "MaxTessEvaluationInputComponents 128\n" 279 "MaxTessEvaluationOutputComponents 128\n" 280 "MaxTessEvaluationTextureImageUnits 16\n" 281 "MaxTessEvaluationUniformComponents 1024\n" 282 "MaxTessPatchComponents 120\n" 283 "MaxPatchVertices 32\n" 284 "MaxTessGenLevel 64\n" 285 "MaxViewports 16\n" 286 "MaxVertexAtomicCounters 0\n" 287 "MaxTessControlAtomicCounters 0\n" 288 "MaxTessEvaluationAtomicCounters 0\n" 289 "MaxGeometryAtomicCounters 0\n" 290 "MaxFragmentAtomicCounters 8\n" 291 "MaxCombinedAtomicCounters 8\n" 292 "MaxAtomicCounterBindings 1\n" 293 "MaxVertexAtomicCounterBuffers 0\n" 294 "MaxTessControlAtomicCounterBuffers 0\n" 295 "MaxTessEvaluationAtomicCounterBuffers 0\n" 296 "MaxGeometryAtomicCounterBuffers 0\n" 297 "MaxFragmentAtomicCounterBuffers 1\n" 298 "MaxCombinedAtomicCounterBuffers 1\n" 299 "MaxAtomicCounterBufferSize 16384\n" 300 "MaxTransformFeedbackBuffers 4\n" 301 "MaxTransformFeedbackInterleavedComponents 64\n" 302 "MaxCullDistances 8\n" 303 "MaxCombinedClipAndCullDistances 8\n" 304 "MaxSamples 4\n" 305 306 "nonInductiveForLoops 1\n" 307 "whileLoops 1\n" 308 "doWhileLoops 1\n" 309 "generalUniformIndexing 1\n" 310 "generalAttributeMatrixVectorIndexing 1\n" 311 "generalVaryingIndexing 1\n" 312 "generalSamplerIndexing 1\n" 313 "generalVariableIndexing 1\n" 314 "generalConstantMatrixVectorIndexing 1\n"; 315 316 // 317 // *.conf => this is a config file that can set limits/resources 318 // 319 bool VkTestFramework::SetConfigFile(const std::string &name) { 320 if (name.size() < 5) 321 return false; 322 323 if (name.compare(name.size() - 5, 5, ".conf") == 0) { 324 ConfigFile = name; 325 return true; 326 } 327 328 return false; 329 } 330 331 // 332 // Parse either a .conf file provided by the user or the default string above. 333 // 334 void VkTestFramework::ProcessConfigFile() { 335 char **configStrings = 0; 336 char *config = 0; 337 if (ConfigFile.size() > 0) { 338 configStrings = ReadFileData(ConfigFile.c_str()); 339 if (configStrings) 340 config = *configStrings; 341 else { 342 printf("Error opening configuration file; will instead use the " 343 "default configuration\n"); 344 } 345 } 346 347 if (config == 0) { 348 config = (char *)alloca(strlen(DefaultConfig) + 1); 349 strcpy(config, DefaultConfig); 350 } 351 352 const char *delims = " \t\n\r"; 353 const char *token = strtok(config, delims); 354 while (token) { 355 const char *valueStr = strtok(0, delims); 356 if (valueStr == 0 || !(valueStr[0] == '-' || (valueStr[0] >= '0' && valueStr[0] <= '9'))) { 357 printf("Error: '%s' bad .conf file. Each name must be followed by " 358 "one number.\n", 359 valueStr ? valueStr : ""); 360 return; 361 } 362 int value = atoi(valueStr); 363 364 if (strcmp(token, "MaxLights") == 0) 365 Resources.maxLights = value; 366 else if (strcmp(token, "MaxClipPlanes") == 0) 367 Resources.maxClipPlanes = value; 368 else if (strcmp(token, "MaxTextureUnits") == 0) 369 Resources.maxTextureUnits = value; 370 else if (strcmp(token, "MaxTextureCoords") == 0) 371 Resources.maxTextureCoords = value; 372 else if (strcmp(token, "MaxVertexAttribs") == 0) 373 Resources.maxVertexAttribs = value; 374 else if (strcmp(token, "MaxVertexUniformComponents") == 0) 375 Resources.maxVertexUniformComponents = value; 376 else if (strcmp(token, "MaxVaryingFloats") == 0) 377 Resources.maxVaryingFloats = value; 378 else if (strcmp(token, "MaxVertexTextureImageUnits") == 0) 379 Resources.maxVertexTextureImageUnits = value; 380 else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0) 381 Resources.maxCombinedTextureImageUnits = value; 382 else if (strcmp(token, "MaxTextureImageUnits") == 0) 383 Resources.maxTextureImageUnits = value; 384 else if (strcmp(token, "MaxFragmentUniformComponents") == 0) 385 Resources.maxFragmentUniformComponents = value; 386 else if (strcmp(token, "MaxDrawBuffers") == 0) 387 Resources.maxDrawBuffers = value; 388 else if (strcmp(token, "MaxVertexUniformVectors") == 0) 389 Resources.maxVertexUniformVectors = value; 390 else if (strcmp(token, "MaxVaryingVectors") == 0) 391 Resources.maxVaryingVectors = value; 392 else if (strcmp(token, "MaxFragmentUniformVectors") == 0) 393 Resources.maxFragmentUniformVectors = value; 394 else if (strcmp(token, "MaxVertexOutputVectors") == 0) 395 Resources.maxVertexOutputVectors = value; 396 else if (strcmp(token, "MaxFragmentInputVectors") == 0) 397 Resources.maxFragmentInputVectors = value; 398 else if (strcmp(token, "MinProgramTexelOffset") == 0) 399 Resources.minProgramTexelOffset = value; 400 else if (strcmp(token, "MaxProgramTexelOffset") == 0) 401 Resources.maxProgramTexelOffset = value; 402 else if (strcmp(token, "MaxClipDistances") == 0) 403 Resources.maxClipDistances = value; 404 else if (strcmp(token, "MaxComputeWorkGroupCountX") == 0) 405 Resources.maxComputeWorkGroupCountX = value; 406 else if (strcmp(token, "MaxComputeWorkGroupCountY") == 0) 407 Resources.maxComputeWorkGroupCountY = value; 408 else if (strcmp(token, "MaxComputeWorkGroupCountZ") == 0) 409 Resources.maxComputeWorkGroupCountZ = value; 410 else if (strcmp(token, "MaxComputeWorkGroupSizeX") == 0) 411 Resources.maxComputeWorkGroupSizeX = value; 412 else if (strcmp(token, "MaxComputeWorkGroupSizeY") == 0) 413 Resources.maxComputeWorkGroupSizeY = value; 414 else if (strcmp(token, "MaxComputeWorkGroupSizeZ") == 0) 415 Resources.maxComputeWorkGroupSizeZ = value; 416 else if (strcmp(token, "MaxComputeUniformComponents") == 0) 417 Resources.maxComputeUniformComponents = value; 418 else if (strcmp(token, "MaxComputeTextureImageUnits") == 0) 419 Resources.maxComputeTextureImageUnits = value; 420 else if (strcmp(token, "MaxComputeImageUniforms") == 0) 421 Resources.maxComputeImageUniforms = value; 422 else if (strcmp(token, "MaxComputeAtomicCounters") == 0) 423 Resources.maxComputeAtomicCounters = value; 424 else if (strcmp(token, "MaxComputeAtomicCounterBuffers") == 0) 425 Resources.maxComputeAtomicCounterBuffers = value; 426 else if (strcmp(token, "MaxVaryingComponents") == 0) 427 Resources.maxVaryingComponents = value; 428 else if (strcmp(token, "MaxVertexOutputComponents") == 0) 429 Resources.maxVertexOutputComponents = value; 430 else if (strcmp(token, "MaxGeometryInputComponents") == 0) 431 Resources.maxGeometryInputComponents = value; 432 else if (strcmp(token, "MaxGeometryOutputComponents") == 0) 433 Resources.maxGeometryOutputComponents = value; 434 else if (strcmp(token, "MaxFragmentInputComponents") == 0) 435 Resources.maxFragmentInputComponents = value; 436 else if (strcmp(token, "MaxImageUnits") == 0) 437 Resources.maxImageUnits = value; 438 else if (strcmp(token, "MaxCombinedImageUnitsAndFragmentOutputs") == 0) 439 Resources.maxCombinedImageUnitsAndFragmentOutputs = value; 440 else if (strcmp(token, "MaxCombinedShaderOutputResources") == 0) 441 Resources.maxCombinedShaderOutputResources = value; 442 else if (strcmp(token, "MaxImageSamples") == 0) 443 Resources.maxImageSamples = value; 444 else if (strcmp(token, "MaxVertexImageUniforms") == 0) 445 Resources.maxVertexImageUniforms = value; 446 else if (strcmp(token, "MaxTessControlImageUniforms") == 0) 447 Resources.maxTessControlImageUniforms = value; 448 else if (strcmp(token, "MaxTessEvaluationImageUniforms") == 0) 449 Resources.maxTessEvaluationImageUniforms = value; 450 else if (strcmp(token, "MaxGeometryImageUniforms") == 0) 451 Resources.maxGeometryImageUniforms = value; 452 else if (strcmp(token, "MaxFragmentImageUniforms") == 0) 453 Resources.maxFragmentImageUniforms = value; 454 else if (strcmp(token, "MaxCombinedImageUniforms") == 0) 455 Resources.maxCombinedImageUniforms = value; 456 else if (strcmp(token, "MaxGeometryTextureImageUnits") == 0) 457 Resources.maxGeometryTextureImageUnits = value; 458 else if (strcmp(token, "MaxGeometryOutputVertices") == 0) 459 Resources.maxGeometryOutputVertices = value; 460 else if (strcmp(token, "MaxGeometryTotalOutputComponents") == 0) 461 Resources.maxGeometryTotalOutputComponents = value; 462 else if (strcmp(token, "MaxGeometryUniformComponents") == 0) 463 Resources.maxGeometryUniformComponents = value; 464 else if (strcmp(token, "MaxGeometryVaryingComponents") == 0) 465 Resources.maxGeometryVaryingComponents = value; 466 else if (strcmp(token, "MaxTessControlInputComponents") == 0) 467 Resources.maxTessControlInputComponents = value; 468 else if (strcmp(token, "MaxTessControlOutputComponents") == 0) 469 Resources.maxTessControlOutputComponents = value; 470 else if (strcmp(token, "MaxTessControlTextureImageUnits") == 0) 471 Resources.maxTessControlTextureImageUnits = value; 472 else if (strcmp(token, "MaxTessControlUniformComponents") == 0) 473 Resources.maxTessControlUniformComponents = value; 474 else if (strcmp(token, "MaxTessControlTotalOutputComponents") == 0) 475 Resources.maxTessControlTotalOutputComponents = value; 476 else if (strcmp(token, "MaxTessEvaluationInputComponents") == 0) 477 Resources.maxTessEvaluationInputComponents = value; 478 else if (strcmp(token, "MaxTessEvaluationOutputComponents") == 0) 479 Resources.maxTessEvaluationOutputComponents = value; 480 else if (strcmp(token, "MaxTessEvaluationTextureImageUnits") == 0) 481 Resources.maxTessEvaluationTextureImageUnits = value; 482 else if (strcmp(token, "MaxTessEvaluationUniformComponents") == 0) 483 Resources.maxTessEvaluationUniformComponents = value; 484 else if (strcmp(token, "MaxTessPatchComponents") == 0) 485 Resources.maxTessPatchComponents = value; 486 else if (strcmp(token, "MaxPatchVertices") == 0) 487 Resources.maxPatchVertices = value; 488 else if (strcmp(token, "MaxTessGenLevel") == 0) 489 Resources.maxTessGenLevel = value; 490 else if (strcmp(token, "MaxViewports") == 0) 491 Resources.maxViewports = value; 492 else if (strcmp(token, "MaxVertexAtomicCounters") == 0) 493 Resources.maxVertexAtomicCounters = value; 494 else if (strcmp(token, "MaxTessControlAtomicCounters") == 0) 495 Resources.maxTessControlAtomicCounters = value; 496 else if (strcmp(token, "MaxTessEvaluationAtomicCounters") == 0) 497 Resources.maxTessEvaluationAtomicCounters = value; 498 else if (strcmp(token, "MaxGeometryAtomicCounters") == 0) 499 Resources.maxGeometryAtomicCounters = value; 500 else if (strcmp(token, "MaxFragmentAtomicCounters") == 0) 501 Resources.maxFragmentAtomicCounters = value; 502 else if (strcmp(token, "MaxCombinedAtomicCounters") == 0) 503 Resources.maxCombinedAtomicCounters = value; 504 else if (strcmp(token, "MaxAtomicCounterBindings") == 0) 505 Resources.maxAtomicCounterBindings = value; 506 else if (strcmp(token, "MaxVertexAtomicCounterBuffers") == 0) 507 Resources.maxVertexAtomicCounterBuffers = value; 508 else if (strcmp(token, "MaxTessControlAtomicCounterBuffers") == 0) 509 Resources.maxTessControlAtomicCounterBuffers = value; 510 else if (strcmp(token, "MaxTessEvaluationAtomicCounterBuffers") == 0) 511 Resources.maxTessEvaluationAtomicCounterBuffers = value; 512 else if (strcmp(token, "MaxGeometryAtomicCounterBuffers") == 0) 513 Resources.maxGeometryAtomicCounterBuffers = value; 514 else if (strcmp(token, "MaxFragmentAtomicCounterBuffers") == 0) 515 Resources.maxFragmentAtomicCounterBuffers = value; 516 else if (strcmp(token, "MaxCombinedAtomicCounterBuffers") == 0) 517 Resources.maxCombinedAtomicCounterBuffers = value; 518 else if (strcmp(token, "MaxAtomicCounterBufferSize") == 0) 519 Resources.maxAtomicCounterBufferSize = value; 520 else if (strcmp(token, "MaxTransformFeedbackBuffers") == 0) 521 Resources.maxTransformFeedbackBuffers = value; 522 else if (strcmp(token, "MaxTransformFeedbackInterleavedComponents") == 0) 523 Resources.maxTransformFeedbackInterleavedComponents = value; 524 else if (strcmp(token, "MaxCullDistances") == 0) 525 Resources.maxCullDistances = value; 526 else if (strcmp(token, "MaxCombinedClipAndCullDistances") == 0) 527 Resources.maxCombinedClipAndCullDistances = value; 528 else if (strcmp(token, "MaxSamples") == 0) 529 Resources.maxSamples = value; 530 531 else if (strcmp(token, "nonInductiveForLoops") == 0) 532 Resources.limits.nonInductiveForLoops = (value != 0); 533 else if (strcmp(token, "whileLoops") == 0) 534 Resources.limits.whileLoops = (value != 0); 535 else if (strcmp(token, "doWhileLoops") == 0) 536 Resources.limits.doWhileLoops = (value != 0); 537 else if (strcmp(token, "generalUniformIndexing") == 0) 538 Resources.limits.generalUniformIndexing = (value != 0); 539 else if (strcmp(token, "generalAttributeMatrixVectorIndexing") == 0) 540 Resources.limits.generalAttributeMatrixVectorIndexing = (value != 0); 541 else if (strcmp(token, "generalVaryingIndexing") == 0) 542 Resources.limits.generalVaryingIndexing = (value != 0); 543 else if (strcmp(token, "generalSamplerIndexing") == 0) 544 Resources.limits.generalSamplerIndexing = (value != 0); 545 else if (strcmp(token, "generalVariableIndexing") == 0) 546 Resources.limits.generalVariableIndexing = (value != 0); 547 else if (strcmp(token, "generalConstantMatrixVectorIndexing") == 0) 548 Resources.limits.generalConstantMatrixVectorIndexing = (value != 0); 549 else 550 printf("Warning: unrecognized limit (%s) in configuration file.\n", token); 551 552 token = strtok(0, delims); 553 } 554 if (configStrings) 555 FreeFileData(configStrings); 556 } 557 558 void VkTestFramework::SetMessageOptions(EShMessages &messages) { 559 if (m_compile_options & EOptionRelaxedErrors) 560 messages = (EShMessages)(messages | EShMsgRelaxedErrors); 561 if (m_compile_options & EOptionIntermediate) 562 messages = (EShMessages)(messages | EShMsgAST); 563 if (m_compile_options & EOptionSuppressWarnings) 564 messages = (EShMessages)(messages | EShMsgSuppressWarnings); 565 } 566 567 // 568 // Malloc a string of sufficient size and read a string into it. 569 // 570 char **VkTestFramework::ReadFileData(const char *fileName) { 571 FILE *in; 572 #if defined(_WIN32) && defined(__GNUC__) 573 in = fopen(fileName, "r"); 574 int errorCode = in ? 0 : 1; 575 #else 576 int errorCode = fopen_s(&in, fileName, "r"); 577 #endif 578 579 char *fdata; 580 size_t count = 0; 581 const int maxSourceStrings = 5; 582 char **return_data = (char **)malloc(sizeof(char *) * (maxSourceStrings + 1)); 583 584 if (errorCode) { 585 printf("Error: unable to open input file: %s\n", fileName); 586 return 0; 587 } 588 589 while (fgetc(in) != EOF) 590 count++; 591 592 fseek(in, 0, SEEK_SET); 593 594 if (!(fdata = (char *)malloc(count + 2))) { 595 printf("Error allocating memory\n"); 596 return 0; 597 } 598 if (fread(fdata, 1, count, in) != count) { 599 printf("Error reading input file: %s\n", fileName); 600 return 0; 601 } 602 fdata[count] = '\0'; 603 fclose(in); 604 if (count == 0) { 605 return_data[0] = (char *)malloc(count + 2); 606 return_data[0][0] = '\0'; 607 m_num_shader_strings = 0; 608 return return_data; 609 } else 610 m_num_shader_strings = 1; 611 612 size_t len = (int)(ceil)((float)count / (float)m_num_shader_strings); 613 size_t ptr_len = 0, i = 0; 614 while (count > 0) { 615 return_data[i] = (char *)malloc(len + 2); 616 memcpy(return_data[i], fdata + ptr_len, len); 617 return_data[i][len] = '\0'; 618 count -= (len); 619 ptr_len += (len); 620 if (count < len) { 621 if (count == 0) { 622 m_num_shader_strings = (i + 1); 623 break; 624 } 625 len = count; 626 } 627 ++i; 628 } 629 return return_data; 630 } 631 632 void VkTestFramework::FreeFileData(char **data) { 633 for (int i = 0; i < m_num_shader_strings; i++) 634 free(data[i]); 635 } 636 637 // 638 // Deduce the language from the filename. Files must end in one of the 639 // following extensions: 640 // 641 // .vert = vertex 642 // .tesc = tessellation control 643 // .tese = tessellation evaluation 644 // .geom = geometry 645 // .frag = fragment 646 // .comp = compute 647 // 648 EShLanguage VkTestFramework::FindLanguage(const std::string &name) { 649 size_t ext = name.rfind('.'); 650 if (ext == std::string::npos) { 651 return EShLangVertex; 652 } 653 654 std::string suffix = name.substr(ext + 1, std::string::npos); 655 if (suffix == "vert") 656 return EShLangVertex; 657 else if (suffix == "tesc") 658 return EShLangTessControl; 659 else if (suffix == "tese") 660 return EShLangTessEvaluation; 661 else if (suffix == "geom") 662 return EShLangGeometry; 663 else if (suffix == "frag") 664 return EShLangFragment; 665 else if (suffix == "comp") 666 return EShLangCompute; 667 668 return EShLangVertex; 669 } 670 671 // 672 // Convert VK shader type to compiler's 673 // 674 EShLanguage VkTestFramework::FindLanguage(const VkShaderStageFlagBits shader_type) { 675 switch (shader_type) { 676 case VK_SHADER_STAGE_VERTEX_BIT: 677 return EShLangVertex; 678 679 case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: 680 return EShLangTessControl; 681 682 case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: 683 return EShLangTessEvaluation; 684 685 case VK_SHADER_STAGE_GEOMETRY_BIT: 686 return EShLangGeometry; 687 688 case VK_SHADER_STAGE_FRAGMENT_BIT: 689 return EShLangFragment; 690 691 case VK_SHADER_STAGE_COMPUTE_BIT: 692 return EShLangCompute; 693 694 default: 695 return EShLangVertex; 696 } 697 } 698 699 // 700 // Compile a given string containing GLSL into SPV for use by VK 701 // Return value of false means an error was encountered. 702 // 703 bool VkTestFramework::GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector<unsigned int> &spirv) { 704 glslang::TProgram program; 705 const char *shaderStrings[1]; 706 707 // TODO: Do we want to load a special config file depending on the 708 // shader source? Optional name maybe? 709 // SetConfigFile(fileName); 710 711 ProcessConfigFile(); 712 713 EShMessages messages = EShMsgDefault; 714 SetMessageOptions(messages); 715 messages = static_cast<EShMessages>(messages | EShMsgSpvRules | EShMsgVulkanRules); 716 717 EShLanguage stage = FindLanguage(shader_type); 718 glslang::TShader *shader = new glslang::TShader(stage); 719 720 shaderStrings[0] = pshader; 721 shader->setStrings(shaderStrings, 1); 722 723 if (!shader->parse(&Resources, (m_compile_options & EOptionDefaultDesktop) ? 110 : 100, false, messages)) { 724 725 if (!(m_compile_options & EOptionSuppressInfolog)) { 726 puts(shader->getInfoLog()); 727 puts(shader->getInfoDebugLog()); 728 } 729 730 return false; // something didn't work 731 } 732 733 program.addShader(shader); 734 735 // 736 // Program-level processing... 737 // 738 739 if (!program.link(messages)) { 740 741 if (!(m_compile_options & EOptionSuppressInfolog)) { 742 puts(shader->getInfoLog()); 743 puts(shader->getInfoDebugLog()); 744 } 745 746 return false; 747 } 748 749 if (m_compile_options & EOptionDumpReflection) { 750 program.buildReflection(); 751 program.dumpReflection(); 752 } 753 754 glslang::GlslangToSpv(*program.getIntermediate(stage), spirv); 755 756 // 757 // Test the different modes of SPIR-V modification 758 // 759 if (this->m_canonicalize_spv) { 760 spv::spirvbin_t(0).remap(spirv, spv::spirvbin_t::ALL_BUT_STRIP); 761 } 762 763 if (this->m_strip_spv) { 764 spv::spirvbin_t(0).remap(spirv, spv::spirvbin_t::STRIP); 765 } 766 767 if (this->m_do_everything_spv) { 768 spv::spirvbin_t(0).remap(spirv, spv::spirvbin_t::DO_EVERYTHING); 769 } 770 771 delete shader; 772 773 return true; 774 } 775