diff options
| author | 2021-03-28 19:53:34 -0300 | |
|---|---|---|
| committer | 2021-07-22 21:51:25 -0400 | |
| commit | e860870dd2244cd87645190c89244f1d2c4c775b (patch) | |
| tree | 90ff582c6837e7fd873287b5948e9da4ac10d865 /src/shader_recompiler/backend/spirv/emit_context.cpp | |
| parent | shader: Implement ISCADD CC (diff) | |
| download | yuzu-e860870dd2244cd87645190c89244f1d2c4c775b.tar.gz yuzu-e860870dd2244cd87645190c89244f1d2c4c775b.tar.xz yuzu-e860870dd2244cd87645190c89244f1d2c4c775b.zip | |
shader: Implement LDS, STS, LDL, and STS and use SPIR-V 1.4 when available
Diffstat (limited to 'src/shader_recompiler/backend/spirv/emit_context.cpp')
| -rw-r--r-- | src/shader_recompiler/backend/spirv/emit_context.cpp | 115 |
1 files changed, 114 insertions, 1 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp index a8ca33c1d..96d0e9b4d 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/emit_context.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <fmt/format.h> | 9 | #include <fmt/format.h> |
| 10 | 10 | ||
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "common/div_ceil.h" | ||
| 12 | #include "shader_recompiler/backend/spirv/emit_context.h" | 13 | #include "shader_recompiler/backend/spirv/emit_context.h" |
| 13 | 14 | ||
| 14 | namespace Shader::Backend::SPIRV { | 15 | namespace Shader::Backend::SPIRV { |
| @@ -96,11 +97,13 @@ void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_vie | |||
| 96 | } | 97 | } |
| 97 | 98 | ||
| 98 | EmitContext::EmitContext(const Profile& profile_, IR::Program& program, u32& binding) | 99 | EmitContext::EmitContext(const Profile& profile_, IR::Program& program, u32& binding) |
| 99 | : Sirit::Module(0x00010000), profile{profile_}, stage{program.stage} { | 100 | : Sirit::Module(profile_.supported_spirv), profile{profile_}, stage{program.stage} { |
| 100 | AddCapability(spv::Capability::Shader); | 101 | AddCapability(spv::Capability::Shader); |
| 101 | DefineCommonTypes(program.info); | 102 | DefineCommonTypes(program.info); |
| 102 | DefineCommonConstants(); | 103 | DefineCommonConstants(); |
| 103 | DefineInterfaces(program.info); | 104 | DefineInterfaces(program.info); |
| 105 | DefineLocalMemory(program); | ||
| 106 | DefineSharedMemory(program); | ||
| 104 | DefineConstantBuffers(program.info, binding); | 107 | DefineConstantBuffers(program.info, binding); |
| 105 | DefineStorageBuffers(program.info, binding); | 108 | DefineStorageBuffers(program.info, binding); |
| 106 | DefineTextures(program.info, binding); | 109 | DefineTextures(program.info, binding); |
| @@ -143,6 +146,8 @@ void EmitContext::DefineCommonTypes(const Info& info) { | |||
| 143 | F32.Define(*this, TypeFloat(32), "f32"); | 146 | F32.Define(*this, TypeFloat(32), "f32"); |
| 144 | U32.Define(*this, TypeInt(32, false), "u32"); | 147 | U32.Define(*this, TypeInt(32, false), "u32"); |
| 145 | 148 | ||
| 149 | private_u32 = Name(TypePointer(spv::StorageClass::Private, U32[1]), "private_u32"); | ||
| 150 | |||
| 146 | input_f32 = Name(TypePointer(spv::StorageClass::Input, F32[1]), "input_f32"); | 151 | input_f32 = Name(TypePointer(spv::StorageClass::Input, F32[1]), "input_f32"); |
| 147 | input_u32 = Name(TypePointer(spv::StorageClass::Input, U32[1]), "input_u32"); | 152 | input_u32 = Name(TypePointer(spv::StorageClass::Input, U32[1]), "input_u32"); |
| 148 | input_s32 = Name(TypePointer(spv::StorageClass::Input, TypeInt(32, true)), "input_s32"); | 153 | input_s32 = Name(TypePointer(spv::StorageClass::Input, TypeInt(32, true)), "input_s32"); |
| @@ -184,6 +189,105 @@ void EmitContext::DefineInterfaces(const Info& info) { | |||
| 184 | DefineOutputs(info); | 189 | DefineOutputs(info); |
| 185 | } | 190 | } |
| 186 | 191 | ||
| 192 | void EmitContext::DefineLocalMemory(const IR::Program& program) { | ||
| 193 | if (program.local_memory_size == 0) { | ||
| 194 | return; | ||
| 195 | } | ||
| 196 | const u32 num_elements{Common::DivCeil(program.local_memory_size, 4U)}; | ||
| 197 | const Id type{TypeArray(U32[1], Constant(U32[1], num_elements))}; | ||
| 198 | const Id pointer{TypePointer(spv::StorageClass::Private, type)}; | ||
| 199 | local_memory = AddGlobalVariable(pointer, spv::StorageClass::Private); | ||
| 200 | if (profile.supported_spirv >= 0x00010400) { | ||
| 201 | interfaces.push_back(local_memory); | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | void EmitContext::DefineSharedMemory(const IR::Program& program) { | ||
| 206 | if (program.shared_memory_size == 0) { | ||
| 207 | return; | ||
| 208 | } | ||
| 209 | const auto make{[&](Id element_type, u32 element_size) { | ||
| 210 | const u32 num_elements{Common::DivCeil(program.shared_memory_size, element_size)}; | ||
| 211 | const Id array_type{TypeArray(element_type, Constant(U32[1], num_elements))}; | ||
| 212 | Decorate(array_type, spv::Decoration::ArrayStride, element_size); | ||
| 213 | |||
| 214 | const Id struct_type{TypeStruct(array_type)}; | ||
| 215 | MemberDecorate(struct_type, 0U, spv::Decoration::Offset, 0U); | ||
| 216 | Decorate(struct_type, spv::Decoration::Block); | ||
| 217 | |||
| 218 | const Id pointer{TypePointer(spv::StorageClass::Workgroup, struct_type)}; | ||
| 219 | const Id element_pointer{TypePointer(spv::StorageClass::Workgroup, element_type)}; | ||
| 220 | const Id variable{AddGlobalVariable(pointer, spv::StorageClass::Workgroup)}; | ||
| 221 | Decorate(variable, spv::Decoration::Aliased); | ||
| 222 | interfaces.push_back(variable); | ||
| 223 | |||
| 224 | return std::make_pair(variable, element_pointer); | ||
| 225 | }}; | ||
| 226 | if (profile.support_explicit_workgroup_layout) { | ||
| 227 | AddExtension("SPV_KHR_workgroup_memory_explicit_layout"); | ||
| 228 | AddCapability(spv::Capability::WorkgroupMemoryExplicitLayoutKHR); | ||
| 229 | if (program.info.uses_int8) { | ||
| 230 | AddCapability(spv::Capability::WorkgroupMemoryExplicitLayout8BitAccessKHR); | ||
| 231 | std::tie(shared_memory_u8, shared_u8) = make(U8, 1); | ||
| 232 | } | ||
| 233 | if (program.info.uses_int16) { | ||
| 234 | AddCapability(spv::Capability::WorkgroupMemoryExplicitLayout16BitAccessKHR); | ||
| 235 | std::tie(shared_memory_u16, shared_u16) = make(U16, 2); | ||
| 236 | } | ||
| 237 | std::tie(shared_memory_u32, shared_u32) = make(U32[1], 4); | ||
| 238 | std::tie(shared_memory_u32x2, shared_u32x2) = make(U32[2], 8); | ||
| 239 | std::tie(shared_memory_u32x4, shared_u32x4) = make(U32[4], 16); | ||
| 240 | } | ||
| 241 | const u32 num_elements{Common::DivCeil(program.shared_memory_size, 4U)}; | ||
| 242 | const Id type{TypeArray(U32[1], Constant(U32[1], num_elements))}; | ||
| 243 | const Id pointer_type{TypePointer(spv::StorageClass::Workgroup, type)}; | ||
| 244 | shared_u32 = TypePointer(spv::StorageClass::Workgroup, U32[1]); | ||
| 245 | shared_memory_u32 = AddGlobalVariable(pointer_type, spv::StorageClass::Workgroup); | ||
| 246 | interfaces.push_back(shared_memory_u32); | ||
| 247 | |||
| 248 | const Id func_type{TypeFunction(void_id, U32[1], U32[1])}; | ||
| 249 | const auto make_function{[&](u32 mask, u32 size) { | ||
| 250 | const Id loop_header{OpLabel()}; | ||
| 251 | const Id continue_block{OpLabel()}; | ||
| 252 | const Id merge_block{OpLabel()}; | ||
| 253 | |||
| 254 | const Id func{OpFunction(void_id, spv::FunctionControlMask::MaskNone, func_type)}; | ||
| 255 | const Id offset{OpFunctionParameter(U32[1])}; | ||
| 256 | const Id insert_value{OpFunctionParameter(U32[1])}; | ||
| 257 | AddLabel(); | ||
| 258 | OpBranch(loop_header); | ||
| 259 | |||
| 260 | AddLabel(loop_header); | ||
| 261 | const Id word_offset{OpShiftRightArithmetic(U32[1], offset, Constant(U32[1], 2U))}; | ||
| 262 | const Id shift_offset{OpShiftLeftLogical(U32[1], offset, Constant(U32[1], 3U))}; | ||
| 263 | const Id bit_offset{OpBitwiseAnd(U32[1], shift_offset, Constant(U32[1], mask))}; | ||
| 264 | const Id count{Constant(U32[1], size)}; | ||
| 265 | OpLoopMerge(merge_block, continue_block, spv::LoopControlMask::MaskNone); | ||
| 266 | OpBranch(continue_block); | ||
| 267 | |||
| 268 | AddLabel(continue_block); | ||
| 269 | const Id word_pointer{OpAccessChain(shared_u32, shared_memory_u32, word_offset)}; | ||
| 270 | const Id old_value{OpLoad(U32[1], word_pointer)}; | ||
| 271 | const Id new_value{OpBitFieldInsert(U32[1], old_value, insert_value, bit_offset, count)}; | ||
| 272 | const Id atomic_res{OpAtomicCompareExchange(U32[1], word_pointer, Constant(U32[1], 1U), | ||
| 273 | u32_zero_value, u32_zero_value, new_value, | ||
| 274 | old_value)}; | ||
| 275 | const Id success{OpIEqual(U1, atomic_res, old_value)}; | ||
| 276 | OpBranchConditional(success, merge_block, loop_header); | ||
| 277 | |||
| 278 | AddLabel(merge_block); | ||
| 279 | OpReturn(); | ||
| 280 | OpFunctionEnd(); | ||
| 281 | return func; | ||
| 282 | }}; | ||
| 283 | if (program.info.uses_int8) { | ||
| 284 | shared_store_u8_func = make_function(24, 8); | ||
| 285 | } | ||
| 286 | if (program.info.uses_int16) { | ||
| 287 | shared_store_u16_func = make_function(16, 16); | ||
| 288 | } | ||
| 289 | } | ||
| 290 | |||
| 187 | void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { | 291 | void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { |
| 188 | if (info.constant_buffer_descriptors.empty()) { | 292 | if (info.constant_buffer_descriptors.empty()) { |
| 189 | return; | 293 | return; |
| @@ -234,6 +338,9 @@ void EmitContext::DefineStorageBuffers(const Info& info, u32& binding) { | |||
| 234 | Decorate(id, spv::Decoration::Binding, binding); | 338 | Decorate(id, spv::Decoration::Binding, binding); |
| 235 | Decorate(id, spv::Decoration::DescriptorSet, 0U); | 339 | Decorate(id, spv::Decoration::DescriptorSet, 0U); |
| 236 | Name(id, fmt::format("ssbo{}", index)); | 340 | Name(id, fmt::format("ssbo{}", index)); |
| 341 | if (profile.supported_spirv >= 0x00010400) { | ||
| 342 | interfaces.push_back(id); | ||
| 343 | } | ||
| 237 | std::fill_n(ssbos.data() + index, desc.count, id); | 344 | std::fill_n(ssbos.data() + index, desc.count, id); |
| 238 | index += desc.count; | 345 | index += desc.count; |
| 239 | binding += desc.count; | 346 | binding += desc.count; |
| @@ -261,6 +368,9 @@ void EmitContext::DefineTextures(const Info& info, u32& binding) { | |||
| 261 | .image_type{image_type}, | 368 | .image_type{image_type}, |
| 262 | }); | 369 | }); |
| 263 | } | 370 | } |
| 371 | if (profile.supported_spirv >= 0x00010400) { | ||
| 372 | interfaces.push_back(id); | ||
| 373 | } | ||
| 264 | binding += desc.count; | 374 | binding += desc.count; |
| 265 | } | 375 | } |
| 266 | } | 376 | } |
| @@ -363,6 +473,9 @@ void EmitContext::DefineConstantBuffers(const Info& info, Id UniformDefinitions: | |||
| 363 | for (size_t i = 0; i < desc.count; ++i) { | 473 | for (size_t i = 0; i < desc.count; ++i) { |
| 364 | cbufs[desc.index + i].*member_type = id; | 474 | cbufs[desc.index + i].*member_type = id; |
| 365 | } | 475 | } |
| 476 | if (profile.supported_spirv >= 0x00010400) { | ||
| 477 | interfaces.push_back(id); | ||
| 478 | } | ||
| 366 | binding += desc.count; | 479 | binding += desc.count; |
| 367 | } | 480 | } |
| 368 | } | 481 | } |