diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index e5d455e13..c966446e4 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -32,6 +32,7 @@ add_library(common
layered_settings_interface.h
log.cpp
log.h
+ log_channels.h
memmap.cpp
memmap.h
md5_digest.cpp
diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj
index bbaab73d1..ab8e27fa0 100644
--- a/src/common/common.vcxproj
+++ b/src/common/common.vcxproj
@@ -24,6 +24,7 @@
+
diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters
index a671d44e9..90a750fea 100644
--- a/src/common/common.vcxproj.filters
+++ b/src/common/common.vcxproj.filters
@@ -49,6 +49,7 @@
+
diff --git a/src/common/log.cpp b/src/common/log.cpp
index e6ff17134..0b05b9432 100644
--- a/src/common/log.cpp
+++ b/src/common/log.cpp
@@ -9,6 +9,8 @@
#include "fmt/format.h"
+#include
+#include
#include
#include
#include
@@ -34,12 +36,15 @@ struct RegisteredCallback
};
} // namespace
+using ChannelBitSet = std::bitset(Channel::MaxCount)>;
+
static void RegisterCallback(CallbackFunctionType callbackFunction, void* pUserParam,
const std::unique_lock& lock);
static void UnregisterCallback(CallbackFunctionType callbackFunction, void* pUserParam,
const std::unique_lock& lock);
-static bool FilterTest(Level level, const char* channelName, const std::unique_lock& lock);
-static void ExecuteCallbacks(const char* channelName, const char* functionName, Level level, std::string_view message,
+
+static bool FilterTest(Channel channel, Level level);
+static void ExecuteCallbacks(Channel channel, const char* functionName, Level level, std::string_view message,
const std::unique_lock& lock);
static void FormatLogMessageForDisplay(fmt::memory_buffer& buffer, const char* channelName, const char* functionName,
Level level, std::string_view message, bool timestamp, bool ansi_color_code,
@@ -61,38 +66,61 @@ static void FormatLogMessageAndPrintW(const char* channelName, const char* funct
const T& callback);
#endif
-static const char s_log_level_characters[static_cast(Level::Count)] = {'X', 'E', 'W', 'I', 'V', 'D', 'B', 'T'};
+ALWAYS_INLINE static Channel UnpackLogChannel(PackedChannelAndLevel cat)
+{
+ return static_cast(cat >> 3);
+}
-static std::vector s_callbacks;
-static std::mutex s_callback_mutex;
+ALWAYS_INLINE static Level UnpackLogLevel(PackedChannelAndLevel cat)
+{
+ return static_cast(cat & 0x7);
+}
-static Common::Timer::Value s_start_timestamp = Common::Timer::GetCurrentValue();
+static constexpr const std::array(Level::MaxCount)> s_log_level_characters = {
+ {'X', 'E', 'W', 'I', 'V', 'D', 'B', 'T'}};
-static std::string s_log_filter;
-static Level s_log_level = Level::None;
-static bool s_console_output_enabled = false;
-static bool s_console_output_timestamps = false;
-static bool s_file_output_enabled = false;
-static bool s_file_output_timestamp = false;
-static bool s_debug_output_enabled = false;
+static constexpr const std::array(Channel::MaxCount)> s_log_channel_names = {{
+#define LOG_CHANNEL_NAME(X) #X,
+ ENUMERATE_LOG_CHANNELS(LOG_CHANNEL_NAME)
+#undef LOG_CHANNEL_NAME
+}};
+
+namespace {
+
+struct State
+{
+ Level log_level = Level::Trace;
+ ChannelBitSet log_channels_enabled = ChannelBitSet().set();
+
+ std::vector callbacks;
+ std::mutex callbacks_mutex;
+
+ Common::Timer::Value start_timestamp = Common::Timer::GetCurrentValue();
+
+ FileSystem::ManagedCFilePtr file_handle;
+
+ bool console_output_enabled = false;
+ bool console_output_timestamps = false;
+ bool file_output_enabled = false;
+ bool file_output_timestamp = false;
+ bool debug_output_enabled = false;
#ifdef _WIN32
-static HANDLE s_hConsoleStdIn = NULL;
-static HANDLE s_hConsoleStdOut = NULL;
-static HANDLE s_hConsoleStdErr = NULL;
+ HANDLE hConsoleStdIn = NULL;
+ HANDLE hConsoleStdOut = NULL;
+ HANDLE hConsoleStdErr = NULL;
#endif
-} // namespace Log
+};
-std::unique_ptr s_file_handle(nullptr, [](std::FILE* fp) {
- if (fp)
- {
- std::fclose(fp);
- }
-});
+} // namespace
+
+ALIGN_TO_CACHE_LINE static State s_state;
+
+} // namespace Log
void Log::RegisterCallback(CallbackFunctionType callbackFunction, void* pUserParam)
{
- std::unique_lock lock(s_callback_mutex);
+ std::unique_lock lock(s_state.callbacks_mutex);
RegisterCallback(callbackFunction, pUserParam, lock);
}
@@ -103,31 +131,42 @@ void Log::RegisterCallback(CallbackFunctionType callbackFunction, void* pUserPar
Callback.Function = callbackFunction;
Callback.Parameter = pUserParam;
- s_callbacks.push_back(std::move(Callback));
+ s_state.callbacks.push_back(std::move(Callback));
}
void Log::UnregisterCallback(CallbackFunctionType callbackFunction, void* pUserParam)
{
- std::unique_lock lock(s_callback_mutex);
+ std::unique_lock lock(s_state.callbacks_mutex);
UnregisterCallback(callbackFunction, pUserParam, lock);
}
void Log::UnregisterCallback(CallbackFunctionType callbackFunction, void* pUserParam,
const std::unique_lock& lock)
{
- for (auto iter = s_callbacks.begin(); iter != s_callbacks.end(); ++iter)
+ for (auto iter = s_state.callbacks.begin(); iter != s_state.callbacks.end(); ++iter)
{
if (iter->Function == callbackFunction && iter->Parameter == pUserParam)
{
- s_callbacks.erase(iter);
+ s_state.callbacks.erase(iter);
break;
}
}
}
+const std::array(Log::Channel::MaxCount)>& Log::GetChannelNames()
+{
+ return s_log_channel_names;
+}
+
float Log::GetCurrentMessageTime()
{
- return static_cast(Common::Timer::ConvertValueToSeconds(Common::Timer::GetCurrentValue() - s_start_timestamp));
+ return static_cast(
+ Common::Timer::ConvertValueToSeconds(Common::Timer::GetCurrentValue() - s_state.start_timestamp));
+}
+
+bool Log::AreTimestampsEnabled()
+{
+ return s_state.console_output_timestamps || s_state.file_output_timestamp;
}
bool Log::IsConsoleOutputCurrentlyAvailable()
@@ -146,19 +185,20 @@ bool Log::IsConsoleOutputCurrentlyAvailable()
bool Log::IsConsoleOutputEnabled()
{
- return s_console_output_enabled;
+ return s_state.console_output_enabled;
}
bool Log::IsDebugOutputEnabled()
{
- return s_debug_output_enabled;
+ return s_state.debug_output_enabled;
}
-void Log::ExecuteCallbacks(const char* channelName, const char* functionName, Level level, std::string_view message,
+void Log::ExecuteCallbacks(Channel channel, const char* functionName, Level level, std::string_view message,
const std::unique_lock& lock)
{
- for (RegisteredCallback& callback : s_callbacks)
- callback.Function(callback.Parameter, channelName, functionName, level, message);
+ for (RegisteredCallback& callback : s_state.callbacks)
+ callback.Function(callback.Parameter, s_log_channel_names[static_cast(channel)], functionName, level,
+ message);
}
ALWAYS_INLINE_RELEASE void Log::FormatLogMessageForDisplay(fmt::memory_buffer& buffer, const char* channelName,
@@ -166,7 +206,7 @@ ALWAYS_INLINE_RELEASE void Log::FormatLogMessageForDisplay(fmt::memory_buffer& b
std::string_view message, bool timestamp,
bool ansi_color_code, bool newline)
{
- static constexpr std::string_view s_ansi_color_codes[static_cast(Level::Count)] = {
+ static constexpr const std::array s_ansi_color_codes = {
"\033[0m"sv, // None
"\033[1;31m"sv, // Error
"\033[1;33m"sv, // Warning
@@ -277,19 +317,19 @@ static bool EnableVirtualTerminalProcessing(HANDLE hConsole)
void Log::ConsoleOutputLogCallback(void* pUserParam, const char* channelName, const char* functionName, Level level,
std::string_view message)
{
- if (!s_console_output_enabled)
+ if (!s_state.console_output_enabled)
return;
#if defined(_WIN32)
- FormatLogMessageAndPrintW(channelName, functionName, level, message, s_console_output_timestamps, true, true,
- [level](const std::wstring_view& message) {
- HANDLE hOutput = (level <= Level::Warning) ? s_hConsoleStdErr : s_hConsoleStdOut;
- DWORD chars_written;
- WriteConsoleW(hOutput, message.data(), static_cast(message.length()),
- &chars_written, nullptr);
- });
+ FormatLogMessageAndPrintW(
+ channelName, functionName, level, message, s_state.console_output_timestamps, true, true,
+ [level](const std::wstring_view& message) {
+ HANDLE hOutput = (level <= Level::Warning) ? s_state.hConsoleStdErr : s_state.hConsoleStdOut;
+ DWORD chars_written;
+ WriteConsoleW(hOutput, message.data(), static_cast(message.length()), &chars_written, nullptr);
+ });
#elif !defined(__ANDROID__)
- FormatLogMessageAndPrint(channelName, functionName, level, message, s_console_output_timestamps, true, true,
+ FormatLogMessageAndPrint(channelName, functionName, level, message, s_state.console_output_timestamps, true, true,
[level](std::string_view message) {
const int outputFd = (level <= Log::Level::Warning) ? STDERR_FILENO : STDOUT_FILENO;
write(outputFd, message.data(), message.length());
@@ -300,7 +340,7 @@ void Log::ConsoleOutputLogCallback(void* pUserParam, const char* channelName, co
void Log::DebugOutputLogCallback(void* pUserParam, const char* channelName, const char* functionName, Level level,
std::string_view message)
{
- if (!s_debug_output_enabled)
+ if (!s_state.debug_output_enabled)
return;
#if defined(_WIN32)
@@ -328,13 +368,13 @@ void Log::DebugOutputLogCallback(void* pUserParam, const char* channelName, cons
void Log::SetConsoleOutputParams(bool enabled, bool timestamps)
{
- std::unique_lock lock(s_callback_mutex);
+ std::unique_lock lock(s_state.callbacks_mutex);
- s_console_output_timestamps = timestamps;
- if (s_console_output_enabled == enabled)
+ s_state.console_output_timestamps = timestamps;
+ if (s_state.console_output_enabled == enabled)
return;
- s_console_output_enabled = enabled;
+ s_state.console_output_enabled = enabled;
#if defined(_WIN32)
// On windows, no console is allocated by default on a windows based application
@@ -355,12 +395,12 @@ void Log::SetConsoleOutputParams(bool enabled, bool timestamps)
if (!AttachConsole(ATTACH_PARENT_PROCESS) && !AllocConsole())
return;
- s_hConsoleStdIn = GetStdHandle(STD_INPUT_HANDLE);
- s_hConsoleStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
- s_hConsoleStdErr = GetStdHandle(STD_ERROR_HANDLE);
+ s_state.hConsoleStdIn = GetStdHandle(STD_INPUT_HANDLE);
+ s_state.hConsoleStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
+ s_state.hConsoleStdErr = GetStdHandle(STD_ERROR_HANDLE);
- EnableVirtualTerminalProcessing(s_hConsoleStdOut);
- EnableVirtualTerminalProcessing(s_hConsoleStdErr);
+ EnableVirtualTerminalProcessing(s_state.hConsoleStdOut);
+ EnableVirtualTerminalProcessing(s_state.hConsoleStdErr);
std::FILE* fp;
freopen_s(&fp, "CONIN$", "r", stdin);
@@ -371,9 +411,9 @@ void Log::SetConsoleOutputParams(bool enabled, bool timestamps)
}
else
{
- s_hConsoleStdIn = old_stdin;
- s_hConsoleStdOut = old_stdout;
- s_hConsoleStdErr = old_stderr;
+ s_state.hConsoleStdIn = old_stdin;
+ s_state.hConsoleStdOut = old_stdout;
+ s_state.hConsoleStdErr = old_stderr;
}
}
else
@@ -391,9 +431,9 @@ void Log::SetConsoleOutputParams(bool enabled, bool timestamps)
SetStdHandle(STD_OUTPUT_HANDLE, old_stdout);
SetStdHandle(STD_INPUT_HANDLE, old_stdin);
- s_hConsoleStdIn = NULL;
- s_hConsoleStdOut = NULL;
- s_hConsoleStdErr = NULL;
+ s_state.hConsoleStdIn = NULL;
+ s_state.hConsoleStdOut = NULL;
+ s_state.hConsoleStdErr = NULL;
FreeConsole();
}
@@ -408,11 +448,11 @@ void Log::SetConsoleOutputParams(bool enabled, bool timestamps)
void Log::SetDebugOutputParams(bool enabled)
{
- std::unique_lock lock(s_callback_mutex);
- if (s_debug_output_enabled == enabled)
+ std::unique_lock lock(s_state.callbacks_mutex);
+ if (s_state.debug_output_enabled == enabled)
return;
- s_debug_output_enabled = enabled;
+ s_state.debug_output_enabled = enabled;
if (enabled)
RegisterCallback(DebugOutputLogCallback, nullptr, lock);
else
@@ -422,27 +462,27 @@ void Log::SetDebugOutputParams(bool enabled)
void Log::FileOutputLogCallback(void* pUserParam, const char* channelName, const char* functionName, Level level,
std::string_view message)
{
- if (!s_file_output_enabled)
+ if (!s_state.file_output_enabled)
return;
FormatLogMessageAndPrint(channelName, functionName, level, message, true, false, true, [](std::string_view message) {
- std::fwrite(message.data(), 1, message.size(), s_file_handle.get());
- std::fflush(s_file_handle.get());
+ std::fwrite(message.data(), 1, message.size(), s_state.file_handle.get());
+ std::fflush(s_state.file_handle.get());
});
}
void Log::SetFileOutputParams(bool enabled, const char* filename, bool timestamps /* = true */)
{
- std::unique_lock lock(s_callback_mutex);
- if (s_file_output_enabled == enabled)
+ std::unique_lock lock(s_state.callbacks_mutex);
+ if (s_state.file_output_enabled == enabled)
return;
if (enabled)
{
- s_file_handle.reset(FileSystem::OpenCFile(filename, "wb"));
- if (!s_file_handle) [[unlikely]]
+ s_state.file_handle = FileSystem::OpenManagedCFile(filename, "wb");
+ if (!s_state.file_handle) [[unlikely]]
{
- ExecuteCallbacks("Log", __FUNCTION__, Level::Error,
+ ExecuteCallbacks(Log::Channel::Log, __FUNCTION__, Level::Error,
TinyString::from_format("Failed to open log file '{}'", filename), lock);
return;
}
@@ -452,86 +492,88 @@ void Log::SetFileOutputParams(bool enabled, const char* filename, bool timestamp
else
{
UnregisterCallback(FileOutputLogCallback, nullptr, lock);
- s_file_handle.reset();
+ s_state.file_handle.reset();
}
- s_file_output_enabled = enabled;
- s_file_output_timestamp = timestamps;
+ s_state.file_output_enabled = enabled;
+ s_state.file_output_timestamp = timestamps;
}
Log::Level Log::GetLogLevel()
{
- return s_log_level;
+ return s_state.log_level;
}
-bool Log::IsLogVisible(Level level, const char* channelName)
+bool Log::IsLogVisible(Level level, Channel channel)
{
- if (level > s_log_level)
- return false;
-
- std::unique_lock lock(s_callback_mutex);
- return FilterTest(level, channelName, lock);
+ return FilterTest(channel, level);
}
void Log::SetLogLevel(Level level)
{
- std::unique_lock lock(s_callback_mutex);
- DebugAssert(level < Level::Count);
- s_log_level = level;
+ std::unique_lock lock(s_state.callbacks_mutex);
+ DebugAssert(level < Level::MaxCount);
+ s_state.log_level = level;
}
-void Log::SetLogFilter(std::string_view filter)
+void Log::SetLogChannelEnabled(Channel channel, bool enabled)
{
- std::unique_lock lock(s_callback_mutex);
- if (s_log_filter != filter)
- s_log_filter = filter;
+ std::unique_lock lock(s_state.callbacks_mutex);
+ DebugAssert(channel < Channel::MaxCount);
+ s_state.log_channels_enabled[static_cast(channel)] = enabled;
}
-ALWAYS_INLINE_RELEASE bool Log::FilterTest(Level level, const char* channelName,
- const std::unique_lock& lock)
+ALWAYS_INLINE_RELEASE bool Log::FilterTest(Channel channel, Level level)
{
- return (level <= s_log_level && s_log_filter.find(channelName) == std::string::npos);
+ return (level <= s_state.log_level && s_state.log_channels_enabled[static_cast(channel)]);
}
-void Log::Write(const char* channelName, Level level, std::string_view message)
+void Log::Write(PackedChannelAndLevel cat, std::string_view message)
{
- std::unique_lock lock(s_callback_mutex);
- if (!FilterTest(level, channelName, lock))
+ const Channel channel = UnpackLogChannel(cat);
+ const Level level = UnpackLogLevel(cat);
+ if (!FilterTest(channel, level))
return;
- ExecuteCallbacks(channelName, nullptr, level, message, lock);
+ std::unique_lock lock(s_state.callbacks_mutex);
+ ExecuteCallbacks(channel, nullptr, level, message, lock);
}
-void Log::Write(const char* channelName, const char* functionName, Level level, std::string_view message)
+void Log::Write(PackedChannelAndLevel cat, const char* functionName, std::string_view message)
{
- std::unique_lock lock(s_callback_mutex);
- if (!FilterTest(level, channelName, lock))
+ const Channel channel = UnpackLogChannel(cat);
+ const Level level = UnpackLogLevel(cat);
+ if (!FilterTest(channel, level))
return;
- ExecuteCallbacks(channelName, functionName, level, message, lock);
+ std::unique_lock lock(s_state.callbacks_mutex);
+ ExecuteCallbacks(channel, functionName, level, message, lock);
}
-void Log::WriteFmtArgs(const char* channelName, Level level, fmt::string_view fmt, fmt::format_args args)
+void Log::WriteFmtArgs(PackedChannelAndLevel cat, fmt::string_view fmt, fmt::format_args args)
{
- std::unique_lock lock(s_callback_mutex);
- if (!FilterTest(level, channelName, lock))
+ const Channel channel = UnpackLogChannel(cat);
+ const Level level = UnpackLogLevel(cat);
+ if (!FilterTest(channel, level))
return;
fmt::memory_buffer buffer;
fmt::vformat_to(std::back_inserter(buffer), fmt, args);
- ExecuteCallbacks(channelName, nullptr, level, std::string_view(buffer.data(), buffer.size()), lock);
+ std::unique_lock lock(s_state.callbacks_mutex);
+ ExecuteCallbacks(channel, nullptr, level, std::string_view(buffer.data(), buffer.size()), lock);
}
-void Log::WriteFmtArgs(const char* channelName, const char* functionName, Level level, fmt::string_view fmt,
- fmt::format_args args)
+void Log::WriteFmtArgs(PackedChannelAndLevel cat, const char* functionName, fmt::string_view fmt, fmt::format_args args)
{
- std::unique_lock lock(s_callback_mutex);
- if (!FilterTest(level, channelName, lock))
+ const Channel channel = UnpackLogChannel(cat);
+ const Level level = UnpackLogLevel(cat);
+ if (!FilterTest(channel, level))
return;
fmt::memory_buffer buffer;
fmt::vformat_to(std::back_inserter(buffer), fmt, args);
- ExecuteCallbacks(channelName, functionName, level, std::string_view(buffer.data(), buffer.size()), lock);
+ std::unique_lock lock(s_state.callbacks_mutex);
+ ExecuteCallbacks(channel, functionName, level, std::string_view(buffer.data(), buffer.size()), lock);
}
diff --git a/src/common/log.h b/src/common/log.h
index 43d4b7798..deffc1361 100644
--- a/src/common/log.h
+++ b/src/common/log.h
@@ -3,17 +3,19 @@
#pragma once
+#include "log_channels.h"
#include "types.h"
#include "fmt/base.h"
+#include
#include
#include
#include
#include
namespace Log {
-enum class Level
+enum class Level : u32
{
None, // Silences all log traffic
Error,
@@ -24,7 +26,16 @@ enum class Level
Debug,
Trace,
- Count
+ MaxCount
+};
+
+enum class Channel : u32
+{
+#define LOG_CHANNEL_ENUM(X) X,
+ ENUMERATE_LOG_CHANNELS(LOG_CHANNEL_ENUM)
+#undef LOG_CHANNEL_ENUM
+
+ MaxCount
};
// log message callback type
@@ -37,8 +48,12 @@ void RegisterCallback(CallbackFunctionType callbackFunction, void* pUserParam);
// unregisters a log callback
void UnregisterCallback(CallbackFunctionType callbackFunction, void* pUserParam);
+// returns a list of all log channels
+const std::array(Channel::MaxCount)>& GetChannelNames();
+
// returns the time in seconds since the start of the process
float GetCurrentMessageTime();
+bool AreTimestampsEnabled();
// adds a standard console output
bool IsConsoleOutputCurrentlyAvailable();
@@ -56,49 +71,54 @@ void SetFileOutputParams(bool enabled, const char* filename, bool timestamps = t
Level GetLogLevel();
// Returns true if log messages for the specified log level/filter would not be filtered (and visible).
-bool IsLogVisible(Level level, const char* channelName);
+bool IsLogVisible(Level level, Channel channel);
// Sets global filtering level, messages below this level won't be sent to any of the logging sinks.
void SetLogLevel(Level level);
// Sets global filter, any messages from these channels won't be sent to any of the logging sinks.
-void SetLogFilter(std::string_view filter);
+void SetLogChannelEnabled(Channel channel, bool enabled);
+
+// Packs a level and channel into one 16-bit number.
+using PackedChannelAndLevel = u32;
+[[maybe_unused]] ALWAYS_INLINE static u32 PackChannelAndLevel(Channel channel, Level level)
+{
+ return ((static_cast(channel) << 3) | static_cast(level));
+}
// writes a message to the log
-void Write(const char* channelName, Level level, std::string_view message);
-void Write(const char* channelName, const char* functionName, Level level, std::string_view message);
-void WriteFmtArgs(const char* channelName, Level level, fmt::string_view fmt, fmt::format_args args);
-void WriteFmtArgs(const char* channelName, const char* functionName, Level level, fmt::string_view fmt,
- fmt::format_args args);
+void Write(PackedChannelAndLevel cat, std::string_view message);
+void Write(PackedChannelAndLevel cat, const char* functionName, std::string_view message);
+void WriteFmtArgs(PackedChannelAndLevel cat, fmt::string_view fmt, fmt::format_args args);
+void WriteFmtArgs(PackedChannelAndLevel cat, const char* functionName, fmt::string_view fmt, fmt::format_args args);
-ALWAYS_INLINE static void FastWrite(const char* channelName, Level level, std::string_view message)
+ALWAYS_INLINE static void FastWrite(Channel channel, Level level, std::string_view message)
{
if (level <= GetLogLevel()) [[unlikely]]
- Write(channelName, level, message);
+ Write(PackChannelAndLevel(channel, level), message);
}
-ALWAYS_INLINE static void FastWrite(const char* channelName, const char* functionName, Level level,
- std::string_view message)
+ALWAYS_INLINE static void FastWrite(Channel channel, const char* functionName, Level level, std::string_view message)
{
if (level <= GetLogLevel()) [[unlikely]]
- Write(channelName, functionName, level, message);
+ Write(PackChannelAndLevel(channel, level), functionName, message);
}
template
-ALWAYS_INLINE static void FastWrite(const char* channelName, Level level, fmt::format_string fmt, T&&... args)
+ALWAYS_INLINE static void FastWrite(Channel channel, Level level, fmt::format_string fmt, T&&... args)
{
if (level <= GetLogLevel()) [[unlikely]]
- WriteFmtArgs(channelName, level, fmt, fmt::make_format_args(args...));
+ WriteFmtArgs(PackChannelAndLevel(channel, level), fmt, fmt::make_format_args(args...));
}
template
-ALWAYS_INLINE static void FastWrite(const char* channelName, const char* functionName, Level level,
+ALWAYS_INLINE static void FastWrite(Channel channel, const char* functionName, Level level,
fmt::format_string fmt, T&&... args)
{
if (level <= GetLogLevel()) [[unlikely]]
- WriteFmtArgs(channelName, functionName, level, fmt, fmt::make_format_args(args...));
+ WriteFmtArgs(PackChannelAndLevel(channel, level), functionName, fmt, fmt::make_format_args(args...));
}
} // namespace Log
// log wrappers
-#define LOG_CHANNEL(name) [[maybe_unused]] static const char* ___LogChannel___ = #name;
+#define LOG_CHANNEL(name) [[maybe_unused]] static constexpr Log::Channel ___LogChannel___ = Log::Channel::name;
#define ERROR_LOG(...) Log::FastWrite(___LogChannel___, __func__, Log::Level::Error, __VA_ARGS__)
#define WARNING_LOG(...) Log::FastWrite(___LogChannel___, __func__, Log::Level::Warning, __VA_ARGS__)
diff --git a/src/common/log_channels.h b/src/common/log_channels.h
new file mode 100644
index 000000000..425ebb510
--- /dev/null
+++ b/src/common/log_channels.h
@@ -0,0 +1,84 @@
+// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin
+// SPDX-License-Identifier: CC-BY-NC-ND-4.0
+
+#define ENUMERATE_LOG_CHANNELS(X) \
+ X(Achievements) \
+ X(AnalogController) \
+ X(AnalogJoystick) \
+ X(AudioStream) \
+ X(AutoUpdaterDialog) \
+ X(BIOS) \
+ X(Bus) \
+ X(CDImage) \
+ X(CDROM) \
+ X(CDROMAsyncReader) \
+ X(CPU) \
+ X(Cheats) \
+ X(CodeCache) \
+ X(CompressHelpers) \
+ X(ControllerBindingWidget) \
+ X(CubebAudioStream) \
+ X(CueParser) \
+ X(DInputSource) \
+ X(DMA) \
+ X(DynamicLibrary) \
+ X(FileSystem) \
+ X(FullscreenUI) \
+ X(GDBProtocol) \
+ X(GPU) \
+ X(GPUBackend) \
+ X(GPUDevice) \
+ X(GPUDump) \
+ X(GPUShaderCache) \
+ X(GPUTexture) \
+ X(GPUTextureCache) \
+ X(GPU_HW) \
+ X(GPU_SW) \
+ X(GPU_SW_Rasterizer) \
+ X(GameDatabase) \
+ X(GameList) \
+ X(GunCon) \
+ X(HTTPDownloader) \
+ X(Host) \
+ X(ImGuiFullscreen) \
+ X(ImGuiManager) \
+ X(Image) \
+ X(InputManager) \
+ X(InterruptController) \
+ X(IsoReader) \
+ X(Justifier) \
+ X(Log) \
+ X(MDEC) \
+ X(MediaCapture) \
+ X(MemMap) \
+ X(MemoryCard) \
+ X(Multitap) \
+ X(NeGconRumble) \
+ X(PCDrv) \
+ X(PSFLoader) \
+ X(Pad) \
+ X(PerfMon) \
+ X(PlatformMisc) \
+ X(PlayStationMouse) \
+ X(PostProcessing) \
+ X(ProgressCallback) \
+ X(ReShadeFXShader) \
+ X(Recompiler) \
+ X(SDL) \
+ X(SIO) \
+ X(SPU) \
+ X(Settings) \
+ X(SettingsWindow) \
+ X(ShaderGen) \
+ X(Sockets) \
+ X(StateWrapper) \
+ X(System) \
+ X(TTY) \
+ X(Threading) \
+ X(Timers) \
+ X(TimingEvents) \
+ X(Ungrouped) \
+ X(WAVWriter) \
+ X(Win32RawInputSource) \
+ X(WindowInfo) \
+ X(XInputSource)
diff --git a/src/common/zip_helpers.h b/src/common/zip_helpers.h
index 54656ff7f..da6b5c50e 100644
--- a/src/common/zip_helpers.h
+++ b/src/common/zip_helpers.h
@@ -33,7 +33,7 @@ struct ZipDeleter
const int err = zip_close(zf);
if (err != 0)
{
- Log::FastWrite("ZipHelpers", __FUNCTION__, Log::Level::Error, "Failed to close zip file: {}", err);
+ Log::FastWrite(Log::Channel::Ungrouped, __FUNCTION__, Log::Level::Error, "Failed to close zip file: {}", err);
zip_discard(zf);
}
}
diff --git a/src/core/bus.cpp b/src/core/bus.cpp
index 34cb8426c..c1e870cd3 100644
--- a/src/core/bus.cpp
+++ b/src/core/bus.cpp
@@ -936,7 +936,7 @@ void Bus::AddTTYCharacter(char ch)
{
if (!s_tty_line_buffer.empty())
{
- Log::FastWrite("TTY", "", Log::Level::Info, "\033[1;34m{}\033[0m", s_tty_line_buffer);
+ Log::FastWrite(Log::Channel::TTY, Log::Level::Info, "\033[1;34m{}\033[0m", s_tty_line_buffer);
#ifdef _DEBUG
if (CPU::IsTraceEnabled())
CPU::WriteToExecutionLog("TTY: %s\n", s_tty_line_buffer.c_str());
diff --git a/src/core/cheats.cpp b/src/core/cheats.cpp
index 307f6222a..c4492be25 100644
--- a/src/core/cheats.cpp
+++ b/src/core/cheats.cpp
@@ -77,7 +77,8 @@ public:
{
if (!stop_on_error)
{
- Log::WriteFmtArgs(___LogChannel___, Log::Level::Warning, fmt, fmt::make_format_args(args...));
+ Log::WriteFmtArgs(Log::PackChannelAndLevel(Log::Channel::Cheats, Log::Level::Warning), fmt,
+ fmt::make_format_args(args...));
return true;
}
diff --git a/src/core/cpu_code_cache.cpp b/src/core/cpu_code_cache.cpp
index 901a1343d..c9e16e0cb 100644
--- a/src/core/cpu_code_cache.cpp
+++ b/src/core/cpu_code_cache.cpp
@@ -21,7 +21,7 @@
#include "common/log.h"
#include "common/memmap.h"
-LOG_CHANNEL(CPU::CodeCache);
+LOG_CHANNEL(CodeCache);
// Enable dumping of recompiled block code size statistics.
// #define DUMP_CODE_SIZE_STATS 1
diff --git a/src/core/cpu_core.cpp b/src/core/cpu_core.cpp
index e257bf688..c78029e40 100644
--- a/src/core/cpu_core.cpp
+++ b/src/core/cpu_core.cpp
@@ -26,7 +26,7 @@
#include
-LOG_CHANNEL(CPU::Core);
+LOG_CHANNEL(CPU);
namespace CPU {
enum class ExecutionBreakType
diff --git a/src/core/cpu_newrec_compiler.cpp b/src/core/cpu_newrec_compiler.cpp
index a95e9f996..8f0aef3f3 100644
--- a/src/core/cpu_newrec_compiler.cpp
+++ b/src/core/cpu_newrec_compiler.cpp
@@ -15,7 +15,7 @@
#include
#include
-LOG_CHANNEL(NewRec::Compiler);
+LOG_CHANNEL(Recompiler);
// TODO: direct link skip delay slot check
// TODO: speculative constants
diff --git a/src/core/cpu_newrec_compiler_aarch32.cpp b/src/core/cpu_newrec_compiler_aarch32.cpp
index 2d9b02ca4..fb8f7c08f 100644
--- a/src/core/cpu_newrec_compiler_aarch32.cpp
+++ b/src/core/cpu_newrec_compiler_aarch32.cpp
@@ -19,7 +19,7 @@
#ifdef CPU_ARCH_ARM32
-LOG_CHANNEL(CPU::NewRec);
+LOG_CHANNEL(Recompiler);
#define PTR(x) vixl::aarch32::MemOperand(RSTATE, (((u8*)(x)) - ((u8*)&g_state)))
#define RMEMBASE vixl::aarch32::r3
diff --git a/src/core/cpu_newrec_compiler_aarch64.cpp b/src/core/cpu_newrec_compiler_aarch64.cpp
index e0a323de2..cb3efeb49 100644
--- a/src/core/cpu_newrec_compiler_aarch64.cpp
+++ b/src/core/cpu_newrec_compiler_aarch64.cpp
@@ -19,7 +19,7 @@
#ifdef CPU_ARCH_ARM64
-LOG_CHANNEL(CPU::NewRec);
+LOG_CHANNEL(Recompiler);
#define PTR(x) vixl::aarch64::MemOperand(RSTATE, (((u8*)(x)) - ((u8*)&g_state)))
diff --git a/src/core/cpu_newrec_compiler_riscv64.cpp b/src/core/cpu_newrec_compiler_riscv64.cpp
index 4204c893c..61ac7604b 100644
--- a/src/core/cpu_newrec_compiler_riscv64.cpp
+++ b/src/core/cpu_newrec_compiler_riscv64.cpp
@@ -20,7 +20,7 @@
#ifdef CPU_ARCH_RISCV64
-LOG_CHANNEL(CPU::NewRec);
+LOG_CHANNEL(Recompiler);
#ifdef ENABLE_HOST_DISASSEMBLY
extern "C" {
diff --git a/src/core/cpu_newrec_compiler_x64.cpp b/src/core/cpu_newrec_compiler_x64.cpp
index bf555ac29..5c427f489 100644
--- a/src/core/cpu_newrec_compiler_x64.cpp
+++ b/src/core/cpu_newrec_compiler_x64.cpp
@@ -20,7 +20,7 @@
#ifdef CPU_ARCH_X64
-LOG_CHANNEL(CPU::NewRec);
+LOG_CHANNEL(Recompiler);
#define RMEMBASE cg->rbx
#define RSTATE cg->rbp
diff --git a/src/core/cpu_pgxp.cpp b/src/core/cpu_pgxp.cpp
index e4a3ee4d9..163506d7d 100644
--- a/src/core/cpu_pgxp.cpp
+++ b/src/core/cpu_pgxp.cpp
@@ -19,7 +19,7 @@
#include
#include
-LOG_CHANNEL(CPU::PGXP);
+LOG_CHANNEL(CPU);
// #define LOG_VALUES 1
// #define LOG_LOOKUPS 1
diff --git a/src/core/cpu_recompiler_code_generator.cpp b/src/core/cpu_recompiler_code_generator.cpp
index 40e144ce2..50c413918 100644
--- a/src/core/cpu_recompiler_code_generator.cpp
+++ b/src/core/cpu_recompiler_code_generator.cpp
@@ -11,7 +11,7 @@
#include "common/log.h"
-LOG_CHANNEL(CPU::Recompiler);
+LOG_CHANNEL(Recompiler);
// TODO: Turn load+sext/zext into a single signed/unsigned load
// TODO: mulx/shlx/etc
diff --git a/src/core/cpu_recompiler_code_generator_aarch32.cpp b/src/core/cpu_recompiler_code_generator_aarch32.cpp
index 6b67bb4f1..6d7264256 100644
--- a/src/core/cpu_recompiler_code_generator_aarch32.cpp
+++ b/src/core/cpu_recompiler_code_generator_aarch32.cpp
@@ -16,7 +16,7 @@
#ifdef CPU_ARCH_ARM32
-LOG_CHANNEL(CPU::Recompiler);
+LOG_CHANNEL(Recompiler);
#ifdef ENABLE_HOST_DISASSEMBLY
#include "vixl/aarch32/disasm-aarch32.h"
diff --git a/src/core/cpu_recompiler_code_generator_aarch64.cpp b/src/core/cpu_recompiler_code_generator_aarch64.cpp
index df6ae270b..bf207e4e6 100644
--- a/src/core/cpu_recompiler_code_generator_aarch64.cpp
+++ b/src/core/cpu_recompiler_code_generator_aarch64.cpp
@@ -16,7 +16,7 @@
#ifdef CPU_ARCH_ARM64
-LOG_CHANNEL(CPU::Recompiler);
+LOG_CHANNEL(Recompiler);
#ifdef ENABLE_HOST_DISASSEMBLY
#include "vixl/aarch64/disasm-aarch64.h"
diff --git a/src/core/cpu_recompiler_code_generator_generic.cpp b/src/core/cpu_recompiler_code_generator_generic.cpp
index 97e3b3414..2661e1d13 100644
--- a/src/core/cpu_recompiler_code_generator_generic.cpp
+++ b/src/core/cpu_recompiler_code_generator_generic.cpp
@@ -8,7 +8,7 @@
#include "common/log.h"
-LOG_CHANNEL(Recompiler::CodeGenerator);
+LOG_CHANNEL(Recompiler);
namespace CPU::Recompiler {
diff --git a/src/core/cpu_recompiler_code_generator_x64.cpp b/src/core/cpu_recompiler_code_generator_x64.cpp
index bb4160639..4ceb71cca 100644
--- a/src/core/cpu_recompiler_code_generator_x64.cpp
+++ b/src/core/cpu_recompiler_code_generator_x64.cpp
@@ -16,7 +16,7 @@
#ifdef CPU_ARCH_X64
-LOG_CHANNEL(Recompiler::CodeGenerator);
+LOG_CHANNEL(Recompiler);
#ifdef ENABLE_HOST_DISASSEMBLY
#include "Zycore/Format.h"
@@ -260,8 +260,7 @@ void CPU::CodeCache::DisassembleAndLogHostCode(const void* start, u32 size)
else
hex.append(" ");
}
- Log::FastWrite("HostCode", "", Log::Level::Debug, " {:016X} {} {}",
- static_cast(reinterpret_cast(ptr)), hex, buffer);
+ DEBUG_LOG(" {:016X} {} {}", static_cast(reinterpret_cast(ptr)), hex, buffer);
}
ptr += disas_instruction.length;
diff --git a/src/core/cpu_recompiler_register_cache.cpp b/src/core/cpu_recompiler_register_cache.cpp
index 0efbd4496..7e5329015 100644
--- a/src/core/cpu_recompiler_register_cache.cpp
+++ b/src/core/cpu_recompiler_register_cache.cpp
@@ -8,7 +8,7 @@
#include
-LOG_CHANNEL(CPU::Recompiler);
+LOG_CHANNEL(Recompiler);
namespace CPU::Recompiler {
diff --git a/src/core/fullscreen_ui.cpp b/src/core/fullscreen_ui.cpp
index 4c2a3f141..f70596100 100644
--- a/src/core/fullscreen_ui.cpp
+++ b/src/core/fullscreen_ui.cpp
@@ -5173,7 +5173,7 @@ void FullscreenUI::DrawAdvancedSettingsPage()
DrawEnumSetting(bsi, FSUI_CSTR("Log Level"),
FSUI_CSTR("Sets the verbosity of messages logged. Higher levels will log more messages."), "Logging",
"LogLevel", Settings::DEFAULT_LOG_LEVEL, &Settings::ParseLogLevelName, &Settings::GetLogLevelName,
- &Settings::GetLogLevelDisplayName, Log::Level::Count);
+ &Settings::GetLogLevelDisplayName, Log::Level::MaxCount);
DrawToggleSetting(bsi, FSUI_CSTR("Log To System Console"), FSUI_CSTR("Logs messages to the console window."),
FSUI_CSTR("Logging"), "LogToConsole", false);
DrawToggleSetting(bsi, FSUI_CSTR("Log To Debug Console"),
diff --git a/src/core/host_interface_progress_callback.cpp b/src/core/host_interface_progress_callback.cpp
index 05d348d8c..c9fbc58e6 100644
--- a/src/core/host_interface_progress_callback.cpp
+++ b/src/core/host_interface_progress_callback.cpp
@@ -6,7 +6,7 @@
#include "common/log.h"
-LOG_CHANNEL(HostInterfaceProgressCallback);
+LOG_CHANNEL(Host);
HostInterfaceProgressCallback::HostInterfaceProgressCallback() : ProgressCallback()
{
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index c4feb6efb..401525463 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -423,15 +423,6 @@ void Settings::Load(const SettingsInterface& si, const SettingsInterface& contro
achievements_leaderboard_duration =
si.GetIntValue("Cheevos", "LeaderboardsDuration", DEFAULT_LEADERBOARD_NOTIFICATION_TIME);
- log_level = ParseLogLevelName(si.GetStringValue("Logging", "LogLevel", GetLogLevelName(DEFAULT_LOG_LEVEL)).c_str())
- .value_or(DEFAULT_LOG_LEVEL);
- log_filter = si.GetStringValue("Logging", "LogFilter", "");
- log_timestamps = si.GetBoolValue("Logging", "LogTimestamps", true);
- log_to_console = si.GetBoolValue("Logging", "LogToConsole", false);
- log_to_debug = si.GetBoolValue("Logging", "LogToDebug", false);
- log_to_window = si.GetBoolValue("Logging", "LogToWindow", false);
- log_to_file = si.GetBoolValue("Logging", "LogToFile", false);
-
debugging.show_vram = si.GetBoolValue("Debug", "ShowVRAM");
debugging.dump_cpu_to_vram_copies = si.GetBoolValue("Debug", "DumpCPUToVRAMCopies");
debugging.dump_vram_to_cpu_copies = si.GetBoolValue("Debug", "DumpVRAMToCPUCopies");
@@ -694,14 +685,6 @@ void Settings::Save(SettingsInterface& si, bool ignore_base) const
if (!ignore_base)
{
- si.SetStringValue("Logging", "LogLevel", GetLogLevelName(log_level));
- si.SetStringValue("Logging", "LogFilter", log_filter.c_str());
- si.SetBoolValue("Logging", "LogTimestamps", log_timestamps);
- si.SetBoolValue("Logging", "LogToConsole", log_to_console);
- si.SetBoolValue("Logging", "LogToDebug", log_to_debug);
- si.SetBoolValue("Logging", "LogToWindow", log_to_window);
- si.SetBoolValue("Logging", "LogToFile", log_to_file);
-
si.SetBoolValue("Debug", "ShowVRAM", debugging.show_vram);
si.SetBoolValue("Debug", "DumpCPUToVRAMCopies", debugging.dump_cpu_to_vram_copies);
si.SetBoolValue("Debug", "DumpVRAMToCPUCopies", debugging.dump_vram_to_cpu_copies);
@@ -1036,11 +1019,40 @@ void Settings::FixIncompatibleSettings(bool display_osd_messages)
}
}
-void Settings::UpdateLogSettings()
+void Settings::SetDefaultLogConfig(SettingsInterface& si)
{
+ si.SetStringValue("Logging", "LogLevel", GetLogLevelName(DEFAULT_LOG_LEVEL));
+ si.SetBoolValue("Logging", "LogTimestamps", true);
+
+#if !defined(_WIN32) && !defined(__ANDROID__)
+ // On Linux, default the console to whether standard input is currently available.
+ si.SetBoolValue("Logging", "LogToConsole", Log::IsConsoleOutputCurrentlyAvailable());
+#else
+ si.SetBoolValue("Logging", "LogToConsole", false);
+#endif
+
+ si.SetBoolValue("Logging", "LogToDebug", false);
+ si.SetBoolValue("Logging", "LogToWindow", false);
+ si.SetBoolValue("Logging", "LogToFile", false);
+
+ for (const char* channel_name : Log::GetChannelNames())
+ si.SetBoolValue("Logging", channel_name, true);
+}
+
+void Settings::UpdateLogConfig(const SettingsInterface& si)
+{
+ const Log::Level log_level =
+ ParseLogLevelName(si.GetStringValue("Logging", "LogLevel", GetLogLevelName(DEFAULT_LOG_LEVEL)).c_str())
+ .value_or(DEFAULT_LOG_LEVEL);
+ const bool log_timestamps = si.GetBoolValue("Logging", "LogTimestamps", true);
+ const bool log_to_console = si.GetBoolValue("Logging", "LogToConsole", false);
+ const bool log_to_debug = si.GetBoolValue("Logging", "LogToDebug", false);
+ const bool log_to_window = si.GetBoolValue("Logging", "LogToWindow", false);
+ const bool log_to_file = si.GetBoolValue("Logging", "LogToFile", false);
+
const bool any_logs_enabled = (log_to_console || log_to_debug || log_to_window || log_to_file);
Log::SetLogLevel(any_logs_enabled ? log_level : Log::Level::None);
- Log::SetLogFilter(any_logs_enabled ? std::string_view(log_filter) : std::string_view());
+
Log::SetConsoleOutputParams(log_to_console, log_timestamps);
Log::SetDebugOutputParams(log_to_debug);
@@ -1053,6 +1065,10 @@ void Settings::UpdateLogSettings()
{
Log::SetFileOutputParams(false, nullptr);
}
+
+ const auto channel_names = Log::GetChannelNames();
+ for (size_t i = 0; i < channel_names.size(); i++)
+ Log::SetLogChannelEnabled(static_cast(i), si.GetBoolValue("Logging", channel_names[i], true));
}
void Settings::SetDefaultControllerConfig(SettingsInterface& si)
@@ -2306,131 +2322,3 @@ std::string EmuFolders::GetOverridableResourcePath(std::string_view name)
return upath;
}
-
-static const char* s_log_filters[] = {
- "Achievements",
- "AnalogController",
- "AnalogJoystick",
- "AudioStream",
- "AutoUpdaterDialog",
- "BIOS",
- "Bus",
- "CDImage",
- "CDImageBin",
- "CDImageCHD",
- "CDImageCueSheet",
- "CDImageDevice",
- "CDImageEcm",
- "CDImageMds",
- "CDImageMemory",
- "CDImagePBP",
- "CDImagePPF",
- "CDROM",
- "CDROMAsyncReader",
- "CDSubChannelReplacement",
- "CPU::CodeCache",
- "CPU::Core",
- "CPU::Recompiler",
- "Common::PageFaultHandler",
- "ControllerBindingWidget",
- "CueParser",
- "Cheats",
- "DMA",
- "DisplayWidget",
- "FileSystem",
- "FullscreenUI",
- "GDBConnection",
- "GDBProtocol",
- "GDBServer",
- "GPU",
- "GPUBackend",
- "GPUDevice",
- "GPUShaderCache",
- "GPUTexture",
- "GPU_HW",
- "GPU_SW",
- "GameDatabase",
- "GameList",
- "GunCon",
- "HTTPDownloader",
- "Host",
- "HostInterfaceProgressCallback",
- "INISettingsInterface",
- "ISOReader",
- "ImGuiFullscreen",
- "ImGuiManager",
- "Image",
- "InputManager",
- "InterruptController",
- "JitCodeBuffer",
- "MDEC",
- "MainWindow",
- "MemoryArena",
- "MemoryCard",
- "Multitap",
- "NoGUIHost",
- "PCDrv",
- "PGXP",
- "PSFLoader",
- "Pad",
- "PlatformMisc",
- "PlayStationMouse",
- "PostProcessing",
- "ProgressCallback",
- "QTTranslations",
- "QtHost",
- "ReShadeFXShader",
- "Recompiler::CodeGenerator",
- "RegTestHost",
- "SDLInputSource",
- "SIO",
- "SPIRVCompiler",
- "SPU",
- "Settings",
- "ShaderGen",
- "StateWrapper",
- "System",
- "TextureReplacements",
- "Timers",
- "TimingEvents",
- "WAVWriter",
- "WindowInfo",
-
-#ifndef __ANDROID__
- "CubebAudioStream",
- "SDLAudioStream",
-#endif
-
-#ifdef ENABLE_OPENGL
- "OpenGLContext",
- "OpenGLDevice",
-#endif
-
-#ifdef ENABLE_VULKAN
- "VulkanDevice",
-#endif
-
-#if defined(_WIN32)
- "D3D11Device",
- "D3D12Device",
- "D3D12StreamBuffer",
- "D3DCommon",
- "DInputSource",
- "Win32ProgressCallback",
- "Win32RawInputSource",
- "XAudio2AudioStream",
- "XInputSource",
-#elif defined(__APPLE__)
- "CocoaNoGUIPlatform",
- "CocoaProgressCallback",
- "MetalDevice",
-#else
- "X11NoGUIPlatform",
- "WaylandNoGUIPlatform",
-#endif
-};
-
-std::span Settings::GetLogFilters()
-{
- return s_log_filters;
-}
diff --git a/src/core/settings.h b/src/core/settings.h
index 1f82f8fd5..d30b40767 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -291,14 +291,6 @@ struct Settings
std::string pcdrv_root;
bool pcdrv_enable_writes = false;
- Log::Level log_level = DEFAULT_LOG_LEVEL;
- std::string log_filter;
- bool log_timestamps : 1 = true;
- bool log_to_console : 1 = false;
- bool log_to_debug : 1 = false;
- bool log_to_window : 1 = false;
- bool log_to_file : 1 = false;
-
ALWAYS_INLINE bool IsUsingSoftwareRenderer() const { return (gpu_renderer == GPURenderer::Software); }
ALWAYS_INLINE bool IsUsingAccurateBlending() const { return (gpu_accurate_blending && !gpu_true_color); }
ALWAYS_INLINE bool IsRunaheadEnabled() const { return (runahead_frames > 0); }
@@ -375,7 +367,8 @@ struct Settings
void FixIncompatibleSettings(bool display_osd_messages);
/// Initializes configuration.
- void UpdateLogSettings();
+ static void SetDefaultLogConfig(SettingsInterface& si);
+ static void UpdateLogConfig(const SettingsInterface& si);
static void SetDefaultControllerConfig(SettingsInterface& si);
static void SetDefaultHotkeyConfig(SettingsInterface& si);
@@ -383,7 +376,6 @@ struct Settings
static std::optional ParseLogLevelName(const char* str);
static const char* GetLogLevelName(Log::Level level);
static const char* GetLogLevelDisplayName(Log::Level level);
- static std::span GetLogFilters();
static std::optional ParseConsoleRegionName(const char* str);
static const char* GetConsoleRegionName(ConsoleRegion region);
diff --git a/src/core/system.cpp b/src/core/system.cpp
index 6573cd13d..c8e64f7e5 100644
--- a/src/core/system.cpp
+++ b/src/core/system.cpp
@@ -1292,13 +1292,13 @@ void System::LoadSettings(bool display_osd_messages)
const SettingsInterface& controller_si = GetControllerSettingsLayer(lock);
const SettingsInterface& hotkey_si = GetHotkeySettingsLayer(lock);
g_settings.Load(si, controller_si);
- g_settings.UpdateLogSettings();
// Global safe mode overrides game settings.
g_settings.disable_all_enhancements =
(g_settings.disable_all_enhancements ||
Host::Internal::GetBaseSettingsLayer()->GetBoolValue("Main", "DisableAllEnhancements", false));
+ Settings::UpdateLogConfig(si);
Host::LoadSettings(si, lock);
InputManager::ReloadSources(controller_si, lock);
InputManager::ReloadBindings(controller_si, hotkey_si);
@@ -1399,10 +1399,7 @@ void System::SetDefaultSettings(SettingsInterface& si)
si.SetBoolValue("Main", "StartPaused", false);
si.SetBoolValue("Main", "StartFullscreen", false);
-#if !defined(_WIN32) && !defined(__ANDROID__)
- // On Linux, default the console to whether standard input is currently available.
- si.SetBoolValue("Logging", "LogToConsole", Log::IsConsoleOutputCurrentlyAvailable());
-#endif
+ Settings::SetDefaultLogConfig(si);
#ifndef __ANDROID__
si.SetStringValue("MediaCapture", "Backend", MediaCapture::GetBackendName(Settings::DEFAULT_MEDIA_CAPTURE_BACKEND));
@@ -4493,15 +4490,6 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
Panic("Failed to reallocate memory map. The log may contain more information.");
}
}
-
- if (g_settings.log_level != old_settings.log_level || g_settings.log_filter != old_settings.log_filter ||
- g_settings.log_timestamps != old_settings.log_timestamps ||
- g_settings.log_to_console != old_settings.log_to_console ||
- g_settings.log_to_debug != old_settings.log_to_debug || g_settings.log_to_window != old_settings.log_to_window ||
- g_settings.log_to_file != old_settings.log_to_file)
- {
- g_settings.UpdateLogSettings();
- }
}
void System::SetTaintsFromSettings()
diff --git a/src/duckstation-qt/advancedsettingswidget.cpp b/src/duckstation-qt/advancedsettingswidget.cpp
index bc41b29c0..6a0b1f845 100644
--- a/src/duckstation-qt/advancedsettingswidget.cpp
+++ b/src/duckstation-qt/advancedsettingswidget.cpp
@@ -2,12 +2,17 @@
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#include "advancedsettingswidget.h"
-#include "core/gpu_types.h"
+#include "logwindow.h"
#include "mainwindow.h"
#include "qtutils.h"
#include "settingswindow.h"
#include "settingwidgetbinder.h"
+#include "core/gpu_types.h"
+
+#include
+#include
+
static QCheckBox* addBooleanTweakOption(SettingsWindow* dialog, QTableWidget* table, QString name, std::string section,
std::string key, bool default_value)
{
@@ -162,12 +167,11 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsWindow* dialog, QWidget*
m_ui.setupUi(this);
- for (u32 i = 0; i < static_cast(Log::Level::Count); i++)
+ for (u32 i = 0; i < static_cast(Log::Level::MaxCount); i++)
m_ui.logLevel->addItem(QString::fromUtf8(Settings::GetLogLevelDisplayName(static_cast(i))));
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.logLevel, "Logging", "LogLevel", &Settings::ParseLogLevelName,
&Settings::GetLogLevelName, Settings::DEFAULT_LOG_LEVEL);
- SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.logFilter, "Logging", "LogFilter");
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.logToConsole, "Logging", "LogToConsole", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.logToDebug, "Logging", "LogToDebug", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.logToWindow, "Logging", "LogToWindow", false);
@@ -175,6 +179,7 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsWindow* dialog, QWidget*
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showDebugMenu, "Main", "ShowDebugMenu", false);
+ connect(m_ui.logChannels, &QToolButton::clicked, this, &AdvancedSettingsWidget::onLogChannelsButtonClicked);
connect(m_ui.resetToDefaultButton, &QPushButton::clicked, this, &AdvancedSettingsWidget::onResetToDefaultClicked);
connect(m_ui.showDebugMenu, &QCheckBox::checkStateChanged, g_main_window, &MainWindow::updateDebugMenuVisibility,
Qt::QueuedConnection);
@@ -202,6 +207,13 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsWindow* dialog, QWidget*
AdvancedSettingsWidget::~AdvancedSettingsWidget() = default;
+void AdvancedSettingsWidget::onLogChannelsButtonClicked()
+{
+ QMenu menu;
+ LogWindow::populateFilterMenu(&menu);
+ menu.exec(QCursor::pos());
+}
+
void AdvancedSettingsWidget::onShowDebugOptionsStateChanged()
{
const bool enabled = QtHost::ShouldShowDebugOptions();
diff --git a/src/duckstation-qt/advancedsettingswidget.h b/src/duckstation-qt/advancedsettingswidget.h
index ab51eda31..a1bb393a1 100644
--- a/src/duckstation-qt/advancedsettingswidget.h
+++ b/src/duckstation-qt/advancedsettingswidget.h
@@ -21,6 +21,7 @@ Q_SIGNALS:
void onShowDebugOptionsChanged(bool enabled);
private Q_SLOTS:
+ void onLogChannelsButtonClicked();
void onShowDebugOptionsStateChanged();
private:
diff --git a/src/duckstation-qt/advancedsettingswidget.ui b/src/duckstation-qt/advancedsettingswidget.ui
index 9e6047e42..529184056 100644
--- a/src/duckstation-qt/advancedsettingswidget.ui
+++ b/src/duckstation-qt/advancedsettingswidget.ui
@@ -6,8 +6,8 @@
0
0
- 973
- 507
+ 560
+ 358
@@ -39,17 +39,21 @@
-
-
-
- -
-
-
- Log Filters:
-
-
-
- -
-
+
+
-
+
+
+ -
+
+
+ Log Channels
+
+
+
+
+
+
+
@@ -158,7 +162,7 @@
-
+
diff --git a/src/duckstation-qt/displaywidget.cpp b/src/duckstation-qt/displaywidget.cpp
index 575f18f6c..e91790d5f 100644
--- a/src/duckstation-qt/displaywidget.cpp
+++ b/src/duckstation-qt/displaywidget.cpp
@@ -30,7 +30,7 @@
#include "common/windows_headers.h"
#endif
-LOG_CHANNEL(DisplayWidget);
+LOG_CHANNEL(Host);
DisplayWidget::DisplayWidget(QWidget* parent) : QWidget(parent)
{
diff --git a/src/duckstation-qt/logwindow.cpp b/src/duckstation-qt/logwindow.cpp
index 3d80c5f7e..8b7b9f58f 100644
--- a/src/duckstation-qt/logwindow.cpp
+++ b/src/duckstation-qt/logwindow.cpp
@@ -19,8 +19,7 @@
LogWindow* g_log_window;
LogWindow::LogWindow(bool attach_to_main)
- : QMainWindow(), m_filter_names(Settings::GetLogFilters()), m_is_dark_theme(QtHost::IsDarkApplicationTheme()),
- m_attached_to_main_window(attach_to_main)
+ : QMainWindow(), m_is_dark_theme(QtHost::IsDarkApplicationTheme()), m_attached_to_main_window(attach_to_main)
{
restoreSize();
createUi();
@@ -158,7 +157,7 @@ void LogWindow::createUi()
settings_menu->addSeparator();
m_level_menu = settings_menu->addMenu(tr("&Log Level"));
- for (u32 i = 0; i < static_cast(Log::Level::Count); i++)
+ for (u32 i = 0; i < static_cast(Log::Level::MaxCount); i++)
{
action = m_level_menu->addAction(QString::fromUtf8(Settings::GetLogLevelDisplayName(static_cast(i))));
action->setCheckable(true);
@@ -166,8 +165,11 @@ void LogWindow::createUi()
}
updateLogLevelUi();
- QMenu* filters_menu = menu->addMenu(tr("&Filters"));
- populateFilters(filters_menu);
+ QMenu* filters_menu = menu->addMenu(tr("&Channels"));
+ connect(filters_menu, &QMenu::aboutToShow, this, [filters_menu]() {
+ filters_menu->clear();
+ populateFilterMenu(filters_menu);
+ });
m_text = new QPlainTextEdit(this);
m_text->setReadOnly(true);
@@ -208,52 +210,25 @@ void LogWindow::setLogLevel(Log::Level level)
g_emu_thread->applySettings(false);
}
-void LogWindow::populateFilters(QMenu* filter_menu)
+void LogWindow::populateFilterMenu(QMenu* filter_menu)
{
- const std::string filters = Host::GetBaseStringSettingValue("Logging", "LogFilter", "");
- for (size_t i = 0; i < m_filter_names.size(); i++)
+ const auto settings_Lock = Host::GetSettingsLock();
+ const INISettingsInterface* si = QtHost::GetBaseSettingsInterface();
+
+ for (const char* channel_name : Log::GetChannelNames())
{
- const char* filter = m_filter_names[i];
- const bool is_currently_filtered = (filters.find(filter) == std::string::npos);
- QAction* action = filter_menu->addAction(QString::fromUtf8(filter));
- action->setCheckable(action);
- action->setChecked(is_currently_filtered);
- connect(action, &QAction::triggered, this, [this, i](bool checked) { setChannelFiltered(i, !checked); });
+ const bool enabled = si->GetBoolValue("Logging", channel_name, true);
+ QAction* action = filter_menu->addAction(QString::fromUtf8(channel_name));
+ action->setCheckable(true);
+ action->setChecked(enabled);
+ connect(action, &QAction::triggered, action, [channel_name](bool checked) {
+ Host::SetBaseBoolSettingValue("Logging", channel_name, checked);
+ Host::CommitBaseSettingChanges();
+ g_emu_thread->applySettings(false);
+ });
}
}
-void LogWindow::setChannelFiltered(size_t index, bool enabled)
-{
- const char* filter = m_filter_names[index];
- const size_t filter_len = std::strlen(filter);
-
- std::string filters = Host::GetBaseStringSettingValue("Logging", "LogFilter", "");
- const std::string::size_type pos = filters.find(filter);
-
- if (!enabled)
- {
- if (pos == std::string::npos)
- return;
-
- const size_t erase_count =
- filter_len + (((pos + filter_len) < filters.length() && filters[pos + filter_len] == ' ') ? 1 : 0);
- filters.erase(pos, erase_count);
- }
- else
- {
- if (pos != std::string::npos)
- return;
-
- if (!filters.empty() && filters.back() != ' ')
- filters.push_back(' ');
- filters.append(filter);
- }
-
- Host::SetBaseStringSettingValue("Logging", "LogFilter", filters.c_str());
- Host::CommitBaseSettingChanges();
- g_emu_thread->applySettings(false);
-}
-
void LogWindow::onClearTriggered()
{
m_text->clear();
@@ -339,9 +314,9 @@ void LogWindow::appendMessage(const QLatin1StringView& channel, quint32 level, c
temp_cursor.movePosition(QTextCursor::End);
{
- static constexpr const QChar level_characters[static_cast(Log::Level::Count)] = {'X', 'E', 'W', 'I',
- 'V', 'D', 'B', 'T'};
- static constexpr const QColor level_colors[2][static_cast(Log::Level::Count)] = {
+ static constexpr const QChar level_characters[static_cast(Log::Level::MaxCount)] = {'X', 'E', 'W', 'I',
+ 'V', 'D', 'B', 'T'};
+ static constexpr const QColor level_colors[2][static_cast(Log::Level::MaxCount)] = {
{
// Light theme
QColor(0, 0, 0), // NONE
@@ -371,7 +346,7 @@ void LogWindow::appendMessage(const QLatin1StringView& channel, quint32 level, c
QTextCharFormat format = temp_cursor.charFormat();
const size_t dark = static_cast(m_is_dark_theme);
- if (g_settings.log_timestamps)
+ if (Log::AreTimestampsEnabled())
{
const float message_time = Log::GetCurrentMessageTime();
const QString qtimestamp = QStringLiteral("[%1] ").arg(message_time, 10, 'f', 4);
diff --git a/src/duckstation-qt/logwindow.h b/src/duckstation-qt/logwindow.h
index d00054191..ffd2e0ee1 100644
--- a/src/duckstation-qt/logwindow.h
+++ b/src/duckstation-qt/logwindow.h
@@ -25,12 +25,12 @@ public:
void updateWindowTitle();
+ static void populateFilterMenu(QMenu* menu);
+
private:
void createUi();
void updateLogLevelUi();
void setLogLevel(Log::Level level);
- void populateFilters(QMenu* filter_menu);
- void setChannelFiltered(size_t index, bool state);
static void logCallback(void* pUserParam, const char* channelName, const char* functionName, Log::Level level,
std::string_view message);
@@ -53,7 +53,6 @@ private:
QPlainTextEdit* m_text;
QMenu* m_level_menu;
- std::span m_filter_names;
bool m_is_dark_theme = false;
bool m_attached_to_main_window = true;
diff --git a/src/duckstation-qt/mainwindow.cpp b/src/duckstation-qt/mainwindow.cpp
index 99e8b7011..d2312dc1d 100644
--- a/src/duckstation-qt/mainwindow.cpp
+++ b/src/duckstation-qt/mainwindow.cpp
@@ -58,7 +58,7 @@
#include
#endif
-LOG_CHANNEL(MainWindow);
+LOG_CHANNEL(Host);
static constexpr char DISC_IMAGE_FILTER[] = QT_TRANSLATE_NOOP(
"MainWindow", "All File Types (*.bin *.img *.iso *.cue *.chd *.ecm *.mds *.pbp *.exe *.psexe *.ps-exe *.psx *.psf "
diff --git a/src/duckstation-qt/qthost.cpp b/src/duckstation-qt/qthost.cpp
index 76719b7e3..49f59bf2d 100644
--- a/src/duckstation-qt/qthost.cpp
+++ b/src/duckstation-qt/qthost.cpp
@@ -69,7 +69,7 @@
#include
#include
-LOG_CHANNEL(QtHost);
+LOG_CHANNEL(Host);
#ifdef _WIN32
#include "common/windows_headers.h"
diff --git a/src/duckstation-qt/qttranslations.cpp b/src/duckstation-qt/qttranslations.cpp
index 8bba4f646..c1fe0eb2d 100644
--- a/src/duckstation-qt/qttranslations.cpp
+++ b/src/duckstation-qt/qttranslations.cpp
@@ -32,7 +32,7 @@
#include
#endif
-LOG_CHANNEL(QTTranslations);
+LOG_CHANNEL(Host);
#if 0
// Qt internal strings we'd like to have translated
diff --git a/src/duckstation-qt/qtutils.cpp b/src/duckstation-qt/qtutils.cpp
index 82a133953..f613aa2a6 100644
--- a/src/duckstation-qt/qtutils.cpp
+++ b/src/duckstation-qt/qtutils.cpp
@@ -40,7 +40,7 @@
#include "common/windows_headers.h"
#endif
-LOG_CHANNEL(QtUtils);
+LOG_CHANNEL(Host);
QFrame* QtUtils::CreateHorizontalLine(QWidget* parent)
{
diff --git a/src/updater/cocoa_progress_callback.mm b/src/updater/cocoa_progress_callback.mm
index ac2e61370..229e4903a 100644
--- a/src/updater/cocoa_progress_callback.mm
+++ b/src/updater/cocoa_progress_callback.mm
@@ -6,7 +6,7 @@
#include "common/cocoa_tools.h"
#include "common/log.h"
-LOG_CHANNEL(CocoaProgressCallback);
+LOG_CHANNEL(Host);
CocoaProgressCallback::CocoaProgressCallback() : ProgressCallback()
{
diff --git a/src/updater/win32_progress_callback.cpp b/src/updater/win32_progress_callback.cpp
index e046b090d..a7b50a2cf 100644
--- a/src/updater/win32_progress_callback.cpp
+++ b/src/updater/win32_progress_callback.cpp
@@ -8,7 +8,7 @@
#include
-LOG_CHANNEL(Win32ProgressCallback);
+LOG_CHANNEL(Host);
Win32ProgressCallback::Win32ProgressCallback() : ProgressCallback()
{
diff --git a/src/util/cd_image_chd.cpp b/src/util/cd_image_chd.cpp
index a315be7e1..42e575de6 100644
--- a/src/util/cd_image_chd.cpp
+++ b/src/util/cd_image_chd.cpp
@@ -26,7 +26,7 @@
#include
#include
-LOG_CHANNEL(CDImageCHD);
+LOG_CHANNEL(CDImage);
namespace {
diff --git a/src/util/cd_image_cue.cpp b/src/util/cd_image_cue.cpp
index 6b1406632..c4e52c84e 100644
--- a/src/util/cd_image_cue.cpp
+++ b/src/util/cd_image_cue.cpp
@@ -16,7 +16,7 @@
#include
#include