blob: ca6dbf1d60d96fdcc6cec6ff388d000bdf70f571 [file] [log] [blame]
Tobin Ehlis35308dd2016-10-31 13:27:36 -06001#!/usr/bin/env python3
Shannon McPherson9a4ae982019-01-07 16:05:25 -07002# Copyright (c) 2015-2019 The Khronos Group Inc.
3# Copyright (c) 2015-2019 Valve Corporation
4# Copyright (c) 2015-2019 LunarG, Inc.
5# Copyright (c) 2015-2019 Google Inc.
Tobin Ehlis35308dd2016-10-31 13:27:36 -06006#
7# Licensed under the Apache License, Version 2.0 (the "License");
8# you may not use this file except in compliance with the License.
9# You may obtain a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS,
15# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16# See the License for the specific language governing permissions and
17# limitations under the License.
18#
19# Author: Tobin Ehlis <tobine@google.com>
Dave Houltoncacef472018-05-29 13:00:42 -060020# Author: Dave Houlton <daveh@lunarg.com>
Shannon McPherson3ea65132018-12-05 10:37:39 -070021# Author: Shannon McPherson <shannon@lunarg.com>
Tobin Ehlis35308dd2016-10-31 13:27:36 -060022
23import argparse
24import os
25import sys
Dave Houltoncacef472018-05-29 13:00:42 -060026import operator
Tobin Ehlis35308dd2016-10-31 13:27:36 -060027import platform
Dave Houltoncacef472018-05-29 13:00:42 -060028import json
29import re
30import csv
31import html
Dave Houlton729c7822018-11-19 11:52:23 -070032import time
Dave Houltoncacef472018-05-29 13:00:42 -060033from collections import defaultdict
Tobin Ehlis35308dd2016-10-31 13:27:36 -060034
Dave Houltoncacef472018-05-29 13:00:42 -060035verbose_mode = False
36txt_db = False
37csv_db = False
38html_db = False
39txt_filename = "validation_error_database.txt"
40csv_filename = "validation_error_database.csv"
41html_filename = "validation_error_database.html"
Dave Houlton407df732018-08-06 17:58:24 -060042header_filename = "../layers/vk_validation_error_messages.h"
Dave Houltoncacef472018-05-29 13:00:42 -060043test_file = '../tests/layer_validation_tests.cpp'
44vuid_prefixes = ['VUID-', 'UNASSIGNED-']
Tobin Ehlis35308dd2016-10-31 13:27:36 -060045
Dave Houltoncacef472018-05-29 13:00:42 -060046# Hard-coded flags that could be command line args, if we decide that's useful
47# replace KHR vuids with non-KHR during consistency checking
48dealias_khr = True
49ignore_unassigned = True # These are not found in layer code unless they appear explicitly (most don't), so produce false positives
50
Mark Lobodzinski05849f02017-06-21 14:44:14 -060051generated_layer_source_directories = [
52'build',
53'dbuild',
54'release',
Jasper St. Pierref5addf32019-01-18 13:56:42 -080055'../build/Vulkan-ValidationLayers/'
Mark Lobodzinski05849f02017-06-21 14:44:14 -060056]
57generated_layer_source_files = [
Mark Lobodzinskid4950072017-08-01 13:02:20 -060058'parameter_validation.cpp',
Mark Lobodzinski09fa2d42017-07-21 10:16:53 -060059'object_tracker.cpp',
Mark Lobodzinski05849f02017-06-21 14:44:14 -060060]
Tobin Ehlis35308dd2016-10-31 13:27:36 -060061layer_source_files = [
Shannon McPherson9a4ae982019-01-07 16:05:25 -070062'../layers/buffer_validation.cpp',
Mark Lobodzinskie3787b42017-06-21 13:41:00 -060063'../layers/core_validation.cpp',
64'../layers/descriptor_sets.cpp',
Shannon McPhersonde3eeba2019-04-30 16:53:59 -060065'../layers/drawdispatch.cpp',
Mark Lobodzinskid4950072017-08-01 13:02:20 -060066'../layers/parameter_validation_utils.cpp',
Mark Lobodzinskib2de97f2017-07-06 15:28:11 -060067'../layers/object_tracker_utils.cpp',
Mark Lobodzinskie3787b42017-06-21 13:41:00 -060068'../layers/shader_validation.cpp',
Shannon McPherson9a4ae982019-01-07 16:05:25 -070069'../layers/stateless_validation.h'
Tobin Ehlis35308dd2016-10-31 13:27:36 -060070]
Tobin Ehlis35308dd2016-10-31 13:27:36 -060071
Dave Houlton407df732018-08-06 17:58:24 -060072# This needs to be updated as new extensions roll in
Mark Lobodzinski02e23172019-03-04 15:27:55 -070073khr_aliases = {
74 'VUID-vkBindBufferMemory2KHR-device-parameter' : 'VUID-vkBindBufferMemory2-device-parameter',
75 'VUID-vkBindBufferMemory2KHR-pBindInfos-parameter' : 'VUID-vkBindBufferMemory2-pBindInfos-parameter',
76 'VUID-vkBindImageMemory2KHR-device-parameter' : 'VUID-vkBindImageMemory2-device-parameter',
77 'VUID-vkBindImageMemory2KHR-pBindInfos-parameter' : 'VUID-vkBindImageMemory2-pBindInfos-parameter',
78 'VUID-vkCmdDispatchBaseKHR-commandBuffer-parameter' : 'VUID-vkCmdDispatchBase-commandBuffer-parameter',
79 'VUID-vkCmdSetDeviceMaskKHR-commandBuffer-parameter' : 'VUID-vkCmdSetDeviceMask-commandBuffer-parameter',
80 'VUID-vkCreateDescriptorUpdateTemplateKHR-device-parameter' : 'VUID-vkCreateDescriptorUpdateTemplate-device-parameter',
81 'VUID-vkCreateDescriptorUpdateTemplateKHR-pDescriptorUpdateTemplate-parameter' : 'VUID-vkCreateDescriptorUpdateTemplate-pDescriptorUpdateTemplate-parameter',
82 'VUID-vkCreateSamplerYcbcrConversionKHR-device-parameter' : 'VUID-vkCreateSamplerYcbcrConversion-device-parameter',
83 'VUID-vkCreateSamplerYcbcrConversionKHR-pYcbcrConversion-parameter' : 'VUID-vkCreateSamplerYcbcrConversion-pYcbcrConversion-parameter',
84 'VUID-vkDestroyDescriptorUpdateTemplateKHR-descriptorUpdateTemplate-parameter' : 'VUID-vkDestroyDescriptorUpdateTemplate-descriptorUpdateTemplate-parameter',
Dave Houltoncacef472018-05-29 13:00:42 -060085 'VUID-vkDestroyDescriptorUpdateTemplateKHR-descriptorUpdateTemplate-parent' : 'VUID-vkDestroyDescriptorUpdateTemplate-descriptorUpdateTemplate-parent',
Mark Lobodzinski02e23172019-03-04 15:27:55 -070086 'VUID-vkDestroyDescriptorUpdateTemplateKHR-device-parameter' : 'VUID-vkDestroyDescriptorUpdateTemplate-device-parameter',
87 'VUID-vkDestroySamplerYcbcrConversionKHR-device-parameter' : 'VUID-vkDestroySamplerYcbcrConversion-device-parameter',
88 'VUID-vkDestroySamplerYcbcrConversionKHR-ycbcrConversion-parameter' : 'VUID-vkDestroySamplerYcbcrConversion-ycbcrConversion-parameter',
Dave Houltoncacef472018-05-29 13:00:42 -060089 'VUID-vkDestroySamplerYcbcrConversionKHR-ycbcrConversion-parent' : 'VUID-vkDestroySamplerYcbcrConversion-ycbcrConversion-parent',
Mark Lobodzinski02e23172019-03-04 15:27:55 -070090 'VUID-vkEnumeratePhysicalDeviceGroupsKHR-instance-parameter' : 'VUID-vkEnumeratePhysicalDeviceGroups-instance-parameter',
91 'VUID-vkEnumeratePhysicalDeviceGroupsKHR-pPhysicalDeviceGroupProperties-parameter' : 'VUID-vkEnumeratePhysicalDeviceGroups-pPhysicalDeviceGroupProperties-parameter',
92 'VUID-vkGetBufferMemoryRequirements2KHR-device-parameter' : 'VUID-vkGetBufferMemoryRequirements2-device-parameter',
93 'VUID-vkGetDescriptorSetLayoutSupportKHR-device-parameter' : 'VUID-vkGetDescriptorSetLayoutSupport-device-parameter',
94 'VUID-vkGetDeviceGroupPeerMemoryFeaturesKHR-device-parameter' : 'VUID-vkGetDeviceGroupPeerMemoryFeatures-device-parameter',
95 'VUID-vkGetDeviceGroupPeerMemoryFeaturesKHR-pPeerMemoryFeatures-parameter' : 'VUID-vkGetDeviceGroupPeerMemoryFeatures-pPeerMemoryFeatures-parameter',
96 'VUID-vkGetImageMemoryRequirements2KHR-device-parameter' : 'VUID-vkGetImageMemoryRequirements2-device-parameter',
97 'VUID-vkGetImageSparseMemoryRequirements2KHR-device-parameter' : 'VUID-vkGetImageSparseMemoryRequirements2-device-parameter',
98 'VUID-vkGetImageSparseMemoryRequirements2KHR-pSparseMemoryRequirements-parameter' : 'VUID-vkGetImageSparseMemoryRequirements2-pSparseMemoryRequirements-parameter',
99 'VUID-vkGetPhysicalDeviceExternalBufferPropertiesKHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceExternalBufferProperties-physicalDevice-parameter',
100 'VUID-vkGetPhysicalDeviceExternalFencePropertiesKHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceExternalFenceProperties-physicalDevice-parameter',
101 'VUID-vkGetPhysicalDeviceExternalSemaphorePropertiesKHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceExternalSemaphoreProperties-physicalDevice-parameter',
102 'VUID-vkGetPhysicalDeviceFeatures2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceFeatures2-physicalDevice-parameter',
103 'VUID-vkGetPhysicalDeviceFormatProperties2KHR-format-parameter' : 'VUID-vkGetPhysicalDeviceFormatProperties2-format-parameter',
104 'VUID-vkGetPhysicalDeviceFormatProperties2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceFormatProperties2-physicalDevice-parameter',
105 'VUID-vkGetPhysicalDeviceImageFormatProperties2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceImageFormatProperties2-physicalDevice-parameter',
106 'VUID-vkGetPhysicalDeviceMemoryProperties2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceMemoryProperties2-physicalDevice-parameter',
107 'VUID-vkGetPhysicalDeviceProperties2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceProperties2-physicalDevice-parameter',
108 'VUID-vkGetPhysicalDeviceQueueFamilyProperties2KHR-pQueueFamilyProperties-parameter' : 'VUID-vkGetPhysicalDeviceQueueFamilyProperties2-pQueueFamilyProperties-parameter',
109 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2KHR-pProperties-parameter' : 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2-pProperties-parameter',
110 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2-physicalDevice-parameter',
111 'VUID-vkTrimCommandPoolKHR-commandPool-parameter' : 'VUID-vkTrimCommandPool-commandPool-parameter',
Dave Houltoncacef472018-05-29 13:00:42 -0600112 'VUID-vkTrimCommandPoolKHR-commandPool-parent' : 'VUID-vkTrimCommandPool-commandPool-parent',
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700113 'VUID-vkTrimCommandPoolKHR-device-parameter' : 'VUID-vkTrimCommandPool-device-parameter',
Dave Houltoncacef472018-05-29 13:00:42 -0600114 'VUID-vkTrimCommandPoolKHR-flags-zerobitmask' : 'VUID-vkTrimCommandPool-flags-zerobitmask',
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700115 'VUID-vkUpdateDescriptorSetWithTemplateKHR-descriptorSet-parameter' : 'VUID-vkUpdateDescriptorSetWithTemplate-descriptorSet-parameter',
116 'VUID-vkUpdateDescriptorSetWithTemplateKHR-descriptorUpdateTemplate-parameter' : 'VUID-vkUpdateDescriptorSetWithTemplate-descriptorUpdateTemplate-parameter',
Dave Houltoncacef472018-05-29 13:00:42 -0600117 'VUID-vkUpdateDescriptorSetWithTemplateKHR-descriptorUpdateTemplate-parent' : 'VUID-vkUpdateDescriptorSetWithTemplate-descriptorUpdateTemplate-parent',
118 'VUID-vkUpdateDescriptorSetWithTemplateKHR-device-parameter' : 'VUID-vkUpdateDescriptorSetWithTemplate-device-parameter',
119 'VUID-vkCreateDescriptorUpdateTemplateKHR-pCreateInfo-parameter' : 'VUID-vkCreateDescriptorUpdateTemplate-pCreateInfo-parameter',
120 'VUID-vkCreateSamplerYcbcrConversionKHR-pCreateInfo-parameter' : 'VUID-vkCreateSamplerYcbcrConversion-pCreateInfo-parameter',
121 'VUID-vkGetBufferMemoryRequirements2KHR-pInfo-parameter' : 'VUID-vkGetBufferMemoryRequirements2-pInfo-parameter',
122 'VUID-vkGetBufferMemoryRequirements2KHR-pMemoryRequirements-parameter' : 'VUID-vkGetBufferMemoryRequirements2-pMemoryRequirements-parameter',
123 'VUID-vkGetDescriptorSetLayoutSupportKHR-pCreateInfo-parameter' : 'VUID-vkGetDescriptorSetLayoutSupport-pCreateInfo-parameter',
124 'VUID-vkGetDescriptorSetLayoutSupportKHR-pSupport-parameter' : 'VUID-vkGetDescriptorSetLayoutSupport-pSupport-parameter',
125 'VUID-vkGetImageMemoryRequirements2KHR-pInfo-parameter' : 'VUID-vkGetImageMemoryRequirements2-pInfo-parameter',
126 'VUID-vkGetImageMemoryRequirements2KHR-pMemoryRequirements-parameter' : 'VUID-vkGetImageMemoryRequirements2-pMemoryRequirements-parameter',
127 'VUID-vkGetImageSparseMemoryRequirements2KHR-pInfo-parameter' : 'VUID-vkGetImageSparseMemoryRequirements2-pInfo-parameter',
128 'VUID-vkGetPhysicalDeviceExternalBufferPropertiesKHR-pExternalBufferInfo-parameter' : 'VUID-vkGetPhysicalDeviceExternalBufferProperties-pExternalBufferInfo-parameter',
129 'VUID-vkGetPhysicalDeviceExternalBufferPropertiesKHR-pExternalBufferProperties-parameter' : 'VUID-vkGetPhysicalDeviceExternalBufferProperties-pExternalBufferProperties-parameter',
130 'VUID-vkGetPhysicalDeviceExternalFencePropertiesKHR-pExternalFenceInfo-parameter' : 'VUID-vkGetPhysicalDeviceExternalFenceProperties-pExternalFenceInfo-parameter',
131 'VUID-vkGetPhysicalDeviceExternalFencePropertiesKHR-pExternalFenceProperties-parameter' : 'VUID-vkGetPhysicalDeviceExternalFenceProperties-pExternalFenceProperties-parameter',
132 'VUID-vkGetPhysicalDeviceExternalSemaphorePropertiesKHR-pExternalSemaphoreInfo-parameter' : 'VUID-vkGetPhysicalDeviceExternalSemaphoreProperties-pExternalSemaphoreInfo-parameter',
133 'VUID-vkGetPhysicalDeviceExternalSemaphorePropertiesKHR-pExternalSemaphoreProperties-parameter' : 'VUID-vkGetPhysicalDeviceExternalSemaphoreProperties-pExternalSemaphoreProperties-parameter',
134 'VUID-vkGetPhysicalDeviceFeatures2KHR-pFeatures-parameter' : 'VUID-vkGetPhysicalDeviceFeatures2-pFeatures-parameter',
135 'VUID-vkGetPhysicalDeviceFormatProperties2KHR-pFormatProperties-parameter' : 'VUID-vkGetPhysicalDeviceFormatProperties2-pFormatProperties-parameter',
136 'VUID-vkGetPhysicalDeviceImageFormatProperties2KHR-pImageFormatInfo-parameter' : 'VUID-vkGetPhysicalDeviceImageFormatProperties2-pImageFormatInfo-parameter',
137 'VUID-vkGetPhysicalDeviceImageFormatProperties2KHR-pImageFormatProperties-parameter' : 'VUID-vkGetPhysicalDeviceImageFormatProperties2-pImageFormatProperties-parameter',
138 'VUID-vkGetPhysicalDeviceMemoryProperties2KHR-pMemoryProperties-parameter' : 'VUID-vkGetPhysicalDeviceMemoryProperties2-pMemoryProperties-parameter',
139 'VUID-vkGetPhysicalDeviceProperties2KHR-pProperties-parameter' : 'VUID-vkGetPhysicalDeviceProperties2-pProperties-parameter',
140 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2KHR-pFormatInfo-parameter' : 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2-pFormatInfo-parameter' }
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600141
Dave Houltoncacef472018-05-29 13:00:42 -0600142def printHelp():
143 print ("Usage:")
144 print (" python vk_validation_stats.py <json_file>")
145 print (" [ -c ]")
146 print (" [ -todo ]")
147 print (" [ -vuid <vuid_name> ]")
148 print (" [ -text [ <text_out_filename>] ]")
149 print (" [ -csv [ <csv_out_filename>] ]")
150 print (" [ -html [ <html_out_filename>] ]")
Dave Houlton407df732018-08-06 17:58:24 -0600151 print (" [ -export_header ]")
Dave Houltoncacef472018-05-29 13:00:42 -0600152 print (" [ -verbose ]")
153 print (" [ -help ]")
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700154 print ("\n The vk_validation_stats script parses validation layer source files to")
155 print (" determine the set of valid usage checks and tests currently implemented,")
Dave Houltoncacef472018-05-29 13:00:42 -0600156 print (" and generates coverage values by comparing against the full set of valid")
157 print (" usage identifiers in the Vulkan-Headers registry file 'validusage.json'")
158 print ("\nArguments: ")
159 print (" <json-file> (required) registry file 'validusage.json'")
160 print (" -c report consistency warnings")
161 print (" -todo report unimplemented VUIDs")
162 print (" -vuid <vuid_name> report status of individual VUID <vuid_name>")
163 print (" -text [filename] output the error database text to <text_database_filename>,")
164 print (" defaults to 'validation_error_database.txt'")
165 print (" -csv [filename] output the error database in csv to <csv_database_filename>,")
166 print (" defaults to 'validation_error_database.csv'")
167 print (" -html [filename] output the error database in html to <html_database_filename>,")
168 print (" defaults to 'validation_error_database.html'")
Dave Houlton407df732018-08-06 17:58:24 -0600169 print (" -export_header export a new VUID error text header file to <%s>" % header_filename)
Dave Houltoncacef472018-05-29 13:00:42 -0600170 print (" -verbose show your work (to stdout)")
171
172class ValidationJSON:
173 def __init__(self, filename):
174 self.filename = filename
175 self.explicit_vuids = set()
176 self.implicit_vuids = set()
177 self.all_vuids = set()
178 self.vuid_db = defaultdict(list) # Maps VUID string to list of json-data dicts
179 self.apiversion = ""
Dave Houltoncacef472018-05-29 13:00:42 -0600180 self.duplicate_vuids = set()
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700181
Dave Houlton407df732018-08-06 17:58:24 -0600182 # A set of specific regular expression substitutions needed to clean up VUID text
183 self.regex_dict = {}
184 self.regex_dict[re.compile('<.*?>|&(amp;)+lt;|&(amp;)+gt;')] = ""
185 self.regex_dict[re.compile(r'\\\(codeSize \\over 4\\\)')] = "(codeSize/4)"
Shannon McPherson3ea65132018-12-05 10:37:39 -0700186 self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{height}{maxFragmentDensityTexelSize_{height}}}\\rceil\\\)')] = "the ceiling of height/maxFragmentDensityTexelSize.height"
187 self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{width}{maxFragmentDensityTexelSize_{width}}}\\rceil\\\)')] = "the ceiling of width/maxFragmentDensityTexelSize.width"
188 self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{maxFramebufferHeight}{minFragmentDensityTexelSize_{height}}}\\rceil\\\)')] = "the ceiling of maxFramebufferHeight/minFragmentDensityTexelSize.height"
189 self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{maxFramebufferWidth}{minFragmentDensityTexelSize_{width}}}\\rceil\\\)')] = "the ceiling of maxFramebufferWidth/minFragmentDensityTexelSize.width"
Dave Houlton407df732018-08-06 17:58:24 -0600190 self.regex_dict[re.compile(r'\\\(\\lceil\{\\mathit\{rasterizationSamples} \\over 32}\\rceil\\\)')] = "(rasterizationSamples/32)"
Shannon McPhersonb40f1a22018-10-30 16:45:07 -0600191 self.regex_dict[re.compile(r'\\\(\\textrm\{codeSize} \\over 4\\\)')] = "(codeSize/4)"
Dave Houlton407df732018-08-06 17:58:24 -0600192 # Some fancy punctuation chars that break the Android build...
193 self.regex_dict[re.compile('&#8594;')] = "->" # Arrow char
194 self.regex_dict[re.compile('&#8217;')] = "'" # Left-slanting apostrophe to apostrophe
195 self.regex_dict[re.compile('&#822(0|1);')] = "'" # L/R-slanting quotes to apostrophe
Dave Houltoncacef472018-05-29 13:00:42 -0600196
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600197 def read(self):
Dave Houltoncacef472018-05-29 13:00:42 -0600198 self.json_dict = {}
199 if os.path.isfile(self.filename):
Dave Houlton407df732018-08-06 17:58:24 -0600200 json_file = open(self.filename, 'r', encoding='utf-8')
Dave Houltoncacef472018-05-29 13:00:42 -0600201 self.json_dict = json.load(json_file)
202 json_file.close()
203 if len(self.json_dict) == 0:
204 print("Error: Error loading validusage.json file <%s>" % self.filename)
205 sys.exit(-1)
206 try:
207 version = self.json_dict['version info']
208 validation = self.json_dict['validation']
209 self.apiversion = version['api version']
210 except:
211 print("Error: Failure parsing validusage.json object")
212 sys.exit(-1)
213
214 # Parse vuid from json into local databases
215 for apiname in validation.keys():
216 # print("entrypoint:%s"%apiname)
217 apidict = validation[apiname]
218 for ext in apidict.keys():
219 vlist = apidict[ext]
220 for ventry in vlist:
221 vuid_string = ventry['vuid']
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700222 if (vuid_string[-5:-1].isdecimal()):
Dave Houltoncacef472018-05-29 13:00:42 -0600223 self.explicit_vuids.add(vuid_string) # explicit end in 5 numeric chars
224 vtype = 'explicit'
225 else:
226 self.implicit_vuids.add(vuid_string) # otherwise, implicit
227 vtype = 'implicit'
228 vuid_text = ventry['text']
Dave Houlton407df732018-08-06 17:58:24 -0600229 for regex, replacement in self.regex_dict.items():
230 vuid_text = re.sub(regex, replacement, vuid_text) # do regex substitution
231 vuid_text = html.unescape(vuid_text) # anything missed by the regex
232 self.vuid_db[vuid_string].append({'api':apiname, 'ext':ext, 'type':vtype, 'text':vuid_text})
Dave Houltoncacef472018-05-29 13:00:42 -0600233 self.all_vuids = self.explicit_vuids | self.implicit_vuids
234 self.duplicate_vuids = set({v for v in self.vuid_db if len(self.vuid_db[v]) > 1})
Dave Houlton407df732018-08-06 17:58:24 -0600235 if len(self.duplicate_vuids) > 0:
236 print("Warning: duplicate VUIDs found in validusage.json")
237
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600238
239class ValidationSource:
Mark Lobodzinski05849f02017-06-21 14:44:14 -0600240 def __init__(self, source_file_list, generated_source_file_list, generated_source_directories):
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600241 self.source_files = source_file_list
Mark Lobodzinski05849f02017-06-21 14:44:14 -0600242 self.generated_source_files = generated_source_file_list
243 self.generated_source_dirs = generated_source_directories
Dave Houltoncacef472018-05-29 13:00:42 -0600244 self.vuid_count_dict = {} # dict of vuid values to the count of how much they're used, and location of where they're used
245 self.duplicated_checks = 0
246 self.explicit_vuids = set()
247 self.implicit_vuids = set()
248 self.unassigned_vuids = set()
249 self.all_vuids = set()
Mark Lobodzinski05849f02017-06-21 14:44:14 -0600250
251 if len(self.generated_source_files) > 0:
252 qualified_paths = []
253 for source in self.generated_source_files:
254 for build_dir in self.generated_source_dirs:
255 filepath = '../%s/layers/%s' % (build_dir, source)
256 if os.path.isfile(filepath):
257 qualified_paths.append(filepath)
John Zulaufdde04c42018-01-16 15:32:45 -0700258 break
Mark Lobodzinski05849f02017-06-21 14:44:14 -0600259 if len(self.generated_source_files) != len(qualified_paths):
Mark Lobodzinski2d193ac2017-06-27 09:38:15 -0600260 print("Error: Unable to locate one or more of the following source files in the %s directories" % (", ".join(generated_source_directories)))
Mark Lobodzinski05849f02017-06-21 14:44:14 -0600261 print(self.generated_source_files)
Dave Houltoncacef472018-05-29 13:00:42 -0600262 print("Failed to locate one or more codegen files in layer source code - cannot proceed.")
John Zulaufdde04c42018-01-16 15:32:45 -0700263 exit(1)
Mark Lobodzinski05849f02017-06-21 14:44:14 -0600264 else:
265 self.source_files.extend(qualified_paths)
266
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600267 def parse(self):
Dave Houltoncacef472018-05-29 13:00:42 -0600268 prepend = None
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600269 for sf in self.source_files:
Tobin Ehlis3d1f2bd2016-12-22 11:19:15 -0700270 line_num = 0
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600271 with open(sf) as f:
272 for line in f:
Tobin Ehlis3d1f2bd2016-12-22 11:19:15 -0700273 line_num = line_num + 1
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600274 if True in [line.strip().startswith(comment) for comment in ['//', '/*']]:
275 continue
Dave Houltoncacef472018-05-29 13:00:42 -0600276 # Find vuid strings
Michał Janiszewski3c3ce9e2018-10-30 23:25:21 +0100277 if prepend is not None:
Dave Houltoncacef472018-05-29 13:00:42 -0600278 line = prepend[:-2] + line.lstrip().lstrip('"') # join lines skipping CR, whitespace and trailing/leading quote char
279 prepend = None
280 if any(prefix in line for prefix in vuid_prefixes):
Shannon McPhersondad26362019-06-12 10:51:46 -0600281 # Replace the '(' of lines containing validation helper functions with ' ' to make them easier to parse
282 line = line.replace("(", " ")
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600283 line_list = line.split()
Dave Houltoncacef472018-05-29 13:00:42 -0600284
285 # A VUID string that has been broken by clang will start with a vuid prefix and end with -, and will be last in the list
286 broken_vuid = line_list[-1].strip('"')
287 if any(broken_vuid.startswith(prefix) for prefix in vuid_prefixes) and broken_vuid.endswith('-'):
288 prepend = line
289 continue
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700290
Dave Houltoncacef472018-05-29 13:00:42 -0600291 vuid_list = []
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600292 for str in line_list:
Dave Houltoncacef472018-05-29 13:00:42 -0600293 if any(prefix in str for prefix in vuid_prefixes):
294 vuid_list.append(str.strip(',);{}"'))
295 for vuid in vuid_list:
296 if vuid not in self.vuid_count_dict:
297 self.vuid_count_dict[vuid] = {}
298 self.vuid_count_dict[vuid]['count'] = 1
299 self.vuid_count_dict[vuid]['file_line'] = []
300 else:
301 if self.vuid_count_dict[vuid]['count'] == 1: # only count first time duplicated
302 self.duplicated_checks = self.duplicated_checks + 1
303 self.vuid_count_dict[vuid]['count'] = self.vuid_count_dict[vuid]['count'] + 1
304 self.vuid_count_dict[vuid]['file_line'].append('%s,%d' % (sf, line_num))
305 # Sort vuids by type
306 for vuid in self.vuid_count_dict.keys():
307 if (vuid.startswith('VUID-')):
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700308 if (vuid[-5:-1].isdecimal()):
Dave Houltoncacef472018-05-29 13:00:42 -0600309 self.explicit_vuids.add(vuid) # explicit end in 5 numeric chars
310 else:
311 self.implicit_vuids.add(vuid)
312 elif (vuid.startswith('UNASSIGNED-')):
313 self.unassigned_vuids.add(vuid)
314 else:
315 print("Unable to categorize VUID: %s" % vuid)
316 print("Confused while parsing VUIDs in layer source code - cannot proceed. (FIXME)")
317 exit(-1)
318 self.all_vuids = self.explicit_vuids | self.implicit_vuids | self.unassigned_vuids
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600319
320# Class to parse the validation layer test source and store testnames
Dave Houltoncacef472018-05-29 13:00:42 -0600321class ValidationTests:
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600322 def __init__(self, test_file_list, test_group_name=['VkLayerTest', 'VkPositiveLayerTest', 'VkWsiEnabledLayerTest']):
323 self.test_files = test_file_list
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600324 self.test_trigger_txt_list = []
325 for tg in test_group_name:
326 self.test_trigger_txt_list.append('TEST_F(%s' % tg)
Dave Houltoncacef472018-05-29 13:00:42 -0600327 self.explicit_vuids = set()
328 self.implicit_vuids = set()
329 self.unassigned_vuids = set()
330 self.all_vuids = set()
331 #self.test_to_vuids = {} # Map test name to VUIDs tested
332 self.vuid_to_tests = defaultdict(set) # Map VUIDs to set of test names where implemented
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600333
334 # Parse test files into internal data struct
335 def parse(self):
336 # For each test file, parse test names into set
337 grab_next_line = False # handle testname on separate line than wildcard
Tobin Ehlis9a68c982016-12-29 14:51:17 -0700338 testname = ''
Dave Houltoncacef472018-05-29 13:00:42 -0600339 prepend = None
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600340 for test_file in self.test_files:
341 with open(test_file) as tf:
342 for line in tf:
343 if True in [line.strip().startswith(comment) for comment in ['//', '/*']]:
344 continue
345
Dave Houltoncacef472018-05-29 13:00:42 -0600346 # if line ends in a broken VUID string, fix that before proceeding
Michał Janiszewski3c3ce9e2018-10-30 23:25:21 +0100347 if prepend is not None:
Dave Houltoncacef472018-05-29 13:00:42 -0600348 line = prepend[:-2] + line.lstrip().lstrip('"') # join lines skipping CR, whitespace and trailing/leading quote char
349 prepend = None
350 if any(prefix in line for prefix in vuid_prefixes):
351 line_list = line.split()
352
353 # A VUID string that has been broken by clang will start with a vuid prefix and end with -, and will be last in the list
354 broken_vuid = line_list[-1].strip('"')
355 if any(broken_vuid.startswith(prefix) for prefix in vuid_prefixes) and broken_vuid.endswith('-'):
356 prepend = line
357 continue
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700358
Dave Houltoncacef472018-05-29 13:00:42 -0600359 if any(ttt in line for ttt in self.test_trigger_txt_list):
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600360 testname = line.split(',')[-1]
361 testname = testname.strip().strip(' {)')
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600362 if ('' == testname):
363 grab_next_line = True
364 continue
Dave Houltoncacef472018-05-29 13:00:42 -0600365 #self.test_to_vuids[testname] = []
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600366 if grab_next_line: # test name on its own line
367 grab_next_line = False
368 testname = testname.strip().strip(' {)')
Dave Houltoncacef472018-05-29 13:00:42 -0600369 #self.test_to_vuids[testname] = []
370 if any(prefix in line for prefix in vuid_prefixes):
371 line_list = re.split('[\s{}[\]()"]+',line)
Tobin Ehlis71f38c12017-01-12 14:26:56 -0700372 for sub_str in line_list:
Dave Houltoncacef472018-05-29 13:00:42 -0600373 if any(prefix in sub_str for prefix in vuid_prefixes):
374 vuid_str = sub_str.strip(',);:"')
375 self.vuid_to_tests[vuid_str].add(testname)
376 #self.test_to_vuids[testname].append(vuid_str)
377 if (vuid_str.startswith('VUID-')):
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700378 if (vuid_str[-5:-1].isdecimal()):
Dave Houltoncacef472018-05-29 13:00:42 -0600379 self.explicit_vuids.add(vuid_str) # explicit end in 5 numeric chars
380 else:
381 self.implicit_vuids.add(vuid_str)
382 elif (vuid_str.startswith('UNASSIGNED-')):
383 self.unassigned_vuids.add(vuid_str)
384 else:
385 print("Unable to categorize VUID: %s" % vuid_str)
386 print("Confused while parsing VUIDs in test code - cannot proceed. (FIXME)")
387 exit(-1)
388 self.all_vuids = self.explicit_vuids | self.implicit_vuids | self.unassigned_vuids
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600389
Dave Houltoncacef472018-05-29 13:00:42 -0600390# Class to do consistency checking
391#
392class Consistency:
393 def __init__(self, all_json, all_checks, all_tests):
394 self.valid = all_json
395 self.checks = all_checks
396 self.tests = all_tests
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600397
Dave Houltoncacef472018-05-29 13:00:42 -0600398 if (dealias_khr):
399 dk = set()
400 for vuid in self.checks:
401 if vuid in khr_aliases:
402 dk.add(khr_aliases[vuid])
403 else:
404 dk.add(vuid)
405 self.checks = dk
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600406
Dave Houltoncacef472018-05-29 13:00:42 -0600407 dk = set()
408 for vuid in self.tests:
409 if vuid in khr_aliases:
410 dk.add(khr_aliases[vuid])
411 else:
412 dk.add(vuid)
413 self.tests = dk
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600414
Dave Houltoncacef472018-05-29 13:00:42 -0600415 # Report undefined VUIDs in source code
416 def undef_vuids_in_layer_code(self):
417 undef_set = self.checks - self.valid
418 undef_set.discard('VUID-Undefined') # don't report Undefined
419 if ignore_unassigned:
420 unassigned = set({uv for uv in undef_set if uv.startswith('UNASSIGNED-')})
421 undef_set = undef_set - unassigned
422 if (len(undef_set) > 0):
423 print("\nFollowing VUIDs found in layer code are not defined in validusage.json (%d):" % len(undef_set))
424 undef = list(undef_set)
425 undef.sort()
426 for vuid in undef:
427 print(" %s" % vuid)
428 return False
429 return True
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600430
Dave Houltoncacef472018-05-29 13:00:42 -0600431 # Report undefined VUIDs in tests
432 def undef_vuids_in_tests(self):
433 undef_set = self.tests - self.valid
434 undef_set.discard('VUID-Undefined') # don't report Undefined
435 if ignore_unassigned:
436 unassigned = set({uv for uv in undef_set if uv.startswith('UNASSIGNED-')})
437 undef_set = undef_set - unassigned
438 if (len(undef_set) > 0):
439 ok = False
440 print("\nFollowing VUIDs found in layer tests are not defined in validusage.json (%d):" % len(undef_set))
441 undef = list(undef_set)
442 undef.sort()
443 for vuid in undef:
444 print(" %s" % vuid)
445 return False
446 return True
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600447
Dave Houltoncacef472018-05-29 13:00:42 -0600448 # Report vuids in tests that are not in source
449 def vuids_tested_not_checked(self):
450 undef_set = self.tests - self.checks
451 undef_set.discard('VUID-Undefined') # don't report Undefined
452 if ignore_unassigned:
453 unassigned = set()
454 for vuid in undef_set:
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700455 if vuid.startswith('UNASSIGNED-'):
Dave Houltoncacef472018-05-29 13:00:42 -0600456 unassigned.add(vuid)
457 undef_set = undef_set - unassigned
458 if (len(undef_set) > 0):
459 ok = False
460 print("\nFollowing VUIDs found in tests but are not checked in layer code (%d):" % len(undef_set))
461 undef = list(undef_set)
462 undef.sort()
463 for vuid in undef:
464 print(" %s" % vuid)
465 return False
466 return True
467
468 # TODO: Explicit checked VUIDs which have no test
469 # def explicit_vuids_checked_not_tested(self):
470
471
472# Class to output database in various flavors
473#
474class OutputDatabase:
475 def __init__(self, val_json, val_source, val_tests):
476 self.vj = val_json
477 self.vs = val_source
478 self.vt = val_tests
Dave Houlton729c7822018-11-19 11:52:23 -0700479 self.header_version = "/* THIS FILE IS GENERATED - DO NOT EDIT (scripts/vk_validation_stats.py) */"
480 self.header_version += "\n/* Vulkan specification version: %s */" % val_json.apiversion
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700481 self.header_version += "\n/* Header generated: %s */\n" % time.strftime('%Y-%m-%d %H:%M:%S')
Dave Houlton729c7822018-11-19 11:52:23 -0700482 self.header_preamble = """
Dave Houlton407df732018-08-06 17:58:24 -0600483/*
484 * Vulkan
485 *
Jasper St. Pierre1948bcc2019-01-18 13:55:20 -0800486 * Copyright (c) 2016-2019 Google Inc.
487 * Copyright (c) 2016-2019 LunarG, Inc.
Dave Houlton407df732018-08-06 17:58:24 -0600488 *
489 * Licensed under the Apache License, Version 2.0 (the "License");
490 * you may not use this file except in compliance with the License.
491 * You may obtain a copy of the License at
492 *
493 * http://www.apache.org/licenses/LICENSE-2.0
494 *
495 * Unless required by applicable law or agreed to in writing, software
496 * distributed under the License is distributed on an "AS IS" BASIS,
497 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
498 * See the License for the specific language governing permissions and
499 * limitations under the License.
500 *
501 * Author: Tobin Ehlis <tobine@google.com>
502 * Author: Dave Houlton <daveh@lunarg.com>
503 */
504
505#pragma once
506
507// Disable auto-formatting for generated file
508// clang-format off
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700509
Dave Houlton407df732018-08-06 17:58:24 -0600510// Mapping from VUID string to the corresponding spec text
Dave Houlton4d9b2f82018-10-24 18:21:06 -0600511typedef struct _vuid_spec_text_pair {
512 const char * vuid;
513 const char * spec_text;
514} vuid_spec_text_pair;
515
516static const vuid_spec_text_pair vuid_spec_text[] = {
Dave Houlton407df732018-08-06 17:58:24 -0600517"""
518 self.header_postamble = """};
Dave Houlton4d9b2f82018-10-24 18:21:06 -0600519"""
Dave Houlton407df732018-08-06 17:58:24 -0600520 self.spec_url = "https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html"
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700521
Dave Houltoncacef472018-05-29 13:00:42 -0600522 def dump_txt(self):
523 print("\n Dumping database to text file: %s" % txt_filename)
524 with open (txt_filename, 'w') as txt:
525 txt.write("## VUID Database\n")
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700526 txt.write("## Format: VUID_NAME | CHECKED | TEST | TYPE | API/STRUCT | EXTENSION | VUID_TEXT\n##\n")
Dave Houltoncacef472018-05-29 13:00:42 -0600527 vuid_list = list(self.vj.all_vuids)
528 vuid_list.sort()
529 for vuid in vuid_list:
530 db_list = self.vj.vuid_db[vuid]
531 db_list.sort(key=operator.itemgetter('ext')) # sort list to ease diffs of output file
532 for db_entry in db_list:
533 checked = 'N'
534 if vuid in self.vs.all_vuids:
535 checked = 'Y'
536 test = 'None'
537 if vuid in self.vt.vuid_to_tests:
538 test_list = list(self.vt.vuid_to_tests[vuid])
539 test_list.sort() # sort tests, for diff-ability
540 sep = ', '
541 test = sep.join(test_list)
542
543 txt.write("%s | %s | %s | %s | %s | %s | %s\n" % (vuid, checked, test, db_entry['type'], db_entry['api'], db_entry['ext'], db_entry['text']))
544
545 def dump_csv(self):
546 print("\n Dumping database to csv file: %s" % csv_filename)
547 with open (csv_filename, 'w', newline='') as csvfile:
548 cw = csv.writer(csvfile)
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700549 cw.writerow(['VUID_NAME','CHECKED','TEST','TYPE','API/STRUCT','EXTENSION','VUID_TEXT'])
Dave Houltoncacef472018-05-29 13:00:42 -0600550 vuid_list = list(self.vj.all_vuids)
551 vuid_list.sort()
552 for vuid in vuid_list:
553 for db_entry in self.vj.vuid_db[vuid]:
554 row = [vuid]
555 if vuid in self.vs.all_vuids:
556 row.append('Y')
557 else:
558 row.append('N')
559 test = 'None'
560 if vuid in self.vt.vuid_to_tests:
561 sep = ', '
562 test = sep.join(self.vt.vuid_to_tests[vuid])
563 row.append(test)
564 row.append(db_entry['type'])
565 row.append(db_entry['api'])
566 row.append(db_entry['ext'])
567 row.append(db_entry['text'])
568 cw.writerow(row)
569
570 def dump_html(self):
571 print("\n Dumping database to html file: %s" % html_filename)
572 preamble = '<!DOCTYPE html>\n<html>\n<head>\n<style>\ntable, th, td {\n border: 1px solid black;\n border-collapse: collapse; \n}\n</style>\n<body>\n<h2>Valid Usage Database</h2>\n<font size="2" face="Arial">\n<table style="width:100%">\n'
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700573 headers = '<tr><th>VUID NAME</th><th>CHECKED</th><th>TEST</th><th>TYPE</th><th>API/STRUCT</th><th>EXTENSION</th><th>VUID TEXT</th></tr>\n'
Dave Houltoncacef472018-05-29 13:00:42 -0600574 with open (html_filename, 'w') as hfile:
575 hfile.write(preamble)
576 hfile.write(headers)
577 vuid_list = list(self.vj.all_vuids)
578 vuid_list.sort()
579 for vuid in vuid_list:
580 for db_entry in self.vj.vuid_db[vuid]:
581 hfile.write('<tr><th>%s</th>' % vuid)
582 checked = '<span style="color:red;">N</span>'
583 if vuid in self.vs.all_vuids:
584 checked = '<span style="color:limegreen;">Y</span>'
585 hfile.write('<th>%s</th>' % checked)
586 test = 'None'
587 if vuid in self.vt.vuid_to_tests:
588 sep = ', '
589 test = sep.join(self.vt.vuid_to_tests[vuid])
590 hfile.write('<th>%s</th>' % test)
591 hfile.write('<th>%s</th>' % db_entry['type'])
592 hfile.write('<th>%s</th>' % db_entry['api'])
593 hfile.write('<th>%s</th>' % db_entry['ext'])
594 hfile.write('<th>%s</th></tr>\n' % db_entry['text'])
595 hfile.write('</table>\n</body>\n</html>\n')
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600596
Dave Houlton407df732018-08-06 17:58:24 -0600597 def export_header(self):
598 print("\n Exporting header file to: %s" % header_filename)
599 with open (header_filename, 'w') as hfile:
Dave Houlton729c7822018-11-19 11:52:23 -0700600 hfile.write(self.header_version)
Dave Houlton407df732018-08-06 17:58:24 -0600601 hfile.write(self.header_preamble)
602 vuid_list = list(self.vj.all_vuids)
603 vuid_list.sort()
John Zulaufd09ba822019-04-29 07:05:07 -0600604 cmd_dict = {}
Dave Houlton407df732018-08-06 17:58:24 -0600605 for vuid in vuid_list:
606 db_entry = self.vj.vuid_db[vuid][0]
John Zulaufd09ba822019-04-29 07:05:07 -0600607 db_text = db_entry['text'].strip(' ')
608 hfile.write(' {"%s", "%s (%s#%s)"},\n' % (vuid, db_text, self.spec_url, vuid))
Dave Houlton407df732018-08-06 17:58:24 -0600609 # For multiply-defined VUIDs, include versions with extension appended
610 if len(self.vj.vuid_db[vuid]) > 1:
611 for db_entry in self.vj.vuid_db[vuid]:
John Zulaufd09ba822019-04-29 07:05:07 -0600612 hfile.write(' {"%s[%s]", "%s (%s#%s)"},\n' % (vuid, db_entry['ext'].strip(' '), db_text, self.spec_url, vuid))
613 if 'commandBuffer must be in the recording state' in db_text:
614 cmd_dict[vuid] = db_text
Dave Houlton407df732018-08-06 17:58:24 -0600615 hfile.write(self.header_postamble)
616
John Zulaufd09ba822019-04-29 07:05:07 -0600617 # Generate the information for validating recording state VUID's
618 cmd_prefix = 'prefix##'
619 cmd_regex = re.compile(r'VUID-vk(Cmd|End)(\w+)')
620 cmd_vuid_vector = [' "VUID_Undefined"']
621 cmd_name_vector = [ ' "Command_Undefined"' ]
622 cmd_enum = [' ' + cmd_prefix + 'NONE = 0']
623
624 cmd_ordinal = 1
Mike Schuchardtaed5ac32019-06-21 09:03:31 -0700625 for vuid, db_text in sorted(cmd_dict.items()):
John Zulaufd09ba822019-04-29 07:05:07 -0600626 cmd_match = cmd_regex.match(vuid)
627 if cmd_match.group(1) == "End":
628 end = "END"
629 else:
630 end = ""
631 cmd_name_vector.append(' "vk'+ cmd_match.group(1) + cmd_match.group(2) + '"')
632 cmd_name = cmd_prefix + end + cmd_match.group(2).upper()
633 cmd_enum.append(' {} = {}'.format(cmd_name, cmd_ordinal))
634 cmd_ordinal += 1
635 cmd_vuid_vector.append(' "{}"'.format(vuid))
636
637 hfile.write('\n// Defines to allow creating "must be recording" meta data\n')
638 cmd_enum.append(' {}RANGE_SIZE = {}'.format(cmd_prefix, cmd_ordinal))
639 cmd_enum_string = '#define VUID_CMD_ENUM_LIST(prefix)\\\n' + ',\\\n'.join(cmd_enum) + '\n\n'
640 hfile.write(cmd_enum_string)
641 cmd_name_list_string = '#define VUID_CMD_NAME_LIST\\\n' + ',\\\n'.join(cmd_name_vector) + '\n\n'
642 hfile.write(cmd_name_list_string)
643 vuid_vector_string = '#define VUID_MUST_BE_RECORDING_LIST\\\n' + ',\\\n'.join(cmd_vuid_vector) + '\n'
644 hfile.write(vuid_vector_string)
645
Mark Lobodzinskib44c54a2017-06-12 12:02:38 -0600646def main(argv):
Dave Houltoncacef472018-05-29 13:00:42 -0600647 global verbose_mode
648 global txt_filename
649 global csv_filename
650 global html_filename
651
652 run_consistency = False
653 report_unimplemented = False
654 get_vuid_status = ''
655 txt_out = False
656 csv_out = False
657 html_out = False
Dave Houlton407df732018-08-06 17:58:24 -0600658 header_out = False
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700659
Dave Houltoncacef472018-05-29 13:00:42 -0600660 if (1 > len(argv)):
661 printHelp()
662 sys.exit()
663
664 # Parse script args
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700665 json_filename = argv[0]
Dave Houltoncacef472018-05-29 13:00:42 -0600666 i = 1
667 while (i < len(argv)):
668 arg = argv[i]
669 i = i + 1
670 if (arg == '-c'):
671 run_consistency = True
672 elif (arg == '-vuid'):
673 get_vuid_status = argv[i]
674 i = i + 1
675 elif (arg == '-todo'):
676 report_unimplemented = True
Karl Schultz49d66bb2018-07-09 16:24:46 -0600677 elif (arg == '-text'):
Dave Houltoncacef472018-05-29 13:00:42 -0600678 txt_out = True
679 # Set filename if supplied, else use default
680 if i < len(argv) and not argv[i].startswith('-'):
681 txt_filename = argv[i]
682 i = i + 1
683 elif (arg == '-csv'):
684 csv_out = True
685 # Set filename if supplied, else use default
686 if i < len(argv) and not argv[i].startswith('-'):
687 csv_filename = argv[i]
688 i = i + 1
689 elif (arg == '-html'):
690 html_out = True
691 # Set filename if supplied, else use default
692 if i < len(argv) and not argv[i].startswith('-'):
693 html_filename = argv[i]
694 i = i + 1
Dave Houlton407df732018-08-06 17:58:24 -0600695 elif (arg == '-export_header'):
696 header_out = True
Dave Houltoncacef472018-05-29 13:00:42 -0600697 elif (arg in ['-verbose']):
698 verbose_mode = True
699 elif (arg in ['-help', '-h']):
700 printHelp()
701 sys.exit()
702 else:
703 print("Unrecognized argument: %s\n" % arg)
704 printHelp()
705 sys.exit()
706
Tobin Ehlis20e32582016-12-05 14:50:03 -0700707 result = 0 # Non-zero result indicates an error case
Dave Houltoncacef472018-05-29 13:00:42 -0600708
709 # Parse validusage json
710 val_json = ValidationJSON(json_filename)
711 val_json.read()
712 exp_json = len(val_json.explicit_vuids)
713 imp_json = len(val_json.implicit_vuids)
714 all_json = len(val_json.all_vuids)
715 if verbose_mode:
716 print("Found %d unique error vuids in validusage.json file." % all_json)
717 print(" %d explicit" % exp_json)
718 print(" %d implicit" % imp_json)
719 if len(val_json.duplicate_vuids) > 0:
720 print("%d VUIDs appear in validusage.json more than once." % len(val_json.duplicate_vuids))
721 for vuid in val_json.duplicate_vuids:
722 print(" %s" % vuid)
723 for ext in val_json.vuid_db[vuid]:
724 print(" with extension: %s" % ext['ext'])
725
726 # Parse layer source files
Mark Lobodzinski05849f02017-06-21 14:44:14 -0600727 val_source = ValidationSource(layer_source_files, generated_layer_source_files, generated_layer_source_directories)
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600728 val_source.parse()
Dave Houltoncacef472018-05-29 13:00:42 -0600729 exp_checks = len(val_source.explicit_vuids)
730 imp_checks = len(val_source.implicit_vuids)
731 all_checks = len(val_source.vuid_count_dict.keys())
732 if verbose_mode:
733 print("Found %d unique vuid checks in layer source code." % all_checks)
734 print(" %d explicit" % exp_checks)
735 print(" %d implicit" % imp_checks)
736 print(" %d unassigned" % len(val_source.unassigned_vuids))
737 print(" %d checks are implemented more that once" % val_source.duplicated_checks)
738
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600739 # Parse test files
Dave Houltoncacef472018-05-29 13:00:42 -0600740 val_tests = ValidationTests([test_file, ])
741 val_tests.parse()
742 exp_tests = len(val_tests.explicit_vuids)
743 imp_tests = len(val_tests.implicit_vuids)
744 all_tests = len(val_tests.all_vuids)
Mark Lobodzinski060a8e32018-01-08 09:08:06 -0700745 if verbose_mode:
Dave Houltoncacef472018-05-29 13:00:42 -0600746 print("Found %d unique error vuids in test file %s." % (all_tests, test_file))
747 print(" %d explicit" % exp_tests)
748 print(" %d implicit" % imp_tests)
749 print(" %d unassigned" % len(val_tests.unassigned_vuids))
Mike Weiblenfe186122017-02-03 12:44:53 -0700750
Dave Houltoncacef472018-05-29 13:00:42 -0600751 # Process stats
752 print("\nValidation Statistics (using validusage.json version %s)" % val_json.apiversion)
753 print(" VUIDs defined in JSON file: %04d explicit, %04d implicit, %04d total." % (exp_json, imp_json, all_json))
754 print(" VUIDs checked in layer code: %04d explicit, %04d implicit, %04d total." % (exp_checks, imp_checks, all_checks))
755 print(" VUIDs tested in layer tests: %04d explicit, %04d implicit, %04d total." % (exp_tests, imp_tests, all_tests))
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700756
Dave Houltoncacef472018-05-29 13:00:42 -0600757 print("\nVUID check coverage")
758 print(" Explicit VUIDs checked: %.1f%% (%d checked vs %d defined)" % ((100.0 * exp_checks / exp_json), exp_checks, exp_json))
759 print(" Implicit VUIDs checked: %.1f%% (%d checked vs %d defined)" % ((100.0 * imp_checks / imp_json), imp_checks, imp_json))
760 print(" Overall VUIDs checked: %.1f%% (%d checked vs %d defined)" % ((100.0 * all_checks / all_json), all_checks, all_json))
Mike Weiblenfe186122017-02-03 12:44:53 -0700761
Dave Houltoncacef472018-05-29 13:00:42 -0600762 print("\nVUID test coverage")
763 print(" Explicit VUIDs tested: %.1f%% (%d tested vs %d checks)" % ((100.0 * exp_tests / exp_checks), exp_tests, exp_checks))
764 print(" Implicit VUIDs tested: %.1f%% (%d tested vs %d checks)" % ((100.0 * imp_tests / imp_checks), imp_tests, imp_checks))
765 print(" Overall VUIDs tested: %.1f%% (%d tested vs %d checks)" % ((100.0 * all_tests / all_checks), all_tests, all_checks))
Mike Weiblenfe186122017-02-03 12:44:53 -0700766
Dave Houltoncacef472018-05-29 13:00:42 -0600767 # Report status of a single VUID
768 if len(get_vuid_status) > 1:
769 print("\n\nChecking status of <%s>" % get_vuid_status);
770 if get_vuid_status not in val_json.all_vuids:
771 print(' Not a valid VUID string.')
772 else:
773 if get_vuid_status in val_source.explicit_vuids:
774 print(' Implemented!')
775 line_list = val_source.vuid_count_dict[get_vuid_status]['file_line']
776 for line in line_list:
777 print(' => %s' % line)
Dave Houltonf93bbab2018-06-26 17:21:12 -0600778 elif get_vuid_status in val_source.implicit_vuids:
779 print(' Implemented! (Implicit)')
780 line_list = val_source.vuid_count_dict[get_vuid_status]['file_line']
781 for line in line_list:
782 print(' => %s' % line)
Tobin Ehlis9a68c982016-12-29 14:51:17 -0700783 else:
Dave Houltoncacef472018-05-29 13:00:42 -0600784 print(' Not implemented.')
Dave Houltonf93bbab2018-06-26 17:21:12 -0600785 if get_vuid_status in val_tests.all_vuids:
Dave Houltoncacef472018-05-29 13:00:42 -0600786 print(' Has a test!')
787 test_list = val_tests.vuid_to_tests[get_vuid_status]
788 for test in test_list:
789 print(' => %s' % test)
790 else:
791 print(' Not tested.')
Mike Weiblenfe186122017-02-03 12:44:53 -0700792
Dave Houltoncacef472018-05-29 13:00:42 -0600793 # Report unimplemented explicit VUIDs
794 if report_unimplemented:
795 unim_explicit = val_json.explicit_vuids - val_source.explicit_vuids
796 print("\n\n%d explicit VUID checks remain unimplemented:" % len(unim_explicit))
797 ulist = list(unim_explicit)
798 ulist.sort()
799 for vuid in ulist:
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700800 print(" => %s" % vuid)
Dave Houltoncacef472018-05-29 13:00:42 -0600801
802 # Consistency tests
803 if run_consistency:
804 print("\n\nRunning consistency tests...")
805 con = Consistency(val_json.all_vuids, val_source.all_vuids, val_tests.all_vuids)
806 ok = con.undef_vuids_in_layer_code()
807 ok &= con.undef_vuids_in_tests()
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700808 ok &= con.vuids_tested_not_checked()
Dave Houltoncacef472018-05-29 13:00:42 -0600809
810 if ok:
811 print(" OK! No inconsistencies found.")
812
813 # Output database in requested format(s)
814 db_out = OutputDatabase(val_json, val_source, val_tests)
815 if txt_out:
816 db_out.dump_txt()
817 if csv_out:
818 db_out.dump_csv()
819 if html_out:
820 db_out.dump_html()
Dave Houlton407df732018-08-06 17:58:24 -0600821 if header_out:
822 db_out.export_header()
Tobin Ehlis20e32582016-12-05 14:50:03 -0700823 return result
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600824
825if __name__ == "__main__":
Mark Lobodzinskib44c54a2017-06-12 12:02:38 -0600826 sys.exit(main(sys.argv[1:]))
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600827