summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/shader_recompiler/CMakeLists.txt2
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.cpp29
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.h6
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.cpp2
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.h103
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp28
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_composite.cpp48
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp2
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp89
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp48
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp16
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp72
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp22
-rw-r--r--src/shader_recompiler/frontend/ir/condition.h2
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.cpp70
-rw-r--r--src/shader_recompiler/frontend/ir/microinstruction.cpp4
-rw-r--r--src/shader_recompiler/frontend/ir/microinstruction.h2
-rw-r--r--src/shader_recompiler/frontend/ir/opcodes.inc6
-rw-r--r--src/shader_recompiler/frontend/ir/program.cpp2
-rw-r--r--src/shader_recompiler/frontend/maxwell/program.cpp2
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp62
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/impl.h2
-rw-r--r--src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp18
-rw-r--r--src/shader_recompiler/ir_opt/constant_propagation_pass.cpp12
-rw-r--r--src/shader_recompiler/ir_opt/lower_fp16_to_fp32.cpp79
-rw-r--r--src/shader_recompiler/ir_opt/passes.h1
-rw-r--r--src/shader_recompiler/main.cpp10
-rw-r--r--src/shader_recompiler/object_pool.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.cpp3
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp8
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp2
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp10
32 files changed, 479 insertions, 285 deletions
diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt
index b56bdd3d9..6047f3ebe 100644
--- a/src/shader_recompiler/CMakeLists.txt
+++ b/src/shader_recompiler/CMakeLists.txt
@@ -7,6 +7,7 @@ add_library(shader_recompiler STATIC
7 backend/spirv/emit_spirv_composite.cpp 7 backend/spirv/emit_spirv_composite.cpp
8 backend/spirv/emit_spirv_context_get_set.cpp 8 backend/spirv/emit_spirv_context_get_set.cpp
9 backend/spirv/emit_spirv_control_flow.cpp 9 backend/spirv/emit_spirv_control_flow.cpp
10 backend/spirv/emit_spirv_convert.cpp
10 backend/spirv/emit_spirv_floating_point.cpp 11 backend/spirv/emit_spirv_floating_point.cpp
11 backend/spirv/emit_spirv_integer.cpp 12 backend/spirv/emit_spirv_integer.cpp
12 backend/spirv/emit_spirv_logical.cpp 13 backend/spirv/emit_spirv_logical.cpp
@@ -82,6 +83,7 @@ add_library(shader_recompiler STATIC
82 ir_opt/dead_code_elimination_pass.cpp 83 ir_opt/dead_code_elimination_pass.cpp
83 ir_opt/global_memory_to_storage_buffer_pass.cpp 84 ir_opt/global_memory_to_storage_buffer_pass.cpp
84 ir_opt/identity_removal_pass.cpp 85 ir_opt/identity_removal_pass.cpp
86 ir_opt/lower_fp16_to_fp32.cpp
85 ir_opt/passes.h 87 ir_opt/passes.h
86 ir_opt/ssa_rewrite_pass.cpp 88 ir_opt/ssa_rewrite_pass.cpp
87 ir_opt/verification_pass.cpp 89 ir_opt/verification_pass.cpp
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp
index 770067d98..ea1c8a3be 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_context.cpp
@@ -30,8 +30,11 @@ EmitContext::EmitContext(IR::Program& program) : Sirit::Module(0x00010000) {
30 DefineCommonTypes(program.info); 30 DefineCommonTypes(program.info);
31 DefineCommonConstants(); 31 DefineCommonConstants();
32 DefineSpecialVariables(program.info); 32 DefineSpecialVariables(program.info);
33 DefineConstantBuffers(program.info); 33
34 DefineStorageBuffers(program.info); 34 u32 binding{};
35 DefineConstantBuffers(program.info, binding);
36 DefineStorageBuffers(program.info, binding);
37
35 DefineLabels(program); 38 DefineLabels(program);
36} 39}
37 40
@@ -58,6 +61,12 @@ void EmitContext::DefineCommonTypes(const Info& info) {
58 61
59 U1 = Name(TypeBool(), "u1"); 62 U1 = Name(TypeBool(), "u1");
60 63
64 // TODO: Conditionally define these
65 AddCapability(spv::Capability::Int16);
66 AddCapability(spv::Capability::Int64);
67 U16 = Name(TypeInt(16, false), "u16");
68 U64 = Name(TypeInt(64, false), "u64");
69
61 F32.Define(*this, TypeFloat(32), "f32"); 70 F32.Define(*this, TypeFloat(32), "f32");
62 U32.Define(*this, TypeInt(32, false), "u32"); 71 U32.Define(*this, TypeInt(32, false), "u32");
63 72
@@ -95,12 +104,12 @@ void EmitContext::DefineSpecialVariables(const Info& info) {
95 } 104 }
96} 105}
97 106
98void EmitContext::DefineConstantBuffers(const Info& info) { 107void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) {
99 if (info.constant_buffer_descriptors.empty()) { 108 if (info.constant_buffer_descriptors.empty()) {
100 return; 109 return;
101 } 110 }
102 const Id array_type{TypeArray(U32[1], Constant(U32[1], 4096))}; 111 const Id array_type{TypeArray(U32[1], Constant(U32[1], 4096))};
103 Decorate(array_type, spv::Decoration::ArrayStride, 16U); 112 Decorate(array_type, spv::Decoration::ArrayStride, 4U);
104 113
105 const Id struct_type{TypeStruct(array_type)}; 114 const Id struct_type{TypeStruct(array_type)};
106 Name(struct_type, "cbuf_block"); 115 Name(struct_type, "cbuf_block");
@@ -111,18 +120,19 @@ void EmitContext::DefineConstantBuffers(const Info& info) {
111 const Id uniform_type{TypePointer(spv::StorageClass::Uniform, struct_type)}; 120 const Id uniform_type{TypePointer(spv::StorageClass::Uniform, struct_type)};
112 uniform_u32 = TypePointer(spv::StorageClass::Uniform, U32[1]); 121 uniform_u32 = TypePointer(spv::StorageClass::Uniform, U32[1]);
113 122
114 u32 binding{}; 123 u32 index{};
115 for (const Info::ConstantBufferDescriptor& desc : info.constant_buffer_descriptors) { 124 for (const Info::ConstantBufferDescriptor& desc : info.constant_buffer_descriptors) {
116 const Id id{AddGlobalVariable(uniform_type, spv::StorageClass::Uniform)}; 125 const Id id{AddGlobalVariable(uniform_type, spv::StorageClass::Uniform)};
117 Decorate(id, spv::Decoration::Binding, binding); 126 Decorate(id, spv::Decoration::Binding, binding);
118 Decorate(id, spv::Decoration::DescriptorSet, 0U); 127 Decorate(id, spv::Decoration::DescriptorSet, 0U);
119 Name(id, fmt::format("c{}", desc.index)); 128 Name(id, fmt::format("c{}", desc.index));
120 std::fill_n(cbufs.data() + desc.index, desc.count, id); 129 std::fill_n(cbufs.data() + desc.index, desc.count, id);
130 index += desc.count;
121 binding += desc.count; 131 binding += desc.count;
122 } 132 }
123} 133}
124 134
125void EmitContext::DefineStorageBuffers(const Info& info) { 135void EmitContext::DefineStorageBuffers(const Info& info, u32& binding) {
126 if (info.storage_buffers_descriptors.empty()) { 136 if (info.storage_buffers_descriptors.empty()) {
127 return; 137 return;
128 } 138 }
@@ -140,13 +150,14 @@ void EmitContext::DefineStorageBuffers(const Info& info) {
140 const Id storage_type{TypePointer(spv::StorageClass::StorageBuffer, struct_type)}; 150 const Id storage_type{TypePointer(spv::StorageClass::StorageBuffer, struct_type)};
141 storage_u32 = TypePointer(spv::StorageClass::StorageBuffer, U32[1]); 151 storage_u32 = TypePointer(spv::StorageClass::StorageBuffer, U32[1]);
142 152
143 u32 binding{}; 153 u32 index{};
144 for (const Info::StorageBufferDescriptor& desc : info.storage_buffers_descriptors) { 154 for (const Info::StorageBufferDescriptor& desc : info.storage_buffers_descriptors) {
145 const Id id{AddGlobalVariable(storage_type, spv::StorageClass::StorageBuffer)}; 155 const Id id{AddGlobalVariable(storage_type, spv::StorageClass::StorageBuffer)};
146 Decorate(id, spv::Decoration::Binding, binding); 156 Decorate(id, spv::Decoration::Binding, binding);
147 Decorate(id, spv::Decoration::DescriptorSet, 0U); 157 Decorate(id, spv::Decoration::DescriptorSet, 0U);
148 Name(id, fmt::format("ssbo{}", binding)); 158 Name(id, fmt::format("ssbo{}", index));
149 std::fill_n(ssbos.data() + binding, desc.count, id); 159 std::fill_n(ssbos.data() + index, desc.count, id);
160 index += desc.count;
150 binding += desc.count; 161 binding += desc.count;
151 } 162 }
152} 163}
diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/emit_context.h
index c4b84759d..8de203da2 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.h
+++ b/src/shader_recompiler/backend/spirv/emit_context.h
@@ -37,6 +37,8 @@ public:
37 37
38 Id void_id{}; 38 Id void_id{};
39 Id U1{}; 39 Id U1{};
40 Id U16{};
41 Id U64{};
40 VectorTypes F32; 42 VectorTypes F32;
41 VectorTypes U32; 43 VectorTypes U32;
42 VectorTypes F16; 44 VectorTypes F16;
@@ -59,8 +61,8 @@ private:
59 void DefineCommonTypes(const Info& info); 61 void DefineCommonTypes(const Info& info);
60 void DefineCommonConstants(); 62 void DefineCommonConstants();
61 void DefineSpecialVariables(const Info& info); 63 void DefineSpecialVariables(const Info& info);
62 void DefineConstantBuffers(const Info& info); 64 void DefineConstantBuffers(const Info& info, u32& binding);
63 void DefineStorageBuffers(const Info& info); 65 void DefineStorageBuffers(const Info& info, u32& binding);
64 void DefineLabels(IR::Program& program); 66 void DefineLabels(IR::Program& program);
65}; 67};
66 68
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
index d59718435..4ce07c281 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
@@ -14,6 +14,8 @@
14#include "shader_recompiler/frontend/ir/microinstruction.h" 14#include "shader_recompiler/frontend/ir/microinstruction.h"
15#include "shader_recompiler/frontend/ir/program.h" 15#include "shader_recompiler/frontend/ir/program.h"
16 16
17#pragma optimize("", off)
18
17namespace Shader::Backend::SPIRV { 19namespace Shader::Backend::SPIRV {
18namespace { 20namespace {
19template <class Func> 21template <class Func>
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h
index 5813f51ff..2b59c0b72 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.h
@@ -79,26 +79,27 @@ void EmitWriteStorageU16(EmitContext& ctx);
79void EmitWriteStorageS16(EmitContext& ctx); 79void EmitWriteStorageS16(EmitContext& ctx);
80void EmitWriteStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, 80void EmitWriteStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
81 Id value); 81 Id value);
82void EmitWriteStorage64(EmitContext& ctx); 82void EmitWriteStorage64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
83 Id value);
83void EmitWriteStorage128(EmitContext& ctx); 84void EmitWriteStorage128(EmitContext& ctx);
84void EmitCompositeConstructU32x2(EmitContext& ctx); 85Id EmitCompositeConstructU32x2(EmitContext& ctx, Id e1, Id e2);
85void EmitCompositeConstructU32x3(EmitContext& ctx); 86Id EmitCompositeConstructU32x3(EmitContext& ctx, Id e1, Id e2, Id e3);
86void EmitCompositeConstructU32x4(EmitContext& ctx); 87Id EmitCompositeConstructU32x4(EmitContext& ctx, Id e1, Id e2, Id e3, Id e4);
87void EmitCompositeExtractU32x2(EmitContext& ctx); 88Id EmitCompositeExtractU32x2(EmitContext& ctx, Id composite, u32 index);
88Id EmitCompositeExtractU32x3(EmitContext& ctx, Id vector, u32 index); 89Id EmitCompositeExtractU32x3(EmitContext& ctx, Id composite, u32 index);
89void EmitCompositeExtractU32x4(EmitContext& ctx); 90Id EmitCompositeExtractU32x4(EmitContext& ctx, Id composite, u32 index);
90void EmitCompositeConstructF16x2(EmitContext& ctx); 91void EmitCompositeConstructF16x2(EmitContext& ctx);
91void EmitCompositeConstructF16x3(EmitContext& ctx); 92void EmitCompositeConstructF16x3(EmitContext& ctx);
92void EmitCompositeConstructF16x4(EmitContext& ctx); 93void EmitCompositeConstructF16x4(EmitContext& ctx);
93void EmitCompositeExtractF16x2(EmitContext& ctx); 94Id EmitCompositeExtractF16x2(EmitContext& ctx, Id composite, u32 index);
94void EmitCompositeExtractF16x3(EmitContext& ctx); 95Id EmitCompositeExtractF16x3(EmitContext& ctx, Id composite, u32 index);
95void EmitCompositeExtractF16x4(EmitContext& ctx); 96Id EmitCompositeExtractF16x4(EmitContext& ctx, Id composite, u32 index);
96void EmitCompositeConstructF32x2(EmitContext& ctx); 97void EmitCompositeConstructF32x2(EmitContext& ctx);
97void EmitCompositeConstructF32x3(EmitContext& ctx); 98void EmitCompositeConstructF32x3(EmitContext& ctx);
98void EmitCompositeConstructF32x4(EmitContext& ctx); 99void EmitCompositeConstructF32x4(EmitContext& ctx);
99void EmitCompositeExtractF32x2(EmitContext& ctx); 100Id EmitCompositeExtractF32x2(EmitContext& ctx, Id composite, u32 index);
100void EmitCompositeExtractF32x3(EmitContext& ctx); 101Id EmitCompositeExtractF32x3(EmitContext& ctx, Id composite, u32 index);
101void EmitCompositeExtractF32x4(EmitContext& ctx); 102Id EmitCompositeExtractF32x4(EmitContext& ctx, Id composite, u32 index);
102void EmitCompositeConstructF64x2(EmitContext& ctx); 103void EmitCompositeConstructF64x2(EmitContext& ctx);
103void EmitCompositeConstructF64x3(EmitContext& ctx); 104void EmitCompositeConstructF64x3(EmitContext& ctx);
104void EmitCompositeConstructF64x4(EmitContext& ctx); 105void EmitCompositeConstructF64x4(EmitContext& ctx);
@@ -116,11 +117,13 @@ void EmitBitCastF16U16(EmitContext& ctx);
116Id EmitBitCastF32U32(EmitContext& ctx, Id value); 117Id EmitBitCastF32U32(EmitContext& ctx, Id value);
117void EmitBitCastF64U64(EmitContext& ctx); 118void EmitBitCastF64U64(EmitContext& ctx);
118void EmitPackUint2x32(EmitContext& ctx); 119void EmitPackUint2x32(EmitContext& ctx);
119void EmitUnpackUint2x32(EmitContext& ctx); 120Id EmitUnpackUint2x32(EmitContext& ctx, Id value);
120void EmitPackFloat2x16(EmitContext& ctx); 121Id EmitPackFloat2x16(EmitContext& ctx, Id value);
121void EmitUnpackFloat2x16(EmitContext& ctx); 122Id EmitUnpackFloat2x16(EmitContext& ctx, Id value);
122void EmitPackDouble2x32(EmitContext& ctx); 123Id EmitPackHalf2x16(EmitContext& ctx, Id value);
123void EmitUnpackDouble2x32(EmitContext& ctx); 124Id EmitUnpackHalf2x16(EmitContext& ctx, Id value);
125Id EmitPackDouble2x32(EmitContext& ctx, Id value);
126Id EmitUnpackDouble2x32(EmitContext& ctx, Id value);
124void EmitGetZeroFromOp(EmitContext& ctx); 127void EmitGetZeroFromOp(EmitContext& ctx);
125void EmitGetSignFromOp(EmitContext& ctx); 128void EmitGetSignFromOp(EmitContext& ctx);
126void EmitGetCarryFromOp(EmitContext& ctx); 129void EmitGetCarryFromOp(EmitContext& ctx);
@@ -159,18 +162,18 @@ void EmitFPLog2(EmitContext& ctx);
159void EmitFPSaturate16(EmitContext& ctx); 162void EmitFPSaturate16(EmitContext& ctx);
160void EmitFPSaturate32(EmitContext& ctx); 163void EmitFPSaturate32(EmitContext& ctx);
161void EmitFPSaturate64(EmitContext& ctx); 164void EmitFPSaturate64(EmitContext& ctx);
162void EmitFPRoundEven16(EmitContext& ctx); 165Id EmitFPRoundEven16(EmitContext& ctx, Id value);
163void EmitFPRoundEven32(EmitContext& ctx); 166Id EmitFPRoundEven32(EmitContext& ctx, Id value);
164void EmitFPRoundEven64(EmitContext& ctx); 167Id EmitFPRoundEven64(EmitContext& ctx, Id value);
165void EmitFPFloor16(EmitContext& ctx); 168Id EmitFPFloor16(EmitContext& ctx, Id value);
166void EmitFPFloor32(EmitContext& ctx); 169Id EmitFPFloor32(EmitContext& ctx, Id value);
167void EmitFPFloor64(EmitContext& ctx); 170Id EmitFPFloor64(EmitContext& ctx, Id value);
168void EmitFPCeil16(EmitContext& ctx); 171Id EmitFPCeil16(EmitContext& ctx, Id value);
169void EmitFPCeil32(EmitContext& ctx); 172Id EmitFPCeil32(EmitContext& ctx, Id value);
170void EmitFPCeil64(EmitContext& ctx); 173Id EmitFPCeil64(EmitContext& ctx, Id value);
171void EmitFPTrunc16(EmitContext& ctx); 174Id EmitFPTrunc16(EmitContext& ctx, Id value);
172void EmitFPTrunc32(EmitContext& ctx); 175Id EmitFPTrunc32(EmitContext& ctx, Id value);
173void EmitFPTrunc64(EmitContext& ctx); 176Id EmitFPTrunc64(EmitContext& ctx, Id value);
174Id EmitIAdd32(EmitContext& ctx, IR::Inst* inst, Id a, Id b); 177Id EmitIAdd32(EmitContext& ctx, IR::Inst* inst, Id a, Id b);
175void EmitIAdd64(EmitContext& ctx); 178void EmitIAdd64(EmitContext& ctx);
176Id EmitISub32(EmitContext& ctx, Id a, Id b); 179Id EmitISub32(EmitContext& ctx, Id a, Id b);
@@ -201,25 +204,25 @@ void EmitLogicalOr(EmitContext& ctx);
201void EmitLogicalAnd(EmitContext& ctx); 204void EmitLogicalAnd(EmitContext& ctx);
202void EmitLogicalXor(EmitContext& ctx); 205void EmitLogicalXor(EmitContext& ctx);
203void EmitLogicalNot(EmitContext& ctx); 206void EmitLogicalNot(EmitContext& ctx);
204void EmitConvertS16F16(EmitContext& ctx); 207Id EmitConvertS16F16(EmitContext& ctx, Id value);
205void EmitConvertS16F32(EmitContext& ctx); 208Id EmitConvertS16F32(EmitContext& ctx, Id value);
206void EmitConvertS16F64(EmitContext& ctx); 209Id EmitConvertS16F64(EmitContext& ctx, Id value);
207void EmitConvertS32F16(EmitContext& ctx); 210Id EmitConvertS32F16(EmitContext& ctx, Id value);
208void EmitConvertS32F32(EmitContext& ctx); 211Id EmitConvertS32F32(EmitContext& ctx, Id value);
209void EmitConvertS32F64(EmitContext& ctx); 212Id EmitConvertS32F64(EmitContext& ctx, Id value);
210void EmitConvertS64F16(EmitContext& ctx); 213Id EmitConvertS64F16(EmitContext& ctx, Id value);
211void EmitConvertS64F32(EmitContext& ctx); 214Id EmitConvertS64F32(EmitContext& ctx, Id value);
212void EmitConvertS64F64(EmitContext& ctx); 215Id EmitConvertS64F64(EmitContext& ctx, Id value);
213void EmitConvertU16F16(EmitContext& ctx); 216Id EmitConvertU16F16(EmitContext& ctx, Id value);
214void EmitConvertU16F32(EmitContext& ctx); 217Id EmitConvertU16F32(EmitContext& ctx, Id value);
215void EmitConvertU16F64(EmitContext& ctx); 218Id EmitConvertU16F64(EmitContext& ctx, Id value);
216void EmitConvertU32F16(EmitContext& ctx); 219Id EmitConvertU32F16(EmitContext& ctx, Id value);
217void EmitConvertU32F32(EmitContext& ctx); 220Id EmitConvertU32F32(EmitContext& ctx, Id value);
218void EmitConvertU32F64(EmitContext& ctx); 221Id EmitConvertU32F64(EmitContext& ctx, Id value);
219void EmitConvertU64F16(EmitContext& ctx); 222Id EmitConvertU64F16(EmitContext& ctx, Id value);
220void EmitConvertU64F32(EmitContext& ctx); 223Id EmitConvertU64F32(EmitContext& ctx, Id value);
221void EmitConvertU64F64(EmitContext& ctx); 224Id EmitConvertU64F64(EmitContext& ctx, Id value);
222void EmitConvertU64U32(EmitContext& ctx); 225Id EmitConvertU64U32(EmitContext& ctx, Id value);
223void EmitConvertU32U64(EmitContext& ctx); 226Id EmitConvertU32U64(EmitContext& ctx, Id value);
224 227
225} // namespace Shader::Backend::SPIRV 228} // namespace Shader::Backend::SPIRV
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp
index 49c200498..e0d1ba413 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp
@@ -34,24 +34,32 @@ void EmitPackUint2x32(EmitContext&) {
34 throw NotImplementedException("SPIR-V Instruction"); 34 throw NotImplementedException("SPIR-V Instruction");
35} 35}
36 36
37void EmitUnpackUint2x32(EmitContext&) { 37Id EmitUnpackUint2x32(EmitContext& ctx, Id value) {
38 throw NotImplementedException("SPIR-V Instruction"); 38 return ctx.OpBitcast(ctx.U32[2], value);
39} 39}
40 40
41void EmitPackFloat2x16(EmitContext&) { 41Id EmitPackFloat2x16(EmitContext& ctx, Id value) {
42 throw NotImplementedException("SPIR-V Instruction"); 42 return ctx.OpBitcast(ctx.U32[1], value);
43} 43}
44 44
45void EmitUnpackFloat2x16(EmitContext&) { 45Id EmitUnpackFloat2x16(EmitContext& ctx, Id value) {
46 throw NotImplementedException("SPIR-V Instruction"); 46 return ctx.OpBitcast(ctx.F16[2], value);
47} 47}
48 48
49void EmitPackDouble2x32(EmitContext&) { 49Id EmitPackHalf2x16(EmitContext& ctx, Id value) {
50 throw NotImplementedException("SPIR-V Instruction"); 50 return ctx.OpPackHalf2x16(ctx.U32[1], value);
51} 51}
52 52
53void EmitUnpackDouble2x32(EmitContext&) { 53Id EmitUnpackHalf2x16(EmitContext& ctx, Id value) {
54 throw NotImplementedException("SPIR-V Instruction"); 54 return ctx.OpUnpackHalf2x16(ctx.F32[2], value);
55}
56
57Id EmitPackDouble2x32(EmitContext& ctx, Id value) {
58 return ctx.OpBitcast(ctx.F64[1], value);
59}
60
61Id EmitUnpackDouble2x32(EmitContext& ctx, Id value) {
62 return ctx.OpBitcast(ctx.U32[2], value);
55} 63}
56 64
57} // namespace Shader::Backend::SPIRV 65} // namespace Shader::Backend::SPIRV
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_composite.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_composite.cpp
index 348e4796d..c950854a0 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_composite.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_composite.cpp
@@ -6,28 +6,28 @@
6 6
7namespace Shader::Backend::SPIRV { 7namespace Shader::Backend::SPIRV {
8 8
9void EmitCompositeConstructU32x2(EmitContext&) { 9Id EmitCompositeConstructU32x2(EmitContext& ctx, Id e1, Id e2) {
10 throw NotImplementedException("SPIR-V Instruction"); 10 return ctx.OpCompositeConstruct(ctx.U32[2], e1, e2);
11} 11}
12 12
13void EmitCompositeConstructU32x3(EmitContext&) { 13Id EmitCompositeConstructU32x3(EmitContext& ctx, Id e1, Id e2, Id e3) {
14 throw NotImplementedException("SPIR-V Instruction"); 14 return ctx.OpCompositeConstruct(ctx.U32[3], e1, e2, e3);
15} 15}
16 16
17void EmitCompositeConstructU32x4(EmitContext&) { 17Id EmitCompositeConstructU32x4(EmitContext& ctx, Id e1, Id e2, Id e3, Id e4) {
18 throw NotImplementedException("SPIR-V Instruction"); 18 return ctx.OpCompositeConstruct(ctx.U32[4], e1, e2, e3, e4);
19} 19}
20 20
21void EmitCompositeExtractU32x2(EmitContext&) { 21Id EmitCompositeExtractU32x2(EmitContext& ctx, Id composite, u32 index) {
22 throw NotImplementedException("SPIR-V Instruction"); 22 return ctx.OpCompositeExtract(ctx.U32[1], composite, index);
23} 23}
24 24
25Id EmitCompositeExtractU32x3(EmitContext& ctx, Id vector, u32 index) { 25Id EmitCompositeExtractU32x3(EmitContext& ctx, Id composite, u32 index) {
26 return ctx.OpCompositeExtract(ctx.U32[1], vector, index); 26 return ctx.OpCompositeExtract(ctx.U32[1], composite, index);
27} 27}
28 28
29void EmitCompositeExtractU32x4(EmitContext&) { 29Id EmitCompositeExtractU32x4(EmitContext& ctx, Id composite, u32 index) {
30 throw NotImplementedException("SPIR-V Instruction"); 30 return ctx.OpCompositeExtract(ctx.U32[1], composite, index);
31} 31}
32 32
33void EmitCompositeConstructF16x2(EmitContext&) { 33void EmitCompositeConstructF16x2(EmitContext&) {
@@ -42,16 +42,16 @@ void EmitCompositeConstructF16x4(EmitContext&) {
42 throw NotImplementedException("SPIR-V Instruction"); 42 throw NotImplementedException("SPIR-V Instruction");
43} 43}
44 44
45void EmitCompositeExtractF16x2(EmitContext&) { 45Id EmitCompositeExtractF16x2(EmitContext& ctx, Id composite, u32 index) {
46 throw NotImplementedException("SPIR-V Instruction"); 46 return ctx.OpCompositeExtract(ctx.F16[1], composite, index);
47} 47}
48 48
49void EmitCompositeExtractF16x3(EmitContext&) { 49Id EmitCompositeExtractF16x3(EmitContext& ctx, Id composite, u32 index) {
50 throw NotImplementedException("SPIR-V Instruction"); 50 return ctx.OpCompositeExtract(ctx.F16[1], composite, index);
51} 51}
52 52
53void EmitCompositeExtractF16x4(EmitContext&) { 53Id EmitCompositeExtractF16x4(EmitContext& ctx, Id composite, u32 index) {
54 throw NotImplementedException("SPIR-V Instruction"); 54 return ctx.OpCompositeExtract(ctx.F16[1], composite, index);
55} 55}
56 56
57void EmitCompositeConstructF32x2(EmitContext&) { 57void EmitCompositeConstructF32x2(EmitContext&) {
@@ -66,16 +66,16 @@ void EmitCompositeConstructF32x4(EmitContext&) {
66 throw NotImplementedException("SPIR-V Instruction"); 66 throw NotImplementedException("SPIR-V Instruction");
67} 67}
68 68
69void EmitCompositeExtractF32x2(EmitContext&) { 69Id EmitCompositeExtractF32x2(EmitContext& ctx, Id composite, u32 index) {
70 throw NotImplementedException("SPIR-V Instruction"); 70 return ctx.OpCompositeExtract(ctx.F32[1], composite, index);
71} 71}
72 72
73void EmitCompositeExtractF32x3(EmitContext&) { 73Id EmitCompositeExtractF32x3(EmitContext& ctx, Id composite, u32 index) {
74 throw NotImplementedException("SPIR-V Instruction"); 74 return ctx.OpCompositeExtract(ctx.F32[1], composite, index);
75} 75}
76 76
77void EmitCompositeExtractF32x4(EmitContext&) { 77Id EmitCompositeExtractF32x4(EmitContext& ctx, Id composite, u32 index) {
78 throw NotImplementedException("SPIR-V Instruction"); 78 return ctx.OpCompositeExtract(ctx.F32[1], composite, index);
79} 79}
80 80
81void EmitCompositeConstructF64x2(EmitContext&) { 81void EmitCompositeConstructF64x2(EmitContext&) {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp
index 6c4199664..48755b827 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp
@@ -11,7 +11,7 @@ void EmitBranch(EmitContext& ctx, IR::Block* label) {
11} 11}
12 12
13void EmitBranchConditional(EmitContext& ctx, Id condition, IR::Block* true_label, 13void EmitBranchConditional(EmitContext& ctx, Id condition, IR::Block* true_label,
14 IR::Block* false_label) { 14 IR::Block* false_label) {
15 ctx.OpBranchConditional(condition, true_label->Definition<Id>(), false_label->Definition<Id>()); 15 ctx.OpBranchConditional(condition, true_label->Definition<Id>(), false_label->Definition<Id>());
16} 16}
17 17
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp
new file mode 100644
index 000000000..76ccaffce
--- /dev/null
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp
@@ -0,0 +1,89 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "shader_recompiler/backend/spirv/emit_spirv.h"
6
7namespace Shader::Backend::SPIRV {
8
9Id EmitConvertS16F16(EmitContext& ctx, Id value) {
10 return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToS(ctx.U16, value));
11}
12
13Id EmitConvertS16F32(EmitContext& ctx, Id value) {
14 return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToS(ctx.U16, value));
15}
16
17Id EmitConvertS16F64(EmitContext& ctx, Id value) {
18 return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToS(ctx.U16, value));
19}
20
21Id EmitConvertS32F16(EmitContext& ctx, Id value) {
22 return ctx.OpConvertFToS(ctx.U32[1], value);
23}
24
25Id EmitConvertS32F32(EmitContext& ctx, Id value) {
26 return ctx.OpConvertFToS(ctx.U32[1], value);
27}
28
29Id EmitConvertS32F64(EmitContext& ctx, Id value) {
30 return ctx.OpConvertFToS(ctx.U32[1], value);
31}
32
33Id EmitConvertS64F16(EmitContext& ctx, Id value) {
34 return ctx.OpConvertFToS(ctx.U64, value);
35}
36
37Id EmitConvertS64F32(EmitContext& ctx, Id value) {
38 return ctx.OpConvertFToS(ctx.U64, value);
39}
40
41Id EmitConvertS64F64(EmitContext& ctx, Id value) {
42 return ctx.OpConvertFToS(ctx.U64, value);
43}
44
45Id EmitConvertU16F16(EmitContext& ctx, Id value) {
46 return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToU(ctx.U16, value));
47}
48
49Id EmitConvertU16F32(EmitContext& ctx, Id value) {
50 return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToU(ctx.U16, value));
51}
52
53Id EmitConvertU16F64(EmitContext& ctx, Id value) {
54 return ctx.OpUConvert(ctx.U32[1], ctx.OpConvertFToU(ctx.U16, value));
55}
56
57Id EmitConvertU32F16(EmitContext& ctx, Id value) {
58 return ctx.OpConvertFToU(ctx.U32[1], value);
59}
60
61Id EmitConvertU32F32(EmitContext& ctx, Id value) {
62 return ctx.OpConvertFToU(ctx.U32[1], value);
63}
64
65Id EmitConvertU32F64(EmitContext& ctx, Id value) {
66 return ctx.OpConvertFToU(ctx.U32[1], value);
67}
68
69Id EmitConvertU64F16(EmitContext& ctx, Id value) {
70 return ctx.OpConvertFToU(ctx.U64, value);
71}
72
73Id EmitConvertU64F32(EmitContext& ctx, Id value) {
74 return ctx.OpConvertFToU(ctx.U64, value);
75}
76
77Id EmitConvertU64F64(EmitContext& ctx, Id value) {
78 return ctx.OpConvertFToU(ctx.U64, value);
79}
80
81Id EmitConvertU64U32(EmitContext& ctx, Id value) {
82 return ctx.OpUConvert(ctx.U64, value);
83}
84
85Id EmitConvertU32U64(EmitContext& ctx, Id value) {
86 return ctx.OpUConvert(ctx.U32[1], value);
87}
88
89} // namespace Shader::Backend::SPIRV
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp
index d24fbb353..9ef180531 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp
@@ -169,52 +169,52 @@ void EmitFPSaturate64(EmitContext&) {
169 throw NotImplementedException("SPIR-V Instruction"); 169 throw NotImplementedException("SPIR-V Instruction");
170} 170}
171 171
172void EmitFPRoundEven16(EmitContext&) { 172Id EmitFPRoundEven16(EmitContext& ctx, Id value) {
173 throw NotImplementedException("SPIR-V Instruction"); 173 return ctx.OpRoundEven(ctx.F16[1], value);
174} 174}
175 175
176void EmitFPRoundEven32(EmitContext&) { 176Id EmitFPRoundEven32(EmitContext& ctx, Id value) {
177 throw NotImplementedException("SPIR-V Instruction"); 177 return ctx.OpRoundEven(ctx.F32[1], value);
178} 178}
179 179
180void EmitFPRoundEven64(EmitContext&) { 180Id EmitFPRoundEven64(EmitContext& ctx, Id value) {
181 throw NotImplementedException("SPIR-V Instruction"); 181 return ctx.OpRoundEven(ctx.F64[1], value);
182} 182}
183 183
184void EmitFPFloor16(EmitContext&) { 184Id EmitFPFloor16(EmitContext& ctx, Id value) {
185 throw NotImplementedException("SPIR-V Instruction"); 185 return ctx.OpFloor(ctx.F16[1], value);
186} 186}
187 187
188void EmitFPFloor32(EmitContext&) { 188Id EmitFPFloor32(EmitContext& ctx, Id value) {
189 throw NotImplementedException("SPIR-V Instruction"); 189 return ctx.OpFloor(ctx.F32[1], value);
190} 190}
191 191
192void EmitFPFloor64(EmitContext&) { 192Id EmitFPFloor64(EmitContext& ctx, Id value) {
193 throw NotImplementedException("SPIR-V Instruction"); 193 return ctx.OpFloor(ctx.F64[1], value);
194} 194}
195 195
196void EmitFPCeil16(EmitContext&) { 196Id EmitFPCeil16(EmitContext& ctx, Id value) {
197 throw NotImplementedException("SPIR-V Instruction"); 197 return ctx.OpCeil(ctx.F16[1], value);
198} 198}
199 199
200void EmitFPCeil32(EmitContext&) { 200Id EmitFPCeil32(EmitContext& ctx, Id value) {
201 throw NotImplementedException("SPIR-V Instruction"); 201 return ctx.OpCeil(ctx.F32[1], value);
202} 202}
203 203
204void EmitFPCeil64(EmitContext&) { 204Id EmitFPCeil64(EmitContext& ctx, Id value) {
205 throw NotImplementedException("SPIR-V Instruction"); 205 return ctx.OpCeil(ctx.F64[1], value);
206} 206}
207 207
208void EmitFPTrunc16(EmitContext&) { 208Id EmitFPTrunc16(EmitContext& ctx, Id value) {
209 throw NotImplementedException("SPIR-V Instruction"); 209 return ctx.OpTrunc(ctx.F16[1], value);
210} 210}
211 211
212void EmitFPTrunc32(EmitContext&) { 212Id EmitFPTrunc32(EmitContext& ctx, Id value) {
213 throw NotImplementedException("SPIR-V Instruction"); 213 return ctx.OpTrunc(ctx.F32[1], value);
214} 214}
215 215
216void EmitFPTrunc64(EmitContext&) { 216Id EmitFPTrunc64(EmitContext& ctx, Id value) {
217 throw NotImplementedException("SPIR-V Instruction"); 217 return ctx.OpTrunc(ctx.F64[1], value);
218} 218}
219 219
220} // namespace Shader::Backend::SPIRV 220} // namespace Shader::Backend::SPIRV
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp
index a1d16b81e..22117a4ee 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp
@@ -113,20 +113,4 @@ Id EmitUGreaterThanEqual(EmitContext& ctx, Id lhs, Id rhs) {
113 return ctx.OpUGreaterThanEqual(ctx.U1, lhs, rhs); 113 return ctx.OpUGreaterThanEqual(ctx.U1, lhs, rhs);
114} 114}
115 115
116void EmitLogicalOr(EmitContext&) {
117 throw NotImplementedException("SPIR-V Instruction");
118}
119
120void EmitLogicalAnd(EmitContext&) {
121 throw NotImplementedException("SPIR-V Instruction");
122}
123
124void EmitLogicalXor(EmitContext&) {
125 throw NotImplementedException("SPIR-V Instruction");
126}
127
128void EmitLogicalNot(EmitContext&) {
129 throw NotImplementedException("SPIR-V Instruction");
130}
131
132} // namespace Shader::Backend::SPIRV 116} // namespace Shader::Backend::SPIRV
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp
index ff2f4fb74..c5a07252f 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp
@@ -6,83 +6,19 @@
6 6
7namespace Shader::Backend::SPIRV { 7namespace Shader::Backend::SPIRV {
8 8
9void EmitConvertS16F16(EmitContext&) { 9void EmitLogicalOr(EmitContext&) {
10 throw NotImplementedException("SPIR-V Instruction"); 10 throw NotImplementedException("SPIR-V Instruction");
11} 11}
12 12
13void EmitConvertS16F32(EmitContext&) { 13void EmitLogicalAnd(EmitContext&) {
14 throw NotImplementedException("SPIR-V Instruction"); 14 throw NotImplementedException("SPIR-V Instruction");
15} 15}
16 16
17void EmitConvertS16F64(EmitContext&) { 17void EmitLogicalXor(EmitContext&) {
18 throw NotImplementedException("SPIR-V Instruction"); 18 throw NotImplementedException("SPIR-V Instruction");
19} 19}
20 20
21void EmitConvertS32F16(EmitContext&) { 21void EmitLogicalNot(EmitContext&) {
22 throw NotImplementedException("SPIR-V Instruction");
23}
24
25void EmitConvertS32F32(EmitContext&) {
26 throw NotImplementedException("SPIR-V Instruction");
27}
28
29void EmitConvertS32F64(EmitContext&) {
30 throw NotImplementedException("SPIR-V Instruction");
31}
32
33void EmitConvertS64F16(EmitContext&) {
34 throw NotImplementedException("SPIR-V Instruction");
35}
36
37void EmitConvertS64F32(EmitContext&) {
38 throw NotImplementedException("SPIR-V Instruction");
39}
40
41void EmitConvertS64F64(EmitContext&) {
42 throw NotImplementedException("SPIR-V Instruction");
43}
44
45void EmitConvertU16F16(EmitContext&) {
46 throw NotImplementedException("SPIR-V Instruction");
47}
48
49void EmitConvertU16F32(EmitContext&) {
50 throw NotImplementedException("SPIR-V Instruction");
51}
52
53void EmitConvertU16F64(EmitContext&) {
54 throw NotImplementedException("SPIR-V Instruction");
55}
56
57void EmitConvertU32F16(EmitContext&) {
58 throw NotImplementedException("SPIR-V Instruction");
59}
60
61void EmitConvertU32F32(EmitContext&) {
62 throw NotImplementedException("SPIR-V Instruction");
63}
64
65void EmitConvertU32F64(EmitContext&) {
66 throw NotImplementedException("SPIR-V Instruction");
67}
68
69void EmitConvertU64F16(EmitContext&) {
70 throw NotImplementedException("SPIR-V Instruction");
71}
72
73void EmitConvertU64F32(EmitContext&) {
74 throw NotImplementedException("SPIR-V Instruction");
75}
76
77void EmitConvertU64F64(EmitContext&) {
78 throw NotImplementedException("SPIR-V Instruction");
79}
80
81void EmitConvertU64U32(EmitContext&) {
82 throw NotImplementedException("SPIR-V Instruction");
83}
84
85void EmitConvertU32U64(EmitContext&) {
86 throw NotImplementedException("SPIR-V Instruction"); 22 throw NotImplementedException("SPIR-V Instruction");
87} 23}
88 24
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp
index 77d698ffd..808c1b401 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_memory.cpp
@@ -94,8 +94,7 @@ void EmitLoadStorageS16(EmitContext&) {
94 throw NotImplementedException("SPIR-V Instruction"); 94 throw NotImplementedException("SPIR-V Instruction");
95} 95}
96 96
97Id EmitLoadStorage32(EmitContext& ctx, const IR::Value& binding, 97Id EmitLoadStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
98 const IR::Value& offset) {
99 if (!binding.IsImmediate()) { 98 if (!binding.IsImmediate()) {
100 throw NotImplementedException("Dynamic storage buffer indexing"); 99 throw NotImplementedException("Dynamic storage buffer indexing");
101 } 100 }
@@ -129,8 +128,8 @@ void EmitWriteStorageS16(EmitContext&) {
129 throw NotImplementedException("SPIR-V Instruction"); 128 throw NotImplementedException("SPIR-V Instruction");
130} 129}
131 130
132void EmitWriteStorage32(EmitContext& ctx, const IR::Value& binding, 131void EmitWriteStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
133 const IR::Value& offset, Id value) { 132 Id value) {
134 if (!binding.IsImmediate()) { 133 if (!binding.IsImmediate()) {
135 throw NotImplementedException("Dynamic storage buffer indexing"); 134 throw NotImplementedException("Dynamic storage buffer indexing");
136 } 135 }
@@ -140,8 +139,19 @@ void EmitWriteStorage32(EmitContext& ctx, const IR::Value& binding,
140 ctx.OpStore(pointer, value); 139 ctx.OpStore(pointer, value);
141} 140}
142 141
143void EmitWriteStorage64(EmitContext&) { 142void EmitWriteStorage64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
144 throw NotImplementedException("SPIR-V Instruction"); 143 Id value) {
144 if (!binding.IsImmediate()) {
145 throw NotImplementedException("Dynamic storage buffer indexing");
146 }
147 // TODO: Support reinterpreting bindings, guaranteed to be aligned
148 const Id ssbo{ctx.ssbos[binding.U32()]};
149 const Id low_index{StorageIndex(ctx, offset, sizeof(u32))};
150 const Id high_index{ctx.OpIAdd(ctx.U32[1], low_index, ctx.Constant(ctx.U32[1], 1U))};
151 const Id low_pointer{ctx.OpAccessChain(ctx.storage_u32, ssbo, ctx.u32_zero_value, low_index)};
152 const Id high_pointer{ctx.OpAccessChain(ctx.storage_u32, ssbo, ctx.u32_zero_value, high_index)};
153 ctx.OpStore(low_pointer, ctx.OpCompositeExtract(ctx.U32[1], value, 0U));
154 ctx.OpStore(high_pointer, ctx.OpCompositeExtract(ctx.U32[1], value, 1U));
145} 155}
146 156
147void EmitWriteStorage128(EmitContext&) { 157void EmitWriteStorage128(EmitContext&) {
diff --git a/src/shader_recompiler/frontend/ir/condition.h b/src/shader_recompiler/frontend/ir/condition.h
index 16b4ae888..51c2f15cf 100644
--- a/src/shader_recompiler/frontend/ir/condition.h
+++ b/src/shader_recompiler/frontend/ir/condition.h
@@ -4,8 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <string>
8#include <compare> 7#include <compare>
8#include <string>
9 9
10#include <fmt/format.h> 10#include <fmt/format.h>
11 11
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
index f42489d41..559ab9cca 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
@@ -547,11 +547,11 @@ F32 IREmitter::FPSqrt(const F32& value) {
547 547
548F16F32F64 IREmitter::FPSaturate(const F16F32F64& value) { 548F16F32F64 IREmitter::FPSaturate(const F16F32F64& value) {
549 switch (value.Type()) { 549 switch (value.Type()) {
550 case Type::U16: 550 case Type::F16:
551 return Inst<F16>(Opcode::FPSaturate16, value); 551 return Inst<F16>(Opcode::FPSaturate16, value);
552 case Type::U32: 552 case Type::F32:
553 return Inst<F32>(Opcode::FPSaturate32, value); 553 return Inst<F32>(Opcode::FPSaturate32, value);
554 case Type::U64: 554 case Type::F64:
555 return Inst<F64>(Opcode::FPSaturate64, value); 555 return Inst<F64>(Opcode::FPSaturate64, value);
556 default: 556 default:
557 ThrowInvalidType(value.Type()); 557 ThrowInvalidType(value.Type());
@@ -560,11 +560,11 @@ F16F32F64 IREmitter::FPSaturate(const F16F32F64& value) {
560 560
561F16F32F64 IREmitter::FPRoundEven(const F16F32F64& value) { 561F16F32F64 IREmitter::FPRoundEven(const F16F32F64& value) {
562 switch (value.Type()) { 562 switch (value.Type()) {
563 case Type::U16: 563 case Type::F16:
564 return Inst<F16>(Opcode::FPRoundEven16, value); 564 return Inst<F16>(Opcode::FPRoundEven16, value);
565 case Type::U32: 565 case Type::F32:
566 return Inst<F32>(Opcode::FPRoundEven32, value); 566 return Inst<F32>(Opcode::FPRoundEven32, value);
567 case Type::U64: 567 case Type::F64:
568 return Inst<F64>(Opcode::FPRoundEven64, value); 568 return Inst<F64>(Opcode::FPRoundEven64, value);
569 default: 569 default:
570 ThrowInvalidType(value.Type()); 570 ThrowInvalidType(value.Type());
@@ -573,11 +573,11 @@ F16F32F64 IREmitter::FPRoundEven(const F16F32F64& value) {
573 573
574F16F32F64 IREmitter::FPFloor(const F16F32F64& value) { 574F16F32F64 IREmitter::FPFloor(const F16F32F64& value) {
575 switch (value.Type()) { 575 switch (value.Type()) {
576 case Type::U16: 576 case Type::F16:
577 return Inst<F16>(Opcode::FPFloor16, value); 577 return Inst<F16>(Opcode::FPFloor16, value);
578 case Type::U32: 578 case Type::F32:
579 return Inst<F32>(Opcode::FPFloor32, value); 579 return Inst<F32>(Opcode::FPFloor32, value);
580 case Type::U64: 580 case Type::F64:
581 return Inst<F64>(Opcode::FPFloor64, value); 581 return Inst<F64>(Opcode::FPFloor64, value);
582 default: 582 default:
583 ThrowInvalidType(value.Type()); 583 ThrowInvalidType(value.Type());
@@ -586,11 +586,11 @@ F16F32F64 IREmitter::FPFloor(const F16F32F64& value) {
586 586
587F16F32F64 IREmitter::FPCeil(const F16F32F64& value) { 587F16F32F64 IREmitter::FPCeil(const F16F32F64& value) {
588 switch (value.Type()) { 588 switch (value.Type()) {
589 case Type::U16: 589 case Type::F16:
590 return Inst<F16>(Opcode::FPCeil16, value); 590 return Inst<F16>(Opcode::FPCeil16, value);
591 case Type::U32: 591 case Type::F32:
592 return Inst<F32>(Opcode::FPCeil32, value); 592 return Inst<F32>(Opcode::FPCeil32, value);
593 case Type::U64: 593 case Type::F64:
594 return Inst<F64>(Opcode::FPCeil64, value); 594 return Inst<F64>(Opcode::FPCeil64, value);
595 default: 595 default:
596 ThrowInvalidType(value.Type()); 596 ThrowInvalidType(value.Type());
@@ -599,11 +599,11 @@ F16F32F64 IREmitter::FPCeil(const F16F32F64& value) {
599 599
600F16F32F64 IREmitter::FPTrunc(const F16F32F64& value) { 600F16F32F64 IREmitter::FPTrunc(const F16F32F64& value) {
601 switch (value.Type()) { 601 switch (value.Type()) {
602 case Type::U16: 602 case Type::F16:
603 return Inst<F16>(Opcode::FPTrunc16, value); 603 return Inst<F16>(Opcode::FPTrunc16, value);
604 case Type::U32: 604 case Type::F32:
605 return Inst<F32>(Opcode::FPTrunc32, value); 605 return Inst<F32>(Opcode::FPTrunc32, value);
606 case Type::U64: 606 case Type::F64:
607 return Inst<F64>(Opcode::FPTrunc64, value); 607 return Inst<F64>(Opcode::FPTrunc64, value);
608 default: 608 default:
609 ThrowInvalidType(value.Type()); 609 ThrowInvalidType(value.Type());
@@ -729,33 +729,33 @@ U32U64 IREmitter::ConvertFToS(size_t bitsize, const F16F32F64& value) {
729 switch (bitsize) { 729 switch (bitsize) {
730 case 16: 730 case 16:
731 switch (value.Type()) { 731 switch (value.Type()) {
732 case Type::U16: 732 case Type::F16:
733 return Inst<U32>(Opcode::ConvertS16F16, value); 733 return Inst<U32>(Opcode::ConvertS16F16, value);
734 case Type::U32: 734 case Type::F32:
735 return Inst<U32>(Opcode::ConvertS16F32, value); 735 return Inst<U32>(Opcode::ConvertS16F32, value);
736 case Type::U64: 736 case Type::F64:
737 return Inst<U32>(Opcode::ConvertS16F64, value); 737 return Inst<U32>(Opcode::ConvertS16F64, value);
738 default: 738 default:
739 ThrowInvalidType(value.Type()); 739 ThrowInvalidType(value.Type());
740 } 740 }
741 case 32: 741 case 32:
742 switch (value.Type()) { 742 switch (value.Type()) {
743 case Type::U16: 743 case Type::F16:
744 return Inst<U32>(Opcode::ConvertS32F16, value); 744 return Inst<U32>(Opcode::ConvertS32F16, value);
745 case Type::U32: 745 case Type::F32:
746 return Inst<U32>(Opcode::ConvertS32F32, value); 746 return Inst<U32>(Opcode::ConvertS32F32, value);
747 case Type::U64: 747 case Type::F64:
748 return Inst<U32>(Opcode::ConvertS32F64, value); 748 return Inst<U32>(Opcode::ConvertS32F64, value);
749 default: 749 default:
750 ThrowInvalidType(value.Type()); 750 ThrowInvalidType(value.Type());
751 } 751 }
752 case 64: 752 case 64:
753 switch (value.Type()) { 753 switch (value.Type()) {
754 case Type::U16: 754 case Type::F16:
755 return Inst<U64>(Opcode::ConvertS64F16, value); 755 return Inst<U64>(Opcode::ConvertS64F16, value);
756 case Type::U32: 756 case Type::F32:
757 return Inst<U64>(Opcode::ConvertS64F32, value); 757 return Inst<U64>(Opcode::ConvertS64F32, value);
758 case Type::U64: 758 case Type::F64:
759 return Inst<U64>(Opcode::ConvertS64F64, value); 759 return Inst<U64>(Opcode::ConvertS64F64, value);
760 default: 760 default:
761 ThrowInvalidType(value.Type()); 761 ThrowInvalidType(value.Type());
@@ -769,33 +769,33 @@ U32U64 IREmitter::ConvertFToU(size_t bitsize, const F16F32F64& value) {
769 switch (bitsize) { 769 switch (bitsize) {
770 case 16: 770 case 16:
771 switch (value.Type()) { 771 switch (value.Type()) {
772 case Type::U16: 772 case Type::F16:
773 return Inst<U32>(Opcode::ConvertU16F16, value); 773 return Inst<U32>(Opcode::ConvertU16F16, value);
774 case Type::U32: 774 case Type::F32:
775 return Inst<U32>(Opcode::ConvertU16F32, value); 775 return Inst<U32>(Opcode::ConvertU16F32, value);
776 case Type::U64: 776 case Type::F64:
777 return Inst<U32>(Opcode::ConvertU16F64, value); 777 return Inst<U32>(Opcode::ConvertU16F64, value);
778 default: 778 default:
779 ThrowInvalidType(value.Type()); 779 ThrowInvalidType(value.Type());
780 } 780 }
781 case 32: 781 case 32:
782 switch (value.Type()) { 782 switch (value.Type()) {
783 case Type::U16: 783 case Type::F16:
784 return Inst<U32>(Opcode::ConvertU32F16, value); 784 return Inst<U32>(Opcode::ConvertU32F16, value);
785 case Type::U32: 785 case Type::F32:
786 return Inst<U32>(Opcode::ConvertU32F32, value); 786 return Inst<U32>(Opcode::ConvertU32F32, value);
787 case Type::U64: 787 case Type::F64:
788 return Inst<U32>(Opcode::ConvertU32F64, value); 788 return Inst<U32>(Opcode::ConvertU32F64, value);
789 default: 789 default:
790 ThrowInvalidType(value.Type()); 790 ThrowInvalidType(value.Type());
791 } 791 }
792 case 64: 792 case 64:
793 switch (value.Type()) { 793 switch (value.Type()) {
794 case Type::U16: 794 case Type::F16:
795 return Inst<U64>(Opcode::ConvertU64F16, value); 795 return Inst<U64>(Opcode::ConvertU64F16, value);
796 case Type::U32: 796 case Type::F32:
797 return Inst<U64>(Opcode::ConvertU64F32, value); 797 return Inst<U64>(Opcode::ConvertU64F32, value);
798 case Type::U64: 798 case Type::F64:
799 return Inst<U64>(Opcode::ConvertU64F64, value); 799 return Inst<U64>(Opcode::ConvertU64F64, value);
800 default: 800 default:
801 ThrowInvalidType(value.Type()); 801 ThrowInvalidType(value.Type());
@@ -829,10 +829,10 @@ U32U64 IREmitter::ConvertU(size_t result_bitsize, const U32U64& value) {
829 case 64: 829 case 64:
830 switch (value.Type()) { 830 switch (value.Type()) {
831 case Type::U32: 831 case Type::U32:
832 return Inst<U64>(Opcode::ConvertU64U32, value);
833 case Type::U64:
832 // Nothing to do 834 // Nothing to do
833 return value; 835 return value;
834 case Type::U64:
835 return Inst<U64>(Opcode::ConvertU64U32, value);
836 default: 836 default:
837 break; 837 break;
838 } 838 }
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.cpp b/src/shader_recompiler/frontend/ir/microinstruction.cpp
index ee76db9ad..d6a9be87d 100644
--- a/src/shader_recompiler/frontend/ir/microinstruction.cpp
+++ b/src/shader_recompiler/frontend/ir/microinstruction.cpp
@@ -216,6 +216,10 @@ void Inst::ReplaceUsesWith(Value replacement) {
216 } 216 }
217} 217}
218 218
219void Inst::ReplaceOpcode(IR::Opcode opcode) {
220 op = opcode;
221}
222
219void Inst::Use(const Value& value) { 223void Inst::Use(const Value& value) {
220 Inst* const inst{value.Inst()}; 224 Inst* const inst{value.Inst()};
221 ++inst->use_count; 225 ++inst->use_count;
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.h b/src/shader_recompiler/frontend/ir/microinstruction.h
index 5b244fa0b..321393dd7 100644
--- a/src/shader_recompiler/frontend/ir/microinstruction.h
+++ b/src/shader_recompiler/frontend/ir/microinstruction.h
@@ -86,6 +86,8 @@ public:
86 86
87 void ReplaceUsesWith(Value replacement); 87 void ReplaceUsesWith(Value replacement);
88 88
89 void ReplaceOpcode(IR::Opcode opcode);
90
89 template <typename FlagsType> 91 template <typename FlagsType>
90 requires(sizeof(FlagsType) <= sizeof(u32) && std::is_trivially_copyable_v<FlagsType>) 92 requires(sizeof(FlagsType) <= sizeof(u32) && std::is_trivially_copyable_v<FlagsType>)
91 [[nodiscard]] FlagsType Flags() const noexcept { 93 [[nodiscard]] FlagsType Flags() const noexcept {
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc
index ede5e20c2..50da77535 100644
--- a/src/shader_recompiler/frontend/ir/opcodes.inc
+++ b/src/shader_recompiler/frontend/ir/opcodes.inc
@@ -119,8 +119,10 @@ OPCODE(PackUint2x32, U64, U32x
119OPCODE(UnpackUint2x32, U32x2, U64, ) 119OPCODE(UnpackUint2x32, U32x2, U64, )
120OPCODE(PackFloat2x16, U32, F16x2, ) 120OPCODE(PackFloat2x16, U32, F16x2, )
121OPCODE(UnpackFloat2x16, F16x2, U32, ) 121OPCODE(UnpackFloat2x16, F16x2, U32, )
122OPCODE(PackDouble2x32, U64, U32x2, ) 122OPCODE(PackHalf2x16, U32, F32x2, )
123OPCODE(UnpackDouble2x32, U32x2, U64, ) 123OPCODE(UnpackHalf2x16, F32x2, U32, )
124OPCODE(PackDouble2x32, F64, U32x2, )
125OPCODE(UnpackDouble2x32, U32x2, F64, )
124 126
125// Pseudo-operation, handled specially at final emit 127// Pseudo-operation, handled specially at final emit
126OPCODE(GetZeroFromOp, U1, Opaque, ) 128OPCODE(GetZeroFromOp, U1, Opaque, )
diff --git a/src/shader_recompiler/frontend/ir/program.cpp b/src/shader_recompiler/frontend/ir/program.cpp
index 0ce99ef2a..8c301c3a1 100644
--- a/src/shader_recompiler/frontend/ir/program.cpp
+++ b/src/shader_recompiler/frontend/ir/program.cpp
@@ -35,4 +35,4 @@ std::string DumpProgram(const Program& program) {
35 return ret; 35 return ret;
36} 36}
37 37
38} // namespace Shader::IR \ No newline at end of file 38} // namespace Shader::IR
diff --git a/src/shader_recompiler/frontend/maxwell/program.cpp b/src/shader_recompiler/frontend/maxwell/program.cpp
index 8c44ebb29..16cdc12e2 100644
--- a/src/shader_recompiler/frontend/maxwell/program.cpp
+++ b/src/shader_recompiler/frontend/maxwell/program.cpp
@@ -56,6 +56,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
56 .post_order_blocks{}, 56 .post_order_blocks{},
57 }); 57 });
58 } 58 }
59 Optimization::LowerFp16ToFp32(program);
59 for (IR::Function& function : functions) { 60 for (IR::Function& function : functions) {
60 function.post_order_blocks = PostOrder(function.blocks); 61 function.post_order_blocks = PostOrder(function.blocks);
61 Optimization::SsaRewritePass(function.post_order_blocks); 62 Optimization::SsaRewritePass(function.post_order_blocks);
@@ -69,6 +70,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
69 Optimization::VerificationPass(function); 70 Optimization::VerificationPass(function);
70 } 71 }
71 Optimization::CollectShaderInfoPass(program); 72 Optimization::CollectShaderInfoPass(program);
73
72 fmt::print(stdout, "{}\n", IR::DumpProgram(program)); 74 fmt::print(stdout, "{}\n", IR::DumpProgram(program));
73 return program; 75 return program;
74} 76}
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp
index 3d0c48457..ae2d37405 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp
@@ -34,7 +34,7 @@ union F2I {
34 BitField<8, 2, DestFormat> dest_format; 34 BitField<8, 2, DestFormat> dest_format;
35 BitField<10, 2, SrcFormat> src_format; 35 BitField<10, 2, SrcFormat> src_format;
36 BitField<12, 1, u64> is_signed; 36 BitField<12, 1, u64> is_signed;
37 BitField<39, 1, Rounding> rounding; 37 BitField<39, 2, Rounding> rounding;
38 BitField<49, 1, u64> half; 38 BitField<49, 1, u64> half;
39 BitField<44, 1, u64> ftz; 39 BitField<44, 1, u64> ftz;
40 BitField<45, 1, u64> abs; 40 BitField<45, 1, u64> abs;
@@ -55,6 +55,28 @@ size_t BitSize(DestFormat dest_format) {
55 } 55 }
56} 56}
57 57
58IR::F64 UnpackCbuf(TranslatorVisitor& v, u64 insn) {
59 union {
60 u64 raw;
61 BitField<20, 14, s64> offset;
62 BitField<34, 5, u64> binding;
63 } const cbuf{insn};
64 if (cbuf.binding >= 18) {
65 throw NotImplementedException("Out of bounds constant buffer binding {}", cbuf.binding);
66 }
67 if (cbuf.offset >= 0x4'000 || cbuf.offset < 0) {
68 throw NotImplementedException("Out of bounds constant buffer offset {}", cbuf.offset * 4);
69 }
70 if (cbuf.offset % 2 != 0) {
71 throw NotImplementedException("Unaligned F64 constant buffer offset {}", cbuf.offset * 4);
72 }
73 const IR::U32 binding{v.ir.Imm32(static_cast<u32>(cbuf.binding))};
74 const IR::U32 byte_offset{v.ir.Imm32(static_cast<u32>(cbuf.offset) * 4 + 4)};
75 const IR::U32 cbuf_data{v.ir.GetCbuf(binding, byte_offset)};
76 const IR::Value vector{v.ir.CompositeConstruct(v.ir.Imm32(0U), cbuf_data)};
77 return v.ir.PackDouble2x32(vector);
78}
79
58void TranslateF2I(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a) { 80void TranslateF2I(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a) {
59 // F2I is used to convert from a floating point value to an integer 81 // F2I is used to convert from a floating point value to an integer
60 const F2I f2i{insn}; 82 const F2I f2i{insn};
@@ -82,19 +104,16 @@ void TranslateF2I(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a) {
82 const size_t bitsize{BitSize(f2i.dest_format)}; 104 const size_t bitsize{BitSize(f2i.dest_format)};
83 const IR::U16U32U64 result{v.ir.ConvertFToI(bitsize, is_signed, rounded_value)}; 105 const IR::U16U32U64 result{v.ir.ConvertFToI(bitsize, is_signed, rounded_value)};
84 106
85 v.X(f2i.dest_reg, result); 107 if (bitsize == 64) {
108 const IR::Value vector{v.ir.UnpackUint2x32(result)};
109 v.X(f2i.dest_reg + 0, IR::U32{v.ir.CompositeExtract(vector, 0)});
110 v.X(f2i.dest_reg + 1, IR::U32{v.ir.CompositeExtract(vector, 1)});
111 } else {
112 v.X(f2i.dest_reg, result);
113 }
86 114
87 if (f2i.cc != 0) { 115 if (f2i.cc != 0) {
88 v.SetZFlag(v.ir.GetZeroFromOp(result)); 116 throw NotImplementedException("F2I CC");
89 if (is_signed) {
90 v.SetSFlag(v.ir.GetSignFromOp(result));
91 } else {
92 v.ResetSFlag();
93 }
94 v.ResetCFlag();
95
96 // TODO: Investigate if out of bound conversions sets the overflow flag
97 v.ResetOFlag();
98 } 117 }
99} 118}
100} // Anonymous namespace 119} // Anonymous namespace
@@ -118,12 +137,25 @@ void TranslatorVisitor::F2I_reg(u64 insn) {
118 f2i.base.src_format.Value()); 137 f2i.base.src_format.Value());
119 } 138 }
120 }()}; 139 }()};
121
122 TranslateF2I(*this, insn, op_a); 140 TranslateF2I(*this, insn, op_a);
123} 141}
124 142
125void TranslatorVisitor::F2I_cbuf(u64) { 143void TranslatorVisitor::F2I_cbuf(u64 insn) {
126 throw NotImplementedException("{}", Opcode::F2I_cbuf); 144 const F2I f2i{insn};
145 const IR::F16F32F64 op_a{[&]() -> IR::F16F32F64 {
146 switch (f2i.src_format) {
147 case SrcFormat::F16:
148 return IR::F16{ir.CompositeExtract(ir.UnpackFloat2x16(GetCbuf(insn)), f2i.half)};
149 case SrcFormat::F32:
150 return GetCbufF(insn);
151 case SrcFormat::F64: {
152 return UnpackCbuf(*this, insn);
153 }
154 default:
155 throw NotImplementedException("Invalid F2I source format {}", f2i.src_format.Value());
156 }
157 }()};
158 TranslateF2I(*this, insn, op_a);
127} 159}
128 160
129void TranslatorVisitor::F2I_imm(u64) { 161void TranslatorVisitor::F2I_imm(u64) {
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
index 8bd468244..27aba2cf8 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
@@ -11,7 +11,7 @@ namespace Shader::Maxwell {
11 11
12class TranslatorVisitor { 12class TranslatorVisitor {
13public: 13public:
14 explicit TranslatorVisitor(Environment& env_, IR::Block& block) : env{env_} ,ir(block) {} 14 explicit TranslatorVisitor(Environment& env_, IR::Block& block) : env{env_}, ir(block) {}
15 15
16 Environment& env; 16 Environment& env;
17 IR::IREmitter ir; 17 IR::IREmitter ir;
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 f2326dea1..f7f102f53 100644
--- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
+++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
@@ -26,6 +26,22 @@ void Visit(Info& info, IR::Inst& inst) {
26 case IR::Opcode::LocalInvocationId: 26 case IR::Opcode::LocalInvocationId:
27 info.uses_local_invocation_id = true; 27 info.uses_local_invocation_id = true;
28 break; 28 break;
29 case IR::Opcode::CompositeConstructF16x2:
30 case IR::Opcode::CompositeConstructF16x3:
31 case IR::Opcode::CompositeConstructF16x4:
32 case IR::Opcode::CompositeExtractF16x2:
33 case IR::Opcode::CompositeExtractF16x3:
34 case IR::Opcode::CompositeExtractF16x4:
35 case IR::Opcode::BitCastU16F16:
36 case IR::Opcode::BitCastF16U16:
37 case IR::Opcode::PackFloat2x16:
38 case IR::Opcode::UnpackFloat2x16:
39 case IR::Opcode::ConvertS16F16:
40 case IR::Opcode::ConvertS32F16:
41 case IR::Opcode::ConvertS64F16:
42 case IR::Opcode::ConvertU16F16:
43 case IR::Opcode::ConvertU32F16:
44 case IR::Opcode::ConvertU64F16:
29 case IR::Opcode::FPAbs16: 45 case IR::Opcode::FPAbs16:
30 case IR::Opcode::FPAdd16: 46 case IR::Opcode::FPAdd16:
31 case IR::Opcode::FPCeil16: 47 case IR::Opcode::FPCeil16:
@@ -36,7 +52,7 @@ void Visit(Info& info, IR::Inst& inst) {
36 case IR::Opcode::FPRoundEven16: 52 case IR::Opcode::FPRoundEven16:
37 case IR::Opcode::FPSaturate16: 53 case IR::Opcode::FPSaturate16:
38 case IR::Opcode::FPTrunc16: 54 case IR::Opcode::FPTrunc16:
39 info.uses_fp16; 55 info.uses_fp16 = true;
40 break; 56 break;
41 case IR::Opcode::FPAbs64: 57 case IR::Opcode::FPAbs64:
42 case IR::Opcode::FPAdd64: 58 case IR::Opcode::FPAdd64:
diff --git a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp
index 9eb61b54c..4d4e88259 100644
--- a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp
+++ b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp
@@ -104,12 +104,12 @@ void FoldGetPred(IR::Inst& inst) {
104bool FoldXmadMultiply(IR::Block& block, IR::Inst& inst) { 104bool FoldXmadMultiply(IR::Block& block, IR::Inst& inst) {
105 /* 105 /*
106 * We are looking for this pattern: 106 * We are looking for this pattern:
107 * %rhs_bfe = BitFieldUExtract %factor_a, #0, #16 (uses: 1) 107 * %rhs_bfe = BitFieldUExtract %factor_a, #0, #16
108 * %rhs_mul = IMul32 %rhs_bfe, %factor_b (uses: 1) 108 * %rhs_mul = IMul32 %rhs_bfe, %factor_b
109 * %lhs_bfe = BitFieldUExtract %factor_a, #16, #16 (uses: 1) 109 * %lhs_bfe = BitFieldUExtract %factor_a, #16, #16
110 * %rhs_mul = IMul32 %lhs_bfe, %factor_b (uses: 1) 110 * %rhs_mul = IMul32 %lhs_bfe, %factor_b
111 * %lhs_shl = ShiftLeftLogical32 %rhs_mul, #16 (uses: 1) 111 * %lhs_shl = ShiftLeftLogical32 %rhs_mul, #16
112 * %result = IAdd32 %lhs_shl, %rhs_mul (uses: 10) 112 * %result = IAdd32 %lhs_shl, %rhs_mul
113 * 113 *
114 * And replacing it with 114 * And replacing it with
115 * %result = IMul32 %factor_a, %factor_b 115 * %result = IMul32 %factor_a, %factor_b
diff --git a/src/shader_recompiler/ir_opt/lower_fp16_to_fp32.cpp b/src/shader_recompiler/ir_opt/lower_fp16_to_fp32.cpp
new file mode 100644
index 000000000..c7032f168
--- /dev/null
+++ b/src/shader_recompiler/ir_opt/lower_fp16_to_fp32.cpp
@@ -0,0 +1,79 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6
7#include "shader_recompiler/frontend/ir/ir_emitter.h"
8#include "shader_recompiler/frontend/ir/microinstruction.h"
9#include "shader_recompiler/ir_opt/passes.h"
10
11namespace Shader::Optimization {
12namespace {
13IR::Opcode Replace(IR::Opcode op) {
14 switch (op) {
15 case IR::Opcode::FPAbs16:
16 return IR::Opcode::FPAbs32;
17 case IR::Opcode::FPAdd16:
18 return IR::Opcode::FPAdd32;
19 case IR::Opcode::FPCeil16:
20 return IR::Opcode::FPCeil32;
21 case IR::Opcode::FPFloor16:
22 return IR::Opcode::FPFloor32;
23 case IR::Opcode::FPFma16:
24 return IR::Opcode::FPFma32;
25 case IR::Opcode::FPMul16:
26 return IR::Opcode::FPMul32;
27 case IR::Opcode::FPNeg16:
28 return IR::Opcode::FPNeg32;
29 case IR::Opcode::FPRoundEven16:
30 return IR::Opcode::FPRoundEven32;
31 case IR::Opcode::FPSaturate16:
32 return IR::Opcode::FPSaturate32;
33 case IR::Opcode::FPTrunc16:
34 return IR::Opcode::FPTrunc32;
35 case IR::Opcode::CompositeConstructF16x2:
36 return IR::Opcode::CompositeConstructF32x2;
37 case IR::Opcode::CompositeConstructF16x3:
38 return IR::Opcode::CompositeConstructF32x3;
39 case IR::Opcode::CompositeConstructF16x4:
40 return IR::Opcode::CompositeConstructF32x4;
41 case IR::Opcode::CompositeExtractF16x2:
42 return IR::Opcode::CompositeExtractF32x2;
43 case IR::Opcode::CompositeExtractF16x3:
44 return IR::Opcode::CompositeExtractF32x3;
45 case IR::Opcode::CompositeExtractF16x4:
46 return IR::Opcode::CompositeExtractF32x4;
47 case IR::Opcode::ConvertS16F16:
48 return IR::Opcode::ConvertS16F32;
49 case IR::Opcode::ConvertS32F16:
50 return IR::Opcode::ConvertS32F32;
51 case IR::Opcode::ConvertS64F16:
52 return IR::Opcode::ConvertS64F32;
53 case IR::Opcode::ConvertU16F16:
54 return IR::Opcode::ConvertU16F32;
55 case IR::Opcode::ConvertU32F16:
56 return IR::Opcode::ConvertU32F32;
57 case IR::Opcode::ConvertU64F16:
58 return IR::Opcode::ConvertU64F32;
59 case IR::Opcode::PackFloat2x16:
60 return IR::Opcode::PackHalf2x16;
61 case IR::Opcode::UnpackFloat2x16:
62 return IR::Opcode::UnpackHalf2x16;
63 default:
64 return op;
65 }
66}
67} // Anonymous namespace
68
69void LowerFp16ToFp32(IR::Program& program) {
70 for (IR::Function& function : program.functions) {
71 for (IR::Block* const block : function.blocks) {
72 for (IR::Inst& inst : block->Instructions()) {
73 inst.ReplaceOpcode(Replace(inst.Opcode()));
74 }
75 }
76 }
77}
78
79} // namespace Shader::Optimization
diff --git a/src/shader_recompiler/ir_opt/passes.h b/src/shader_recompiler/ir_opt/passes.h
index 89e5811d3..38106308c 100644
--- a/src/shader_recompiler/ir_opt/passes.h
+++ b/src/shader_recompiler/ir_opt/passes.h
@@ -24,6 +24,7 @@ void ConstantPropagationPass(IR::Block& block);
24void DeadCodeEliminationPass(IR::Block& block); 24void DeadCodeEliminationPass(IR::Block& block);
25void GlobalMemoryToStorageBufferPass(IR::Program& program); 25void GlobalMemoryToStorageBufferPass(IR::Program& program);
26void IdentityRemovalPass(IR::Function& function); 26void IdentityRemovalPass(IR::Function& function);
27void LowerFp16ToFp32(IR::Program& program);
27void SsaRewritePass(std::span<IR::Block* const> post_order_blocks); 28void SsaRewritePass(std::span<IR::Block* const> post_order_blocks);
28void VerificationPass(const IR::Function& function); 29void VerificationPass(const IR::Function& function);
29 30
diff --git a/src/shader_recompiler/main.cpp b/src/shader_recompiler/main.cpp
index 050a37f18..abd44e323 100644
--- a/src/shader_recompiler/main.cpp
+++ b/src/shader_recompiler/main.cpp
@@ -67,8 +67,8 @@ int main() {
67 ObjectPool<IR::Inst> inst_pool; 67 ObjectPool<IR::Inst> inst_pool;
68 ObjectPool<IR::Block> block_pool; 68 ObjectPool<IR::Block> block_pool;
69 69
70 FileEnvironment env{"D:\\Shaders\\Database\\Oninaki\\CS8F146B41DB6BD826.bin"}; 70 // FileEnvironment env{"D:\\Shaders\\Database\\Oninaki\\CS8F146B41DB6BD826.bin"};
71 // FileEnvironment env{"D:\\Shaders\\shader.bin"}; 71 FileEnvironment env{"D:\\Shaders\\shader.bin"};
72 block_pool.ReleaseContents(); 72 block_pool.ReleaseContents();
73 inst_pool.ReleaseContents(); 73 inst_pool.ReleaseContents();
74 flow_block_pool.ReleaseContents(); 74 flow_block_pool.ReleaseContents();
@@ -76,5 +76,9 @@ int main() {
76 fmt::print(stdout, "{}\n", cfg.Dot()); 76 fmt::print(stdout, "{}\n", cfg.Dot());
77 IR::Program program{TranslateProgram(inst_pool, block_pool, env, cfg)}; 77 IR::Program program{TranslateProgram(inst_pool, block_pool, env, cfg)};
78 fmt::print(stdout, "{}\n", IR::DumpProgram(program)); 78 fmt::print(stdout, "{}\n", IR::DumpProgram(program));
79 void(Backend::SPIRV::EmitSPIRV(env, program)); 79 const std::vector<u32> spirv{Backend::SPIRV::EmitSPIRV(env, program)};
80 std::FILE* const file{std::fopen("D:\\shader.spv", "wb")};
81 std::fwrite(spirv.data(), spirv.size(), sizeof(u32), file);
82 std::fclose(file);
83 std::system("spirv-dis D:\\shader.spv");
80} 84}
diff --git a/src/shader_recompiler/object_pool.h b/src/shader_recompiler/object_pool.h
index f78813b5f..c10751b9d 100644
--- a/src/shader_recompiler/object_pool.h
+++ b/src/shader_recompiler/object_pool.h
@@ -18,7 +18,7 @@ public:
18 } 18 }
19 19
20 template <typename... Args> 20 template <typename... Args>
21 requires std::is_constructible_v<T, Args...> [[nodiscard]] T* Create(Args&&... args) { 21 requires std::is_constructible_v<T, Args...>[[nodiscard]] T* Create(Args&&... args) {
22 return std::construct_at(Memory(), std::forward<Args>(args)...); 22 return std::construct_at(Memory(), std::forward<Args>(args)...);
23 } 23 }
24 24
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
index 4181d83ee..a444d55d3 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
@@ -206,6 +206,8 @@ VKComputePass::VKComputePass(const Device& device, VKDescriptorPool& descriptor_
206 .codeSize = static_cast<u32>(code.size_bytes()), 206 .codeSize = static_cast<u32>(code.size_bytes()),
207 .pCode = code.data(), 207 .pCode = code.data(),
208 }); 208 });
209 /*
210 FIXME
209 pipeline = device.GetLogical().CreateComputePipeline({ 211 pipeline = device.GetLogical().CreateComputePipeline({
210 .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, 212 .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
211 .pNext = nullptr, 213 .pNext = nullptr,
@@ -224,6 +226,7 @@ VKComputePass::VKComputePass(const Device& device, VKDescriptorPool& descriptor_
224 .basePipelineHandle = nullptr, 226 .basePipelineHandle = nullptr,
225 .basePipelineIndex = 0, 227 .basePipelineIndex = 0,
226 }); 228 });
229 */
227} 230}
228 231
229VKComputePass::~VKComputePass() = default; 232VKComputePass::~VKComputePass() = default;
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 4bf3e4819..c2a41a360 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -31,8 +31,6 @@
31#include "video_core/vulkan_common/vulkan_device.h" 31#include "video_core/vulkan_common/vulkan_device.h"
32#include "video_core/vulkan_common/vulkan_wrapper.h" 32#include "video_core/vulkan_common/vulkan_wrapper.h"
33 33
34#pragma optimize("", off)
35
36namespace Vulkan { 34namespace Vulkan {
37MICROPROFILE_DECLARE(Vulkan_PipelineCache); 35MICROPROFILE_DECLARE(Vulkan_PipelineCache);
38 36
@@ -180,6 +178,12 @@ ComputePipeline PipelineCache::CreateComputePipeline(ShaderInfo* shader_info) {
180 // TODO: Load from cache 178 // TODO: Load from cache
181 } 179 }
182 const auto [info, code]{Shader::RecompileSPIRV(env, qmd.program_start)}; 180 const auto [info, code]{Shader::RecompileSPIRV(env, qmd.program_start)};
181
182 FILE* file = fopen("D:\\shader.spv", "wb");
183 fwrite(code.data(), 4, code.size(), file);
184 fclose(file);
185 std::system("spirv-dis D:\\shader.spv");
186
183 shader_info->unique_hash = env.ComputeHash(); 187 shader_info->unique_hash = env.ComputeHash();
184 shader_info->size_bytes = env.ShaderSize(); 188 shader_info->size_bytes = env.ShaderSize();
185 return ComputePipeline{device, descriptor_pool, update_descriptor_queue, info, 189 return ComputePipeline{device, descriptor_pool, update_descriptor_queue, info,
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index b757454c4..1b662f9f3 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -36,8 +36,6 @@
36#include "video_core/vulkan_common/vulkan_device.h" 36#include "video_core/vulkan_common/vulkan_device.h"
37#include "video_core/vulkan_common/vulkan_wrapper.h" 37#include "video_core/vulkan_common/vulkan_wrapper.h"
38 38
39#pragma optimize("", off)
40
41namespace Vulkan { 39namespace Vulkan {
42 40
43using Maxwell = Tegra::Engines::Maxwell3D::Regs; 41using Maxwell = Tegra::Engines::Maxwell3D::Regs;
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index f214510da..85f903125 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -247,9 +247,9 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
247 .shaderStorageImageArrayDynamicIndexing = false, 247 .shaderStorageImageArrayDynamicIndexing = false,
248 .shaderClipDistance = false, 248 .shaderClipDistance = false,
249 .shaderCullDistance = false, 249 .shaderCullDistance = false,
250 .shaderFloat64 = false, 250 .shaderFloat64 = true,
251 .shaderInt64 = false, 251 .shaderInt64 = true,
252 .shaderInt16 = false, 252 .shaderInt16 = true,
253 .shaderResourceResidency = false, 253 .shaderResourceResidency = false,
254 .shaderResourceMinLod = false, 254 .shaderResourceMinLod = false,
255 .sparseBinding = false, 255 .sparseBinding = false,
@@ -420,8 +420,8 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
420 } 420 }
421 if (is_float16_supported && driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) { 421 if (is_float16_supported && driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) {
422 // Intel's compiler crashes when using fp16 on Astral Chain, disable it for the time being. 422 // Intel's compiler crashes when using fp16 on Astral Chain, disable it for the time being.
423 LOG_WARNING(Render_Vulkan, "Blacklisting Intel proprietary from float16 math"); 423 // LOG_WARNING(Render_Vulkan, "Blacklisting Intel proprietary from float16 math");
424 is_float16_supported = false; 424 // is_float16_supported = false;
425 } 425 }
426 426
427 graphics_queue = logical.GetQueue(graphics_family); 427 graphics_queue = logical.GetQueue(graphics_family);