From b7203c298978478c315d2ab2c707afa7ced20250 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Sat, 29 Aug 2015 18:06:30 -0700 Subject: [PATCH] Logging to with a ringbuffer. Much faster. --- .gitignore | 1 + README.md | 2 + building.md | 4 +- src/xenia/app/emulator_window.cc | 4 +- src/xenia/apu/xma_decoder.cc | 6 +- src/xenia/base/filesystem.cc | 24 ++- src/xenia/base/filesystem.h | 1 + src/xenia/base/logging.cc | 194 +++++++++++++------- src/xenia/base/logging.h | 75 ++------ src/xenia/base/main_posix.cc | 4 + src/xenia/base/main_win.cc | 4 + src/xenia/base/ring_buffer.cc | 4 +- src/xenia/base/ring_buffer.h | 38 ++-- src/xenia/base/string.cc | 24 +-- src/xenia/base/string.h | 12 +- src/xenia/cpu/backend/x64/x64_emitter.cc | 2 +- src/xenia/cpu/frontend/ppc_scanner.cc | 4 +- src/xenia/debug/ui/application.cc | 4 +- src/xenia/emulator.cc | 9 +- src/xenia/gpu/gl4/command_processor.cc | 2 +- src/xenia/gpu/gl4/gl4_graphics_system.cc | 2 +- src/xenia/gpu/gl4/trace_viewer_main.cc | 4 +- src/xenia/gpu/graphics_system.cc | 4 +- src/xenia/kernel/objects/xuser_module.cc | 220 ++++++++++++----------- src/xenia/ui/gl/gl_context.cc | 51 +++--- 25 files changed, 387 insertions(+), 312 deletions(-) diff --git a/.gitignore b/.gitignore index 3135285c4..9888aa4ee 100644 --- a/.gitignore +++ b/.gitignore @@ -63,6 +63,7 @@ npm-debug.log private/ *.trace imgui.ini +*.log # ============================================================================== # Build system output diff --git a/README.md b/README.md index 26611bd3a..f9a6e8e32 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,8 @@ Have some spare time, know advanced C++, and want to write an emulator? Contribute! There's a ton of work that needs to be done, a lot of which is wide open greenfield fun. +For general rules and guidelines please see [CONTRIBUTING.md](CONTRIBUTING.md). + Fixes and optimizations are always welcome (please!), but in addition to that there are some major work areas still untouched: diff --git a/building.md b/building.md index 487f5d35d..83a6bcb80 100644 --- a/building.md +++ b/building.md @@ -25,8 +25,8 @@ and set the 'Command' to `$(SolutionDir)$(TargetPath)` and the 'Working Directory' to `$(SolutionDir)..\..`. You can specify flags and the file to run in the 'Command Arguments' field (or use `--flagfile=flags.txt`). -To redirect output, use the following command flags: -`--flagfile=$(SolutionDir)scratch\flags.txt 2>&1 1>$(SolutionDir)scratch\stdout.txt` +By default logs are written to a file with the name of the executable. You can +override this with `--log_file=log.txt`. ### Linux diff --git a/src/xenia/app/emulator_window.cc b/src/xenia/app/emulator_window.cc index b7c983565..776dbc82d 100644 --- a/src/xenia/app/emulator_window.cc +++ b/src/xenia/app/emulator_window.cc @@ -44,8 +44,8 @@ std::unique_ptr EmulatorWindow::Create(Emulator* emulator) { xe::Profiler::ThreadEnter("Win32 Loop"); if (!emulator_window->Initialize()) { - XEFATAL("Failed to initialize main window"); - exit(1); + xe::FatalError("Failed to initialize main window"); + return; } }); diff --git a/src/xenia/apu/xma_decoder.cc b/src/xenia/apu/xma_decoder.cc index fe679e14e..d8bd47ef0 100644 --- a/src/xenia/apu/xma_decoder.cc +++ b/src/xenia/apu/xma_decoder.cc @@ -20,7 +20,7 @@ extern "C" { #include "libavutil/log.h" -} +} // extern "C" // As with normal Microsoft, there are like twelve different ways to access // the audio APIs. Early games use XMA*() methods almost exclusively to touch @@ -55,9 +55,7 @@ XmaDecoder::XmaDecoder(cpu::Processor* processor) XmaDecoder::~XmaDecoder() = default; void av_log_callback(void* avcl, int level, const char* fmt, va_list va) { - StringBuffer buff; - buff.AppendVarargs(fmt, va); - xe::log_line('i', "libav: %s", buff.GetString()); + xe::LogLineVarargs('A', fmt, va); } X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) { diff --git a/src/xenia/base/filesystem.cc b/src/xenia/base/filesystem.cc index 1cb20a229..968b3fa65 100644 --- a/src/xenia/base/filesystem.cc +++ b/src/xenia/base/filesystem.cc @@ -34,12 +34,12 @@ std::string CanonicalizePath(const std::string& original_path) { pos_n = std::string::npos; break; case 1: - // Duplicate separators + // Duplicate separators. path.erase(pos, 1); pos_n -= 1; break; case 2: - // Potential marker for current directory + // Potential marker for current directory. if (path[pos + 1] == '.') { path.erase(pos, 2); pos_n -= 2; @@ -48,10 +48,10 @@ std::string CanonicalizePath(const std::string& original_path) { } break; case 3: - // Potential marker for parent directory + // Potential marker for parent directory. if (path[pos + 1] == '.' && path[pos + 2] == '.') { if (path_breaks.empty()) { - // Ensure we don't override the device name + // Ensure we don't override the device name. std::string::size_type loc(path.find_first_of(':')); auto req(pos + 3); if (loc == std::string::npos || loc > req) { @@ -66,7 +66,7 @@ std::string CanonicalizePath(const std::string& original_path) { auto last_diff((pos + 3) - last); path.erase(last, last_diff); pos_n = last; - // Also remove path reference + // Also remove path reference. path_breaks.erase(path_breaks.end() - 1); } } else { @@ -82,12 +82,12 @@ std::string CanonicalizePath(const std::string& original_path) { pos = pos_n; } - // Remove trailing seperator + // Remove trailing seperator. if (!path.empty() && path.back() == path_sep) { path.erase(path.size() - 1); } - // Final sanity check for dead paths + // Final sanity check for dead paths. if ((path.size() == 1 && (path[0] == '.' || path[0] == path_sep)) || (path.size() == 2 && path[0] == '.' && path[1] == '.')) { return ""; @@ -96,6 +96,16 @@ std::string CanonicalizePath(const std::string& original_path) { return path; } +bool CreateParentFolder(const std::wstring& path) { + auto fixed_path = xe::fix_path_separators(path, '/'); + auto base_path = xe::find_base_path(fixed_path, '/'); + if (!PathExists(base_path)) { + return CreateFolder(base_path); + } else { + return true; + } +} + WildcardFlags WildcardFlags::FIRST(true, false); WildcardFlags WildcardFlags::LAST(false, true); diff --git a/src/xenia/base/filesystem.h b/src/xenia/base/filesystem.h index 5dcdf348a..5b7032641 100644 --- a/src/xenia/base/filesystem.h +++ b/src/xenia/base/filesystem.h @@ -24,6 +24,7 @@ std::string CanonicalizePath(const std::string& original_path); bool PathExists(const std::wstring& path); +bool CreateParentFolder(const std::wstring& path); bool CreateFolder(const std::wstring& path); bool DeleteFolder(const std::wstring& path); bool IsFolder(const std::wstring& path); diff --git a/src/xenia/base/logging.cc b/src/xenia/base/logging.cc index 72cd0a1cc..f0fe335d0 100644 --- a/src/xenia/base/logging.cc +++ b/src/xenia/base/logging.cc @@ -11,12 +11,15 @@ #include +#include #include #include #include +#include "xenia/base/filesystem.h" #include "xenia/base/main.h" #include "xenia/base/math.h" +#include "xenia/base/ring_buffer.h" #include "xenia/base/threading.h" // For MessageBox: @@ -25,91 +28,150 @@ #include "xenia/base/platform_win.h" #endif // XE_PLATFORM_WIN32 -DEFINE_bool(fast_stdout, false, - "Don't lock around stdout/stderr. May introduce weirdness."); -DEFINE_bool(flush_stdout, true, "Flush stdout after each log line."); +DEFINE_string(log_file, "", + "Logs are written to the given file instead of the default."); +DEFINE_bool(flush_log, true, "Flush log file after each log line batch."); namespace xe { -std::mutex log_lock; +thread_local std::vector log_format_buffer_(64 * 1024); -thread_local std::vector log_buffer(16 * 1024); - -void format_log_line(char* buffer, size_t buffer_capacity, - const char level_char, const char* fmt, va_list args) { - char* buffer_ptr; - buffer_ptr = buffer; - *(buffer_ptr++) = level_char; - *(buffer_ptr++) = '>'; - *(buffer_ptr++) = ' '; - buffer_ptr += - std::snprintf(buffer_ptr, buffer_capacity - (buffer_ptr - buffer), "%.4X", - xe::threading::current_thread_id()); - *(buffer_ptr++) = ' '; - - // Scribble args into the print buffer. - size_t remaining_capacity = buffer_capacity - (buffer_ptr - buffer) - 3; - size_t chars_written = vsnprintf(buffer_ptr, remaining_capacity, fmt, args); - if (chars_written >= remaining_capacity) { - buffer_ptr += remaining_capacity - 1; - } else { - buffer_ptr += chars_written; +class Logger { + public: + Logger() : ring_buffer_(buffer_, kBufferSize), running_(true) { + flush_event_ = xe::threading::Event::CreateAutoResetEvent(false); + write_thread_ = + xe::threading::Thread::Create({}, [this]() { WriteThread(); }); + write_thread_->set_name("xe::FileLogSink Writer"); } - // Add a trailing newline. - if (buffer_ptr[-1] != '\n') { - buffer_ptr[0] = '\n'; - buffer_ptr[1] = 0; + ~Logger() { + running_ = false; + flush_event_->Set(); + xe::threading::Wait(write_thread_.get(), true); + fflush(file_); + fclose(file_); } + + void Initialize(const std::wstring& app_name) { + if (!FLAGS_log_file.empty()) { + auto file_path = xe::to_wstring(FLAGS_log_file.c_str()); + xe::filesystem::CreateParentFolder(file_path); + file_ = xe::filesystem::OpenFile(file_path, "wt"); + } else { + auto file_path = app_name + L".log"; + file_ = xe::filesystem::OpenFile(file_path, "wt"); + } + } + + void AppendLine(uint32_t thread_id, const char level_char, const char* buffer, + size_t buffer_length) { + LogLine line; + line.thread_id = thread_id; + line.level_char = level_char; + line.buffer_length = buffer_length; + while (true) { + mutex_.lock(); + if (ring_buffer_.write_count() < sizeof(line) + buffer_length) { + // Buffer is full. Stall. + mutex_.unlock(); + xe::threading::MaybeYield(); + continue; + } + ring_buffer_.Write(&line, sizeof(LogLine)); + ring_buffer_.Write(buffer, buffer_length); + mutex_.unlock(); + break; + } + flush_event_->Set(); + } + + private: + static const size_t kBufferSize = 32 * 1024 * 1024; + + struct LogLine { + uint32_t thread_id; + char level_char; + size_t buffer_length; + }; + + void WriteThread() { + while (running_) { + mutex_.lock(); + bool did_write = false; + while (!ring_buffer_.empty()) { + did_write = true; + LogLine line; + ring_buffer_.Read(&line, sizeof(line)); + ring_buffer_.Read(log_format_buffer_.data(), line.buffer_length); + const char prefix[3] = {line.level_char, '>', ' '}; + fwrite(prefix, 1, sizeof(prefix), file_); + fwrite(log_format_buffer_.data(), 1, line.buffer_length, file_); + if (log_format_buffer_[line.buffer_length - 1] != '\n') { + const char suffix[1] = {'\n'}; + fwrite(suffix, 1, sizeof(suffix), file_); + } + } + mutex_.unlock(); + if (did_write) { + if (FLAGS_flush_log) { + fflush(file_); + } + } + xe::threading::Wait(flush_event_.get(), true); + } + } + + FILE* file_ = nullptr; + uint8_t buffer_[kBufferSize]; + RingBuffer ring_buffer_; + std::mutex mutex_; + std::atomic running_; + std::unique_ptr flush_event_; + std::unique_ptr write_thread_; +}; + +Logger logger_; + +void InitializeLogging(const std::wstring& app_name) { + logger_.Initialize(app_name); } -void log_line(const char level_char, const char* fmt, ...) { - // SCOPE_profile_cpu_i("emu", "log_line"); - +void LogLineFormat(const char level_char, const char* fmt, ...) { va_list args; va_start(args, fmt); - format_log_line(log_buffer.data(), log_buffer.capacity(), level_char, fmt, - args); + size_t chars_written = vsnprintf(log_format_buffer_.data(), + log_format_buffer_.capacity(), fmt, args); va_end(args); - - if (!FLAGS_fast_stdout) { - log_lock.lock(); - } -#if 0 // defined(OutputDebugString) - OutputDebugStringA(log_buffer.data()); -#else - fprintf(stdout, "%s", log_buffer.data()); - if (FLAGS_flush_stdout) { - fflush(stdout); - } -#endif // OutputDebugString - if (!FLAGS_fast_stdout) { - log_lock.unlock(); - } + logger_.AppendLine(xe::threading::current_thread_id(), level_char, + log_format_buffer_.data(), chars_written); } -void handle_fatal(const char* fmt, ...) { +void LogLineVarargs(const char level_char, const char* fmt, va_list args) { + size_t chars_written = vsnprintf(log_format_buffer_.data(), + log_format_buffer_.capacity(), fmt, args); + logger_.AppendLine(xe::threading::current_thread_id(), level_char, + log_format_buffer_.data(), chars_written); +} + +void LogLine(const char level_char, const std::string& str) { + logger_.AppendLine(xe::threading::current_thread_id(), level_char, + str.c_str(), str.length()); +} + +void FatalError(const char* fmt, ...) { va_list args; va_start(args, fmt); - format_log_line(log_buffer.data(), log_buffer.capacity(), 'X', fmt, args); + LogLineVarargs('X', fmt, args); va_end(args); - if (!FLAGS_fast_stdout) { - log_lock.lock(); - } -#if defined(OutputDebugString) - OutputDebugStringA(log_buffer.data()); -#else - fprintf(stderr, "%s", log_buffer.data()); - fflush(stderr); -#endif // OutputDebugString - if (!FLAGS_fast_stdout) { - log_lock.unlock(); - } - #if XE_PLATFORM_WIN32 if (!xe::has_console_attached()) { - MessageBoxA(NULL, log_buffer.data(), "Xenia Error", + va_start(args, fmt); + vsnprintf(log_format_buffer_.data(), log_format_buffer_.capacity(), fmt, + args); + va_end(args); + MessageBoxA(NULL, log_format_buffer_.data(), "Xenia Error", MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND); } #endif // WIN32 @@ -117,4 +179,6 @@ void handle_fatal(const char* fmt, ...) { exit(1); } +void FatalError(const std::string& str) { FatalError(str.c_str()); } + } // namespace xe diff --git a/src/xenia/base/logging.h b/src/xenia/base/logging.h index 42613a499..00f3dbd5f 100644 --- a/src/xenia/base/logging.h +++ b/src/xenia/base/logging.h @@ -11,86 +11,47 @@ #define XENIA_BASE_LOGGING_H_ #include +#include #include "xenia/base/string.h" namespace xe { #define XE_OPTION_ENABLE_LOGGING 1 -#define XE_OPTION_LOG_ERROR 1 -#define XE_OPTION_LOG_WARNING 1 -#define XE_OPTION_LOG_INFO 1 -#define XE_OPTION_LOG_DEBUG 1 -#define XE_OPTION_LOG_CPU 1 -#define XE_OPTION_LOG_APU 1 -#define XE_OPTION_LOG_GPU 1 -#define XE_OPTION_LOG_KERNEL 1 -#define XE_OPTION_LOG_FS 1 -#define XE_EMPTY_MACRO \ - do { \ - } while (false) +// Initializes the logging system and any outputs requested. +// Must be called on startup. +void InitializeLogging(const std::wstring& app_name); -void log_line(const char level_char, const char* fmt, ...); -void handle_fatal(const char* fmt, ...); +// Appends a line to the log with printf-style formatting. +void LogLineFormat(const char level_char, const char* fmt, ...); +void LogLineVarargs(const char level_char, const char* fmt, va_list args); +// Appends a line to the log. +void LogLine(const char level_char, const std::string& str); + +// Logs a fatal error with printf-style formatting and aborts the program. +void FatalError(const char* fmt, ...); +// Logs a fatal error and aborts the program. +void FatalError(const std::string& str); #if XE_OPTION_ENABLE_LOGGING -#define XELOGCORE(level, fmt, ...) xe::log_line(level, fmt, ##__VA_ARGS__) +#define XELOGCORE(level, fmt, ...) xe::LogLineFormat(level, fmt, ##__VA_ARGS__) #else -#define XELOGCORE(level, fmt, ...) XE_EMPTY_MACRO +#define XELOGCORE(level, fmt, ...) \ + do { \ + } while (false) #endif // ENABLE_LOGGING -#define XEFATAL(fmt, ...) \ - do { \ - xe::handle_fatal(fmt, ##__VA_ARGS__); \ - } while (false) - -#if XE_OPTION_LOG_ERROR #define XELOGE(fmt, ...) XELOGCORE('!', fmt, ##__VA_ARGS__) -#else -#define XELOGE(fmt, ...) XE_EMPTY_MACRO -#endif -#if XE_OPTION_LOG_WARNING #define XELOGW(fmt, ...) XELOGCORE('w', fmt, ##__VA_ARGS__) -#else -#define XELOGW(fmt, ...) XE_EMPTY_MACRO -#endif -#if XE_OPTION_LOG_INFO #define XELOGI(fmt, ...) XELOGCORE('i', fmt, ##__VA_ARGS__) -#else -#define XELOGI(fmt, ...) XE_EMPTY_MACRO -#endif -#if XE_OPTION_LOG_DEBUG #define XELOGD(fmt, ...) XELOGCORE('d', fmt, ##__VA_ARGS__) -#else -#define XELOGD(fmt, ...) XE_EMPTY_MACRO -#endif -#if XE_OPTION_LOG_CPU #define XELOGCPU(fmt, ...) XELOGCORE('C', fmt, ##__VA_ARGS__) -#else -#define XELOGCPU(fmt, ...) XE_EMPTY_MACRO -#endif -#if XE_OPTION_LOG_APU #define XELOGAPU(fmt, ...) XELOGCORE('A', fmt, ##__VA_ARGS__) -#else -#define XELOGAPU(fmt, ...) XE_EMPTY_MACRO -#endif -#if XE_OPTION_LOG_GPU #define XELOGGPU(fmt, ...) XELOGCORE('G', fmt, ##__VA_ARGS__) -#else -#define XELOGGPU(fmt, ...) XE_EMPTY_MACRO -#endif -#if XE_OPTION_LOG_KERNEL #define XELOGKERNEL(fmt, ...) XELOGCORE('K', fmt, ##__VA_ARGS__) -#else -#define XELOGKERNEL(fmt, ...) XE_EMPTY_MACRO -#endif -#if XE_OPTION_LOG_FS #define XELOGFS(fmt, ...) XELOGCORE('F', fmt, ##__VA_ARGS__) -#else -#define XELOGFS(fmt, ...) XE_EMPTY_MACRO -#endif } // namespace xe diff --git a/src/xenia/base/main_posix.cc b/src/xenia/base/main_posix.cc index cc178672a..55dfae745 100644 --- a/src/xenia/base/main_posix.cc +++ b/src/xenia/base/main_posix.cc @@ -11,6 +11,7 @@ #include +#include "xenia/base/logging.h" #include "xenia/base/string.h" namespace xe { @@ -32,6 +33,9 @@ extern "C" int main(int argc, char** argv) { args.push_back(xe::to_wstring(argv[n])); } + // Initialize logging. Needs parsed FLAGS. + xe::InitializeLogging(entry_info.name); + // Call app-provided entry point. int result = entry_info.entry_point(args); diff --git a/src/xenia/base/main_win.cc b/src/xenia/base/main_win.cc index 187bcc7d8..888f4a1ec 100644 --- a/src/xenia/base/main_win.cc +++ b/src/xenia/base/main_win.cc @@ -13,6 +13,7 @@ #include #include +#include "xenia/base/logging.h" #include "xenia/base/platform_win.h" #include "xenia/base/string.h" @@ -84,6 +85,9 @@ int Main() { // NOTE: this may fail if COM has already been initialized - that's OK. CoInitializeEx(nullptr, COINIT_MULTITHREADED); + // Initialize logging. Needs parsed FLAGS. + xe::InitializeLogging(entry_info.name); + // Call app-provided entry point. int result = entry_info.entry_point(args); diff --git a/src/xenia/base/ring_buffer.cc b/src/xenia/base/ring_buffer.cc index 6fd3578bc..13f727377 100644 --- a/src/xenia/base/ring_buffer.cc +++ b/src/xenia/base/ring_buffer.cc @@ -15,7 +15,7 @@ namespace xe { RingBuffer::RingBuffer(uint8_t* buffer, size_t capacity) - : buffer_(buffer), capacity_(capacity), read_offset_(0), write_offset_(0) {} + : buffer_(buffer), capacity_(capacity) {} size_t RingBuffer::Read(uint8_t* buffer, size_t count) { count = std::min(count, capacity_); @@ -37,7 +37,7 @@ size_t RingBuffer::Read(uint8_t* buffer, size_t count) { return count; } -size_t RingBuffer::Write(uint8_t* buffer, size_t count) { +size_t RingBuffer::Write(const uint8_t* buffer, size_t count) { count = std::min(count, capacity_); if (!count) { return 0; diff --git a/src/xenia/base/ring_buffer.h b/src/xenia/base/ring_buffer.h index 300c4cdb1..abe07ff53 100644 --- a/src/xenia/base/ring_buffer.h +++ b/src/xenia/base/ring_buffer.h @@ -20,14 +20,13 @@ class RingBuffer { public: RingBuffer(uint8_t* buffer, size_t capacity); - size_t Read(uint8_t* buffer, size_t count); - size_t Write(uint8_t* buffer, size_t count); + uint8_t* buffer() const { return buffer_; } + size_t capacity() const { return capacity_; } + bool empty() const { return read_offset_ == write_offset_; } - uint8_t* buffer() { return buffer_; } - size_t capacity() { return capacity_; } - - size_t read_offset() { return read_offset_; } - size_t read_count() { + size_t read_offset() const { return read_offset_; } + void set_read_offset(size_t offset) { read_offset_ = offset % capacity_; } + size_t read_count() const { if (read_offset_ == write_offset_) { return 0; } else if (read_offset_ < write_offset_) { @@ -37,8 +36,9 @@ class RingBuffer { } } - size_t write_offset() { return write_offset_; } - size_t write_count() { + size_t write_offset() const { return write_offset_; } + void set_write_offset(size_t offset) { write_offset_ = offset % capacity_; } + size_t write_count() const { if (read_offset_ == write_offset_) { return capacity_; } else if (write_offset_ < read_offset_) { @@ -48,15 +48,23 @@ class RingBuffer { } } - void set_read_offset(size_t offset) { read_offset_ = offset % capacity_; } + size_t Read(uint8_t* buffer, size_t count); + template + size_t Read(T* buffer, size_t count) { + return Read(reinterpret_cast(buffer), count); + } - void set_write_offset(size_t offset) { write_offset_ = offset % capacity_; } + size_t Write(const uint8_t* buffer, size_t count); + template + size_t Write(const T* buffer, size_t count) { + return Write(reinterpret_cast(buffer), count); + } private: - uint8_t* buffer_; - size_t capacity_; - size_t read_offset_; - size_t write_offset_; + uint8_t* buffer_ = nullptr; + size_t capacity_ = 0; + size_t read_offset_ = 0; + size_t write_offset_ = 0; }; } // namespace xe diff --git a/src/xenia/base/string.cc b/src/xenia/base/string.cc index 2dcc93d49..4e31292a9 100644 --- a/src/xenia/base/string.cc +++ b/src/xenia/base/string.cc @@ -155,14 +155,14 @@ std::string fix_path_separators(const std::string& source, char new_sep) { return dest; } -std::string find_name_from_path(const std::string& path) { +std::string find_name_from_path(const std::string& path, char sep) { std::string name(path); if (!path.empty()) { std::string::size_type from(std::string::npos); - if (path.back() == '\\') { + if (path.back() == sep) { from = path.size() - 2; } - auto pos(path.find_last_of('\\', from)); + auto pos(path.find_last_of(sep, from)); if (pos != std::string::npos) { if (from == std::string::npos) { name = path.substr(pos + 1); @@ -175,14 +175,14 @@ std::string find_name_from_path(const std::string& path) { return name; } -std::wstring find_name_from_path(const std::wstring& path) { +std::wstring find_name_from_path(const std::wstring& path, wchar_t sep) { std::wstring name(path); if (!path.empty()) { std::wstring::size_type from(std::wstring::npos); - if (path.back() == '\\') { + if (path.back() == sep) { from = path.size() - 2; } - auto pos(path.find_last_of('\\', from)); + auto pos(path.find_last_of(sep, from)); if (pos != std::wstring::npos) { if (from == std::wstring::npos) { name = path.substr(pos + 1); @@ -195,12 +195,12 @@ std::wstring find_name_from_path(const std::wstring& path) { return name; } -std::string find_base_path(const std::string& path) { - auto last_slash = path.find_last_of('\\'); +std::string find_base_path(const std::string& path, char sep) { + auto last_slash = path.find_last_of(sep); if (last_slash == std::string::npos) { return path; } else if (last_slash == path.length() - 1) { - auto prev_slash = path.find_last_of('\\', last_slash - 1); + auto prev_slash = path.find_last_of(sep, last_slash - 1); if (prev_slash == std::string::npos) { return ""; } else { @@ -211,12 +211,12 @@ std::string find_base_path(const std::string& path) { } } -std::wstring find_base_path(const std::wstring& path) { - auto last_slash = path.find_last_of('\\'); +std::wstring find_base_path(const std::wstring& path, wchar_t sep) { + auto last_slash = path.find_last_of(sep); if (last_slash == std::wstring::npos) { return path; } else if (last_slash == path.length() - 1) { - auto prev_slash = path.find_last_of('\\', last_slash - 1); + auto prev_slash = path.find_last_of(sep, last_slash - 1); if (prev_slash == std::wstring::npos) { return L""; } else { diff --git a/src/xenia/base/string.h b/src/xenia/base/string.h index 4c560671d..f611a2b5c 100644 --- a/src/xenia/base/string.h +++ b/src/xenia/base/string.h @@ -45,12 +45,16 @@ std::string fix_path_separators(const std::string& source, char new_sep = xe::kPathSeparator); // Find the top directory name or filename from a path. -std::string find_name_from_path(const std::string& path); -std::wstring find_name_from_path(const std::wstring& path); +std::string find_name_from_path(const std::string& path, + char sep = xe::kPathSeparator); +std::wstring find_name_from_path(const std::wstring& path, + wchar_t sep = xe::kPathSeparator); // Get parent path of the given directory or filename. -std::string find_base_path(const std::string& path); -std::wstring find_base_path(const std::wstring& path); +std::string find_base_path(const std::string& path, + char sep = xe::kPathSeparator); +std::wstring find_base_path(const std::wstring& path, + wchar_t sep = xe::kPathSeparator); } // namespace xe diff --git a/src/xenia/cpu/backend/x64/x64_emitter.cc b/src/xenia/cpu/backend/x64/x64_emitter.cc index ed5d07856..5cd66c4ac 100644 --- a/src/xenia/cpu/backend/x64/x64_emitter.cc +++ b/src/xenia/cpu/backend/x64/x64_emitter.cc @@ -75,7 +75,7 @@ X64Emitter::X64Emitter(X64Backend* backend, XbyakAllocator* allocator) } if (!cpu_.has(Xbyak::util::Cpu::tAVX)) { - XEFATAL( + xe::FatalError( "Your CPU is too old to support Xenia. See the FAQ for system " "requirements at http://xenia.jp"); return; diff --git a/src/xenia/cpu/frontend/ppc_scanner.cc b/src/xenia/cpu/frontend/ppc_scanner.cc index a8e157781..f0bc53ceb 100644 --- a/src/xenia/cpu/frontend/ppc_scanner.cc +++ b/src/xenia/cpu/frontend/ppc_scanner.cc @@ -22,7 +22,9 @@ #if 0 #define LOGPPC(fmt, ...) XELOGCORE('p', fmt, ##__VA_ARGS__) #else -#define LOGPPC(fmt, ...) XE_EMPTY_MACRO +#define LOGPPC(fmt, ...) \ + do { \ + } while (false) #endif namespace xe { diff --git a/src/xenia/debug/ui/application.cc b/src/xenia/debug/ui/application.cc index a5aeaeea1..75c8ab5a3 100644 --- a/src/xenia/debug/ui/application.cc +++ b/src/xenia/debug/ui/application.cc @@ -46,8 +46,8 @@ std::unique_ptr Application::Create() { xe::Profiler::ThreadEnter("Win32 Loop"); if (!app->Initialize()) { - XEFATAL("Failed to initialize application"); - exit(1); + xe::FatalError("Failed to initialize application"); + return; } fence.Signal(); diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index b54b80902..62873c454 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -228,11 +228,11 @@ X_STATUS Emulator::LaunchDiscImage(std::wstring path) { // Register the disc image in the virtual filesystem. auto device = std::make_unique(mount_path, path); if (!device->Initialize()) { - XELOGE("Unable to mount disc image"); + xe::FatalError("Unable to mount disc image; file not found or corrupt."); return X_STATUS_NO_SUCH_FILE; } if (!file_system_->RegisterDevice(std::move(device))) { - XELOGE("Unable to register disc image"); + xe::FatalError("Unable to register disc image."); return X_STATUS_NO_SUCH_FILE; } @@ -250,11 +250,12 @@ X_STATUS Emulator::LaunchStfsContainer(std::wstring path) { // Register the container in the virtual filesystem. auto device = std::make_unique(mount_path, path); if (!device->Initialize()) { - XELOGE("Unable to mount STFS container"); + xe::FatalError( + "Unable to mount STFS container; file not found or corrupt."); return X_STATUS_NO_SUCH_FILE; } if (!file_system_->RegisterDevice(std::move(device))) { - XELOGE("Unable to register STFS container"); + xe::FatalError("Unable to register STFS container."); return X_STATUS_NO_SUCH_FILE; } diff --git a/src/xenia/gpu/gl4/command_processor.cc b/src/xenia/gpu/gl4/command_processor.cc index 467f3f0ad..da65ff63c 100644 --- a/src/xenia/gpu/gl4/command_processor.cc +++ b/src/xenia/gpu/gl4/command_processor.cc @@ -172,7 +172,7 @@ void CommandProcessor::ClearCaches() { void CommandProcessor::WorkerThreadMain() { context_->MakeCurrent(); if (!SetupGL()) { - XEFATAL("Unable to setup command processor GL state"); + xe::FatalError("Unable to setup command processor GL state"); return; } diff --git a/src/xenia/gpu/gl4/gl4_graphics_system.cc b/src/xenia/gpu/gl4/gl4_graphics_system.cc index 1d2cd320f..845ddb91d 100644 --- a/src/xenia/gpu/gl4/gl4_graphics_system.cc +++ b/src/xenia/gpu/gl4/gl4_graphics_system.cc @@ -88,7 +88,7 @@ X_STATUS GL4GraphicsSystem::Setup(cpu::Processor* processor, processor_context->ClearCurrent(); }); if (!processor_context) { - XEFATAL( + xe::FatalError( "Unable to initialize GL context. Xenia requires OpenGL 4.5. Ensure " "you have the latest drivers for your GPU and that it supports OpenGL " "4.5. See http://xenia.jp/faq/ for more information."); diff --git a/src/xenia/gpu/gl4/trace_viewer_main.cc b/src/xenia/gpu/gl4/trace_viewer_main.cc index 346e61495..bdf639afc 100644 --- a/src/xenia/gpu/gl4/trace_viewer_main.cc +++ b/src/xenia/gpu/gl4/trace_viewer_main.cc @@ -2197,8 +2197,8 @@ int trace_viewer_main(const std::vector& args) { loop->PostSynchronous([&window]() { xe::threading::set_name("Win32 Loop"); if (!window->Initialize()) { - XEFATAL("Failed to initialize main window"); - exit(1); + FatalError("Failed to initialize main window"); + return; } }); window->on_closed.AddListener([&loop](xe::ui::UIEvent* e) { diff --git a/src/xenia/gpu/graphics_system.cc b/src/xenia/gpu/graphics_system.cc index 55bc3d8e1..11691fbd5 100644 --- a/src/xenia/gpu/graphics_system.cc +++ b/src/xenia/gpu/graphics_system.cc @@ -76,8 +76,8 @@ void GraphicsSystem::DispatchInterruptCallback(uint32_t source, uint32_t cpu) { } thread->SetActiveCpu(cpu); - // XELOGGPU("Dispatching GPU interrupt at %.8X w/ mode %d on cpu %d", - // interrupt_callback_, source, cpu); + XELOGGPU("Dispatching GPU interrupt at %.8X w/ mode %d on cpu %d", + interrupt_callback_, source, cpu); uint64_t args[] = {source, interrupt_callback_data_}; processor_->Execute(thread->thread_state(), interrupt_callback_, args, diff --git a/src/xenia/kernel/objects/xuser_module.cc b/src/xenia/kernel/objects/xuser_module.cc index 9f4499264..78090b3a8 100644 --- a/src/xenia/kernel/objects/xuser_module.cc +++ b/src/xenia/kernel/objects/xuser_module.cc @@ -276,8 +276,8 @@ X_STATUS XUserModule::Launch(uint32_t flags) { // We know this is the 'main thread'. char thread_name[32]; - snprintf(thread_name, xe::countof(thread_name), "Main XThread %04X", - thread->handle()); + std::snprintf(thread_name, xe::countof(thread_name), "Main XThread %04X", + thread->handle()); thread->set_name(thread_name); X_STATUS result = thread->Create(); @@ -308,24 +308,31 @@ void XUserModule::Dump() { return; } + StringBuffer sb; + xe::cpu::ExportResolver* export_resolver = kernel_state_->emulator()->export_resolver(); auto header = xex_header(); // XEX header. - printf("Module %s:\n", path_.c_str()); - printf(" Module Flags: %.8X\n", (uint32_t)header->module_flags); + sb.AppendFormat("Module %s:\n", path_.c_str()); + sb.AppendFormat(" Module Flags: %.8X\n", (uint32_t)header->module_flags); // Security header auto security_info = xex_module()->xex_security_info(); - printf("Security Header:\n"); - printf(" Image Flags: %.8X\n", (uint32_t)security_info->image_flags); - printf(" Load Address: %.8X\n", (uint32_t)security_info->load_address); - printf(" Image Size: %.8X\n", (uint32_t)security_info->image_size); - printf(" Export Table: %.8X\n", (uint32_t)security_info->export_table); + sb.AppendFormat("Security Header:\n"); + sb.AppendFormat(" Image Flags: %.8X\n", + (uint32_t)security_info->image_flags); + sb.AppendFormat(" Load Address: %.8X\n", + (uint32_t)security_info->load_address); + sb.AppendFormat(" Image Size: %.8X\n", + (uint32_t)security_info->image_size); + sb.AppendFormat(" Export Table: %.8X\n", + (uint32_t)security_info->export_table); // Optional headers - printf("Optional Header Count: %d\n", (uint32_t)header->header_count); + sb.AppendFormat("Optional Header Count: %d\n", + (uint32_t)header->header_count); for (uint32_t i = 0; i < header->header_count; i++) { auto& opt_header = header->headers[i]; @@ -335,7 +342,7 @@ void XUserModule::Dump() { reinterpret_cast(header) + opt_header.offset; switch (opt_header.key) { case XEX_HEADER_RESOURCE_INFO: { - printf(" XEX_HEADER_RESOURCE_INFO:\n"); + sb.AppendFormat(" XEX_HEADER_RESOURCE_INFO:\n"); auto opt_resource_info = reinterpret_cast(opt_header_ptr); @@ -348,35 +355,37 @@ void XUserModule::Dump() { std::memcpy(name, res.name, sizeof(res.name)); name[8] = 0; - printf(" %-8s %.8X-%.8X, %db\n", name, (uint32_t)res.address, - (uint32_t)res.address + (uint32_t)res.size, - (uint32_t)res.size); + sb.AppendFormat( + " %-8s %.8X-%.8X, %db\n", name, (uint32_t)res.address, + (uint32_t)res.address + (uint32_t)res.size, (uint32_t)res.size); } } break; case XEX_HEADER_FILE_FORMAT_INFO: { - printf(" XEX_HEADER_FILE_FORMAT_INFO (TODO):\n"); + sb.AppendFormat(" XEX_HEADER_FILE_FORMAT_INFO (TODO):\n"); } break; case XEX_HEADER_DELTA_PATCH_DESCRIPTOR: { - printf(" XEX_HEADER_DELTA_PATCH_DESCRIPTOR (TODO):\n"); + sb.AppendFormat(" XEX_HEADER_DELTA_PATCH_DESCRIPTOR (TODO):\n"); } break; case XEX_HEADER_BOUNDING_PATH: { auto opt_bound_path = reinterpret_cast(opt_header_ptr); - printf(" XEX_HEADER_BOUNDING_PATH: %s\n", opt_bound_path->path); + sb.AppendFormat(" XEX_HEADER_BOUNDING_PATH: %s\n", + opt_bound_path->path); } break; case XEX_HEADER_ORIGINAL_BASE_ADDRESS: { - printf(" XEX_HEADER_ORIGINAL_BASE_ADDRESS: %.8X\n", - (uint32_t)opt_header.value); + sb.AppendFormat(" XEX_HEADER_ORIGINAL_BASE_ADDRESS: %.8X\n", + (uint32_t)opt_header.value); } break; case XEX_HEADER_ENTRY_POINT: { - printf(" XEX_HEADER_ENTRY_POINT: %.8X\n", (uint32_t)opt_header.value); + sb.AppendFormat(" XEX_HEADER_ENTRY_POINT: %.8X\n", + (uint32_t)opt_header.value); } break; case XEX_HEADER_IMAGE_BASE_ADDRESS: { - printf(" XEX_HEADER_IMAGE_BASE_ADDRESS: %.8X\n", - (uint32_t)opt_header.value); + sb.AppendFormat(" XEX_HEADER_IMAGE_BASE_ADDRESS: %.8X\n", + (uint32_t)opt_header.value); } break; case XEX_HEADER_IMPORT_LIBRARIES: { - printf(" XEX_HEADER_IMPORT_LIBRARIES:\n"); + sb.AppendFormat(" XEX_HEADER_IMPORT_LIBRARIES:\n"); auto opt_import_libraries = reinterpret_cast(opt_header_ptr); @@ -408,116 +417,119 @@ void XUserModule::Dump() { auto library = reinterpret_cast( libraries + library_offset); auto name = string_table[library->name_index]; - printf(" %s - %d imports\n", name, (uint16_t)library->count); + sb.AppendFormat(" %s - %d imports\n", name, + (uint16_t)library->count); // Manually byteswap these because of the bitfields. xex2_version version, version_min; version.value = xe::byte_swap(library->version.value); version_min.value = xe::byte_swap(library->version_min.value); - printf(" Version: %d.%d.%d.%d\n", version.major, version.minor, - version.build, version.qfe); - printf(" Min Version: %d.%d.%d.%d\n", version_min.major, - version_min.minor, version_min.build, version_min.qfe); + sb.AppendFormat(" Version: %d.%d.%d.%d\n", version.major, + version.minor, version.build, version.qfe); + sb.AppendFormat(" Min Version: %d.%d.%d.%d\n", version_min.major, + version_min.minor, version_min.build, + version_min.qfe); library_offset += library->size; } } break; case XEX_HEADER_CHECKSUM_TIMESTAMP: { - printf(" XEX_HEADER_CHECKSUM_TIMESTAMP (TODO):\n"); + sb.AppendFormat(" XEX_HEADER_CHECKSUM_TIMESTAMP (TODO):\n"); } break; case XEX_HEADER_ORIGINAL_PE_NAME: { auto opt_pe_name = reinterpret_cast(opt_header_ptr); - printf(" XEX_HEADER_ORIGINAL_PE_NAME: %s\n", opt_pe_name->name); + sb.AppendFormat(" XEX_HEADER_ORIGINAL_PE_NAME: %s\n", + opt_pe_name->name); } break; case XEX_HEADER_STATIC_LIBRARIES: { - printf(" XEX_HEADER_STATIC_LIBRARIES:\n"); + sb.AppendFormat(" XEX_HEADER_STATIC_LIBRARIES:\n"); auto opt_static_libraries = reinterpret_cast(opt_header_ptr); uint32_t count = (opt_static_libraries->size - 4) / 0x10; for (uint32_t l = 0; l < count; l++) { auto& library = opt_static_libraries->libraries[l]; - printf(" %-8s : %d.%d.%d.%d\n", library.name, - static_cast(library.version_major), - static_cast(library.version_minor), - static_cast(library.version_build), - static_cast(library.version_qfe)); + sb.AppendFormat(" %-8s : %d.%d.%d.%d\n", library.name, + static_cast(library.version_major), + static_cast(library.version_minor), + static_cast(library.version_build), + static_cast(library.version_qfe)); } } break; case XEX_HEADER_TLS_INFO: { - printf(" XEX_HEADER_TLS_INFO:\n"); + sb.AppendFormat(" XEX_HEADER_TLS_INFO:\n"); auto opt_tls_info = reinterpret_cast(opt_header_ptr); - printf(" Slot Count: %d\n", - static_cast(opt_tls_info->slot_count)); - printf(" Raw Data Address: %.8X\n", - static_cast(opt_tls_info->raw_data_address)); - printf(" Data Size: %d\n", - static_cast(opt_tls_info->data_size)); - printf(" Raw Data Size: %d\n", - static_cast(opt_tls_info->raw_data_size)); + sb.AppendFormat(" Slot Count: %d\n", + static_cast(opt_tls_info->slot_count)); + sb.AppendFormat(" Raw Data Address: %.8X\n", + static_cast(opt_tls_info->raw_data_address)); + sb.AppendFormat(" Data Size: %d\n", + static_cast(opt_tls_info->data_size)); + sb.AppendFormat(" Raw Data Size: %d\n", + static_cast(opt_tls_info->raw_data_size)); } break; case XEX_HEADER_DEFAULT_STACK_SIZE: { - printf(" XEX_HEADER_DEFAULT_STACK_SIZE: %d\n", - static_cast(opt_header.value)); + sb.AppendFormat(" XEX_HEADER_DEFAULT_STACK_SIZE: %d\n", + static_cast(opt_header.value)); } break; case XEX_HEADER_DEFAULT_FILESYSTEM_CACHE_SIZE: { - printf(" XEX_HEADER_DEFAULT_FILESYSTEM_CACHE_SIZE: %d\n", - static_cast(opt_header.value)); + sb.AppendFormat(" XEX_HEADER_DEFAULT_FILESYSTEM_CACHE_SIZE: %d\n", + static_cast(opt_header.value)); } break; case XEX_HEADER_DEFAULT_HEAP_SIZE: { - printf(" XEX_HEADER_DEFAULT_HEAP_SIZE: %d\n", - static_cast(opt_header.value)); + sb.AppendFormat(" XEX_HEADER_DEFAULT_HEAP_SIZE: %d\n", + static_cast(opt_header.value)); } break; case XEX_HEADER_PAGE_HEAP_SIZE_AND_FLAGS: { - printf(" XEX_HEADER_PAGE_HEAP_SIZE_AND_FLAGS (TODO):\n"); + sb.AppendFormat(" XEX_HEADER_PAGE_HEAP_SIZE_AND_FLAGS (TODO):\n"); } break; case XEX_HEADER_SYSTEM_FLAGS: { - printf(" XEX_HEADER_SYSTEM_FLAGS: %.8X\n", - static_cast(opt_header.value)); + sb.AppendFormat(" XEX_HEADER_SYSTEM_FLAGS: %.8X\n", + static_cast(opt_header.value)); } break; case XEX_HEADER_EXECUTION_INFO: { - printf(" XEX_HEADER_EXECUTION_INFO:\n"); + sb.AppendFormat(" XEX_HEADER_EXECUTION_INFO:\n"); auto opt_exec_info = reinterpret_cast(opt_header_ptr); - printf(" Media ID: %.8X\n", - static_cast(opt_exec_info->media_id)); - printf(" Title ID: %.8X\n", - static_cast(opt_exec_info->title_id)); - printf(" Savegame ID: %.8X\n", - static_cast(opt_exec_info->title_id)); - printf(" Disc Number / Total: %d / %d\n", opt_exec_info->disc_number, - opt_exec_info->disc_count); + sb.AppendFormat(" Media ID: %.8X\n", + static_cast(opt_exec_info->media_id)); + sb.AppendFormat(" Title ID: %.8X\n", + static_cast(opt_exec_info->title_id)); + sb.AppendFormat(" Savegame ID: %.8X\n", + static_cast(opt_exec_info->title_id)); + sb.AppendFormat(" Disc Number / Total: %d / %d\n", + opt_exec_info->disc_number, opt_exec_info->disc_count); } break; case XEX_HEADER_TITLE_WORKSPACE_SIZE: { - printf(" XEX_HEADER_TITLE_WORKSPACE_SIZE: %d\n", - uint32_t(opt_header.value)); + sb.AppendFormat(" XEX_HEADER_TITLE_WORKSPACE_SIZE: %d\n", + uint32_t(opt_header.value)); } break; case XEX_HEADER_GAME_RATINGS: { - printf(" XEX_HEADER_GAME_RATINGS (TODO):\n"); + sb.AppendFormat(" XEX_HEADER_GAME_RATINGS (TODO):\n"); } break; case XEX_HEADER_LAN_KEY: { - printf(" XEX_HEADER_LAN_KEY (TODO):\n"); + sb.AppendFormat(" XEX_HEADER_LAN_KEY (TODO):\n"); } break; case XEX_HEADER_XBOX360_LOGO: { - printf(" XEX_HEADER_XBOX360_LOGO (TODO):\n"); + sb.AppendFormat(" XEX_HEADER_XBOX360_LOGO (TODO):\n"); } break; case XEX_HEADER_MULTIDISC_MEDIA_IDS: { - printf(" XEX_HEADER_MULTIDISC_MEDIA_IDS (TODO):\n"); + sb.AppendFormat(" XEX_HEADER_MULTIDISC_MEDIA_IDS (TODO):\n"); } break; case XEX_HEADER_ALTERNATE_TITLE_IDS: { - printf(" XEX_HEADER_ALTERNATE_TITLE_IDS (TODO):\n"); + sb.AppendFormat(" XEX_HEADER_ALTERNATE_TITLE_IDS (TODO):\n"); } break; case XEX_HEADER_ADDITIONAL_TITLE_MEMORY: { - printf(" XEX_HEADER_ADDITIONAL_TITLE_MEMORY: %d\n", - uint32_t(opt_header.value)); + sb.AppendFormat(" XEX_HEADER_ADDITIONAL_TITLE_MEMORY: %d\n", + uint32_t(opt_header.value)); } break; case XEX_HEADER_EXPORTS_BY_NAME: { - printf(" XEX_HEADER_EXPORTS_BY_NAME:\n"); + sb.AppendFormat(" XEX_HEADER_EXPORTS_BY_NAME:\n"); auto dir = reinterpret_cast(opt_header_ptr); @@ -539,16 +551,16 @@ void XUserModule::Dump() { auto name = reinterpret_cast(e_base + name_table[n]); uint16_t ordinal = ordinal_table[n]; uint32_t addr = exe_address + function_table[ordinal]; - printf(" %-28s - %.3X - %.8X\n", name, ordinal, addr); + sb.AppendFormat(" %-28s - %.3X - %.8X\n", name, ordinal, addr); } } break; default: { - printf(" Unknown Header %.8X\n", (uint32_t)opt_header.key); + sb.AppendFormat(" Unknown Header %.8X\n", (uint32_t)opt_header.key); } break; } } - printf("Sections:\n"); + sb.AppendFormat("Sections:\n"); for (uint32_t i = 0, page = 0; i < security_info->page_descriptor_count; i++) { // Manually byteswap the bitfield data. @@ -574,9 +586,9 @@ void XUserModule::Dump() { uint32_t start_address = security_info->load_address + (page * page_size); uint32_t end_address = start_address + (page_descriptor.size * page_size); - printf(" %3u %s %3u pages %.8X - %.8X (%d bytes)\n", page, type, - page_descriptor.size, start_address, end_address, - page_descriptor.size * page_size); + sb.AppendFormat(" %3u %s %3u pages %.8X - %.8X (%d bytes)\n", page, + type, page_descriptor.size, start_address, end_address, + page_descriptor.size * page_size); page += page_descriptor.size; } @@ -584,7 +596,7 @@ void XUserModule::Dump() { // TODO(benvanik): figure out a way to remove dependency on old xex header. auto old_header = xe_xex2_get_header(xex_module()->xex()); - printf("Imports:\n"); + sb.AppendFormat("Imports:\n"); for (size_t n = 0; n < old_header->import_library_count; n++) { const xe_xex2_import_library_t* library = &old_header->import_libraries[n]; @@ -592,14 +604,14 @@ void XUserModule::Dump() { size_t import_info_count; if (!xe_xex2_get_import_infos(xex_module()->xex(), library, &import_infos, &import_info_count)) { - printf(" %s - %lld imports\n", library->name, import_info_count); - printf(" Version: %d.%d.%d.%d\n", library->version.major, - library->version.minor, library->version.build, - library->version.qfe); - printf(" Min Version: %d.%d.%d.%d\n", library->min_version.major, - library->min_version.minor, library->min_version.build, - library->min_version.qfe); - printf("\n"); + sb.AppendFormat(" %s - %lld imports\n", library->name, import_info_count); + sb.AppendFormat(" Version: %d.%d.%d.%d\n", library->version.major, + library->version.minor, library->version.build, + library->version.qfe); + sb.AppendFormat(" Min Version: %d.%d.%d.%d\n", + library->min_version.major, library->min_version.minor, + library->min_version.build, library->min_version.qfe); + sb.AppendFormat("\n"); // Counts. int known_count = 0; @@ -642,14 +654,14 @@ void XUserModule::Dump() { } } float total_count = static_cast(import_info_count) / 100.0f; - printf(" Total: %4llu\n", import_info_count); - printf(" Known: %3d%% (%d known, %d unknown)\n", - static_cast(known_count / total_count), known_count, - unknown_count); - printf(" Implemented: %3d%% (%d implemented, %d unimplemented)\n", - static_cast(impl_count / total_count), impl_count, - unimpl_count); - printf("\n"); + sb.AppendFormat(" Total: %4llu\n", import_info_count); + sb.AppendFormat(" Known: %3d%% (%d known, %d unknown)\n", + static_cast(known_count / total_count), known_count, + unknown_count); + sb.AppendFormat( + " Implemented: %3d%% (%d implemented, %d unimplemented)\n", + static_cast(impl_count / total_count), impl_count, unimpl_count); + sb.AppendFormat("\n"); // Listing. for (size_t m = 0; m < import_info_count; m++) { @@ -674,18 +686,22 @@ void XUserModule::Dump() { } if (kernel_export && kernel_export->type == cpu::Export::Type::kVariable) { - printf(" V %.8X %.3X (%3d) %s %s\n", info->value_address, - info->ordinal, info->ordinal, implemented ? " " : "!!", name); + sb.AppendFormat(" V %.8X %.3X (%3d) %s %s\n", + info->value_address, info->ordinal, info->ordinal, + implemented ? " " : "!!", name); } else if (info->thunk_address) { - printf(" F %.8X %.8X %.3X (%3d) %s %s\n", info->value_address, - info->thunk_address, info->ordinal, info->ordinal, - implemented ? " " : "!!", name); + sb.AppendFormat(" F %.8X %.8X %.3X (%3d) %s %s\n", + info->value_address, info->thunk_address, + info->ordinal, info->ordinal, + implemented ? " " : "!!", name); } } } - printf("\n"); + sb.AppendFormat("\n"); } + + XELOGI(sb.GetString()); } } // namespace kernel diff --git a/src/xenia/ui/gl/gl_context.cc b/src/xenia/ui/gl/gl_context.cc index cbddc7055..9dadea451 100644 --- a/src/xenia/ui/gl/gl_context.cc +++ b/src/xenia/ui/gl/gl_context.cc @@ -51,6 +51,14 @@ thread_local WGLEWContext* tls_wglew_context_ = nullptr; extern "C" GLEWContext* glewGetContext() { return tls_glew_context_; } extern "C" WGLEWContext* wglewGetContext() { return tls_wglew_context_; } +void FatalGLError(std::string error) { + xe::FatalError( + error + + "\nEnsure you have the latest drivers for your GPU and that it supports " + "OpenGL 4.5. See http://xenia.jp/faq/ for more information and a list" + "of supported GPUs."); +} + std::unique_ptr GLContext::Create(Window* target_window) { auto context = std::unique_ptr(new GLContext(target_window)); if (!context->Initialize(target_window)) { @@ -98,17 +106,17 @@ bool GLContext::Initialize(Window* target_window) { pfd.iLayerType = PFD_MAIN_PLANE; int pixel_format = ChoosePixelFormat(dc_, &pfd); if (!pixel_format) { - XELOGE("Unable to choose pixel format"); + FatalGLError("Unable to choose pixel format."); return false; } if (!SetPixelFormat(dc_, pixel_format, &pfd)) { - XELOGE("Unable to set pixel format"); + FatalGLError("Unable to set pixel format."); return false; } HGLRC temp_context = wglCreateContext(dc_); if (!temp_context) { - XELOGE("Unable to create temporary GL context"); + FatalGLError("Unable to create temporary GL context."); return false; } wglMakeCurrent(dc_, temp_context); @@ -116,16 +124,16 @@ bool GLContext::Initialize(Window* target_window) { tls_glew_context_ = glew_context_.get(); tls_wglew_context_ = wglew_context_.get(); if (glewInit() != GLEW_OK) { - XELOGE("Unable to initialize GLEW"); + FatalGLError("Unable to initialize GLEW."); return false; } if (wglewInit() != GLEW_OK) { - XELOGE("Unable to initialize WGLEW"); + FatalGLError("Unable to initialize WGLEW."); return false; } if (!WGLEW_ARB_create_context) { - XELOGE("WGL_ARG_create_context not supported by GL ICD"); + FatalGLError("WGL_ARG_create_context not supported by GL ICD."); return false; } @@ -148,12 +156,12 @@ bool GLContext::Initialize(Window* target_window) { wglMakeCurrent(nullptr, nullptr); wglDeleteContext(temp_context); if (!glrc_) { - XELOGE("Unable to create real GL context"); + FatalGLError("Unable to create real GL context."); return false; } if (!MakeCurrent()) { - XELOGE("Could not make real GL context current"); + FatalGLError("Could not make real GL context current."); return false; } @@ -171,7 +179,7 @@ bool GLContext::Initialize(Window* target_window) { SetupDebugging(); if (!blitter_.Initialize()) { - XELOGE("Unable to initialize blitter"); + FatalGLError("Unable to initialize blitter."); ClearCurrent(); return false; } @@ -204,7 +212,7 @@ std::unique_ptr GLContext::CreateShared() { 0}; new_glrc = wglCreateContextAttribsARB(dc_, glrc_, attrib_list); if (!new_glrc) { - XELOGE("Could not create shared context"); + FatalGLError("Could not create shared context."); return nullptr; } } @@ -212,30 +220,30 @@ std::unique_ptr GLContext::CreateShared() { auto new_context = std::unique_ptr(new GLContext(target_window_, new_glrc)); if (!new_context->MakeCurrent()) { - XELOGE("Could not make new GL context current"); + FatalGLError("Could not make new GL context current."); return nullptr; } if (!glGetString(GL_EXTENSIONS)) { new_context->ClearCurrent(); - XELOGE("New GL context did not have extensions"); + FatalGLError("New GL context did not have extensions."); return nullptr; } if (glewInit() != GLEW_OK) { new_context->ClearCurrent(); - XELOGE("Unable to initialize GLEW"); + FatalGLError("Unable to initialize GLEW on shared context."); return nullptr; } if (wglewInit() != GLEW_OK) { new_context->ClearCurrent(); - XELOGE("Unable to initialize WGLEW"); + FatalGLError("Unable to initialize WGLEW on shared context."); return nullptr; } SetupDebugging(); if (!new_context->blitter_.Initialize()) { - XELOGE("Unable to initialize blitter"); + FatalGLError("Unable to initialize blitter on shared context."); return nullptr; } @@ -244,18 +252,9 @@ std::unique_ptr GLContext::CreateShared() { return std::unique_ptr(new_context.release()); } -void FatalGLError(std::string error) { - XEFATAL( - (error + - "\nEnsure you have the latest drivers for your GPU and that it supports " - "OpenGL 4.5. See http://xenia.jp/faq/ for more information and a list" - "of supported GPUs.") - .c_str()); -} - void GLContext::AssertExtensionsPresent() { if (!MakeCurrent()) { - XEFATAL("Unable to make GL context current"); + FatalGLError("Unable to make GL context current."); return; } @@ -425,7 +424,7 @@ bool GLContext::MakeCurrent() { if (FLAGS_thread_safe_gl) { global_gl_mutex_.unlock(); } - XELOGE("Unable to make GL context current"); + FatalGLError("Unable to make GL context current."); return false; } tls_glew_context_ = glew_context_.get();