mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-04 16:32:39 +00:00
test: make local/tcs use attr arrays
This commit is contained in:
parent
917e02f997
commit
bcc95bfbbc
@ -47,24 +47,27 @@ Id VsOutputAttrPointer(EmitContext& ctx, VsOutput output) {
|
||||
}
|
||||
}
|
||||
|
||||
Id OutputAttrPointer(EmitContext& ctx, IR::Attribute attr, Id array_index, u32 element) {
|
||||
// TODO refactor
|
||||
Id SpecialOutputAttrPointer(EmitContext& ctx, IR::Attribute attr, u32 element) {
|
||||
const u32 attr_index{u32(attr) - u32(IR::Attribute::Param0)};
|
||||
if (ctx.stage == Stage::Local && ctx.runtime_info.ls_info.links_with_tcs) {
|
||||
// TODO refactor all this
|
||||
const auto component_ptr = ctx.TypePointer(spv::StorageClass::Output, ctx.F32[1]);
|
||||
return ctx.OpAccessChain(component_ptr, ctx.output_attr_array, ctx.ConstU32(attr_index),
|
||||
ctx.ConstU32(element));
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
Id OutputAttrPointer(EmitContext& ctx, IR::Attribute attr, u32 element) {
|
||||
if (IR::IsParam(attr)) {
|
||||
const u32 index{u32(attr) - u32(IR::Attribute::Param0)};
|
||||
const auto& info{ctx.output_params.at(index)};
|
||||
ASSERT(info.num_components > 0);
|
||||
Id base = info.id;
|
||||
boost::container::small_vector<Id, 2> indices;
|
||||
if (ctx.l_stage == LogicalStage::TessellationControl) {
|
||||
indices.push_back(array_index);
|
||||
}
|
||||
if (info.num_components > 1) {
|
||||
indices.push_back(ctx.ConstU32(element));
|
||||
}
|
||||
|
||||
if (indices.empty()) {
|
||||
if (info.num_components == 1) {
|
||||
return info.id;
|
||||
} else {
|
||||
return ctx.OpAccessChain(info.pointer_type, info.id, indices);
|
||||
return ctx.OpAccessChain(info.pointer_type, info.id, ctx.ConstU32(element));
|
||||
}
|
||||
}
|
||||
if (IR::IsMrt(attr)) {
|
||||
@ -93,10 +96,6 @@ Id OutputAttrPointer(EmitContext& ctx, IR::Attribute attr, Id array_index, u32 e
|
||||
}
|
||||
}
|
||||
|
||||
Id OutputAttrPointer(EmitContext& ctx, IR::Attribute attr, u32 element) {
|
||||
return OutputAttrPointer(ctx, attr, {}, element);
|
||||
}
|
||||
|
||||
std::pair<Id, bool> OutputAttrComponentType(EmitContext& ctx, IR::Attribute attr) {
|
||||
if (IR::IsParam(attr)) {
|
||||
const u32 index{u32(attr) - u32(IR::Attribute::Param0)};
|
||||
@ -233,6 +232,15 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, u32 comp, Id index) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
if (ctx.info.l_stage == LogicalStage::TessellationControl) {
|
||||
ASSERT(IR::IsParam(attr));
|
||||
const u32 attr_index{u32(attr) - u32(IR::Attribute::Param0)};
|
||||
const auto attr_comp_ptr = ctx.TypePointer(spv::StorageClass::Input, ctx.F32[1]);
|
||||
return ctx.OpLoad(ctx.F32[1],
|
||||
ctx.OpAccessChain(attr_comp_ptr, ctx.input_attr_array, index,
|
||||
ctx.ConstU32(attr_index), ctx.ConstU32(comp)));
|
||||
}
|
||||
|
||||
if (IR::IsParam(attr)) {
|
||||
const u32 index{u32(attr) - u32(IR::Attribute::Param0)};
|
||||
const auto& param{ctx.input_params.at(index)};
|
||||
@ -333,12 +341,13 @@ void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value, u32 elemen
|
||||
return;
|
||||
}
|
||||
|
||||
Id pointer;
|
||||
if (ctx.l_stage == LogicalStage::TessellationControl) {
|
||||
pointer = OutputAttrPointer(ctx, attr, ctx.OpLoad(ctx.U32[1], ctx.invocation_id), element);
|
||||
} else {
|
||||
pointer = OutputAttrPointer(ctx, attr, element);
|
||||
// TODO refactor
|
||||
if (ctx.stage == Stage::Local && ctx.runtime_info.ls_info.links_with_tcs) {
|
||||
ctx.OpStore(SpecialOutputAttrPointer(ctx, attr, element), value);
|
||||
return;
|
||||
}
|
||||
|
||||
const Id pointer{OutputAttrPointer(ctx, attr, element)};
|
||||
const auto component_type{OutputAttrComponentType(ctx, attr)};
|
||||
if (component_type.second) {
|
||||
ctx.OpStore(pointer, ctx.OpBitcast(component_type.first, value));
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
||||
#include "shader_recompiler/frontend/fetch_shader.h"
|
||||
#include "shader_recompiler/ir/passes/srt.h"
|
||||
#include "shader_recompiler/runtime_info.h"
|
||||
#include "video_core/amdgpu/types.h"
|
||||
|
||||
#include <boost/container/static_vector.hpp>
|
||||
@ -393,6 +394,7 @@ void EmitContext::DefineInputs() {
|
||||
DefineVariable(U32[1], spv::BuiltIn::PatchVertices, spv::StorageClass::Input);
|
||||
primitive_id = DefineVariable(U32[1], spv::BuiltIn::PrimitiveId, spv::StorageClass::Input);
|
||||
|
||||
#if 0
|
||||
for (u32 i = 0; i < IR::NumParams; i++) {
|
||||
const IR::Attribute param{IR::Attribute::Param0 + i};
|
||||
if (!info.loads.GetAny(param)) {
|
||||
@ -405,6 +407,14 @@ void EmitContext::DefineInputs() {
|
||||
Name(id, fmt::format("in_attr{}", i));
|
||||
input_params[i] = {id, input_f32, F32[1], 4};
|
||||
}
|
||||
#else
|
||||
const u32 num_attrs = runtime_info.hs_info.ls_stride >> 4;
|
||||
const Id per_vertex_type{TypeArray(F32[4], ConstU32(num_attrs))};
|
||||
// The input vertex count isn't statically known, so make length 32 (what glslang does)
|
||||
const Id patch_array_type{TypeArray(per_vertex_type, ConstU32(32u))};
|
||||
input_attr_array = DefineInput(patch_array_type, 0);
|
||||
Name(input_attr_array, "in_attrs");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case LogicalStage::TessellationEval: {
|
||||
@ -458,16 +468,23 @@ void EmitContext::DefineOutputs() {
|
||||
cull_distances =
|
||||
DefineVariable(type, spv::BuiltIn::CullDistance, spv::StorageClass::Output);
|
||||
}
|
||||
for (u32 i = 0; i < IR::NumParams; i++) {
|
||||
const IR::Attribute param{IR::Attribute::Param0 + i};
|
||||
if (!info.stores.GetAny(param)) {
|
||||
continue;
|
||||
if (stage == Shader::Stage::Local && runtime_info.ls_info.links_with_tcs) {
|
||||
const u32 num_attrs = runtime_info.ls_info.ls_stride >> 4;
|
||||
const Id type{TypeArray(F32[4], ConstU32(num_attrs))};
|
||||
output_attr_array = DefineOutput(type, 0);
|
||||
Name(output_attr_array, "out_attrs");
|
||||
} else {
|
||||
for (u32 i = 0; i < IR::NumParams; i++) {
|
||||
const IR::Attribute param{IR::Attribute::Param0 + i};
|
||||
if (!info.stores.GetAny(param)) {
|
||||
continue;
|
||||
}
|
||||
const u32 num_components = info.stores.NumComponents(param);
|
||||
const Id id{DefineOutput(F32[num_components], i)};
|
||||
Name(id, fmt::format("out_attr{}", i));
|
||||
output_params[i] =
|
||||
GetAttributeInfo(AmdGpu::NumberFormat::Float, id, num_components, true);
|
||||
}
|
||||
const u32 num_components = info.stores.NumComponents(param);
|
||||
const Id id{DefineOutput(F32[num_components], i)};
|
||||
Name(id, fmt::format("out_attr{}", i));
|
||||
output_params[i] =
|
||||
GetAttributeInfo(AmdGpu::NumberFormat::Float, id, num_components, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -264,6 +264,8 @@ public:
|
||||
bool is_loaded{};
|
||||
s32 buffer_handle{-1};
|
||||
};
|
||||
Id input_attr_array;
|
||||
Id output_attr_array;
|
||||
std::array<SpirvAttribute, IR::NumParams> input_params{};
|
||||
std::array<SpirvAttribute, IR::NumParams> output_params{};
|
||||
std::array<SpirvAttribute, IR::NumRenderTargets> frag_outputs{};
|
||||
|
@ -255,11 +255,11 @@ struct Info {
|
||||
}
|
||||
|
||||
// TODO probably not needed
|
||||
bool FoundTessConstantsSharp() {
|
||||
bool FoundTessConstantsSharp() const {
|
||||
return tess_consts_dword_offset >= 0;
|
||||
}
|
||||
|
||||
void ReadTessConstantBuffer(TessellationDataConstantBuffer& tess_constants) {
|
||||
void ReadTessConstantBuffer(TessellationDataConstantBuffer& tess_constants) const {
|
||||
ASSERT(FoundTessConstantsSharp());
|
||||
auto buf = ReadUdReg<AmdGpu::Buffer>(static_cast<u32>(tess_consts_ptr_base),
|
||||
static_cast<u32>(tess_consts_dword_offset));
|
||||
|
@ -38,6 +38,13 @@ enum class LogicalStage : u32 {
|
||||
return static_cast<Stage>(index);
|
||||
}
|
||||
|
||||
struct LocalRuntimeInfo {
|
||||
u32 ls_stride;
|
||||
bool links_with_tcs;
|
||||
|
||||
auto operator<=>(const LocalRuntimeInfo&) const noexcept = default;
|
||||
};
|
||||
|
||||
struct ExportRuntimeInfo {
|
||||
u32 vertex_data_size;
|
||||
|
||||
@ -208,6 +215,7 @@ struct RuntimeInfo {
|
||||
AmdGpu::FpDenormMode fp_denorm_mode32;
|
||||
AmdGpu::FpRoundMode fp_round_mode32;
|
||||
union {
|
||||
LocalRuntimeInfo ls_info;
|
||||
ExportRuntimeInfo es_info;
|
||||
VertexRuntimeInfo vs_info;
|
||||
HullRuntimeInfo hs_info;
|
||||
@ -235,6 +243,8 @@ struct RuntimeInfo {
|
||||
return gs_info == other.gs_info;
|
||||
case Stage::Hull:
|
||||
return hs_info == other.hs_info;
|
||||
case Stage::Local:
|
||||
return ls_info == other.ls_info;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
@ -346,15 +346,33 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
||||
|
||||
GraphicsPipeline::~GraphicsPipeline() = default;
|
||||
|
||||
boost::container::small_vector<const Shader::Info*, MaxShaderStages>
|
||||
GraphicsPipeline::GetCompilationOrder() const {
|
||||
bool uses_tessellation = stages[static_cast<size_t>(Shader::LogicalStage::TessellationControl)];
|
||||
|
||||
boost::container::small_vector<const Shader::Info*, MaxShaderStages> ordered_stages;
|
||||
for (auto s = 0; s < MaxShaderStages; s++) {
|
||||
if (uses_tessellation &&
|
||||
static_cast<Shader::LogicalStage>(s) == Shader::LogicalStage::Vertex) {
|
||||
continue;
|
||||
}
|
||||
if (stages[s]) {
|
||||
ordered_stages.push_back(stages[s]);
|
||||
}
|
||||
}
|
||||
if (uses_tessellation) {
|
||||
ordered_stages.push_back(stages[static_cast<size_t>(Shader::LogicalStage::Vertex)]);
|
||||
}
|
||||
// TODO handle geometry + tess
|
||||
return ordered_stages;
|
||||
}
|
||||
|
||||
void GraphicsPipeline::BuildDescSetLayout() {
|
||||
boost::container::small_vector<vk::DescriptorSetLayoutBinding, 32> bindings;
|
||||
u32 binding{};
|
||||
|
||||
for (const auto* stage : stages) {
|
||||
if (!stage) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto* stage : GetCompilationOrder()) {
|
||||
ASSERT(stage);
|
||||
if (stage->has_readconst) {
|
||||
bindings.push_back({
|
||||
.binding = binding++,
|
||||
|
@ -101,6 +101,9 @@ public:
|
||||
|
||||
private:
|
||||
void BuildDescSetLayout();
|
||||
// Temp, find better way
|
||||
boost::container::small_vector<const Shader::Info*, MaxShaderStages> GetCompilationOrder()
|
||||
const;
|
||||
|
||||
private:
|
||||
GraphicsPipelineKey key;
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "common/path_util.h"
|
||||
#include "core/debug_state.h"
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||
#include "shader_recompiler/frontend/tessellation.h"
|
||||
#include "shader_recompiler/info.h"
|
||||
#include "shader_recompiler/recompiler.h"
|
||||
#include "shader_recompiler/runtime_info.h"
|
||||
@ -93,6 +94,15 @@ Shader::RuntimeInfo PipelineCache::BuildRuntimeInfo(Stage stage, LogicalStage l_
|
||||
switch (stage) {
|
||||
case Stage::Local: {
|
||||
BuildCommon(regs.ls_program);
|
||||
if (regs.stage_enable.IsStageEnabled(static_cast<u32>(Stage::Hull))) {
|
||||
info.ls_info.links_with_tcs = true;
|
||||
Shader::TessellationDataConstantBuffer tess_constants;
|
||||
const auto* pgm = regs.ProgramForStage(static_cast<u32>(Stage::Hull));
|
||||
const auto params = Liverpool::GetParams(*pgm);
|
||||
const auto& hull_info = program_cache.at(params.hash)->info;
|
||||
hull_info.ReadTessConstantBuffer(tess_constants);
|
||||
info.ls_info.ls_stride = tess_constants.m_lsStride;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Stage::Hull: {
|
||||
@ -396,15 +406,15 @@ bool PipelineCache::RefreshGraphicsKey() {
|
||||
if (!instance.IsTessellationSupported()) {
|
||||
break;
|
||||
}
|
||||
if (!TryBindStage(Stage::Local, LogicalStage::Vertex)) {
|
||||
return false;
|
||||
}
|
||||
if (!TryBindStage(Stage::Hull, LogicalStage::TessellationControl)) {
|
||||
return false;
|
||||
}
|
||||
if (!TryBindStage(Stage::Vertex, LogicalStage::TessellationEval)) {
|
||||
return false;
|
||||
}
|
||||
if (!TryBindStage(Stage::Local, LogicalStage::Vertex)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
Loading…
Reference in New Issue
Block a user