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@gmail.com> 19 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com> 20 * Author: Tony Barbour <tony@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 80enum 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 97struct SwapchainBuffers { 98 VkImage image; 99 VkCommandBuffer cmd; 100 VkImageView view; 101}; 102 103#ifndef _WIN32 104 105#include <errno.h> 106 107int 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 129void TestEnvironment::SetUp() { 130 // Initialize GLSL to SPV compiler utility 131 glslang::InitializeProcess(); 132 133 vk_testing::set_error_callback(test_error_callback); 134} 135 136void TestEnvironment::TearDown() { glslang::FinalizeProcess(); } 137 138VkTestFramework::VkTestFramework() : m_compile_options(0), m_num_shader_strings(0) {} 139 140VkTestFramework::~VkTestFramework() {} 141 142// Define all the static elements 143bool VkTestFramework::m_canonicalize_spv = false; 144bool VkTestFramework::m_strip_spv = false; 145bool VkTestFramework::m_do_everything_spv = false; 146bool VkTestFramework::m_devsim_layer = false; 147int VkTestFramework::m_width = 0; 148int VkTestFramework::m_height = 0; 149 150bool 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 157void 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 210VkFormat 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 227void 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// 234static 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 319 "nonInductiveForLoops 1\n" 320 "whileLoops 1\n" 321 "doWhileLoops 1\n" 322 "generalUniformIndexing 1\n" 323 "generalAttributeMatrixVectorIndexing 1\n" 324 "generalVaryingIndexing 1\n" 325 "generalSamplerIndexing 1\n" 326 "generalVariableIndexing 1\n" 327 "generalConstantMatrixVectorIndexing 1\n"; 328 329// 330// *.conf => this is a config file that can set limits/resources 331// 332bool VkTestFramework::SetConfigFile(const std::string &name) { 333 if (name.size() < 5) return false; 334 335 if (name.compare(name.size() - 5, 5, ".conf") == 0) { 336 ConfigFile = name; 337 return true; 338 } 339 340 return false; 341} 342 343// 344// Parse either a .conf file provided by the user or the default string above. 345// 346void VkTestFramework::ProcessConfigFile() { 347 char **configStrings = 0; 348 char *config = 0; 349 if (ConfigFile.size() > 0) { 350 configStrings = ReadFileData(ConfigFile.c_str()); 351 if (configStrings) 352 config = *configStrings; 353 else { 354 printf("Error opening configuration file; will instead use the default configuration\n"); 355 } 356 } 357 358 if (config == 0) { 359 config = (char *)alloca(strlen(DefaultConfig) + 1); 360 strcpy(config, DefaultConfig); 361 } 362 363 const char *delims = " \t\n\r"; 364 const char *token = strtok(config, delims); 365 while (token) { 366 const char *valueStr = strtok(0, delims); 367 if (valueStr == 0 || !(valueStr[0] == '-' || (valueStr[0] >= '0' && valueStr[0] <= '9'))) { 368 printf("Error: '%s' bad .conf file. Each name must be followed by one number.\n", valueStr ? valueStr : ""); 369 return; 370 } 371 int value = atoi(valueStr); 372 373 if (strcmp(token, "MaxLights") == 0) 374 Resources.maxLights = value; 375 else if (strcmp(token, "MaxClipPlanes") == 0) 376 Resources.maxClipPlanes = value; 377 else if (strcmp(token, "MaxTextureUnits") == 0) 378 Resources.maxTextureUnits = value; 379 else if (strcmp(token, "MaxTextureCoords") == 0) 380 Resources.maxTextureCoords = value; 381 else if (strcmp(token, "MaxVertexAttribs") == 0) 382 Resources.maxVertexAttribs = value; 383 else if (strcmp(token, "MaxVertexUniformComponents") == 0) 384 Resources.maxVertexUniformComponents = value; 385 else if (strcmp(token, "MaxVaryingFloats") == 0) 386 Resources.maxVaryingFloats = value; 387 else if (strcmp(token, "MaxVertexTextureImageUnits") == 0) 388 Resources.maxVertexTextureImageUnits = value; 389 else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0) 390 Resources.maxCombinedTextureImageUnits = value; 391 else if (strcmp(token, "MaxTextureImageUnits") == 0) 392 Resources.maxTextureImageUnits = value; 393 else if (strcmp(token, "MaxFragmentUniformComponents") == 0) 394 Resources.maxFragmentUniformComponents = value; 395 else if (strcmp(token, "MaxDrawBuffers") == 0) 396 Resources.maxDrawBuffers = value; 397 else if (strcmp(token, "MaxVertexUniformVectors") == 0) 398 Resources.maxVertexUniformVectors = value; 399 else if (strcmp(token, "MaxVaryingVectors") == 0) 400 Resources.maxVaryingVectors = value; 401 else if (strcmp(token, "MaxFragmentUniformVectors") == 0) 402 Resources.maxFragmentUniformVectors = value; 403 else if (strcmp(token, "MaxVertexOutputVectors") == 0) 404 Resources.maxVertexOutputVectors = value; 405 else if (strcmp(token, "MaxFragmentInputVectors") == 0) 406 Resources.maxFragmentInputVectors = value; 407 else if (strcmp(token, "MinProgramTexelOffset") == 0) 408 Resources.minProgramTexelOffset = value; 409 else if (strcmp(token, "MaxProgramTexelOffset") == 0) 410 Resources.maxProgramTexelOffset = value; 411 else if (strcmp(token, "MaxClipDistances") == 0) 412 Resources.maxClipDistances = value; 413 else if (strcmp(token, "MaxComputeWorkGroupCountX") == 0) 414 Resources.maxComputeWorkGroupCountX = value; 415 else if (strcmp(token, "MaxComputeWorkGroupCountY") == 0) 416 Resources.maxComputeWorkGroupCountY = value; 417 else if (strcmp(token, "MaxComputeWorkGroupCountZ") == 0) 418 Resources.maxComputeWorkGroupCountZ = value; 419 else if (strcmp(token, "MaxComputeWorkGroupSizeX") == 0) 420 Resources.maxComputeWorkGroupSizeX = value; 421 else if (strcmp(token, "MaxComputeWorkGroupSizeY") == 0) 422 Resources.maxComputeWorkGroupSizeY = value; 423 else if (strcmp(token, "MaxComputeWorkGroupSizeZ") == 0) 424 Resources.maxComputeWorkGroupSizeZ = value; 425 else if (strcmp(token, "MaxComputeUniformComponents") == 0) 426 Resources.maxComputeUniformComponents = value; 427 else if (strcmp(token, "MaxComputeTextureImageUnits") == 0) 428 Resources.maxComputeTextureImageUnits = value; 429 else if (strcmp(token, "MaxComputeImageUniforms") == 0) 430 Resources.maxComputeImageUniforms = value; 431 else if (strcmp(token, "MaxComputeAtomicCounters") == 0) 432 Resources.maxComputeAtomicCounters = value; 433 else if (strcmp(token, "MaxComputeAtomicCounterBuffers") == 0) 434 Resources.maxComputeAtomicCounterBuffers = value; 435 else if (strcmp(token, "MaxVaryingComponents") == 0) 436 Resources.maxVaryingComponents = value; 437 else if (strcmp(token, "MaxVertexOutputComponents") == 0) 438 Resources.maxVertexOutputComponents = value; 439 else if (strcmp(token, "MaxGeometryInputComponents") == 0) 440 Resources.maxGeometryInputComponents = value; 441 else if (strcmp(token, "MaxGeometryOutputComponents") == 0) 442 Resources.maxGeometryOutputComponents = value; 443 else if (strcmp(token, "MaxFragmentInputComponents") == 0) 444 Resources.maxFragmentInputComponents = value; 445 else if (strcmp(token, "MaxImageUnits") == 0) 446 Resources.maxImageUnits = value; 447 else if (strcmp(token, "MaxCombinedImageUnitsAndFragmentOutputs") == 0) 448 Resources.maxCombinedImageUnitsAndFragmentOutputs = value; 449 else if (strcmp(token, "MaxCombinedShaderOutputResources") == 0) 450 Resources.maxCombinedShaderOutputResources = value; 451 else if (strcmp(token, "MaxImageSamples") == 0) 452 Resources.maxImageSamples = value; 453 else if (strcmp(token, "MaxVertexImageUniforms") == 0) 454 Resources.maxVertexImageUniforms = value; 455 else if (strcmp(token, "MaxTessControlImageUniforms") == 0) 456 Resources.maxTessControlImageUniforms = value; 457 else if (strcmp(token, "MaxTessEvaluationImageUniforms") == 0) 458 Resources.maxTessEvaluationImageUniforms = value; 459 else if (strcmp(token, "MaxGeometryImageUniforms") == 0) 460 Resources.maxGeometryImageUniforms = value; 461 else if (strcmp(token, "MaxFragmentImageUniforms") == 0) 462 Resources.maxFragmentImageUniforms = value; 463 else if (strcmp(token, "MaxCombinedImageUniforms") == 0) 464 Resources.maxCombinedImageUniforms = value; 465 else if (strcmp(token, "MaxGeometryTextureImageUnits") == 0) 466 Resources.maxGeometryTextureImageUnits = value; 467 else if (strcmp(token, "MaxGeometryOutputVertices") == 0) 468 Resources.maxGeometryOutputVertices = value; 469 else if (strcmp(token, "MaxGeometryTotalOutputComponents") == 0) 470 Resources.maxGeometryTotalOutputComponents = value; 471 else if (strcmp(token, "MaxGeometryUniformComponents") == 0) 472 Resources.maxGeometryUniformComponents = value; 473 else if (strcmp(token, "MaxGeometryVaryingComponents") == 0) 474 Resources.maxGeometryVaryingComponents = value; 475 else if (strcmp(token, "MaxTessControlInputComponents") == 0) 476 Resources.maxTessControlInputComponents = value; 477 else if (strcmp(token, "MaxTessControlOutputComponents") == 0) 478 Resources.maxTessControlOutputComponents = value; 479 else if (strcmp(token, "MaxTessControlTextureImageUnits") == 0) 480 Resources.maxTessControlTextureImageUnits = value; 481 else if (strcmp(token, "MaxTessControlUniformComponents") == 0) 482 Resources.maxTessControlUniformComponents = value; 483 else if (strcmp(token, "MaxTessControlTotalOutputComponents") == 0) 484 Resources.maxTessControlTotalOutputComponents = value; 485 else if (strcmp(token, "MaxTessEvaluationInputComponents") == 0) 486 Resources.maxTessEvaluationInputComponents = value; 487 else if (strcmp(token, "MaxTessEvaluationOutputComponents") == 0) 488 Resources.maxTessEvaluationOutputComponents = value; 489 else if (strcmp(token, "MaxTessEvaluationTextureImageUnits") == 0) 490 Resources.maxTessEvaluationTextureImageUnits = value; 491 else if (strcmp(token, "MaxTessEvaluationUniformComponents") == 0) 492 Resources.maxTessEvaluationUniformComponents = value; 493 else if (strcmp(token, "MaxTessPatchComponents") == 0) 494 Resources.maxTessPatchComponents = value; 495 else if (strcmp(token, "MaxPatchVertices") == 0) 496 Resources.maxPatchVertices = value; 497 else if (strcmp(token, "MaxTessGenLevel") == 0) 498 Resources.maxTessGenLevel = value; 499 else if (strcmp(token, "MaxViewports") == 0) 500 Resources.maxViewports = value; 501 else if (strcmp(token, "MaxVertexAtomicCounters") == 0) 502 Resources.maxVertexAtomicCounters = value; 503 else if (strcmp(token, "MaxTessControlAtomicCounters") == 0) 504 Resources.maxTessControlAtomicCounters = value; 505 else if (strcmp(token, "MaxTessEvaluationAtomicCounters") == 0) 506 Resources.maxTessEvaluationAtomicCounters = value; 507 else if (strcmp(token, "MaxGeometryAtomicCounters") == 0) 508 Resources.maxGeometryAtomicCounters = value; 509 else if (strcmp(token, "MaxFragmentAtomicCounters") == 0) 510 Resources.maxFragmentAtomicCounters = value; 511 else if (strcmp(token, "MaxCombinedAtomicCounters") == 0) 512 Resources.maxCombinedAtomicCounters = value; 513 else if (strcmp(token, "MaxAtomicCounterBindings") == 0) 514 Resources.maxAtomicCounterBindings = value; 515 else if (strcmp(token, "MaxVertexAtomicCounterBuffers") == 0) 516 Resources.maxVertexAtomicCounterBuffers = value; 517 else if (strcmp(token, "MaxTessControlAtomicCounterBuffers") == 0) 518 Resources.maxTessControlAtomicCounterBuffers = value; 519 else if (strcmp(token, "MaxTessEvaluationAtomicCounterBuffers") == 0) 520 Resources.maxTessEvaluationAtomicCounterBuffers = value; 521 else if (strcmp(token, "MaxGeometryAtomicCounterBuffers") == 0) 522 Resources.maxGeometryAtomicCounterBuffers = value; 523 else if (strcmp(token, "MaxFragmentAtomicCounterBuffers") == 0) 524 Resources.maxFragmentAtomicCounterBuffers = value; 525 else if (strcmp(token, "MaxCombinedAtomicCounterBuffers") == 0) 526 Resources.maxCombinedAtomicCounterBuffers = value; 527 else if (strcmp(token, "MaxAtomicCounterBufferSize") == 0) 528 Resources.maxAtomicCounterBufferSize = value; 529 else if (strcmp(token, "MaxTransformFeedbackBuffers") == 0) 530 Resources.maxTransformFeedbackBuffers = value; 531 else if (strcmp(token, "MaxTransformFeedbackInterleavedComponents") == 0) 532 Resources.maxTransformFeedbackInterleavedComponents = value; 533 else if (strcmp(token, "MaxCullDistances") == 0) 534 Resources.maxCullDistances = value; 535 else if (strcmp(token, "MaxCombinedClipAndCullDistances") == 0) 536 Resources.maxCombinedClipAndCullDistances = value; 537 else if (strcmp(token, "MaxSamples") == 0) 538 Resources.maxSamples = value; 539 540 else if (strcmp(token, "nonInductiveForLoops") == 0) 541 Resources.limits.nonInductiveForLoops = (value != 0); 542 else if (strcmp(token, "whileLoops") == 0) 543 Resources.limits.whileLoops = (value != 0); 544 else if (strcmp(token, "doWhileLoops") == 0) 545 Resources.limits.doWhileLoops = (value != 0); 546 else if (strcmp(token, "generalUniformIndexing") == 0) 547 Resources.limits.generalUniformIndexing = (value != 0); 548 else if (strcmp(token, "generalAttributeMatrixVectorIndexing") == 0) 549 Resources.limits.generalAttributeMatrixVectorIndexing = (value != 0); 550 else if (strcmp(token, "generalVaryingIndexing") == 0) 551 Resources.limits.generalVaryingIndexing = (value != 0); 552 else if (strcmp(token, "generalSamplerIndexing") == 0) 553 Resources.limits.generalSamplerIndexing = (value != 0); 554 else if (strcmp(token, "generalVariableIndexing") == 0) 555 Resources.limits.generalVariableIndexing = (value != 0); 556 else if (strcmp(token, "generalConstantMatrixVectorIndexing") == 0) 557 Resources.limits.generalConstantMatrixVectorIndexing = (value != 0); 558 else 559 printf("Warning: unrecognized limit (%s) in configuration file.\n", token); 560 561 token = strtok(0, delims); 562 } 563 if (configStrings) FreeFileData(configStrings); 564} 565 566void VkTestFramework::SetMessageOptions(EShMessages &messages) { 567 if (m_compile_options & EOptionRelaxedErrors) messages = (EShMessages)(messages | EShMsgRelaxedErrors); 568 if (m_compile_options & EOptionIntermediate) messages = (EShMessages)(messages | EShMsgAST); 569 if (m_compile_options & EOptionSuppressWarnings) messages = (EShMessages)(messages | EShMsgSuppressWarnings); 570} 571 572// 573// Malloc a string of sufficient size and read a string into it. 574// 575char **VkTestFramework::ReadFileData(const char *fileName) { 576 FILE *in; 577#if defined(_WIN32) && defined(__GNUC__) 578 in = fopen(fileName, "r"); 579 int errorCode = in ? 0 : 1; 580#else 581 int errorCode = fopen_s(&in, fileName, "r"); 582#endif 583 584 char *fdata; 585 size_t count = 0; 586 const int maxSourceStrings = 5; 587 char **return_data = (char **)malloc(sizeof(char *) * (maxSourceStrings + 1)); 588 589 if (errorCode) { 590 printf("Error: unable to open input file: %s\n", fileName); 591 return 0; 592 } 593 594 while (fgetc(in) != EOF) count++; 595 596 fseek(in, 0, SEEK_SET); 597 598 if (!(fdata = (char *)malloc(count + 2))) { 599 printf("Error allocating memory\n"); 600 return 0; 601 } 602 if (fread(fdata, 1, count, in) != count) { 603 printf("Error reading input file: %s\n", fileName); 604 return 0; 605 } 606 fdata[count] = '\0'; 607 fclose(in); 608 if (count == 0) { 609 return_data[0] = (char *)malloc(count + 2); 610 return_data[0][0] = '\0'; 611 m_num_shader_strings = 0; 612 return return_data; 613 } else 614 m_num_shader_strings = 1; 615 616 size_t len = (int)(ceil)((float)count / (float)m_num_shader_strings); 617 size_t ptr_len = 0, i = 0; 618 while (count > 0) { 619 return_data[i] = (char *)malloc(len + 2); 620 memcpy(return_data[i], fdata + ptr_len, len); 621 return_data[i][len] = '\0'; 622 count -= (len); 623 ptr_len += (len); 624 if (count < len) { 625 if (count == 0) { 626 m_num_shader_strings = (i + 1); 627 break; 628 } 629 len = count; 630 } 631 ++i; 632 } 633 return return_data; 634} 635 636void VkTestFramework::FreeFileData(char **data) { 637 for (int i = 0; i < m_num_shader_strings; i++) free(data[i]); 638} 639 640// 641// Deduce the language from the filename. Files must end in one of the 642// following extensions: 643// 644// .vert = vertex 645// .tesc = tessellation control 646// .tese = tessellation evaluation 647// .geom = geometry 648// .frag = fragment 649// .comp = compute 650// 651EShLanguage VkTestFramework::FindLanguage(const std::string &name) { 652 size_t ext = name.rfind('.'); 653 if (ext == std::string::npos) { 654 return EShLangVertex; 655 } 656 657 std::string suffix = name.substr(ext + 1, std::string::npos); 658 if (suffix == "vert") 659 return EShLangVertex; 660 else if (suffix == "tesc") 661 return EShLangTessControl; 662 else if (suffix == "tese") 663 return EShLangTessEvaluation; 664 else if (suffix == "geom") 665 return EShLangGeometry; 666 else if (suffix == "frag") 667 return EShLangFragment; 668 else if (suffix == "comp") 669 return EShLangCompute; 670 671 return EShLangVertex; 672} 673 674// 675// Convert VK shader type to compiler's 676// 677EShLanguage VkTestFramework::FindLanguage(const VkShaderStageFlagBits shader_type) { 678 switch (shader_type) { 679 case VK_SHADER_STAGE_VERTEX_BIT: 680 return EShLangVertex; 681 682 case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: 683 return EShLangTessControl; 684 685 case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: 686 return EShLangTessEvaluation; 687 688 case VK_SHADER_STAGE_GEOMETRY_BIT: 689 return EShLangGeometry; 690 691 case VK_SHADER_STAGE_FRAGMENT_BIT: 692 return EShLangFragment; 693 694 case VK_SHADER_STAGE_COMPUTE_BIT: 695 return EShLangCompute; 696 697 default: 698 return EShLangVertex; 699 } 700} 701 702// 703// Compile a given string containing GLSL into SPV for use by VK 704// Return value of false means an error was encountered. 705// 706bool VkTestFramework::GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector<unsigned int> &spirv) { 707 glslang::TProgram program; 708 const char *shaderStrings[1]; 709 710 // TODO: Do we want to load a special config file depending on the 711 // shader source? Optional name maybe? 712 // SetConfigFile(fileName); 713 714 ProcessConfigFile(); 715 716 EShMessages messages = EShMsgDefault; 717 SetMessageOptions(messages); 718 messages = static_cast<EShMessages>(messages | EShMsgSpvRules | EShMsgVulkanRules); 719 720 EShLanguage stage = FindLanguage(shader_type); 721 glslang::TShader *shader = new glslang::TShader(stage); 722 723 shaderStrings[0] = pshader; 724 shader->setStrings(shaderStrings, 1); 725 726 if (!shader->parse(&Resources, (m_compile_options & EOptionDefaultDesktop) ? 110 : 100, false, messages)) { 727 if (!(m_compile_options & EOptionSuppressInfolog)) { 728 puts(shader->getInfoLog()); 729 puts(shader->getInfoDebugLog()); 730 } 731 732 return false; // something didn't work 733 } 734 735 program.addShader(shader); 736 737 // 738 // Program-level processing... 739 // 740 741 if (!program.link(messages)) { 742 if (!(m_compile_options & EOptionSuppressInfolog)) { 743 puts(shader->getInfoLog()); 744 puts(shader->getInfoDebugLog()); 745 } 746 747 return false; 748 } 749 750 if (m_compile_options & EOptionDumpReflection) { 751 program.buildReflection(); 752 program.dumpReflection(); 753 } 754 755 glslang::GlslangToSpv(*program.getIntermediate(stage), spirv); 756 757 // 758 // Test the different modes of SPIR-V modification 759 // 760 if (this->m_canonicalize_spv) { 761 spv::spirvbin_t(0).remap(spirv, spv::spirvbin_t::ALL_BUT_STRIP); 762 } 763 764 if (this->m_strip_spv) { 765 spv::spirvbin_t(0).remap(spirv, spv::spirvbin_t::STRIP); 766 } 767 768 if (this->m_do_everything_spv) { 769 spv::spirvbin_t(0).remap(spirv, spv::spirvbin_t::DO_EVERYTHING); 770 } 771 772 delete shader; 773 774 return true; 775} 776