layers: eradicate remaining VUID enums
Improved format stripping of error text strings in vk_validation_stats
script and added functionality to export a new header file that
maps text VUIDs to these spec error strings. Removed lingering
references to UNIQUE_VALIDATION_ERROR_CODE enums and functions that
were still passing (now unused) msg_code parameters.
Updated CMakeLists to avoid build errors on Win64 related to the size
of the new error map.
Change-Id: I1ff74c7b57ce5021271842da5419055820bd4730
diff --git a/layers/CMakeLists.txt b/layers/CMakeLists.txt
index 50cdca1..b5c0981 100644
--- a/layers/CMakeLists.txt
+++ b/layers/CMakeLists.txt
@@ -231,7 +231,7 @@
# Applies to all configurations
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
# Avoid: fatal error C1128: number of sections exceeded object file format limit: compile with /bigobj
- set_source_files_properties(core_validation.cpp threading.cpp PROPERTIES COMPILE_FLAGS "/bigobj")
+ set_source_files_properties(core_validation.cpp threading.cpp parameter_validation_utils.cpp PROPERTIES COMPILE_FLAGS "/bigobj")
# Turn off transitional "changed behavior" warning message for Visual Studio versions prior to 2015. The changed behavior is
# that constructor initializers are now fixed to clear the struct members.
add_compile_options("$<$<AND:$<CXX_COMPILER_ID:MSVC>,$<VERSION_LESS:$<CXX_COMPILER_VERSION>,19>>:/wd4351>")
diff --git a/layers/vk_layer_logging.h b/layers/vk_layer_logging.h
index 9af840e..03eb91f 100644
--- a/layers/vk_layer_logging.h
+++ b/layers/vk_layer_logging.h
@@ -113,8 +113,8 @@
// Forward Declarations
static inline bool debug_log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
- uint64_t src_object, size_t location, int32_t msg_code, const char *layer_prefix,
- const char *message, const char *text_vuid = NULL);
+ uint64_t src_object, size_t location, const char *layer_prefix, const char *message,
+ const char *text_vuid);
// Add a debug message callback node structure to the specified callback linked list
static inline void AddDebugCallbackNode(debug_report_data *debug_data, VkLayerDbgFunctionNode **list_head,
@@ -140,8 +140,8 @@
*list_head = cur_callback->pNext;
}
debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
- reinterpret_cast<uint64_t &>(cur_callback->messenger.messenger), 0, 0, "DebugUtilsMessenger",
- "Destroyed messenger\n");
+ reinterpret_cast<uint64_t &>(cur_callback->messenger.messenger), 0, "DebugUtilsMessenger",
+ "Destroyed messenger\n", kVUIDUndefined);
} else {
matched = false;
local_severities |= cur_callback->messenger.messageSeverity;
@@ -174,8 +174,8 @@
*list_head = cur_callback->pNext;
}
debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
- reinterpret_cast<uint64_t &>(cur_callback->report.msgCallback), 0, 0, "DebugReport",
- "Destroyed callback\n");
+ reinterpret_cast<uint64_t &>(cur_callback->report.msgCallback), 0, "DebugReport", "Destroyed callback\n",
+ kVUIDUndefined);
} else {
matched = false;
VkFlags this_severities = 0;
@@ -203,12 +203,12 @@
prev_callback = current_callback->pNext;
if (!current_callback->is_messenger) {
debug_log_msg(debug_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
- (uint64_t)current_callback->report.msgCallback, 0, 0, "DebugReport",
- "Debug Report callbacks not removed before DestroyInstance");
+ (uint64_t)current_callback->report.msgCallback, 0, "DebugReport",
+ "Debug Report callbacks not removed before DestroyInstance", kVUIDUndefined);
} else {
debug_log_msg(debug_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
- (uint64_t)current_callback->messenger.messenger, 0, 0, "Messenger",
- "Debug messengers not removed before DestroyInstance");
+ (uint64_t)current_callback->messenger.messenger, 0, "Messenger",
+ "Debug messengers not removed before DestroyInstance", kVUIDUndefined);
}
free(current_callback);
current_callback = prev_callback;
@@ -216,10 +216,9 @@
*list_head = NULL;
}
-// Note that text_vuid is a default parameter, and is optional. See the above forward declaration
static inline bool debug_log_msg(const debug_report_data *debug_data, VkFlags msg_flags, VkDebugReportObjectTypeEXT object_type,
- uint64_t src_object, size_t location, int32_t msg_code, const char *layer_prefix,
- const char *message, const char *text_vuid) {
+ uint64_t src_object, size_t location, const char *layer_prefix, const char *message,
+ const char *text_vuid) {
bool bail = false;
VkLayerDbgFunctionNode *layer_dbg_node = NULL;
@@ -246,7 +245,7 @@
callback_data.pNext = NULL;
callback_data.flags = 0;
callback_data.pMessageIdName = text_vuid;
- callback_data.messageIdNumber = msg_code;
+ callback_data.messageIdNumber = 0; // deprecated, validation layers use only the pMessageIdName
callback_data.pMessage = message;
callback_data.queueLabelCount = 0;
callback_data.pQueueLabels = NULL;
@@ -343,7 +342,7 @@
new_debug_report_message.insert(0, " [ ");
}
- if (layer_dbg_node->report.pfnMsgCallback(msg_flags, object_type, src_object, location, msg_code, layer_prefix,
+ if (layer_dbg_node->report.pfnMsgCallback(msg_flags, object_type, src_object, location, 0, layer_prefix,
new_debug_report_message.c_str(), layer_dbg_node->pUserData)) {
bail = true;
}
@@ -583,7 +582,7 @@
}
debug_log_msg(debug_data, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT, (uint64_t)*callback, 0,
- 0, "DebugReport", "Added callback");
+ "DebugReport", "Added callback", kVUIDUndefined);
return VK_SUCCESS;
}
@@ -856,19 +855,23 @@
}
va_end(argptr);
- std::string str_plus_spec_text(str);
+ std::string str_plus_spec_text(str ? str : "Allocation failure");
- // If the vuid string is in the error map: find the legacy enum, look up spec text, and tack it onto error message.
- int32_t legacy_vuid_enum = VALIDATION_ERROR_UNDEFINED;
- if (validation_error_text_map.find(vuid_text.c_str()) != validation_error_text_map.end()) {
- legacy_vuid_enum = validation_error_text_map[vuid_text.c_str()];
- str_plus_spec_text += " ";
- str_plus_spec_text += validation_error_map[legacy_vuid_enum];
+ // Append the spec error text to the error message, unless it's an UNASSIGNED or UNDEFINED vuid
+ if ((vuid_text.find("UNASSIGNED-") == std::string::npos) && (vuid_text.find(kVUIDUndefined) == std::string::npos)) {
+ if (vuid_to_error_text_map.find(vuid_text) == vuid_to_error_text_map.end()) {
+ // If this happens, you've hit a VUID string that isn't defined in the spec's json file
+ // Try running 'vk_validation_stats -c' to look for invalid VUID strings in the repo code
+ assert(0);
+ } else {
+ str_plus_spec_text += " The Vulkan spec states: ";
+ str_plus_spec_text += vuid_to_error_text_map[vuid_text];
+ }
}
// Append layer prefix with VUID string, pass in recovered legacy numerical VUID
- bool result = debug_log_msg(debug_data, msg_flags, object_type, src_object, 0, legacy_vuid_enum, "Validation",
- str_plus_spec_text.c_str() ? str_plus_spec_text.c_str() : "Allocation failure", vuid_text.c_str());
+ bool result = debug_log_msg(debug_data, msg_flags, object_type, src_object, 0, "Validation", str_plus_spec_text.c_str(),
+ vuid_text.c_str());
free(str);
return result;
diff --git a/scripts/vk_validation_stats.py b/scripts/vk_validation_stats.py
index 5b87be4..faacdf3 100755
--- a/scripts/vk_validation_stats.py
+++ b/scripts/vk_validation_stats.py
@@ -37,7 +37,7 @@
txt_filename = "validation_error_database.txt"
csv_filename = "validation_error_database.csv"
html_filename = "validation_error_database.html"
-# header_file = '../layers/vk_validation_error_messages.h'
+header_filename = "../layers/vk_validation_error_messages.h"
test_file = '../tests/layer_validation_tests.cpp'
vuid_prefixes = ['VUID-', 'UNASSIGNED-']
@@ -64,6 +64,7 @@
'../layers/buffer_validation.cpp',
]
+# This needs to be updated as new extensions roll in
khr_aliases = {
'VUID-vkBindBufferMemory2KHR-device-parameter' : 'VUID-vkBindBufferMemory2-device-parameter',
'VUID-vkBindBufferMemory2KHR-pBindInfos-parameter' : 'VUID-vkBindBufferMemory2-pBindInfos-parameter',
@@ -142,6 +143,7 @@
print (" [ -text [ <text_out_filename>] ]")
print (" [ -csv [ <csv_out_filename>] ]")
print (" [ -html [ <html_out_filename>] ]")
+ print (" [ -export_header ]")
print (" [ -verbose ]")
print (" [ -help ]")
print ("\n The vk_validation_stats script parses validation layer source files to")
@@ -159,6 +161,7 @@
print (" defaults to 'validation_error_database.csv'")
print (" -html [filename] output the error database in html to <html_database_filename>,")
print (" defaults to 'validation_error_database.html'")
+ print (" -export_header export a new VUID error text header file to <%s>" % header_filename)
print (" -verbose show your work (to stdout)")
class ValidationJSON:
@@ -169,13 +172,22 @@
self.all_vuids = set()
self.vuid_db = defaultdict(list) # Maps VUID string to list of json-data dicts
self.apiversion = ""
- self.re_striptags = re.compile('<.*?>|&(amp;)+lt;|&(amp;)+gt;')
self.duplicate_vuids = set()
+
+ # A set of specific regular expression substitutions needed to clean up VUID text
+ self.regex_dict = {}
+ self.regex_dict[re.compile('<.*?>|&(amp;)+lt;|&(amp;)+gt;')] = ""
+ self.regex_dict[re.compile(r'\\\(codeSize \\over 4\\\)')] = "(codeSize/4)"
+ self.regex_dict[re.compile(r'\\\(\\lceil\{\\mathit\{rasterizationSamples} \\over 32}\\rceil\\\)')] = "(rasterizationSamples/32)"
+ # Some fancy punctuation chars that break the Android build...
+ self.regex_dict[re.compile('→')] = "->" # Arrow char
+ self.regex_dict[re.compile('’')] = "'" # Left-slanting apostrophe to apostrophe
+ self.regex_dict[re.compile('̶(0|1);')] = "'" # L/R-slanting quotes to apostrophe
def read(self):
self.json_dict = {}
if os.path.isfile(self.filename):
- json_file = open(self.filename, 'r')
+ json_file = open(self.filename, 'r', encoding='utf-8')
self.json_dict = json.load(json_file)
json_file.close()
if len(self.json_dict) == 0:
@@ -204,15 +216,15 @@
self.implicit_vuids.add(vuid_string) # otherwise, implicit
vtype = 'implicit'
vuid_text = ventry['text']
- #if 'amp;' in vuid_text:
- # print(vuid_text)
- stripped = re.sub(self.re_striptags, '', vuid_text) # strip tags & literals
- stripped = html.unescape(stripped) # anything missed by the regex
- #if 'amp;' in stripped:
- # print(" %s" % stripped)
- self.vuid_db[vuid_string].append({'api':apiname, 'ext':ext, 'type':vtype, 'text':stripped})
+ for regex, replacement in self.regex_dict.items():
+ vuid_text = re.sub(regex, replacement, vuid_text) # do regex substitution
+ vuid_text = html.unescape(vuid_text) # anything missed by the regex
+ self.vuid_db[vuid_string].append({'api':apiname, 'ext':ext, 'type':vtype, 'text':vuid_text})
self.all_vuids = self.explicit_vuids | self.implicit_vuids
self.duplicate_vuids = set({v for v in self.vuid_db if len(self.vuid_db[v]) > 1})
+ if len(self.duplicate_vuids) > 0:
+ print("Warning: duplicate VUIDs found in validusage.json")
+
class ValidationSource:
def __init__(self, source_file_list, generated_source_file_list, generated_source_directories):
@@ -452,6 +464,47 @@
self.vj = val_json
self.vs = val_source
self.vt = val_tests
+ self.header_preamble = """/* THIS FILE IS GENERATED. DO NOT EDIT. */
+/* (scripts/vk_validation_stats.py) */
+/*
+ * Vulkan
+ *
+ * Copyright (c) 2016-2018 Google Inc.
+ * Copyright (c) 2016-2018 LunarG, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Author: Tobin Ehlis <tobine@google.com>
+ * Author: Dave Houlton <daveh@lunarg.com>
+ */
+
+#pragma once
+
+// Disable auto-formatting for generated file
+// clang-format off
+
+#include <string>
+#include <unordered_map>
+
+// Mapping from VUID string to the corresponding spec text
+#ifdef VALIDATION_ERROR_MAP_IMPL
+std::unordered_map<std::string, std::string> vuid_to_error_text_map {
+"""
+ self.header_postamble = """};
+#else
+extern std::unordered_map<std::string, std::string> vuid_to_error_text_map;
+#endif"""
+ self.spec_url = "https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html"
def dump_txt(self):
print("\n Dumping database to text file: %s" % txt_filename)
@@ -528,6 +581,21 @@
hfile.write('<th>%s</th></tr>\n' % db_entry['text'])
hfile.write('</table>\n</body>\n</html>\n')
+ def export_header(self):
+ print("\n Exporting header file to: %s" % header_filename)
+ with open (header_filename, 'w') as hfile:
+ hfile.write(self.header_preamble)
+ vuid_list = list(self.vj.all_vuids)
+ vuid_list.sort()
+ for vuid in vuid_list:
+ db_entry = self.vj.vuid_db[vuid][0]
+ hfile.write(' {"%s", "%s (%s#%s)"},\n' % (vuid, db_entry['text'].strip(' '), self.spec_url, vuid))
+ # For multiply-defined VUIDs, include versions with extension appended
+ if len(self.vj.vuid_db[vuid]) > 1:
+ for db_entry in self.vj.vuid_db[vuid]:
+ hfile.write(' {"%s[%s]", "%s (%s#%s)"},\n' % (vuid, db_entry['ext'].strip(' '), db_entry['text'].strip(' '), self.spec_url, vuid))
+ hfile.write(self.header_postamble)
+
def main(argv):
global verbose_mode
global txt_filename
@@ -540,6 +608,7 @@
txt_out = False
csv_out = False
html_out = False
+ header_out = False
if (1 > len(argv)):
printHelp()
@@ -576,6 +645,8 @@
if i < len(argv) and not argv[i].startswith('-'):
html_filename = argv[i]
i = i + 1
+ elif (arg == '-export_header'):
+ header_out = True
elif (arg in ['-verbose']):
verbose_mode = True
elif (arg in ['-help', '-h']):
@@ -700,7 +771,8 @@
db_out.dump_csv()
if html_out:
db_out.dump_html()
-
+ if header_out:
+ db_out.export_header()
return result
if __name__ == "__main__":
diff --git a/tests/layer_validation_tests.cpp b/tests/layer_validation_tests.cpp
index 6ec8a5d..94aa49f 100644
--- a/tests/layer_validation_tests.cpp
+++ b/tests/layer_validation_tests.cpp
@@ -294,7 +294,7 @@
test_platform_thread_unlock_mutex(&mutex_);
}
- VkBool32 CheckForDesiredMsg(const uint32_t message_code, const char *const msgString) {
+ VkBool32 CheckForDesiredMsg(const char *const msgString) {
VkBool32 result = VK_FALSE;
test_platform_thread_lock_mutex(&mutex_);
if (bailout_ != nullptr) {
@@ -415,13 +415,7 @@
void *pUserData) {
ErrorMonitor *errMonitor = (ErrorMonitor *)pUserData;
if (msgFlags & errMonitor->GetMessageFlags()) {
-#ifdef _DEBUG
- char embedded_code_string[2048];
- snprintf(embedded_code_string, 2048, "%s [%08x]", pMsg, msgCode);
- return errMonitor->CheckForDesiredMsg(msgCode, embedded_code_string);
-#else
- return errMonitor->CheckForDesiredMsg(msgCode, pMsg);
-#endif
+ return errMonitor->CheckForDesiredMsg(pMsg);
}
return VK_FALSE;
}