blob: 1ec5d1a5042caa41885e0f2f7a6ddf99fcbe5e07 [file] [log] [blame]
/* Copyright (c) 2024-2026 LunarG, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <stdint.h>
#include <vulkan/vulkan_core.h>
#include <string>
#include <vector>
// The goal is to keep instrumentation a seperate library to draw a strong line where the GPU-AV SPIR-V logic is.
// This header is designed as the interface that can be shared between the instrumentation passes and the rest of GPU-AV
struct Location;
namespace gpuav {
namespace spirv {
// Each descriptor set can be tought as a linear, single buffer of descriptors (ignoring binding and arrays for the moment)
//
// Example:
// layout(binding = 0) buffer a[4];
// layout(binding = 2) buffer b;
// layout(binding = 3) buffer c[2];
//
// We can think of this as being in a buffer as
// [ a0, a1, a2, a3, b0, c0, c1]
//
// In order to do this, we need some sort of LUT, per BINDING, to know where in this LAYOUT of descriptors the binding starts.
// This means given the index into any binding, we can locate the exact descriptor in the entire descriptor set.
//
// This information used to be in a BDA buffer that the GPU would do a look-up and produced slow SPIR-V to compile/execute.
// Now that we do instrumentation at Pipeline creation time, we can just view the DescriptorSetLayout and inject this offset into
// the instrumentation.
//
// ** With Variable Descriptor Count, the buffer will only get smaller from the end.
// We will still validate as being "uninitialized" in that case.
struct BindingLayout {
uint32_t start;
uint32_t count;
};
// When instrumenting, we need information about the array of VkDescriptorSetLayouts. The core issue is that for pipelines, we
// might have to merge 2 pipeline layouts together (because of GPL) and therefore both ShaderObject and PipelineLayout state
// objects don't have a single way to describe their VkDescriptorSetLayouts. If there are multiple shaders, we also want to only
// build this information once.
// This struct is designed to be filled in from both Pipeline and ShaderObject and then passed down to the SPIR-V Instrumentation,
// and afterwards we don't need to save it.
struct InstrumentationDescriptorSetLayouts {
bool has_bindless_descriptors = false;
// < set , [ bindings ] >
std::vector<std::vector<spirv::BindingLayout>> set_index_to_bindings_layout_lut;
// Pipeline flags for ray tracing validation hit objects
bool pipeline_has_skip_aabbs_flag = false;
bool pipeline_has_skip_triangles_flag = false;
uint32_t max_shader_binding_table_record_index = 0;
};
// Top level struct to hold all the things we want to pass in from the Vulkan GPU-AV code into the SPIR-V instrumentation passes
struct InstrumentationInterface {
// Used to do a look up the corresponding shader handle GpuShaderInstrumentor::instrumented_shaders_map_
// (Embedded into the GLSL at linking time with SpecConstantLinkShaderId)
uint32_t unique_shader_id = 0;
// We only need to instrument the functions in the entry point
const char* entry_point_name = nullptr;
VkShaderStageFlagBits entry_point_stage = VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM;
InstrumentationDescriptorSetLayouts instrumentation_dsl;
const Location& loc;
explicit InstrumentationInterface(const Location& loc) : loc(loc) {}
};
// Global settings we would know at vkCreateDevice
// All setting must be set in FinishDeviceSetup, where defaults values are set
struct DeviceSettings {
// Will replace the "OpDecorate DescriptorSet" for the output buffer in the incoming linked module
// This allows anything to be set in the GLSL for the set value, as we change it at runtime
uint32_t output_buffer_descriptor_set;
// When off (unsafe mode) reduce amount of work so compiling the pipeline/shader is quicker
// This is a global setting for all passes
bool safe_mode;
// Used to help debug
bool print_debug_info;
// zero is same as "unlimited"
uint32_t max_instrumentations_count;
bool support_non_semantic_info;
// Lets us embed the size instead of calling OpArrayLength
uint32_t error_buffer_data_length;
uint32_t debug_printf_buffer_size;
};
// When running the DebugPrintf pass, if we detect an instrumented shader has a printf call (for debugging) we can hold them until
// we need them after GPU execution. (Note, this is needed because we don't store the instrumented SPIR-V and have no way to get the
// OpString back afterwards)
struct InternalOnlyDebugPrintf {
uint32_t unique_shader_id;
uint32_t op_string_id;
std::string op_string_text;
};
} // namespace spirv
} // namespace gpuav