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