From 05fb634f9102f18e6a2c9e84939d0fb0a3618671 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Mon, 13 Mar 2023 15:45:18 +0100 Subject: [PATCH] [util] Use __wine_dbg_output if available --- README.md | 7 ++++- src/util/log/log.cpp | 74 +++++++++++++++++++++++++++++--------------- src/util/log/log.h | 22 ++++++++----- 3 files changed, 69 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index ae06e41a..f5ebf671 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ cp x32/*.dll $WINEPREFIX/drive_c/windows/syswow64 winecfg ``` -Verify that your application uses DXVK instead of wined3d by checking for the presence of the log file `d3d9.log` or `d3d11.log` in the application's directory, or by enabling the HUD (see notes below). +Verify that your application uses DXVK instead of wined3d by by enabling the HUD (see notes below). In order to remove DXVK from a prefix, remove the DLLs and DLL overrides, and run `wineboot -u` to restore the original DLL files. @@ -70,6 +70,11 @@ Before reporting an issue, please check the [Wiki](https://github.com/doitsujin/ ### Online multi-player games Manipulation of Direct3D libraries in multi-player games may be considered cheating and can get your account **banned**. This may also apply to single-player games with an embedded or dedicated multiplayer portion. **Use at your own risk.** +### Logs +When used with Wine, DXVK will print log messages to `stderr`. Additionally, standalone log files can optionally be generated by setting the `DXVK_LOG_PATH` variable, where log files in the given directory will be called `app_d3d11.log`, `app_dxgi.log` etc., where `app` is the name of the game executable. + +On Windows, log files will be created in the game's working directory by default, which is usually next to the game executable. + ### HUD The `DXVK_HUD` environment variable controls a HUD which can display the framerate and some stat counters. It accepts a comma-separated list of the following options: - `devinfo`: Displays the name of the GPU and the driver version. diff --git a/src/util/log/log.cpp b/src/util/log/log.cpp index b3eaa37a..da8b620d 100644 --- a/src/util/log/log.cpp +++ b/src/util/log/log.cpp @@ -1,17 +1,14 @@ +#include + #include "log.h" #include "../util_env.h" namespace dxvk { - Logger::Logger(const std::string& file_name) - : m_minLevel(getMinLogLevel()) { - if (m_minLevel != LogLevel::None) { - auto path = getFileName(file_name); + Logger::Logger(const std::string& fileName) + : m_minLevel(getMinLogLevel()), m_fileName(fileName) { - if (!path.empty()) - m_fileStream = std::ofstream(str::topath(path.c_str()).c_str()); - } } @@ -57,19 +54,61 @@ namespace dxvk { const char* prefix = s_prefixes.at(static_cast(level)); + if (!std::exchange(m_initialized, true)) { +#ifdef _WIN32 + HMODULE ntdll = GetModuleHandleA("ntdll.dll"); + + if (ntdll) + m_wineLogOutput = reinterpret_cast(GetProcAddress(ntdll, "__wine_dbg_output")); +#endif + auto path = getFileName(m_fileName); + + if (!path.empty()) + m_fileStream = std::ofstream(str::topath(path.c_str()).c_str()); + } + std::stringstream stream(message); - std::string line; + std::string line; while (std::getline(stream, line, '\n')) { - std::cerr << prefix << line << std::endl; + std::stringstream outstream; + outstream << prefix << line << std::endl; + + std::string adjusted = outstream.str(); + + if (!adjusted.empty()) { + if (m_wineLogOutput) + m_wineLogOutput(adjusted.c_str()); + else + std::cerr << adjusted; + } if (m_fileStream) - m_fileStream << prefix << line << std::endl; + m_fileStream << adjusted; } } } + std::string Logger::getFileName(const std::string& base) { + std::string path = env::getEnvVar("DXVK_LOG_PATH"); + + if (path == "none") + return std::string(); + + // Don't create a log file if we're writing to wine's console output + if (path.empty() && m_wineLogOutput) + return std::string(); + + if (!path.empty() && *path.rbegin() != '/') + path += '/'; + + std::string exeName = env::getExeBaseName(); + path += exeName + "_" + base; + return path; + } + + LogLevel Logger::getMinLogLevel() { const std::array, 6> logLevels = {{ { "trace", LogLevel::Trace }, @@ -90,19 +129,4 @@ namespace dxvk { return LogLevel::Info; } - - std::string Logger::getFileName(const std::string& base) { - std::string path = env::getEnvVar("DXVK_LOG_PATH"); - - if (path == "none") - return ""; - - if (!path.empty() && *path.rbegin() != '/') - path += '/'; - - std::string exeName = env::getExeBaseName(); - path += exeName + "_" + base; - return path; - } - } diff --git a/src/util/log/log.h b/src/util/log/log.h index 5d301628..3589d709 100644 --- a/src/util/log/log.h +++ b/src/util/log/log.h @@ -18,6 +18,8 @@ namespace dxvk { None = 5, }; + using PFN_wineLogOutput = int (STDMETHODCALLTYPE *)(const char *); + /** * \brief Logger * @@ -44,20 +46,24 @@ namespace dxvk { private: - static Logger s_instance; + static Logger s_instance; - const LogLevel m_minLevel; - - dxvk::mutex m_mutex; - std::ofstream m_fileStream; + const LogLevel m_minLevel; + const std::string m_fileName; + dxvk::mutex m_mutex; + std::ofstream m_fileStream; + + bool m_initialized = false; + PFN_wineLogOutput m_wineLogOutput = nullptr; + void emitMsg(LogLevel level, const std::string& message); - static LogLevel getMinLogLevel(); - - static std::string getFileName( + std::string getFileName( const std::string& base); + static LogLevel getMinLogLevel(); + }; }