PostProcessing: Support loading slang shaders/presets

Compatibility will likely vary quite a bit.
This commit is contained in:
Stenzek
2025-10-25 23:42:49 +10:00
parent 81fb8014a1
commit 8a732ded41
8 changed files with 2304 additions and 3 deletions

View File

@@ -59,6 +59,8 @@ add_library(util
postprocessing_shader_fx.h
postprocessing_shader_glsl.cpp
postprocessing_shader_glsl.h
postprocessing_shader_slang.cpp
postprocessing_shader_slang.h
shadergen.cpp
shadergen.h
shiftjis.cpp

View File

@@ -24,6 +24,11 @@ class Error;
X(spvc_compiler_set_name) \
X(spvc_compiler_set_decoration) \
X(spvc_compiler_get_decoration) \
X(spvc_compiler_get_member_name) \
X(spvc_compiler_get_member_decoration) \
X(spvc_compiler_get_declared_struct_size) \
X(spvc_compiler_get_declared_struct_member_size) \
X(spvc_compiler_get_type_handle) \
X(spvc_resources_get_resource_list_for_type)
#ifdef _WIN32

View File

@@ -690,6 +690,7 @@ public:
static constexpr u32 MAX_IMAGE_RENDER_TARGETS = 2;
static constexpr u32 DEFAULT_CLEAR_COLOR = 0xFF000000u;
static constexpr u32 PIPELINE_CACHE_HASH_SIZE = 20;
static constexpr u32 BASE_UNIFORM_BUFFER_ALIGNMENT = 16;
static_assert(sizeof(GPUPipeline::GraphicsConfig::color_formats) == sizeof(GPUTexture::Format) * MAX_RENDER_TARGETS);
GPUDevice();

View File

@@ -8,6 +8,7 @@
#include "postprocessing_shader.h"
#include "postprocessing_shader_fx.h"
#include "postprocessing_shader_glsl.h"
#include "postprocessing_shader_slang.h"
#include "shadergen.h"
// TODO: Remove me
@@ -195,6 +196,33 @@ std::vector<std::pair<std::string, std::string>> PostProcessing::GetAvailableSha
}
}
FileSystem::FindFiles(Path::Combine(EmuFolders::Shaders, "slang").c_str(), "*.slangp",
FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_RECURSIVE | FILESYSTEM_FIND_RELATIVE_PATHS, &results);
FileSystem::FindFiles(
Path::Combine(EmuFolders::Resources, "shaders" FS_OSPATH_SEPARATOR_STR "slang").c_str(), "*.slangp",
FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_RECURSIVE | FILESYSTEM_FIND_RELATIVE_PATHS | FILESYSTEM_FIND_KEEP_ARRAY,
&results);
std::sort(results.begin(), results.end(),
[](const auto& lhs, const auto& rhs) { return lhs.FileName < rhs.FileName; });
for (FILESYSTEM_FIND_DATA& fd : results)
{
size_t pos = fd.FileName.rfind('.');
if (pos != std::string::npos && pos > 0)
fd.FileName.erase(pos);
#ifdef _WIN32
// swap any backslashes for forward slashes so the config is cross-platform
StringUtil::ReplaceAll(&fd.FileName, '\\', '/');
#endif
if (std::none_of(names.begin(), names.end(), [&fd](const auto& other) { return fd.FileName == other.second; }))
{
std::string display_name = fmt::format(TRANSLATE_FS("PostProcessing", "{} [Slang]"), fd.FileName);
names.emplace_back(std::move(display_name), std::move(fd.FileName));
}
}
std::sort(names.begin(), names.end(),
[](const std::pair<std::string, std::string>& lhs, const std::pair<std::string, std::string>& rhs) {
return (StringUtil::Strcasecmp(lhs.first.c_str(), rhs.first.c_str()) < 0);
@@ -770,6 +798,19 @@ std::unique_ptr<PostProcessing::Shader> PostProcessing::TryLoadingShader(const s
return shader;
}
filename = Path::Combine(EmuFolders::Shaders, fmt::format("slang" FS_OSPATH_SEPARATOR_STR "{}.slangp", shader_name));
if (FileSystem::FileExists(filename.c_str()))
{
std::unique_ptr<SlangShader> shader = std::make_unique<SlangShader>();
if (!shader->LoadFromFile(shader_name, filename.c_str(), error))
{
ERROR_LOG("Failed to load shader '{}': {}", shader_name, error->GetDescription());
shader.reset();
}
return shader;
}
filename = Path::Combine(EmuFolders::Shaders, fmt::format("{}.glsl", shader_name));
if (FileSystem::FileExists(filename.c_str()))
{
@@ -783,8 +824,7 @@ std::unique_ptr<PostProcessing::Shader> PostProcessing::TryLoadingShader(const s
return shader;
}
filename =
fmt::format("shaders/reshade" FS_OSPATH_SEPARATOR_STR "Shaders" FS_OSPATH_SEPARATOR_STR "{}.fx", shader_name);
filename = fmt::format("shaders/reshade/Shaders/{}.fx", shader_name);
resource_str = Host::ReadResourceFileToString(filename.c_str(), true, error);
if (resource_str.has_value())
{
@@ -798,7 +838,21 @@ std::unique_ptr<PostProcessing::Shader> PostProcessing::TryLoadingShader(const s
return shader;
}
filename = fmt::format("shaders" FS_OSPATH_SEPARATOR_STR "{}.glsl", shader_name);
filename = fmt::format("shaders/slang/{}.slangp", shader_name);
resource_str = Host::ReadResourceFileToString(filename.c_str(), true, error);
if (resource_str.has_value())
{
std::unique_ptr<SlangShader> shader = std::make_unique<SlangShader>();
if (!shader->LoadFromString(shader_name, filename, std::move(resource_str.value()), error))
{
ERROR_LOG("Failed to load shader '{}': {}", shader_name, error->GetDescription());
shader.reset();
}
return shader;
}
filename = fmt::format("shaders/{}.glsl", shader_name);
resource_str = Host::ReadResourceFileToString(filename.c_str(), true, error);
if (resource_str.has_value())
{

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,151 @@
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#pragma once
#include "postprocessing_shader.h"
#include "common/thirdparty/SmallVector.h"
#include <array>
#include <span>
#include <tuple>
#include <utility>
#include <vector>
typedef struct spvc_compiler_s* spvc_compiler;
struct spvc_reflected_resource;
namespace PostProcessing {
class SlangPresetParser;
class SlangShaderPreprocessor;
class SlangShader final : public Shader
{
public:
SlangShader();
~SlangShader();
bool WantsUnscaledInput() const override;
bool LoadFromFile(std::string name, const char* path, Error* error);
bool LoadFromString(std::string name, std::string_view path, std::string_view code, Error* error);
bool ResizeTargets(u32 source_width, u32 source_height, GPUTexture::Format target_format, u32 target_width,
u32 target_height, u32 viewport_width, u32 viewport_height, Error* error) override;
bool CompilePipeline(GPUTexture::Format format, u32 width, u32 height, Error* error,
ProgressCallback* progress) override;
GPUDevice::PresentResult Apply(GPUTexture* input_color, GPUTexture* input_depth, GPUTexture* final_target,
GSVector4i final_rect, s32 orig_width, s32 orig_height, s32 native_width,
s32 native_height, u32 target_width, u32 target_height, float time) override;
private:
using TextureID = u32;
using UniformType = s32;
using AliasMap = std::vector<std::pair<std::string, u32>>;
enum class ScaleType : u8
{
Source,
Viewport,
Absolute,
Original,
};
static constexpr u32 MAX_ORIGINAL_HISTORY_SIZE = 16;
static constexpr TextureID TEXTURE_ID_SOURCE = 0xFFFFFFFFu;
static constexpr TextureID TEXTURE_ID_ORIGINAL = 0xFFFFFFFEu;
static constexpr TextureID TEXTURE_ID_ORIGINAL_HISTORY_START = TEXTURE_ID_ORIGINAL - MAX_ORIGINAL_HISTORY_SIZE;
static constexpr TextureID TEXTURE_ID_FEEDBACK = 0x80000000u;
struct Texture
{
std::string name;
std::string path;
std::unique_ptr<GPUTexture> texture;
std::unique_ptr<GPUTexture> feedback_texture;
GPUSampler* sampler;
bool linear_filter;
bool needs_feedback;
bool generate_mipmaps;
};
struct Uniform
{
UniformType type;
TextureID associated_texture;
bool push_constant;
u16 size;
u32 offset;
};
struct Pass
{
std::unique_ptr<GPUPipeline> pipeline;
// Textures
llvm::SmallVector<std::pair<TextureID, u32>, GPUDevice::MAX_TEXTURE_SAMPLERS> samplers;
// Uniforms
llvm::SmallVector<Uniform, 8> uniforms;
u32 uniforms_size = 0;
u32 push_constants_size = 0;
u32 frame_count_mod = 0;
bool is_reflected = false;
// Framebuffer
TextureID output_texture_id = 0;
GPUTexture::Format output_format = GPUTexture::Format::Unknown;
std::array<std::pair<ScaleType, float>, 2> output_scale = {};
GPUSampler::Config output_sampler_config = {};
std::string vertex_shader_code;
std::string fragment_shader_code;
DynamicHeapArray<u32> vertex_shader_spv;
DynamicHeapArray<u32> fragment_shader_spv;
std::string name;
};
static bool ParseScaleType(ScaleType* dst, std::string_view value, Error* error);
static GPUSampler::AddressMode ParseWrapMode(std::string_view value);
static std::unique_ptr<GPUPipeline> CreateBlitPipeline(GPUTexture::Format format, Error* error);
bool ParsePresetFile(std::string_view path, std::string_view code, Error* error);
bool ParsePresetTextures(std::string_view preset_path, const SlangPresetParser& parser, Error* error);
bool ParsePresetPass(std::string_view preset_path, const SlangPresetParser& parser, u32 idx, bool is_final_pass,
Error* error);
bool ReflectPass(Pass& pass, Error* error);
bool ReflectShader(Pass& pass, std::span<u32> spv, GPUShaderStage stage, Error* error);
bool ReflectPassUniforms(const spvc_compiler& scompiler, const spvc_reflected_resource& resource, Pass& pass,
bool push_constant, Error* error);
bool CompilePass(Pass& pass, Error* error);
bool UploadLUTTextures(Error* error);
std::optional<TextureID> FindTextureByName(std::string_view name, Error* error);
std::optional<Uniform> GetUniformInfo(std::string_view name, bool push_constant, u32 offset, u16 size, Error* error);
TinyString GetTextureNameForID(TextureID id) const;
std::tuple<GPUTexture*, GPUSampler*> GetTextureByID(const Pass& pass, TextureID id, GPUTexture* input_color) const;
void BindPassUniforms(const Pass& pass, u8* const push_constant_data, GPUTexture* input_color, GSVector2i output_size,
GSVector4i final_rect, s32 orig_width, s32 orig_height, s32 native_width, s32 native_height,
u32 target_width, u32 target_height, float time);
std::vector<Texture> m_textures;
std::vector<Pass> m_passes;
AliasMap m_aliases;
u32 m_frame_count = 0;
std::vector<std::unique_ptr<GPUTexture>> m_original_history_textures;
std::unique_ptr<GPUPipeline> m_output_blit_pipeline;
GPUTexture::Format m_output_framebuffer_format = GPUTexture::Format::Unknown;
};
} // namespace PostProcessing

View File

@@ -89,6 +89,7 @@
<ClInclude Include="postprocessing_shader.h" />
<ClInclude Include="postprocessing_shader_fx.h" />
<ClInclude Include="postprocessing_shader_glsl.h" />
<ClInclude Include="postprocessing_shader_slang.h" />
<ClInclude Include="sdl_input_source.h" />
<ClInclude Include="shadergen.h" />
<ClInclude Include="shiftjis.h" />
@@ -198,6 +199,7 @@
<ClCompile Include="postprocessing_shader.cpp" />
<ClCompile Include="postprocessing_shader_fx.cpp" />
<ClCompile Include="postprocessing_shader_glsl.cpp" />
<ClCompile Include="postprocessing_shader_slang.cpp" />
<ClCompile Include="sdl_audio_stream.cpp" />
<ClCompile Include="sdl_input_source.cpp" />
<ClCompile Include="shadergen.cpp" />

View File

@@ -78,6 +78,7 @@
<ClInclude Include="dyn_shaderc.h" />
<ClInclude Include="dyn_spirv_cross.h" />
<ClInclude Include="spirv_module.h" />
<ClInclude Include="postprocessing_shader_slang.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="state_wrapper.cpp" />
@@ -162,6 +163,7 @@
<ClCompile Include="opengl_context_sdl.cpp" />
<ClCompile Include="animated_image.cpp" />
<ClCompile Include="spirv_module.cpp" />
<ClCompile Include="postprocessing_shader_slang.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="metal_shaders.metal" />