diff options
Diffstat (limited to '')
5 files changed, 97 insertions, 16 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp index df53e58a8..74c42233d 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/emit_context.cpp @@ -135,6 +135,45 @@ Id DefineOutput(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin = return DefineVariable(ctx, type, builtin, spv::StorageClass::Output); } +void DefineGenericOutput(EmitContext& ctx, size_t index) { + static constexpr std::string_view swizzle{"xyzw"}; + const size_t base_attr_index{static_cast<size_t>(IR::Attribute::Generic0X) + index * 4}; + u32 element{0}; + while (element < 4) { + const u32 remainder{4 - element}; + const TransformFeedbackVarying* xfb_varying{}; + if (!ctx.profile.xfb_varyings.empty()) { + xfb_varying = &ctx.profile.xfb_varyings[base_attr_index + element]; + xfb_varying = xfb_varying && xfb_varying->components > 0 ? xfb_varying : nullptr; + } + const u32 num_components{xfb_varying ? xfb_varying->components : remainder}; + + const Id id{DefineOutput(ctx, ctx.F32[num_components])}; + ctx.Decorate(id, spv::Decoration::Location, static_cast<u32>(index)); + if (element > 0) { + ctx.Decorate(id, spv::Decoration::Component, element); + } + if (xfb_varying) { + ctx.Decorate(id, spv::Decoration::XfbBuffer, xfb_varying->buffer); + ctx.Decorate(id, spv::Decoration::XfbStride, xfb_varying->stride); + ctx.Decorate(id, spv::Decoration::Offset, xfb_varying->offset); + } + if (num_components < 4 || element > 0) { + ctx.Name(id, fmt::format("out_attr{}", index)); + } else { + const std::string_view subswizzle{swizzle.substr(element, num_components)}; + ctx.Name(id, fmt::format("out_attr{}_{}", index, subswizzle)); + } + const GenericElementInfo info{ + .id = id, + .first_element = element, + .num_components = num_components, + }; + std::fill_n(ctx.output_generics[index].begin(), num_components, info); + element += num_components; + } +} + Id GetAttributeType(EmitContext& ctx, AttributeType type) { switch (type) { case AttributeType::Float: @@ -663,12 +702,15 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) { OpReturn(); ++label_index; } - for (size_t i = 0; i < info.stores_generics.size(); i++) { + for (size_t i = 0; i < info.stores_generics.size(); ++i) { if (!info.stores_generics[i]) { continue; } + if (output_generics[i][0].num_components != 4) { + throw NotImplementedException("Physical stores and transform feedbacks"); + } AddLabel(labels[label_index]); - const Id generic_id{output_generics.at(i)}; + const Id generic_id{output_generics[i][0].id}; const Id pointer{OpAccessChain(output_f32, generic_id, masked_index)}; OpStore(pointer, store_value); OpReturn(); @@ -1015,11 +1057,9 @@ void EmitContext::DefineOutputs(const Info& info) { } viewport_index = DefineOutput(*this, U32[1], spv::BuiltIn::ViewportIndex); } - for (size_t i = 0; i < info.stores_generics.size(); ++i) { - if (info.stores_generics[i]) { - output_generics[i] = DefineOutput(*this, F32[4]); - Decorate(output_generics[i], spv::Decoration::Location, static_cast<u32>(i)); - Name(output_generics[i], fmt::format("out_attr{}", i)); + for (size_t index = 0; index < info.stores_generics.size(); ++index) { + if (info.stores_generics[index]) { + DefineGenericOutput(*this, index); } } if (stage == Stage::Fragment) { diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/emit_context.h index cade1fa0d..b27e5540c 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.h +++ b/src/shader_recompiler/backend/spirv/emit_context.h @@ -79,6 +79,12 @@ struct StorageDefinitions { Id U32x4{}; }; +struct GenericElementInfo { + Id id{}; + u32 first_element{}; + u32 num_components{}; +}; + class EmitContext final : public Sirit::Module { public: explicit EmitContext(const Profile& profile, IR::Program& program, u32& binding); @@ -189,7 +195,7 @@ public: Id output_point_size{}; Id output_position{}; - std::array<Id, 32> output_generics{}; + std::array<std::array<GenericElementInfo, 4>, 32> output_generics{}; std::array<Id, 8> frag_color{}; Id frag_depth{}; diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 7ad00c434..444ba276f 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp @@ -288,6 +288,9 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct if (info.uses_typeless_image_writes) { ctx.AddCapability(spv::Capability::StorageImageWriteWithoutFormat); } + if (!ctx.profile.xfb_varyings.empty()) { + ctx.AddCapability(spv::Capability::TransformFeedback); + } // TODO: Track this usage ctx.AddCapability(spv::Capability::ImageGatherExtended); ctx.AddCapability(spv::Capability::ImageQuery); diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp index a91b4c212..f9c151a5c 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp @@ -40,11 +40,17 @@ Id AttrPointer(EmitContext& ctx, Id pointer_type, Id vertex, Id base, Args&&... } std::optional<Id> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) { - const u32 element{static_cast<u32>(attr) % 4}; - const auto element_id{[&] { return ctx.Constant(ctx.U32[1], element); }}; if (IR::IsGeneric(attr)) { const u32 index{IR::GenericAttributeIndex(attr)}; - return ctx.OpAccessChain(ctx.output_f32, ctx.output_generics.at(index), element_id()); + const u32 element{IR::GenericAttributeElement(attr)}; + const GenericElementInfo& info{ctx.output_generics.at(index).at(element)}; + if (info.num_components == 1) { + return info.id; + } else { + const u32 index_element{element - info.first_element}; + const Id index_id{ctx.Constant(ctx.U32[1], index_element)}; + return ctx.OpAccessChain(ctx.output_f32, info.id, index_id); + } } switch (attr) { case IR::Attribute::PointSize: @@ -52,8 +58,11 @@ std::optional<Id> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) { case IR::Attribute::PositionX: case IR::Attribute::PositionY: case IR::Attribute::PositionZ: - case IR::Attribute::PositionW: - return ctx.OpAccessChain(ctx.output_f32, ctx.output_position, element_id()); + case IR::Attribute::PositionW: { + const u32 element{static_cast<u32>(attr) % 4}; + const Id element_id{ctx.Constant(ctx.U32[1], element)}; + return ctx.OpAccessChain(ctx.output_f32, ctx.output_position, element_id); + } case IR::Attribute::ClipDistance0: case IR::Attribute::ClipDistance1: case IR::Attribute::ClipDistance2: diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp index fee740c08..7af29e4dd 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp @@ -22,6 +22,21 @@ void SetFixedPipelinePointSize(EmitContext& ctx) { ctx.OpStore(ctx.output_point_size, ctx.Constant(ctx.F32[1], point_size)); } } + +Id DefaultVarying(EmitContext& ctx, u32 num_components, u32 element, Id zero, Id one, + Id default_vector) { + switch (num_components) { + case 1: + return element == 3 ? one : zero; + case 2: + return ctx.ConstantComposite(ctx.F32[2], zero, element + 1 == 3 ? one : zero); + case 3: + return ctx.ConstantComposite(ctx.F32[3], zero, zero, element + 2 == 3 ? one : zero); + case 4: + return default_vector; + } + throw InvalidArgument("Bad element"); +} } // Anonymous namespace void EmitPrologue(EmitContext& ctx) { @@ -30,9 +45,17 @@ void EmitPrologue(EmitContext& ctx) { const Id one{ctx.Constant(ctx.F32[1], 1.0f)}; const Id default_vector{ctx.ConstantComposite(ctx.F32[4], zero, zero, zero, one)}; ctx.OpStore(ctx.output_position, default_vector); - for (const Id generic_id : ctx.output_generics) { - if (Sirit::ValidId(generic_id)) { - ctx.OpStore(generic_id, default_vector); + for (const auto& info : ctx.output_generics) { + if (info[0].num_components == 0) { + continue; + } + u32 element{0}; + while (element < 4) { + const auto& element_info{info[element]}; + const u32 num{element_info.num_components}; + const Id value{DefaultVarying(ctx, num, element, zero, one, default_vector)}; + ctx.OpStore(element_info.id, value); + element += num; } } } |