mirror of
https://github.com/stenzek/duckstation.git
synced 2026-02-13 18:04:32 +00:00
PostProcessing: Support loading slang shaders/presets
Compatibility will likely vary quite a bit.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
2084
src/util/postprocessing_shader_slang.cpp
Normal file
2084
src/util/postprocessing_shader_slang.cpp
Normal file
File diff suppressed because it is too large
Load Diff
151
src/util/postprocessing_shader_slang.h
Normal file
151
src/util/postprocessing_shader_slang.h
Normal 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
|
||||
@@ -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" />
|
||||
|
||||
@@ -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" />
|
||||
|
||||
Reference in New Issue
Block a user