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