shader_recompiler: Additional scope handling and user data as push constants (#1013)

* shader_recompiler: Use push constants for user data regs

* shader: Add some GR2 instructions

* shader: Add some instructions

* shader: Add instructions for knack

* touchups

* spirv: Better names

* buffer_cache: Ignore non gpu modified images

* clang format

* Add log

* more fixes
This commit is contained in:
TheTurtle 2024-09-23 09:55:43 +03:00 committed by GitHub
parent fb5bc371cb
commit ee38eec7fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 180 additions and 87 deletions

View file

@ -581,13 +581,16 @@ bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr,
return false;
}
Image& image = texture_cache.GetImage(image_id);
if (False(image.flags & ImageFlagBits::GpuModified)) {
return false;
}
ASSERT_MSG(device_addr == image.info.guest_address,
"Texel buffer aliases image subresources {:x} : {:x}", device_addr,
image.info.guest_address);
boost::container::small_vector<vk::BufferImageCopy, 8> copies;
u32 offset = buffer.Offset(image.cpu_addr);
const u32 num_layers = image.info.resources.layers;
u32 total_size = 0;
const u32 max_offset = offset + size;
for (u32 m = 0; m < image.info.resources.levels; m++) {
const u32 width = std::max(image.info.size.width >> m, 1u);
const u32 height = std::max(image.info.size.height >> m, 1u);
@ -595,7 +598,7 @@ bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr,
image.info.props.is_volume ? std::max(image.info.size.depth >> m, 1u) : 1u;
const auto& [mip_size, mip_pitch, mip_height, mip_ofs] = image.info.mips_layout[m];
offset += mip_ofs * num_layers;
if (offset + (mip_size * num_layers) > buffer.SizeBytes()) {
if (offset + (mip_size * num_layers) > max_offset) {
break;
}
copies.push_back({
@ -611,7 +614,6 @@ bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr,
.imageOffset = {0, 0, 0},
.imageExtent = {width, height, depth},
});
total_size += mip_size * num_layers;
}
if (!copies.empty()) {
scheduler.EndRendering();

View file

@ -112,10 +112,11 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
boost::container::small_vector<vk::WriteDescriptorSet, 16> set_writes;
boost::container::small_vector<vk::BufferMemoryBarrier2, 16> buffer_barriers;
Shader::PushData push_data{};
u32 binding{};
Shader::Backend::Bindings binding{};
image_infos.clear();
info->PushUd(binding, push_data);
for (const auto& desc : info->buffers) {
bool is_storage = true;
if (desc.is_gds_buffer) {
@ -147,21 +148,20 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
buffer_cache.ObtainBuffer(address, size, desc.is_written);
const u32 offset_aligned = Common::AlignDown(offset, alignment);
const u32 adjust = offset - offset_aligned;
if (adjust != 0) {
ASSERT(adjust % 4 == 0);
push_data.AddOffset(binding, adjust);
}
ASSERT(adjust % 4 == 0);
push_data.AddOffset(binding.buffer, adjust);
buffer_infos.emplace_back(vk_buffer->Handle(), offset_aligned, size + adjust);
}
set_writes.push_back({
.dstSet = VK_NULL_HANDLE,
.dstBinding = binding++,
.dstBinding = binding.unified++,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = is_storage ? vk::DescriptorType::eStorageBuffer
: vk::DescriptorType::eUniformBuffer,
.pBufferInfo = &buffer_infos.back(),
});
++binding.buffer;
}
for (const auto& desc : info->texture_buffers) {
@ -188,10 +188,8 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
"Texel buffer stride must match format stride");
const u32 offset_aligned = Common::AlignDown(offset, alignment);
const u32 adjust = offset - offset_aligned;
if (adjust != 0) {
ASSERT(adjust % fmt_stride == 0);
push_data.AddOffset(binding, adjust / fmt_stride);
}
ASSERT(adjust % fmt_stride == 0);
push_data.AddOffset(binding.buffer, adjust / fmt_stride);
buffer_view = vk_buffer->View(offset_aligned, size + adjust, desc.is_written,
vsharp.GetDataFmt(), vsharp.GetNumberFmt());
if (auto barrier =
@ -206,13 +204,14 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
}
set_writes.push_back({
.dstSet = VK_NULL_HANDLE,
.dstBinding = binding++,
.dstBinding = binding.unified++,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = desc.is_written ? vk::DescriptorType::eStorageTexelBuffer
: vk::DescriptorType::eUniformTexelBuffer,
.pTexelBufferView = &buffer_view,
});
++binding.buffer;
}
BindTextures(texture_cache, *info, binding, set_writes);
@ -226,7 +225,7 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
image_infos.emplace_back(vk_sampler, VK_NULL_HANDLE, vk::ImageLayout::eGeneral);
set_writes.push_back({
.dstSet = VK_NULL_HANDLE,
.dstBinding = binding++,
.dstBinding = binding.unified++,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = vk::DescriptorType::eSampler,

View file

@ -83,8 +83,9 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
.topology = LiverpoolToVK::PrimitiveType(key.prim_type),
.primitiveRestartEnable = key.enable_primitive_restart != 0,
};
ASSERT_MSG(!key.enable_primitive_restart || key.primitive_restart_index == 0xFFFF,
"Primitive restart index other than 0xFFFF is not supported yet");
ASSERT_MSG(!key.enable_primitive_restart || key.primitive_restart_index == 0xFFFF ||
key.primitive_restart_index == 0xFFFFFFFF,
"Primitive restart index other than -1 is not supported yet");
const vk::PipelineRasterizationStateCreateInfo raster_state = {
.depthClampEnable = false,
@ -356,7 +357,7 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
boost::container::small_vector<vk::WriteDescriptorSet, 16> set_writes;
boost::container::small_vector<vk::BufferMemoryBarrier2, 16> buffer_barriers;
Shader::PushData push_data{};
u32 binding{};
Shader::Backend::Bindings binding{};
image_infos.clear();
@ -368,6 +369,7 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
push_data.step0 = regs.vgt_instance_step_rate_0;
push_data.step1 = regs.vgt_instance_step_rate_1;
}
stage->PushUd(binding, push_data);
for (const auto& buffer : stage->buffers) {
const auto vsharp = buffer.GetSharp(*stage);
const bool is_storage = buffer.IsStorage(vsharp);
@ -383,10 +385,8 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
buffer_cache.ObtainBuffer(address, size, buffer.is_written);
const u32 offset_aligned = Common::AlignDown(offset, alignment);
const u32 adjust = offset - offset_aligned;
if (adjust != 0) {
ASSERT(adjust % 4 == 0);
push_data.AddOffset(binding, adjust);
}
ASSERT(adjust % 4 == 0);
push_data.AddOffset(binding.buffer, adjust);
buffer_infos.emplace_back(vk_buffer->Handle(), offset_aligned, size + adjust);
} else if (instance.IsNullDescriptorSupported()) {
buffer_infos.emplace_back(VK_NULL_HANDLE, 0, VK_WHOLE_SIZE);
@ -396,13 +396,14 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
}
set_writes.push_back({
.dstSet = VK_NULL_HANDLE,
.dstBinding = binding++,
.dstBinding = binding.unified++,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = is_storage ? vk::DescriptorType::eStorageBuffer
: vk::DescriptorType::eUniformBuffer,
.pBufferInfo = &buffer_infos.back(),
});
++binding.buffer;
}
for (const auto& desc : stage->texture_buffers) {
@ -419,10 +420,8 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
"Texel buffer stride must match format stride");
const u32 offset_aligned = Common::AlignDown(offset, alignment);
const u32 adjust = offset - offset_aligned;
if (adjust != 0) {
ASSERT(adjust % fmt_stride == 0);
push_data.AddOffset(binding, adjust / fmt_stride);
}
ASSERT(adjust % fmt_stride == 0);
push_data.AddOffset(binding.buffer, adjust / fmt_stride);
buffer_view = vk_buffer->View(offset_aligned, size + adjust, desc.is_written,
vsharp.GetDataFmt(), vsharp.GetNumberFmt());
const auto dst_access = desc.is_written ? vk::AccessFlagBits2::eShaderWrite
@ -437,13 +436,14 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
}
set_writes.push_back({
.dstSet = VK_NULL_HANDLE,
.dstBinding = binding++,
.dstBinding = binding.unified++,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = desc.is_written ? vk::DescriptorType::eStorageTexelBuffer
: vk::DescriptorType::eUniformTexelBuffer,
.pTexelBufferView = &buffer_view,
});
++binding.buffer;
}
BindTextures(texture_cache, *stage, binding, set_writes);
@ -463,7 +463,7 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs,
image_infos.emplace_back(vk_sampler, VK_NULL_HANDLE, vk::ImageLayout::eGeneral);
set_writes.push_back({
.dstSet = VK_NULL_HANDLE,
.dstBinding = binding++,
.dstBinding = binding.unified++,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = vk::DescriptorType::eSampler,

View file

@ -264,7 +264,7 @@ bool PipelineCache::RefreshGraphicsKey() {
++remapped_cb;
}
u32 binding{};
Shader::Backend::Bindings binding{};
for (u32 i = 0; i < MaxShaderStages; i++) {
if (!regs.stage_enable.IsStageEnabled(i)) {
key.stage_hashes[i] = 0;
@ -332,7 +332,7 @@ bool PipelineCache::RefreshGraphicsKey() {
}
bool PipelineCache::RefreshComputeKey() {
u32 binding{};
Shader::Backend::Bindings binding{};
const auto* cs_pgm = &liverpool->regs.cs_program;
const auto cs_params = Liverpool::GetParams(*cs_pgm);
if (ShouldSkipShader(cs_params.hash, "compute")) {
@ -346,7 +346,7 @@ bool PipelineCache::RefreshComputeKey() {
vk::ShaderModule PipelineCache::CompileModule(Shader::Info& info,
const Shader::RuntimeInfo& runtime_info,
std::span<const u32> code, size_t perm_idx,
u32& binding) {
Shader::Backend::Bindings& binding) {
LOG_INFO(Render_Vulkan, "Compiling {} shader {:#x} {}", info.stage, info.pgm_hash,
perm_idx != 0 ? "(permutation)" : "");
if (Config::dumpShaders()) {
@ -366,14 +366,14 @@ vk::ShaderModule PipelineCache::CompileModule(Shader::Info& info,
}
std::tuple<const Shader::Info*, vk::ShaderModule, u64> PipelineCache::GetProgram(
Shader::Stage stage, Shader::ShaderParams params, u32& binding) {
Shader::Stage stage, Shader::ShaderParams params, Shader::Backend::Bindings& binding) {
const auto runtime_info = BuildRuntimeInfo(stage);
auto [it_pgm, new_program] = program_cache.try_emplace(params.hash);
if (new_program) {
Program* program = program_pool.Create(stage, params);
u32 start_binding = binding;
auto start = binding;
const auto module = CompileModule(program->info, runtime_info, params.code, 0, binding);
const auto spec = Shader::StageSpecialization(program->info, runtime_info, start_binding);
const auto spec = Shader::StageSpecialization(program->info, runtime_info, start);
program->AddPermut(module, std::move(spec));
it_pgm.value() = program;
return std::make_tuple(&program->info, module, HashCombine(params.hash, 0));
@ -391,7 +391,7 @@ std::tuple<const Shader::Info*, vk::ShaderModule, u64> PipelineCache::GetProgram
module = CompileModule(new_info, runtime_info, params.code, perm_idx, binding);
program->AddPermut(module, std::move(spec));
} else {
binding += info.NumBindings();
info.AddBindings(binding);
module = it->module;
perm_idx = std::distance(program->modules.begin(), it);
}

View file

@ -49,9 +49,8 @@ public:
const ComputePipeline* GetComputePipeline();
std::tuple<const Shader::Info*, vk::ShaderModule, u64> GetProgram(Shader::Stage stage,
Shader::ShaderParams params,
u32& binding);
std::tuple<const Shader::Info*, vk::ShaderModule, u64> GetProgram(
Shader::Stage stage, Shader::ShaderParams params, Shader::Backend::Bindings& binding);
private:
bool RefreshGraphicsKey();
@ -60,7 +59,8 @@ private:
void DumpShader(std::span<const u32> code, u64 hash, Shader::Stage stage, size_t perm_idx,
std::string_view ext);
vk::ShaderModule CompileModule(Shader::Info& info, const Shader::RuntimeInfo& runtime_info,
std::span<const u32> code, size_t perm_idx, u32& binding);
std::span<const u32> code, size_t perm_idx,
Shader::Backend::Bindings& binding);
Shader::RuntimeInfo BuildRuntimeInfo(Shader::Stage stage);
private:

View file

@ -20,7 +20,8 @@ Pipeline::Pipeline(const Instance& instance_, Scheduler& scheduler_, DescriptorH
Pipeline::~Pipeline() = default;
void Pipeline::BindTextures(VideoCore::TextureCache& texture_cache, const Shader::Info& stage,
u32& binding, DescriptorWrites& set_writes) const {
Shader::Backend::Bindings& binding,
DescriptorWrites& set_writes) const {
using ImageBindingInfo = std::tuple<VideoCore::ImageId, AmdGpu::Image, Shader::ImageResource>;
boost::container::static_vector<ImageBindingInfo, 32> image_bindings;
@ -67,7 +68,7 @@ void Pipeline::BindTextures(VideoCore::TextureCache& texture_cache, const Shader
set_writes.push_back({
.dstSet = VK_NULL_HANDLE,
.dstBinding = binding++,
.dstBinding = binding.unified++,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = desc.is_storage ? vk::DescriptorType::eStorageImage

View file

@ -3,6 +3,7 @@
#pragma once
#include "shader_recompiler/backend/bindings.h"
#include "shader_recompiler/info.h"
#include "video_core/renderer_vulkan/vk_common.h"
@ -33,7 +34,7 @@ public:
using DescriptorWrites = boost::container::small_vector<vk::WriteDescriptorSet, 16>;
void BindTextures(VideoCore::TextureCache& texture_cache, const Shader::Info& stage,
u32& binding, DescriptorWrites& set_writes) const;
Shader::Backend::Bindings& binding, DescriptorWrites& set_writes) const;
protected:
const Instance& instance;