xref: /aosp_15_r20/external/vulkan-validation-layers/layers/shader_validation.h (revision b7893ccf7851cd6a48cc5a1e965257d8a5cdcc70)
1*b7893ccfSSadaf Ebrahimi /* Copyright (c) 2015-2019 The Khronos Group Inc.
2*b7893ccfSSadaf Ebrahimi  * Copyright (c) 2015-2019 Valve Corporation
3*b7893ccfSSadaf Ebrahimi  * Copyright (c) 2015-2019 LunarG, Inc.
4*b7893ccfSSadaf Ebrahimi  * Copyright (C) 2015-2019 Google Inc.
5*b7893ccfSSadaf Ebrahimi  *
6*b7893ccfSSadaf Ebrahimi  * Licensed under the Apache License, Version 2.0 (the "License");
7*b7893ccfSSadaf Ebrahimi  * you may not use this file except in compliance with the License.
8*b7893ccfSSadaf Ebrahimi  * You may obtain a copy of the License at
9*b7893ccfSSadaf Ebrahimi  *
10*b7893ccfSSadaf Ebrahimi  *     http://www.apache.org/licenses/LICENSE-2.0
11*b7893ccfSSadaf Ebrahimi  *
12*b7893ccfSSadaf Ebrahimi  * Unless required by applicable law or agreed to in writing, software
13*b7893ccfSSadaf Ebrahimi  * distributed under the License is distributed on an "AS IS" BASIS,
14*b7893ccfSSadaf Ebrahimi  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15*b7893ccfSSadaf Ebrahimi  * See the License for the specific language governing permissions and
16*b7893ccfSSadaf Ebrahimi  * limitations under the License.
17*b7893ccfSSadaf Ebrahimi  *
18*b7893ccfSSadaf Ebrahimi  * Author: Chris Forbes <[email protected]>
19*b7893ccfSSadaf Ebrahimi  */
20*b7893ccfSSadaf Ebrahimi #ifndef VULKAN_SHADER_VALIDATION_H
21*b7893ccfSSadaf Ebrahimi #define VULKAN_SHADER_VALIDATION_H
22*b7893ccfSSadaf Ebrahimi 
23*b7893ccfSSadaf Ebrahimi #include <unordered_map>
24*b7893ccfSSadaf Ebrahimi 
25*b7893ccfSSadaf Ebrahimi #include <SPIRV/spirv.hpp>
26*b7893ccfSSadaf Ebrahimi #include <generated/spirv_tools_commit_id.h>
27*b7893ccfSSadaf Ebrahimi #include "spirv-tools/optimizer.hpp"
28*b7893ccfSSadaf Ebrahimi 
29*b7893ccfSSadaf Ebrahimi // A forward iterator over spirv instructions. Provides easy access to len, opcode, and content words
30*b7893ccfSSadaf Ebrahimi // without the caller needing to care too much about the physical SPIRV module layout.
31*b7893ccfSSadaf Ebrahimi struct spirv_inst_iter {
32*b7893ccfSSadaf Ebrahimi     std::vector<uint32_t>::const_iterator zero;
33*b7893ccfSSadaf Ebrahimi     std::vector<uint32_t>::const_iterator it;
34*b7893ccfSSadaf Ebrahimi 
lenspirv_inst_iter35*b7893ccfSSadaf Ebrahimi     uint32_t len() const {
36*b7893ccfSSadaf Ebrahimi         auto result = *it >> 16;
37*b7893ccfSSadaf Ebrahimi         assert(result > 0);
38*b7893ccfSSadaf Ebrahimi         return result;
39*b7893ccfSSadaf Ebrahimi     }
40*b7893ccfSSadaf Ebrahimi 
opcodespirv_inst_iter41*b7893ccfSSadaf Ebrahimi     uint32_t opcode() { return *it & 0x0ffffu; }
42*b7893ccfSSadaf Ebrahimi 
wordspirv_inst_iter43*b7893ccfSSadaf Ebrahimi     uint32_t const &word(unsigned n) const {
44*b7893ccfSSadaf Ebrahimi         assert(n < len());
45*b7893ccfSSadaf Ebrahimi         return it[n];
46*b7893ccfSSadaf Ebrahimi     }
47*b7893ccfSSadaf Ebrahimi 
offsetspirv_inst_iter48*b7893ccfSSadaf Ebrahimi     uint32_t offset() { return (uint32_t)(it - zero); }
49*b7893ccfSSadaf Ebrahimi 
spirv_inst_iterspirv_inst_iter50*b7893ccfSSadaf Ebrahimi     spirv_inst_iter() {}
51*b7893ccfSSadaf Ebrahimi 
spirv_inst_iterspirv_inst_iter52*b7893ccfSSadaf Ebrahimi     spirv_inst_iter(std::vector<uint32_t>::const_iterator zero, std::vector<uint32_t>::const_iterator it) : zero(zero), it(it) {}
53*b7893ccfSSadaf Ebrahimi 
54*b7893ccfSSadaf Ebrahimi     bool operator==(spirv_inst_iter const &other) const { return it == other.it; }
55*b7893ccfSSadaf Ebrahimi 
56*b7893ccfSSadaf Ebrahimi     bool operator!=(spirv_inst_iter const &other) const { return it != other.it; }
57*b7893ccfSSadaf Ebrahimi 
58*b7893ccfSSadaf Ebrahimi     spirv_inst_iter operator++(int) {  // x++
59*b7893ccfSSadaf Ebrahimi         spirv_inst_iter ii = *this;
60*b7893ccfSSadaf Ebrahimi         it += len();
61*b7893ccfSSadaf Ebrahimi         return ii;
62*b7893ccfSSadaf Ebrahimi     }
63*b7893ccfSSadaf Ebrahimi 
64*b7893ccfSSadaf Ebrahimi     spirv_inst_iter operator++() {  // ++x;
65*b7893ccfSSadaf Ebrahimi         it += len();
66*b7893ccfSSadaf Ebrahimi         return *this;
67*b7893ccfSSadaf Ebrahimi     }
68*b7893ccfSSadaf Ebrahimi 
69*b7893ccfSSadaf Ebrahimi     // The iterator and the value are the same thing.
70*b7893ccfSSadaf Ebrahimi     spirv_inst_iter &operator*() { return *this; }
71*b7893ccfSSadaf Ebrahimi     spirv_inst_iter const &operator*() const { return *this; }
72*b7893ccfSSadaf Ebrahimi };
73*b7893ccfSSadaf Ebrahimi 
74*b7893ccfSSadaf Ebrahimi struct decoration_set {
75*b7893ccfSSadaf Ebrahimi     enum {
76*b7893ccfSSadaf Ebrahimi         location_bit = 1 << 0,
77*b7893ccfSSadaf Ebrahimi         patch_bit = 1 << 1,
78*b7893ccfSSadaf Ebrahimi         relaxed_precision_bit = 1 << 2,
79*b7893ccfSSadaf Ebrahimi         block_bit = 1 << 3,
80*b7893ccfSSadaf Ebrahimi         buffer_block_bit = 1 << 4,
81*b7893ccfSSadaf Ebrahimi         component_bit = 1 << 5,
82*b7893ccfSSadaf Ebrahimi         input_attachment_index_bit = 1 << 6,
83*b7893ccfSSadaf Ebrahimi         descriptor_set_bit = 1 << 7,
84*b7893ccfSSadaf Ebrahimi         binding_bit = 1 << 8,
85*b7893ccfSSadaf Ebrahimi         nonwritable_bit = 1 << 9,
86*b7893ccfSSadaf Ebrahimi         builtin_bit = 1 << 10,
87*b7893ccfSSadaf Ebrahimi     };
88*b7893ccfSSadaf Ebrahimi     uint32_t flags = 0;
89*b7893ccfSSadaf Ebrahimi     uint32_t location = static_cast<uint32_t>(-1);
90*b7893ccfSSadaf Ebrahimi     uint32_t component = 0;
91*b7893ccfSSadaf Ebrahimi     uint32_t input_attachment_index = 0;
92*b7893ccfSSadaf Ebrahimi     uint32_t descriptor_set = 0;
93*b7893ccfSSadaf Ebrahimi     uint32_t binding = 0;
94*b7893ccfSSadaf Ebrahimi     uint32_t builtin = static_cast<uint32_t>(-1);
95*b7893ccfSSadaf Ebrahimi 
mergedecoration_set96*b7893ccfSSadaf Ebrahimi     void merge(decoration_set const &other) {
97*b7893ccfSSadaf Ebrahimi         if (other.flags & location_bit) location = other.location;
98*b7893ccfSSadaf Ebrahimi         if (other.flags & component_bit) component = other.component;
99*b7893ccfSSadaf Ebrahimi         if (other.flags & input_attachment_index_bit) input_attachment_index = other.input_attachment_index;
100*b7893ccfSSadaf Ebrahimi         if (other.flags & descriptor_set_bit) descriptor_set = other.descriptor_set;
101*b7893ccfSSadaf Ebrahimi         if (other.flags & binding_bit) binding = other.binding;
102*b7893ccfSSadaf Ebrahimi         if (other.flags & builtin_bit) builtin = other.builtin;
103*b7893ccfSSadaf Ebrahimi         flags |= other.flags;
104*b7893ccfSSadaf Ebrahimi     }
105*b7893ccfSSadaf Ebrahimi 
106*b7893ccfSSadaf Ebrahimi     void add(uint32_t decoration, uint32_t value);
107*b7893ccfSSadaf Ebrahimi };
108*b7893ccfSSadaf Ebrahimi 
109*b7893ccfSSadaf Ebrahimi struct SHADER_MODULE_STATE {
110*b7893ccfSSadaf Ebrahimi     // The spirv image itself
111*b7893ccfSSadaf Ebrahimi     std::vector<uint32_t> words;
112*b7893ccfSSadaf Ebrahimi     // A mapping of <id> to the first word of its def. this is useful because walking type
113*b7893ccfSSadaf Ebrahimi     // trees, constant expressions, etc requires jumping all over the instruction stream.
114*b7893ccfSSadaf Ebrahimi     std::unordered_map<unsigned, unsigned> def_index;
115*b7893ccfSSadaf Ebrahimi     std::unordered_map<unsigned, decoration_set> decorations;
116*b7893ccfSSadaf Ebrahimi     struct EntryPoint {
117*b7893ccfSSadaf Ebrahimi         uint32_t offset;
118*b7893ccfSSadaf Ebrahimi         VkShaderStageFlags stage;
119*b7893ccfSSadaf Ebrahimi     };
120*b7893ccfSSadaf Ebrahimi     std::unordered_multimap<std::string, EntryPoint> entry_points;
121*b7893ccfSSadaf Ebrahimi     bool has_valid_spirv;
122*b7893ccfSSadaf Ebrahimi     VkShaderModule vk_shader_module;
123*b7893ccfSSadaf Ebrahimi     uint32_t gpu_validation_shader_id;
124*b7893ccfSSadaf Ebrahimi 
PreprocessShaderBinarySHADER_MODULE_STATE125*b7893ccfSSadaf Ebrahimi     std::vector<uint32_t> PreprocessShaderBinary(uint32_t *src_binary, size_t binary_size, spv_target_env env) {
126*b7893ccfSSadaf Ebrahimi         std::vector<uint32_t> src(src_binary, src_binary + binary_size / sizeof(uint32_t));
127*b7893ccfSSadaf Ebrahimi 
128*b7893ccfSSadaf Ebrahimi         // Check if there are any group decoration instructions, and flatten them if found.
129*b7893ccfSSadaf Ebrahimi         bool has_group_decoration = false;
130*b7893ccfSSadaf Ebrahimi         bool done = false;
131*b7893ccfSSadaf Ebrahimi 
132*b7893ccfSSadaf Ebrahimi         // Walk through the first part of the SPIR-V module, looking for group decoration instructions.
133*b7893ccfSSadaf Ebrahimi         // Skip the header (5 words).
134*b7893ccfSSadaf Ebrahimi         auto itr = spirv_inst_iter(src.begin(), src.begin() + 5);
135*b7893ccfSSadaf Ebrahimi         auto itrend = spirv_inst_iter(src.begin(), src.end());
136*b7893ccfSSadaf Ebrahimi         while (itr != itrend && !done) {
137*b7893ccfSSadaf Ebrahimi             spv::Op opcode = (spv::Op)itr.opcode();
138*b7893ccfSSadaf Ebrahimi             switch (opcode) {
139*b7893ccfSSadaf Ebrahimi                 case spv::OpDecorationGroup:
140*b7893ccfSSadaf Ebrahimi                 case spv::OpGroupDecorate:
141*b7893ccfSSadaf Ebrahimi                 case spv::OpGroupMemberDecorate:
142*b7893ccfSSadaf Ebrahimi                     has_group_decoration = true;
143*b7893ccfSSadaf Ebrahimi                     done = true;
144*b7893ccfSSadaf Ebrahimi                     break;
145*b7893ccfSSadaf Ebrahimi                 case spv::OpFunction:
146*b7893ccfSSadaf Ebrahimi                     // An OpFunction indicates there are no more decorations
147*b7893ccfSSadaf Ebrahimi                     done = true;
148*b7893ccfSSadaf Ebrahimi                     break;
149*b7893ccfSSadaf Ebrahimi                 default:
150*b7893ccfSSadaf Ebrahimi                     break;
151*b7893ccfSSadaf Ebrahimi             }
152*b7893ccfSSadaf Ebrahimi             itr++;
153*b7893ccfSSadaf Ebrahimi         }
154*b7893ccfSSadaf Ebrahimi 
155*b7893ccfSSadaf Ebrahimi         if (has_group_decoration) {
156*b7893ccfSSadaf Ebrahimi             spvtools::Optimizer optimizer(env);
157*b7893ccfSSadaf Ebrahimi             optimizer.RegisterPass(spvtools::CreateFlattenDecorationPass());
158*b7893ccfSSadaf Ebrahimi             std::vector<uint32_t> optimized_binary;
159*b7893ccfSSadaf Ebrahimi             // Run optimizer to flatten decorations only, set skip_validation so as to not re-run validator
160*b7893ccfSSadaf Ebrahimi             auto result =
161*b7893ccfSSadaf Ebrahimi                 optimizer.Run(src_binary, binary_size / sizeof(uint32_t), &optimized_binary, spvtools::ValidatorOptions(), true);
162*b7893ccfSSadaf Ebrahimi             if (result) {
163*b7893ccfSSadaf Ebrahimi                 return optimized_binary;
164*b7893ccfSSadaf Ebrahimi             }
165*b7893ccfSSadaf Ebrahimi         }
166*b7893ccfSSadaf Ebrahimi         // Return the original module.
167*b7893ccfSSadaf Ebrahimi         return src;
168*b7893ccfSSadaf Ebrahimi     }
169*b7893ccfSSadaf Ebrahimi 
SHADER_MODULE_STATESHADER_MODULE_STATE170*b7893ccfSSadaf Ebrahimi     SHADER_MODULE_STATE(VkShaderModuleCreateInfo const *pCreateInfo, VkShaderModule shaderModule, spv_target_env env,
171*b7893ccfSSadaf Ebrahimi                         uint32_t unique_shader_id)
172*b7893ccfSSadaf Ebrahimi         : words(PreprocessShaderBinary((uint32_t *)pCreateInfo->pCode, pCreateInfo->codeSize, env)),
173*b7893ccfSSadaf Ebrahimi           def_index(),
174*b7893ccfSSadaf Ebrahimi           has_valid_spirv(true),
175*b7893ccfSSadaf Ebrahimi           vk_shader_module(shaderModule),
176*b7893ccfSSadaf Ebrahimi           gpu_validation_shader_id(unique_shader_id) {
177*b7893ccfSSadaf Ebrahimi         BuildDefIndex();
178*b7893ccfSSadaf Ebrahimi     }
179*b7893ccfSSadaf Ebrahimi 
SHADER_MODULE_STATESHADER_MODULE_STATE180*b7893ccfSSadaf Ebrahimi     SHADER_MODULE_STATE() : has_valid_spirv(false), vk_shader_module(VK_NULL_HANDLE) {}
181*b7893ccfSSadaf Ebrahimi 
get_decorationsSHADER_MODULE_STATE182*b7893ccfSSadaf Ebrahimi     decoration_set get_decorations(unsigned id) const {
183*b7893ccfSSadaf Ebrahimi         // return the actual decorations for this id, or a default set.
184*b7893ccfSSadaf Ebrahimi         auto it = decorations.find(id);
185*b7893ccfSSadaf Ebrahimi         if (it != decorations.end()) return it->second;
186*b7893ccfSSadaf Ebrahimi         return decoration_set();
187*b7893ccfSSadaf Ebrahimi     }
188*b7893ccfSSadaf Ebrahimi 
189*b7893ccfSSadaf Ebrahimi     // Expose begin() / end() to enable range-based for
beginSHADER_MODULE_STATE190*b7893ccfSSadaf Ebrahimi     spirv_inst_iter begin() const { return spirv_inst_iter(words.begin(), words.begin() + 5); }  // First insn
endSHADER_MODULE_STATE191*b7893ccfSSadaf Ebrahimi     spirv_inst_iter end() const { return spirv_inst_iter(words.begin(), words.end()); }          // Just past last insn
192*b7893ccfSSadaf Ebrahimi     // Given an offset into the module, produce an iterator there.
atSHADER_MODULE_STATE193*b7893ccfSSadaf Ebrahimi     spirv_inst_iter at(unsigned offset) const { return spirv_inst_iter(words.begin(), words.begin() + offset); }
194*b7893ccfSSadaf Ebrahimi 
195*b7893ccfSSadaf Ebrahimi     // Gets an iterator to the definition of an id
get_defSHADER_MODULE_STATE196*b7893ccfSSadaf Ebrahimi     spirv_inst_iter get_def(unsigned id) const {
197*b7893ccfSSadaf Ebrahimi         auto it = def_index.find(id);
198*b7893ccfSSadaf Ebrahimi         if (it == def_index.end()) {
199*b7893ccfSSadaf Ebrahimi             return end();
200*b7893ccfSSadaf Ebrahimi         }
201*b7893ccfSSadaf Ebrahimi         return at(it->second);
202*b7893ccfSSadaf Ebrahimi     }
203*b7893ccfSSadaf Ebrahimi 
204*b7893ccfSSadaf Ebrahimi     void BuildDefIndex();
205*b7893ccfSSadaf Ebrahimi };
206*b7893ccfSSadaf Ebrahimi 
207*b7893ccfSSadaf Ebrahimi class ValidationCache {
208*b7893ccfSSadaf Ebrahimi     // hashes of shaders that have passed validation before, and can be skipped.
209*b7893ccfSSadaf Ebrahimi     // we don't store negative results, as we would have to also store what was
210*b7893ccfSSadaf Ebrahimi     // wrong with them; also, we expect they will get fixed, so we're less
211*b7893ccfSSadaf Ebrahimi     // likely to see them again.
212*b7893ccfSSadaf Ebrahimi     std::unordered_set<uint32_t> good_shader_hashes;
ValidationCache()213*b7893ccfSSadaf Ebrahimi     ValidationCache() {}
214*b7893ccfSSadaf Ebrahimi 
215*b7893ccfSSadaf Ebrahimi    public:
Create(VkValidationCacheCreateInfoEXT const * pCreateInfo)216*b7893ccfSSadaf Ebrahimi     static VkValidationCacheEXT Create(VkValidationCacheCreateInfoEXT const *pCreateInfo) {
217*b7893ccfSSadaf Ebrahimi         auto cache = new ValidationCache();
218*b7893ccfSSadaf Ebrahimi         cache->Load(pCreateInfo);
219*b7893ccfSSadaf Ebrahimi         return VkValidationCacheEXT(cache);
220*b7893ccfSSadaf Ebrahimi     }
221*b7893ccfSSadaf Ebrahimi 
Load(VkValidationCacheCreateInfoEXT const * pCreateInfo)222*b7893ccfSSadaf Ebrahimi     void Load(VkValidationCacheCreateInfoEXT const *pCreateInfo) {
223*b7893ccfSSadaf Ebrahimi         const auto headerSize = 2 * sizeof(uint32_t) + VK_UUID_SIZE;
224*b7893ccfSSadaf Ebrahimi         auto size = headerSize;
225*b7893ccfSSadaf Ebrahimi         if (!pCreateInfo->pInitialData || pCreateInfo->initialDataSize < size) return;
226*b7893ccfSSadaf Ebrahimi 
227*b7893ccfSSadaf Ebrahimi         uint32_t const *data = (uint32_t const *)pCreateInfo->pInitialData;
228*b7893ccfSSadaf Ebrahimi         if (data[0] != size) return;
229*b7893ccfSSadaf Ebrahimi         if (data[1] != VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT) return;
230*b7893ccfSSadaf Ebrahimi         uint8_t expected_uuid[VK_UUID_SIZE];
231*b7893ccfSSadaf Ebrahimi         Sha1ToVkUuid(SPIRV_TOOLS_COMMIT_ID, expected_uuid);
232*b7893ccfSSadaf Ebrahimi         if (memcmp(&data[2], expected_uuid, VK_UUID_SIZE) != 0) return;  // different version
233*b7893ccfSSadaf Ebrahimi 
234*b7893ccfSSadaf Ebrahimi         data = (uint32_t const *)(reinterpret_cast<uint8_t const *>(data) + headerSize);
235*b7893ccfSSadaf Ebrahimi 
236*b7893ccfSSadaf Ebrahimi         for (; size < pCreateInfo->initialDataSize; data++, size += sizeof(uint32_t)) {
237*b7893ccfSSadaf Ebrahimi             good_shader_hashes.insert(*data);
238*b7893ccfSSadaf Ebrahimi         }
239*b7893ccfSSadaf Ebrahimi     }
240*b7893ccfSSadaf Ebrahimi 
Write(size_t * pDataSize,void * pData)241*b7893ccfSSadaf Ebrahimi     void Write(size_t *pDataSize, void *pData) {
242*b7893ccfSSadaf Ebrahimi         const auto headerSize = 2 * sizeof(uint32_t) + VK_UUID_SIZE;  // 4 bytes for header size + 4 bytes for version number + UUID
243*b7893ccfSSadaf Ebrahimi         if (!pData) {
244*b7893ccfSSadaf Ebrahimi             *pDataSize = headerSize + good_shader_hashes.size() * sizeof(uint32_t);
245*b7893ccfSSadaf Ebrahimi             return;
246*b7893ccfSSadaf Ebrahimi         }
247*b7893ccfSSadaf Ebrahimi 
248*b7893ccfSSadaf Ebrahimi         if (*pDataSize < headerSize) {
249*b7893ccfSSadaf Ebrahimi             *pDataSize = 0;
250*b7893ccfSSadaf Ebrahimi             return;  // Too small for even the header!
251*b7893ccfSSadaf Ebrahimi         }
252*b7893ccfSSadaf Ebrahimi 
253*b7893ccfSSadaf Ebrahimi         uint32_t *out = (uint32_t *)pData;
254*b7893ccfSSadaf Ebrahimi         size_t actualSize = headerSize;
255*b7893ccfSSadaf Ebrahimi 
256*b7893ccfSSadaf Ebrahimi         // Write the header
257*b7893ccfSSadaf Ebrahimi         *out++ = headerSize;
258*b7893ccfSSadaf Ebrahimi         *out++ = VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT;
259*b7893ccfSSadaf Ebrahimi         Sha1ToVkUuid(SPIRV_TOOLS_COMMIT_ID, reinterpret_cast<uint8_t *>(out));
260*b7893ccfSSadaf Ebrahimi         out = (uint32_t *)(reinterpret_cast<uint8_t *>(out) + VK_UUID_SIZE);
261*b7893ccfSSadaf Ebrahimi 
262*b7893ccfSSadaf Ebrahimi         for (auto it = good_shader_hashes.begin(); it != good_shader_hashes.end() && actualSize < *pDataSize;
263*b7893ccfSSadaf Ebrahimi              it++, out++, actualSize += sizeof(uint32_t)) {
264*b7893ccfSSadaf Ebrahimi             *out = *it;
265*b7893ccfSSadaf Ebrahimi         }
266*b7893ccfSSadaf Ebrahimi 
267*b7893ccfSSadaf Ebrahimi         *pDataSize = actualSize;
268*b7893ccfSSadaf Ebrahimi     }
269*b7893ccfSSadaf Ebrahimi 
Merge(ValidationCache const * other)270*b7893ccfSSadaf Ebrahimi     void Merge(ValidationCache const *other) {
271*b7893ccfSSadaf Ebrahimi         good_shader_hashes.reserve(good_shader_hashes.size() + other->good_shader_hashes.size());
272*b7893ccfSSadaf Ebrahimi         for (auto h : other->good_shader_hashes) good_shader_hashes.insert(h);
273*b7893ccfSSadaf Ebrahimi     }
274*b7893ccfSSadaf Ebrahimi 
275*b7893ccfSSadaf Ebrahimi     static uint32_t MakeShaderHash(VkShaderModuleCreateInfo const *smci);
276*b7893ccfSSadaf Ebrahimi 
Contains(uint32_t hash)277*b7893ccfSSadaf Ebrahimi     bool Contains(uint32_t hash) { return good_shader_hashes.count(hash) != 0; }
278*b7893ccfSSadaf Ebrahimi 
Insert(uint32_t hash)279*b7893ccfSSadaf Ebrahimi     void Insert(uint32_t hash) { good_shader_hashes.insert(hash); }
280*b7893ccfSSadaf Ebrahimi 
281*b7893ccfSSadaf Ebrahimi    private:
Sha1ToVkUuid(const char * sha1_str,uint8_t uuid[VK_UUID_SIZE])282*b7893ccfSSadaf Ebrahimi     void Sha1ToVkUuid(const char *sha1_str, uint8_t uuid[VK_UUID_SIZE]) {
283*b7893ccfSSadaf Ebrahimi         // Convert sha1_str from a hex string to binary. We only need VK_UUID_BYTES of
284*b7893ccfSSadaf Ebrahimi         // output, so pad with zeroes if the input string is shorter than that, and truncate
285*b7893ccfSSadaf Ebrahimi         // if it's longer.
286*b7893ccfSSadaf Ebrahimi         char padded_sha1_str[2 * VK_UUID_SIZE + 1] = {};
287*b7893ccfSSadaf Ebrahimi         strncpy(padded_sha1_str, sha1_str, 2 * VK_UUID_SIZE + 1);
288*b7893ccfSSadaf Ebrahimi         char byte_str[3] = {};
289*b7893ccfSSadaf Ebrahimi         for (uint32_t i = 0; i < VK_UUID_SIZE; ++i) {
290*b7893ccfSSadaf Ebrahimi             byte_str[0] = padded_sha1_str[2 * i + 0];
291*b7893ccfSSadaf Ebrahimi             byte_str[1] = padded_sha1_str[2 * i + 1];
292*b7893ccfSSadaf Ebrahimi             uuid[i] = static_cast<uint8_t>(strtol(byte_str, NULL, 16));
293*b7893ccfSSadaf Ebrahimi         }
294*b7893ccfSSadaf Ebrahimi     }
295*b7893ccfSSadaf Ebrahimi };
296*b7893ccfSSadaf Ebrahimi 
297*b7893ccfSSadaf Ebrahimi #endif  // VULKAN_SHADER_VALIDATION_H
298