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