shader_validation.cpp revision bb6e1ecb1215cdd9aa496b3f9e2c5521711760f6
1d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes/* Copyright (c) 2015-2017 The Khronos Group Inc.
2d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes * Copyright (c) 2015-2017 Valve Corporation
3d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes * Copyright (c) 2015-2017 LunarG, Inc.
4d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes * Copyright (C) 2015-2017 Google Inc.
5d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes *
6d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes * Licensed under the Apache License, Version 2.0 (the "License");
7d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes * you may not use this file except in compliance with the License.
8d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes * You may obtain a copy of the License at
9d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes *
10d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes *     http://www.apache.org/licenses/LICENSE-2.0
11d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes *
12d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes * Unless required by applicable law or agreed to in writing, software
13d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes * distributed under the License is distributed on an "AS IS" BASIS,
14d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes * See the License for the specific language governing permissions and
16d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes * limitations under the License.
17d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes *
18d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes * Author: Chris Forbes <chrisf@ijw.co.nz>
19d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes */
20d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
21d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes#include <cinttypes>
22d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes#include <cassert>
23d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes#include <vector>
24d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes#include <unordered_map>
25d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes#include <string>
26d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes#include <sstream>
27d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes#include <SPIRV/spirv.hpp>
28d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes#include "vk_loader_platform.h"
29d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes#include "vk_enum_string_helper.h"
30d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes#include "vk_layer_table.h"
31d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes#include "vk_layer_data.h"
32d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes#include "vk_layer_extension_utils.h"
33d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes#include "vk_layer_utils.h"
34d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes#include "core_validation.h"
35d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes#include "core_validation_types.h"
36d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes#include "shader_validation.h"
377aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes#include "spirv-tools/libspirv.h"
38d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
39d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesenum FORMAT_TYPE {
40d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    FORMAT_TYPE_FLOAT = 1,  // UNORM, SNORM, FLOAT, USCALED, SSCALED, SRGB -- anything we consider float in the shader
41d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    FORMAT_TYPE_SINT = 2,
42d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    FORMAT_TYPE_UINT = 4,
43d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes};
44d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
45d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbestypedef std::pair<unsigned, unsigned> location_t;
46d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
47d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstruct interface_var {
48d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    uint32_t id;
49d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    uint32_t type_id;
50d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    uint32_t offset;
51d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    bool is_patch;
52d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    bool is_block_member;
53d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    bool is_relaxed_precision;
54d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // TODO: collect the name, too? Isn't required to be present.
55d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes};
56d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
57d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstruct shader_stage_attributes {
58d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    char const *const name;
59d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    bool arrayed_input;
60d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    bool arrayed_output;
61d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes};
62d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
63d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic shader_stage_attributes shader_stage_attribs[] = {
64d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    {"vertex shader", false, false},  {"tessellation control shader", true, true}, {"tessellation evaluation shader", true, false},
65d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    {"geometry shader", true, false}, {"fragment shader", false, false},
66d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes};
67d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
68d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes// SPIRV utility functions
69d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesvoid shader_module::build_def_index() {
70d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    for (auto insn : *this) {
71d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        switch (insn.opcode()) {
72d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // Types
73d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypeVoid:
74d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypeBool:
75d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypeInt:
76d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypeFloat:
77d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypeVector:
78d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypeMatrix:
79d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypeImage:
80d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypeSampler:
81d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypeSampledImage:
82d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypeArray:
83d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypeRuntimeArray:
84d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypeStruct:
85d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypeOpaque:
86d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypePointer:
87d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypeFunction:
88d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypeEvent:
89d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypeDeviceEvent:
90d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypeReserveId:
91d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypeQueue:
92d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypePipe:
93d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                def_index[insn.word(1)] = insn.offset();
94d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                break;
95d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
96d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                // Fixed constants
97d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpConstantTrue:
98d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpConstantFalse:
99d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpConstant:
100d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpConstantComposite:
101d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpConstantSampler:
102d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpConstantNull:
103d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                def_index[insn.word(2)] = insn.offset();
104d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                break;
105d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
106d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                // Specialization constants
107d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpSpecConstantTrue:
108d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpSpecConstantFalse:
109d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpSpecConstant:
110d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpSpecConstantComposite:
111d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpSpecConstantOp:
112d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                def_index[insn.word(2)] = insn.offset();
113d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                break;
114d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
115d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                // Variables
116d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpVariable:
117d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                def_index[insn.word(2)] = insn.offset();
118d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                break;
119d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
120d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                // Functions
121d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpFunction:
122d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                def_index[insn.word(2)] = insn.offset();
123d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                break;
124d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
125d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            default:
126d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                // We don't care about any other defs for now.
127d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                break;
128d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
129d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
130d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
131d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
132d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic spirv_inst_iter find_entrypoint(shader_module const *src, char const *name, VkShaderStageFlagBits stageBits) {
133d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    for (auto insn : *src) {
134d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (insn.opcode() == spv::OpEntryPoint) {
135d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            auto entrypointName = (char const *)&insn.word(3);
136d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            auto entrypointStageBits = 1u << insn.word(1);
137d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
138d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (!strcmp(entrypointName, name) && (entrypointStageBits & stageBits)) {
139d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                return insn;
140d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
141d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
142d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
143d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
144d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return src->end();
145d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
146d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
147d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic char const *storage_class_name(unsigned sc) {
148d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    switch (sc) {
149d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::StorageClassInput:
150d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return "input";
151d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::StorageClassOutput:
152d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return "output";
153d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::StorageClassUniformConstant:
154d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return "const uniform";
155d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::StorageClassUniform:
156d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return "uniform";
157d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::StorageClassWorkgroup:
158d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return "workgroup local";
159d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::StorageClassCrossWorkgroup:
160d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return "workgroup global";
161d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::StorageClassPrivate:
162d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return "private global";
163d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::StorageClassFunction:
164d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return "function";
165d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::StorageClassGeneric:
166d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return "generic";
167d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::StorageClassAtomicCounter:
168d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return "atomic counter";
169d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::StorageClassImage:
170d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return "image";
171d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::StorageClassPushConstant:
172d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return "push constant";
173d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        default:
174d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return "unknown";
175d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
176d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
177d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
178d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes// Get the value of an integral constant
179d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesunsigned get_constant_value(shader_module const *src, unsigned id) {
180d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto value = src->get_def(id);
181d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    assert(value != src->end());
182d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
183d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (value.opcode() != spv::OpConstant) {
184d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        // TODO: Either ensure that the specialization transform is already performed on a module we're
185d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        //       considering here, OR -- specialize on the fly now.
186d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        return 1;
187d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
188d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
189d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return value.word(3);
190d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
191d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
192d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic void describe_type_inner(std::ostringstream &ss, shader_module const *src, unsigned type) {
193d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto insn = src->get_def(type);
194d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    assert(insn != src->end());
195d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
196d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    switch (insn.opcode()) {
197d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeBool:
198d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            ss << "bool";
199d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            break;
200d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeInt:
201d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            ss << (insn.word(3) ? 's' : 'u') << "int" << insn.word(2);
202d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            break;
203d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeFloat:
204d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            ss << "float" << insn.word(2);
205d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            break;
206d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeVector:
207d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            ss << "vec" << insn.word(3) << " of ";
208d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            describe_type_inner(ss, src, insn.word(2));
209d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            break;
210d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeMatrix:
211d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            ss << "mat" << insn.word(3) << " of ";
212d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            describe_type_inner(ss, src, insn.word(2));
213d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            break;
214d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeArray:
215d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            ss << "arr[" << get_constant_value(src, insn.word(3)) << "] of ";
216d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            describe_type_inner(ss, src, insn.word(2));
217d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            break;
218d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypePointer:
219d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            ss << "ptr to " << storage_class_name(insn.word(2)) << " ";
220d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            describe_type_inner(ss, src, insn.word(3));
221d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            break;
222d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeStruct: {
223d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            ss << "struct of (";
224d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            for (unsigned i = 2; i < insn.len(); i++) {
225d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                describe_type_inner(ss, src, insn.word(i));
226d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                if (i == insn.len() - 1) {
227d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    ss << ")";
228d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                } else {
229d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    ss << ", ";
230d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                }
231d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
232d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            break;
233d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
234d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeSampler:
235d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            ss << "sampler";
236d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            break;
237d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeSampledImage:
238d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            ss << "sampler+";
239d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            describe_type_inner(ss, src, insn.word(2));
240d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            break;
241d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeImage:
242d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            ss << "image(dim=" << insn.word(3) << ", sampled=" << insn.word(7) << ")";
243d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            break;
244d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        default:
245d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            ss << "oddtype";
246d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            break;
247d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
248d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
249d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
250d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic std::string describe_type(shader_module const *src, unsigned type) {
251d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    std::ostringstream ss;
252d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    describe_type_inner(ss, src, type);
253d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return ss.str();
254d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
255d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
256d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic bool is_narrow_numeric_type(spirv_inst_iter type) {
257d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (type.opcode() != spv::OpTypeInt && type.opcode() != spv::OpTypeFloat) return false;
258d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return type.word(2) < 64;
259d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
260d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
261d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic bool types_match(shader_module const *a, shader_module const *b, unsigned a_type, unsigned b_type, bool a_arrayed,
262d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        bool b_arrayed, bool relaxed) {
263d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // Walk two type trees together, and complain about differences
264d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto a_insn = a->get_def(a_type);
265d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto b_insn = b->get_def(b_type);
266d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    assert(a_insn != a->end());
267d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    assert(b_insn != b->end());
268d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
269d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (a_arrayed && a_insn.opcode() == spv::OpTypeArray) {
270d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        return types_match(a, b, a_insn.word(2), b_type, false, b_arrayed, relaxed);
271d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
272d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
273d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (b_arrayed && b_insn.opcode() == spv::OpTypeArray) {
274d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        // We probably just found the extra level of arrayness in b_type: compare the type inside it to a_type
275d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        return types_match(a, b, a_type, b_insn.word(2), a_arrayed, false, relaxed);
276d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
277d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
278d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (a_insn.opcode() == spv::OpTypeVector && relaxed && is_narrow_numeric_type(b_insn)) {
279d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        return types_match(a, b, a_insn.word(2), b_type, a_arrayed, b_arrayed, false);
280d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
281d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
282d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (a_insn.opcode() != b_insn.opcode()) {
283d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        return false;
284d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
285d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
286d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (a_insn.opcode() == spv::OpTypePointer) {
287d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        // Match on pointee type. storage class is expected to differ
288d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        return types_match(a, b, a_insn.word(3), b_insn.word(3), a_arrayed, b_arrayed, relaxed);
289d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
290d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
291d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (a_arrayed || b_arrayed) {
292d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        // If we havent resolved array-of-verts by here, we're not going to.
293d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        return false;
294d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
295d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
296d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    switch (a_insn.opcode()) {
297d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeBool:
298d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return true;
299d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeInt:
300d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // Match on width, signedness
301d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return a_insn.word(2) == b_insn.word(2) && a_insn.word(3) == b_insn.word(3);
302d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeFloat:
303d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // Match on width
304d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return a_insn.word(2) == b_insn.word(2);
305d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeVector:
306d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // Match on element type, count.
307d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (!types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false)) return false;
308d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (relaxed && is_narrow_numeric_type(a->get_def(a_insn.word(2)))) {
309d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                return a_insn.word(3) >= b_insn.word(3);
310d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            } else {
311d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                return a_insn.word(3) == b_insn.word(3);
312d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
313d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeMatrix:
314d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // Match on element type, count.
315d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
316d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                a_insn.word(3) == b_insn.word(3);
317d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeArray:
318d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // Match on element type, count. these all have the same layout. we don't get here if b_arrayed. This differs from
319d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // vector & matrix types in that the array size is the id of a constant instruction, * not a literal within OpTypeArray
320d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
321d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                get_constant_value(a, a_insn.word(3)) == get_constant_value(b, b_insn.word(3));
322d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeStruct:
323d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // Match on all element types
324d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {
325d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (a_insn.len() != b_insn.len()) {
326d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                return false;  // Structs cannot match if member counts differ
327d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
328d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
329d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            for (unsigned i = 2; i < a_insn.len(); i++) {
330d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                if (!types_match(a, b, a_insn.word(i), b_insn.word(i), a_arrayed, b_arrayed, false)) {
331d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    return false;
332d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                }
333d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
334d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
335d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return true;
336d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
337d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        default:
338d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // Remaining types are CLisms, or may not appear in the interfaces we are interested in. Just claim no match.
339d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return false;
340d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
341d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
342d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
343d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic unsigned value_or_default(std::unordered_map<unsigned, unsigned> const &map, unsigned id, unsigned def) {
344d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto it = map.find(id);
345d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (it == map.end())
346d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        return def;
347d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    else
348d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        return it->second;
349d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
350d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
351d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic unsigned get_locations_consumed_by_type(shader_module const *src, unsigned type, bool strip_array_level) {
352d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto insn = src->get_def(type);
353d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    assert(insn != src->end());
354d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
355d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    switch (insn.opcode()) {
356d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypePointer:
357d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // See through the ptr -- this is only ever at the toplevel for graphics shaders we're never actually passing
358d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // pointers around.
359d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return get_locations_consumed_by_type(src, insn.word(3), strip_array_level);
360d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeArray:
361d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (strip_array_level) {
362d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                return get_locations_consumed_by_type(src, insn.word(2), false);
363d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            } else {
364d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                return get_constant_value(src, insn.word(3)) * get_locations_consumed_by_type(src, insn.word(2), false);
365d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
366d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeMatrix:
367d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // Num locations is the dimension * element size
368d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return insn.word(3) * get_locations_consumed_by_type(src, insn.word(2), false);
369d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeVector: {
370d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            auto scalar_type = src->get_def(insn.word(2));
371d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            auto bit_width =
372d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                (scalar_type.opcode() == spv::OpTypeInt || scalar_type.opcode() == spv::OpTypeFloat) ? scalar_type.word(2) : 32;
373d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
374d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // Locations are 128-bit wide; 3- and 4-component vectors of 64 bit types require two.
375d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return (bit_width * insn.word(3) + 127) / 128;
376d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
377d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        default:
378d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // Everything else is just 1.
379d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return 1;
380d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
381d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // TODO: extend to handle 64bit scalar types, whose vectors may need multiple locations.
382d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
383d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
384d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
385d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic unsigned get_locations_consumed_by_format(VkFormat format) {
386d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    switch (format) {
387d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case VK_FORMAT_R64G64B64A64_SFLOAT:
388d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case VK_FORMAT_R64G64B64A64_SINT:
389d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case VK_FORMAT_R64G64B64A64_UINT:
390d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case VK_FORMAT_R64G64B64_SFLOAT:
391d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case VK_FORMAT_R64G64B64_SINT:
392d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case VK_FORMAT_R64G64B64_UINT:
393d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return 2;
394d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        default:
395d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return 1;
396d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
397d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
398d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
399d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic unsigned get_format_type(VkFormat fmt) {
400d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (FormatIsSInt(fmt))
401d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        return FORMAT_TYPE_SINT;
402d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (FormatIsUInt(fmt))
403d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        return FORMAT_TYPE_UINT;
404d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (FormatIsDepthAndStencil(fmt))
405d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        return FORMAT_TYPE_FLOAT | FORMAT_TYPE_UINT;
406d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (fmt == VK_FORMAT_UNDEFINED)
407d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        return 0;
408d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // everything else -- UNORM/SNORM/FLOAT/USCALED/SSCALED is all float in the shader.
409d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return FORMAT_TYPE_FLOAT;
410d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
411d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
412d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes// characterizes a SPIR-V type appearing in an interface to a FF stage, for comparison to a VkFormat's characterization above.
413d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic unsigned get_fundamental_type(shader_module const *src, unsigned type) {
414d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto insn = src->get_def(type);
415d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    assert(insn != src->end());
416d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
417d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    switch (insn.opcode()) {
418d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeInt:
419d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return insn.word(3) ? FORMAT_TYPE_SINT : FORMAT_TYPE_UINT;
420d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeFloat:
421d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return FORMAT_TYPE_FLOAT;
422d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeVector:
423d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return get_fundamental_type(src, insn.word(2));
424d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeMatrix:
425d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return get_fundamental_type(src, insn.word(2));
426d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeArray:
427d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return get_fundamental_type(src, insn.word(2));
428d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypePointer:
429d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return get_fundamental_type(src, insn.word(3));
430d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeImage:
431d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return get_fundamental_type(src, insn.word(2));
432d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
433d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        default:
434d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return 0;
435d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
436d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
437d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
438d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic uint32_t get_shader_stage_id(VkShaderStageFlagBits stage) {
439d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    uint32_t bit_pos = uint32_t(u_ffs(stage));
440d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return bit_pos - 1;
441d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
442d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
443d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic spirv_inst_iter get_struct_type(shader_module const *src, spirv_inst_iter def, bool is_array_of_verts) {
444d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    while (true) {
445d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (def.opcode() == spv::OpTypePointer) {
446d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            def = src->get_def(def.word(3));
447d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        } else if (def.opcode() == spv::OpTypeArray && is_array_of_verts) {
448d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            def = src->get_def(def.word(2));
449d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            is_array_of_verts = false;
450d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        } else if (def.opcode() == spv::OpTypeStruct) {
451d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return def;
452d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        } else {
453d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return src->end();
454d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
455d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
456d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
457d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
458e0143ed99bb745a09b27fc7cb535ae7dcc91c09cChris Forbesstatic bool collect_interface_block_members(shader_module const *src, std::map<location_t, interface_var> *out,
459d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                            std::unordered_map<unsigned, unsigned> const &blocks, bool is_array_of_verts,
460e0143ed99bb745a09b27fc7cb535ae7dcc91c09cChris Forbes                                            uint32_t id, uint32_t type_id, bool is_patch, int /*first_location*/) {
461d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // Walk down the type_id presented, trying to determine whether it's actually an interface block.
462d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto type = get_struct_type(src, src->get_def(type_id), is_array_of_verts && !is_patch);
463d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (type == src->end() || blocks.find(type.word(1)) == blocks.end()) {
464d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        // This isn't an interface block.
465e0143ed99bb745a09b27fc7cb535ae7dcc91c09cChris Forbes        return false;
466d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
467d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
468d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    std::unordered_map<unsigned, unsigned> member_components;
469d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    std::unordered_map<unsigned, unsigned> member_relaxed_precision;
470e0143ed99bb745a09b27fc7cb535ae7dcc91c09cChris Forbes    std::unordered_map<unsigned, unsigned> member_patch;
471d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
472d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // Walk all the OpMemberDecorate for type's result id -- first pass, collect components.
473d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    for (auto insn : *src) {
474d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
475d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            unsigned member_index = insn.word(2);
476d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
477d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (insn.word(3) == spv::DecorationComponent) {
478d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                unsigned component = insn.word(4);
479d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                member_components[member_index] = component;
480d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
481d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
482d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (insn.word(3) == spv::DecorationRelaxedPrecision) {
483d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                member_relaxed_precision[member_index] = 1;
484d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
485e0143ed99bb745a09b27fc7cb535ae7dcc91c09cChris Forbes
486e0143ed99bb745a09b27fc7cb535ae7dcc91c09cChris Forbes            if (insn.word(3) == spv::DecorationPatch) {
487e0143ed99bb745a09b27fc7cb535ae7dcc91c09cChris Forbes                member_patch[member_index] = 1;
488e0143ed99bb745a09b27fc7cb535ae7dcc91c09cChris Forbes            }
489d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
490d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
491d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
492e0143ed99bb745a09b27fc7cb535ae7dcc91c09cChris Forbes    // TODO: correctly handle location assignment from outside
493e0143ed99bb745a09b27fc7cb535ae7dcc91c09cChris Forbes
494d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // Second pass -- produce the output, from Location decorations
495d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    for (auto insn : *src) {
496d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
497d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            unsigned member_index = insn.word(2);
498d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            unsigned member_type_id = type.word(2 + member_index);
499d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
500d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (insn.word(3) == spv::DecorationLocation) {
501d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                unsigned location = insn.word(4);
502d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                unsigned num_locations = get_locations_consumed_by_type(src, member_type_id, false);
503d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                auto component_it = member_components.find(member_index);
504d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                unsigned component = component_it == member_components.end() ? 0 : component_it->second;
505d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                bool is_relaxed_precision = member_relaxed_precision.find(member_index) != member_relaxed_precision.end();
506e0143ed99bb745a09b27fc7cb535ae7dcc91c09cChris Forbes                bool member_is_patch = is_patch || member_patch.count(member_index)>0;
507d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
508d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                for (unsigned int offset = 0; offset < num_locations; offset++) {
509d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    interface_var v = {};
510d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    v.id = id;
511d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    // TODO: member index in interface_var too?
512d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    v.type_id = member_type_id;
513d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    v.offset = offset;
514e0143ed99bb745a09b27fc7cb535ae7dcc91c09cChris Forbes                    v.is_patch = member_is_patch;
515d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    v.is_block_member = true;
516d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    v.is_relaxed_precision = is_relaxed_precision;
517d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    (*out)[std::make_pair(location + offset, component)] = v;
518d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                }
519d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
520d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
521d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
522e0143ed99bb745a09b27fc7cb535ae7dcc91c09cChris Forbes
523e0143ed99bb745a09b27fc7cb535ae7dcc91c09cChris Forbes    return true;
524d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
525d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
526d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic std::map<location_t, interface_var> collect_interface_by_location(shader_module const *src, spirv_inst_iter entrypoint,
527d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                                                         spv::StorageClass sinterface, bool is_array_of_verts) {
528d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    std::unordered_map<unsigned, unsigned> var_locations;
529d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    std::unordered_map<unsigned, unsigned> var_builtins;
530d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    std::unordered_map<unsigned, unsigned> var_components;
531d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    std::unordered_map<unsigned, unsigned> blocks;
532d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    std::unordered_map<unsigned, unsigned> var_patch;
533d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    std::unordered_map<unsigned, unsigned> var_relaxed_precision;
534d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
535d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    for (auto insn : *src) {
536d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        // We consider two interface models: SSO rendezvous-by-location, and builtins. Complain about anything that
537d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        // fits neither model.
538d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (insn.opcode() == spv::OpDecorate) {
539d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (insn.word(2) == spv::DecorationLocation) {
540d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                var_locations[insn.word(1)] = insn.word(3);
541d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
542d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
543d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (insn.word(2) == spv::DecorationBuiltIn) {
544d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                var_builtins[insn.word(1)] = insn.word(3);
545d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
546d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
547d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (insn.word(2) == spv::DecorationComponent) {
548d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                var_components[insn.word(1)] = insn.word(3);
549d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
550d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
551d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (insn.word(2) == spv::DecorationBlock) {
552d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                blocks[insn.word(1)] = 1;
553d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
554d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
555d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (insn.word(2) == spv::DecorationPatch) {
556d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                var_patch[insn.word(1)] = 1;
557d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
558d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
559d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (insn.word(2) == spv::DecorationRelaxedPrecision) {
560d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                var_relaxed_precision[insn.word(1)] = 1;
561d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
562d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
563d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
564d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
565d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // TODO: handle grouped decorations
566d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // TODO: handle index=1 dual source outputs from FS -- two vars will have the same location, and we DON'T want to clobber.
567d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
568d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // Find the end of the entrypoint's name string. additional zero bytes follow the actual null terminator, to fill out the
569d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // rest of the word - so we only need to look at the last byte in the word to determine which word contains the terminator.
570d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    uint32_t word = 3;
571d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    while (entrypoint.word(word) & 0xff000000u) {
572d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        ++word;
573d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
574d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    ++word;
575d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
576d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    std::map<location_t, interface_var> out;
577d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
578d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    for (; word < entrypoint.len(); word++) {
579d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        auto insn = src->get_def(entrypoint.word(word));
580d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        assert(insn != src->end());
581d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        assert(insn.opcode() == spv::OpVariable);
582d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
583d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (insn.word(3) == static_cast<uint32_t>(sinterface)) {
584d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            unsigned id = insn.word(2);
585d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            unsigned type = insn.word(1);
586d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
587bb6e1ecb1215cdd9aa496b3f9e2c5521711760f6Jamie Madill            int location = value_or_default(var_locations, id, static_cast<unsigned>(-1));
588bb6e1ecb1215cdd9aa496b3f9e2c5521711760f6Jamie Madill            int builtin = value_or_default(var_builtins, id, static_cast<unsigned>(-1));
589d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            unsigned component = value_or_default(var_components, id, 0);  // Unspecified is OK, is 0
590d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            bool is_patch = var_patch.find(id) != var_patch.end();
591d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            bool is_relaxed_precision = var_relaxed_precision.find(id) != var_relaxed_precision.end();
592d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
593e0143ed99bb745a09b27fc7cb535ae7dcc91c09cChris Forbes            if (builtin != -1) continue;
594e0143ed99bb745a09b27fc7cb535ae7dcc91c09cChris Forbes            else if (!collect_interface_block_members(src, &out, blocks, is_array_of_verts, id, type, is_patch, location)) {
595d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                // A user-defined interface variable, with a location. Where a variable occupied multiple locations, emit
596d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                // one result for each.
597d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                unsigned num_locations = get_locations_consumed_by_type(src, type, is_array_of_verts && !is_patch);
598d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                for (unsigned int offset = 0; offset < num_locations; offset++) {
599d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    interface_var v = {};
600d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    v.id = id;
601d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    v.type_id = type;
602d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    v.offset = offset;
603d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    v.is_patch = is_patch;
604d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    v.is_relaxed_precision = is_relaxed_precision;
605d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    out[std::make_pair(location + offset, component)] = v;
606d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                }
607d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
608d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
609d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
610d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
611d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return out;
612d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
613d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
614d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic std::vector<std::pair<uint32_t, interface_var>> collect_interface_by_input_attachment_index(
615d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    shader_module const *src, std::unordered_set<uint32_t> const &accessible_ids) {
616d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    std::vector<std::pair<uint32_t, interface_var>> out;
617d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
618d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    for (auto insn : *src) {
619d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (insn.opcode() == spv::OpDecorate) {
620d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (insn.word(2) == spv::DecorationInputAttachmentIndex) {
621d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                auto attachment_index = insn.word(3);
622d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                auto id = insn.word(1);
623d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
624d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                if (accessible_ids.count(id)) {
625d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    auto def = src->get_def(id);
626d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    assert(def != src->end());
627d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
628d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    if (def.opcode() == spv::OpVariable && insn.word(3) == spv::StorageClassUniformConstant) {
629d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        auto num_locations = get_locations_consumed_by_type(src, def.word(1), false);
630d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        for (unsigned int offset = 0; offset < num_locations; offset++) {
631d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            interface_var v = {};
632d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            v.id = id;
633d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            v.type_id = def.word(1);
634d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            v.offset = offset;
635d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            out.emplace_back(attachment_index + offset, v);
636d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        }
637d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    }
638d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                }
639d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
640d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
641d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
642d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
643d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return out;
644d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
645d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
646d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic std::vector<std::pair<descriptor_slot_t, interface_var>> collect_interface_by_descriptor_slot(
647d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    debug_report_data const *report_data, shader_module const *src, std::unordered_set<uint32_t> const &accessible_ids) {
648d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    std::unordered_map<unsigned, unsigned> var_sets;
649d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    std::unordered_map<unsigned, unsigned> var_bindings;
650d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
651d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    for (auto insn : *src) {
652d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        // All variables in the Uniform or UniformConstant storage classes are required to be decorated with both
653d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        // DecorationDescriptorSet and DecorationBinding.
654d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (insn.opcode() == spv::OpDecorate) {
655d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (insn.word(2) == spv::DecorationDescriptorSet) {
656d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                var_sets[insn.word(1)] = insn.word(3);
657d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
658d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
659d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (insn.word(2) == spv::DecorationBinding) {
660d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                var_bindings[insn.word(1)] = insn.word(3);
661d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
662d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
663d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
664d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
665d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    std::vector<std::pair<descriptor_slot_t, interface_var>> out;
666d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
667d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    for (auto id : accessible_ids) {
668d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        auto insn = src->get_def(id);
669d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        assert(insn != src->end());
670d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
671d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (insn.opcode() == spv::OpVariable &&
672d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            (insn.word(3) == spv::StorageClassUniform || insn.word(3) == spv::StorageClassUniformConstant)) {
673d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            unsigned set = value_or_default(var_sets, insn.word(2), 0);
674d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            unsigned binding = value_or_default(var_bindings, insn.word(2), 0);
675d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
676d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            interface_var v = {};
677d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            v.id = insn.word(2);
678d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            v.type_id = insn.word(1);
679d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            out.emplace_back(std::make_pair(set, binding), v);
680d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
681d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
682d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
683d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return out;
684d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
685d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
686d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
687d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
688d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic bool validate_vi_consistency(debug_report_data const *report_data, VkPipelineVertexInputStateCreateInfo const *vi) {
689d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // Walk the binding descriptions, which describe the step rate and stride of each vertex buffer.  Each binding should
690d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // be specified only once.
691d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    std::unordered_map<uint32_t, VkVertexInputBindingDescription const *> bindings;
692d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    bool skip = false;
693d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
694d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    for (unsigned i = 0; i < vi->vertexBindingDescriptionCount; i++) {
695d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        auto desc = &vi->pVertexBindingDescriptions[i];
696d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        auto &binding = bindings[desc->binding];
697d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (binding) {
698d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // TODO: VALIDATION_ERROR_096005cc perhaps?
699d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
700d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            SHADER_CHECKER_INCONSISTENT_VI, "SC", "Duplicate vertex input binding descriptions for binding %d",
701d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            desc->binding);
702d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        } else {
703d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            binding = desc;
704d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
705d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
706d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
707d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return skip;
708d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
709d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
710d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic bool validate_vi_against_vs_inputs(debug_report_data const *report_data, VkPipelineVertexInputStateCreateInfo const *vi,
711d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                          shader_module const *vs, spirv_inst_iter entrypoint) {
712d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    bool skip = false;
713d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
714d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto inputs = collect_interface_by_location(vs, entrypoint, spv::StorageClassInput, false);
715d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
716d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // Build index by location
717d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    std::map<uint32_t, VkVertexInputAttributeDescription const *> attribs;
718d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (vi) {
719d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        for (unsigned i = 0; i < vi->vertexAttributeDescriptionCount; i++) {
720d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            auto num_locations = get_locations_consumed_by_format(vi->pVertexAttributeDescriptions[i].format);
721d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            for (auto j = 0u; j < num_locations; j++) {
722d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                attribs[vi->pVertexAttributeDescriptions[i].location + j] = &vi->pVertexAttributeDescriptions[i];
723d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
724d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
725d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
726d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
727d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto it_a = attribs.begin();
728d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto it_b = inputs.begin();
729d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    bool used = false;
730d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
731d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    while ((attribs.size() > 0 && it_a != attribs.end()) || (inputs.size() > 0 && it_b != inputs.end())) {
732d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        bool a_at_end = attribs.size() == 0 || it_a == attribs.end();
733d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        bool b_at_end = inputs.size() == 0 || it_b == inputs.end();
734d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        auto a_first = a_at_end ? 0 : it_a->first;
735d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        auto b_first = b_at_end ? 0 : it_b->first.first;
736d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (!a_at_end && (b_at_end || a_first < b_first)) {
737d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (!used && log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
738d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                 0, __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
739d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                 "Vertex attribute at location %d not consumed by vertex shader", a_first)) {
740d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                skip = true;
741d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
742d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            used = false;
743d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            it_a++;
744d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        } else if (!b_at_end && (a_at_end || b_first < a_first)) {
745d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
746d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Vertex shader consumes input at location %d but not provided",
747d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            b_first);
748d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            it_b++;
749d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        } else {
750d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            unsigned attrib_type = get_format_type(it_a->second->format);
751d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            unsigned input_type = get_fundamental_type(vs, it_b->second.type_id);
752d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
753d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // Type checking
754d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (!(attrib_type & input_type)) {
755d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
756d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
757d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                "Attribute type of `%s` at location %d does not match vertex shader input type of `%s`",
758d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                string_VkFormat(it_a->second->format), a_first, describe_type(vs, it_b->second.type_id).c_str());
759d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
760d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
761d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // OK!
762d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            used = true;
763d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            it_b++;
764d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
765d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
766d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
767d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return skip;
768d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
769d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
770d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic bool validate_fs_outputs_against_render_pass(debug_report_data const *report_data, shader_module const *fs,
771ac7791048680b52b3f3f751b350567b5092cd02eChris Forbes                                                    spirv_inst_iter entrypoint, PIPELINE_STATE const *pipeline,
772d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                                    uint32_t subpass_index) {
773ac7791048680b52b3f3f751b350567b5092cd02eChris Forbes    auto rpci = pipeline->render_pass_ci.ptr();
7748534a4d376268080c7cf7443a095e3d7ca59af1bChris Forbes
775d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    std::map<uint32_t, VkFormat> color_attachments;
776d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto subpass = rpci->pSubpasses[subpass_index];
777d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    for (auto i = 0u; i < subpass.colorAttachmentCount; ++i) {
778d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        uint32_t attachment = subpass.pColorAttachments[i].attachment;
779d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (attachment == VK_ATTACHMENT_UNUSED) continue;
780d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (rpci->pAttachments[attachment].format != VK_FORMAT_UNDEFINED) {
781d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            color_attachments[i] = rpci->pAttachments[attachment].format;
782d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
783d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
784d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
785d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    bool skip = false;
786d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
787d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // TODO: dual source blend index (spv::DecIndex, zero if not provided)
788d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
789d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto outputs = collect_interface_by_location(fs, entrypoint, spv::StorageClassOutput, false);
790d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
791d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto it_a = outputs.begin();
792d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto it_b = color_attachments.begin();
793d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
794d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // Walk attachment list and outputs together
795d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
796d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    while ((outputs.size() > 0 && it_a != outputs.end()) || (color_attachments.size() > 0 && it_b != color_attachments.end())) {
797d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        bool a_at_end = outputs.size() == 0 || it_a == outputs.end();
798d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        bool b_at_end = color_attachments.size() == 0 || it_b == color_attachments.end();
799d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
800d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (!a_at_end && (b_at_end || it_a->first.first < it_b->first)) {
801d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
802d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
803d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            "fragment shader writes to output location %d with no matching attachment", it_a->first.first);
804d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            it_a++;
805d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        } else if (!b_at_end && (a_at_end || it_a->first.first > it_b->first)) {
806841b2fe0cb1151b0eaf3c519f87162ce960e02c1Chris Forbes            // Only complain if there are unmasked channels for this attachment. If the writemask is 0, it's acceptable for the
807841b2fe0cb1151b0eaf3c519f87162ce960e02c1Chris Forbes            // shader to not produce a matching output.
808ac7791048680b52b3f3f751b350567b5092cd02eChris Forbes            if (pipeline->attachments[it_b->first].colorWriteMask != 0) {
809841b2fe0cb1151b0eaf3c519f87162ce960e02c1Chris Forbes                skip |=
810841b2fe0cb1151b0eaf3c519f87162ce960e02c1Chris Forbes                    log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
811d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Attachment %d not written by fragment shader", it_b->first);
812841b2fe0cb1151b0eaf3c519f87162ce960e02c1Chris Forbes            }
813d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            it_b++;
814d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        } else {
815d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            unsigned output_type = get_fundamental_type(fs, it_a->second.type_id);
816d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            unsigned att_type = get_format_type(it_b->second);
817d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
818d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // Type checking
819d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (!(output_type & att_type)) {
820d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
821d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
822d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                "Attachment %d of type `%s` does not match fragment shader output type of `%s`", it_b->first,
823d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                string_VkFormat(it_b->second), describe_type(fs, it_a->second.type_id).c_str());
824d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
825d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
826d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // OK!
827d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            it_a++;
828d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            it_b++;
829d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
830d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
831d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
832d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return skip;
833d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
834d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
835d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes// For some analyses, we need to know about all ids referenced by the static call tree of a particular entrypoint. This is
836d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes// important for identifying the set of shader resources actually used by an entrypoint, for example.
837d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes// Note: we only explore parts of the image which might actually contain ids we care about for the above analyses.
838d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes//  - NOT the shader input/output interfaces.
839d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes//
840d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes// TODO: The set of interesting opcodes here was determined by eyeballing the SPIRV spec. It might be worth
841d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes// converting parts of this to be generated from the machine-readable spec instead.
842d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic std::unordered_set<uint32_t> mark_accessible_ids(shader_module const *src, spirv_inst_iter entrypoint) {
843d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    std::unordered_set<uint32_t> ids;
844d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    std::unordered_set<uint32_t> worklist;
845d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    worklist.insert(entrypoint.word(2));
846d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
847d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    while (!worklist.empty()) {
848d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        auto id_iter = worklist.begin();
849d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        auto id = *id_iter;
850d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        worklist.erase(id_iter);
851d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
852d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        auto insn = src->get_def(id);
853d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (insn == src->end()) {
854d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // ID is something we didn't collect in build_def_index. that's OK -- we'll stumble across all kinds of things here
855d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // that we may not care about.
856d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            continue;
857d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
858d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
859d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        // Try to add to the output set
860d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (!ids.insert(id).second) {
861d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            continue;  // If we already saw this id, we don't want to walk it again.
862d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
863d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
864d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        switch (insn.opcode()) {
865d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpFunction:
866d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                // Scan whole body of the function, enlisting anything interesting
867d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                while (++insn, insn.opcode() != spv::OpFunctionEnd) {
868d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    switch (insn.opcode()) {
869d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpLoad:
870d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpAtomicLoad:
871d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpAtomicExchange:
872d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpAtomicCompareExchange:
873d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpAtomicCompareExchangeWeak:
874d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpAtomicIIncrement:
875d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpAtomicIDecrement:
876d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpAtomicIAdd:
877d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpAtomicISub:
878d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpAtomicSMin:
879d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpAtomicUMin:
880d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpAtomicSMax:
881d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpAtomicUMax:
882d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpAtomicAnd:
883d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpAtomicOr:
884d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpAtomicXor:
885d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            worklist.insert(insn.word(3));  // ptr
886d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            break;
887d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpStore:
888d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpAtomicStore:
889d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            worklist.insert(insn.word(1));  // ptr
890d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            break;
891d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpAccessChain:
892d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpInBoundsAccessChain:
893d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            worklist.insert(insn.word(3));  // base ptr
894d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            break;
895d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpSampledImage:
896d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageSampleImplicitLod:
897d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageSampleExplicitLod:
898d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageSampleDrefImplicitLod:
899d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageSampleDrefExplicitLod:
900d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageSampleProjImplicitLod:
901d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageSampleProjExplicitLod:
902d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageSampleProjDrefImplicitLod:
903d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageSampleProjDrefExplicitLod:
904d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageFetch:
905d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageGather:
906d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageDrefGather:
907d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageRead:
908d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImage:
909d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageQueryFormat:
910d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageQueryOrder:
911d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageQuerySizeLod:
912d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageQuerySize:
913d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageQueryLod:
914d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageQueryLevels:
915d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageQuerySamples:
916d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageSparseSampleImplicitLod:
917d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageSparseSampleExplicitLod:
918d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageSparseSampleDrefImplicitLod:
919d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageSparseSampleDrefExplicitLod:
920d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageSparseSampleProjImplicitLod:
921d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageSparseSampleProjExplicitLod:
922d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageSparseSampleProjDrefImplicitLod:
923d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageSparseSampleProjDrefExplicitLod:
924d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageSparseFetch:
925d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageSparseGather:
926d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageSparseDrefGather:
927d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageTexelPointer:
928d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            worklist.insert(insn.word(3));  // Image or sampled image
929d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            break;
930d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpImageWrite:
931d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            worklist.insert(insn.word(1));  // Image -- different operand order to above
932d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            break;
933d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpFunctionCall:
934d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            for (uint32_t i = 3; i < insn.len(); i++) {
935d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                worklist.insert(insn.word(i));  // fn itself, and all args
936d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            }
937d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            break;
938d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
939d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        case spv::OpExtInst:
940d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            for (uint32_t i = 5; i < insn.len(); i++) {
941d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                worklist.insert(insn.word(i));  // Operands to ext inst
942d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            }
943d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            break;
944d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    }
945d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                }
946d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                break;
947d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
948d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
949d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
950d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return ids;
951d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
952d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
953d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic bool validate_push_constant_block_against_pipeline(debug_report_data const *report_data,
954d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                                          std::vector<VkPushConstantRange> const *push_constant_ranges,
955d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                                          shader_module const *src, spirv_inst_iter type,
956d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                                          VkShaderStageFlagBits stage) {
957d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    bool skip = false;
958d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
959d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // Strip off ptrs etc
960d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    type = get_struct_type(src, type, false);
961d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    assert(type != src->end());
962d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
963d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // Validate directly off the offsets. this isn't quite correct for arrays and matrices, but is a good first step.
964d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // TODO: arrays, matrices, weird sizes
965d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    for (auto insn : *src) {
966d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
967d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (insn.word(3) == spv::DecorationOffset) {
968d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                unsigned offset = insn.word(4);
969d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                auto size = 4;  // Bytes; TODO: calculate this based on the type
970d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
971d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                bool found_range = false;
972d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                for (auto const &range : *push_constant_ranges) {
973d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    if (range.offset <= offset && range.offset + range.size >= offset + size) {
974d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        found_range = true;
975d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
976d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        if ((range.stageFlags & stage) == 0) {
977d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
978d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                            __LINE__, SHADER_CHECKER_PUSH_CONSTANT_NOT_ACCESSIBLE_FROM_STAGE, "SC",
979d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                            "Push constant range covering variable starting at "
980d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                                "offset %u not accessible from stage %s",
981d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                            offset, string_VkShaderStageFlagBits(stage));
982d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        }
983d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
984d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        break;
985d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    }
986d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                }
987d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
988d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                if (!found_range) {
989d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
990d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                    __LINE__, SHADER_CHECKER_PUSH_CONSTANT_OUT_OF_RANGE, "SC",
991d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                    "Push constant range covering variable starting at "
992d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                        "offset %u not declared in layout",
993d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                    offset);
994d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                }
995d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
996d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
997d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
998d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
999d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return skip;
1000d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
1001d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1002d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic bool validate_push_constant_usage(debug_report_data const *report_data,
1003d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                         std::vector<VkPushConstantRange> const *push_constant_ranges, shader_module const *src,
1004d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                         std::unordered_set<uint32_t> accessible_ids, VkShaderStageFlagBits stage) {
1005d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    bool skip = false;
1006d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1007d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    for (auto id : accessible_ids) {
1008d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        auto def_insn = src->get_def(id);
1009d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (def_insn.opcode() == spv::OpVariable && def_insn.word(3) == spv::StorageClassPushConstant) {
1010d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            skip |= validate_push_constant_block_against_pipeline(report_data, push_constant_ranges, src,
1011d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                                                  src->get_def(def_insn.word(1)), stage);
1012d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
1013d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
1014d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1015d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return skip;
1016d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
1017d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1018d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes// Validate that data for each specialization entry is fully contained within the buffer.
1019d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic bool validate_specialization_offsets(debug_report_data const *report_data, VkPipelineShaderStageCreateInfo const *info) {
1020d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    bool skip = false;
1021d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1022d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    VkSpecializationInfo const *spec = info->pSpecializationInfo;
1023d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1024d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (spec) {
1025d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        for (auto i = 0u; i < spec->mapEntryCount; i++) {
1026d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // TODO: This is a good place for VALIDATION_ERROR_1360060a.
1027d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (spec->pMapEntries[i].offset + spec->pMapEntries[i].size > spec->dataSize) {
1028d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
1029d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                VALIDATION_ERROR_1360060c, "SC",
1030d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                "Specialization entry %u (for constant id %u) references memory outside provided "
1031d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                    "specialization data (bytes %u.." PRINTF_SIZE_T_SPECIFIER "; " PRINTF_SIZE_T_SPECIFIER
1032d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                " bytes provided). %s.",
1033d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    i, spec->pMapEntries[i].constantID, spec->pMapEntries[i].offset,
1034d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    spec->pMapEntries[i].offset + spec->pMapEntries[i].size - 1, spec->dataSize,
1035d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    validation_error_map[VALIDATION_ERROR_1360060c]);
1036d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
1037d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
1038d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
1039d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1040d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return skip;
1041d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
1042d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1043d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic bool descriptor_type_match(shader_module const *module, uint32_t type_id, VkDescriptorType descriptor_type,
1044d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                  unsigned &descriptor_count) {
1045d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto type = module->get_def(type_id);
1046d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1047d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    descriptor_count = 1;
1048d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1049d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // Strip off any array or ptrs. Where we remove array levels, adjust the  descriptor count for each dimension.
1050d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    while (type.opcode() == spv::OpTypeArray || type.opcode() == spv::OpTypePointer) {
1051d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (type.opcode() == spv::OpTypeArray) {
1052d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            descriptor_count *= get_constant_value(module, type.word(3));
1053d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            type = module->get_def(type.word(2));
1054d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        } else {
1055d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            type = module->get_def(type.word(3));
1056d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
1057d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
1058d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1059d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    switch (type.opcode()) {
1060d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeStruct: {
1061d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            for (auto insn : *module) {
1062d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                if (insn.opcode() == spv::OpDecorate && insn.word(1) == type.word(1)) {
1063d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    if (insn.word(2) == spv::DecorationBlock) {
1064d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
1065d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
1066d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    } else if (insn.word(2) == spv::DecorationBufferBlock) {
1067d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
1068d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
1069d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    }
1070d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                }
1071d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
1072d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1073d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // Invalid
1074d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return false;
1075d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
1076d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1077d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeSampler:
1078d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLER || descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1079d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1080d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeSampledImage:
1081d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) {
1082d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                // Slight relaxation for some GLSL historical madness: samplerBuffer doesn't really have a sampler, and a texel
1083d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                // buffer descriptor doesn't really provide one. Allow this slight mismatch.
1084d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                auto image_type = module->get_def(type.word(2));
1085d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                auto dim = image_type.word(3);
1086d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                auto sampled = image_type.word(7);
1087d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                return dim == spv::DimBuffer && sampled == 1;
1088d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
1089d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1090d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1091d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        case spv::OpTypeImage: {
1092d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // Many descriptor types backing image types-- depends on dimension and whether the image will be used with a sampler.
1093d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // SPIRV for Vulkan requires that sampled be 1 or 2 -- leaving the decision to runtime is unacceptable.
1094d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            auto dim = type.word(3);
1095d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            auto sampled = type.word(7);
1096d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1097d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (dim == spv::DimSubpassData) {
1098d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                return descriptor_type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
1099d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            } else if (dim == spv::DimBuffer) {
1100d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                if (sampled == 1) {
1101d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
1102d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                } else {
1103d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
1104d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                }
1105d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            } else if (sampled == 1) {
1106d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ||
1107d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1108d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            } else {
1109d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
1110d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
1111d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
1112d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1113d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // We shouldn't really see any other junk types -- but if we do, they're a mismatch.
1114d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        default:
1115d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return false;  // Mismatch
1116d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
1117d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
1118d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1119d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic bool require_feature(debug_report_data const *report_data, VkBool32 feature, char const *feature_name) {
1120d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (!feature) {
1121d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
1122d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    SHADER_CHECKER_FEATURE_NOT_ENABLED, "SC",
1123d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    "Shader requires VkPhysicalDeviceFeatures::%s but is not "
1124d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        "enabled on the device",
1125d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    feature_name)) {
1126d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return true;
1127d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
1128d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
1129d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1130d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return false;
1131d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
1132d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1133d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic bool require_extension(debug_report_data const *report_data, bool extension, char const *extension_name) {
1134d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (!extension) {
1135d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
1136d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    SHADER_CHECKER_FEATURE_NOT_ENABLED, "SC",
1137d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    "Shader requires extension %s but is not "
1138d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        "enabled on the device",
1139d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    extension_name)) {
1140d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return true;
1141d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
1142d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
1143d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1144d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return false;
1145d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
1146d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1147d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic bool validate_shader_capabilities(layer_data *dev_data, shader_module const *src) {
1148d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    bool skip = false;
1149d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1150d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto report_data = GetReportData(dev_data);
1151d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto const & enabledFeatures = GetEnabledFeatures(dev_data);
1152d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto const & extensions = GetEnabledExtensions(dev_data);
1153d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1154d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    struct CapabilityInfo {
1155d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        char const *name;
1156d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        VkBool32 const VkPhysicalDeviceFeatures::*feature;
1157d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        bool const DeviceExtensions::*extension;
1158d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    };
1159d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1160d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    using F = VkPhysicalDeviceFeatures;
1161d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    using E = DeviceExtensions;
1162d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1163d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // clang-format off
1164d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    static const std::unordered_map<uint32_t, CapabilityInfo> capabilities = {
1165d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        // Capabilities always supported by a Vulkan 1.0 implementation -- no
1166d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        // feature bits.
1167d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityMatrix, {nullptr}},
1168d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityShader, {nullptr}},
1169d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityInputAttachment, {nullptr}},
1170d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilitySampled1D, {nullptr}},
1171d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityImage1D, {nullptr}},
1172d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilitySampledBuffer, {nullptr}},
1173d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityImageQuery, {nullptr}},
1174d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityDerivativeControl, {nullptr}},
1175d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1176d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        // Capabilities that are optionally supported, but require a feature to
1177d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        // be enabled on the device
1178d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityGeometry, {"geometryShader", &F::geometryShader}},
1179d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityTessellation, {"tessellationShader", &F::tessellationShader}},
1180d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityFloat64, {"shaderFloat64", &F::shaderFloat64}},
1181d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityInt64, {"shaderInt64", &F::shaderInt64}},
1182d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityTessellationPointSize, {"shaderTessellationAndGeometryPointSize", &F::shaderTessellationAndGeometryPointSize}},
1183d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityGeometryPointSize, {"shaderTessellationAndGeometryPointSize", &F::shaderTessellationAndGeometryPointSize}},
1184d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityImageGatherExtended, {"shaderImageGatherExtended", &F::shaderImageGatherExtended}},
1185d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityStorageImageMultisample, {"shaderStorageImageMultisample", &F::shaderStorageImageMultisample}},
1186d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityUniformBufferArrayDynamicIndexing, {"shaderUniformBufferArrayDynamicIndexing", &F::shaderUniformBufferArrayDynamicIndexing}},
1187d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilitySampledImageArrayDynamicIndexing, {"shaderSampledImageArrayDynamicIndexing", &F::shaderSampledImageArrayDynamicIndexing}},
1188d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityStorageBufferArrayDynamicIndexing, {"shaderStorageBufferArrayDynamicIndexing", &F::shaderStorageBufferArrayDynamicIndexing}},
1189d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityStorageImageArrayDynamicIndexing, {"shaderStorageImageArrayDynamicIndexing", &F::shaderStorageBufferArrayDynamicIndexing}},
1190d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityClipDistance, {"shaderClipDistance", &F::shaderClipDistance}},
1191d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityCullDistance, {"shaderCullDistance", &F::shaderCullDistance}},
1192d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityImageCubeArray, {"imageCubeArray", &F::imageCubeArray}},
1193d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilitySampleRateShading, {"sampleRateShading", &F::sampleRateShading}},
1194d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilitySparseResidency, {"shaderResourceResidency", &F::shaderResourceResidency}},
1195d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityMinLod, {"shaderResourceMinLod", &F::shaderResourceMinLod}},
1196d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilitySampledCubeArray, {"imageCubeArray", &F::imageCubeArray}},
1197d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityImageMSArray, {"shaderStorageImageMultisample", &F::shaderStorageImageMultisample}},
1198d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityStorageImageExtendedFormats, {"shaderStorageImageExtendedFormats", &F::shaderStorageImageExtendedFormats}},
1199d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityInterpolationFunction, {"sampleRateShading", &F::sampleRateShading}},
1200d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityStorageImageReadWithoutFormat, {"shaderStorageImageReadWithoutFormat", &F::shaderStorageImageReadWithoutFormat}},
1201d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityStorageImageWriteWithoutFormat, {"shaderStorageImageWriteWithoutFormat", &F::shaderStorageImageWriteWithoutFormat}},
1202d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityMultiViewport, {"multiViewport", &F::multiViewport}},
1203d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1204d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        // Capabilities that require an extension
1205d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityDrawParameters, {VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, nullptr, &E::vk_khr_shader_draw_parameters}},
1206d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityGeometryShaderPassthroughNV, {VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME, nullptr, &E::vk_nv_geometry_shader_passthrough}},
1207d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilitySampleMaskOverrideCoverageNV, {VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME, nullptr, &E::vk_nv_sample_mask_override_coverage}},
1208d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityShaderViewportIndexLayerNV, {VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME, nullptr, &E::vk_nv_viewport_array2}},
1209d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilityShaderViewportMaskNV, {VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME, nullptr, &E::vk_nv_viewport_array2}},
1210d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilitySubgroupBallotKHR, {VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME, nullptr, &E::vk_ext_shader_subgroup_ballot }},
1211d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        {spv::CapabilitySubgroupVoteKHR, {VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME, nullptr, &E::vk_ext_shader_subgroup_vote }},
1212d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    };
1213d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // clang-format on
1214d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1215d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    for (auto insn : *src) {
1216d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (insn.opcode() == spv::OpCapability) {
1217d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            auto it = capabilities.find(insn.word(1));
1218d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (it != capabilities.end()) {
1219d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                if (it->second.feature) {
1220d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    skip |= require_feature(report_data, enabledFeatures->*(it->second.feature), it->second.name);
1221d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                }
1222d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                if (it->second.extension) {
1223d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    skip |= require_extension(report_data, extensions->*(it->second.extension), it->second.name);
1224d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                }
1225d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
1226d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
1227d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
1228d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1229d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return skip;
1230d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
1231d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1232d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic uint32_t descriptor_type_to_reqs(shader_module const *module, uint32_t type_id) {
1233d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto type = module->get_def(type_id);
1234d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1235d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    while (true) {
1236d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        switch (type.opcode()) {
1237d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypeArray:
1238d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypeSampledImage:
1239d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                type = module->get_def(type.word(2));
1240d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                break;
1241d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypePointer:
1242d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                type = module->get_def(type.word(3));
1243d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                break;
1244d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            case spv::OpTypeImage: {
1245d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                auto dim = type.word(3);
1246d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                auto arrayed = type.word(5);
1247d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                auto msaa = type.word(6);
1248d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1249d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                switch (dim) {
1250d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    case spv::Dim1D:
1251d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        return arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_1D_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_1D;
1252d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    case spv::Dim2D:
1253d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        return (msaa ? DESCRIPTOR_REQ_MULTI_SAMPLE : DESCRIPTOR_REQ_SINGLE_SAMPLE) |
1254d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            (arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_2D_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_2D);
1255d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    case spv::Dim3D:
1256d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        return DESCRIPTOR_REQ_VIEW_TYPE_3D;
1257d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    case spv::DimCube:
1258d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        return arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_CUBE_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_CUBE;
1259d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    case spv::DimSubpassData:
1260d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        return msaa ? DESCRIPTOR_REQ_MULTI_SAMPLE : DESCRIPTOR_REQ_SINGLE_SAMPLE;
1261d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    default:  // buffer, etc.
1262d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                        return 0;
1263d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                }
1264d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
1265d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            default:
1266d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                return 0;
1267d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
1268d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
1269d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
1270d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1271d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes// For given pipelineLayout verify that the set_layout_node at slot.first
1272d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes//  has the requested binding at slot.second and return ptr to that binding
1273d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic VkDescriptorSetLayoutBinding const *get_descriptor_binding(PIPELINE_LAYOUT_NODE const *pipelineLayout,
1274d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                                                  descriptor_slot_t slot) {
1275d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (!pipelineLayout) return nullptr;
1276d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1277d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (slot.first >= pipelineLayout->set_layouts.size()) return nullptr;
1278d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1279d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return pipelineLayout->set_layouts[slot.first]->GetDescriptorSetLayoutBindingPtrFromBinding(slot.second);
1280d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
1281d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1282d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1283d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic bool validate_pipeline_shader_stage(
1284d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    layer_data *dev_data, VkPipelineShaderStageCreateInfo const *pStage, PIPELINE_STATE *pipeline,
1285d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    shader_module const **out_module, spirv_inst_iter *out_entrypoint) {
1286d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    bool skip = false;
1287d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto module = *out_module = GetShaderModuleState(dev_data, pStage->module);
1288d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto report_data = GetReportData(dev_data);
1289d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1290d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (!module->has_valid_spirv) return false;
1291d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1292d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // Find the entrypoint
1293d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto entrypoint = *out_entrypoint = find_entrypoint(module, pStage->pName, pStage->stage);
1294d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (entrypoint == module->end()) {
1295d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
1296d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    VALIDATION_ERROR_10600586, "SC", "No entrypoint found named `%s` for stage %s. %s.", pStage->pName,
1297d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    string_VkShaderStageFlagBits(pStage->stage), validation_error_map[VALIDATION_ERROR_10600586])) {
1298d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            return true;  // no point continuing beyond here, any analysis is just going to be garbage.
1299d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
1300d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
1301d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1302d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // Validate shader capabilities against enabled device features
1303d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    skip |= validate_shader_capabilities(dev_data, module);
1304d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1305d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // Mark accessible ids
1306d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto accessible_ids = mark_accessible_ids(module, entrypoint);
1307d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1308d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // Validate descriptor set layout against what the entrypoint actually uses
1309d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto descriptor_uses = collect_interface_by_descriptor_slot(report_data, module, accessible_ids);
1310d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1311d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    skip |= validate_specialization_offsets(report_data, pStage);
13129ce5c15788e545ece9820a9d3de9075c980dd21aChris Forbes    skip |= validate_push_constant_usage(report_data, &pipeline->pipeline_layout.push_constant_ranges, module, accessible_ids, pStage->stage);
1313d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1314d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // Validate descriptor use
1315d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    for (auto use : descriptor_uses) {
1316d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        // While validating shaders capture which slots are used by the pipeline
1317d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        auto &reqs = pipeline->active_slots[use.first.first][use.first.second];
1318d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        reqs = descriptor_req(reqs | descriptor_type_to_reqs(module, use.second.type_id));
1319d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1320d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        // Verify given pipelineLayout has requested setLayout with requested binding
13219ce5c15788e545ece9820a9d3de9075c980dd21aChris Forbes        const auto &binding = get_descriptor_binding(&pipeline->pipeline_layout, use.first);
1322d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        unsigned required_descriptor_count;
1323d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1324d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (!binding) {
1325d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
1326d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            SHADER_CHECKER_MISSING_DESCRIPTOR, "SC",
1327d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            "Shader uses descriptor slot %u.%u (used as type `%s`) but not declared in pipeline layout",
1328d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str());
1329d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        } else if (~binding->stageFlags & pStage->stage) {
1330d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
1331d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            SHADER_CHECKER_DESCRIPTOR_NOT_ACCESSIBLE_FROM_STAGE, "SC",
1332d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            "Shader uses descriptor slot %u.%u (used "
1333d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                "as type `%s`) but descriptor not "
1334d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                "accessible from stage %s",
1335d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
1336d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            string_VkShaderStageFlagBits(pStage->stage));
1337d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        } else if (!descriptor_type_match(module, use.second.type_id, binding->descriptorType, required_descriptor_count)) {
1338d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
1339d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
1340d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            "Type mismatch on descriptor slot "
1341d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                "%u.%u (used as type `%s`) but "
1342d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                "descriptor of type %s",
1343d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
1344d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            string_VkDescriptorType(binding->descriptorType));
1345d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        } else if (binding->descriptorCount < required_descriptor_count) {
1346d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
1347d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
1348d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            "Shader expects at least %u descriptors for binding %u.%u (used as type `%s`) but only %u provided",
1349d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            required_descriptor_count, use.first.first, use.first.second,
1350d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            describe_type(module, use.second.type_id).c_str(), binding->descriptorCount);
1351d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
1352d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
1353d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1354d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // Validate use of input attachments against subpass structure
1355d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (pStage->stage == VK_SHADER_STAGE_FRAGMENT_BIT) {
1356d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        auto input_attachment_uses = collect_interface_by_input_attachment_index(module, accessible_ids);
1357d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1358d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        auto rpci = pipeline->render_pass_ci.ptr();
1359d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        auto subpass = pipeline->graphicsPipelineCI.subpass;
1360d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1361d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        for (auto use : input_attachment_uses) {
1362d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            auto input_attachments = rpci->pSubpasses[subpass].pInputAttachments;
1363d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            auto index = (input_attachments && use.first < rpci->pSubpasses[subpass].inputAttachmentCount)
1364d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                         ? input_attachments[use.first].attachment
1365d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                         : VK_ATTACHMENT_UNUSED;
1366d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1367d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (index == VK_ATTACHMENT_UNUSED) {
1368d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
1369d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                SHADER_CHECKER_MISSING_INPUT_ATTACHMENT, "SC",
1370d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                "Shader consumes input attachment index %d but not provided in subpass", use.first);
1371d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            } else if (!(get_format_type(rpci->pAttachments[index].format) & get_fundamental_type(module, use.second.type_id))) {
1372d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                skip |=
1373d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                    log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
1374d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            SHADER_CHECKER_INPUT_ATTACHMENT_TYPE_MISMATCH, "SC",
1375d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            "Subpass input attachment %u format of %s does not match type used in shader `%s`", use.first,
1376d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            string_VkFormat(rpci->pAttachments[index].format), describe_type(module, use.second.type_id).c_str());
1377d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
1378d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
1379d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
1380d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1381d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return skip;
1382d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
1383d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1384d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbesstatic bool validate_interface_between_stages(debug_report_data const *report_data, shader_module const *producer,
1385d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                              spirv_inst_iter producer_entrypoint, shader_stage_attributes const *producer_stage,
1386d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                              shader_module const *consumer, spirv_inst_iter consumer_entrypoint,
1387d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                              shader_stage_attributes const *consumer_stage) {
1388d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    bool skip = false;
1389d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1390d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto outputs =
1391d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        collect_interface_by_location(producer, producer_entrypoint, spv::StorageClassOutput, producer_stage->arrayed_output);
1392d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto inputs =
1393d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        collect_interface_by_location(consumer, consumer_entrypoint, spv::StorageClassInput, consumer_stage->arrayed_input);
1394d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1395d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto a_it = outputs.begin();
1396d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto b_it = inputs.begin();
1397d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1398d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // Maps sorted by key (location); walk them together to find mismatches
1399d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    while ((outputs.size() > 0 && a_it != outputs.end()) || (inputs.size() && b_it != inputs.end())) {
1400d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        bool a_at_end = outputs.size() == 0 || a_it == outputs.end();
1401d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        bool b_at_end = inputs.size() == 0 || b_it == inputs.end();
1402d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        auto a_first = a_at_end ? std::make_pair(0u, 0u) : a_it->first;
1403d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        auto b_first = b_at_end ? std::make_pair(0u, 0u) : b_it->first;
1404d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1405d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (b_at_end || ((!a_at_end) && (a_first < b_first))) {
1406d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1407d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
1408d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            "%s writes to output location %u.%u which is not consumed by %s", producer_stage->name, a_first.first,
1409d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            a_first.second, consumer_stage->name);
1410d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            a_it++;
1411d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        } else if (a_at_end || a_first > b_first) {
1412d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
1413d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "%s consumes input location %u.%u which is not written by %s",
1414d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                            consumer_stage->name, b_first.first, b_first.second, producer_stage->name);
1415d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            b_it++;
1416d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        } else {
1417d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // subtleties of arrayed interfaces:
1418d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // - if is_patch, then the member is not arrayed, even though the interface may be.
1419d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            // - if is_block_member, then the extra array level of an arrayed interface is not
1420d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            //   expressed in the member type -- it's expressed in the block type.
1421d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (!types_match(producer, consumer, a_it->second.type_id, b_it->second.type_id,
1422d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                             producer_stage->arrayed_output && !a_it->second.is_patch && !a_it->second.is_block_member,
1423d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                             consumer_stage->arrayed_input && !b_it->second.is_patch && !b_it->second.is_block_member, true)) {
1424d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
1425d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC", "Type mismatch on location %u.%u: '%s' vs '%s'",
1426d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                a_first.first, a_first.second, describe_type(producer, a_it->second.type_id).c_str(),
1427d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                describe_type(consumer, b_it->second.type_id).c_str());
1428d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
1429d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (a_it->second.is_patch != b_it->second.is_patch) {
1430d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
1431d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
1432d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                "Decoration mismatch on location %u.%u: is per-%s in %s stage but "
1433d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                    "per-%s in %s stage",
1434d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                a_first.first, a_first.second, a_it->second.is_patch ? "patch" : "vertex", producer_stage->name,
1435d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                b_it->second.is_patch ? "patch" : "vertex", consumer_stage->name);
1436d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
1437d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            if (a_it->second.is_relaxed_precision != b_it->second.is_relaxed_precision) {
1438d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0, __LINE__,
1439d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
1440d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                "Decoration mismatch on location %u.%u: %s and %s stages differ in precision", a_first.first,
1441d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                a_first.second, producer_stage->name, consumer_stage->name);
1442d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            }
1443d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            a_it++;
1444d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            b_it++;
1445d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
1446d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
1447d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1448d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return skip;
1449d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
1450d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1451d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes// Validate that the shaders used by the given pipeline and store the active_slots
1452d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes//  that are actually used by the pipeline into pPipeline->active_slots
1453ac7791048680b52b3f3f751b350567b5092cd02eChris Forbesbool validate_and_capture_pipeline_shader_state(layer_data *dev_data, PIPELINE_STATE *pipeline) {
1454ac7791048680b52b3f3f751b350567b5092cd02eChris Forbes    auto pCreateInfo = pipeline->graphicsPipelineCI.ptr();
1455d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    int vertex_stage = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
1456d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    int fragment_stage = get_shader_stage_id(VK_SHADER_STAGE_FRAGMENT_BIT);
1457d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto report_data = GetReportData(dev_data);
1458d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1459d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    shader_module const *shaders[5];
1460d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    memset(shaders, 0, sizeof(shaders));
1461d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    spirv_inst_iter entrypoints[5];
1462d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    memset(entrypoints, 0, sizeof(entrypoints));
1463d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    bool skip = false;
1464d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1465d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
1466d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        auto pStage = &pCreateInfo->pStages[i];
1467d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        auto stage_id = get_shader_stage_id(pStage->stage);
1468ac7791048680b52b3f3f751b350567b5092cd02eChris Forbes        skip |= validate_pipeline_shader_stage(dev_data, pStage, pipeline, &shaders[stage_id], &entrypoints[stage_id]);
1469d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
1470d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1471d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    // if the shader stages are no good individually, cross-stage validation is pointless.
1472d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (skip) return true;
1473d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1474d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    auto vi = pCreateInfo->pVertexInputState;
1475d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1476d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (vi) {
1477d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        skip |= validate_vi_consistency(report_data, vi);
1478d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
1479d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1480d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (shaders[vertex_stage] && shaders[vertex_stage]->has_valid_spirv) {
1481d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        skip |= validate_vi_against_vs_inputs(report_data, vi, shaders[vertex_stage], entrypoints[vertex_stage]);
1482d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
1483d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1484d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    int producer = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
1485d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    int consumer = get_shader_stage_id(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
1486d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1487d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    while (!shaders[producer] && producer != fragment_stage) {
1488d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        producer++;
1489d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        consumer++;
1490d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
1491d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1492d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    for (; producer != fragment_stage && consumer <= fragment_stage; consumer++) {
1493d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        assert(shaders[producer]);
1494d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        if (shaders[consumer] && shaders[consumer]->has_valid_spirv && shaders[producer]->has_valid_spirv) {
1495d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            skip |= validate_interface_between_stages(report_data, shaders[producer], entrypoints[producer],
1496d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                                      &shader_stage_attribs[producer], shaders[consumer], entrypoints[consumer],
1497d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes                                                      &shader_stage_attribs[consumer]);
1498d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1499d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes            producer = consumer;
1500d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        }
1501d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
1502d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1503d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    if (shaders[fragment_stage] && shaders[fragment_stage]->has_valid_spirv) {
1504d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes        skip |= validate_fs_outputs_against_render_pass(report_data, shaders[fragment_stage], entrypoints[fragment_stage],
1505ac7791048680b52b3f3f751b350567b5092cd02eChris Forbes                                                        pipeline, pCreateInfo->subpass);
1506d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    }
1507d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1508d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    return skip;
1509d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
1510d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1511ac7791048680b52b3f3f751b350567b5092cd02eChris Forbesbool validate_compute_pipeline(layer_data *dev_data, PIPELINE_STATE *pipeline) {
1512ac7791048680b52b3f3f751b350567b5092cd02eChris Forbes    auto pCreateInfo = pipeline->computePipelineCI.ptr();
1513d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1514d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    shader_module const *module;
1515d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes    spirv_inst_iter entrypoint;
1516d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes
1517ac7791048680b52b3f3f751b350567b5092cd02eChris Forbes    return validate_pipeline_shader_stage(dev_data, &pCreateInfo->stage, pipeline, &module, &entrypoint);
1518d7aee1a79b51b1a46cb4f3b0667c24f9416fdd64Chris Forbes}
15197aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes
15207aec8a354c8de254cab09f6da7f24a794525d31eChris Forbesbool PreCallValidateCreateShaderModule(layer_data *dev_data, VkShaderModuleCreateInfo const *pCreateInfo, bool *spirv_valid) {
15217aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes    bool skip = false;
15227aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes    spv_result_t spv_valid = SPV_SUCCESS;
15237aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes    auto report_data = GetReportData(dev_data);
15247aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes
15257aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes    if (GetDisables(dev_data)->shader_validation) {
15267aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes        return false;
15277aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes    }
15287aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes
15297aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes    auto have_glsl_shader = GetEnabledExtensions(dev_data)->vk_nv_glsl_shader;
15307aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes
15317aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes    if (!have_glsl_shader && (pCreateInfo->codeSize % 4)) {
15327aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
15337aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes                        __LINE__, VALIDATION_ERROR_12a00ac0, "SC",
15347aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes                        "SPIR-V module not valid: Codesize must be a multiple of 4 but is " PRINTF_SIZE_T_SPECIFIER ". %s",
15357aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes                        pCreateInfo->codeSize, validation_error_map[VALIDATION_ERROR_12a00ac0]);
15367aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes    } else {
15377aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes        // Use SPIRV-Tools validator to try and catch any issues with the module itself
15387aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes        spv_context ctx = spvContextCreate(SPV_ENV_VULKAN_1_0);
15397aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes        spv_const_binary_t binary{ pCreateInfo->pCode, pCreateInfo->codeSize / sizeof(uint32_t) };
15407aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes        spv_diagnostic diag = nullptr;
15417aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes
15427aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes        spv_valid = spvValidate(ctx, &binary, &diag);
15437aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes        if (spv_valid != SPV_SUCCESS) {
15447aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes            if (!have_glsl_shader || (pCreateInfo->pCode[0] == spv::MagicNumber)) {
15457aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes                skip |= log_msg(report_data,
15467aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes                                spv_valid == SPV_WARNING ? VK_DEBUG_REPORT_WARNING_BIT_EXT : VK_DEBUG_REPORT_ERROR_BIT_EXT,
15477aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes                                VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, SHADER_CHECKER_INCONSISTENT_SPIRV, "SC",
15487aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes                                "SPIR-V module not valid: %s", diag && diag->error ? diag->error : "(no error text)");
15497aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes            }
15507aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes        }
15517aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes
15527aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes        spvDiagnosticDestroy(diag);
15537aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes        spvContextDestroy(ctx);
15547aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes    }
15557aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes
15567aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes    *spirv_valid = (spv_valid == SPV_SUCCESS);
15577aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes    return skip;
15587aec8a354c8de254cab09f6da7f24a794525d31eChris Forbes}
1559