test: make local/tcs use attr arrays

This commit is contained in:
Frodo Baggins 2024-11-24 11:46:36 -08:00
parent 917e02f997
commit bcc95bfbbc
8 changed files with 109 additions and 40 deletions

View File

@ -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));

View File

@ -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;
}

View File

@ -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{};

View File

@ -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));

View File

@ -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;
}

View File

@ -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++,

View File

@ -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;

View File

@ -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: {