summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/backend/spirv/emit_context.cpp
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2021-03-28 19:53:34 -0300
committerGravatar ameerj2021-07-22 21:51:25 -0400
commite860870dd2244cd87645190c89244f1d2c4c775b (patch)
tree90ff582c6837e7fd873287b5948e9da4ac10d865 /src/shader_recompiler/backend/spirv/emit_context.cpp
parentshader: Implement ISCADD CC (diff)
downloadyuzu-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.cpp115
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
14namespace Shader::Backend::SPIRV { 15namespace Shader::Backend::SPIRV {
@@ -96,11 +97,13 @@ void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_vie
96} 97}
97 98
98EmitContext::EmitContext(const Profile& profile_, IR::Program& program, u32& binding) 99EmitContext::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
192void 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
205void 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
187void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { 291void 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}