From ed566919f468e45ecb56e4e61185d98142a2cd1c Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Thu, 10 Sep 2026 15:14:02 +0200 Subject: [vulkan, android] Add feature of post-processing shaders on Android (#4348) Very self-explanatory; implementation of the feature for post-processing shaders for Android (at least for now); will allow users to enhance the graphic quality of video games based on the use of multiple shaders adjustable, presets and more, inspired on the PPSSPP implementation, this feature adds 22 customizable shaders (1 pass) that lives on the overlay of the screen, which means that aside of the capability to chain multiple shaders on the screen, this doesn't have depths (pixel/ depth z-buffer) so it ensures the performance with it's use. Few shaders were a faithful port from PPSSPP with their respective attribution on the shader headers for their respective owners; and there are adaptations from public references/ cinematographic (Anime4K) and the rest are my own addition. _Special Credits:_ 1.- PPSSPP Team for their contribution on the public references for shaders: Henrik Rydgard, ShadX, SimoneT, KillaMaaki and guest(r). 2.- Niklas Haas. 3.- bloc97. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4348 Reviewed-by: lizzie Reviewed-by: Maufeat --- src/video_core/post_processing/fx_compile.cpp | 105 ++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 src/video_core/post_processing/fx_compile.cpp (limited to 'src/video_core/post_processing/fx_compile.cpp') diff --git a/src/video_core/post_processing/fx_compile.cpp b/src/video_core/post_processing/fx_compile.cpp new file mode 100644 index 0000000000..5ee11e9187 --- /dev/null +++ b/src/video_core/post_processing/fx_compile.cpp @@ -0,0 +1,105 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include +#include + +#include "effect_codegen.hpp" +#include "effect_parser.hpp" +#include "effect_preprocessor.hpp" + +#include "common/fs/fs.h" +#include "common/fs/fs_util.h" +#include "video_core/post_processing/fx_compile.h" +#include "video_core/post_processing/fx_effect.h" + +namespace VideoCore { + +FxCompileResult CompileFxEffect(const std::filesystem::path& path, u32 width, u32 height, + u32 color_bit_depth) { + FxCompileResult result; + + if (!Common::FS::Exists(path)) { + result.error = "Effect file not found: " + Common::FS::PathToUTF8String(path); + return result; + } + + reshadefx::preprocessor preprocessor; + preprocessor.add_macro_definition("__RESHADE__", "60800"); + preprocessor.add_macro_definition("__RESHADE_PERFORMANCE_MODE__", "1"); + preprocessor.add_macro_definition("__RENDERER__", "0x20000"); + preprocessor.add_macro_definition("__VENDOR__", "0"); + preprocessor.add_macro_definition("__DEVICE__", "0"); + preprocessor.add_macro_definition("__APPLICATION__", "0"); + preprocessor.add_macro_definition("BUFFER_WIDTH", std::to_string(width)); + preprocessor.add_macro_definition("BUFFER_HEIGHT", std::to_string(height)); + preprocessor.add_macro_definition("BUFFER_RCP_WIDTH", "(1.0 / BUFFER_WIDTH)"); + preprocessor.add_macro_definition("BUFFER_RCP_HEIGHT", "(1.0 / BUFFER_HEIGHT)"); + preprocessor.add_macro_definition("BUFFER_COLOR_DEPTH", std::to_string(color_bit_depth)); + preprocessor.add_macro_definition("BUFFER_COLOR_BIT_DEPTH", std::to_string(color_bit_depth)); + + for (const auto& include : GetFxIncludePaths(path)) { + preprocessor.add_include_path(include); + } + + if (!preprocessor.append_file(path)) { + result.error = preprocessor.errors(); + if (result.error.empty()) { + result.error = "Failed to preprocess " + Common::FS::PathToUTF8String(path); + } + return result; + } + + std::unique_ptr backend( + reshadefx::create_codegen_spirv(true, false, false, false, true)); + + reshadefx::parser parser; + if (!parser.parse(preprocessor.output(), backend.get())) { + result.error = parser.errors(); + if (result.error.empty()) { + result.error = "Failed to parse " + Common::FS::PathToUTF8String(path); + } + return result; + } + + result.module = backend->module(); + + std::set wanted; + for (const auto& technique : result.module.techniques) { + for (const auto& pass : technique.passes) { + if (!pass.vs_entry_point.empty()) { + wanted.insert(pass.vs_entry_point); + } + if (!pass.ps_entry_point.empty()) { + wanted.insert(pass.ps_entry_point); + } + } + } + + for (const auto& name : wanted) { + std::string binary; + std::string assembly; + std::string errors; + if (!backend->assemble_code_for_entry_point(name, binary, assembly, errors)) { + result.error = "Failed to assemble entry point '" + name + "': " + errors; + return result; + } + if (binary.size() % sizeof(u32) != 0) { + result.error = "Entry point '" + name + "' produced a malformed SPIR-V module"; + return result; + } + + std::vector words(binary.size() / sizeof(u32)); + std::memcpy(words.data(), binary.data(), binary.size()); + result.entry_points.emplace(name, std::move(words)); + } + + if (result.entry_points.empty()) { + result.error = "Effect declares no usable entry points"; + } + + return result; +} + +} // namespace VideoCore -- cgit v1.2.3