diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp | 136 |
1 files changed, 99 insertions, 37 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp index 8849258e3..a6a3f3351 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp | |||
| @@ -8,44 +8,62 @@ | |||
| 8 | 8 | ||
| 9 | namespace Shader::Backend::SPIRV { | 9 | namespace Shader::Backend::SPIRV { |
| 10 | namespace { | 10 | namespace { |
| 11 | Id StorageIndex(EmitContext& ctx, const IR::Value& offset, size_t element_size) { | 11 | Id StorageIndex(EmitContext& ctx, const IR::Value& offset, size_t element_size, |
| 12 | u32 index_offset = 0) { | ||
| 12 | if (offset.IsImmediate()) { | 13 | if (offset.IsImmediate()) { |
| 13 | const u32 imm_offset{static_cast<u32>(offset.U32() / element_size)}; | 14 | const u32 imm_offset{static_cast<u32>(offset.U32() / element_size) + index_offset}; |
| 14 | return ctx.Const(imm_offset); | 15 | return ctx.Const(imm_offset); |
| 15 | } | 16 | } |
| 16 | const u32 shift{static_cast<u32>(std::countr_zero(element_size))}; | 17 | const u32 shift{static_cast<u32>(std::countr_zero(element_size))}; |
| 17 | const Id index{ctx.Def(offset)}; | 18 | Id index{ctx.Def(offset)}; |
| 18 | if (shift == 0) { | 19 | if (shift != 0) { |
| 19 | return index; | 20 | const Id shift_id{ctx.Const(shift)}; |
| 21 | index = ctx.OpShiftRightLogical(ctx.U32[1], index, shift_id); | ||
| 20 | } | 22 | } |
| 21 | const Id shift_id{ctx.Const(shift)}; | 23 | if (index_offset != 0) { |
| 22 | return ctx.OpShiftRightLogical(ctx.U32[1], index, shift_id); | 24 | index = ctx.OpIAdd(ctx.U32[1], index, ctx.Const(index_offset)); |
| 25 | } | ||
| 26 | return index; | ||
| 23 | } | 27 | } |
| 24 | 28 | ||
| 25 | Id StoragePointer(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, | 29 | Id StoragePointer(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, |
| 26 | const StorageTypeDefinition& type_def, size_t element_size, | 30 | const StorageTypeDefinition& type_def, size_t element_size, |
| 27 | Id StorageDefinitions::*member_ptr) { | 31 | Id StorageDefinitions::*member_ptr, u32 index_offset = 0) { |
| 28 | if (!binding.IsImmediate()) { | 32 | if (!binding.IsImmediate()) { |
| 29 | throw NotImplementedException("Dynamic storage buffer indexing"); | 33 | throw NotImplementedException("Dynamic storage buffer indexing"); |
| 30 | } | 34 | } |
| 31 | const Id ssbo{ctx.ssbos[binding.U32()].*member_ptr}; | 35 | const Id ssbo{ctx.ssbos[binding.U32()].*member_ptr}; |
| 32 | const Id index{StorageIndex(ctx, offset, element_size)}; | 36 | const Id index{StorageIndex(ctx, offset, element_size, index_offset)}; |
| 33 | return ctx.OpAccessChain(type_def.element, ssbo, ctx.u32_zero_value, index); | 37 | return ctx.OpAccessChain(type_def.element, ssbo, ctx.u32_zero_value, index); |
| 34 | } | 38 | } |
| 35 | 39 | ||
| 36 | Id LoadStorage(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, Id result_type, | 40 | Id LoadStorage(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, Id result_type, |
| 37 | const StorageTypeDefinition& type_def, size_t element_size, | 41 | const StorageTypeDefinition& type_def, size_t element_size, |
| 38 | Id StorageDefinitions::*member_ptr) { | 42 | Id StorageDefinitions::*member_ptr, u32 index_offset = 0) { |
| 39 | const Id pointer{StoragePointer(ctx, binding, offset, type_def, element_size, member_ptr)}; | 43 | const Id pointer{ |
| 44 | StoragePointer(ctx, binding, offset, type_def, element_size, member_ptr, index_offset)}; | ||
| 40 | return ctx.OpLoad(result_type, pointer); | 45 | return ctx.OpLoad(result_type, pointer); |
| 41 | } | 46 | } |
| 42 | 47 | ||
| 48 | Id LoadStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, | ||
| 49 | u32 index_offset = 0) { | ||
| 50 | return LoadStorage(ctx, binding, offset, ctx.U32[1], ctx.storage_types.U32, sizeof(u32), | ||
| 51 | &StorageDefinitions::U32, index_offset); | ||
| 52 | } | ||
| 53 | |||
| 43 | void WriteStorage(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, Id value, | 54 | void WriteStorage(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, Id value, |
| 44 | const StorageTypeDefinition& type_def, size_t element_size, | 55 | const StorageTypeDefinition& type_def, size_t element_size, |
| 45 | Id StorageDefinitions::*member_ptr) { | 56 | Id StorageDefinitions::*member_ptr, u32 index_offset = 0) { |
| 46 | const Id pointer{StoragePointer(ctx, binding, offset, type_def, element_size, member_ptr)}; | 57 | const Id pointer{ |
| 58 | StoragePointer(ctx, binding, offset, type_def, element_size, member_ptr, index_offset)}; | ||
| 47 | ctx.OpStore(pointer, value); | 59 | ctx.OpStore(pointer, value); |
| 48 | } | 60 | } |
| 61 | |||
| 62 | void WriteStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, Id value, | ||
| 63 | u32 index_offset = 0) { | ||
| 64 | WriteStorage(ctx, binding, offset, value, ctx.storage_types.U32, sizeof(u32), | ||
| 65 | &StorageDefinitions::U32, index_offset); | ||
| 66 | } | ||
| 49 | } // Anonymous namespace | 67 | } // Anonymous namespace |
| 50 | 68 | ||
| 51 | void EmitLoadGlobalU8(EmitContext&) { | 69 | void EmitLoadGlobalU8(EmitContext&) { |
| @@ -105,42 +123,73 @@ void EmitWriteGlobal128(EmitContext& ctx, Id address, Id value) { | |||
| 105 | } | 123 | } |
| 106 | 124 | ||
| 107 | Id EmitLoadStorageU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 125 | Id EmitLoadStorageU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { |
| 108 | return ctx.OpUConvert(ctx.U32[1], | 126 | if (ctx.profile.support_descriptor_aliasing) { |
| 109 | LoadStorage(ctx, binding, offset, ctx.U8, ctx.storage_types.U8, | 127 | return ctx.OpUConvert(ctx.U32[1], |
| 110 | sizeof(u8), &StorageDefinitions::U8)); | 128 | LoadStorage(ctx, binding, offset, ctx.U8, ctx.storage_types.U8, |
| 129 | sizeof(u8), &StorageDefinitions::U8)); | ||
| 130 | } else { | ||
| 131 | return ctx.OpBitFieldUExtract(ctx.U32[1], LoadStorage32(ctx, binding, offset), | ||
| 132 | ctx.BitOffset8(offset), ctx.Const(8u)); | ||
| 133 | } | ||
| 111 | } | 134 | } |
| 112 | 135 | ||
| 113 | Id EmitLoadStorageS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 136 | Id EmitLoadStorageS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { |
| 114 | return ctx.OpSConvert(ctx.U32[1], | 137 | if (ctx.profile.support_descriptor_aliasing) { |
| 115 | LoadStorage(ctx, binding, offset, ctx.S8, ctx.storage_types.S8, | 138 | return ctx.OpSConvert(ctx.U32[1], |
| 116 | sizeof(s8), &StorageDefinitions::S8)); | 139 | LoadStorage(ctx, binding, offset, ctx.S8, ctx.storage_types.S8, |
| 140 | sizeof(s8), &StorageDefinitions::S8)); | ||
| 141 | } else { | ||
| 142 | return ctx.OpBitFieldSExtract(ctx.U32[1], LoadStorage32(ctx, binding, offset), | ||
| 143 | ctx.BitOffset8(offset), ctx.Const(8u)); | ||
| 144 | } | ||
| 117 | } | 145 | } |
| 118 | 146 | ||
| 119 | Id EmitLoadStorageU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 147 | Id EmitLoadStorageU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { |
| 120 | return ctx.OpUConvert(ctx.U32[1], | 148 | if (ctx.profile.support_descriptor_aliasing) { |
| 121 | LoadStorage(ctx, binding, offset, ctx.U16, ctx.storage_types.U16, | 149 | return ctx.OpUConvert(ctx.U32[1], |
| 122 | sizeof(u16), &StorageDefinitions::U16)); | 150 | LoadStorage(ctx, binding, offset, ctx.U16, ctx.storage_types.U16, |
| 151 | sizeof(u16), &StorageDefinitions::U16)); | ||
| 152 | } else { | ||
| 153 | return ctx.OpBitFieldUExtract(ctx.U32[1], LoadStorage32(ctx, binding, offset), | ||
| 154 | ctx.BitOffset16(offset), ctx.Const(16u)); | ||
| 155 | } | ||
| 123 | } | 156 | } |
| 124 | 157 | ||
| 125 | Id EmitLoadStorageS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 158 | Id EmitLoadStorageS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { |
| 126 | return ctx.OpSConvert(ctx.U32[1], | 159 | if (ctx.profile.support_descriptor_aliasing) { |
| 127 | LoadStorage(ctx, binding, offset, ctx.S16, ctx.storage_types.S16, | 160 | return ctx.OpSConvert(ctx.U32[1], |
| 128 | sizeof(s16), &StorageDefinitions::S16)); | 161 | LoadStorage(ctx, binding, offset, ctx.S16, ctx.storage_types.S16, |
| 162 | sizeof(s16), &StorageDefinitions::S16)); | ||
| 163 | } else { | ||
| 164 | return ctx.OpBitFieldSExtract(ctx.U32[1], LoadStorage32(ctx, binding, offset), | ||
| 165 | ctx.BitOffset16(offset), ctx.Const(16u)); | ||
| 166 | } | ||
| 129 | } | 167 | } |
| 130 | 168 | ||
| 131 | Id EmitLoadStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 169 | Id EmitLoadStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { |
| 132 | return LoadStorage(ctx, binding, offset, ctx.U32[1], ctx.storage_types.U32, sizeof(u32), | 170 | return LoadStorage32(ctx, binding, offset); |
| 133 | &StorageDefinitions::U32); | ||
| 134 | } | 171 | } |
| 135 | 172 | ||
| 136 | Id EmitLoadStorage64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 173 | Id EmitLoadStorage64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { |
| 137 | return LoadStorage(ctx, binding, offset, ctx.U32[2], ctx.storage_types.U32x2, sizeof(u32[2]), | 174 | if (ctx.profile.support_descriptor_aliasing) { |
| 138 | &StorageDefinitions::U32x2); | 175 | return LoadStorage(ctx, binding, offset, ctx.U32[2], ctx.storage_types.U32x2, |
| 176 | sizeof(u32[2]), &StorageDefinitions::U32x2); | ||
| 177 | } else { | ||
| 178 | return ctx.OpCompositeConstruct(ctx.U32[2], LoadStorage32(ctx, binding, offset, 0), | ||
| 179 | LoadStorage32(ctx, binding, offset, 1)); | ||
| 180 | } | ||
| 139 | } | 181 | } |
| 140 | 182 | ||
| 141 | Id EmitLoadStorage128(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 183 | Id EmitLoadStorage128(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { |
| 142 | return LoadStorage(ctx, binding, offset, ctx.U32[4], ctx.storage_types.U32x4, sizeof(u32[4]), | 184 | if (ctx.profile.support_descriptor_aliasing) { |
| 143 | &StorageDefinitions::U32x4); | 185 | return LoadStorage(ctx, binding, offset, ctx.U32[4], ctx.storage_types.U32x4, |
| 186 | sizeof(u32[4]), &StorageDefinitions::U32x4); | ||
| 187 | } else { | ||
| 188 | return ctx.OpCompositeConstruct(ctx.U32[4], LoadStorage32(ctx, binding, offset, 0), | ||
| 189 | LoadStorage32(ctx, binding, offset, 1), | ||
| 190 | LoadStorage32(ctx, binding, offset, 2), | ||
| 191 | LoadStorage32(ctx, binding, offset, 3)); | ||
| 192 | } | ||
| 144 | } | 193 | } |
| 145 | 194 | ||
| 146 | void EmitWriteStorageU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, | 195 | void EmitWriteStorageU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, |
| @@ -169,20 +218,33 @@ void EmitWriteStorageS16(EmitContext& ctx, const IR::Value& binding, const IR::V | |||
| 169 | 218 | ||
| 170 | void EmitWriteStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, | 219 | void EmitWriteStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, |
| 171 | Id value) { | 220 | Id value) { |
| 172 | WriteStorage(ctx, binding, offset, value, ctx.storage_types.U32, sizeof(u32), | 221 | WriteStorage32(ctx, binding, offset, value); |
| 173 | &StorageDefinitions::U32); | ||
| 174 | } | 222 | } |
| 175 | 223 | ||
| 176 | void EmitWriteStorage64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, | 224 | void EmitWriteStorage64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, |
| 177 | Id value) { | 225 | Id value) { |
| 178 | WriteStorage(ctx, binding, offset, value, ctx.storage_types.U32x2, sizeof(u32[2]), | 226 | if (ctx.profile.support_descriptor_aliasing) { |
| 179 | &StorageDefinitions::U32x2); | 227 | WriteStorage(ctx, binding, offset, value, ctx.storage_types.U32x2, sizeof(u32[2]), |
| 228 | &StorageDefinitions::U32x2); | ||
| 229 | } else { | ||
| 230 | for (u32 index = 0; index < 2; ++index) { | ||
| 231 | const Id element{ctx.OpCompositeExtract(ctx.U32[1], value, index)}; | ||
| 232 | WriteStorage32(ctx, binding, offset, element, index); | ||
| 233 | } | ||
| 234 | } | ||
| 180 | } | 235 | } |
| 181 | 236 | ||
| 182 | void EmitWriteStorage128(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, | 237 | void EmitWriteStorage128(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, |
| 183 | Id value) { | 238 | Id value) { |
| 184 | WriteStorage(ctx, binding, offset, value, ctx.storage_types.U32x4, sizeof(u32[4]), | 239 | if (ctx.profile.support_descriptor_aliasing) { |
| 185 | &StorageDefinitions::U32x4); | 240 | WriteStorage(ctx, binding, offset, value, ctx.storage_types.U32x4, sizeof(u32[4]), |
| 241 | &StorageDefinitions::U32x4); | ||
| 242 | } else { | ||
| 243 | for (u32 index = 0; index < 4; ++index) { | ||
| 244 | const Id element{ctx.OpCompositeExtract(ctx.U32[1], value, index)}; | ||
| 245 | WriteStorage32(ctx, binding, offset, element, index); | ||
| 246 | } | ||
| 247 | } | ||
| 186 | } | 248 | } |
| 187 | 249 | ||
| 188 | } // namespace Shader::Backend::SPIRV | 250 | } // namespace Shader::Backend::SPIRV |