• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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