From 377a03fe5f5e054ec29e57d292e2c430ca8f7350 Mon Sep 17 00:00:00 2001 From: Samuliak Date: Sat, 4 May 2024 14:31:30 +0200 Subject: [PATCH] support shader inputs --- .../backend/msl/emit_msl.cpp | 206 ++++++++++++++++- .../backend/msl/msl_emit_context.cpp | 212 +----------------- .../backend/msl/msl_emit_context.h | 6 - 3 files changed, 210 insertions(+), 214 deletions(-) diff --git a/src/shader_recompiler/backend/msl/emit_msl.cpp b/src/shader_recompiler/backend/msl/emit_msl.cpp index fa051cb52b..45c2141528 100644 --- a/src/shader_recompiler/backend/msl/emit_msl.cpp +++ b/src/shader_recompiler/backend/msl/emit_msl.cpp @@ -205,11 +205,213 @@ void DefineVariables(const EmitContext& ctx, std::string& header) { header += fmt::format("int loop{}=0x2000;", i); } } + +// TODO +std::string_view DepthSamplerType(TextureType type) { + switch (type) { + case TextureType::Color1D: + return "sampler1DShadow"; + case TextureType::ColorArray1D: + return "sampler1DArrayShadow"; + case TextureType::Color2D: + return "sampler2DShadow"; + case TextureType::ColorArray2D: + return "sampler2DArrayShadow"; + case TextureType::ColorCube: + return "samplerCubeShadow"; + case TextureType::ColorArrayCube: + return "samplerCubeArrayShadow"; + default: + throw NotImplementedException("Texture type: {}", type); + } +} + +// TODO: emit sampler as well +// TODO: handle multisample +// TODO: handle texture buffer +std::string_view ColorSamplerType(TextureType type, bool is_multisample = false) { + if (is_multisample) { + ASSERT(type == TextureType::Color2D || type == TextureType::ColorArray2D); + } + switch (type) { + case TextureType::Color1D: + return "texture1d"; + case TextureType::ColorArray1D: + return "texture1d_array"; + case TextureType::Color2D: + case TextureType::Color2DRect: + return "texture2d"; + case TextureType::ColorArray2D: + return "texture2d_array"; + case TextureType::Color3D: + return "texture3d"; + case TextureType::ColorCube: + return "texturecube"; + case TextureType::ColorArrayCube: + return "texturecube_array"; + default: + throw NotImplementedException("Texture type: {}", type); + } +} + +// TODO: handle texture buffer +std::string_view ImageType(TextureType type) { + switch (type) { + case TextureType::Color1D: + return "texture1d"; + case TextureType::ColorArray1D: + return "texture1d_array"; + case TextureType::Color2D: + return "texture2d"; + case TextureType::ColorArray2D: + return "texture2d_array"; + case TextureType::Color3D: + return "texture3d"; + case TextureType::ColorCube: + return "texturecube"; + case TextureType::ColorArrayCube: + return "texturecube_array"; + default: + throw NotImplementedException("Image type: {}", type); + } +} + +// TODO: is this needed? +/* +std::string_view ImageFormatString(ImageFormat format) { + switch (format) { + case ImageFormat::Typeless: + return ""; + case ImageFormat::R8_UINT: + return ",r8ui"; + case ImageFormat::R8_SINT: + return ",r8i"; + case ImageFormat::R16_UINT: + return ",r16ui"; + case ImageFormat::R16_SINT: + return ",r16i"; + case ImageFormat::R32_UINT: + return ",r32ui"; + case ImageFormat::R32G32_UINT: + return ",rg32ui"; + case ImageFormat::R32G32B32A32_UINT: + return ",rgba32ui"; + default: + throw NotImplementedException("Image format: {}", format); + } +} +*/ + +std::string_view ImageAccessQualifier(bool is_written, bool is_read) { + if (is_written && is_read) { + return "access::read, access::write"; + } + if (is_written) { + return "access::write"; + } + if (is_read) { + return "access::read"; + } + return ""; +} + +void DefineInputs(EmitContext& ctx, std::string& header, Bindings& bindings) { + bool added{false}; + + // Constant buffers + for (const auto& desc : ctx.info.constant_buffer_descriptors) { + const u32 cbuf_used_size{ + Common::DivCeil(ctx.info.constant_buffer_used_sizes[desc.index], 16U)}; + const u32 cbuf_binding_size{ctx.info.uses_global_memory ? 0x1000U : cbuf_used_size}; + if (added) + header += ","; + header += fmt::format("constant float4& cbuf{}[{}] [[buffer({})]]", desc.index, + cbuf_binding_size, bindings.uniform_buffer); + bindings.uniform_buffer += desc.count; + added = true; + } + + // Constant buffer indirect + // TODO + + // Storage space buffers + u32 index{}; + for (const auto& desc : ctx.info.storage_buffers_descriptors) { + if (added) + header += ","; + header += + fmt::format("device uint& ssbo{}[] [[buffer({})]]", index, bindings.storage_buffer); + bindings.storage_buffer += desc.count; + index += desc.count; + added = true; + } + + // Images + // TODO + /* + image_buffers.reserve(info.image_buffer_descriptors.size()); + for (const auto& desc : info.image_buffer_descriptors) { + image_buffers.push_back({bindings.image, desc.count}); + const auto format{ImageFormatString(desc.format)}; + const auto qualifier{ImageAccessQualifier(desc.is_written, desc.is_read)}; + const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""}; + header += fmt::format("layout(binding={}{}) uniform {}uimageBuffer img{}{};", + bindings.image, format, qualifier, bindings.image, array_decorator); + bindings.image += desc.count; + } + */ + ctx.images.reserve(ctx.info.image_descriptors.size()); + for (const auto& desc : ctx.info.image_descriptors) { + ctx.images.push_back({bindings.image, desc.count}); + // TODO: do we need format? + // const auto format{ImageFormatString(desc.format)}; + const auto image_type{ImageType(desc.type)}; + const auto qualifier{ImageAccessQualifier(desc.is_written, desc.is_read)}; + const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""}; + if (added) + header += ","; + header += fmt::format("{}<{}> img{}{} [[texture({})]]", qualifier, image_type, + bindings.image, array_decorator, bindings.image); + bindings.image += desc.count; + added = true; + } + + // Textures + // TODO + /* + texture_buffers.reserve(info.texture_buffer_descriptors.size()); + for (const auto& desc : info.texture_buffer_descriptors) { + texture_buffers.push_back({bindings.texture, desc.count}); + const auto sampler_type{ColorSamplerType(TextureType::Buffer)}; + const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""}; + header += fmt::format("layout(binding={}) uniform {} tex{}{};", bindings.texture, + sampler_type, bindings.texture, array_decorator); + bindings.texture += desc.count; + } + */ + ctx.textures.reserve(ctx.info.texture_descriptors.size()); + for (const auto& desc : ctx.info.texture_descriptors) { + ctx.textures.push_back({bindings.texture, desc.count}); + const auto texture_type{desc.is_depth ? DepthSamplerType(desc.type) + : ColorSamplerType(desc.type, desc.is_multisample)}; + const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""}; + if (added) + header += ","; + header += fmt::format("{} tex{}{} [[texture({})]]", texture_type, bindings.texture, + array_decorator, bindings.texture); + header += fmt::format(",sampler samp{}{} [[sampler({})]]", bindings.texture, + array_decorator, bindings.texture); + bindings.texture += desc.count; + added = true; + } +} } // Anonymous namespace std::string EmitMSL(const Profile& profile, const RuntimeInfo& runtime_info, IR::Program& program, Bindings& bindings) { EmitContext ctx{program, bindings, profile, runtime_info}; + std::string inputs; + DefineInputs(ctx, inputs, bindings); Precolor(program); EmitCode(ctx, program); ctx.header.insert(0, "#include \nusing namespace metal;\n"); @@ -224,7 +426,9 @@ std::string EmitMSL(const Profile& profile, const RuntimeInfo& runtime_info, IR: const auto smem_size{needs_clamp ? max_size : requested_size}; ctx.header += fmt::format("shared uint smem[{}];", Common::DivCeil(smem_size, 4U)); } - ctx.header += "void main_(){\n"; + ctx.header += "void main_("; + ctx.header += inputs; + ctx.header += "){\n"; if (program.local_memory_size > 0) { ctx.header += fmt::format("uint lmem[{}];", Common::DivCeil(program.local_memory_size, 4U)); } diff --git a/src/shader_recompiler/backend/msl/msl_emit_context.cpp b/src/shader_recompiler/backend/msl/msl_emit_context.cpp index e6e18a136c..9dc25df7a9 100644 --- a/src/shader_recompiler/backend/msl/msl_emit_context.cpp +++ b/src/shader_recompiler/backend/msl/msl_emit_context.cpp @@ -30,6 +30,7 @@ std::string_view InterpDecorator(Interpolation interp) { throw InvalidArgument("Invalid interpolation {}", interp); } +// TODO std::string_view InputArrayDecorator(Stage stage) { switch (stage) { case Stage::Geometry: @@ -41,6 +42,7 @@ std::string_view InputArrayDecorator(Stage stage) { } } +// TODO std::string OutputDecorator(Stage stage, u32 size) { switch (stage) { case Stage::TessellationControl: @@ -50,113 +52,6 @@ std::string OutputDecorator(Stage stage, u32 size) { } } -// TODO -std::string_view DepthSamplerType(TextureType type) { - switch (type) { - case TextureType::Color1D: - return "sampler1DShadow"; - case TextureType::ColorArray1D: - return "sampler1DArrayShadow"; - case TextureType::Color2D: - return "sampler2DShadow"; - case TextureType::ColorArray2D: - return "sampler2DArrayShadow"; - case TextureType::ColorCube: - return "samplerCubeShadow"; - case TextureType::ColorArrayCube: - return "samplerCubeArrayShadow"; - default: - throw NotImplementedException("Texture type: {}", type); - } -} - -// TODO: emit sampler as well -// TODO: handle multisample -// TODO: handle texture buffer -std::string_view ColorSamplerType(TextureType type, bool is_multisample = false) { - if (is_multisample) { - ASSERT(type == TextureType::Color2D || type == TextureType::ColorArray2D); - } - switch (type) { - case TextureType::Color1D: - return "texture1d"; - case TextureType::ColorArray1D: - return "texture1d_array"; - case TextureType::Color2D: - case TextureType::Color2DRect: - return "texture2d"; - case TextureType::ColorArray2D: - return "texture2d_array"; - case TextureType::Color3D: - return "texture3d"; - case TextureType::ColorCube: - return "texturecube"; - case TextureType::ColorArrayCube: - return "texturecube_array"; - default: - throw NotImplementedException("Texture type: {}", type); - } -} - -// TODO: handle texture buffer -std::string_view ImageType(TextureType type) { - switch (type) { - case TextureType::Color1D: - return "texture1d"; - case TextureType::ColorArray1D: - return "texture1d_array"; - case TextureType::Color2D: - return "texture2d"; - case TextureType::ColorArray2D: - return "texture2d_array"; - case TextureType::Color3D: - return "texture3d"; - case TextureType::ColorCube: - return "texturecube"; - case TextureType::ColorArrayCube: - return "texturecube_array"; - default: - throw NotImplementedException("Image type: {}", type); - } -} - -// TODO: is this needed? -std::string_view ImageFormatString(ImageFormat format) { - switch (format) { - case ImageFormat::Typeless: - return ""; - case ImageFormat::R8_UINT: - return ",r8ui"; - case ImageFormat::R8_SINT: - return ",r8i"; - case ImageFormat::R16_UINT: - return ",r16ui"; - case ImageFormat::R16_SINT: - return ",r16i"; - case ImageFormat::R32_UINT: - return ",r32ui"; - case ImageFormat::R32G32_UINT: - return ",rg32ui"; - case ImageFormat::R32G32B32A32_UINT: - return ",rgba32ui"; - default: - throw NotImplementedException("Image format: {}", format); - } -} - -std::string_view ImageAccessQualifier(bool is_written, bool is_read) { - if (is_written && is_read) { - return "access::read, access::write"; - } - if (is_written) { - return "access::write"; - } - if (is_read) { - return "access::read"; - } - return ""; -} - // TODO std::string_view GetTessMode(TessPrimitive primitive) { switch (primitive) { @@ -306,62 +201,11 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile if (info.uses_render_area) { header += "layout(location=1) uniform vec4 render_area;"; } - DefineConstantBuffers(bindings); - DefineConstantBufferIndirect(); - DefineStorageBuffers(bindings); - SetupImages(bindings); - SetupTextures(bindings); DefineHelperFunctions(); DefineConstants(); } -void EmitContext::DefineConstantBuffers(Bindings& bindings) { - if (info.constant_buffer_descriptors.empty()) { - return; - } - for (const auto& desc : info.constant_buffer_descriptors) { - const auto cbuf_type{profile.has_gl_cbuf_ftou_bug ? "uvec4" : "vec4"}; - const u32 cbuf_used_size{Common::DivCeil(info.constant_buffer_used_sizes[desc.index], 16U)}; - const u32 cbuf_binding_size{info.uses_global_memory ? 0x1000U : cbuf_used_size}; - header += fmt::format("layout(std140,binding={}) uniform {}_cbuf_{}{{{} {}_cbuf{}[{}];}};", - bindings.uniform_buffer, stage_name, desc.index, cbuf_type, - stage_name, desc.index, cbuf_binding_size); - bindings.uniform_buffer += desc.count; - } -} - -void EmitContext::DefineConstantBufferIndirect() { - if (!info.uses_cbuf_indirect) { - return; - } - - header += profile.has_gl_cbuf_ftou_bug ? "uvec4 " : "vec4 "; - header += "GetCbufIndirect(uint binding, uint offset){" - "switch(binding){" - "default:"; - - for (const auto& desc : info.constant_buffer_descriptors) { - header += - fmt::format("case {}:return {}_cbuf{}[offset];", desc.index, stage_name, desc.index); - } - - header += "}}"; -} - -void EmitContext::DefineStorageBuffers(Bindings& bindings) { - if (info.storage_buffers_descriptors.empty()) { - return; - } - u32 index{}; - for (const auto& desc : info.storage_buffers_descriptors) { - header += fmt::format("layout(std430,binding={}) buffer {}_ssbo_{}{{uint {}_ssbo{}[];}};", - bindings.storage_buffer, stage_name, bindings.storage_buffer, - stage_name, index); - bindings.storage_buffer += desc.count; - index += desc.count; - } -} - +// TODO void EmitContext::DefineGenericOutput(size_t index, u32 invocations) { static constexpr std::string_view swizzle{"xyzw"}; const size_t base_index{static_cast(IR::Attribute::Generic0X) + index * 4}; @@ -537,57 +381,11 @@ std::string EmitContext::DefineGlobalMemoryFunctions() { write_func_64 += '}'; write_func_128 += '}'; load_func += "return 0u;}"; - load_func_64 += "return uvec2(0);}"; - load_func_128 += "return uvec4(0);}"; + load_func_64 += "return uint2(0);}"; + load_func_128 += "return uint4(0);}"; return write_func + write_func_64 + write_func_128 + load_func + load_func_64 + load_func_128; } -void EmitContext::SetupImages(Bindings& bindings) { - image_buffers.reserve(info.image_buffer_descriptors.size()); - for (const auto& desc : info.image_buffer_descriptors) { - image_buffers.push_back({bindings.image, desc.count}); - const auto format{ImageFormatString(desc.format)}; - const auto qualifier{ImageAccessQualifier(desc.is_written, desc.is_read)}; - const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""}; - header += fmt::format("layout(binding={}{}) uniform {}uimageBuffer img{}{};", - bindings.image, format, qualifier, bindings.image, array_decorator); - bindings.image += desc.count; - } - images.reserve(info.image_descriptors.size()); - for (const auto& desc : info.image_descriptors) { - images.push_back({bindings.image, desc.count}); - const auto format{ImageFormatString(desc.format)}; - const auto image_type{ImageType(desc.type)}; - const auto qualifier{ImageAccessQualifier(desc.is_written, desc.is_read)}; - const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""}; - header += fmt::format("layout(binding={}{})uniform {}{} img{}{};", bindings.image, format, - qualifier, image_type, bindings.image, array_decorator); - bindings.image += desc.count; - } -} - -void EmitContext::SetupTextures(Bindings& bindings) { - texture_buffers.reserve(info.texture_buffer_descriptors.size()); - for (const auto& desc : info.texture_buffer_descriptors) { - texture_buffers.push_back({bindings.texture, desc.count}); - const auto sampler_type{ColorSamplerType(TextureType::Buffer)}; - const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""}; - header += fmt::format("layout(binding={}) uniform {} tex{}{};", bindings.texture, - sampler_type, bindings.texture, array_decorator); - bindings.texture += desc.count; - } - textures.reserve(info.texture_descriptors.size()); - for (const auto& desc : info.texture_descriptors) { - textures.push_back({bindings.texture, desc.count}); - const auto sampler_type{desc.is_depth ? DepthSamplerType(desc.type) - : ColorSamplerType(desc.type, desc.is_multisample)}; - const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""}; - header += fmt::format("layout(binding={}) uniform {} tex{}{};", bindings.texture, - sampler_type, bindings.texture, array_decorator); - bindings.texture += desc.count; - } -} - void EmitContext::DefineConstants() { if (info.uses_fswzadd) { header += "const float FSWZ_A[]=float[4](-1.f,1.f,-1.f,0.f);" diff --git a/src/shader_recompiler/backend/msl/msl_emit_context.h b/src/shader_recompiler/backend/msl/msl_emit_context.h index 6753d875e9..233b4bd606 100644 --- a/src/shader_recompiler/backend/msl/msl_emit_context.h +++ b/src/shader_recompiler/backend/msl/msl_emit_context.h @@ -158,16 +158,10 @@ public: bool uses_geometry_passthrough{}; private: - void SetupExtensions(); - void DefineConstantBuffers(Bindings& bindings); - void DefineConstantBufferIndirect(); - void DefineStorageBuffers(Bindings& bindings); void DefineGenericOutput(size_t index, u32 invocations); void DefineHelperFunctions(); void DefineConstants(); std::string DefineGlobalMemoryFunctions(); - void SetupImages(Bindings& bindings); - void SetupTextures(Bindings& bindings); }; } // namespace Shader::Backend::MSL