forked from KhronosGroup/Vulkan-ValidationLayers
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcore_error_location.h
254 lines (228 loc) · 7.78 KB
/
core_error_location.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
/* Copyright (c) 2021 The Khronos Group Inc.
* Copyright (c) 2021 Valve Corporation
* Copyright (c) 2021 LunarG, Inc.
* Copyright (C) 2021 Google 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: Jeremy Gebben <[email protected]>
*/
#pragma once
#include <cstdint>
#include <string>
#include <sstream>
#include <limits>
#include "vk_layer_data.h"
namespace core_error {
// structure to track where a validation error occurs, and capture enough information
// to generate the start of a log message and find the correct VUID for many commonvalidity errors.
//
// usage example:
// Location outer(Func::vkCmdPipelineBarrier, Struct::VkImageMemoryBarrier);
// auto struct_level = outer.dot(Field::pImageMemoryBarriers, i);
// auto field_level = struct_level.dot(Field::srcAccessMask);
// std::cout << field_level.Message() << std::endl;
// will print:
// vkCmdPipelineBarrier(): pImageMemoryBarriers[42].srcAccessMask
// VUIDs can be found for an error in generic code using a combination of the
// function, structure, and fieldmembers.
/// TODO: these enums can eventually be autogenerated from vk.xml
enum class Func {
Empty = 0,
vkQueueSubmit,
vkQueueSubmit2KHR,
vkCmdSetEvent,
vkCmdSetEvent2KHR,
vkCmdResetEvent,
vkCmdResetEvent2KHR,
vkCmdPipelineBarrier,
vkCmdPipelineBarrier2KHR,
vkCmdWaitEvents,
vkCmdWaitEvents2KHR,
vkCmdWriteTimestamp,
vkCmdWriteTimestamp2KHR,
vkCreateRenderPass,
vkCreateRenderPass2,
vkQueueBindSparse,
vkSignalSemaphore,
};
const std::string& String(Func func);
enum class Struct {
Empty = 0,
VkMemoryBarrier,
VkMemoryBarrier2KHR,
VkBufferMemoryBarrier,
VkImageMemoryBarrier,
VkBufferMemoryBarrier2KHR,
VkImageMemoryBarrier2KHR,
VkSubmitInfo,
VkSubmitInfo2KHR,
VkCommandBufferSubmitInfoKHR,
VkSubpassDependency,
VkSubpassDependency2,
VkBindSparseInfo,
VkSemaphoreSignalInfo,
VkSemaphoreSubmitInfoKHR,
VkProtectedSubmitInfo,
};
const std::string& String(Struct s);
enum class Field {
Empty = 0,
oldLayout,
newLayout,
image,
buffer,
pMemoryBarriers,
pBufferMemoryBarriers,
pImageMemoryBarriers,
offset,
size,
subresourceRange,
srcAccessMask,
dstAccessMask,
srcStageMask,
dstStageMask,
pNext,
pWaitDstStageMask,
pWaitSemaphores,
pSignalSemaphores,
pWaitSemaphoreInfos,
pWaitSemaphoreValues,
pSignalSemaphoreInfos,
pSignalSemaphoreValues,
stage,
stageMask,
value,
pCommandBuffers,
pSubmits,
pCommandBufferInfos,
semaphore,
commandBuffer,
dependencyFlags,
pDependencyInfo,
pDependencyInfos,
srcQueueFamilyIndex,
dstQueueFamilyIndex,
queryPool,
pDependencies,
pipelineStage,
};
const std::string& String(Field field);
struct Location {
static const uint32_t kNoIndex = std::numeric_limits<uint32_t>::max();
// name of the vulkan function we're checking
Func function;
Struct structure;
Field field;
// optional index if checking an array.
uint32_t index;
const Location* prev;
Location(Func func, Struct s, Field f = Field::Empty, uint32_t i = kNoIndex)
: function(func), structure(s), field(f), index(i), prev(nullptr) {}
Location(Func func, Field f = Field::Empty, uint32_t i = kNoIndex)
: function(func), structure(Struct::Empty), field(f), index(i), prev(nullptr) {}
Location(const Location& prev_loc, Struct s, Field f, uint32_t i)
: function(prev_loc.function), structure(s), field(f), index(i), prev(&prev_loc) {}
void AppendFields(std::ostream &out) const;
std::string Message() const {
std::stringstream out;
out << StringFunc() << "(): ";
AppendFields(out);
return out.str();
}
// the dot() method is for walking down into a structure that is being validated
// eg: loc.dot(Field::pMemoryBarriers, 5).dot(Field::srcStagemask)
Location dot(Struct s, Field sub_field, uint32_t sub_index = kNoIndex) const {
Location result(*this, s, sub_field, sub_index);
return result;
}
Location dot(Field sub_field, uint32_t sub_index = kNoIndex) const {
Location result(*this, this->structure, sub_field, sub_index);
return result;
}
const std::string& StringFunc() const { return String(function); }
const std::string& StringStruct() const { return String(structure); }
const std::string& StringField() const { return String(field); }
};
template <typename VuidFunctor>
struct LocationVuidAdapter {
const Location loc;
VuidFunctor vuid_functor;
const char* FuncName() const {
// the returned reference from loc must be valid for lifespan of loc, at least.
const std::string& function = loc.StringFunc();
return function.c_str();
}
const char* Vuid() const {
// the returned reference from functor must be valid for lifespan of vuid_functor, at least.
const std::string& vuid = vuid_functor(loc);
return vuid.c_str();
}
template <typename... Args>
LocationVuidAdapter(const Location& loc_, const Args&... args) : loc(loc_), vuid_functor(args...) {}
};
struct LocationCapture {
LocationCapture(const Location& loc);
const Location& Get() const { return capture.back(); }
protected:
// TODO: Optimize this for "new" minimization
using CaptureStore = small_vector<Location, 2>;
const Location* Capture(const Location& loc, CaptureStore::size_type depth);
CaptureStore capture;
};
// Key for use in tables of VUIDs.
//
// Fuzzy match rules:
// key.function OR key.structure may be Empty
// loc.structure may be Empty
// key.field may be Empty
// if key.recurse_field is true, key.field can match loc.field or any fields in loc.prev
//
struct Key {
Func function;
Struct structure;
Field field;
bool recurse_field;
Key(Struct r, Field f = Field::Empty, bool recurse = false)
: function(Func::Empty), structure(r), field(f), recurse_field(recurse) {}
Key(Func fn, Field f = Field::Empty, bool recurse = false)
: function(fn), structure(Struct::Empty), field(f), recurse_field(recurse) {}
};
bool operator==(const Key& key, const Location& loc);
// Entry in a VUID lookup table
struct Entry {
Key k;
std::string v;
};
// look for a matching VUID in a vector or array-ish table
template <typename Table>
static const std::string& FindVUID(const Location& loc, const Table& table) {
static const std::string empty;
auto predicate = [&loc](const Entry& entry) { return entry.k == loc; };
// consistency check: there should never be more than 1 match in a table
assert(std::count_if(table.begin(), table.end(), predicate) <= 1);
const auto pos = std::find_if(table.begin(), table.end(), predicate);
return (pos != table.end()) ? pos->v : empty;
}
// 2-level look up where the outer container is a map where we need to find
// different VUIDs for different values of an enum or bitfield
template <typename OuterKey, typename Table>
static const std::string& FindVUID(OuterKey key, const Location& loc, const Table& table) {
static const std::string empty;
const auto entry = table.find(key);
if (entry != table.end()) {
return FindVUID(loc, entry->second);
}
return empty;
}
} // namespace core_error