diff options
| author | 2021-03-27 04:59:58 -0300 | |
|---|---|---|
| committer | 2021-07-22 21:51:24 -0400 | |
| commit | dbd882ddeb1a1a9233c0085d0b8ccb022db385b2 (patch) | |
| tree | 5a8456364cc41a0a53acf93e22e3f9ce855bd413 /src | |
| parent | spirv: Remove dependencies on Environment when generating SPIR-V (diff) | |
| download | yuzu-dbd882ddeb1a1a9233c0085d0b8ccb022db385b2.tar.gz yuzu-dbd882ddeb1a1a9233c0085d0b8ccb022db385b2.tar.xz yuzu-dbd882ddeb1a1a9233c0085d0b8ccb022db385b2.zip | |
shader: Better interpolation and disabled attributes support
Diffstat (limited to 'src')
9 files changed, 101 insertions, 25 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp index 4d5dabcbf..a8ca33c1d 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/emit_context.cpp | |||
| @@ -76,6 +76,8 @@ Id GetAttributeType(EmitContext& ctx, AttributeType type) { | |||
| 76 | return ctx.TypeVector(ctx.TypeInt(32, true), 4); | 76 | return ctx.TypeVector(ctx.TypeInt(32, true), 4); |
| 77 | case AttributeType::UnsignedInt: | 77 | case AttributeType::UnsignedInt: |
| 78 | return ctx.U32[4]; | 78 | return ctx.U32[4]; |
| 79 | case AttributeType::Disabled: | ||
| 80 | break; | ||
| 79 | } | 81 | } |
| 80 | throw InvalidArgument("Invalid attribute type {}", type); | 82 | throw InvalidArgument("Invalid attribute type {}", type); |
| 81 | } | 83 | } |
| @@ -305,15 +307,36 @@ void EmitContext::DefineInputs(const Info& info) { | |||
| 305 | if (info.loads_front_face) { | 307 | if (info.loads_front_face) { |
| 306 | front_face = DefineInput(*this, U1, spv::BuiltIn::FrontFacing); | 308 | front_face = DefineInput(*this, U1, spv::BuiltIn::FrontFacing); |
| 307 | } | 309 | } |
| 308 | for (size_t index = 0; index < info.loads_generics.size(); ++index) { | 310 | for (size_t index = 0; index < info.input_generics.size(); ++index) { |
| 309 | if (!info.loads_generics[index]) { | 311 | const InputVarying generic{info.input_generics[index]}; |
| 312 | if (!generic.used) { | ||
| 310 | continue; | 313 | continue; |
| 311 | } | 314 | } |
| 312 | const Id type{GetAttributeType(*this, profile.generic_input_types[index])}; | 315 | const AttributeType input_type{profile.generic_input_types[index]}; |
| 316 | if (input_type == AttributeType::Disabled) { | ||
| 317 | continue; | ||
| 318 | } | ||
| 319 | const Id type{GetAttributeType(*this, input_type)}; | ||
| 313 | const Id id{DefineInput(*this, type)}; | 320 | const Id id{DefineInput(*this, type)}; |
| 314 | Decorate(id, spv::Decoration::Location, static_cast<u32>(index)); | 321 | Decorate(id, spv::Decoration::Location, static_cast<u32>(index)); |
| 315 | Name(id, fmt::format("in_attr{}", index)); | 322 | Name(id, fmt::format("in_attr{}", index)); |
| 316 | input_generics[index] = id; | 323 | input_generics[index] = id; |
| 324 | |||
| 325 | if (stage != Stage::Fragment) { | ||
| 326 | continue; | ||
| 327 | } | ||
| 328 | switch (generic.interpolation) { | ||
| 329 | case Interpolation::Smooth: | ||
| 330 | // Default | ||
| 331 | // Decorate(id, spv::Decoration::Smooth); | ||
| 332 | break; | ||
| 333 | case Interpolation::NoPerspective: | ||
| 334 | Decorate(id, spv::Decoration::NoPerspective); | ||
| 335 | break; | ||
| 336 | case Interpolation::Flat: | ||
| 337 | Decorate(id, spv::Decoration::Flat); | ||
| 338 | break; | ||
| 339 | } | ||
| 317 | } | 340 | } |
| 318 | } | 341 | } |
| 319 | 342 | ||
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 6fa16eb80..4cbc2aec1 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 | |||
| @@ -10,16 +10,23 @@ | |||
| 10 | 10 | ||
| 11 | namespace Shader::Backend::SPIRV { | 11 | namespace Shader::Backend::SPIRV { |
| 12 | namespace { | 12 | namespace { |
| 13 | std::tuple<Id, Id, bool> AttrTypes(EmitContext& ctx, u32 index) { | 13 | struct AttrInfo { |
| 14 | const bool is_first_reader{ctx.stage == Stage::VertexB}; | 14 | Id pointer; |
| 15 | Id id; | ||
| 16 | bool needs_cast; | ||
| 17 | }; | ||
| 18 | |||
| 19 | std::optional<AttrInfo> AttrTypes(EmitContext& ctx, u32 index) { | ||
| 15 | const AttributeType type{ctx.profile.generic_input_types.at(index)}; | 20 | const AttributeType type{ctx.profile.generic_input_types.at(index)}; |
| 16 | switch (type) { | 21 | switch (type) { |
| 17 | case AttributeType::Float: | 22 | case AttributeType::Float: |
| 18 | return {ctx.input_f32, ctx.F32[1], false}; | 23 | return AttrInfo{ctx.input_f32, ctx.F32[1], false}; |
| 19 | case AttributeType::UnsignedInt: | 24 | case AttributeType::UnsignedInt: |
| 20 | return {ctx.input_u32, ctx.U32[1], true}; | 25 | return AttrInfo{ctx.input_u32, ctx.U32[1], true}; |
| 21 | case AttributeType::SignedInt: | 26 | case AttributeType::SignedInt: |
| 22 | return {ctx.input_s32, ctx.TypeInt(32, true), true}; | 27 | return AttrInfo{ctx.input_s32, ctx.TypeInt(32, true), true}; |
| 28 | case AttributeType::Disabled: | ||
| 29 | return std::nullopt; | ||
| 23 | } | 30 | } |
| 24 | throw InvalidArgument("Invalid attribute type {}", type); | 31 | throw InvalidArgument("Invalid attribute type {}", type); |
| 25 | } | 32 | } |
| @@ -129,11 +136,15 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr) { | |||
| 129 | const auto element_id{[&] { return ctx.Constant(ctx.U32[1], element); }}; | 136 | const auto element_id{[&] { return ctx.Constant(ctx.U32[1], element); }}; |
| 130 | if (IR::IsGeneric(attr)) { | 137 | if (IR::IsGeneric(attr)) { |
| 131 | const u32 index{IR::GenericAttributeIndex(attr)}; | 138 | const u32 index{IR::GenericAttributeIndex(attr)}; |
| 132 | const auto [pointer_type, type, needs_cast]{AttrTypes(ctx, index)}; | 139 | const std::optional<AttrInfo> type{AttrTypes(ctx, index)}; |
| 140 | if (!type) { | ||
| 141 | // Attribute is disabled | ||
| 142 | return ctx.Constant(ctx.F32[1], 0.0f); | ||
| 143 | } | ||
| 133 | const Id generic_id{ctx.input_generics.at(index)}; | 144 | const Id generic_id{ctx.input_generics.at(index)}; |
| 134 | const Id pointer{ctx.OpAccessChain(pointer_type, generic_id, element_id())}; | 145 | const Id pointer{ctx.OpAccessChain(type->pointer, generic_id, element_id())}; |
| 135 | const Id value{ctx.OpLoad(type, pointer)}; | 146 | const Id value{ctx.OpLoad(type->id, pointer)}; |
| 136 | return needs_cast ? ctx.OpBitcast(ctx.F32[1], value) : value; | 147 | return type->needs_cast ? ctx.OpBitcast(ctx.F32[1], value) : value; |
| 137 | } | 148 | } |
| 138 | switch (attr) { | 149 | switch (attr) { |
| 139 | case IR::Attribute::PositionX: | 150 | case IR::Attribute::PositionX: |
diff --git a/src/shader_recompiler/frontend/maxwell/program.cpp b/src/shader_recompiler/frontend/maxwell/program.cpp index 6efaf6ee0..a914a91f4 100644 --- a/src/shader_recompiler/frontend/maxwell/program.cpp +++ b/src/shader_recompiler/frontend/maxwell/program.cpp | |||
| @@ -27,6 +27,40 @@ static void RemoveUnreachableBlocks(IR::Program& program) { | |||
| 27 | }); | 27 | }); |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | static void CollectInterpolationInfo(Environment& env, IR::Program& program) { | ||
| 31 | if (program.stage != Stage::Fragment) { | ||
| 32 | return; | ||
| 33 | } | ||
| 34 | const ProgramHeader& sph{env.SPH()}; | ||
| 35 | for (size_t index = 0; index < program.info.input_generics.size(); ++index) { | ||
| 36 | std::optional<PixelImap> imap; | ||
| 37 | for (const PixelImap value : sph.ps.GenericInputMap(static_cast<u32>(index))) { | ||
| 38 | if (value == PixelImap::Unused) { | ||
| 39 | continue; | ||
| 40 | } | ||
| 41 | if (imap && imap != value) { | ||
| 42 | throw NotImplementedException("Per component interpolation"); | ||
| 43 | } | ||
| 44 | imap = value; | ||
| 45 | } | ||
| 46 | if (!imap) { | ||
| 47 | continue; | ||
| 48 | } | ||
| 49 | program.info.input_generics[index].interpolation = [&] { | ||
| 50 | switch (*imap) { | ||
| 51 | case PixelImap::Unused: | ||
| 52 | case PixelImap::Perspective: | ||
| 53 | return Interpolation::Smooth; | ||
| 54 | case PixelImap::Constant: | ||
| 55 | return Interpolation::Flat; | ||
| 56 | case PixelImap::ScreenLinear: | ||
| 57 | return Interpolation::NoPerspective; | ||
| 58 | } | ||
| 59 | throw NotImplementedException("Unknown interpolation {}", *imap); | ||
| 60 | }(); | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 30 | IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Block>& block_pool, | 64 | IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Block>& block_pool, |
| 31 | Environment& env, Flow::CFG& cfg) { | 65 | Environment& env, Flow::CFG& cfg) { |
| 32 | IR::Program program; | 66 | IR::Program program; |
| @@ -51,6 +85,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo | |||
| 51 | Optimization::IdentityRemovalPass(program); | 85 | Optimization::IdentityRemovalPass(program); |
| 52 | Optimization::VerificationPass(program); | 86 | Optimization::VerificationPass(program); |
| 53 | Optimization::CollectShaderInfoPass(program); | 87 | Optimization::CollectShaderInfoPass(program); |
| 88 | CollectInterpolationInfo(env, program); | ||
| 54 | return program; | 89 | return program; |
| 55 | } | 90 | } |
| 56 | 91 | ||
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp index 516ffec2d..54bc1e34c 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp | |||
| @@ -151,16 +151,8 @@ void TranslatorVisitor::IPA(u64 insn) { | |||
| 151 | value = ir.FPMul(value, position_w); | 151 | value = ir.FPMul(value, position_w); |
| 152 | } | 152 | } |
| 153 | } | 153 | } |
| 154 | switch (ipa.interpolation_mode) { | 154 | if (ipa.interpolation_mode == InterpolationMode::Multiply) { |
| 155 | case InterpolationMode::Pass: | ||
| 156 | break; | ||
| 157 | case InterpolationMode::Multiply: | ||
| 158 | value = ir.FPMul(value, F(ipa.multiplier)); | 155 | value = ir.FPMul(value, F(ipa.multiplier)); |
| 159 | break; | ||
| 160 | case InterpolationMode::Constant: | ||
| 161 | throw NotImplementedException("IPA.CONSTANT"); | ||
| 162 | case InterpolationMode::Sc: | ||
| 163 | throw NotImplementedException("IPA.SC"); | ||
| 164 | } | 156 | } |
| 165 | 157 | ||
| 166 | // Saturated IPAs are generally generated out of clamped varyings. | 158 | // Saturated IPAs are generally generated out of clamped varyings. |
diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp index 0ec0d4c01..60be67228 100644 --- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp +++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp | |||
| @@ -28,7 +28,7 @@ void AddConstantBufferDescriptor(Info& info, u32 index, u32 count) { | |||
| 28 | 28 | ||
| 29 | void GetAttribute(Info& info, IR::Attribute attribute) { | 29 | void GetAttribute(Info& info, IR::Attribute attribute) { |
| 30 | if (IR::IsGeneric(attribute)) { | 30 | if (IR::IsGeneric(attribute)) { |
| 31 | info.loads_generics.at(IR::GenericAttributeIndex(attribute)) = true; | 31 | info.input_generics.at(IR::GenericAttributeIndex(attribute)).used = true; |
| 32 | return; | 32 | return; |
| 33 | } | 33 | } |
| 34 | switch (attribute) { | 34 | switch (attribute) { |
diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h index 41550bfc6..e26047751 100644 --- a/src/shader_recompiler/profile.h +++ b/src/shader_recompiler/profile.h | |||
| @@ -14,6 +14,7 @@ enum class AttributeType : u8 { | |||
| 14 | Float, | 14 | Float, |
| 15 | SignedInt, | 15 | SignedInt, |
| 16 | UnsignedInt, | 16 | UnsignedInt, |
| 17 | Disabled, | ||
| 17 | }; | 18 | }; |
| 18 | 19 | ||
| 19 | struct Profile { | 20 | struct Profile { |
diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index 8ab66bb2a..9111159f3 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h | |||
| @@ -31,6 +31,17 @@ enum class TextureType : u32 { | |||
| 31 | ShadowArrayCube, | 31 | ShadowArrayCube, |
| 32 | }; | 32 | }; |
| 33 | 33 | ||
| 34 | enum class Interpolation { | ||
| 35 | Smooth, | ||
| 36 | Flat, | ||
| 37 | NoPerspective, | ||
| 38 | }; | ||
| 39 | |||
| 40 | struct InputVarying { | ||
| 41 | Interpolation interpolation{Interpolation::Smooth}; | ||
| 42 | bool used{false}; | ||
| 43 | }; | ||
| 44 | |||
| 34 | struct TextureDescriptor { | 45 | struct TextureDescriptor { |
| 35 | TextureType type; | 46 | TextureType type; |
| 36 | u32 cbuf_index; | 47 | u32 cbuf_index; |
| @@ -58,7 +69,7 @@ struct Info { | |||
| 58 | bool uses_local_invocation_id{}; | 69 | bool uses_local_invocation_id{}; |
| 59 | bool uses_subgroup_invocation_id{}; | 70 | bool uses_subgroup_invocation_id{}; |
| 60 | 71 | ||
| 61 | std::array<bool, 32> loads_generics{}; | 72 | std::array<InputVarying, 32> input_generics{}; |
| 62 | bool loads_position{}; | 73 | bool loads_position{}; |
| 63 | bool loads_instance_id{}; | 74 | bool loads_instance_id{}; |
| 64 | bool loads_vertex_id{}; | 75 | bool loads_vertex_id{}; |
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 82536b9d6..278509bf0 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | |||
| @@ -221,10 +221,10 @@ void GraphicsPipeline::MakePipeline(const Device& device, const FixedPipelineSta | |||
| 221 | } | 221 | } |
| 222 | } | 222 | } |
| 223 | static_vector<VkVertexInputAttributeDescription, 32> vertex_attributes; | 223 | static_vector<VkVertexInputAttributeDescription, 32> vertex_attributes; |
| 224 | const auto& input_attributes = stage_infos[0].loads_generics; | 224 | const auto& input_attributes = stage_infos[0].input_generics; |
| 225 | for (size_t index = 0; index < state.attributes.size(); ++index) { | 225 | for (size_t index = 0; index < state.attributes.size(); ++index) { |
| 226 | const auto& attribute = state.attributes[index]; | 226 | const auto& attribute = state.attributes[index]; |
| 227 | if (!attribute.enabled || !input_attributes[index]) { | 227 | if (!attribute.enabled || !input_attributes[index].used) { |
| 228 | continue; | 228 | continue; |
| 229 | } | 229 | } |
| 230 | vertex_attributes.push_back({ | 230 | vertex_attributes.push_back({ |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 251559b16..69dd945b2 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -755,6 +755,9 @@ ComputePipeline PipelineCache::CreateComputePipeline(ShaderPools& pools, | |||
| 755 | } | 755 | } |
| 756 | 756 | ||
| 757 | static Shader::AttributeType CastAttributeType(const FixedPipelineState::VertexAttribute& attr) { | 757 | static Shader::AttributeType CastAttributeType(const FixedPipelineState::VertexAttribute& attr) { |
| 758 | if (attr.enabled == 0) { | ||
| 759 | return Shader::AttributeType::Disabled; | ||
| 760 | } | ||
| 758 | switch (attr.Type()) { | 761 | switch (attr.Type()) { |
| 759 | case Maxwell::VertexAttribute::Type::SignedNorm: | 762 | case Maxwell::VertexAttribute::Type::SignedNorm: |
| 760 | case Maxwell::VertexAttribute::Type::UnsignedNorm: | 763 | case Maxwell::VertexAttribute::Type::UnsignedNorm: |