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