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