mirror of
				https://github.com/RetroDECK/Duckstation.git
				synced 2025-04-10 19:15:14 +00:00 
			
		
		
		
	dep/reshadefx: Add manual include callbacks
This commit is contained in:
		
							parent
							
								
									273979405d
								
							
						
					
					
						commit
						1a79a2f196
					
				|  | @ -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(); | ||||
| 
 | ||||
| 		/// <summary>
 | ||||
| 		/// Sets callbacks to use for reading files. If this is not called, std::filesystem will be used.
 | ||||
| 		/// </summary>
 | ||||
| 		void set_include_callbacks(include_file_exists_callback file_exists, include_read_file_callback read_file); | ||||
| 
 | ||||
| 		/// <summary>
 | ||||
| 		/// Adds an include directory to the list of search paths used when resolving #include directives.
 | ||||
| 		/// </summary>
 | ||||
| 		/// <param name="path">Path to the directory to add.</param>
 | ||||
| 		void add_include_path(const std::filesystem::path &path); | ||||
| 		void add_include_path(const std::string &path); | ||||
| 
 | ||||
| 		/// <summary>
 | ||||
| 		/// Adds a new macro definition. This is equal to appending '#define name macro' to this preprocessor instance.
 | ||||
|  | @ -62,14 +73,14 @@ namespace reshadefx | |||
| 		/// </summary>
 | ||||
| 		/// <param name="path">Path to the file to parse.</param>
 | ||||
| 		/// <returns><see langword="true"/> if parsing was successful, <see langword="false"/> otherwise.</returns>
 | ||||
| 		bool append_file(const std::filesystem::path &path); | ||||
| 		bool append_file(const std::string &path); | ||||
| 		/// <summary>
 | ||||
| 		/// Parses the specified string and appends it to the output.
 | ||||
| 		/// </summary>
 | ||||
| 		/// <param name="source_code">String to parse.</param>
 | ||||
| 		/// <param name="path">Optional file path to identify this string with.</param>
 | ||||
| 		/// <returns><see langword="true"/> if parsing was successful, <see langword="false"/> otherwise.</returns>
 | ||||
| 		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()); | ||||
| 
 | ||||
| 		/// <summary>
 | ||||
| 		/// 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; | ||||
|  |  | |||
|  | @ -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<size_t>(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<size_t>(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 <char ESCAPE_CHAR = '\\'> | ||||
| 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") | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Stenzek
						Stenzek