mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-05-24 12:25:00 +00:00
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:
parent
fb5bc371cb
commit
ee38eec7fe
23 changed files with 180 additions and 87 deletions
|
@ -9,10 +9,10 @@ namespace Shader::Backend {
|
|||
|
||||
struct Bindings {
|
||||
u32 unified{};
|
||||
u32 uniform_buffer{};
|
||||
u32 storage_buffer{};
|
||||
u32 texture{};
|
||||
u32 image{};
|
||||
u32 buffer{};
|
||||
u32 user_data{};
|
||||
|
||||
auto operator<=>(const Bindings&) const = default;
|
||||
};
|
||||
|
||||
} // namespace Shader::Backend
|
||||
|
|
|
@ -265,7 +265,7 @@ void PatchPhiNodes(const IR::Program& program, EmitContext& ctx) {
|
|||
} // Anonymous namespace
|
||||
|
||||
std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info,
|
||||
const IR::Program& program, u32& binding) {
|
||||
const IR::Program& program, Bindings& binding) {
|
||||
EmitContext ctx{profile, runtime_info, program.info, binding};
|
||||
const Id main{DefineMain(ctx, program)};
|
||||
DefineEntryPoint(program, ctx, main);
|
||||
|
|
|
@ -4,12 +4,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "shader_recompiler/backend/bindings.h"
|
||||
#include "shader_recompiler/ir/program.h"
|
||||
#include "shader_recompiler/profile.h"
|
||||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
|
||||
[[nodiscard]] std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info,
|
||||
const IR::Program& program, u32& binding);
|
||||
const IR::Program& program, Bindings& binding);
|
||||
|
||||
} // namespace Shader::Backend::SPIRV
|
||||
|
|
|
@ -86,7 +86,14 @@ Id OutputAttrPointer(EmitContext& ctx, IR::Attribute attr, u32 element) {
|
|||
} // Anonymous namespace
|
||||
|
||||
Id EmitGetUserData(EmitContext& ctx, IR::ScalarReg reg) {
|
||||
return ctx.ConstU32(ctx.info.user_data[static_cast<size_t>(reg)]);
|
||||
const u32 index = ctx.binding.user_data + ctx.info.ud_mask.Index(reg);
|
||||
const u32 half = PushData::UdRegsIndex + (index >> 2);
|
||||
const Id ud_ptr{ctx.OpAccessChain(ctx.TypePointer(spv::StorageClass::PushConstant, ctx.U32[1]),
|
||||
ctx.push_data_block, ctx.ConstU32(half),
|
||||
ctx.ConstU32(index & 3))};
|
||||
const Id ud_reg{ctx.OpLoad(ctx.U32[1], ud_ptr)};
|
||||
ctx.Name(ud_reg, fmt::format("ud_{}", u32(reg)));
|
||||
return ud_reg;
|
||||
}
|
||||
|
||||
void EmitGetThreadBitScalarReg(EmitContext& ctx) {
|
||||
|
|
|
@ -181,6 +181,7 @@ Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, u32 handle, Id lod
|
|||
case AmdGpu::ImageType::Color1DArray:
|
||||
case AmdGpu::ImageType::Color2D:
|
||||
case AmdGpu::ImageType::Cube:
|
||||
case AmdGpu::ImageType::Color2DMsaa:
|
||||
return ctx.OpCompositeConstruct(ctx.U32[4], query(ctx.U32[2]), zero, mips());
|
||||
case AmdGpu::ImageType::Color2DArray:
|
||||
case AmdGpu::ImageType::Color3D:
|
||||
|
|
|
@ -42,7 +42,7 @@ void Name(EmitContext& ctx, Id object, std::string_view format_str, Args&&... ar
|
|||
} // Anonymous namespace
|
||||
|
||||
EmitContext::EmitContext(const Profile& profile_, const RuntimeInfo& runtime_info_,
|
||||
const Info& info_, u32& binding_)
|
||||
const Info& info_, Bindings& binding_)
|
||||
: Sirit::Module(profile_.supported_spirv), info{info_}, runtime_info{runtime_info_},
|
||||
profile{profile_}, stage{info.stage}, binding{binding_} {
|
||||
AddCapability(spv::Capability::Shader);
|
||||
|
@ -173,7 +173,7 @@ EmitContext::SpirvAttribute EmitContext::GetAttributeInfo(AmdGpu::NumberFormat f
|
|||
}
|
||||
|
||||
void EmitContext::DefineBufferOffsets() {
|
||||
for (auto& buffer : buffers) {
|
||||
for (BufferDefinition& buffer : buffers) {
|
||||
const u32 binding = buffer.binding;
|
||||
const u32 half = PushData::BufOffsetIndex + (binding >> 4);
|
||||
const u32 comp = (binding & 0xf) >> 2;
|
||||
|
@ -182,9 +182,11 @@ void EmitContext::DefineBufferOffsets() {
|
|||
push_data_block, ConstU32(half), ConstU32(comp))};
|
||||
const Id value{OpLoad(U32[1], ptr)};
|
||||
buffer.offset = OpBitFieldUExtract(U32[1], value, ConstU32(offset), ConstU32(8U));
|
||||
Name(buffer.offset, fmt::format("buf{}_off", binding));
|
||||
buffer.offset_dwords = OpShiftRightLogical(U32[1], buffer.offset, ConstU32(2U));
|
||||
Name(buffer.offset_dwords, fmt::format("buf{}_dword_off", binding));
|
||||
}
|
||||
for (auto& tex_buffer : texture_buffers) {
|
||||
for (TextureBufferDefinition& tex_buffer : texture_buffers) {
|
||||
const u32 binding = tex_buffer.binding;
|
||||
const u32 half = PushData::BufOffsetIndex + (binding >> 4);
|
||||
const u32 comp = (binding & 0xf) >> 2;
|
||||
|
@ -192,7 +194,8 @@ void EmitContext::DefineBufferOffsets() {
|
|||
const Id ptr{OpAccessChain(TypePointer(spv::StorageClass::PushConstant, U32[1]),
|
||||
push_data_block, ConstU32(half), ConstU32(comp))};
|
||||
const Id value{OpLoad(U32[1], ptr)};
|
||||
tex_buffer.coord_offset = OpBitFieldUExtract(U32[1], value, ConstU32(offset), ConstU32(8U));
|
||||
tex_buffer.coord_offset = OpBitFieldUExtract(U32[1], value, ConstU32(offset), ConstU32(6U));
|
||||
Name(tex_buffer.coord_offset, fmt::format("texbuf{}_off", binding));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -330,18 +333,21 @@ void EmitContext::DefineOutputs() {
|
|||
|
||||
void EmitContext::DefinePushDataBlock() {
|
||||
// Create push constants block for instance steps rates
|
||||
const Id struct_type{Name(TypeStruct(U32[1], U32[1], U32[4], U32[4], U32[4]), "AuxData")};
|
||||
const Id struct_type{
|
||||
Name(TypeStruct(U32[1], U32[1], U32[4], U32[4], U32[4], U32[4]), "AuxData")};
|
||||
Decorate(struct_type, spv::Decoration::Block);
|
||||
MemberName(struct_type, 0, "sr0");
|
||||
MemberName(struct_type, 1, "sr1");
|
||||
MemberName(struct_type, 2, "buf_offsets0");
|
||||
MemberName(struct_type, 3, "buf_offsets1");
|
||||
MemberName(struct_type, 4, "buf_offsets2");
|
||||
MemberName(struct_type, 4, "ud_regs0");
|
||||
MemberName(struct_type, 5, "ud_regs1");
|
||||
MemberDecorate(struct_type, 0, spv::Decoration::Offset, 0U);
|
||||
MemberDecorate(struct_type, 1, spv::Decoration::Offset, 4U);
|
||||
MemberDecorate(struct_type, 2, spv::Decoration::Offset, 8U);
|
||||
MemberDecorate(struct_type, 3, spv::Decoration::Offset, 24U);
|
||||
MemberDecorate(struct_type, 4, spv::Decoration::Offset, 40U);
|
||||
MemberDecorate(struct_type, 5, spv::Decoration::Offset, 56U);
|
||||
push_data_block = DefineVar(struct_type, spv::StorageClass::PushConstant);
|
||||
Name(push_data_block, "push_data");
|
||||
interfaces.push_back(push_data_block);
|
||||
|
@ -379,7 +385,7 @@ void EmitContext::DefineBuffers() {
|
|||
const Id struct_pointer_type{TypePointer(storage_class, struct_type)};
|
||||
const Id pointer_type = TypePointer(storage_class, data_type);
|
||||
const Id id{AddGlobalVariable(struct_pointer_type, storage_class)};
|
||||
Decorate(id, spv::Decoration::Binding, binding);
|
||||
Decorate(id, spv::Decoration::Binding, binding.unified++);
|
||||
Decorate(id, spv::Decoration::DescriptorSet, 0U);
|
||||
if (is_storage && !desc.is_written) {
|
||||
Decorate(id, spv::Decoration::NonWritable);
|
||||
|
@ -388,7 +394,7 @@ void EmitContext::DefineBuffers() {
|
|||
|
||||
buffers.push_back({
|
||||
.id = id,
|
||||
.binding = binding++,
|
||||
.binding = binding.buffer++,
|
||||
.data_types = data_types,
|
||||
.pointer_type = pointer_type,
|
||||
});
|
||||
|
@ -406,12 +412,12 @@ void EmitContext::DefineTextureBuffers() {
|
|||
sampled, spv::ImageFormat::Unknown)};
|
||||
const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)};
|
||||
const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)};
|
||||
Decorate(id, spv::Decoration::Binding, binding);
|
||||
Decorate(id, spv::Decoration::Binding, binding.unified++);
|
||||
Decorate(id, spv::Decoration::DescriptorSet, 0U);
|
||||
Name(id, fmt::format("{}_{}", desc.is_written ? "imgbuf" : "texbuf", desc.sgpr_base));
|
||||
texture_buffers.push_back({
|
||||
.id = id,
|
||||
.binding = binding++,
|
||||
.binding = binding.buffer++,
|
||||
.image_type = image_type,
|
||||
.result_type = sampled_type[4],
|
||||
.is_integer = is_integer,
|
||||
|
@ -507,6 +513,8 @@ Id ImageType(EmitContext& ctx, const ImageResource& desc, Id sampled_type) {
|
|||
return ctx.TypeImage(sampled_type, spv::Dim::Dim2D, false, false, false, sampled, format);
|
||||
case AmdGpu::ImageType::Color2DArray:
|
||||
return ctx.TypeImage(sampled_type, spv::Dim::Dim2D, false, true, false, sampled, format);
|
||||
case AmdGpu::ImageType::Color2DMsaa:
|
||||
return ctx.TypeImage(sampled_type, spv::Dim::Dim2D, false, false, true, sampled, format);
|
||||
case AmdGpu::ImageType::Color3D:
|
||||
return ctx.TypeImage(sampled_type, spv::Dim::Dim3D, false, false, false, sampled, format);
|
||||
case AmdGpu::ImageType::Cube:
|
||||
|
@ -525,7 +533,7 @@ void EmitContext::DefineImagesAndSamplers() {
|
|||
const Id image_type{ImageType(*this, image_desc, sampled_type)};
|
||||
const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)};
|
||||
const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)};
|
||||
Decorate(id, spv::Decoration::Binding, binding);
|
||||
Decorate(id, spv::Decoration::Binding, binding.unified++);
|
||||
Decorate(id, spv::Decoration::DescriptorSet, 0U);
|
||||
Name(id, fmt::format("{}_{}{}_{:02x}", stage, "img", image_desc.sgpr_base,
|
||||
image_desc.dword_offset));
|
||||
|
@ -538,7 +546,6 @@ void EmitContext::DefineImagesAndSamplers() {
|
|||
.is_storage = image_desc.is_storage,
|
||||
});
|
||||
interfaces.push_back(id);
|
||||
++binding;
|
||||
}
|
||||
if (std::ranges::any_of(info.images, &ImageResource::is_atomic)) {
|
||||
image_u32 = TypePointer(spv::StorageClass::Image, U32[1]);
|
||||
|
@ -550,13 +557,12 @@ void EmitContext::DefineImagesAndSamplers() {
|
|||
sampler_pointer_type = TypePointer(spv::StorageClass::UniformConstant, sampler_type);
|
||||
for (const auto& samp_desc : info.samplers) {
|
||||
const Id id{AddGlobalVariable(sampler_pointer_type, spv::StorageClass::UniformConstant)};
|
||||
Decorate(id, spv::Decoration::Binding, binding);
|
||||
Decorate(id, spv::Decoration::Binding, binding.unified++);
|
||||
Decorate(id, spv::Decoration::DescriptorSet, 0U);
|
||||
Name(id, fmt::format("{}_{}{}_{:02x}", stage, "samp", samp_desc.sgpr_base,
|
||||
samp_desc.dword_offset));
|
||||
samplers.push_back(id);
|
||||
interfaces.push_back(id);
|
||||
++binding;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <array>
|
||||
#include <sirit/sirit.h>
|
||||
|
||||
#include "shader_recompiler/backend/bindings.h"
|
||||
#include "shader_recompiler/info.h"
|
||||
#include "shader_recompiler/ir/program.h"
|
||||
#include "shader_recompiler/profile.h"
|
||||
|
@ -37,7 +38,7 @@ struct VectorIds {
|
|||
class EmitContext final : public Sirit::Module {
|
||||
public:
|
||||
explicit EmitContext(const Profile& profile, const RuntimeInfo& runtime_info, const Info& info,
|
||||
u32& binding);
|
||||
Bindings& binding);
|
||||
~EmitContext();
|
||||
|
||||
Id Def(const IR::Value& value);
|
||||
|
@ -221,7 +222,7 @@ public:
|
|||
bool is_storage = false;
|
||||
};
|
||||
|
||||
u32& binding;
|
||||
Bindings& binding;
|
||||
boost::container::small_vector<BufferDefinition, 16> buffers;
|
||||
boost::container::small_vector<TextureBufferDefinition, 8> texture_buffers;
|
||||
boost::container::small_vector<TextureDefinition, 8> images;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue