From 1a79a2f19644f2e6a8da645afe0d68f3b2d5f8cd Mon Sep 17 00:00:00 2001 From: Stenzek Date: Thu, 23 Nov 2023 19:50:40 +1000 Subject: [PATCH] dep/reshadefx: Add manual include callbacks --- dep/reshadefx/include/effect_preprocessor.hpp | 19 ++++- dep/reshadefx/src/effect_preprocessor.cpp | 83 ++++++++++++------- src/util/postprocessing_shader_fx.cpp | 6 +- 3 files changed, 71 insertions(+), 37 deletions(-) diff --git a/dep/reshadefx/include/effect_preprocessor.hpp b/dep/reshadefx/include/effect_preprocessor.hpp index c11dc58c9..aa416d4e8 100644 --- a/dep/reshadefx/include/effect_preprocessor.hpp +++ b/dep/reshadefx/include/effect_preprocessor.hpp @@ -29,15 +29,26 @@ namespace reshadefx bool is_function_like = false; }; + // Callbacks for manual file reading. + using include_file_exists_callback = bool(*)(const std::string &path); + using include_read_file_callback = bool(*)(const std::string &path, std::string &data); + static bool stdfs_read_file_callback(const std::string &path, std::string& data); + static bool stdfs_file_exists_callback(const std::string &path); + // Define constructor explicitly because lexer class is not included here preprocessor(); ~preprocessor(); + /// + /// Sets callbacks to use for reading files. If this is not called, std::filesystem will be used. + /// + void set_include_callbacks(include_file_exists_callback file_exists, include_read_file_callback read_file); + /// /// Adds an include directory to the list of search paths used when resolving #include directives. /// /// Path to the directory to add. - void add_include_path(const std::filesystem::path &path); + void add_include_path(const std::string &path); /// /// Adds a new macro definition. This is equal to appending '#define name macro' to this preprocessor instance. @@ -62,14 +73,14 @@ namespace reshadefx /// /// Path to the file to parse. /// if parsing was successful, otherwise. - bool append_file(const std::filesystem::path &path); + bool append_file(const std::string &path); /// /// Parses the specified string and appends it to the output. /// /// String to parse. /// Optional file path to identify this string with. /// if parsing was successful, otherwise. - bool append_string(std::string source_code, const std::filesystem::path &path = std::filesystem::path()); + bool append_string(std::string source_code, const std::string &path = std::string()); /// /// Gets the list of error messages. @@ -144,6 +155,8 @@ namespace reshadefx void create_macro_replacement_list(macro ¯o); bool _success = true; + include_file_exists_callback _file_exists_cb; + include_read_file_callback _read_file_cb; std::string _output, _errors; std::string _current_token_raw_data; diff --git a/dep/reshadefx/src/effect_preprocessor.cpp b/dep/reshadefx/src/effect_preprocessor.cpp index ba491f098..9a03ec77c 100644 --- a/dep/reshadefx/src/effect_preprocessor.cpp +++ b/dep/reshadefx/src/effect_preprocessor.cpp @@ -61,27 +61,14 @@ static const int precedence_lookup[] = { 11, 11, 11, 11 // unary operators }; -static bool read_file(const std::filesystem::path &path, std::string &data) +static bool read_file(const std::string &path, std::string &data, reshadefx::preprocessor::include_read_file_callback &cb) { - std::ifstream file(path, std::ios::binary); - if (!file) + std::string file_data; + if (!cb(path, file_data)) return false; - // Read file contents into memory - std::error_code ec; - const uintmax_t file_size = std::filesystem::file_size(path, ec); - if (ec) - return false; - - std::string file_data(static_cast(file_size + 1), '\0'); - if (!file.read(file_data.data(), file_size)) - return false; - - // No longer need to have a handle open to the file, since all data was read, so can safely close it - file.close(); - // Append a new line feed to the end of the input string to avoid issues with parsing - file_data.back() = '\n'; + file_data.push_back('\n'); // Remove BOM (0xefbbbf means 0xfeff) if (file_data.size() >= 3 && @@ -94,6 +81,33 @@ static bool read_file(const std::filesystem::path &path, std::string &data) return true; } +bool reshadefx::preprocessor::stdfs_read_file_callback(const std::string &path, std::string &data) +{ + std::ifstream file(std::filesystem::path(path), std::ios::binary); + if (!file) + return false; + + // Read file contents into memory + std::error_code ec; + const uintmax_t file_size = std::filesystem::file_size(path, ec); + if (ec) + return false; + + data.reserve(file_size + 1); + data.resize(static_cast(file_size), '\0'); + if (!file.read(data.data(), file_size)) + return false; + + // No longer need to have a handle open to the file, since all data was read, so can safely close it + file.close(); + return true; +} + +bool reshadefx::preprocessor::stdfs_file_exists_callback(const std::string &path) +{ + return std::filesystem::exists(std::filesystem::path(path)); +} + template static std::string escape_string(std::string s) { @@ -103,16 +117,25 @@ static std::string escape_string(std::string s) } reshadefx::preprocessor::preprocessor() + : _file_exists_cb(stdfs_file_exists_callback) + , _read_file_cb(stdfs_read_file_callback) { } reshadefx::preprocessor::~preprocessor() { } -void reshadefx::preprocessor::add_include_path(const std::filesystem::path &path) +void reshadefx::preprocessor::set_include_callbacks(include_file_exists_callback file_exists, + include_read_file_callback read_file) +{ + _file_exists_cb = file_exists; + _read_file_cb = read_file; +} + +void reshadefx::preprocessor::add_include_path(const std::string &path) { assert(!path.empty()); - _include_paths.push_back(path); + _include_paths.push_back(std::filesystem::path(path)); } bool reshadefx::preprocessor::add_macro_definition(const std::string &name, const macro ¯o) { @@ -120,15 +143,15 @@ bool reshadefx::preprocessor::add_macro_definition(const std::string &name, cons return _macros.emplace(name, macro).second; } -bool reshadefx::preprocessor::append_file(const std::filesystem::path &path) +bool reshadefx::preprocessor::append_file(const std::string &path) { std::string source_code; - if (!read_file(path, source_code)) + if (!read_file(path, source_code, _read_file_cb)) return false; return append_string(std::move(source_code), path); } -bool reshadefx::preprocessor::append_string(std::string source_code, const std::filesystem::path &path) +bool reshadefx::preprocessor::append_string(std::string source_code, const std::string &path /* = std::string() */) { // Enforce all input strings to end with a line feed assert(!source_code.empty() && source_code.back() == '\n'); @@ -138,7 +161,7 @@ bool reshadefx::preprocessor::append_string(std::string source_code, const std:: // Give this push a name, so that lexer location starts at a new line // This is necessary in case this string starts with a preprocessor directive, since the lexer only reports those as such if they appear at the beginning of a new line // But without a name, the lexer location is set to the last token location, which most likely will not be at the start of the line - push(std::move(source_code), path.empty() ? "unknown" : path.u8string()); + push(std::move(source_code), path.empty() ? "unknown" : path); parse(); return _success; @@ -667,10 +690,9 @@ void reshadefx::preprocessor::parse_include() std::filesystem::path file_path = std::filesystem::u8path(_output_location.source); file_path.replace_filename(file_name); - std::error_code ec; - if (!std::filesystem::exists(file_path, ec)) + if (!_file_exists_cb(file_path.u8string())) for (const std::filesystem::path &include_path : _include_paths) - if (std::filesystem::exists(file_path = include_path / file_name, ec)) + if (_file_exists_cb((file_path = include_path / file_name).u8string())) break; const std::string file_path_string = file_path.u8string(); @@ -687,7 +709,7 @@ void reshadefx::preprocessor::parse_include() } else { - if (!read_file(file_path, input)) + if (!read_file(file_path_string, input, _read_file_cb)) return error(keyword_location, "could not open included file '" + file_name.u8string() + '\''); _file_cache.emplace(file_path_string, input); @@ -863,13 +885,12 @@ bool reshadefx::preprocessor::evaluate_expression() if (has_parentheses && !expect(tokenid::parenthesis_close)) return false; - std::error_code ec; - if (!std::filesystem::exists(file_path, ec)) + if (!_file_exists_cb(file_path.u8string())) for (const std::filesystem::path &include_path : _include_paths) - if (std::filesystem::exists(file_path = include_path / file_name, ec)) + if (_file_exists_cb((file_path = include_path / file_name).u8string())) break; - rpn[rpn_index++] = { std::filesystem::exists(file_path, ec) ? 1 : 0, false }; + rpn[rpn_index++] = { _file_exists_cb(file_path.u8string()) ? 1 : 0, false }; continue; } if (_token.literal_as_string == "defined") diff --git a/src/util/postprocessing_shader_fx.cpp b/src/util/postprocessing_shader_fx.cpp index c5804217a..33a8402ff 100644 --- a/src/util/postprocessing_shader_fx.cpp +++ b/src/util/postprocessing_shader_fx.cpp @@ -321,8 +321,8 @@ bool PostProcessing::ReShadeFXShader::CreateModule(s32 buffer_width, s32 buffer_ Error* error) { reshadefx::preprocessor pp; - pp.add_include_path(std::filesystem::path(Path::GetDirectory(m_filename))); - pp.add_include_path(std::filesystem::path(Path::Combine( + pp.add_include_path(std::string(Path::GetDirectory(m_filename))); + pp.add_include_path(std::string(Path::Combine( EmuFolders::Resources, "shaders" FS_OSPATH_SEPARATOR_STR "reshade" FS_OSPATH_SEPARATOR_STR "Shaders"))); pp.add_macro_definition("__RESHADE__", "50901"); pp.add_macro_definition("BUFFER_WIDTH", std::to_string(buffer_width)); // TODO: can we make these uniforms? @@ -350,7 +350,7 @@ bool PostProcessing::ReShadeFXShader::CreateModule(s32 buffer_width, s32 buffer_ break; } - if (!pp.append_file(std::filesystem::path(m_filename))) + if (!pp.append_file(m_filename)) { Error::SetString(error, fmt::format("Failed to preprocess:\n{}", pp.errors())); return false;