mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-05-19 09:54:54 +00:00
video_core: Add image support
This commit is contained in:
parent
729e166cd3
commit
d59b102b6f
48 changed files with 1264 additions and 259 deletions
|
@ -218,8 +218,8 @@ void PatchPhiNodes(IR::Program& program, EmitContext& ctx) {
|
|||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program, Bindings& bindings) {
|
||||
EmitContext ctx{profile, program, bindings};
|
||||
std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program, u32& binding) {
|
||||
EmitContext ctx{profile, program, binding};
|
||||
const Id main{DefineMain(ctx, program)};
|
||||
DefineEntryPoint(program, ctx, main);
|
||||
if (program.info.stage == Stage::Vertex) {
|
||||
|
|
|
@ -4,18 +4,12 @@
|
|||
#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, IR::Program& program,
|
||||
Bindings& bindings);
|
||||
|
||||
[[nodiscard]] inline std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program) {
|
||||
Bindings binding;
|
||||
return EmitSPIRV(profile, program, binding);
|
||||
}
|
||||
u32& binding);
|
||||
|
||||
} // namespace Shader::Backend::SPIRV
|
||||
|
|
|
@ -61,14 +61,11 @@ Id EmitReadConst(EmitContext& ctx) {
|
|||
throw LogicError("Unreachable instruction");
|
||||
}
|
||||
|
||||
Id EmitReadConstBuffer(EmitContext& ctx, const IR::Value& binding, const IR::Value& addr,
|
||||
const IR::Value& offset) {
|
||||
throw LogicError("Unreachable instruction");
|
||||
}
|
||||
|
||||
Id EmitReadConstBufferF32(EmitContext& ctx, const IR::Value& binding, const IR::Value& addr,
|
||||
const IR::Value& offset) {
|
||||
throw LogicError("Unreachable instruction");
|
||||
Id EmitReadConstBuffer(EmitContext& ctx, u32 handle, Id index) {
|
||||
const Id buffer = ctx.buffers[handle];
|
||||
const Id type = ctx.info.buffers[handle].is_storage ? ctx.storage_f32 : ctx.uniform_f32;
|
||||
const Id ptr{ctx.OpAccessChain(type, buffer, ctx.ConstU32(0U), index)};
|
||||
return ctx.OpLoad(ctx.F32[1], ptr);
|
||||
}
|
||||
|
||||
Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, u32 comp) {
|
||||
|
@ -99,32 +96,28 @@ void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value, u32 elemen
|
|||
ctx.OpStore(pointer, value);
|
||||
}
|
||||
|
||||
Id EmitLoadBufferF32(EmitContext& ctx, IR::Inst* inst, const IR::Value& handle,
|
||||
const IR::Value& address) {
|
||||
Id EmitLoadBufferF32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
Id EmitLoadBufferF32x2(EmitContext& ctx, IR::Inst* inst, const IR::Value& handle,
|
||||
const IR::Value& address) {
|
||||
Id EmitLoadBufferF32x2(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
Id EmitLoadBufferF32x3(EmitContext& ctx, IR::Inst* inst, const IR::Value& handle,
|
||||
const IR::Value& address) {
|
||||
Id EmitLoadBufferF32x3(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
Id EmitLoadBufferF32x4(EmitContext& ctx, IR::Inst* inst, const IR::Value& handle,
|
||||
const IR::Value& address) {
|
||||
Id EmitLoadBufferF32x4(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address) {
|
||||
const auto info = inst->Flags<IR::BufferInstInfo>();
|
||||
const Id buffer = ctx.buffers[handle.U32()];
|
||||
const Id type = ctx.info.buffers[handle.U32()].is_storage ? ctx.storage_f32 : ctx.uniform_f32;
|
||||
const Id buffer = ctx.buffers[handle];
|
||||
const Id type = ctx.info.buffers[handle].is_storage ? ctx.storage_f32 : ctx.uniform_f32;
|
||||
if (info.index_enable && info.offset_enable) {
|
||||
UNREACHABLE();
|
||||
} else if (info.index_enable) {
|
||||
boost::container::static_vector<Id, 4> ids;
|
||||
for (u32 i = 0; i < 4; i++) {
|
||||
const Id index{ctx.OpIAdd(ctx.U32[1], ctx.Def(address), ctx.ConstU32(i))};
|
||||
const Id index{ctx.OpIAdd(ctx.U32[1], address, ctx.ConstU32(i))};
|
||||
const Id ptr{ctx.OpAccessChain(type, buffer, ctx.ConstU32(0U), index)};
|
||||
ids.push_back(ctx.OpLoad(ctx.F32[1], ptr));
|
||||
}
|
||||
|
|
|
@ -6,9 +6,14 @@
|
|||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
|
||||
Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id bias_lc, const IR::Value& offset) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id bias_lc,
|
||||
Id offset) {
|
||||
const auto& texture = ctx.images[handle & 0xFFFF];
|
||||
const Id image = ctx.OpLoad(texture.image_type, texture.id);
|
||||
const Id sampler = ctx.OpLoad(ctx.sampler_type, ctx.samplers[handle >> 16]);
|
||||
const Id sampled_image = ctx.OpSampledImage(texture.sampled_type, image, sampler);
|
||||
const auto info = inst->Flags<IR::TextureInstInfo>();
|
||||
return ctx.OpImageSampleImplicitLod(ctx.F32[4], sampled_image, coords);
|
||||
}
|
||||
|
||||
Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
|
|
|
@ -43,18 +43,11 @@ void EmitSetGotoVariable(EmitContext& ctx);
|
|||
void EmitGetGotoVariable(EmitContext& ctx);
|
||||
void EmitSetScc(EmitContext& ctx);
|
||||
Id EmitReadConst(EmitContext& ctx);
|
||||
Id EmitReadConstBuffer(EmitContext& ctx, const IR::Value& handle, const IR::Value& index,
|
||||
const IR::Value& offset);
|
||||
Id EmitReadConstBufferF32(EmitContext& ctx, const IR::Value& handle, const IR::Value& index,
|
||||
const IR::Value& offset);
|
||||
Id EmitLoadBufferF32(EmitContext& ctx, IR::Inst* inst, const IR::Value& handle,
|
||||
const IR::Value& address);
|
||||
Id EmitLoadBufferF32x2(EmitContext& ctx, IR::Inst* inst, const IR::Value& handle,
|
||||
const IR::Value& address);
|
||||
Id EmitLoadBufferF32x3(EmitContext& ctx, IR::Inst* inst, const IR::Value& handle,
|
||||
const IR::Value& address);
|
||||
Id EmitLoadBufferF32x4(EmitContext& ctx, IR::Inst* inst, const IR::Value& handle,
|
||||
const IR::Value& address);
|
||||
Id EmitReadConstBuffer(EmitContext& ctx, u32 handle, Id index);
|
||||
Id EmitLoadBufferF32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address);
|
||||
Id EmitLoadBufferF32x2(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address);
|
||||
Id EmitLoadBufferF32x3(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address);
|
||||
Id EmitLoadBufferF32x4(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address);
|
||||
Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, u32 comp);
|
||||
Id EmitGetAttributeU32(EmitContext& ctx, IR::Attribute attr, u32 comp);
|
||||
void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value, u32 comp);
|
||||
|
@ -319,8 +312,8 @@ Id EmitConvertF64U16(EmitContext& ctx, Id value);
|
|||
Id EmitConvertF64U32(EmitContext& ctx, Id value);
|
||||
Id EmitConvertF64U64(EmitContext& ctx, Id value);
|
||||
|
||||
Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id bias_lc, const IR::Value& offset);
|
||||
Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id bias_lc,
|
||||
Id offset);
|
||||
Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id lod, const IR::Value& offset);
|
||||
Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
|
||||
|
|
|
@ -35,17 +35,14 @@ void Name(EmitContext& ctx, Id object, std::string_view format_str, Args&&... ar
|
|||
|
||||
} // Anonymous namespace
|
||||
|
||||
EmitContext::EmitContext(const Profile& profile_, IR::Program& program, Bindings& bindings)
|
||||
EmitContext::EmitContext(const Profile& profile_, IR::Program& program, u32& binding_)
|
||||
: Sirit::Module(profile_.supported_spirv), info{program.info}, profile{profile_},
|
||||
stage{program.info.stage} {
|
||||
u32& uniform_binding{bindings.unified};
|
||||
u32& storage_binding{bindings.unified};
|
||||
u32& texture_binding{bindings.unified};
|
||||
u32& image_binding{bindings.unified};
|
||||
stage{program.info.stage}, binding{binding_} {
|
||||
AddCapability(spv::Capability::Shader);
|
||||
DefineArithmeticTypes();
|
||||
DefineInterfaces(program);
|
||||
DefineBuffers(program.info);
|
||||
DefineImagesAndSamplers(program.info);
|
||||
}
|
||||
|
||||
EmitContext::~EmitContext() = default;
|
||||
|
@ -235,16 +232,15 @@ void EmitContext::DefineOutputs(const Info& info) {
|
|||
}
|
||||
|
||||
void EmitContext::DefineBuffers(const Info& info) {
|
||||
const auto define_buffer = [&](const BufferResource& buffer, Id type, u32 element_size,
|
||||
char type_char, u32 index) {
|
||||
ASSERT(buffer.stride % element_size == 0);
|
||||
const u32 num_elements = buffer.stride * buffer.num_records / element_size;
|
||||
for (u32 i = 0; const auto& buffer : info.buffers) {
|
||||
ASSERT(True(buffer.used_types & IR::Type::F32));
|
||||
ASSERT(buffer.stride % sizeof(float) == 0);
|
||||
const u32 num_elements = buffer.stride * buffer.num_records / sizeof(float);
|
||||
const Id record_array_type{TypeArray(F32[1], ConstU32(num_elements))};
|
||||
Decorate(record_array_type, spv::Decoration::ArrayStride, element_size);
|
||||
Decorate(record_array_type, spv::Decoration::ArrayStride, sizeof(float));
|
||||
|
||||
const Id struct_type{TypeStruct(record_array_type)};
|
||||
const auto name =
|
||||
fmt::format("{}_cbuf_block_{}{}", stage, type_char, element_size * CHAR_BIT);
|
||||
const auto name = fmt::format("{}_cbuf_block_{}{}", stage, 'f', sizeof(float) * CHAR_BIT);
|
||||
Name(struct_type, name);
|
||||
Decorate(struct_type, spv::Decoration::Block);
|
||||
MemberName(struct_type, 0, "data");
|
||||
|
@ -254,25 +250,112 @@ void EmitContext::DefineBuffers(const Info& info) {
|
|||
buffer.is_storage ? spv::StorageClass::StorageBuffer : spv::StorageClass::Uniform;
|
||||
const Id struct_pointer_type{TypePointer(storage_class, struct_type)};
|
||||
if (buffer.is_storage) {
|
||||
storage_f32 = TypePointer(storage_class, type);
|
||||
storage_f32 = TypePointer(storage_class, F32[1]);
|
||||
} else {
|
||||
uniform_f32 = TypePointer(storage_class, type);
|
||||
uniform_f32 = TypePointer(storage_class, F32[1]);
|
||||
}
|
||||
const Id id{AddGlobalVariable(struct_pointer_type, storage_class)};
|
||||
Decorate(id, spv::Decoration::Binding, binding);
|
||||
Decorate(id, spv::Decoration::DescriptorSet, 0U);
|
||||
Name(id, fmt::format("c{}", index));
|
||||
Name(id, fmt::format("c{}", i));
|
||||
|
||||
binding++;
|
||||
buffers.push_back(id);
|
||||
interfaces.push_back(id);
|
||||
};
|
||||
|
||||
for (u32 i = 0; const auto& buffer : info.buffers) {
|
||||
ASSERT(True(buffer.used_types & IR::Type::F32));
|
||||
define_buffer(buffer, F32[1], 4, 'f', i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
Id ImageType(EmitContext& ctx, const ImageResource& desc) {
|
||||
const spv::ImageFormat format{spv::ImageFormat::Unknown};
|
||||
const Id type{ctx.F32[1]};
|
||||
const bool depth{desc.is_depth};
|
||||
switch (desc.type) {
|
||||
case AmdGpu::ImageType::Color1D:
|
||||
return ctx.TypeImage(type, spv::Dim::Dim1D, depth, false, false, 1, format,
|
||||
spv::AccessQualifier::ReadOnly);
|
||||
case AmdGpu::ImageType::Color1DArray:
|
||||
return ctx.TypeImage(type, spv::Dim::Dim1D, depth, true, false, 1, format,
|
||||
spv::AccessQualifier::ReadOnly);
|
||||
case AmdGpu::ImageType::Color2D:
|
||||
case AmdGpu::ImageType::Color2DMsaa:
|
||||
return ctx.TypeImage(type, spv::Dim::Dim2D, depth, false,
|
||||
desc.type == AmdGpu::ImageType::Color2DMsaa, 1, format,
|
||||
spv::AccessQualifier::ReadOnly);
|
||||
case AmdGpu::ImageType::Color2DArray:
|
||||
case AmdGpu::ImageType::Color2DMsaaArray:
|
||||
return ctx.TypeImage(type, spv::Dim::Dim2D, depth, true,
|
||||
desc.type == AmdGpu::ImageType::Color2DMsaaArray, 1, format,
|
||||
spv::AccessQualifier::ReadOnly);
|
||||
case AmdGpu::ImageType::Color3D:
|
||||
return ctx.TypeImage(type, spv::Dim::Dim3D, depth, false, false, 1, format,
|
||||
spv::AccessQualifier::ReadOnly);
|
||||
case AmdGpu::ImageType::Cube:
|
||||
return ctx.TypeImage(type, spv::Dim::Cube, depth, false, false, 1, format,
|
||||
spv::AccessQualifier::ReadOnly);
|
||||
case AmdGpu::ImageType::Buffer:
|
||||
break;
|
||||
}
|
||||
throw InvalidArgument("Invalid texture type {}", desc.type);
|
||||
}
|
||||
|
||||
Id ImageType(EmitContext& ctx, const ImageResource& desc, Id sampled_type) {
|
||||
const auto format = spv::ImageFormat::Unknown; // Read this from tsharp?
|
||||
switch (desc.type) {
|
||||
case AmdGpu::ImageType::Color1D:
|
||||
return ctx.TypeImage(sampled_type, spv::Dim::Dim1D, false, false, false, 1, format);
|
||||
case AmdGpu::ImageType::Color1DArray:
|
||||
return ctx.TypeImage(sampled_type, spv::Dim::Dim1D, false, true, false, 1, format);
|
||||
case AmdGpu::ImageType::Color2D:
|
||||
return ctx.TypeImage(sampled_type, spv::Dim::Dim2D, false, false, false, 1, format);
|
||||
case AmdGpu::ImageType::Color2DArray:
|
||||
return ctx.TypeImage(sampled_type, spv::Dim::Dim2D, false, true, false, 1, format);
|
||||
case AmdGpu::ImageType::Color3D:
|
||||
return ctx.TypeImage(sampled_type, spv::Dim::Dim3D, false, false, false, 2, format);
|
||||
case AmdGpu::ImageType::Buffer:
|
||||
throw NotImplementedException("Image buffer");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
throw InvalidArgument("Invalid texture type {}", desc.type);
|
||||
}
|
||||
|
||||
void EmitContext::DefineImagesAndSamplers(const Info& info) {
|
||||
for (const auto& image_desc : info.images) {
|
||||
const Id sampled_type{image_desc.nfmt == AmdGpu::NumberFormat::Uint ? U32[1] : F32[1]};
|
||||
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::DescriptorSet, 0U);
|
||||
Name(id, fmt::format("{}_{}{}_{:02x}", stage, "img", image_desc.sgpr_base,
|
||||
image_desc.dword_offset));
|
||||
images.push_back({
|
||||
.id = id,
|
||||
.sampled_type = TypeSampledImage(image_type),
|
||||
.pointer_type = pointer_type,
|
||||
.image_type = image_type,
|
||||
});
|
||||
interfaces.push_back(id);
|
||||
++binding;
|
||||
}
|
||||
|
||||
if (info.samplers.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
sampler_type = TypeSampler();
|
||||
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::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;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Shader::Backend::SPIRV
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include <array>
|
||||
#include <sirit/sirit.h>
|
||||
|
||||
#include "shader_recompiler/backend/bindings.h"
|
||||
#include "shader_recompiler/ir/program.h"
|
||||
#include "shader_recompiler/profile.h"
|
||||
#include "shader_recompiler/runtime_info.h"
|
||||
|
@ -29,7 +28,7 @@ struct VectorIds {
|
|||
|
||||
class EmitContext final : public Sirit::Module {
|
||||
public:
|
||||
explicit EmitContext(const Profile& profile, IR::Program& program, Bindings& binding);
|
||||
explicit EmitContext(const Profile& profile, IR::Program& program, u32& binding);
|
||||
~EmitContext();
|
||||
|
||||
Id Def(const IR::Value& value);
|
||||
|
@ -152,8 +151,20 @@ public:
|
|||
Id base_vertex{};
|
||||
std::array<Id, 8> frag_color{};
|
||||
|
||||
u32 binding{};
|
||||
struct TextureDefinition {
|
||||
Id id;
|
||||
Id sampled_type;
|
||||
Id pointer_type;
|
||||
Id image_type;
|
||||
};
|
||||
|
||||
u32& binding;
|
||||
boost::container::small_vector<Id, 4> buffers;
|
||||
boost::container::small_vector<TextureDefinition, 4> images;
|
||||
boost::container::small_vector<Id, 4> samplers;
|
||||
|
||||
Id sampler_type{};
|
||||
Id sampler_pointer_type{};
|
||||
|
||||
struct SpirvAttribute {
|
||||
Id id;
|
||||
|
@ -170,6 +181,7 @@ private:
|
|||
void DefineInputs(const Info& info);
|
||||
void DefineOutputs(const Info& info);
|
||||
void DefineBuffers(const Info& info);
|
||||
void DefineImagesAndSamplers(const Info& info);
|
||||
|
||||
SpirvAttribute GetAttributeInfo(AmdGpu::NumberFormat fmt, Id id);
|
||||
};
|
||||
|
|
|
@ -8,15 +8,18 @@ namespace Shader::Gcn {
|
|||
void Load(IR::IREmitter& ir, int num_dwords, const IR::Value& handle, IR::ScalarReg dst_reg,
|
||||
const IR::U32U64& address) {
|
||||
for (u32 i = 0; i < num_dwords; i++) {
|
||||
const IR::U32 value = handle.IsEmpty() ? ir.ReadConst(address, ir.Imm32(i))
|
||||
: ir.ReadConstBuffer(handle, address, ir.Imm32(i));
|
||||
ir.SetScalarReg(dst_reg++, value);
|
||||
if (handle.IsEmpty()) {
|
||||
ir.SetScalarReg(dst_reg++, ir.ReadConst(address, ir.Imm32(i)));
|
||||
} else {
|
||||
const IR::U32 index = ir.IAdd(address, ir.Imm32(i));
|
||||
ir.SetScalarReg(dst_reg++, ir.ReadConstBuffer(handle, index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Translator::S_LOAD_DWORD(int num_dwords, const GcnInst& inst) {
|
||||
const auto& smrd = inst.control.smrd;
|
||||
const IR::ScalarReg sbase = IR::ScalarReg(inst.src[0].code * 2);
|
||||
const IR::ScalarReg sbase{inst.src[0].code * 2};
|
||||
const IR::U32 offset =
|
||||
smrd.imm ? ir.Imm32(smrd.offset * 4)
|
||||
: IR::U32{ir.ShiftLeftLogical(ir.GetScalarReg(IR::ScalarReg(smrd.offset)),
|
||||
|
@ -30,14 +33,12 @@ void Translator::S_LOAD_DWORD(int num_dwords, const GcnInst& inst) {
|
|||
|
||||
void Translator::S_BUFFER_LOAD_DWORD(int num_dwords, const GcnInst& inst) {
|
||||
const auto& smrd = inst.control.smrd;
|
||||
const IR::ScalarReg sbase = IR::ScalarReg(inst.src[0].code * 2);
|
||||
const IR::ScalarReg sbase{inst.src[0].code * 2};
|
||||
const IR::U32 offset =
|
||||
smrd.imm ? ir.Imm32(smrd.offset * 4)
|
||||
: IR::U32{ir.ShiftLeftLogical(ir.GetScalarReg(IR::ScalarReg(smrd.offset)),
|
||||
ir.Imm32(2))};
|
||||
const IR::Value vsharp =
|
||||
ir.CompositeConstruct(ir.GetScalarReg(sbase), ir.GetScalarReg(sbase + 1),
|
||||
ir.GetScalarReg(sbase + 2), ir.GetScalarReg(sbase + 3));
|
||||
const IR::Value vsharp = ir.GetScalarReg(sbase);
|
||||
const IR::ScalarReg dst_reg{inst.dst[0].code};
|
||||
Load(ir, num_dwords, vsharp, dst_reg, offset);
|
||||
}
|
||||
|
|
|
@ -73,8 +73,14 @@ IR::U32F32 Translator::GetSrc(const InstOperand& operand, bool force_flt) {
|
|||
return ir.Imm32(1.f);
|
||||
case OperandField::ConstFloatPos_0_5:
|
||||
return ir.Imm32(0.5f);
|
||||
case OperandField::ConstFloatPos_2_0:
|
||||
return ir.Imm32(2.0f);
|
||||
case OperandField::ConstFloatPos_4_0:
|
||||
return ir.Imm32(4.0f);
|
||||
case OperandField::ConstFloatNeg_0_5:
|
||||
return ir.Imm32(-0.5f);
|
||||
case OperandField::ConstFloatNeg_1_0:
|
||||
return ir.Imm32(-1.0f);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -135,6 +141,9 @@ void Translate(IR::Block* block, std::span<const GcnInst> inst_list, Info& info)
|
|||
case Opcode::S_MUL_I32:
|
||||
translator.S_MUL_I32(inst);
|
||||
break;
|
||||
case Opcode::V_MAD_F32:
|
||||
translator.V_MAD_F32(inst);
|
||||
break;
|
||||
case Opcode::V_MOV_B32:
|
||||
translator.V_MOV(inst);
|
||||
break;
|
||||
|
@ -144,12 +153,39 @@ void Translate(IR::Block* block, std::span<const GcnInst> inst_list, Info& info)
|
|||
case Opcode::V_MUL_F32:
|
||||
translator.V_MUL_F32(inst);
|
||||
break;
|
||||
case Opcode::V_AND_B32:
|
||||
translator.V_AND_B32(inst);
|
||||
break;
|
||||
case Opcode::V_LSHLREV_B32:
|
||||
translator.V_LSHLREV_B32(inst);
|
||||
break;
|
||||
case Opcode::V_ADD_I32:
|
||||
translator.V_ADD_I32(inst);
|
||||
break;
|
||||
case Opcode::V_CVT_F32_I32:
|
||||
translator.V_CVT_F32_I32(inst);
|
||||
break;
|
||||
case Opcode::V_CVT_F32_U32:
|
||||
translator.V_CVT_F32_U32(inst);
|
||||
break;
|
||||
case Opcode::S_SWAPPC_B64:
|
||||
ASSERT(info.stage == Stage::Vertex);
|
||||
translator.EmitFetch(inst);
|
||||
break;
|
||||
case Opcode::S_WAITCNT:
|
||||
break; // Ignore for now.
|
||||
break;
|
||||
case Opcode::S_BUFFER_LOAD_DWORD:
|
||||
translator.S_BUFFER_LOAD_DWORD(1, inst);
|
||||
break;
|
||||
case Opcode::S_BUFFER_LOAD_DWORDX2:
|
||||
translator.S_BUFFER_LOAD_DWORD(2, inst);
|
||||
break;
|
||||
case Opcode::S_BUFFER_LOAD_DWORDX4:
|
||||
translator.S_BUFFER_LOAD_DWORD(4, inst);
|
||||
break;
|
||||
case Opcode::S_BUFFER_LOAD_DWORDX8:
|
||||
translator.S_BUFFER_LOAD_DWORD(8, inst);
|
||||
break;
|
||||
case Opcode::S_BUFFER_LOAD_DWORDX16:
|
||||
translator.S_BUFFER_LOAD_DWORD(16, inst);
|
||||
break;
|
||||
|
@ -180,7 +216,8 @@ void Translate(IR::Block* block, std::span<const GcnInst> inst_list, Info& info)
|
|||
case Opcode::S_ENDPGM:
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE_MSG("Unknown opcode {}", u32(inst.opcode));
|
||||
const u32 opcode = u32(inst.opcode);
|
||||
UNREACHABLE_MSG("Unknown opcode {}", opcode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,12 @@ public:
|
|||
void V_MUL_F32(const GcnInst& inst);
|
||||
void V_CMP_EQ_U32(const GcnInst& inst);
|
||||
void V_CNDMASK_B32(const GcnInst& inst);
|
||||
void V_AND_B32(const GcnInst& inst);
|
||||
void V_LSHLREV_B32(const GcnInst& inst);
|
||||
void V_ADD_I32(const GcnInst& inst);
|
||||
void V_CVT_F32_I32(const GcnInst& inst);
|
||||
void V_CVT_F32_U32(const GcnInst& inst);
|
||||
void V_MAD_F32(const GcnInst& inst);
|
||||
|
||||
// Vector Memory
|
||||
void TBUFFER_LOAD_FORMAT_XYZW(const GcnInst& inst);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma clang optimize off
|
||||
|
||||
#include "shader_recompiler/frontend/translate/translate.h"
|
||||
|
||||
namespace Shader::Gcn {
|
||||
|
@ -61,4 +61,45 @@ void Translator::V_CNDMASK_B32(const GcnInst& inst) {
|
|||
ir.SetVectorReg(dst_reg, IR::U32F32{result});
|
||||
}
|
||||
|
||||
void Translator::V_AND_B32(const GcnInst& inst) {
|
||||
const IR::U32 src0{GetSrc(inst.src[0])};
|
||||
const IR::U32 src1{ir.GetVectorReg(IR::VectorReg(inst.src[1].code))};
|
||||
const IR::VectorReg dst_reg{inst.dst[0].code};
|
||||
ir.SetVectorReg(dst_reg, ir.BitwiseAnd(src0, src1));
|
||||
}
|
||||
|
||||
void Translator::V_LSHLREV_B32(const GcnInst& inst) {
|
||||
const IR::U32 src0{GetSrc(inst.src[0])};
|
||||
const IR::U32 src1{ir.GetVectorReg(IR::VectorReg(inst.src[1].code))};
|
||||
const IR::VectorReg dst_reg{inst.dst[0].code};
|
||||
ir.SetVectorReg(dst_reg, ir.ShiftLeftLogical(src1, src0));
|
||||
}
|
||||
|
||||
void Translator::V_ADD_I32(const GcnInst& inst) {
|
||||
const IR::U32 src0{GetSrc(inst.src[0])};
|
||||
const IR::U32 src1{ir.GetVectorReg(IR::VectorReg(inst.src[1].code))};
|
||||
const IR::VectorReg dst_reg{inst.dst[0].code};
|
||||
ir.SetVectorReg(dst_reg, ir.IAdd(src0, src1));
|
||||
// TODO: Carry
|
||||
}
|
||||
|
||||
void Translator::V_CVT_F32_I32(const GcnInst& inst) {
|
||||
const IR::U32 src0{GetSrc(inst.src[0])};
|
||||
const IR::VectorReg dst_reg{inst.dst[0].code};
|
||||
ir.SetVectorReg(dst_reg, ir.ConvertSToF(32, 32, src0));
|
||||
}
|
||||
|
||||
void Translator::V_CVT_F32_U32(const GcnInst& inst) {
|
||||
const IR::U32 src0{GetSrc(inst.src[0])};
|
||||
const IR::VectorReg dst_reg{inst.dst[0].code};
|
||||
ir.SetVectorReg(dst_reg, ir.ConvertUToF(32, 32, src0));
|
||||
}
|
||||
|
||||
void Translator::V_MAD_F32(const GcnInst& inst) {
|
||||
const IR::F32 src0{GetSrc(inst.src[0])};
|
||||
const IR::F32 src1{GetSrc(inst.src[1])};
|
||||
const IR::F32 src2{GetSrc(inst.src[2])};
|
||||
SetDst(inst.dst[0], ir.FPFma(src0, src1, src2));
|
||||
}
|
||||
|
||||
} // namespace Shader::Gcn
|
||||
|
|
|
@ -63,27 +63,34 @@ void Translator::IMAGE_SAMPLE(const GcnInst& inst) {
|
|||
// Now we can load body components as noted in Table 8.9 Image Opcodes with Sampler
|
||||
// Since these are at most 4 dwords, we load them into a single uvec4 and place them
|
||||
// in coords field of the instruction. Then the resource tracking pass will patch the
|
||||
// IR instruction to fill in lod_clamp field. The vector can also be used
|
||||
// as coords directly as SPIR-V will ignore any extra parameters.
|
||||
const IR::Value body =
|
||||
ir.CompositeConstruct(ir.GetVectorReg(addr_reg++), ir.GetVectorReg(addr_reg++),
|
||||
ir.GetVectorReg(addr_reg++), ir.GetVectorReg(addr_reg++));
|
||||
// IR instruction to fill in lod_clamp field.
|
||||
const IR::Value body = ir.CompositeConstruct(
|
||||
ir.GetVectorReg<IR::F32>(addr_reg), ir.GetVectorReg<IR::F32>(addr_reg + 1),
|
||||
ir.GetVectorReg<IR::F32>(addr_reg + 2), ir.GetVectorReg<IR::F32>(addr_reg + 3));
|
||||
|
||||
const bool explicit_lod = flags.any(MimgModifier::Level0, MimgModifier::Lod);
|
||||
|
||||
IR::TextureInstInfo info{};
|
||||
info.is_depth.Assign(flags.test(MimgModifier::Pcf));
|
||||
info.has_bias.Assign(flags.test(MimgModifier::LodBias));
|
||||
info.has_lod_clamp.Assign(flags.test(MimgModifier::LodClamp));
|
||||
info.force_level0.Assign(flags.test(MimgModifier::Level0));
|
||||
info.explicit_lod.Assign(explicit_lod);
|
||||
|
||||
// Issue IR instruction, leaving unknown fields blank to patch later.
|
||||
const IR::Value texel = [&]() -> IR::Value {
|
||||
const IR::F32 lod = flags.test(MimgModifier::Level0) ? ir.Imm32(0.f) : IR::F32{};
|
||||
const bool explicit_lod = flags.any(MimgModifier::Level0, MimgModifier::Lod);
|
||||
if (!flags.test(MimgModifier::Pcf)) {
|
||||
if (explicit_lod) {
|
||||
return ir.ImageSampleExplicitLod(handle, body, lod, offset, {});
|
||||
return ir.ImageSampleExplicitLod(handle, body, lod, offset, info);
|
||||
} else {
|
||||
return ir.ImageSampleImplicitLod(handle, body, bias, offset, {}, {});
|
||||
return ir.ImageSampleImplicitLod(handle, body, bias, offset, {}, info);
|
||||
}
|
||||
}
|
||||
if (explicit_lod) {
|
||||
return ir.ImageSampleDrefExplicitLod(handle, body, dref, lod, offset, {});
|
||||
return ir.ImageSampleDrefExplicitLod(handle, body, dref, lod, offset, info);
|
||||
}
|
||||
return ir.ImageSampleDrefImplicitLod(handle, body, dref, bias, offset, {}, {});
|
||||
return ir.ImageSampleDrefImplicitLod(handle, body, dref, bias, offset, {}, info);
|
||||
}();
|
||||
|
||||
for (u32 i = 0; i < 4; i++) {
|
||||
|
|
|
@ -110,6 +110,8 @@ std::string NameOf(Attribute attribute) {
|
|||
return "InstanceId";
|
||||
case Attribute::FragCoord:
|
||||
return "FragCoord";
|
||||
case Attribute::IsFrontFace:
|
||||
return "IsFrontFace";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -227,14 +227,8 @@ U32 IREmitter::ReadConst(const U64& address, const U32& offset) {
|
|||
return Inst<U32>(Opcode::ReadConst, address, offset);
|
||||
}
|
||||
|
||||
template <>
|
||||
U32 IREmitter::ReadConstBuffer(const Value& handle, const U32& index, const U32& offset) {
|
||||
return Inst<U32>(Opcode::ReadConstBuffer, handle, index, offset);
|
||||
}
|
||||
|
||||
template <>
|
||||
F32 IREmitter::ReadConstBuffer(const Value& handle, const U32& index, const U32& offset) {
|
||||
return Inst<F32>(Opcode::ReadConstBufferF32, handle, index, offset);
|
||||
F32 IREmitter::ReadConstBuffer(const Value& handle, const U32& index) {
|
||||
return Inst<F32>(Opcode::ReadConstBuffer, handle, index);
|
||||
}
|
||||
|
||||
Value IREmitter::LoadBuffer(int num_dwords, const Value& handle, const Value& address,
|
||||
|
|
|
@ -68,8 +68,7 @@ public:
|
|||
void WriteShared(int bit_size, const Value& value, const U32& offset);
|
||||
|
||||
[[nodiscard]] U32 ReadConst(const U64& address, const U32& offset);
|
||||
template <typename T = U32>
|
||||
[[nodiscard]] T ReadConstBuffer(const Value& handle, const U32& index, const U32& offset);
|
||||
[[nodiscard]] F32 ReadConstBuffer(const Value& handle, const U32& index);
|
||||
|
||||
[[nodiscard]] Value LoadBuffer(int num_dwords, const Value& handle, const Value& address,
|
||||
BufferInstInfo info);
|
||||
|
|
|
@ -15,8 +15,7 @@ OPCODE(Epilogue, Void,
|
|||
|
||||
// Constant memory operations
|
||||
OPCODE(ReadConst, U32, U64, U32, )
|
||||
OPCODE(ReadConstBuffer, U32, Opaque, U32, U32 )
|
||||
OPCODE(ReadConstBufferF32, F32, Opaque, U32, U32 )
|
||||
OPCODE(ReadConstBuffer, F32, Opaque, U32, )
|
||||
|
||||
// Context getters/setters
|
||||
OPCODE(GetUserData, U32, ScalarReg, )
|
||||
|
|
|
@ -88,15 +88,15 @@ void FoldBitCast(IR::Inst& inst, IR::Opcode reverse) {
|
|||
inst.ReplaceUsesWith(arg_inst->Arg(0));
|
||||
return;
|
||||
}
|
||||
if constexpr (op == IR::Opcode::BitCastF32U32) {
|
||||
if (arg_inst->GetOpcode() == IR::Opcode::ReadConstBuffer) {
|
||||
// Replace the bitcast with a typed constant buffer read
|
||||
inst.ReplaceOpcode(IR::Opcode::ReadConstBufferF32);
|
||||
inst.SetArg(0, arg_inst->Arg(0));
|
||||
inst.SetArg(1, arg_inst->Arg(1));
|
||||
return;
|
||||
}
|
||||
}
|
||||
// if constexpr (op == IR::Opcode::BitCastF32U32) {
|
||||
// if (arg_inst->GetOpcode() == IR::Opcode::ReadConstBuffer) {
|
||||
// // Replace the bitcast with a typed constant buffer read
|
||||
// inst.ReplaceOpcode(IR::Opcode::ReadConstBufferF32);
|
||||
// inst.SetArg(0, arg_inst->Arg(0));
|
||||
// inst.SetArg(1, arg_inst->Arg(1));
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
std::optional<IR::Value> FoldCompositeExtractImpl(IR::Value inst_value, IR::Opcode insert,
|
||||
|
|
|
@ -28,7 +28,6 @@ bool IsBufferInstruction(const IR::Inst& inst) {
|
|||
case IR::Opcode::LoadBufferF32x3:
|
||||
case IR::Opcode::LoadBufferF32x4:
|
||||
case IR::Opcode::ReadConstBuffer:
|
||||
case IR::Opcode::ReadConstBufferF32:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -41,6 +40,7 @@ IR::Type BufferLoadType(const IR::Inst& inst) {
|
|||
case IR::Opcode::LoadBufferF32x2:
|
||||
case IR::Opcode::LoadBufferF32x3:
|
||||
case IR::Opcode::LoadBufferF32x4:
|
||||
case IR::Opcode::ReadConstBuffer:
|
||||
return IR::Type::F32;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
|
@ -69,8 +69,10 @@ bool IsImageInstruction(const IR::Inst& inst) {
|
|||
|
||||
class Descriptors {
|
||||
public:
|
||||
explicit Descriptors(BufferResourceList& buffer_resources_)
|
||||
: buffer_resources{buffer_resources_} {}
|
||||
explicit Descriptors(BufferResourceList& buffer_resources_, ImageResourceList& image_resources_,
|
||||
SamplerResourceList& sampler_resources_)
|
||||
: buffer_resources{buffer_resources_}, image_resources{image_resources_},
|
||||
sampler_resources{sampler_resources_} {}
|
||||
|
||||
u32 Add(const BufferResource& desc) {
|
||||
const u32 index{Add(buffer_resources, desc, [&desc](const auto& existing) {
|
||||
|
@ -84,6 +86,23 @@ public:
|
|||
return index;
|
||||
}
|
||||
|
||||
u32 Add(const ImageResource& desc) {
|
||||
const u32 index{Add(image_resources, desc, [&desc](const auto& existing) {
|
||||
return desc.sgpr_base == existing.sgpr_base &&
|
||||
desc.dword_offset == existing.dword_offset && desc.type == existing.type &&
|
||||
desc.is_storage == existing.is_storage;
|
||||
})};
|
||||
return index;
|
||||
}
|
||||
|
||||
u32 Add(const SamplerResource& desc) {
|
||||
const u32 index{Add(sampler_resources, desc, [&desc](const auto& existing) {
|
||||
return desc.sgpr_base == existing.sgpr_base &&
|
||||
desc.dword_offset == existing.dword_offset;
|
||||
})};
|
||||
return index;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Descriptors, typename Descriptor, typename Func>
|
||||
static u32 Add(Descriptors& descriptors, const Descriptor& desc, Func&& pred) {
|
||||
|
@ -96,6 +115,8 @@ private:
|
|||
}
|
||||
|
||||
BufferResourceList& buffer_resources;
|
||||
ImageResourceList& image_resources;
|
||||
SamplerResourceList& sampler_resources;
|
||||
};
|
||||
|
||||
} // Anonymous namespace
|
||||
|
@ -118,8 +139,7 @@ SharpLocation TrackSharp(const IR::Inst* inst) {
|
|||
|
||||
// Retrieve SGPR that holds sbase
|
||||
inst = addr->Arg(0).InstRecursive()->Arg(0).InstRecursive();
|
||||
ASSERT_MSG(inst->GetOpcode() == IR::Opcode::GetScalarRegister,
|
||||
"Nested resource loads not supported");
|
||||
ASSERT_MSG(inst->GetOpcode() == IR::Opcode::GetUserData, "Nested resource loads not supported");
|
||||
const IR::ScalarReg base = inst->Arg(0).ScalarReg();
|
||||
|
||||
// Return retrieved location.
|
||||
|
@ -140,7 +160,7 @@ void PatchBufferInstruction(IR::Block& block, IR::Inst& inst, Info& info,
|
|||
.stride = u32(buffer.stride),
|
||||
.num_records = u32(buffer.num_records),
|
||||
.used_types = BufferLoadType(inst),
|
||||
.is_storage = buffer.base_address % 64 != 0,
|
||||
.is_storage = /*buffer.base_address % 64 != 0*/ true,
|
||||
});
|
||||
const auto inst_info = inst.Flags<IR::BufferInstInfo>();
|
||||
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
|
||||
|
@ -151,6 +171,9 @@ void PatchBufferInstruction(IR::Block& block, IR::Inst& inst, Info& info,
|
|||
ASSERT(inst_info.nfmt == AmdGpu::NumberFormat::Float &&
|
||||
inst_info.dmft == AmdGpu::DataFormat::Format32_32_32_32);
|
||||
}
|
||||
if (inst.GetOpcode() == IR::Opcode::ReadConstBuffer) {
|
||||
return;
|
||||
}
|
||||
// Calculate buffer address.
|
||||
const u32 dword_stride = buffer.stride / sizeof(u32);
|
||||
const u32 dword_offset = inst_info.inst_offset.Value() / sizeof(u32);
|
||||
|
@ -160,19 +183,79 @@ void PatchBufferInstruction(IR::Block& block, IR::Inst& inst, Info& info,
|
|||
} else if (inst_info.index_enable) {
|
||||
const IR::U32 index{inst.Arg(1)};
|
||||
address = ir.IAdd(ir.IMul(index, ir.Imm32(dword_stride)), address);
|
||||
} else if (inst_info.offset_enable) {
|
||||
const IR::U32 offset{inst.Arg(1)};
|
||||
}
|
||||
inst.SetArg(1, address);
|
||||
}
|
||||
|
||||
void PatchImageInstruction(IR::Block& block, IR::Inst& inst, Info& info, Descriptors& descriptors) {
|
||||
IR::Inst* producer = inst.Arg(0).InstRecursive();
|
||||
ASSERT(producer->GetOpcode() == IR::Opcode::CompositeConstructU32x2);
|
||||
|
||||
// Read image sharp.
|
||||
const auto tsharp = TrackSharp(producer->Arg(0).InstRecursive());
|
||||
const auto image = info.ReadUd<AmdGpu::Image>(tsharp.sgpr_base, tsharp.dword_offset);
|
||||
const auto inst_info = inst.Flags<IR::TextureInstInfo>();
|
||||
const u32 image_binding = descriptors.Add(ImageResource{
|
||||
.sgpr_base = tsharp.sgpr_base,
|
||||
.dword_offset = tsharp.dword_offset,
|
||||
.type = image.type,
|
||||
.nfmt = static_cast<AmdGpu::NumberFormat>(image.num_format.Value()),
|
||||
.is_storage = false,
|
||||
.is_depth = bool(inst_info.is_depth),
|
||||
});
|
||||
|
||||
// Read sampler sharp.
|
||||
const auto ssharp = TrackSharp(producer->Arg(1).InstRecursive());
|
||||
const u32 sampler_binding = descriptors.Add(SamplerResource{
|
||||
.sgpr_base = ssharp.sgpr_base,
|
||||
.dword_offset = ssharp.dword_offset,
|
||||
});
|
||||
|
||||
// Patch image handle
|
||||
const u32 handle = image_binding | (sampler_binding << 16);
|
||||
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
|
||||
inst.SetArg(0, ir.Imm32(handle));
|
||||
|
||||
// Now that we know the image type, adjust texture coordinate vector.
|
||||
const IR::Inst* body = inst.Arg(1).InstRecursive();
|
||||
const auto [coords, arg] = [&] -> std::pair<IR::Value, IR::Value> {
|
||||
switch (image.type) {
|
||||
case AmdGpu::ImageType::Color1D:
|
||||
return {body->Arg(0), body->Arg(1)};
|
||||
case AmdGpu::ImageType::Color1DArray:
|
||||
case AmdGpu::ImageType::Color2D:
|
||||
return {ir.CompositeConstruct(body->Arg(0), body->Arg(1)), body->Arg(2)};
|
||||
case AmdGpu::ImageType::Color2DArray:
|
||||
case AmdGpu::ImageType::Color3D:
|
||||
case AmdGpu::ImageType::Cube:
|
||||
return {ir.CompositeConstruct(body->Arg(0), body->Arg(1), body->Arg(2)), body->Arg(3)};
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}();
|
||||
inst.SetArg(1, coords);
|
||||
|
||||
if (inst_info.has_lod_clamp) {
|
||||
// Final argument contains lod_clamp
|
||||
const u32 arg_pos = inst_info.is_depth ? 5 : 4;
|
||||
inst.SetArg(arg_pos, arg);
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceTrackingPass(IR::Program& program) {
|
||||
auto& info = program.info;
|
||||
Descriptors descriptors{info.buffers};
|
||||
Descriptors descriptors{info.buffers, info.images, info.samplers};
|
||||
for (IR::Block* const block : program.post_order_blocks) {
|
||||
for (IR::Inst& inst : block->Instructions()) {
|
||||
if (IsBufferInstruction(inst)) {
|
||||
PatchBufferInstruction(*block, inst, info, descriptors);
|
||||
continue;
|
||||
}
|
||||
if (IsImageInstruction(inst)) {
|
||||
PatchImageInstruction(*block, inst, info, descriptors);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,13 +33,11 @@ union Mode {
|
|||
|
||||
union TextureInstInfo {
|
||||
u32 raw;
|
||||
BitField<0, 16, u32> descriptor_index;
|
||||
BitField<19, 1, u32> is_depth;
|
||||
BitField<20, 1, u32> has_bias;
|
||||
BitField<21, 1, u32> has_lod_clamp;
|
||||
BitField<22, 1, u32> relaxed_precision;
|
||||
BitField<23, 2, u32> gather_component;
|
||||
BitField<25, 2, u32> num_derivatives;
|
||||
BitField<0, 1, u32> is_depth;
|
||||
BitField<1, 1, u32> has_bias;
|
||||
BitField<2, 1, u32> has_lod_clamp;
|
||||
BitField<3, 1, u32> force_level0;
|
||||
BitField<4, 1, u32> explicit_lod;
|
||||
};
|
||||
|
||||
union BufferInstInfo {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <fstream>
|
||||
#include "shader_recompiler/frontend/control_flow_graph.h"
|
||||
#include "shader_recompiler/frontend/decode.h"
|
||||
#include "shader_recompiler/frontend/structured_control_flow.h"
|
||||
|
@ -38,11 +37,6 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
|
|||
Gcn::GcnCodeSlice slice(token.data(), token.data() + token.size());
|
||||
Gcn::GcnDecodeContext decoder;
|
||||
|
||||
static int counter = 0;
|
||||
std::ofstream file(fmt::format("shader{}.bin", counter++), std::ios::out | std::ios::binary);
|
||||
file.write((const char*)token.data(), token.size_bytes());
|
||||
file.close();
|
||||
|
||||
// Decode and save instructions
|
||||
IR::Program program;
|
||||
program.ins_list.reserve(token.size());
|
||||
|
@ -71,7 +65,6 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
|
|||
for (const auto& block : program.blocks) {
|
||||
fmt::print("{}\n", IR::DumpBlock(*block));
|
||||
}
|
||||
std::fflush(stdout);
|
||||
|
||||
return program;
|
||||
}
|
||||
|
|
|
@ -9,25 +9,6 @@
|
|||
|
||||
namespace Shader {
|
||||
|
||||
struct BinaryInfo {
|
||||
u8 signature[7];
|
||||
u8 version;
|
||||
u32 pssl_or_cg : 1;
|
||||
u32 cached : 1;
|
||||
u32 type : 4;
|
||||
u32 source_type : 2;
|
||||
u32 length : 24;
|
||||
u8 chunk_usage_base_offset_in_dw;
|
||||
u8 num_input_usage_slots;
|
||||
u8 is_srt : 1;
|
||||
u8 is_srt_used_info_valid : 1;
|
||||
u8 is_extended_usage_info : 1;
|
||||
u8 reserved2 : 5;
|
||||
u8 reserved3;
|
||||
u64 shader_hash;
|
||||
u32 crc32;
|
||||
};
|
||||
|
||||
[[nodiscard]] IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool,
|
||||
ObjectPool<IR::Block>& block_pool,
|
||||
std::span<const u32> code, const Info&& info);
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "shader_recompiler/ir/attribute.h"
|
||||
#include "shader_recompiler/ir/reg.h"
|
||||
#include "shader_recompiler/ir/type.h"
|
||||
#include "video_core/amdgpu/pixel_format.h"
|
||||
#include "video_core/amdgpu/resource.h"
|
||||
|
||||
namespace Shader {
|
||||
|
||||
|
@ -53,6 +53,22 @@ struct BufferResource {
|
|||
};
|
||||
using BufferResourceList = boost::container::static_vector<BufferResource, 8>;
|
||||
|
||||
struct ImageResource {
|
||||
u32 sgpr_base;
|
||||
u32 dword_offset;
|
||||
AmdGpu::ImageType type;
|
||||
AmdGpu::NumberFormat nfmt;
|
||||
bool is_storage;
|
||||
bool is_depth;
|
||||
};
|
||||
using ImageResourceList = boost::container::static_vector<ImageResource, 8>;
|
||||
|
||||
struct SamplerResource {
|
||||
u32 sgpr_base;
|
||||
u32 dword_offset;
|
||||
};
|
||||
using SamplerResourceList = boost::container::static_vector<SamplerResource, 8>;
|
||||
|
||||
struct Info {
|
||||
struct VsInput {
|
||||
AmdGpu::NumberFormat fmt;
|
||||
|
@ -101,6 +117,9 @@ struct Info {
|
|||
AttributeFlags stores{};
|
||||
|
||||
BufferResourceList buffers;
|
||||
ImageResourceList images;
|
||||
SamplerResourceList samplers;
|
||||
|
||||
std::span<const u32> user_data;
|
||||
Stage stage;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue