diff options
| author | 2022-03-17 13:30:21 -0400 | |
|---|---|---|
| committer | 2022-03-17 13:30:21 -0400 | |
| commit | e228a40db807c20a2484169bd0a1447a081ea1ce (patch) | |
| tree | cd69df019ebf505189e5ee897ae042f9bc131119 /src/shader_recompiler | |
| parent | Address review comments (diff) | |
| download | yuzu-e228a40db807c20a2484169bd0a1447a081ea1ce.tar.gz yuzu-e228a40db807c20a2484169bd0a1447a081ea1ce.tar.xz yuzu-e228a40db807c20a2484169bd0a1447a081ea1ce.zip | |
shader_recompiler: Use functions for indirect const buffer accesses
Diffstat (limited to 'src/shader_recompiler')
5 files changed, 94 insertions, 39 deletions
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 264646115..9f6d5e3a5 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 | |||
| @@ -123,7 +123,7 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) { | |||
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr, u32 element_size, | 125 | Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr, u32 element_size, |
| 126 | const IR::Value& binding, const IR::Value& offset) { | 126 | const IR::Value& binding, const IR::Value& offset, const Id indirect_func) { |
| 127 | Id buffer_offset; | 127 | Id buffer_offset; |
| 128 | 128 | ||
| 129 | const Id uniform_type{ctx.uniform_types.*member_ptr}; | 129 | const Id uniform_type{ctx.uniform_types.*member_ptr}; |
| @@ -145,42 +145,19 @@ Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr, | |||
| 145 | ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, buffer_offset)}; | 145 | ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, buffer_offset)}; |
| 146 | return ctx.OpLoad(result_type, access_chain); | 146 | return ctx.OpLoad(result_type, access_chain); |
| 147 | } else { | 147 | } else { |
| 148 | const Id index{ctx.Def(binding)}; | 148 | const std::array<Id, 2> arguments{ctx.Def(binding), buffer_offset}; |
| 149 | const Id merge_label = ctx.OpLabel(); | 149 | return ctx.OpFunctionCall(result_type, indirect_func, arguments); |
| 150 | |||
| 151 | std::array<Id, Info::MAX_CBUFS> buf_labels; | ||
| 152 | std::array<Sirit::Literal, Info::MAX_CBUFS> buf_literals; | ||
| 153 | for (u32 i = 0; i < Info::MAX_CBUFS; i++) { | ||
| 154 | buf_labels[i] = ctx.OpLabel(); | ||
| 155 | buf_literals[i] = Sirit::Literal{i}; | ||
| 156 | } | ||
| 157 | |||
| 158 | ctx.OpSelectionMerge(merge_label, spv::SelectionControlMask::MaskNone); | ||
| 159 | ctx.OpSwitch(index, buf_labels[0], buf_literals, buf_labels); | ||
| 160 | |||
| 161 | std::array<Id, Info::MAX_CBUFS * 2> phi_targets; | ||
| 162 | for (u32 i = 0; i < Info::MAX_CBUFS; i++) { | ||
| 163 | ctx.AddLabel(buf_labels[i]); | ||
| 164 | const Id cbuf{ctx.cbufs[i].*member_ptr}; | ||
| 165 | const Id access_chain{ | ||
| 166 | ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, buffer_offset)}; | ||
| 167 | phi_targets[2 * i + 0] = ctx.OpLoad(result_type, access_chain); | ||
| 168 | phi_targets[2 * i + 1] = buf_labels[i]; | ||
| 169 | ctx.OpBranch(merge_label); | ||
| 170 | } | ||
| 171 | |||
| 172 | ctx.AddLabel(merge_label); | ||
| 173 | |||
| 174 | return ctx.OpPhi(result_type, phi_targets); | ||
| 175 | } | 150 | } |
| 176 | } | 151 | } |
| 177 | 152 | ||
| 178 | Id GetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 153 | Id GetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { |
| 179 | return GetCbuf(ctx, ctx.U32[1], &UniformDefinitions::U32, sizeof(u32), binding, offset); | 154 | return GetCbuf(ctx, ctx.U32[1], &UniformDefinitions::U32, sizeof(u32), binding, offset, |
| 155 | ctx.load_const_func_u32); | ||
| 180 | } | 156 | } |
| 181 | 157 | ||
| 182 | Id GetCbufU32x4(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 158 | Id GetCbufU32x4(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { |
| 183 | return GetCbuf(ctx, ctx.U32[4], &UniformDefinitions::U32x4, sizeof(u32[4]), binding, offset); | 159 | return GetCbuf(ctx, ctx.U32[4], &UniformDefinitions::U32x4, sizeof(u32[4]), binding, offset, |
| 160 | ctx.load_const_func_u32x4); | ||
| 184 | } | 161 | } |
| 185 | 162 | ||
| 186 | Id GetCbufElement(EmitContext& ctx, Id vector, const IR::Value& offset, u32 index_offset) { | 163 | Id GetCbufElement(EmitContext& ctx, Id vector, const IR::Value& offset, u32 index_offset) { |
| @@ -231,7 +208,8 @@ void EmitGetIndirectBranchVariable(EmitContext&) { | |||
| 231 | 208 | ||
| 232 | Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 209 | Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { |
| 233 | if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int8) { | 210 | if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int8) { |
| 234 | const Id load{GetCbuf(ctx, ctx.U8, &UniformDefinitions::U8, sizeof(u8), binding, offset)}; | 211 | const Id load{GetCbuf(ctx, ctx.U8, &UniformDefinitions::U8, sizeof(u8), binding, offset, |
| 212 | ctx.load_const_func_u8)}; | ||
| 235 | return ctx.OpUConvert(ctx.U32[1], load); | 213 | return ctx.OpUConvert(ctx.U32[1], load); |
| 236 | } | 214 | } |
| 237 | Id element{}; | 215 | Id element{}; |
| @@ -247,7 +225,8 @@ Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& of | |||
| 247 | 225 | ||
| 248 | Id EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 226 | Id EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { |
| 249 | if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int8) { | 227 | if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int8) { |
| 250 | const Id load{GetCbuf(ctx, ctx.S8, &UniformDefinitions::S8, sizeof(s8), binding, offset)}; | 228 | const Id load{GetCbuf(ctx, ctx.S8, &UniformDefinitions::S8, sizeof(s8), binding, offset, |
| 229 | ctx.load_const_func_u8)}; | ||
| 251 | return ctx.OpSConvert(ctx.U32[1], load); | 230 | return ctx.OpSConvert(ctx.U32[1], load); |
| 252 | } | 231 | } |
| 253 | Id element{}; | 232 | Id element{}; |
| @@ -263,8 +242,8 @@ Id EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& of | |||
| 263 | 242 | ||
| 264 | Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 243 | Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { |
| 265 | if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int16) { | 244 | if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int16) { |
| 266 | const Id load{ | 245 | const Id load{GetCbuf(ctx, ctx.U16, &UniformDefinitions::U16, sizeof(u16), binding, offset, |
| 267 | GetCbuf(ctx, ctx.U16, &UniformDefinitions::U16, sizeof(u16), binding, offset)}; | 246 | ctx.load_const_func_u16)}; |
| 268 | return ctx.OpUConvert(ctx.U32[1], load); | 247 | return ctx.OpUConvert(ctx.U32[1], load); |
| 269 | } | 248 | } |
| 270 | Id element{}; | 249 | Id element{}; |
| @@ -280,8 +259,8 @@ Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& o | |||
| 280 | 259 | ||
| 281 | Id EmitGetCbufS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 260 | Id EmitGetCbufS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { |
| 282 | if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int16) { | 261 | if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int16) { |
| 283 | const Id load{ | 262 | const Id load{GetCbuf(ctx, ctx.S16, &UniformDefinitions::S16, sizeof(s16), binding, offset, |
| 284 | GetCbuf(ctx, ctx.S16, &UniformDefinitions::S16, sizeof(s16), binding, offset)}; | 263 | ctx.load_const_func_u16)}; |
| 285 | return ctx.OpSConvert(ctx.U32[1], load); | 264 | return ctx.OpSConvert(ctx.U32[1], load); |
| 286 | } | 265 | } |
| 287 | Id element{}; | 266 | Id element{}; |
| @@ -306,7 +285,8 @@ Id EmitGetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& o | |||
| 306 | 285 | ||
| 307 | Id EmitGetCbufF32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 286 | Id EmitGetCbufF32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { |
| 308 | if (ctx.profile.support_descriptor_aliasing) { | 287 | if (ctx.profile.support_descriptor_aliasing) { |
| 309 | return GetCbuf(ctx, ctx.F32[1], &UniformDefinitions::F32, sizeof(f32), binding, offset); | 288 | return GetCbuf(ctx, ctx.F32[1], &UniformDefinitions::F32, sizeof(f32), binding, offset, |
| 289 | ctx.load_const_func_f32); | ||
| 310 | } else { | 290 | } else { |
| 311 | const Id vector{GetCbufU32x4(ctx, binding, offset)}; | 291 | const Id vector{GetCbufU32x4(ctx, binding, offset)}; |
| 312 | return ctx.OpBitcast(ctx.F32[1], GetCbufElement(ctx, vector, offset, 0u)); | 292 | return ctx.OpBitcast(ctx.F32[1], GetCbufElement(ctx, vector, offset, 0u)); |
| @@ -315,8 +295,8 @@ Id EmitGetCbufF32(EmitContext& ctx, const IR::Value& binding, const IR::Value& o | |||
| 315 | 295 | ||
| 316 | Id EmitGetCbufU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 296 | Id EmitGetCbufU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { |
| 317 | if (ctx.profile.support_descriptor_aliasing) { | 297 | if (ctx.profile.support_descriptor_aliasing) { |
| 318 | return GetCbuf(ctx, ctx.U32[2], &UniformDefinitions::U32x2, sizeof(u32[2]), binding, | 298 | return GetCbuf(ctx, ctx.U32[2], &UniformDefinitions::U32x2, sizeof(u32[2]), binding, offset, |
| 319 | offset); | 299 | ctx.load_const_func_u32x2); |
| 320 | } else { | 300 | } else { |
| 321 | const Id vector{GetCbufU32x4(ctx, binding, offset)}; | 301 | const Id vector{GetCbufU32x4(ctx, binding, offset)}; |
| 322 | return ctx.OpCompositeConstruct(ctx.U32[2], GetCbufElement(ctx, vector, offset, 0u), | 302 | return ctx.OpCompositeConstruct(ctx.U32[2], GetCbufElement(ctx, vector, offset, 0u), |
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index cd90c084a..f85541a2e 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp | |||
| @@ -464,6 +464,7 @@ EmitContext::EmitContext(const Profile& profile_, const RuntimeInfo& runtime_inf | |||
| 464 | DefineSharedMemory(program); | 464 | DefineSharedMemory(program); |
| 465 | DefineSharedMemoryFunctions(program); | 465 | DefineSharedMemoryFunctions(program); |
| 466 | DefineConstantBuffers(program.info, uniform_binding); | 466 | DefineConstantBuffers(program.info, uniform_binding); |
| 467 | DefineConstantBufferIndirectFunctions(program.info); | ||
| 467 | DefineStorageBuffers(program.info, storage_binding); | 468 | DefineStorageBuffers(program.info, storage_binding); |
| 468 | DefineTextureBuffers(program.info, texture_binding); | 469 | DefineTextureBuffers(program.info, texture_binding); |
| 469 | DefineImageBuffers(program.info, image_binding); | 470 | DefineImageBuffers(program.info, image_binding); |
| @@ -1027,6 +1028,69 @@ void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { | |||
| 1027 | binding += static_cast<u32>(info.constant_buffer_descriptors.size()); | 1028 | binding += static_cast<u32>(info.constant_buffer_descriptors.size()); |
| 1028 | } | 1029 | } |
| 1029 | 1030 | ||
| 1031 | void EmitContext::DefineConstantBufferIndirectFunctions(const Info& info) { | ||
| 1032 | if (!info.uses_cbuf_indirect) { | ||
| 1033 | return; | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | const auto make_accessor{[&](Id buffer_type, Id UniformDefinitions::*member_ptr) { | ||
| 1037 | const Id func_type{TypeFunction(buffer_type, U32[1], U32[1])}; | ||
| 1038 | const Id func{OpFunction(buffer_type, spv::FunctionControlMask::MaskNone, func_type)}; | ||
| 1039 | const Id binding{OpFunctionParameter(U32[1])}; | ||
| 1040 | const Id offset{OpFunctionParameter(U32[1])}; | ||
| 1041 | |||
| 1042 | AddLabel(); | ||
| 1043 | |||
| 1044 | const Id merge_label{OpLabel()}; | ||
| 1045 | const Id uniform_type{uniform_types.*member_ptr}; | ||
| 1046 | |||
| 1047 | std::array<Id, Info::MAX_CBUFS> buf_labels; | ||
| 1048 | std::array<Sirit::Literal, Info::MAX_CBUFS> buf_literals; | ||
| 1049 | for (u32 i = 0; i < Info::MAX_CBUFS; i++) { | ||
| 1050 | buf_labels[i] = OpLabel(); | ||
| 1051 | buf_literals[i] = Sirit::Literal{i}; | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | OpSelectionMerge(merge_label, spv::SelectionControlMask::MaskNone); | ||
| 1055 | OpSwitch(binding, buf_labels[0], buf_literals, buf_labels); | ||
| 1056 | |||
| 1057 | for (u32 i = 0; i < Info::MAX_CBUFS; i++) { | ||
| 1058 | AddLabel(buf_labels[i]); | ||
| 1059 | const Id cbuf{cbufs[i].*member_ptr}; | ||
| 1060 | const Id access_chain{OpAccessChain(uniform_type, cbuf, u32_zero_value, offset)}; | ||
| 1061 | const Id result{OpLoad(buffer_type, access_chain)}; | ||
| 1062 | OpReturnValue(result); | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | AddLabel(merge_label); | ||
| 1066 | OpUnreachable(); | ||
| 1067 | OpFunctionEnd(); | ||
| 1068 | |||
| 1069 | return func; | ||
| 1070 | }}; | ||
| 1071 | |||
| 1072 | IR::Type types{info.used_constant_buffer_types}; | ||
| 1073 | |||
| 1074 | if (True(types & IR::Type::U8)) { | ||
| 1075 | load_const_func_u8 = make_accessor(U8, &UniformDefinitions::U8); | ||
| 1076 | } | ||
| 1077 | if (True(types & IR::Type::U16)) { | ||
| 1078 | load_const_func_u16 = make_accessor(U16, &UniformDefinitions::U16); | ||
| 1079 | } | ||
| 1080 | if (True(types & IR::Type::F32)) { | ||
| 1081 | load_const_func_f32 = make_accessor(F32[1], &UniformDefinitions::F32); | ||
| 1082 | } | ||
| 1083 | if (True(types & IR::Type::U32)) { | ||
| 1084 | load_const_func_u32 = make_accessor(U32[1], &UniformDefinitions::U32); | ||
| 1085 | } | ||
| 1086 | if (True(types & IR::Type::U32x2)) { | ||
| 1087 | load_const_func_u32x2 = make_accessor(U32[2], &UniformDefinitions::U32x2); | ||
| 1088 | } | ||
| 1089 | if (True(types & IR::Type::U32x4)) { | ||
| 1090 | load_const_func_u32x4 = make_accessor(U32[4], &UniformDefinitions::U32x4); | ||
| 1091 | } | ||
| 1092 | } | ||
| 1093 | |||
| 1030 | void EmitContext::DefineStorageBuffers(const Info& info, u32& binding) { | 1094 | void EmitContext::DefineStorageBuffers(const Info& info, u32& binding) { |
| 1031 | if (info.storage_buffers_descriptors.empty()) { | 1095 | if (info.storage_buffers_descriptors.empty()) { |
| 1032 | return; | 1096 | return; |
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h index f87138f7e..906a1dc2c 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h | |||
| @@ -294,6 +294,13 @@ public: | |||
| 294 | 294 | ||
| 295 | std::vector<Id> interfaces; | 295 | std::vector<Id> interfaces; |
| 296 | 296 | ||
| 297 | Id load_const_func_u8{}; | ||
| 298 | Id load_const_func_u16{}; | ||
| 299 | Id load_const_func_u32{}; | ||
| 300 | Id load_const_func_f32{}; | ||
| 301 | Id load_const_func_u32x2{}; | ||
| 302 | Id load_const_func_u32x4{}; | ||
| 303 | |||
| 297 | private: | 304 | private: |
| 298 | void DefineCommonTypes(const Info& info); | 305 | void DefineCommonTypes(const Info& info); |
| 299 | void DefineCommonConstants(); | 306 | void DefineCommonConstants(); |
| @@ -302,6 +309,7 @@ private: | |||
| 302 | void DefineSharedMemory(const IR::Program& program); | 309 | void DefineSharedMemory(const IR::Program& program); |
| 303 | void DefineSharedMemoryFunctions(const IR::Program& program); | 310 | void DefineSharedMemoryFunctions(const IR::Program& program); |
| 304 | void DefineConstantBuffers(const Info& info, u32& binding); | 311 | void DefineConstantBuffers(const Info& info, u32& binding); |
| 312 | void DefineConstantBufferIndirectFunctions(const Info& info); | ||
| 305 | void DefineStorageBuffers(const Info& info, u32& binding); | 313 | void DefineStorageBuffers(const Info& info, u32& binding); |
| 306 | void DefineTextureBuffers(const Info& info, u32& binding); | 314 | void DefineTextureBuffers(const Info& info, u32& binding); |
| 307 | void DefineImageBuffers(const Info& info, u32& binding); | 315 | void DefineImageBuffers(const Info& info, u32& binding); |
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 1a50dd382..b54894a9b 100644 --- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp +++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp | |||
| @@ -30,6 +30,8 @@ void AddConstantBufferDescriptor(Info& info, u32 index, u32 count) { | |||
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | void AddRegisterIndexedLdc(Info& info) { | 32 | void AddRegisterIndexedLdc(Info& info) { |
| 33 | info.uses_cbuf_indirect = true; | ||
| 34 | |||
| 33 | // The shader can use any possible constant buffer | 35 | // The shader can use any possible constant buffer |
| 34 | info.constant_buffer_mask = (1 << Info::MAX_CBUFS) - 1; | 36 | info.constant_buffer_mask = (1 << Info::MAX_CBUFS) - 1; |
| 35 | 37 | ||
diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index 9f375c30e..9cff2e42d 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h | |||
| @@ -173,6 +173,7 @@ struct Info { | |||
| 173 | bool uses_atomic_image_u32{}; | 173 | bool uses_atomic_image_u32{}; |
| 174 | bool uses_shadow_lod{}; | 174 | bool uses_shadow_lod{}; |
| 175 | bool uses_rescaling_uniform{}; | 175 | bool uses_rescaling_uniform{}; |
| 176 | bool uses_cbuf_indirect{}; | ||
| 176 | 177 | ||
| 177 | IR::Type used_constant_buffer_types{}; | 178 | IR::Type used_constant_buffer_types{}; |
| 178 | IR::Type used_storage_buffer_types{}; | 179 | IR::Type used_storage_buffer_types{}; |