diff --git a/.travis.yml b/.travis.yml index bda8138c1..85e0678d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,47 +4,52 @@ #sudo: false language: cpp -compiler: - - clang - # - gcc - os: - linux # - osx -env: - - LINT=true - - BUILD=true CONFIG=Debug - - BUILD=true CONFIG=Release - matrix: + include: + - compiler: clang + env: C_COMPILER=clang-3.9 CXX_COMPILER=clang++-3.9 LINT=true + - compiler: clang + env: C_COMPILER=clang-3.9 CXX_COMPILER=clang++-3.9 BUILD=true CONFIG=Debug + - compiler: clang + env: C_COMPILER=clang-3.9 CXX_COMPILER=clang++-3.9 BUILD=true CONFIG=Release allow_failures: # LLVMGold.so is not installed correctly - - env: BUILD=true CONFIG=Release + - env: C_COMPILER=clang-3.9 CXX_COMPILER=clang++-3.9 BUILD=true CONFIG=Release -dist: trusty sudo: required addons: apt: sources: - # - ubuntu-toolchain-r-test - - llvm-toolchain-precise + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty packages: - - clang-3.8 - - clang-format-3.8 + - clang-3.9 + - clang-format-3.9 + #- g++-6 - libc++-dev - python3 + - libc++abi-dev + - libgtk-3-dev + - liblz4-dev git: # We handle submodules ourselves in xenia-build setup. submodules: false before_script: - - export CXX=clang++-3.8 - - export CC=clang-3.8 + - export CXX=$CXX_COMPILER + - export CC=$C_COMPILER # Dump useful info. - $CXX --version - python3 --version + # Add Vulkan dependencies + - travis_retry wget http://mirrors.kernel.org/ubuntu/pool/universe/v/vulkan/libvulkan1_1.0.42.0+dfsg1-1ubuntu1~16.04.1_amd64.deb + - travis_retry wget http://mirrors.kernel.org/ubuntu/pool/universe/v/vulkan/libvulkan-dev_1.0.42.0+dfsg1-1ubuntu1~16.04.1_amd64.deb + - sudo dpkg -i libvulkan1_1.0.42.0+dfsg1-1ubuntu1~16.04.1_amd64.deb libvulkan-dev_1.0.42.0+dfsg1-1ubuntu1~16.04.1_amd64.deb # Prepare environment (pull dependencies, build tools). - travis_retry ./xenia-build setup @@ -59,9 +64,8 @@ script: - if [[ $BUILD == true ]]; then ./xenia-build build --config=$CONFIG --target=xenia-cpu-ppc-tests; fi # - if [[ $BUILD == true ]]; then ./build/bin/Linux/$CONFIG/xenia-cpu-ppc-tests --log_file=stdout; fi - # TODO(DrChat): Enable builds in the future. # Build all of xenia. - #- ./xenia-build build --config=debug + #- if [[ $BUILD == true ]]; then ./xenia-build build --config=$CONFIG; fi # All tests (without haswell support). #- ./xenia-build test --config=debug --no-build -- --enable_haswell_instructions=false # All tests (with haswell support). diff --git a/docs/building.md b/docs/building.md index 3da01799b..842a53156 100644 --- a/docs/building.md +++ b/docs/building.md @@ -52,6 +52,14 @@ sudo -E apt-get -yq update &>> ~/apt-get-update.log sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install clang-3.8 clang-format-3.8 ``` +You will also need some development libraries. To get them on an ubuntu system: +``` +sudo apt-get install libgtk-3-dev libpthread-stubs0-dev liblz4-dev libglew-dev libx11-dev +``` + +In addition, you will need the latest OpenGL libraries and drivers for your hardware. Intel and the open source +drivers are not supported as they do not yet support OpenGL 4.5. + ## Running To make life easier you can use `--flagfile=myflags.txt` to specify all diff --git a/premake5.lua b/premake5.lua index 593f0503d..4d4b3779f 100644 --- a/premake5.lua +++ b/premake5.lua @@ -87,10 +87,30 @@ filter("platforms:Linux") toolset("clang") buildoptions({ -- "-mlzcnt", -- (don't) Assume lzcnt is supported. + "`pkg-config --cflags gtk+-x11-3.0`" }) links({ "pthread", + "dl", + "lz4", + "X11", + "xcb", + "X11-xcb", + "GL", + "GLEW", + "vulkan", + "c++", + "c++abi" }) + linkoptions({ + "`pkg-config --libs gtk+-3.0`", + }) + disablewarnings({ + "deprecated-register" + }) + +filter({"platforms:Linux", "kind:*App"}) + linkgroups("On") filter({"platforms:Linux", "language:C++", "toolset:gcc"}) buildoptions({ @@ -105,7 +125,6 @@ filter({"platforms:Linux", "language:C++", "toolset:clang"}) "-stdlib=libc++", }) links({ - "c++", }) filter("platforms:Windows") diff --git a/src/xenia/app/emulator_window.cc b/src/xenia/app/emulator_window.cc index cd80a30e8..bcb5381b4 100644 --- a/src/xenia/app/emulator_window.cc +++ b/src/xenia/app/emulator_window.cc @@ -28,11 +28,11 @@ namespace xe { namespace app { +using xe::ui::FileDropEvent; using xe::ui::KeyEvent; using xe::ui::MenuItem; using xe::ui::MouseEvent; using xe::ui::UIEvent; -using xe::ui::FileDropEvent; const std::wstring kBaseTitle = L"xenia"; diff --git a/src/xenia/app/premake5.lua b/src/xenia/app/premake5.lua index 26b30fc5b..5803ea4f9 100644 --- a/src/xenia/app/premake5.lua +++ b/src/xenia/app/premake5.lua @@ -8,8 +8,15 @@ project("xenia-app") targetname("xenia") language("C++") links({ + "capstone", "gflags", + "glslang-spirv", "imgui", + "libavcodec", + "libavutil", + "snappy", + "spirv-tools", + "vulkan-loader", "xenia-apu", "xenia-apu-nop", "xenia-base", @@ -21,11 +28,15 @@ project("xenia-app") "xenia-gpu-gl4", "xenia-gpu-null", "xenia-gpu-vulkan", + "xenia-hid", "xenia-hid-nop", "xenia-kernel", "xenia-ui", "xenia-ui-gl", + "xenia-ui-spirv", + "xenia-ui-vulkan", "xenia-vfs", + "xxhash", }) flags({ "WinMain", -- Use WinMain instead of main. @@ -40,9 +51,10 @@ project("xenia-app") "xenia_main.cc", "../base/main_"..platform_suffix..".cc", }) - files({ - "main_resources.rc", - }) + filter("platforms:Windows") + files({ + "main_resources.rc", + }) resincludedirs({ project_root, }) diff --git a/src/xenia/app/xenia_main.cc b/src/xenia/app/xenia_main.cc index b2cf33c9b..a8e136db3 100644 --- a/src/xenia/app/xenia_main.cc +++ b/src/xenia/app/xenia_main.cc @@ -149,21 +149,23 @@ int xenia_main(const std::vector& args) { // This will respond to debugging requests so we can open the debug UI. std::unique_ptr debug_window; if (FLAGS_debug) { - emulator->processor()->set_debug_listener_request_handler([&]( - xe::cpu::Processor* processor) { - if (debug_window) { - return debug_window.get(); - } - emulator_window->loop()->PostSynchronous([&]() { - debug_window = xe::debug::ui::DebugWindow::Create( - emulator.get(), emulator_window->loop()); - debug_window->window()->on_closed.AddListener([&](xe::ui::UIEvent* e) { - emulator->processor()->set_debug_listener(nullptr); - emulator_window->loop()->Post([&]() { debug_window.reset(); }); + emulator->processor()->set_debug_listener_request_handler( + [&](xe::cpu::Processor* processor) { + if (debug_window) { + return debug_window.get(); + } + emulator_window->loop()->PostSynchronous([&]() { + debug_window = xe::debug::ui::DebugWindow::Create( + emulator.get(), emulator_window->loop()); + debug_window->window()->on_closed.AddListener( + [&](xe::ui::UIEvent* e) { + emulator->processor()->set_debug_listener(nullptr); + emulator_window->loop()->Post( + [&]() { debug_window.reset(); }); + }); + }); + return debug_window.get(); }); - }); - return debug_window.get(); - }); } auto evt = xe::threading::Event::CreateAutoResetEvent(false); diff --git a/src/xenia/apu/xaudio2/xaudio2_audio_driver.cc b/src/xenia/apu/xaudio2/xaudio2_audio_driver.cc index 2bb4fb428..d6bc18023 100644 --- a/src/xenia/apu/xaudio2/xaudio2_audio_driver.cc +++ b/src/xenia/apu/xaudio2/xaudio2_audio_driver.cc @@ -53,9 +53,14 @@ XAudio2AudioDriver::XAudio2AudioDriver(Memory* memory, XAudio2AudioDriver::~XAudio2AudioDriver() = default; const DWORD ChannelMasks[] = { - 0, 0, SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY, 0, - 0, 0, SPEAKER_FRONT_LEFT | SPEAKER_FRONT_CENTER | SPEAKER_FRONT_RIGHT | - SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT, + 0, + 0, + SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY, + 0, + 0, + 0, + SPEAKER_FRONT_LEFT | SPEAKER_FRONT_CENTER | SPEAKER_FRONT_RIGHT | + SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT, 0, }; diff --git a/src/xenia/base/bit_field.h b/src/xenia/base/bit_field.h index a089775c9..034f43d9e 100644 --- a/src/xenia/base/bit_field.h +++ b/src/xenia/base/bit_field.h @@ -29,7 +29,8 @@ struct bf { // For enum values, we strip them down to an underlying type. typedef typename std::conditional::value, std::underlying_type, - std::identity>::type::type value_type; + std::remove_reference>::type::type + value_type; inline value_type mask() const { return (((value_type)~0) >> (8 * sizeof(value_type) - n_bits)) << position; } @@ -39,4 +40,4 @@ struct bf { } // namespace xe -#endif // XENIA_BASE_BIT_FIELD_H_ \ No newline at end of file +#endif // XENIA_BASE_BIT_FIELD_H_ diff --git a/src/xenia/base/exception_handler_linux.cc b/src/xenia/base/exception_handler_linux.cc new file mode 100644 index 000000000..bc656a15d --- /dev/null +++ b/src/xenia/base/exception_handler_linux.cc @@ -0,0 +1,35 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2015 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/base/exception_handler.h" + +#include "xenia/base/assert.h" +#include "xenia/base/math.h" +#include "xenia/base/platform_linux.h" + +namespace xe { + +// This can be as large as needed, but isn't often needed. +// As we will be sometimes firing many exceptions we want to avoid having to +// scan the table too much or invoke many custom handlers. +constexpr size_t kMaxHandlerCount = 8; + +// All custom handlers, left-aligned and null terminated. +// Executed in order. +std::pair handlers_[kMaxHandlerCount]; + +void ExceptionHandler::Install(Handler fn, void* data) { + // TODO(dougvj) stub +} + +void ExceptionHandler::Uninstall(Handler fn, void* data) { + // TODO(dougvj) stub +} + +} // namespace xe diff --git a/src/xenia/base/filesystem_posix.cc b/src/xenia/base/filesystem_posix.cc index b9125e319..a948717cc 100644 --- a/src/xenia/base/filesystem_posix.cc +++ b/src/xenia/base/filesystem_posix.cc @@ -12,6 +12,8 @@ #include "xenia/base/string.h" #include +#include +#include #include #include #include @@ -33,6 +35,124 @@ bool CreateFolder(const std::wstring& path) { return mkdir(xe::to_string(path).c_str(), 0774); } +static int removeCallback(const char* fpath, const struct stat* sb, + int typeflag, struct FTW* ftwbuf) { + int rv = remove(fpath); + return rv; +} + +bool DeleteFolder(const std::wstring& path) { + return nftw(xe::to_string(path).c_str(), removeCallback, 64, + FTW_DEPTH | FTW_PHYS) == 0 + ? true + : false; +} + +static uint64_t convertUnixtimeToWinFiletime(time_t unixtime) { + // Linux uses number of seconds since 1/1/1970, and Windows uses + // number of nanoseconds since 1/1/1601 + // so we convert linux time to nanoseconds and then add the number of + // nanoseconds from 1601 to 1970 + // see https://msdn.microsoft.com/en-us/library/ms724228 + uint64_t filetime = filetime = (unixtime * 10000000) + 116444736000000000; + return filetime; +} + +bool IsFolder(const std::wstring& path) { + struct stat st; + if (stat(xe::to_string(path).c_str(), &st) == 0) { + if (S_ISDIR(st.st_mode)) return true; + } + return false; +} + +bool CreateFile(const std::wstring& path) { + int file = creat(xe::to_string(path).c_str(), 0774); + if (file >= 0) { + close(file); + return true; + } + return false; +} + +bool DeleteFile(const std::wstring& path) { + return (xe::to_string(path).c_str()) == 0 ? true : false; +} + +class PosixFileHandle : public FileHandle { + public: + PosixFileHandle(std::wstring path, int handle) + : FileHandle(std::move(path)), handle_(handle) {} + ~PosixFileHandle() override { + close(handle_); + handle_ = -1; + } + bool Read(size_t file_offset, void* buffer, size_t buffer_length, + size_t* out_bytes_read) override { + ssize_t out = pread(handle_, buffer, buffer_length, file_offset); + *out_bytes_read = out; + return out >= 0 ? true : false; + } + bool Write(size_t file_offset, const void* buffer, size_t buffer_length, + size_t* out_bytes_written) override { + ssize_t out = pwrite(handle_, buffer, buffer_length, file_offset); + *out_bytes_written = out; + return out >= 0 ? true : false; + } + void Flush() override { fsync(handle_); } + + private: + int handle_ = -1; +}; + +std::unique_ptr FileHandle::OpenExisting(std::wstring path, + uint32_t desired_access) { + int open_access; + if (desired_access & FileAccess::kGenericRead) { + open_access |= O_RDONLY; + } + if (desired_access & FileAccess::kGenericWrite) { + open_access |= O_WRONLY; + } + if (desired_access & FileAccess::kGenericExecute) { + open_access |= O_RDONLY; + } + if (desired_access & FileAccess::kGenericAll) { + open_access |= O_RDWR; + } + if (desired_access & FileAccess::kFileReadData) { + open_access |= O_RDONLY; + } + if (desired_access & FileAccess::kFileWriteData) { + open_access |= O_WRONLY; + } + if (desired_access & FileAccess::kFileAppendData) { + open_access |= O_APPEND; + } + int handle = open(xe::to_string(path).c_str(), open_access); + if (handle == -1) { + // TODO(benvanik): pick correct response. + return nullptr; + } + return std::make_unique(path, handle); +} + +bool GetInfo(const std::wstring& path, FileInfo* out_info) { + struct stat st; + if (stat(xe::to_string(path).c_str(), &st) == 0) { + if (S_ISDIR(st.st_mode)) { + out_info->type = FileInfo::Type::kDirectory; + } else { + out_info->type = FileInfo::Type::kFile; + } + out_info->create_timestamp = convertUnixtimeToWinFiletime(st.st_ctime); + out_info->access_timestamp = convertUnixtimeToWinFiletime(st.st_atime); + out_info->write_timestamp = convertUnixtimeToWinFiletime(st.st_mtime); + return true; + } + return false; +} + std::vector ListFiles(const std::wstring& path) { std::vector result; @@ -43,18 +163,20 @@ std::vector ListFiles(const std::wstring& path) { while (auto ent = readdir(dir)) { FileInfo info; + + info.name = xe::to_wstring(ent->d_name); + struct stat st; + stat((xe::to_string(path) + xe::to_string(info.name)).c_str(), &st); + info.create_timestamp = convertUnixtimeToWinFiletime(st.st_ctime); + info.access_timestamp = convertUnixtimeToWinFiletime(st.st_atime); + info.write_timestamp = convertUnixtimeToWinFiletime(st.st_mtime); if (ent->d_type == DT_DIR) { info.type = FileInfo::Type::kDirectory; info.total_size = 0; } else { info.type = FileInfo::Type::kFile; - info.total_size = 0; // TODO(DrChat): Find a way to get this + info.total_size = st.st_size; } - - info.create_timestamp = 0; - info.access_timestamp = 0; - info.write_timestamp = 0; - info.name = xe::to_wstring(ent->d_name); result.push_back(info); } @@ -62,4 +184,4 @@ std::vector ListFiles(const std::wstring& path) { } } // namespace filesystem -} // namespace xe \ No newline at end of file +} // namespace xe diff --git a/src/xenia/base/math.h b/src/xenia/base/math.h index 539a98b3c..d2c58ee3a 100644 --- a/src/xenia/base/math.h +++ b/src/xenia/base/math.h @@ -11,10 +11,10 @@ #define XENIA_BASE_MATH_H_ #include +#include #include #include #include - #include "xenia/base/platform.h" #if XE_ARCH_AMD64 diff --git a/src/xenia/base/platform_linux.cc b/src/xenia/base/platform_linux.cc new file mode 100644 index 000000000..b90c6f78e --- /dev/null +++ b/src/xenia/base/platform_linux.cc @@ -0,0 +1,21 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2015 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/base/platform_linux.h" +#include +#include + +namespace xe { + +void LaunchBrowser(const char* url) { + auto cmd = std::string("xdg-open " + std::string(url)); + system(cmd.c_str()); +} + +} // namespace xe diff --git a/src/xenia/base/platform_linux.h b/src/xenia/base/platform_linux.h new file mode 100644 index 000000000..345be94ab --- /dev/null +++ b/src/xenia/base/platform_linux.h @@ -0,0 +1,32 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2015 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_BASE_PLATFORM_X11_H_ +#define XENIA_BASE_PLATFORM_X11_H_ + +// NOTE: if you're including this file it means you are explicitly depending +// on Linux headers. Including this file outside of linux platform specific +// source code will break portability + +#include "xenia/base/platform.h" + +// Xlib/Xcb is used only for GLX/Vulkan interaction, the window management +// and input events are done with gtk/gdk +#include +#include +#include +#include +#include + +// Used for window management. Gtk is for GUI and wigets, gdk is for lower +// level events like key presses, mouse events, window handles, etc +#include +#include + +#endif // XENIA_BASE_PLATFORM_X11_H_ diff --git a/src/xenia/base/profiling.cc b/src/xenia/base/profiling.cc index 69d4e090e..da069b6f5 100644 --- a/src/xenia/base/profiling.cc +++ b/src/xenia/base/profiling.cc @@ -268,6 +268,7 @@ void Profiler::ToggleDisplay() {} void Profiler::TogglePause() {} void Profiler::set_window(ui::Window* window) {} void Profiler::Present() {} +void Profiler::Flip() {} #endif // XE_OPTION_PROFILING diff --git a/src/xenia/base/socket_win.cc b/src/xenia/base/socket_win.cc index 5d9789fa8..d3e4406ca 100644 --- a/src/xenia/base/socket_win.cc +++ b/src/xenia/base/socket_win.cc @@ -259,29 +259,26 @@ class Win32SocketServer : public SocketServer { return false; } - accept_thread_ = xe::threading::Thread::Create( - {}, - [this, port]() { - xe::threading::set_name(std::string("xe::SocketServer localhost:") + - std::to_string(port)); - while (socket_ != INVALID_SOCKET) { - sockaddr_in6 client_addr; - int client_count = sizeof(client_addr); - SOCKET client_socket = - accept(socket_, reinterpret_cast(&client_addr), - &client_count); - if (client_socket == INVALID_SOCKET) { - continue; - } + accept_thread_ = xe::threading::Thread::Create({}, [this, port]() { + xe::threading::set_name(std::string("xe::SocketServer localhost:") + + std::to_string(port)); + while (socket_ != INVALID_SOCKET) { + sockaddr_in6 client_addr; + int client_count = sizeof(client_addr); + SOCKET client_socket = accept( + socket_, reinterpret_cast(&client_addr), &client_count); + if (client_socket == INVALID_SOCKET) { + continue; + } - auto client = std::make_unique(); - if (!client->Accept(client_socket)) { - XELOGE("Unable to accept socket; ignoring"); - continue; - } - accept_callback_(std::move(client)); - } - }); + auto client = std::make_unique(); + if (!client->Accept(client_socket)) { + XELOGE("Unable to accept socket; ignoring"); + continue; + } + accept_callback_(std::move(client)); + } + }); return true; } diff --git a/src/xenia/base/threading.h b/src/xenia/base/threading.h index 62fb5e815..480b76207 100644 --- a/src/xenia/base/threading.h +++ b/src/xenia/base/threading.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/src/xenia/base/threading_linux.cc b/src/xenia/base/threading_linux.cc index 6f4a97584..3535f3011 100644 --- a/src/xenia/base/threading_linux.cc +++ b/src/xenia/base/threading_linux.cc @@ -13,9 +13,5 @@ #include namespace xe { -namespace threading { - -void MaybeYield() { pthread_yield(); } - -} // namespace threading +namespace threading {} // namespace threading } // namespace xe diff --git a/src/xenia/base/threading_posix.cc b/src/xenia/base/threading_posix.cc index 3089f11b8..7570a824a 100644 --- a/src/xenia/base/threading_posix.cc +++ b/src/xenia/base/threading_posix.cc @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -21,6 +22,9 @@ namespace xe { namespace threading { +// TODO(dougvj) +void EnableAffinityConfiguration() {} + // uint64_t ticks() { return mach_absolute_time(); } uint32_t current_thread_system_id() { @@ -32,9 +36,16 @@ void set_name(const std::string& name) { } void set_name(std::thread::native_handle_type handle, const std::string& name) { - pthread_setname_np(pthread_self(), name.c_str()); + pthread_setname_np(handle, name.c_str()); } +void MaybeYield() { + pthread_yield(); + __sync_synchronize(); +} + +void SyncMemory() { __sync_synchronize(); } + void Sleep(std::chrono::microseconds duration) { timespec rqtp = {time_t(duration.count() / 1000000), time_t(duration.count() % 1000)}; @@ -42,11 +53,133 @@ void Sleep(std::chrono::microseconds duration) { // TODO(benvanik): spin while rmtp >0? } -template -class PosixHandle : public T { +// TODO(dougvj) Not sure how to implement the equivalent of this on POSIX. +SleepResult AlertableSleep(std::chrono::microseconds duration) { + sleep(duration.count() / 1000); + return SleepResult::kSuccess; +} + +// TODO(dougvj) We can probably wrap this with pthread_key_t but the type of +// TlsHandle probably needs to be refactored +TlsHandle AllocateTlsHandle() { + assert_always(); + return 0; +} + +bool FreeTlsHandle(TlsHandle handle) { return true; } + +uintptr_t GetTlsValue(TlsHandle handle) { + assert_always(); + return 0; +} + +bool SetTlsValue(TlsHandle handle, uintptr_t value) { + assert_always(); + return false; +} + +// TODO(dougvj) +class PosixHighResolutionTimer : public HighResolutionTimer { public: - explicit PosixHandle(pthread_t handle) : handle_(handle) {} - ~PosixHandle() override {} + PosixHighResolutionTimer(std::function callback) + : callback_(callback) {} + ~PosixHighResolutionTimer() override {} + + bool Initialize(std::chrono::milliseconds period) { + assert_always(); + return false; + } + + private: + std::function callback_; +}; + +std::unique_ptr HighResolutionTimer::CreateRepeating( + std::chrono::milliseconds period, std::function callback) { + auto timer = std::make_unique(std::move(callback)); + if (!timer->Initialize(period)) { + return nullptr; + } + return std::unique_ptr(timer.release()); +} + +// TODO(dougvj) There really is no native POSIX handle for a single wait/signal +// construct pthreads is at a lower level with more handles for such a mechanism +// This simple wrapper class could function as our handle, but probably needs +// some more functionality +class PosixCondition { + public: + PosixCondition() : signal_(false) { + pthread_mutex_init(&mutex_, NULL); + pthread_cond_init(&cond_, NULL); + } + + ~PosixCondition() { + pthread_mutex_destroy(&mutex_); + pthread_cond_destroy(&cond_); + } + + void Signal() { + pthread_mutex_lock(&mutex_); + signal_ = true; + pthread_cond_broadcast(&cond_); + pthread_mutex_unlock(&mutex_); + } + + void Reset() { + pthread_mutex_lock(&mutex_); + signal_ = false; + pthread_mutex_unlock(&mutex_); + } + + bool Wait(unsigned int timeout_ms) { + // Assume 0 means no timeout, not instant timeout + if (timeout_ms == 0) { + Wait(); + } + struct timespec time_to_wait; + struct timeval now; + gettimeofday(&now, NULL); + + // Add the number of seconds we want to wait to the current time + time_to_wait.tv_sec = now.tv_sec + (timeout_ms / 1000); + // Add the number of nanoseconds we want to wait to the current nanosecond + // stride + long nsec = (now.tv_usec + (timeout_ms % 1000)) * 1000; + // If we overflowed the nanosecond count then we add a second + time_to_wait.tv_sec += nsec / 1000000000UL; + // We only add nanoseconds within the 1 second stride + time_to_wait.tv_nsec = nsec % 1000000000UL; + pthread_mutex_lock(&mutex_); + while (!signal_) { + int status = pthread_cond_timedwait(&cond_, &mutex_, &time_to_wait); + if (status == ETIMEDOUT) return false; // We timed out + } + pthread_mutex_unlock(&mutex_); + return true; // We didn't time out + } + + bool Wait() { + pthread_mutex_lock(&mutex_); + while (!signal_) { + pthread_cond_wait(&cond_, &mutex_); + } + pthread_mutex_unlock(&mutex_); + return true; // Did not time out; + } + + private: + bool signal_; + pthread_cond_t cond_; + pthread_mutex_t mutex_; +}; + +// Native posix thread handle +template +class PosixThreadHandle : public T { + public: + explicit PosixThreadHandle(pthread_t handle) : handle_(handle) {} + ~PosixThreadHandle() override {} protected: void* native_handle() const override { @@ -56,13 +189,134 @@ class PosixHandle : public T { pthread_t handle_; }; -class PosixThread : public PosixHandle { +// This is wraps a condition object as our handle because posix has no single +// native handle for higher level concurrency constructs such as semaphores +template +class PosixConditionHandle : public T { public: - explicit PosixThread(pthread_t handle) : PosixHandle(handle) {} + ~PosixConditionHandle() override {} + + protected: + void* native_handle() const override { + return reinterpret_cast(const_cast(&handle_)); + } + + PosixCondition handle_; +}; + +// TODO(dougvj) +WaitResult Wait(WaitHandle* wait_handle, bool is_alertable, + std::chrono::milliseconds timeout) { + assert_always(); + return WaitResult::kFailed; +} + +// TODO(dougvj) +WaitResult SignalAndWait(WaitHandle* wait_handle_to_signal, + WaitHandle* wait_handle_to_wait_on, bool is_alertable, + std::chrono::milliseconds timeout) { + assert_always(); + return WaitResult::kFailed; +} + +// TODO(dougvj) +std::pair WaitMultiple(WaitHandle* wait_handles[], + size_t wait_handle_count, + bool wait_all, bool is_alertable, + std::chrono::milliseconds timeout) { + assert_always(); + return std::pair(WaitResult::kFailed, 0); +} + +// TODO(dougvj) +class PosixEvent : public PosixConditionHandle { + public: + PosixEvent(bool initial_state, int auto_reset) { assert_always(); } + ~PosixEvent() override = default; + void Set() override { assert_always(); } + void Reset() override { assert_always(); } + void Pulse() override { assert_always(); } + + private: + PosixCondition condition_; +}; + +std::unique_ptr Event::CreateManualResetEvent(bool initial_state) { + return std::make_unique(PosixEvent(initial_state, false)); +} + +std::unique_ptr Event::CreateAutoResetEvent(bool initial_state) { + return std::make_unique(PosixEvent(initial_state, true)); +} + +// TODO(dougvj) +class PosixSemaphore : public PosixConditionHandle { + public: + PosixSemaphore(int initial_count, int maximum_count) { assert_always(); } + ~PosixSemaphore() override = default; + bool Release(int release_count, int* out_previous_count) override { + assert_always(); + return false; + } +}; + +std::unique_ptr Semaphore::Create(int initial_count, + int maximum_count) { + return std::make_unique(initial_count, maximum_count); +} + +// TODO(dougvj) +class PosixMutant : public PosixConditionHandle { + public: + PosixMutant(bool initial_owner) { assert_always(); } + ~PosixMutant() = default; + bool Release() override { + assert_always(); + return false; + } +}; + +std::unique_ptr Mutant::Create(bool initial_owner) { + return std::make_unique(initial_owner); +} + +// TODO(dougvj) +class PosixTimer : public PosixConditionHandle { + public: + PosixTimer(bool manual_reset) { assert_always(); } + ~PosixTimer() = default; + bool SetOnce(std::chrono::nanoseconds due_time, + std::function opt_callback) override { + assert_always(); + return false; + } + bool SetRepeating(std::chrono::nanoseconds due_time, + std::chrono::milliseconds period, + std::function opt_callback) override { + assert_always(); + return false; + } + bool Cancel() override { + assert_always(); + return false; + } +}; + +std::unique_ptr Timer::CreateManualResetTimer() { + return std::make_unique(true); +} + +std::unique_ptr Timer::CreateSynchronizationTimer() { + return std::make_unique(false); +} + +class PosixThread : public PosixThreadHandle { + public: + explicit PosixThread(pthread_t handle) : PosixThreadHandle(handle) {} ~PosixThread() = default; void set_name(std::string name) override { - // TODO(DrChat) + pthread_setname_np(handle_, name.c_str()); } uint32_t system_id() const override { return 0; } @@ -141,5 +395,20 @@ std::unique_ptr Thread::Create(CreationParameters params, return std::unique_ptr(new PosixThread(handle)); } +Thread* Thread::GetCurrentThread() { + if (current_thread_) { + return current_thread_.get(); + } + + pthread_t handle = pthread_self(); + + current_thread_ = std::make_unique(handle); + return current_thread_.get(); +} + +void Thread::Exit(int exit_code) { + pthread_exit(reinterpret_cast(exit_code)); +} + } // namespace threading } // namespace xe diff --git a/src/xenia/cpu/backend/x64/x64_code_cache_win.cc b/src/xenia/cpu/backend/x64/x64_code_cache_win.cc index 068bfa661..1c6eecee0 100644 --- a/src/xenia/cpu/backend/x64/x64_code_cache_win.cc +++ b/src/xenia/cpu/backend/x64/x64_code_cache_win.cc @@ -202,11 +202,11 @@ typedef struct _UNWIND_INFO { uint8_t FrameOffset : 4; UNWIND_CODE UnwindCode[1]; /* UNWIND_CODE MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1]; - * union { - * OPTIONAL ULONG ExceptionHandler; - * OPTIONAL ULONG FunctionEntry; - * }; - * OPTIONAL ULONG ExceptionData[]; */ + * union { + * OPTIONAL ULONG ExceptionHandler; + * OPTIONAL ULONG FunctionEntry; + * }; + * OPTIONAL ULONG ExceptionData[]; */ } UNWIND_INFO, *PUNWIND_INFO; void Win32X64CodeCache::InitializeUnwindEntry(uint8_t* unwind_entry_address, diff --git a/src/xenia/cpu/backend/x64/x64_emitter.cc b/src/xenia/cpu/backend/x64/x64_emitter.cc index 38c811b47..1a7f9f78e 100644 --- a/src/xenia/cpu/backend/x64/x64_emitter.cc +++ b/src/xenia/cpu/backend/x64/x64_emitter.cc @@ -600,78 +600,78 @@ static const vec128_t xmm_consts[] = { /* XMMZero */ vec128f(0.0f), /* XMMOne */ vec128f(1.0f), /* XMMNegativeOne */ vec128f(-1.0f, -1.0f, -1.0f, -1.0f), - /* XMMFFFF */ vec128i(0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, - 0xFFFFFFFFu), - /* XMMMaskX16Y16 */ vec128i(0x0000FFFFu, 0xFFFF0000u, 0x00000000u, - 0x00000000u), - /* XMMFlipX16Y16 */ vec128i(0x00008000u, 0x00000000u, 0x00000000u, - 0x00000000u), + /* XMMFFFF */ + vec128i(0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu), + /* XMMMaskX16Y16 */ + vec128i(0x0000FFFFu, 0xFFFF0000u, 0x00000000u, 0x00000000u), + /* XMMFlipX16Y16 */ + vec128i(0x00008000u, 0x00000000u, 0x00000000u, 0x00000000u), /* XMMFixX16Y16 */ vec128f(-32768.0f, 0.0f, 0.0f, 0.0f), - /* XMMNormalizeX16Y16 */ vec128f( - 1.0f / 32767.0f, 1.0f / (32767.0f * 65536.0f), 0.0f, 0.0f), + /* XMMNormalizeX16Y16 */ + vec128f(1.0f / 32767.0f, 1.0f / (32767.0f * 65536.0f), 0.0f, 0.0f), /* XMM0001 */ vec128f(0.0f, 0.0f, 0.0f, 1.0f), /* XMM3301 */ vec128f(3.0f, 3.0f, 0.0f, 1.0f), /* XMM3333 */ vec128f(3.0f, 3.0f, 3.0f, 3.0f), - /* XMMSignMaskPS */ vec128i(0x80000000u, 0x80000000u, 0x80000000u, - 0x80000000u), - /* XMMSignMaskPD */ vec128i(0x00000000u, 0x80000000u, 0x00000000u, - 0x80000000u), - /* XMMAbsMaskPS */ vec128i(0x7FFFFFFFu, 0x7FFFFFFFu, 0x7FFFFFFFu, - 0x7FFFFFFFu), - /* XMMAbsMaskPD */ vec128i(0xFFFFFFFFu, 0x7FFFFFFFu, 0xFFFFFFFFu, - 0x7FFFFFFFu), - /* XMMByteSwapMask */ vec128i(0x00010203u, 0x04050607u, 0x08090A0Bu, - 0x0C0D0E0Fu), - /* XMMByteOrderMask */ vec128i(0x01000302u, 0x05040706u, 0x09080B0Au, - 0x0D0C0F0Eu), + /* XMMSignMaskPS */ + vec128i(0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u), + /* XMMSignMaskPD */ + vec128i(0x00000000u, 0x80000000u, 0x00000000u, 0x80000000u), + /* XMMAbsMaskPS */ + vec128i(0x7FFFFFFFu, 0x7FFFFFFFu, 0x7FFFFFFFu, 0x7FFFFFFFu), + /* XMMAbsMaskPD */ + vec128i(0xFFFFFFFFu, 0x7FFFFFFFu, 0xFFFFFFFFu, 0x7FFFFFFFu), + /* XMMByteSwapMask */ + vec128i(0x00010203u, 0x04050607u, 0x08090A0Bu, 0x0C0D0E0Fu), + /* XMMByteOrderMask */ + vec128i(0x01000302u, 0x05040706u, 0x09080B0Au, 0x0D0C0F0Eu), /* XMMPermuteControl15 */ vec128b(15), /* XMMPermuteByteMask */ vec128b(0x1F), /* XMMPackD3DCOLORSat */ vec128i(0x404000FFu), - /* XMMPackD3DCOLOR */ vec128i(0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, - 0x0C000408u), - /* XMMUnpackD3DCOLOR */ vec128i(0xFFFFFF0Eu, 0xFFFFFF0Du, 0xFFFFFF0Cu, - 0xFFFFFF0Fu), - /* XMMPackFLOAT16_2 */ vec128i(0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, - 0x01000302u), - /* XMMUnpackFLOAT16_2 */ vec128i(0x0D0C0F0Eu, 0xFFFFFFFFu, 0xFFFFFFFFu, - 0xFFFFFFFFu), - /* XMMPackFLOAT16_4 */ vec128i(0xFFFFFFFFu, 0xFFFFFFFFu, 0x05040706u, - 0x01000302u), - /* XMMUnpackFLOAT16_4 */ vec128i(0x09080B0Au, 0x0D0C0F0Eu, 0xFFFFFFFFu, - 0xFFFFFFFFu), + /* XMMPackD3DCOLOR */ + vec128i(0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0x0C000408u), + /* XMMUnpackD3DCOLOR */ + vec128i(0xFFFFFF0Eu, 0xFFFFFF0Du, 0xFFFFFF0Cu, 0xFFFFFF0Fu), + /* XMMPackFLOAT16_2 */ + vec128i(0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0x01000302u), + /* XMMUnpackFLOAT16_2 */ + vec128i(0x0D0C0F0Eu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu), + /* XMMPackFLOAT16_4 */ + vec128i(0xFFFFFFFFu, 0xFFFFFFFFu, 0x05040706u, 0x01000302u), + /* XMMUnpackFLOAT16_4 */ + vec128i(0x09080B0Au, 0x0D0C0F0Eu, 0xFFFFFFFFu, 0xFFFFFFFFu), /* XMMPackSHORT_Min */ vec128i(0x403F8001u), /* XMMPackSHORT_Max */ vec128i(0x40407FFFu), - /* XMMPackSHORT_2 */ vec128i(0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, - 0x01000504u), - /* XMMPackSHORT_4 */ vec128i(0xFFFFFFFFu, 0xFFFFFFFFu, 0x01000504u, - 0x09080D0Cu), - /* XMMUnpackSHORT_2 */ vec128i(0xFFFF0F0Eu, 0xFFFF0D0Cu, 0xFFFFFFFFu, - 0xFFFFFFFFu), - /* XMMUnpackSHORT_4 */ vec128i(0xFFFF0B0Au, 0xFFFF0908u, 0xFFFF0F0Eu, - 0xFFFF0D0Cu), + /* XMMPackSHORT_2 */ + vec128i(0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0x01000504u), + /* XMMPackSHORT_4 */ + vec128i(0xFFFFFFFFu, 0xFFFFFFFFu, 0x01000504u, 0x09080D0Cu), + /* XMMUnpackSHORT_2 */ + vec128i(0xFFFF0F0Eu, 0xFFFF0D0Cu, 0xFFFFFFFFu, 0xFFFFFFFFu), + /* XMMUnpackSHORT_4 */ + vec128i(0xFFFF0B0Au, 0xFFFF0908u, 0xFFFF0F0Eu, 0xFFFF0D0Cu), /* XMMOneOver255 */ vec128f(1.0f / 255.0f), - /* XMMMaskEvenPI16 */ vec128i(0x0000FFFFu, 0x0000FFFFu, 0x0000FFFFu, - 0x0000FFFFu), - /* XMMShiftMaskEvenPI16 */ vec128i(0x0000000Fu, 0x0000000Fu, 0x0000000Fu, - 0x0000000Fu), - /* XMMShiftMaskPS */ vec128i(0x0000001Fu, 0x0000001Fu, 0x0000001Fu, - 0x0000001Fu), - /* XMMShiftByteMask */ vec128i(0x000000FFu, 0x000000FFu, 0x000000FFu, - 0x000000FFu), - /* XMMSwapWordMask */ vec128i(0x03030303u, 0x03030303u, 0x03030303u, - 0x03030303u), - /* XMMUnsignedDwordMax */ vec128i(0xFFFFFFFFu, 0x00000000u, 0xFFFFFFFFu, - 0x00000000u), + /* XMMMaskEvenPI16 */ + vec128i(0x0000FFFFu, 0x0000FFFFu, 0x0000FFFFu, 0x0000FFFFu), + /* XMMShiftMaskEvenPI16 */ + vec128i(0x0000000Fu, 0x0000000Fu, 0x0000000Fu, 0x0000000Fu), + /* XMMShiftMaskPS */ + vec128i(0x0000001Fu, 0x0000001Fu, 0x0000001Fu, 0x0000001Fu), + /* XMMShiftByteMask */ + vec128i(0x000000FFu, 0x000000FFu, 0x000000FFu, 0x000000FFu), + /* XMMSwapWordMask */ + vec128i(0x03030303u, 0x03030303u, 0x03030303u, 0x03030303u), + /* XMMUnsignedDwordMax */ + vec128i(0xFFFFFFFFu, 0x00000000u, 0xFFFFFFFFu, 0x00000000u), /* XMM255 */ vec128f(255.0f), /* XMMPI32 */ vec128i(32), - /* XMMSignMaskI8 */ vec128i(0x80808080u, 0x80808080u, 0x80808080u, - 0x80808080u), - /* XMMSignMaskI16 */ vec128i(0x80008000u, 0x80008000u, 0x80008000u, - 0x80008000u), - /* XMMSignMaskI32 */ vec128i(0x80000000u, 0x80000000u, 0x80000000u, - 0x80000000u), - /* XMMSignMaskF32 */ vec128i(0x80000000u, 0x80000000u, 0x80000000u, - 0x80000000u), + /* XMMSignMaskI8 */ + vec128i(0x80808080u, 0x80808080u, 0x80808080u, 0x80808080u), + /* XMMSignMaskI16 */ + vec128i(0x80008000u, 0x80008000u, 0x80008000u, 0x80008000u), + /* XMMSignMaskI32 */ + vec128i(0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u), + /* XMMSignMaskF32 */ + vec128i(0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u), /* XMMShortMinPS */ vec128f(SHRT_MIN), /* XMMShortMaxPS */ vec128f(SHRT_MAX), /* XMMIntMin */ vec128i(INT_MIN), diff --git a/src/xenia/cpu/backend/x64/x64_sequences.cc b/src/xenia/cpu/backend/x64/x64_sequences.cc index 09539d377..ec27b16da 100644 --- a/src/xenia/cpu/backend/x64/x64_sequences.cc +++ b/src/xenia/cpu/backend/x64/x64_sequences.cc @@ -2988,8 +2988,9 @@ EMITTER_OPCODE_TABLE(OPCODE_IS_NAN, IS_NAN_F32, IS_NAN_F64); struct COMPARE_EQ_I8 : Sequence> { static void Emit(X64Emitter& e, const EmitArgType& i) { - EmitCommutativeCompareOp(e, i, [](X64Emitter& e, const Reg8& src1, - const Reg8& src2) { e.cmp(src1, src2); }, + EmitCommutativeCompareOp(e, i, + [](X64Emitter& e, const Reg8& src1, + const Reg8& src2) { e.cmp(src1, src2); }, [](X64Emitter& e, const Reg8& src1, int32_t constant) { e.cmp(src1, constant); }); e.sete(i.dest); @@ -2998,8 +2999,9 @@ struct COMPARE_EQ_I8 struct COMPARE_EQ_I16 : Sequence> { static void Emit(X64Emitter& e, const EmitArgType& i) { - EmitCommutativeCompareOp(e, i, [](X64Emitter& e, const Reg16& src1, - const Reg16& src2) { e.cmp(src1, src2); }, + EmitCommutativeCompareOp(e, i, + [](X64Emitter& e, const Reg16& src1, + const Reg16& src2) { e.cmp(src1, src2); }, [](X64Emitter& e, const Reg16& src1, int32_t constant) { e.cmp(src1, constant); }); e.sete(i.dest); @@ -3008,8 +3010,9 @@ struct COMPARE_EQ_I16 struct COMPARE_EQ_I32 : Sequence> { static void Emit(X64Emitter& e, const EmitArgType& i) { - EmitCommutativeCompareOp(e, i, [](X64Emitter& e, const Reg32& src1, - const Reg32& src2) { e.cmp(src1, src2); }, + EmitCommutativeCompareOp(e, i, + [](X64Emitter& e, const Reg32& src1, + const Reg32& src2) { e.cmp(src1, src2); }, [](X64Emitter& e, const Reg32& src1, int32_t constant) { e.cmp(src1, constant); }); e.sete(i.dest); @@ -3018,8 +3021,9 @@ struct COMPARE_EQ_I32 struct COMPARE_EQ_I64 : Sequence> { static void Emit(X64Emitter& e, const EmitArgType& i) { - EmitCommutativeCompareOp(e, i, [](X64Emitter& e, const Reg64& src1, - const Reg64& src2) { e.cmp(src1, src2); }, + EmitCommutativeCompareOp(e, i, + [](X64Emitter& e, const Reg64& src1, + const Reg64& src2) { e.cmp(src1, src2); }, [](X64Emitter& e, const Reg64& src1, int32_t constant) { e.cmp(src1, constant); }); e.sete(i.dest); @@ -3055,8 +3059,9 @@ EMITTER_OPCODE_TABLE(OPCODE_COMPARE_EQ, COMPARE_EQ_I8, COMPARE_EQ_I16, struct COMPARE_NE_I8 : Sequence> { static void Emit(X64Emitter& e, const EmitArgType& i) { - EmitCommutativeCompareOp(e, i, [](X64Emitter& e, const Reg8& src1, - const Reg8& src2) { e.cmp(src1, src2); }, + EmitCommutativeCompareOp(e, i, + [](X64Emitter& e, const Reg8& src1, + const Reg8& src2) { e.cmp(src1, src2); }, [](X64Emitter& e, const Reg8& src1, int32_t constant) { e.cmp(src1, constant); }); e.setne(i.dest); @@ -3065,8 +3070,9 @@ struct COMPARE_NE_I8 struct COMPARE_NE_I16 : Sequence> { static void Emit(X64Emitter& e, const EmitArgType& i) { - EmitCommutativeCompareOp(e, i, [](X64Emitter& e, const Reg16& src1, - const Reg16& src2) { e.cmp(src1, src2); }, + EmitCommutativeCompareOp(e, i, + [](X64Emitter& e, const Reg16& src1, + const Reg16& src2) { e.cmp(src1, src2); }, [](X64Emitter& e, const Reg16& src1, int32_t constant) { e.cmp(src1, constant); }); e.setne(i.dest); @@ -3075,8 +3081,9 @@ struct COMPARE_NE_I16 struct COMPARE_NE_I32 : Sequence> { static void Emit(X64Emitter& e, const EmitArgType& i) { - EmitCommutativeCompareOp(e, i, [](X64Emitter& e, const Reg32& src1, - const Reg32& src2) { e.cmp(src1, src2); }, + EmitCommutativeCompareOp(e, i, + [](X64Emitter& e, const Reg32& src1, + const Reg32& src2) { e.cmp(src1, src2); }, [](X64Emitter& e, const Reg32& src1, int32_t constant) { e.cmp(src1, constant); }); e.setne(i.dest); @@ -3085,8 +3092,9 @@ struct COMPARE_NE_I32 struct COMPARE_NE_I64 : Sequence> { static void Emit(X64Emitter& e, const EmitArgType& i) { - EmitCommutativeCompareOp(e, i, [](X64Emitter& e, const Reg64& src1, - const Reg64& src2) { e.cmp(src1, src2); }, + EmitCommutativeCompareOp(e, i, + [](X64Emitter& e, const Reg64& src1, + const Reg64& src2) { e.cmp(src1, src2); }, [](X64Emitter& e, const Reg64& src1, int32_t constant) { e.cmp(src1, constant); }); e.setne(i.dest); @@ -3421,8 +3429,10 @@ EMITTER_OPCODE_TABLE(OPCODE_VECTOR_COMPARE_UGE, VECTOR_COMPARE_UGE_V128); template void EmitAddXX(X64Emitter& e, const ARGS& i) { SEQ::EmitCommutativeBinaryOp( - e, i, [](X64Emitter& e, const REG& dest_src, - const REG& src) { e.add(dest_src, src); }, + e, i, + [](X64Emitter& e, const REG& dest_src, const REG& src) { + e.add(dest_src, src); + }, [](X64Emitter& e, const REG& dest_src, int32_t constant) { e.add(dest_src, constant); }); @@ -3491,8 +3501,10 @@ void EmitAddCarryXX(X64Emitter& e, const ARGS& i) { e.sahf(); } SEQ::EmitCommutativeBinaryOp( - e, i, [](X64Emitter& e, const REG& dest_src, - const REG& src) { e.adc(dest_src, src); }, + e, i, + [](X64Emitter& e, const REG& dest_src, const REG& src) { + e.adc(dest_src, src); + }, [](X64Emitter& e, const REG& dest_src, int32_t constant) { e.adc(dest_src, constant); }); @@ -3530,105 +3542,110 @@ EMITTER_OPCODE_TABLE(OPCODE_ADD_CARRY, ADD_CARRY_I8, ADD_CARRY_I16, struct VECTOR_ADD : Sequence> { static void Emit(X64Emitter& e, const EmitArgType& i) { - EmitCommutativeBinaryXmmOp(e, i, [&i](X64Emitter& e, const Xmm& dest, - Xmm src1, Xmm src2) { - const TypeName part_type = static_cast(i.instr->flags & 0xFF); - const uint32_t arithmetic_flags = i.instr->flags >> 8; - bool is_unsigned = !!(arithmetic_flags & ARITHMETIC_UNSIGNED); - bool saturate = !!(arithmetic_flags & ARITHMETIC_SATURATE); - switch (part_type) { - case INT8_TYPE: - if (saturate) { - // TODO(benvanik): trace DID_SATURATE - if (is_unsigned) { - e.vpaddusb(dest, src1, src2); - } else { - e.vpaddsb(dest, src1, src2); - } - } else { - e.vpaddb(dest, src1, src2); - } - break; - case INT16_TYPE: - if (saturate) { - // TODO(benvanik): trace DID_SATURATE - if (is_unsigned) { - e.vpaddusw(dest, src1, src2); - } else { - e.vpaddsw(dest, src1, src2); - } - } else { - e.vpaddw(dest, src1, src2); - } - break; - case INT32_TYPE: - if (saturate) { - if (is_unsigned) { - // xmm0 is the only temp register that can be used by src1/src2. - e.vpaddd(e.xmm1, src1, src2); - - // If result is smaller than either of the inputs, we've - // overflowed (only need to check one input) - // if (src1 > res) then overflowed - // http://locklessinc.com/articles/sat_arithmetic/ - e.vpxor(e.xmm2, src1, e.GetXmmConstPtr(XMMSignMaskI32)); - e.vpxor(e.xmm0, e.xmm1, e.GetXmmConstPtr(XMMSignMaskI32)); - e.vpcmpgtd(e.xmm0, e.xmm2, e.xmm0); - e.vpor(dest, e.xmm1, e.xmm0); - } else { - // Preserve the sources. - if (dest == src1) { - e.vmovdqa(e.xmm2, src1); - src1 = e.xmm2; + EmitCommutativeBinaryXmmOp( + e, i, [&i](X64Emitter& e, const Xmm& dest, Xmm src1, Xmm src2) { + const TypeName part_type = + static_cast(i.instr->flags & 0xFF); + const uint32_t arithmetic_flags = i.instr->flags >> 8; + bool is_unsigned = !!(arithmetic_flags & ARITHMETIC_UNSIGNED); + bool saturate = !!(arithmetic_flags & ARITHMETIC_SATURATE); + switch (part_type) { + case INT8_TYPE: + if (saturate) { + // TODO(benvanik): trace DID_SATURATE + if (is_unsigned) { + e.vpaddusb(dest, src1, src2); + } else { + e.vpaddsb(dest, src1, src2); + } + } else { + e.vpaddb(dest, src1, src2); } - if (dest == src2) { - e.vmovdqa(e.xmm1, src2); - src2 = e.xmm1; + break; + case INT16_TYPE: + if (saturate) { + // TODO(benvanik): trace DID_SATURATE + if (is_unsigned) { + e.vpaddusw(dest, src1, src2); + } else { + e.vpaddsw(dest, src1, src2); + } + } else { + e.vpaddw(dest, src1, src2); } + break; + case INT32_TYPE: + if (saturate) { + if (is_unsigned) { + // xmm0 is the only temp register that can be used by + // src1/src2. + e.vpaddd(e.xmm1, src1, src2); - // xmm0 is the only temp register that can be used by src1/src2. - e.vpaddd(dest, src1, src2); + // If result is smaller than either of the inputs, we've + // overflowed (only need to check one input) + // if (src1 > res) then overflowed + // http://locklessinc.com/articles/sat_arithmetic/ + e.vpxor(e.xmm2, src1, e.GetXmmConstPtr(XMMSignMaskI32)); + e.vpxor(e.xmm0, e.xmm1, e.GetXmmConstPtr(XMMSignMaskI32)); + e.vpcmpgtd(e.xmm0, e.xmm2, e.xmm0); + e.vpor(dest, e.xmm1, e.xmm0); + } else { + // Preserve the sources. + if (dest == src1) { + e.vmovdqa(e.xmm2, src1); + src1 = e.xmm2; + } + if (dest == src2) { + e.vmovdqa(e.xmm1, src2); + src2 = e.xmm1; + } - // Overflow results if two inputs are the same sign and the result - // isn't the same sign. - // if ((s32b)(~(src1 ^ src2) & (src1 ^ res)) < 0) then overflowed - // http://locklessinc.com/articles/sat_arithmetic/ - e.vpxor(e.xmm1, src1, src2); + // xmm0 is the only temp register that can be used by + // src1/src2. + e.vpaddd(dest, src1, src2); - // Move src1 to xmm0 in-case it was the same register as the dest. - // This kills src2 if it's a constant. - if (src1 != e.xmm0) { - e.vmovdqa(e.xmm0, src1); - src1 = e.xmm0; + // Overflow results if two inputs are the same sign and the + // result isn't the same sign. if ((s32b)(~(src1 ^ src2) & + // (src1 ^ res)) < 0) then overflowed + // http://locklessinc.com/articles/sat_arithmetic/ + e.vpxor(e.xmm1, src1, src2); + + // Move src1 to xmm0 in-case it was the same register as the + // dest. This kills src2 if it's a constant. + if (src1 != e.xmm0) { + e.vmovdqa(e.xmm0, src1); + src1 = e.xmm0; + } + + e.vpxor(e.xmm2, src1, dest); + e.vpandn(e.xmm1, e.xmm1, e.xmm2); + + // High bit of xmm1 is now set if overflowed. + + // Set any negative overflowed elements of src1 to INT_MIN + e.vpand(e.xmm2, src1, e.xmm1); + e.vblendvps(dest, dest, e.GetXmmConstPtr(XMMSignMaskI32), + e.xmm2); + + // Set any positive overflowed elements of src1 to INT_MAX + e.vpandn(e.xmm2, src1, e.xmm1); + e.vblendvps(dest, dest, e.GetXmmConstPtr(XMMAbsMaskPS), + e.xmm2); + } + } else { + e.vpaddd(dest, src1, src2); } - - e.vpxor(e.xmm2, src1, dest); - e.vpandn(e.xmm1, e.xmm1, e.xmm2); - - // High bit of xmm1 is now set if overflowed. - - // Set any negative overflowed elements of src1 to INT_MIN - e.vpand(e.xmm2, src1, e.xmm1); - e.vblendvps(dest, dest, e.GetXmmConstPtr(XMMSignMaskI32), e.xmm2); - - // Set any positive overflowed elements of src1 to INT_MAX - e.vpandn(e.xmm2, src1, e.xmm1); - e.vblendvps(dest, dest, e.GetXmmConstPtr(XMMAbsMaskPS), e.xmm2); - } - } else { - e.vpaddd(dest, src1, src2); + break; + case FLOAT32_TYPE: + assert_false(is_unsigned); + assert_false(saturate); + e.vaddps(dest, src1, src2); + break; + default: + assert_unhandled_case(part_type); + break; } - break; - case FLOAT32_TYPE: - assert_false(is_unsigned); - assert_false(saturate); - e.vaddps(dest, src1, src2); - break; - default: - assert_unhandled_case(part_type); - break; - } - }); + }); } }; EMITTER_OPCODE_TABLE(OPCODE_VECTOR_ADD, VECTOR_ADD); @@ -3640,8 +3657,10 @@ EMITTER_OPCODE_TABLE(OPCODE_VECTOR_ADD, VECTOR_ADD); template void EmitSubXX(X64Emitter& e, const ARGS& i) { SEQ::EmitAssociativeBinaryOp( - e, i, [](X64Emitter& e, const REG& dest_src, - const REG& src) { e.sub(dest_src, src); }, + e, i, + [](X64Emitter& e, const REG& dest_src, const REG& src) { + e.sub(dest_src, src); + }, [](X64Emitter& e, const REG& dest_src, int32_t constant) { e.sub(dest_src, constant); }); @@ -3693,104 +3712,109 @@ EMITTER_OPCODE_TABLE(OPCODE_SUB, SUB_I8, SUB_I16, SUB_I32, SUB_I64, SUB_F32, struct VECTOR_SUB : Sequence> { static void Emit(X64Emitter& e, const EmitArgType& i) { - EmitCommutativeBinaryXmmOp(e, i, [&i](X64Emitter& e, const Xmm& dest, - Xmm src1, Xmm src2) { - const TypeName part_type = static_cast(i.instr->flags & 0xFF); - const uint32_t arithmetic_flags = i.instr->flags >> 8; - bool is_unsigned = !!(arithmetic_flags & ARITHMETIC_UNSIGNED); - bool saturate = !!(arithmetic_flags & ARITHMETIC_SATURATE); - switch (part_type) { - case INT8_TYPE: - if (saturate) { - // TODO(benvanik): trace DID_SATURATE - if (is_unsigned) { - e.vpsubusb(dest, src1, src2); - } else { - e.vpsubsb(dest, src1, src2); - } - } else { - e.vpsubb(dest, src1, src2); - } - break; - case INT16_TYPE: - if (saturate) { - // TODO(benvanik): trace DID_SATURATE - if (is_unsigned) { - e.vpsubusw(dest, src1, src2); - } else { - e.vpsubsw(dest, src1, src2); - } - } else { - e.vpsubw(dest, src1, src2); - } - break; - case INT32_TYPE: - if (saturate) { - if (is_unsigned) { - // xmm0 is the only temp register that can be used by src1/src2. - e.vpsubd(e.xmm1, src1, src2); - - // If result is greater than either of the inputs, we've - // underflowed (only need to check one input) - // if (res > src1) then underflowed - // http://locklessinc.com/articles/sat_arithmetic/ - e.vpxor(e.xmm2, src1, e.GetXmmConstPtr(XMMSignMaskI32)); - e.vpxor(e.xmm0, e.xmm1, e.GetXmmConstPtr(XMMSignMaskI32)); - e.vpcmpgtd(e.xmm0, e.xmm0, e.xmm2); - e.vpandn(dest, e.xmm0, e.xmm1); - } else { - // Preserve the sources. - if (dest == src1) { - e.vmovdqa(e.xmm2, src1); - src1 = e.xmm2; + EmitCommutativeBinaryXmmOp( + e, i, [&i](X64Emitter& e, const Xmm& dest, Xmm src1, Xmm src2) { + const TypeName part_type = + static_cast(i.instr->flags & 0xFF); + const uint32_t arithmetic_flags = i.instr->flags >> 8; + bool is_unsigned = !!(arithmetic_flags & ARITHMETIC_UNSIGNED); + bool saturate = !!(arithmetic_flags & ARITHMETIC_SATURATE); + switch (part_type) { + case INT8_TYPE: + if (saturate) { + // TODO(benvanik): trace DID_SATURATE + if (is_unsigned) { + e.vpsubusb(dest, src1, src2); + } else { + e.vpsubsb(dest, src1, src2); + } + } else { + e.vpsubb(dest, src1, src2); } - if (dest == src2) { - e.vmovdqa(e.xmm1, src2); - src2 = e.xmm1; + break; + case INT16_TYPE: + if (saturate) { + // TODO(benvanik): trace DID_SATURATE + if (is_unsigned) { + e.vpsubusw(dest, src1, src2); + } else { + e.vpsubsw(dest, src1, src2); + } + } else { + e.vpsubw(dest, src1, src2); } + break; + case INT32_TYPE: + if (saturate) { + if (is_unsigned) { + // xmm0 is the only temp register that can be used by + // src1/src2. + e.vpsubd(e.xmm1, src1, src2); - // xmm0 is the only temp register that can be used by src1/src2. - e.vpsubd(dest, src1, src2); + // If result is greater than either of the inputs, we've + // underflowed (only need to check one input) + // if (res > src1) then underflowed + // http://locklessinc.com/articles/sat_arithmetic/ + e.vpxor(e.xmm2, src1, e.GetXmmConstPtr(XMMSignMaskI32)); + e.vpxor(e.xmm0, e.xmm1, e.GetXmmConstPtr(XMMSignMaskI32)); + e.vpcmpgtd(e.xmm0, e.xmm0, e.xmm2); + e.vpandn(dest, e.xmm0, e.xmm1); + } else { + // Preserve the sources. + if (dest == src1) { + e.vmovdqa(e.xmm2, src1); + src1 = e.xmm2; + } + if (dest == src2) { + e.vmovdqa(e.xmm1, src2); + src2 = e.xmm1; + } - // We can only overflow if the signs of the operands are opposite. - // If signs are opposite and result sign isn't the same as src1's - // sign, we've overflowed. - // if ((s32b)((src1 ^ src2) & (src1 ^ res)) < 0) then overflowed - // http://locklessinc.com/articles/sat_arithmetic/ - e.vpxor(e.xmm1, src1, src2); + // xmm0 is the only temp register that can be used by + // src1/src2. + e.vpsubd(dest, src1, src2); - // Move src1 to xmm0 in-case it's the same register as the dest. - // This kills src2 if it's a constant. - if (src1 != e.xmm0) { - e.vmovdqa(e.xmm0, src1); - src1 = e.xmm0; + // We can only overflow if the signs of the operands are + // opposite. If signs are opposite and result sign isn't the + // same as src1's sign, we've overflowed. if ((s32b)((src1 ^ + // src2) & (src1 ^ res)) < 0) then overflowed + // http://locklessinc.com/articles/sat_arithmetic/ + e.vpxor(e.xmm1, src1, src2); + + // Move src1 to xmm0 in-case it's the same register as the + // dest. This kills src2 if it's a constant. + if (src1 != e.xmm0) { + e.vmovdqa(e.xmm0, src1); + src1 = e.xmm0; + } + + e.vpxor(e.xmm2, src1, dest); + e.vpand(e.xmm1, e.xmm1, e.xmm2); + + // High bit of xmm1 is now set if overflowed. + + // Set any negative overflowed elements of src1 to INT_MIN + e.vpand(e.xmm2, src1, e.xmm1); + e.vblendvps(dest, dest, e.GetXmmConstPtr(XMMSignMaskI32), + e.xmm2); + + // Set any positive overflowed elements of src1 to INT_MAX + e.vpandn(e.xmm2, src1, e.xmm1); + e.vblendvps(dest, dest, e.GetXmmConstPtr(XMMAbsMaskPS), + e.xmm2); + } + } else { + e.vpsubd(dest, src1, src2); } - - e.vpxor(e.xmm2, src1, dest); - e.vpand(e.xmm1, e.xmm1, e.xmm2); - - // High bit of xmm1 is now set if overflowed. - - // Set any negative overflowed elements of src1 to INT_MIN - e.vpand(e.xmm2, src1, e.xmm1); - e.vblendvps(dest, dest, e.GetXmmConstPtr(XMMSignMaskI32), e.xmm2); - - // Set any positive overflowed elements of src1 to INT_MAX - e.vpandn(e.xmm2, src1, e.xmm1); - e.vblendvps(dest, dest, e.GetXmmConstPtr(XMMAbsMaskPS), e.xmm2); - } - } else { - e.vpsubd(dest, src1, src2); + break; + case FLOAT32_TYPE: + e.vsubps(dest, src1, src2); + break; + default: + assert_unhandled_case(part_type); + break; } - break; - case FLOAT32_TYPE: - e.vsubps(dest, src1, src2); - break; - default: - assert_unhandled_case(part_type); - break; - } - }); + }); } }; EMITTER_OPCODE_TABLE(OPCODE_VECTOR_SUB, VECTOR_SUB); @@ -4469,24 +4493,26 @@ struct MUL_ADD_F32 // FMA extension if (e.IsFeatureEnabled(kX64EmitFMA)) { - EmitCommutativeBinaryXmmOp(e, i, [&i](X64Emitter& e, const Xmm& dest, - const Xmm& src1, const Xmm& src2) { - Xmm src3 = i.src3.is_constant ? e.xmm1 : i.src3; - if (i.src3.is_constant) { - e.LoadConstantXmm(e.xmm1, i.src3.constant()); - } - if (i.dest == src1) { - e.vfmadd213ss(i.dest, src2, src3); - } else if (i.dest == src2) { - e.vfmadd213ss(i.dest, src1, src3); - } else if (i.dest == i.src3) { - e.vfmadd231ss(i.dest, src1, src2); - } else { - // Dest not equal to anything - e.vmovss(i.dest, src1); - e.vfmadd213ss(i.dest, src2, src3); - } - }); + EmitCommutativeBinaryXmmOp( + e, i, + [&i](X64Emitter& e, const Xmm& dest, const Xmm& src1, + const Xmm& src2) { + Xmm src3 = i.src3.is_constant ? e.xmm1 : i.src3; + if (i.src3.is_constant) { + e.LoadConstantXmm(e.xmm1, i.src3.constant()); + } + if (i.dest == src1) { + e.vfmadd213ss(i.dest, src2, src3); + } else if (i.dest == src2) { + e.vfmadd213ss(i.dest, src1, src3); + } else if (i.dest == i.src3) { + e.vfmadd231ss(i.dest, src1, src2); + } else { + // Dest not equal to anything + e.vmovss(i.dest, src1); + e.vfmadd213ss(i.dest, src2, src3); + } + }); } else { Xmm src3; if (i.src3.is_constant) { @@ -4526,24 +4552,26 @@ struct MUL_ADD_F64 // FMA extension if (e.IsFeatureEnabled(kX64EmitFMA)) { - EmitCommutativeBinaryXmmOp(e, i, [&i](X64Emitter& e, const Xmm& dest, - const Xmm& src1, const Xmm& src2) { - Xmm src3 = i.src3.is_constant ? e.xmm1 : i.src3; - if (i.src3.is_constant) { - e.LoadConstantXmm(e.xmm1, i.src3.constant()); - } - if (i.dest == src1) { - e.vfmadd213sd(i.dest, src2, src3); - } else if (i.dest == src2) { - e.vfmadd213sd(i.dest, src1, src3); - } else if (i.dest == i.src3) { - e.vfmadd231sd(i.dest, src1, src2); - } else { - // Dest not equal to anything - e.vmovsd(i.dest, src1); - e.vfmadd213sd(i.dest, src2, src3); - } - }); + EmitCommutativeBinaryXmmOp( + e, i, + [&i](X64Emitter& e, const Xmm& dest, const Xmm& src1, + const Xmm& src2) { + Xmm src3 = i.src3.is_constant ? e.xmm1 : i.src3; + if (i.src3.is_constant) { + e.LoadConstantXmm(e.xmm1, i.src3.constant()); + } + if (i.dest == src1) { + e.vfmadd213sd(i.dest, src2, src3); + } else if (i.dest == src2) { + e.vfmadd213sd(i.dest, src1, src3); + } else if (i.dest == i.src3) { + e.vfmadd231sd(i.dest, src1, src2); + } else { + // Dest not equal to anything + e.vmovsd(i.dest, src1); + e.vfmadd213sd(i.dest, src2, src3); + } + }); } else { Xmm src3; if (i.src3.is_constant) { @@ -4589,24 +4617,26 @@ struct MUL_ADD_V128 // than vmul+vadd and it'd be nice to know why. Until we know, it's // disabled so tests pass. if (false && e.IsFeatureEnabled(kX64EmitFMA)) { - EmitCommutativeBinaryXmmOp(e, i, [&i](X64Emitter& e, const Xmm& dest, - const Xmm& src1, const Xmm& src2) { - Xmm src3 = i.src3.is_constant ? e.xmm1 : i.src3; - if (i.src3.is_constant) { - e.LoadConstantXmm(e.xmm1, i.src3.constant()); - } - if (i.dest == src1) { - e.vfmadd213ps(i.dest, src2, src3); - } else if (i.dest == src2) { - e.vfmadd213ps(i.dest, src1, src3); - } else if (i.dest == i.src3) { - e.vfmadd231ps(i.dest, src1, src2); - } else { - // Dest not equal to anything - e.vmovdqa(i.dest, src1); - e.vfmadd213ps(i.dest, src2, src3); - } - }); + EmitCommutativeBinaryXmmOp( + e, i, + [&i](X64Emitter& e, const Xmm& dest, const Xmm& src1, + const Xmm& src2) { + Xmm src3 = i.src3.is_constant ? e.xmm1 : i.src3; + if (i.src3.is_constant) { + e.LoadConstantXmm(e.xmm1, i.src3.constant()); + } + if (i.dest == src1) { + e.vfmadd213ps(i.dest, src2, src3); + } else if (i.dest == src2) { + e.vfmadd213ps(i.dest, src1, src3); + } else if (i.dest == i.src3) { + e.vfmadd231ps(i.dest, src1, src2); + } else { + // Dest not equal to anything + e.vmovdqa(i.dest, src1); + e.vfmadd213ps(i.dest, src2, src3); + } + }); } else { Xmm src3; if (i.src3.is_constant) { @@ -4660,24 +4690,26 @@ struct MUL_SUB_F32 // FMA extension if (e.IsFeatureEnabled(kX64EmitFMA)) { - EmitCommutativeBinaryXmmOp(e, i, [&i](X64Emitter& e, const Xmm& dest, - const Xmm& src1, const Xmm& src2) { - Xmm src3 = i.src3.is_constant ? e.xmm1 : i.src3; - if (i.src3.is_constant) { - e.LoadConstantXmm(e.xmm1, i.src3.constant()); - } - if (i.dest == src1) { - e.vfmsub213ss(i.dest, src2, src3); - } else if (i.dest == src2) { - e.vfmsub213ss(i.dest, src1, src3); - } else if (i.dest == i.src3) { - e.vfmsub231ss(i.dest, src1, src2); - } else { - // Dest not equal to anything - e.vmovss(i.dest, src1); - e.vfmsub213ss(i.dest, src2, src3); - } - }); + EmitCommutativeBinaryXmmOp( + e, i, + [&i](X64Emitter& e, const Xmm& dest, const Xmm& src1, + const Xmm& src2) { + Xmm src3 = i.src3.is_constant ? e.xmm1 : i.src3; + if (i.src3.is_constant) { + e.LoadConstantXmm(e.xmm1, i.src3.constant()); + } + if (i.dest == src1) { + e.vfmsub213ss(i.dest, src2, src3); + } else if (i.dest == src2) { + e.vfmsub213ss(i.dest, src1, src3); + } else if (i.dest == i.src3) { + e.vfmsub231ss(i.dest, src1, src2); + } else { + // Dest not equal to anything + e.vmovss(i.dest, src1); + e.vfmsub213ss(i.dest, src2, src3); + } + }); } else { Xmm src3; if (i.src3.is_constant) { @@ -4717,24 +4749,26 @@ struct MUL_SUB_F64 // FMA extension if (e.IsFeatureEnabled(kX64EmitFMA)) { - EmitCommutativeBinaryXmmOp(e, i, [&i](X64Emitter& e, const Xmm& dest, - const Xmm& src1, const Xmm& src2) { - Xmm src3 = i.src3.is_constant ? e.xmm1 : i.src3; - if (i.src3.is_constant) { - e.LoadConstantXmm(e.xmm1, i.src3.constant()); - } - if (i.dest == src1) { - e.vfmsub213sd(i.dest, src2, src3); - } else if (i.dest == src2) { - e.vfmsub213sd(i.dest, src1, src3); - } else if (i.dest == i.src3) { - e.vfmsub231sd(i.dest, src1, src2); - } else { - // Dest not equal to anything - e.vmovsd(i.dest, src1); - e.vfmsub213sd(i.dest, src2, src3); - } - }); + EmitCommutativeBinaryXmmOp( + e, i, + [&i](X64Emitter& e, const Xmm& dest, const Xmm& src1, + const Xmm& src2) { + Xmm src3 = i.src3.is_constant ? e.xmm1 : i.src3; + if (i.src3.is_constant) { + e.LoadConstantXmm(e.xmm1, i.src3.constant()); + } + if (i.dest == src1) { + e.vfmsub213sd(i.dest, src2, src3); + } else if (i.dest == src2) { + e.vfmsub213sd(i.dest, src1, src3); + } else if (i.dest == i.src3) { + e.vfmsub231sd(i.dest, src1, src2); + } else { + // Dest not equal to anything + e.vmovsd(i.dest, src1); + e.vfmsub213sd(i.dest, src2, src3); + } + }); } else { Xmm src3; if (i.src3.is_constant) { @@ -4778,24 +4812,26 @@ struct MUL_SUB_V128 // FMA extension if (e.IsFeatureEnabled(kX64EmitFMA)) { - EmitCommutativeBinaryXmmOp(e, i, [&i](X64Emitter& e, const Xmm& dest, - const Xmm& src1, const Xmm& src2) { - Xmm src3 = i.src3.is_constant ? e.xmm1 : i.src3; - if (i.src3.is_constant) { - e.LoadConstantXmm(e.xmm1, i.src3.constant()); - } - if (i.dest == src1) { - e.vfmsub213ps(i.dest, src2, src3); - } else if (i.dest == src2) { - e.vfmsub213ps(i.dest, src1, src3); - } else if (i.dest == i.src3) { - e.vfmsub231ps(i.dest, src1, src2); - } else { - // Dest not equal to anything - e.vmovdqa(i.dest, src1); - e.vfmsub213ps(i.dest, src2, src3); - } - }); + EmitCommutativeBinaryXmmOp( + e, i, + [&i](X64Emitter& e, const Xmm& dest, const Xmm& src1, + const Xmm& src2) { + Xmm src3 = i.src3.is_constant ? e.xmm1 : i.src3; + if (i.src3.is_constant) { + e.LoadConstantXmm(e.xmm1, i.src3.constant()); + } + if (i.dest == src1) { + e.vfmsub213ps(i.dest, src2, src3); + } else if (i.dest == src2) { + e.vfmsub213ps(i.dest, src1, src3); + } else if (i.dest == i.src3) { + e.vfmsub231ps(i.dest, src1, src2); + } else { + // Dest not equal to anything + e.vmovdqa(i.dest, src1); + e.vfmsub213ps(i.dest, src2, src3); + } + }); } else { Xmm src3; if (i.src3.is_constant) { @@ -5098,8 +5134,10 @@ EMITTER_OPCODE_TABLE(OPCODE_DOT_PRODUCT_4, DOT_PRODUCT_4_V128); template void EmitAndXX(X64Emitter& e, const ARGS& i) { SEQ::EmitCommutativeBinaryOp( - e, i, [](X64Emitter& e, const REG& dest_src, - const REG& src) { e.and_(dest_src, src); }, + e, i, + [](X64Emitter& e, const REG& dest_src, const REG& src) { + e.and_(dest_src, src); + }, [](X64Emitter& e, const REG& dest_src, int32_t constant) { e.and_(dest_src, constant); }); @@ -5141,8 +5179,10 @@ EMITTER_OPCODE_TABLE(OPCODE_AND, AND_I8, AND_I16, AND_I32, AND_I64, AND_V128); template void EmitOrXX(X64Emitter& e, const ARGS& i) { SEQ::EmitCommutativeBinaryOp( - e, i, [](X64Emitter& e, const REG& dest_src, - const REG& src) { e.or_(dest_src, src); }, + e, i, + [](X64Emitter& e, const REG& dest_src, const REG& src) { + e.or_(dest_src, src); + }, [](X64Emitter& e, const REG& dest_src, int32_t constant) { e.or_(dest_src, constant); }); @@ -5184,8 +5224,10 @@ EMITTER_OPCODE_TABLE(OPCODE_OR, OR_I8, OR_I16, OR_I32, OR_I64, OR_V128); template void EmitXorXX(X64Emitter& e, const ARGS& i) { SEQ::EmitCommutativeBinaryOp( - e, i, [](X64Emitter& e, const REG& dest_src, - const REG& src) { e.xor_(dest_src, src); }, + e, i, + [](X64Emitter& e, const REG& dest_src, const REG& src) { + e.xor_(dest_src, src); + }, [](X64Emitter& e, const REG& dest_src, int32_t constant) { e.xor_(dest_src, constant); }); @@ -6209,57 +6251,59 @@ struct VECTOR_AVERAGE return _mm_load_si128(reinterpret_cast<__m128i*>(value)); } static void Emit(X64Emitter& e, const EmitArgType& i) { - EmitCommutativeBinaryXmmOp(e, i, [&i](X64Emitter& e, const Xmm& dest, - const Xmm& src1, const Xmm& src2) { - const TypeName part_type = static_cast(i.instr->flags & 0xFF); - const uint32_t arithmetic_flags = i.instr->flags >> 8; - bool is_unsigned = !!(arithmetic_flags & ARITHMETIC_UNSIGNED); - switch (part_type) { - case INT8_TYPE: - if (is_unsigned) { - e.vpavgb(dest, src1, src2); - } else { - assert_always(); + EmitCommutativeBinaryXmmOp( + e, i, + [&i](X64Emitter& e, const Xmm& dest, const Xmm& src1, const Xmm& src2) { + const TypeName part_type = + static_cast(i.instr->flags & 0xFF); + const uint32_t arithmetic_flags = i.instr->flags >> 8; + bool is_unsigned = !!(arithmetic_flags & ARITHMETIC_UNSIGNED); + switch (part_type) { + case INT8_TYPE: + if (is_unsigned) { + e.vpavgb(dest, src1, src2); + } else { + assert_always(); + } + break; + case INT16_TYPE: + if (is_unsigned) { + e.vpavgw(dest, src1, src2); + } else { + assert_always(); + } + break; + case INT32_TYPE: + // No 32bit averages in AVX. + if (is_unsigned) { + if (i.src2.is_constant) { + e.LoadConstantXmm(e.xmm0, i.src2.constant()); + e.lea(e.r9, e.StashXmm(1, e.xmm0)); + } else { + e.lea(e.r9, e.StashXmm(1, i.src2)); + } + e.lea(e.r8, e.StashXmm(0, i.src1)); + e.CallNativeSafe( + reinterpret_cast(EmulateVectorAverageUnsignedI32)); + e.vmovaps(i.dest, e.xmm0); + } else { + if (i.src2.is_constant) { + e.LoadConstantXmm(e.xmm0, i.src2.constant()); + e.lea(e.r9, e.StashXmm(1, e.xmm0)); + } else { + e.lea(e.r9, e.StashXmm(1, i.src2)); + } + e.lea(e.r8, e.StashXmm(0, i.src1)); + e.CallNativeSafe( + reinterpret_cast(EmulateVectorAverageSignedI32)); + e.vmovaps(i.dest, e.xmm0); + } + break; + default: + assert_unhandled_case(part_type); + break; } - break; - case INT16_TYPE: - if (is_unsigned) { - e.vpavgw(dest, src1, src2); - } else { - assert_always(); - } - break; - case INT32_TYPE: - // No 32bit averages in AVX. - if (is_unsigned) { - if (i.src2.is_constant) { - e.LoadConstantXmm(e.xmm0, i.src2.constant()); - e.lea(e.r9, e.StashXmm(1, e.xmm0)); - } else { - e.lea(e.r9, e.StashXmm(1, i.src2)); - } - e.lea(e.r8, e.StashXmm(0, i.src1)); - e.CallNativeSafe( - reinterpret_cast(EmulateVectorAverageUnsignedI32)); - e.vmovaps(i.dest, e.xmm0); - } else { - if (i.src2.is_constant) { - e.LoadConstantXmm(e.xmm0, i.src2.constant()); - e.lea(e.r9, e.StashXmm(1, e.xmm0)); - } else { - e.lea(e.r9, e.StashXmm(1, i.src2)); - } - e.lea(e.r8, e.StashXmm(0, i.src1)); - e.CallNativeSafe( - reinterpret_cast(EmulateVectorAverageSignedI32)); - e.vmovaps(i.dest, e.xmm0); - } - break; - default: - assert_unhandled_case(part_type); - break; - } - }); + }); } }; EMITTER_OPCODE_TABLE(OPCODE_VECTOR_AVERAGE, VECTOR_AVERAGE); diff --git a/src/xenia/cpu/compiler/passes/data_flow_analysis_pass.cc b/src/xenia/cpu/compiler/passes/data_flow_analysis_pass.cc index a858e4329..622af656b 100644 --- a/src/xenia/cpu/compiler/passes/data_flow_analysis_pass.cc +++ b/src/xenia/cpu/compiler/passes/data_flow_analysis_pass.cc @@ -24,6 +24,7 @@ #pragma warning(pop) #else #include +#include #endif // XE_COMPILER_MSVC namespace xe { diff --git a/src/xenia/cpu/compiler/passes/register_allocation_pass.cc b/src/xenia/cpu/compiler/passes/register_allocation_pass.cc index c0fb62394..c65cde487 100644 --- a/src/xenia/cpu/compiler/passes/register_allocation_pass.cc +++ b/src/xenia/cpu/compiler/passes/register_allocation_pass.cc @@ -420,7 +420,7 @@ bool RegisterAllocationPass::SpillOneRegister(HIRBuilder* builder, Block* block, auto new_value = builder->LoadLocal(spill_value->local_slot); auto spill_load = builder->last_instr(); spill_load->MoveBefore(next_use->instr); -// Note: implicit first use added. + // Note: implicit first use added. #if ASSERT_NO_CYCLES builder->AssertNoCycles(); diff --git a/src/xenia/cpu/compiler/passes/value_reduction_pass.cc b/src/xenia/cpu/compiler/passes/value_reduction_pass.cc index 94a218219..02ec9e757 100644 --- a/src/xenia/cpu/compiler/passes/value_reduction_pass.cc +++ b/src/xenia/cpu/compiler/passes/value_reduction_pass.cc @@ -23,6 +23,7 @@ #pragma warning(pop) #else #include +#include #endif // XE_COMPILER_MSVC namespace xe { diff --git a/src/xenia/cpu/hir/hir_builder.cc b/src/xenia/cpu/hir/hir_builder.cc index a654ed0ba..a74e28377 100644 --- a/src/xenia/cpu/hir/hir_builder.cc +++ b/src/xenia/cpu/hir/hir_builder.cc @@ -1963,7 +1963,10 @@ Value* HIRBuilder::CountLeadingZeros(Value* value) { if (value->IsConstantZero()) { static const uint8_t zeros[] = { - 8, 16, 32, 64, + 8, + 16, + 32, + 64, }; assert_true(value->type <= INT64_TYPE); return LoadConstantUint8(zeros[value->type]); diff --git a/src/xenia/cpu/hir/opcodes.cc b/src/xenia/cpu/hir/opcodes.cc index bbfe0cebe..b3b14b198 100644 --- a/src/xenia/cpu/hir/opcodes.cc +++ b/src/xenia/cpu/hir/opcodes.cc @@ -15,7 +15,10 @@ namespace hir { #define DEFINE_OPCODE(num, name, sig, flags) \ const OpcodeInfo num##_info = { \ - flags, sig, name, num, \ + flags, \ + sig, \ + name, \ + num, \ }; #include "xenia/cpu/hir/opcodes.inl" #undef DEFINE_OPCODE diff --git a/src/xenia/cpu/hir/opcodes.h b/src/xenia/cpu/hir/opcodes.h index d2e9344db..bfdb7fd15 100644 --- a/src/xenia/cpu/hir/opcodes.h +++ b/src/xenia/cpu/hir/opcodes.h @@ -87,8 +87,7 @@ enum PackType : uint16_t { PACK_TYPE_16_IN_32 = 7, PACK_TYPE_MODE = 0x000F, // just to get the mode - - // Unpack to low or high parts. + // Unpack to low or high parts. PACK_TYPE_TO_LO = 0 << 12, PACK_TYPE_TO_HI = 1 << 12, diff --git a/src/xenia/cpu/mmio_handler.cc b/src/xenia/cpu/mmio_handler.cc index 1a5682eec..a72545a9c 100644 --- a/src/xenia/cpu/mmio_handler.cc +++ b/src/xenia/cpu/mmio_handler.cc @@ -52,7 +52,12 @@ bool MMIOHandler::RegisterRange(uint32_t virtual_address, uint32_t mask, MMIOReadCallback read_callback, MMIOWriteCallback write_callback) { mapped_ranges_.push_back({ - virtual_address, mask, size, context, read_callback, write_callback, + virtual_address, + mask, + size, + context, + read_callback, + write_callback, }); return true; } diff --git a/src/xenia/cpu/ppc/ppc_emit_altivec.cc b/src/xenia/cpu/ppc/ppc_emit_altivec.cc index c71b2ae5c..c749203a9 100644 --- a/src/xenia/cpu/ppc/ppc_emit_altivec.cc +++ b/src/xenia/cpu/ppc/ppc_emit_altivec.cc @@ -2073,7 +2073,7 @@ int InstrEmit_vpkd3d128(PPCHIRBuilder& f, const InstrData& i) { uint32_t control = kIdentityPermuteMask; // original switch (pack) { case 1: // VPACK_32 - // VPACK_32 & shift = 3 puts lower 32 bits in x (leftmost slot). + // VPACK_32 & shift = 3 puts lower 32 bits in x (leftmost slot). switch (shift) { case 0: control = MakePermuteMask(0, 0, 0, 1, 0, 2, 1, 3); diff --git a/src/xenia/cpu/ppc/ppc_emit_control.cc b/src/xenia/cpu/ppc/ppc_emit_control.cc index e4a89be83..bdc7dd552 100644 --- a/src/xenia/cpu/ppc/ppc_emit_control.cc +++ b/src/xenia/cpu/ppc/ppc_emit_control.cc @@ -143,7 +143,7 @@ int InstrEmit_branch(PPCHIRBuilder& f, const char* src, uint64_t cia, } return 0; -} +} // namespace ppc int InstrEmit_bx(PPCHIRBuilder& f, const InstrData& i) { // if AA then @@ -799,6 +799,6 @@ void RegisterEmitCategoryControl() { XEREGISTERINSTR(mtmsrd); } -} // namespace ppc } // namespace cpu } // namespace xe +} // namespace xe diff --git a/src/xenia/cpu/ppc/ppc_scanner.cc b/src/xenia/cpu/ppc/ppc_scanner.cc index edacf31b5..45c640926 100644 --- a/src/xenia/cpu/ppc/ppc_scanner.cc +++ b/src/xenia/cpu/ppc/ppc_scanner.cc @@ -341,14 +341,16 @@ std::vector PPCScanner::FindBlocks(GuestFunction* function) { if (ends_block) { in_block = false; block_map[block_start] = { - block_start, address, + block_start, + address, }; } } if (in_block) { block_map[block_start] = { - block_start, end_address, + block_start, + end_address, }; } diff --git a/src/xenia/cpu/testing/add_test.cc b/src/xenia/cpu/testing/add_test.cc index 425ad9723..8b0a9db54 100644 --- a/src/xenia/cpu/testing/add_test.cc +++ b/src/xenia/cpu/testing/add_test.cc @@ -18,9 +18,10 @@ using xe::cpu::ppc::PPCContext; TEST_CASE("ADD_I8", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreGPR(b, 3, b.ZeroExtend(b.Add(b.Truncate(LoadGPR(b, 4), INT8_TYPE), - b.Truncate(LoadGPR(b, 5), INT8_TYPE)), - INT64_TYPE)); + StoreGPR(b, 3, + b.ZeroExtend(b.Add(b.Truncate(LoadGPR(b, 4), INT8_TYPE), + b.Truncate(LoadGPR(b, 5), INT8_TYPE)), + INT64_TYPE)); b.Return(); }); test.Run( @@ -90,9 +91,10 @@ TEST_CASE("ADD_I8", "[instr]") { TEST_CASE("ADD_I16", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreGPR(b, 3, b.ZeroExtend(b.Add(b.Truncate(LoadGPR(b, 4), INT16_TYPE), - b.Truncate(LoadGPR(b, 5), INT16_TYPE)), - INT64_TYPE)); + StoreGPR(b, 3, + b.ZeroExtend(b.Add(b.Truncate(LoadGPR(b, 4), INT16_TYPE), + b.Truncate(LoadGPR(b, 5), INT16_TYPE)), + INT64_TYPE)); b.Return(); }); test.Run( @@ -162,9 +164,10 @@ TEST_CASE("ADD_I16", "[instr]") { TEST_CASE("ADD_I32", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreGPR(b, 3, b.ZeroExtend(b.Add(b.Truncate(LoadGPR(b, 4), INT32_TYPE), - b.Truncate(LoadGPR(b, 5), INT32_TYPE)), - INT64_TYPE)); + StoreGPR(b, 3, + b.ZeroExtend(b.Add(b.Truncate(LoadGPR(b, 4), INT32_TYPE), + b.Truncate(LoadGPR(b, 5), INT32_TYPE)), + INT64_TYPE)); b.Return(); }); test.Run( @@ -304,9 +307,10 @@ TEST_CASE("ADD_I64", "[instr]") { TEST_CASE("ADD_F32", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreFPR(b, 3, b.Convert(b.Add(b.Convert(LoadFPR(b, 4), FLOAT32_TYPE), - b.Convert(LoadFPR(b, 5), FLOAT32_TYPE)), - FLOAT64_TYPE)); + StoreFPR(b, 3, + b.Convert(b.Add(b.Convert(LoadFPR(b, 4), FLOAT32_TYPE), + b.Convert(LoadFPR(b, 5), FLOAT32_TYPE)), + FLOAT64_TYPE)); b.Return(); }); test.Run( diff --git a/src/xenia/cpu/testing/extract_test.cc b/src/xenia/cpu/testing/extract_test.cc index 1dd1318e9..a88e170e6 100644 --- a/src/xenia/cpu/testing/extract_test.cc +++ b/src/xenia/cpu/testing/extract_test.cc @@ -19,10 +19,11 @@ using xe::cpu::ppc::PPCContext; TEST_CASE("EXTRACT_INT8", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreGPR(b, 3, b.ZeroExtend(b.Extract(LoadVR(b, 4), - b.Truncate(LoadGPR(b, 4), INT8_TYPE), - INT8_TYPE), - INT64_TYPE)); + StoreGPR( + b, 3, + b.ZeroExtend(b.Extract(LoadVR(b, 4), + b.Truncate(LoadGPR(b, 4), INT8_TYPE), INT8_TYPE), + INT64_TYPE)); b.Return(); }); for (int i = 0; i < 16; ++i) { @@ -42,9 +43,10 @@ TEST_CASE("EXTRACT_INT8", "[instr]") { TEST_CASE("EXTRACT_INT8_CONSTANT", "[instr]") { for (int i = 0; i < 16; ++i) { TestFunction([i](HIRBuilder& b) { - StoreGPR(b, 3, b.ZeroExtend(b.Extract(LoadVR(b, 4), b.LoadConstantInt8(i), - INT8_TYPE), - INT64_TYPE)); + StoreGPR(b, 3, + b.ZeroExtend( + b.Extract(LoadVR(b, 4), b.LoadConstantInt8(i), INT8_TYPE), + INT64_TYPE)); b.Return(); }) .Run( @@ -62,10 +64,11 @@ TEST_CASE("EXTRACT_INT8_CONSTANT", "[instr]") { TEST_CASE("EXTRACT_INT16", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreGPR(b, 3, b.ZeroExtend(b.Extract(LoadVR(b, 4), - b.Truncate(LoadGPR(b, 4), INT8_TYPE), - INT16_TYPE), - INT64_TYPE)); + StoreGPR(b, 3, + b.ZeroExtend( + b.Extract(LoadVR(b, 4), b.Truncate(LoadGPR(b, 4), INT8_TYPE), + INT16_TYPE), + INT64_TYPE)); b.Return(); }); for (int i = 0; i < 8; ++i) { @@ -85,9 +88,10 @@ TEST_CASE("EXTRACT_INT16", "[instr]") { TEST_CASE("EXTRACT_INT16_CONSTANT", "[instr]") { for (int i = 0; i < 8; ++i) { TestFunction([i](HIRBuilder& b) { - StoreGPR(b, 3, b.ZeroExtend(b.Extract(LoadVR(b, 4), b.LoadConstantInt8(i), - INT16_TYPE), - INT64_TYPE)); + StoreGPR(b, 3, + b.ZeroExtend( + b.Extract(LoadVR(b, 4), b.LoadConstantInt8(i), INT16_TYPE), + INT64_TYPE)); b.Return(); }) .Run( @@ -104,10 +108,11 @@ TEST_CASE("EXTRACT_INT16_CONSTANT", "[instr]") { TEST_CASE("EXTRACT_INT32", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreGPR(b, 3, b.ZeroExtend(b.Extract(LoadVR(b, 4), - b.Truncate(LoadGPR(b, 4), INT8_TYPE), - INT32_TYPE), - INT64_TYPE)); + StoreGPR(b, 3, + b.ZeroExtend( + b.Extract(LoadVR(b, 4), b.Truncate(LoadGPR(b, 4), INT8_TYPE), + INT32_TYPE), + INT64_TYPE)); b.Return(); }); for (int i = 0; i < 4; ++i) { @@ -126,9 +131,10 @@ TEST_CASE("EXTRACT_INT32", "[instr]") { TEST_CASE("EXTRACT_INT32_CONSTANT", "[instr]") { for (int i = 0; i < 4; ++i) { TestFunction([i](HIRBuilder& b) { - StoreGPR(b, 3, b.ZeroExtend(b.Extract(LoadVR(b, 4), b.LoadConstantInt8(i), - INT32_TYPE), - INT64_TYPE)); + StoreGPR(b, 3, + b.ZeroExtend( + b.Extract(LoadVR(b, 4), b.LoadConstantInt8(i), INT32_TYPE), + INT64_TYPE)); b.Return(); }) .Run( diff --git a/src/xenia/cpu/testing/insert_test.cc b/src/xenia/cpu/testing/insert_test.cc index 569608289..2ea2f152c 100644 --- a/src/xenia/cpu/testing/insert_test.cc +++ b/src/xenia/cpu/testing/insert_test.cc @@ -20,8 +20,9 @@ using xe::cpu::ppc::PPCContext; TEST_CASE("INSERT_INT8", "[instr]") { for (int i = 0; i < 16; ++i) { TestFunction test([i](HIRBuilder& b) { - StoreVR(b, 3, b.Insert(LoadVR(b, 4), b.LoadConstantInt32(i), - b.Truncate(LoadGPR(b, 5), INT8_TYPE))); + StoreVR(b, 3, + b.Insert(LoadVR(b, 4), b.LoadConstantInt32(i), + b.Truncate(LoadGPR(b, 5), INT8_TYPE))); b.Return(); }); test.Run( @@ -44,8 +45,9 @@ TEST_CASE("INSERT_INT8", "[instr]") { TEST_CASE("INSERT_INT16", "[instr]") { for (int i = 0; i < 8; ++i) { TestFunction test([i](HIRBuilder& b) { - StoreVR(b, 3, b.Insert(LoadVR(b, 4), b.LoadConstantInt32(i), - b.Truncate(LoadGPR(b, 5), INT16_TYPE))); + StoreVR(b, 3, + b.Insert(LoadVR(b, 4), b.LoadConstantInt32(i), + b.Truncate(LoadGPR(b, 5), INT16_TYPE))); b.Return(); }); test.Run( @@ -66,8 +68,9 @@ TEST_CASE("INSERT_INT16", "[instr]") { TEST_CASE("INSERT_INT32", "[instr]") { for (int i = 0; i < 4; ++i) { TestFunction test([i](HIRBuilder& b) { - StoreVR(b, 3, b.Insert(LoadVR(b, 4), b.LoadConstantInt32(i), - b.Truncate(LoadGPR(b, 5), INT32_TYPE))); + StoreVR(b, 3, + b.Insert(LoadVR(b, 4), b.LoadConstantInt32(i), + b.Truncate(LoadGPR(b, 5), INT32_TYPE))); b.Return(); }); test.Run( diff --git a/src/xenia/cpu/testing/permute_test.cc b/src/xenia/cpu/testing/permute_test.cc index df2afc8fd..9df8356d4 100644 --- a/src/xenia/cpu/testing/permute_test.cc +++ b/src/xenia/cpu/testing/permute_test.cc @@ -19,8 +19,9 @@ TEST_CASE("PERMUTE_V128_BY_INT32_CONSTANT", "[instr]") { { uint32_t mask = MakePermuteMask(0, 0, 0, 1, 0, 2, 0, 3); TestFunction([mask](HIRBuilder& b) { - StoreVR(b, 3, b.Permute(b.LoadConstantUint32(mask), LoadVR(b, 4), - LoadVR(b, 5), INT32_TYPE)); + StoreVR(b, 3, + b.Permute(b.LoadConstantUint32(mask), LoadVR(b, 4), LoadVR(b, 5), + INT32_TYPE)); b.Return(); }) .Run( @@ -36,8 +37,9 @@ TEST_CASE("PERMUTE_V128_BY_INT32_CONSTANT", "[instr]") { { uint32_t mask = MakePermuteMask(1, 0, 1, 1, 1, 2, 1, 3); TestFunction([mask](HIRBuilder& b) { - StoreVR(b, 3, b.Permute(b.LoadConstantUint32(mask), LoadVR(b, 4), - LoadVR(b, 5), INT32_TYPE)); + StoreVR(b, 3, + b.Permute(b.LoadConstantUint32(mask), LoadVR(b, 4), LoadVR(b, 5), + INT32_TYPE)); b.Return(); }) .Run( @@ -53,8 +55,9 @@ TEST_CASE("PERMUTE_V128_BY_INT32_CONSTANT", "[instr]") { { uint32_t mask = MakePermuteMask(0, 3, 0, 2, 0, 1, 0, 0); TestFunction([mask](HIRBuilder& b) { - StoreVR(b, 3, b.Permute(b.LoadConstantUint32(mask), LoadVR(b, 4), - LoadVR(b, 5), INT32_TYPE)); + StoreVR(b, 3, + b.Permute(b.LoadConstantUint32(mask), LoadVR(b, 4), LoadVR(b, 5), + INT32_TYPE)); b.Return(); }) .Run( @@ -70,8 +73,9 @@ TEST_CASE("PERMUTE_V128_BY_INT32_CONSTANT", "[instr]") { { uint32_t mask = MakePermuteMask(1, 3, 1, 2, 1, 1, 1, 0); TestFunction([mask](HIRBuilder& b) { - StoreVR(b, 3, b.Permute(b.LoadConstantUint32(mask), LoadVR(b, 4), - LoadVR(b, 5), INT32_TYPE)); + StoreVR(b, 3, + b.Permute(b.LoadConstantUint32(mask), LoadVR(b, 4), LoadVR(b, 5), + INT32_TYPE)); b.Return(); }) .Run( diff --git a/src/xenia/cpu/testing/sandbox_main.cc b/src/xenia/cpu/testing/sandbox_main.cc index 28596e7a0..9aedbf288 100644 --- a/src/xenia/cpu/testing/sandbox_main.cc +++ b/src/xenia/cpu/testing/sandbox_main.cc @@ -20,8 +20,8 @@ namespace xe { namespace cpu { namespace sandbox { -using xe::cpu::ppc::PPCContext; using xe::cpu::Runtime; +using xe::cpu::ppc::PPCContext; // TODO(benvanik): simple memory? move more into core? diff --git a/src/xenia/cpu/testing/sha_test.cc b/src/xenia/cpu/testing/sha_test.cc index 4382597b5..6e83aaa2f 100644 --- a/src/xenia/cpu/testing/sha_test.cc +++ b/src/xenia/cpu/testing/sha_test.cc @@ -16,9 +16,10 @@ using xe::cpu::ppc::PPCContext; TEST_CASE("SHA_I8", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreGPR(b, 3, b.ZeroExtend(b.Sha(b.Truncate(LoadGPR(b, 4), INT8_TYPE), - b.Truncate(LoadGPR(b, 5), INT8_TYPE)), - INT64_TYPE)); + StoreGPR(b, 3, + b.ZeroExtend(b.Sha(b.Truncate(LoadGPR(b, 4), INT8_TYPE), + b.Truncate(LoadGPR(b, 5), INT8_TYPE)), + INT64_TYPE)); b.Return(); }); test.Run( @@ -70,9 +71,10 @@ TEST_CASE("SHA_I8", "[instr]") { TEST_CASE("SHA_I16", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreGPR(b, 3, b.ZeroExtend(b.Sha(b.Truncate(LoadGPR(b, 4), INT16_TYPE), - b.Truncate(LoadGPR(b, 5), INT8_TYPE)), - INT64_TYPE)); + StoreGPR(b, 3, + b.ZeroExtend(b.Sha(b.Truncate(LoadGPR(b, 4), INT16_TYPE), + b.Truncate(LoadGPR(b, 5), INT8_TYPE)), + INT64_TYPE)); b.Return(); }); test.Run( @@ -124,9 +126,10 @@ TEST_CASE("SHA_I16", "[instr]") { TEST_CASE("SHA_I32", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreGPR(b, 3, b.ZeroExtend(b.Sha(b.Truncate(LoadGPR(b, 4), INT32_TYPE), - b.Truncate(LoadGPR(b, 5), INT8_TYPE)), - INT64_TYPE)); + StoreGPR(b, 3, + b.ZeroExtend(b.Sha(b.Truncate(LoadGPR(b, 4), INT32_TYPE), + b.Truncate(LoadGPR(b, 5), INT8_TYPE)), + INT64_TYPE)); b.Return(); }); test.Run( @@ -178,8 +181,9 @@ TEST_CASE("SHA_I32", "[instr]") { TEST_CASE("SHA_I64", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreGPR(b, 3, b.Sha(b.Truncate(LoadGPR(b, 4), INT64_TYPE), - b.Truncate(LoadGPR(b, 5), INT8_TYPE))); + StoreGPR(b, 3, + b.Sha(b.Truncate(LoadGPR(b, 4), INT64_TYPE), + b.Truncate(LoadGPR(b, 5), INT8_TYPE))); b.Return(); }); test.Run( diff --git a/src/xenia/cpu/testing/shl_test.cc b/src/xenia/cpu/testing/shl_test.cc index d42ba6d26..d63ddf5a0 100644 --- a/src/xenia/cpu/testing/shl_test.cc +++ b/src/xenia/cpu/testing/shl_test.cc @@ -16,9 +16,10 @@ using xe::cpu::ppc::PPCContext; TEST_CASE("SHL_I8", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreGPR(b, 3, b.ZeroExtend(b.Shl(b.Truncate(LoadGPR(b, 4), INT8_TYPE), - b.Truncate(LoadGPR(b, 5), INT8_TYPE)), - INT64_TYPE)); + StoreGPR(b, 3, + b.ZeroExtend(b.Shl(b.Truncate(LoadGPR(b, 4), INT8_TYPE), + b.Truncate(LoadGPR(b, 5), INT8_TYPE)), + INT64_TYPE)); b.Return(); }); test.Run( @@ -70,9 +71,10 @@ TEST_CASE("SHL_I8", "[instr]") { TEST_CASE("SHL_I16", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreGPR(b, 3, b.ZeroExtend(b.Shl(b.Truncate(LoadGPR(b, 4), INT16_TYPE), - b.Truncate(LoadGPR(b, 5), INT8_TYPE)), - INT64_TYPE)); + StoreGPR(b, 3, + b.ZeroExtend(b.Shl(b.Truncate(LoadGPR(b, 4), INT16_TYPE), + b.Truncate(LoadGPR(b, 5), INT8_TYPE)), + INT64_TYPE)); b.Return(); }); test.Run( @@ -124,9 +126,10 @@ TEST_CASE("SHL_I16", "[instr]") { TEST_CASE("SHL_I32", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreGPR(b, 3, b.ZeroExtend(b.Shl(b.Truncate(LoadGPR(b, 4), INT32_TYPE), - b.Truncate(LoadGPR(b, 5), INT8_TYPE)), - INT64_TYPE)); + StoreGPR(b, 3, + b.ZeroExtend(b.Shl(b.Truncate(LoadGPR(b, 4), INT32_TYPE), + b.Truncate(LoadGPR(b, 5), INT8_TYPE)), + INT64_TYPE)); b.Return(); }); test.Run( @@ -178,8 +181,9 @@ TEST_CASE("SHL_I32", "[instr]") { TEST_CASE("SHL_I64", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreGPR(b, 3, b.Shl(b.Truncate(LoadGPR(b, 4), INT64_TYPE), - b.Truncate(LoadGPR(b, 5), INT8_TYPE))); + StoreGPR(b, 3, + b.Shl(b.Truncate(LoadGPR(b, 4), INT64_TYPE), + b.Truncate(LoadGPR(b, 5), INT8_TYPE))); b.Return(); }); test.Run( diff --git a/src/xenia/cpu/testing/shr_test.cc b/src/xenia/cpu/testing/shr_test.cc index c90ef2005..211dd9416 100644 --- a/src/xenia/cpu/testing/shr_test.cc +++ b/src/xenia/cpu/testing/shr_test.cc @@ -17,9 +17,10 @@ using xe::cpu::ppc::PPCContext; TEST_CASE("SHR_I8", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreGPR(b, 3, b.ZeroExtend(b.Shr(b.Truncate(LoadGPR(b, 4), INT8_TYPE), - b.Truncate(LoadGPR(b, 5), INT8_TYPE)), - INT64_TYPE)); + StoreGPR(b, 3, + b.ZeroExtend(b.Shr(b.Truncate(LoadGPR(b, 4), INT8_TYPE), + b.Truncate(LoadGPR(b, 5), INT8_TYPE)), + INT64_TYPE)); b.Return(); }); test.Run( @@ -71,9 +72,10 @@ TEST_CASE("SHR_I8", "[instr]") { TEST_CASE("SHR_I16", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreGPR(b, 3, b.ZeroExtend(b.Shr(b.Truncate(LoadGPR(b, 4), INT16_TYPE), - b.Truncate(LoadGPR(b, 5), INT8_TYPE)), - INT64_TYPE)); + StoreGPR(b, 3, + b.ZeroExtend(b.Shr(b.Truncate(LoadGPR(b, 4), INT16_TYPE), + b.Truncate(LoadGPR(b, 5), INT8_TYPE)), + INT64_TYPE)); b.Return(); }); test.Run( @@ -125,9 +127,10 @@ TEST_CASE("SHR_I16", "[instr]") { TEST_CASE("SHR_I32", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreGPR(b, 3, b.ZeroExtend(b.Shr(b.Truncate(LoadGPR(b, 4), INT32_TYPE), - b.Truncate(LoadGPR(b, 5), INT8_TYPE)), - INT64_TYPE)); + StoreGPR(b, 3, + b.ZeroExtend(b.Shr(b.Truncate(LoadGPR(b, 4), INT32_TYPE), + b.Truncate(LoadGPR(b, 5), INT8_TYPE)), + INT64_TYPE)); b.Return(); }); test.Run( @@ -179,8 +182,9 @@ TEST_CASE("SHR_I32", "[instr]") { TEST_CASE("SHR_I64", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreGPR(b, 3, b.Shr(b.Truncate(LoadGPR(b, 4), INT64_TYPE), - b.Truncate(LoadGPR(b, 5), INT8_TYPE))); + StoreGPR(b, 3, + b.Shr(b.Truncate(LoadGPR(b, 4), INT64_TYPE), + b.Truncate(LoadGPR(b, 5), INT8_TYPE))); b.Return(); }); test.Run( diff --git a/src/xenia/cpu/testing/vector_add_test.cc b/src/xenia/cpu/testing/vector_add_test.cc index 26e4e9877..dd2f66682 100644 --- a/src/xenia/cpu/testing/vector_add_test.cc +++ b/src/xenia/cpu/testing/vector_add_test.cc @@ -47,8 +47,9 @@ TEST_CASE("VECTOR_ADD_I8", "[instr]") { TEST_CASE("VECTOR_ADD_I8_SAT_SIGNED", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreVR(b, 3, b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), INT8_TYPE, - ARITHMETIC_SATURATE)); + StoreVR(b, 3, + b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), INT8_TYPE, + ARITHMETIC_SATURATE)); b.Return(); }); test.Run( @@ -73,8 +74,9 @@ TEST_CASE("VECTOR_ADD_I8_SAT_SIGNED", "[instr]") { TEST_CASE("VECTOR_ADD_I8_SAT_UNSIGNED", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreVR(b, 3, b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), INT8_TYPE, - ARITHMETIC_SATURATE | ARITHMETIC_UNSIGNED)); + StoreVR(b, 3, + b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), INT8_TYPE, + ARITHMETIC_SATURATE | ARITHMETIC_UNSIGNED)); b.Return(); }); test.Run( @@ -124,8 +126,9 @@ TEST_CASE("VECTOR_ADD_I16", "[instr]") { TEST_CASE("VECTOR_ADD_I16_SAT_SIGNED", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreVR(b, 3, b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), INT16_TYPE, - ARITHMETIC_SATURATE)); + StoreVR(b, 3, + b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), INT16_TYPE, + ARITHMETIC_SATURATE)); b.Return(); }); test.Run( @@ -150,8 +153,9 @@ TEST_CASE("VECTOR_ADD_I16_SAT_SIGNED", "[instr]") { TEST_CASE("VECTOR_ADD_I16_SAT_UNSIGNED", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreVR(b, 3, b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), INT16_TYPE, - ARITHMETIC_SATURATE | ARITHMETIC_UNSIGNED)); + StoreVR(b, 3, + b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), INT16_TYPE, + ARITHMETIC_SATURATE | ARITHMETIC_UNSIGNED)); b.Return(); }); test.Run( @@ -201,8 +205,9 @@ TEST_CASE("VECTOR_ADD_I32", "[instr]") { TEST_CASE("VECTOR_ADD_I32_SAT_SIGNED", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreVR(b, 3, b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), INT32_TYPE, - ARITHMETIC_SATURATE)); + StoreVR(b, 3, + b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), INT32_TYPE, + ARITHMETIC_SATURATE)); b.Return(); }); test.Run( @@ -236,8 +241,9 @@ TEST_CASE("VECTOR_ADD_I32_SAT_SIGNED", "[instr]") { TEST_CASE("VECTOR_ADD_I32_SAT_UNSIGNED", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreVR(b, 3, b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), INT32_TYPE, - ARITHMETIC_SATURATE | ARITHMETIC_UNSIGNED)); + StoreVR(b, 3, + b.VectorAdd(LoadVR(b, 4), LoadVR(b, 5), INT32_TYPE, + ARITHMETIC_SATURATE | ARITHMETIC_UNSIGNED)); b.Return(); }); test.Run( diff --git a/src/xenia/cpu/testing/vector_max_test.cc b/src/xenia/cpu/testing/vector_max_test.cc index eba85a653..0cb35b180 100644 --- a/src/xenia/cpu/testing/vector_max_test.cc +++ b/src/xenia/cpu/testing/vector_max_test.cc @@ -39,8 +39,9 @@ TEST_CASE("VECTOR_MAX_I8_SIGNED", "[instr]") { TEST_CASE("VECTOR_MAX_I8_UNSIGNED", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreVR(b, 3, b.VectorMax(LoadVR(b, 4), LoadVR(b, 5), INT8_TYPE, - ARITHMETIC_UNSIGNED)); + StoreVR(b, 3, + b.VectorMax(LoadVR(b, 4), LoadVR(b, 5), INT8_TYPE, + ARITHMETIC_UNSIGNED)); b.Return(); }); test.Run( @@ -75,8 +76,9 @@ TEST_CASE("VECTOR_MAX_I16_SIGNED", "[instr]") { TEST_CASE("VECTOR_MAX_I16_UNSIGNED", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreVR(b, 3, b.VectorMax(LoadVR(b, 4), LoadVR(b, 5), INT16_TYPE, - ARITHMETIC_UNSIGNED)); + StoreVR(b, 3, + b.VectorMax(LoadVR(b, 4), LoadVR(b, 5), INT16_TYPE, + ARITHMETIC_UNSIGNED)); b.Return(); }); test.Run( @@ -108,8 +110,9 @@ TEST_CASE("VECTOR_MAX_I32_SIGNED", "[instr]") { TEST_CASE("VECTOR_MAX_I32_UNSIGNED", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreVR(b, 3, b.VectorMax(LoadVR(b, 4), LoadVR(b, 5), INT32_TYPE, - ARITHMETIC_UNSIGNED)); + StoreVR(b, 3, + b.VectorMax(LoadVR(b, 4), LoadVR(b, 5), INT32_TYPE, + ARITHMETIC_UNSIGNED)); b.Return(); }); test.Run( diff --git a/src/xenia/cpu/testing/vector_min_test.cc b/src/xenia/cpu/testing/vector_min_test.cc index 6d54c3ef7..2301e5393 100644 --- a/src/xenia/cpu/testing/vector_min_test.cc +++ b/src/xenia/cpu/testing/vector_min_test.cc @@ -39,8 +39,9 @@ TEST_CASE("VECTOR_MIN_I8_SIGNED", "[instr]") { TEST_CASE("VECTOR_MIN_I8_UNSIGNED", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreVR(b, 3, b.VectorMin(LoadVR(b, 4), LoadVR(b, 5), INT8_TYPE, - ARITHMETIC_UNSIGNED)); + StoreVR(b, 3, + b.VectorMin(LoadVR(b, 4), LoadVR(b, 5), INT8_TYPE, + ARITHMETIC_UNSIGNED)); b.Return(); }); test.Run( @@ -75,8 +76,9 @@ TEST_CASE("VECTOR_MIN_I16_SIGNED", "[instr]") { TEST_CASE("VECTOR_MIN_I16_UNSIGNED", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreVR(b, 3, b.VectorMin(LoadVR(b, 4), LoadVR(b, 5), INT16_TYPE, - ARITHMETIC_UNSIGNED)); + StoreVR(b, 3, + b.VectorMin(LoadVR(b, 4), LoadVR(b, 5), INT16_TYPE, + ARITHMETIC_UNSIGNED)); b.Return(); }); test.Run( @@ -108,8 +110,9 @@ TEST_CASE("VECTOR_MIN_I32_SIGNED", "[instr]") { TEST_CASE("VECTOR_MIN_I32_UNSIGNED", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreVR(b, 3, b.VectorMin(LoadVR(b, 4), LoadVR(b, 5), INT32_TYPE, - ARITHMETIC_UNSIGNED)); + StoreVR(b, 3, + b.VectorMin(LoadVR(b, 4), LoadVR(b, 5), INT32_TYPE, + ARITHMETIC_UNSIGNED)); b.Return(); }); test.Run( diff --git a/src/xenia/cpu/testing/vector_sha_test.cc b/src/xenia/cpu/testing/vector_sha_test.cc index fe891ce98..5b4adabc6 100644 --- a/src/xenia/cpu/testing/vector_sha_test.cc +++ b/src/xenia/cpu/testing/vector_sha_test.cc @@ -37,10 +37,12 @@ TEST_CASE("VECTOR_SHA_I8", "[instr]") { TEST_CASE("VECTOR_SHA_I8_CONSTANT", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreVR(b, 3, b.VectorSha(LoadVR(b, 4), b.LoadConstantVec128(vec128b( - 0, 1, 2, 8, 4, 4, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15)), - INT8_TYPE)); + StoreVR( + b, 3, + b.VectorSha(LoadVR(b, 4), + b.LoadConstantVec128(vec128b(0, 1, 2, 8, 4, 4, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15)), + INT8_TYPE)); b.Return(); }); test.Run( @@ -76,9 +78,11 @@ TEST_CASE("VECTOR_SHA_I16", "[instr]") { TEST_CASE("VECTOR_SHA_I16_CONSTANT", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreVR(b, 3, b.VectorSha(LoadVR(b, 4), b.LoadConstantVec128(vec128s( - 0, 1, 8, 15, 15, 8, 1, 16)), - INT16_TYPE)); + StoreVR( + b, 3, + b.VectorSha(LoadVR(b, 4), + b.LoadConstantVec128(vec128s(0, 1, 8, 15, 15, 8, 1, 16)), + INT16_TYPE)); b.Return(); }); test.Run( @@ -122,12 +126,14 @@ TEST_CASE("VECTOR_SHA_I32", "[instr]") { TEST_CASE("VECTOR_SHA_I32_CONSTANT", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreVR(b, 3, b.VectorSha(LoadVR(b, 4), - b.LoadConstantVec128(vec128i(0, 1, 16, 31)), - INT32_TYPE)); - StoreVR(b, 4, b.VectorSha(LoadVR(b, 5), - b.LoadConstantVec128(vec128i(31, 16, 1, 32)), - INT32_TYPE)); + StoreVR( + b, 3, + b.VectorSha(LoadVR(b, 4), b.LoadConstantVec128(vec128i(0, 1, 16, 31)), + INT32_TYPE)); + StoreVR( + b, 4, + b.VectorSha(LoadVR(b, 5), b.LoadConstantVec128(vec128i(31, 16, 1, 32)), + INT32_TYPE)); b.Return(); }); test.Run( diff --git a/src/xenia/cpu/testing/vector_shl_test.cc b/src/xenia/cpu/testing/vector_shl_test.cc index 663c961a6..cdf61c4f8 100644 --- a/src/xenia/cpu/testing/vector_shl_test.cc +++ b/src/xenia/cpu/testing/vector_shl_test.cc @@ -37,10 +37,12 @@ TEST_CASE("VECTOR_SHL_I8", "[instr]") { TEST_CASE("VECTOR_SHL_I8_CONSTANT", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreVR(b, 3, b.VectorShl(LoadVR(b, 4), b.LoadConstantVec128(vec128b( - 0, 1, 2, 8, 4, 4, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15)), - INT8_TYPE)); + StoreVR( + b, 3, + b.VectorShl(LoadVR(b, 4), + b.LoadConstantVec128(vec128b(0, 1, 2, 8, 4, 4, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15)), + INT8_TYPE)); b.Return(); }); test.Run( @@ -76,9 +78,11 @@ TEST_CASE("VECTOR_SHL_I16", "[instr]") { TEST_CASE("VECTOR_SHL_I16_CONSTANT", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreVR(b, 3, b.VectorShl(LoadVR(b, 4), b.LoadConstantVec128(vec128s( - 0, 1, 8, 15, 15, 8, 1, 16)), - INT16_TYPE)); + StoreVR( + b, 3, + b.VectorShl(LoadVR(b, 4), + b.LoadConstantVec128(vec128s(0, 1, 8, 15, 15, 8, 1, 16)), + INT16_TYPE)); b.Return(); }); test.Run( @@ -122,12 +126,14 @@ TEST_CASE("VECTOR_SHL_I32", "[instr]") { TEST_CASE("VECTOR_SHL_I32_CONSTANT", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreVR(b, 3, b.VectorShl(LoadVR(b, 4), - b.LoadConstantVec128(vec128i(0, 1, 16, 31)), - INT32_TYPE)); - StoreVR(b, 4, b.VectorShl(LoadVR(b, 5), - b.LoadConstantVec128(vec128i(31, 16, 1, 32)), - INT32_TYPE)); + StoreVR( + b, 3, + b.VectorShl(LoadVR(b, 4), b.LoadConstantVec128(vec128i(0, 1, 16, 31)), + INT32_TYPE)); + StoreVR( + b, 4, + b.VectorShl(LoadVR(b, 5), b.LoadConstantVec128(vec128i(31, 16, 1, 32)), + INT32_TYPE)); b.Return(); }); test.Run( diff --git a/src/xenia/cpu/testing/vector_shr_test.cc b/src/xenia/cpu/testing/vector_shr_test.cc index 0cb1947b7..8ee36ce73 100644 --- a/src/xenia/cpu/testing/vector_shr_test.cc +++ b/src/xenia/cpu/testing/vector_shr_test.cc @@ -37,10 +37,12 @@ TEST_CASE("VECTOR_SHR_I8", "[instr]") { TEST_CASE("VECTOR_SHR_I8_CONSTANT", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreVR(b, 3, b.VectorShr(LoadVR(b, 4), b.LoadConstantVec128(vec128b( - 0, 1, 2, 8, 4, 4, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15)), - INT8_TYPE)); + StoreVR( + b, 3, + b.VectorShr(LoadVR(b, 4), + b.LoadConstantVec128(vec128b(0, 1, 2, 8, 4, 4, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15)), + INT8_TYPE)); b.Return(); }); test.Run( @@ -76,9 +78,11 @@ TEST_CASE("VECTOR_SHR_I16", "[instr]") { TEST_CASE("VECTOR_SHR_I16_CONSTANT", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreVR(b, 3, b.VectorShr(LoadVR(b, 4), b.LoadConstantVec128(vec128s( - 0, 1, 8, 15, 15, 8, 1, 16)), - INT16_TYPE)); + StoreVR( + b, 3, + b.VectorShr(LoadVR(b, 4), + b.LoadConstantVec128(vec128s(0, 1, 8, 15, 15, 8, 1, 16)), + INT16_TYPE)); b.Return(); }); test.Run( @@ -122,12 +126,14 @@ TEST_CASE("VECTOR_SHR_I32", "[instr]") { TEST_CASE("VECTOR_SHR_I32_CONSTANT", "[instr]") { TestFunction test([](HIRBuilder& b) { - StoreVR(b, 3, b.VectorShr(LoadVR(b, 4), - b.LoadConstantVec128(vec128i(0, 1, 16, 31)), - INT32_TYPE)); - StoreVR(b, 4, b.VectorShr(LoadVR(b, 5), - b.LoadConstantVec128(vec128i(31, 16, 1, 32)), - INT32_TYPE)); + StoreVR( + b, 3, + b.VectorShr(LoadVR(b, 4), b.LoadConstantVec128(vec128i(0, 1, 16, 31)), + INT32_TYPE)); + StoreVR( + b, 4, + b.VectorShr(LoadVR(b, 5), b.LoadConstantVec128(vec128i(31, 16, 1, 32)), + INT32_TYPE)); b.Return(); }); test.Run( diff --git a/src/xenia/debug/ui/debug_window.cc b/src/xenia/debug/ui/debug_window.cc index 27195d94d..8db24092b 100644 --- a/src/xenia/debug/ui/debug_window.cc +++ b/src/xenia/debug/ui/debug_window.cc @@ -395,7 +395,10 @@ void DebugWindow::DrawSourcePane() { ImGui::SameLine(); if (function->is_guest()) { const char* kSourceDisplayModes[] = { - "PPC", "PPC+HIR+x64", "PPC+HIR (opt)+x64", "PPC+x64", + "PPC", + "PPC+HIR+x64", + "PPC+HIR (opt)+x64", + "PPC+x64", }; ImGui::PushItemWidth(90); ImGui::Combo("##display_mode", &state_.source_display_mode, @@ -1338,8 +1341,9 @@ void DebugWindow::DrawBreakpointsPane() { function->MapGuestAddressToMachineCode( breakpoint->guest_address())); } else { - NavigateToFunction(function, function->MapMachineCodeToGuestAddress( - breakpoint->host_address()), + NavigateToFunction(function, + function->MapMachineCodeToGuestAddress( + breakpoint->host_address()), breakpoint->host_address()); } } diff --git a/src/xenia/gpu/gl4/gl4_command_processor.cc b/src/xenia/gpu/gl4/gl4_command_processor.cc index f552178d2..5392c22d2 100644 --- a/src/xenia/gpu/gl4/gl4_command_processor.cc +++ b/src/xenia/gpu/gl4/gl4_command_processor.cc @@ -782,7 +782,9 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::UpdateRenderTargets() { GLuint color_targets[4] = {kAnyTarget, kAnyTarget, kAnyTarget, kAnyTarget}; if (enable_mode == ModeControl::kColorDepth) { uint32_t color_info[4] = { - regs.rb_color_info, regs.rb_color1_info, regs.rb_color2_info, + regs.rb_color_info, + regs.rb_color1_info, + regs.rb_color2_info, regs.rb_color3_info, }; // A2XX_RB_COLOR_MASK_WRITE_* == D3DRS_COLORWRITEENABLE @@ -1099,7 +1101,9 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::UpdateRasterizerState( } static const GLenum kFillModes[3] = { - GL_POINT, GL_LINE, GL_FILL, + GL_POINT, + GL_LINE, + GL_FILL, }; bool poly_mode = ((regs.pa_su_sc_mode_cntl >> 3) & 0x3) != 0; if (poly_mode) { @@ -1590,7 +1594,8 @@ bool GL4CommandProcessor::IssueCopy() { if (copy_src_select <= 3 || color_clear_enabled) { // Source from a color target. uint32_t color_info[4] = { - regs[XE_GPU_REG_RB_COLOR_INFO].u32, regs[XE_GPU_REG_RB_COLOR1_INFO].u32, + regs[XE_GPU_REG_RB_COLOR_INFO].u32, + regs[XE_GPU_REG_RB_COLOR1_INFO].u32, regs[XE_GPU_REG_RB_COLOR2_INFO].u32, regs[XE_GPU_REG_RB_COLOR3_INFO].u32, }; diff --git a/src/xenia/gpu/gl4/gl4_shader_cache.cc b/src/xenia/gpu/gl4/gl4_shader_cache.cc index 033ed1b5e..714de3e1d 100644 --- a/src/xenia/gpu/gl4/gl4_shader_cache.cc +++ b/src/xenia/gpu/gl4/gl4_shader_cache.cc @@ -184,4 +184,4 @@ GL4Shader* GL4ShaderCache::FindCachedShader(ShaderType shader_type, } // namespace gl4 } // namespace gpu -} // namespace xe \ No newline at end of file +} // namespace xe diff --git a/src/xenia/gpu/gl4/gl4_shader_cache.h b/src/xenia/gpu/gl4/gl4_shader_cache.h index 7bac4c084..9c5c77cb2 100644 --- a/src/xenia/gpu/gl4/gl4_shader_cache.h +++ b/src/xenia/gpu/gl4/gl4_shader_cache.h @@ -11,8 +11,10 @@ #define XENIA_GPU_GL4_SHADER_CACHE_H_ #include +#include #include #include +#include #include "xenia/gpu/xenos.h" @@ -57,4 +59,4 @@ class GL4ShaderCache { } // namespace gpu } // namespace xe -#endif // XENIA_GPU_GL4_SHADER_CACHE_H_ \ No newline at end of file +#endif // XENIA_GPU_GL4_SHADER_CACHE_H_ diff --git a/src/xenia/gpu/gl4/texture_cache.cc b/src/xenia/gpu/gl4/texture_cache.cc index 65497c9e8..affd012bd 100644 --- a/src/xenia/gpu/gl4/texture_cache.cc +++ b/src/xenia/gpu/gl4/texture_cache.cc @@ -940,8 +940,9 @@ bool TextureCache::UploadTexture2D(GLuint texture, texture_info.size_2d.logical_height); y++, output_base_offset += host_info.size_2d.output_pitch) { auto input_base_offset = TextureInfo::TiledOffset2DOuter( - offset_y + y, (texture_info.size_2d.input_width / - texture_info.format_info()->block_width), + offset_y + y, + (texture_info.size_2d.input_width / + texture_info.format_info()->block_width), bpp); for (uint32_t x = 0, output_offset = output_base_offset; x < texture_info.size_2d.block_width; @@ -1048,8 +1049,9 @@ bool TextureCache::UploadTextureCube(GLuint texture, y < texture_info.size_cube.block_height; y++, output_base_offset += host_info.size_cube.output_pitch) { auto input_base_offset = TextureInfo::TiledOffset2DOuter( - offset_y + y, (texture_info.size_cube.input_width / - texture_info.format_info()->block_width), + offset_y + y, + (texture_info.size_cube.input_width / + texture_info.format_info()->block_width), bpp); for (uint32_t x = 0, output_offset = output_base_offset; x < texture_info.size_cube.block_width; diff --git a/src/xenia/gpu/graphics_system.cc b/src/xenia/gpu/graphics_system.cc index be8cd633c..8dfb9250f 100644 --- a/src/xenia/gpu/graphics_system.cc +++ b/src/xenia/gpu/graphics_system.cc @@ -159,8 +159,8 @@ uint32_t GraphicsSystem::ReadRegister(uint32_t addr) { case 0x1951: // ? vblank pending? return 1; case 0x1961: // AVIVO_D1MODE_VIEWPORT_SIZE - // Screen res - 1280x720 - // [width(0x0FFF), height(0x0FFF)] + // Screen res - 1280x720 + // [width(0x0FFF), height(0x0FFF)] return 0x050002D0; default: if (!register_file_.GetRegisterInfo(r)) { diff --git a/src/xenia/gpu/register_file.cc b/src/xenia/gpu/register_file.cc index 9346fde52..f65d5d87c 100644 --- a/src/xenia/gpu/register_file.cc +++ b/src/xenia/gpu/register_file.cc @@ -23,7 +23,8 @@ const RegisterInfo* RegisterFile::GetRegisterInfo(uint32_t index) { #define XE_GPU_REGISTER(index, type, name) \ case index: { \ static const RegisterInfo reg_info = { \ - RegisterInfo::Type::type, #name, \ + RegisterInfo::Type::type, \ + #name, \ }; \ return ®_info; \ } diff --git a/src/xenia/gpu/shader_translator_disasm.cc b/src/xenia/gpu/shader_translator_disasm.cc index 8e1bdb996..b36267fb4 100644 --- a/src/xenia/gpu/shader_translator_disasm.cc +++ b/src/xenia/gpu/shader_translator_disasm.cc @@ -356,7 +356,10 @@ void ParsedVertexFetchInstruction::Disassemble(StringBuffer* out) const { void ParsedTextureFetchInstruction::Disassemble(StringBuffer* out) const { static const char* kTextureFilterNames[] = { - "point", "linear", "BASEMAP", "keep", + "point", + "linear", + "BASEMAP", + "keep", }; static const char* kAnisoFilterNames[] = { "disabled", "max1to1", "max2to1", "max4to1", diff --git a/src/xenia/gpu/spirv_shader_translator.cc b/src/xenia/gpu/spirv_shader_translator.cc index bfccc052c..0b24a47c4 100644 --- a/src/xenia/gpu/spirv_shader_translator.cc +++ b/src/xenia/gpu/spirv_shader_translator.cc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2016 Ben Vanik. All rights reserved. * + * Copyright 2017 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -13,6 +13,7 @@ #include #include +#include #include "xenia/base/logging.h" #include "xenia/gpu/spirv/passes/control_flow_analysis_pass.h" @@ -337,8 +338,7 @@ void SpirvShaderTranslator::StartTranslation() { registers_ptr_, std::vector({b.makeUintConstant(0)})); auto r0 = b.createLoad(r0_ptr); - r0 = b.createCompositeInsert(vertex_idx, r0, vec4_float_type_, - std::vector({0})); + r0 = b.createCompositeInsert(vertex_idx, r0, vec4_float_type_, 0); b.createStore(r0, r0_ptr); } else { // Pixel inputs from vertex shader. diff --git a/src/xenia/gpu/trace_viewer.cc b/src/xenia/gpu/trace_viewer.cc index bf3821228..b7fb91ca3 100644 --- a/src/xenia/gpu/trace_viewer.cc +++ b/src/xenia/gpu/trace_viewer.cc @@ -950,9 +950,8 @@ void TraceViewer::DrawVertexFetcher(Shader* shader, } } ImGui::Columns(1); - ImGui::SetCursorPosY(ImGui::GetCursorPosY() + - (vertex_count - display_end) * - ImGui::GetTextLineHeight()); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (vertex_count - display_end) * + ImGui::GetTextLineHeight()); ImGui::PopStyleVar(); ImGui::EndChild(); } @@ -971,10 +970,14 @@ static const char* kStencilFuncNames[] = { "Decrement and Clamp", }; static const char* kIndexFormatNames[] = { - "uint16", "uint32", + "uint16", + "uint32", }; static const char* kEndiannessNames[] = { - "unspecified endianness", "8-in-16", "8-in-32", "16-in-32", + "unspecified endianness", + "8-in-16", + "8-in-32", + "16-in-32", }; static const char* kColorFormatNames[] = { /* 0 */ "k_8_8_8_8", @@ -995,7 +998,8 @@ static const char* kColorFormatNames[] = { /* 15 */ "k_32_32_FLOAT", }; static const char* kDepthFormatNames[] = { - "kD24S8", "kD24FS8", + "kD24S8", + "kD24FS8", }; void ProgressBar(float frac, float width, float height = 0, @@ -1185,7 +1189,9 @@ void TraceViewer::DrawStateUI() { uint32_t surface_pitch = surface_info & 0x3FFF; auto surface_msaa = (surface_info >> 16) & 0x3; static const char* kMsaaNames[] = { - "1X", "2X", "4X", + "1X", + "2X", + "4X", }; ImGui::BulletText("Surface Pitch: %d", surface_pitch); ImGui::BulletText("Surface HI-Z Pitch: %d", surface_hiz); @@ -1270,7 +1276,9 @@ void TraceViewer::DrawStateUI() { ImGui::BulletText("Front-face: counter-clockwise"); } static const char* kFillModeNames[3] = { - "point", "line", "fill", + "point", + "line", + "fill", }; bool poly_mode = ((pa_su_sc_mode_cntl >> 3) & 0x3) != 0; if (poly_mode) { diff --git a/src/xenia/gpu/trace_writer.cc b/src/xenia/gpu/trace_writer.cc index 51fab9763..819029b3d 100644 --- a/src/xenia/gpu/trace_writer.cc +++ b/src/xenia/gpu/trace_writer.cc @@ -72,7 +72,9 @@ void TraceWriter::WritePrimaryBufferStart(uint32_t base_ptr, uint32_t count) { return; } PrimaryBufferStartCommand cmd = { - TraceCommandType::kPrimaryBufferStart, base_ptr, 0, + TraceCommandType::kPrimaryBufferStart, + base_ptr, + 0, }; fwrite(&cmd, 1, sizeof(cmd), file_); } @@ -92,7 +94,9 @@ void TraceWriter::WriteIndirectBufferStart(uint32_t base_ptr, uint32_t count) { return; } IndirectBufferStartCommand cmd = { - TraceCommandType::kIndirectBufferStart, base_ptr, 0, + TraceCommandType::kIndirectBufferStart, + base_ptr, + 0, }; fwrite(&cmd, 1, sizeof(cmd), file_); } @@ -112,7 +116,9 @@ void TraceWriter::WritePacketStart(uint32_t base_ptr, uint32_t count) { return; } PacketStartCommand cmd = { - TraceCommandType::kPacketStart, base_ptr, count, + TraceCommandType::kPacketStart, + base_ptr, + count, }; fwrite(&cmd, 1, sizeof(cmd), file_); fwrite(membase_ + base_ptr, 4, count, file_); @@ -220,7 +226,8 @@ void TraceWriter::WriteEvent(EventCommand::Type event_type) { return; } EventCommand cmd = { - TraceCommandType::kEvent, event_type, + TraceCommandType::kEvent, + event_type, }; fwrite(&cmd, 1, sizeof(cmd), file_); } diff --git a/src/xenia/gpu/vulkan/pipeline_cache.cc b/src/xenia/gpu/vulkan/pipeline_cache.cc index 58d7bd844..8a25bff86 100644 --- a/src/xenia/gpu/vulkan/pipeline_cache.cc +++ b/src/xenia/gpu/vulkan/pipeline_cache.cc @@ -1206,7 +1206,9 @@ PipelineCache::UpdateStatus PipelineCache::UpdateRasterizationState( // Vulkan only supports both matching. assert_true(front_poly_mode == back_poly_mode); static const VkPolygonMode kFillModes[3] = { - VK_POLYGON_MODE_POINT, VK_POLYGON_MODE_LINE, VK_POLYGON_MODE_FILL, + VK_POLYGON_MODE_POINT, + VK_POLYGON_MODE_LINE, + VK_POLYGON_MODE_FILL, }; state_info.polygonMode = kFillModes[front_poly_mode]; } else { diff --git a/src/xenia/gpu/vulkan/render_cache.cc b/src/xenia/gpu/vulkan/render_cache.cc index b5ae200dc..b13225d08 100644 --- a/src/xenia/gpu/vulkan/render_cache.cc +++ b/src/xenia/gpu/vulkan/render_cache.cc @@ -223,7 +223,9 @@ CachedTileView::CachedTileView(ui::vulkan::VulkanDevice* device, image_view_info.format = image_info.format; // TODO(benvanik): manipulate? may not be able to when attached. image_view_info.components = { - VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, + VK_COMPONENT_SWIZZLE_R, + VK_COMPONENT_SWIZZLE_G, + VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A, }; image_view_info.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; @@ -766,7 +768,9 @@ bool RenderCache::ParseConfiguration(RenderConfiguration* config) { // Color attachment configuration. if (config->mode_control == ModeControl::kColorDepth) { reg::RB_COLOR_INFO color_info[4] = { - regs.rb_color_info, regs.rb_color1_info, regs.rb_color2_info, + regs.rb_color_info, + regs.rb_color1_info, + regs.rb_color2_info, regs.rb_color3_info, }; for (int i = 0; i < 4; ++i) { @@ -783,6 +787,9 @@ bool RenderCache::ParseConfiguration(RenderConfiguration* config) { case ColorRenderTargetFormat::k_2_10_10_10_FLOAT_unknown: config->color[i].format = ColorRenderTargetFormat::k_2_10_10_10_FLOAT; break; + default: + // The rest are good + break; } } } else { @@ -863,7 +870,7 @@ bool RenderCache::ConfigureRenderPass(VkCommandBuffer command_buffer, color_key.edram_format = static_cast(config->color[i].format); target_color_attachments[i] = FindOrCreateTileView(command_buffer, color_key); - if (!target_color_attachments) { + if (!target_color_attachments[i]) { XELOGE("Failed to get tile view for color attachment"); return false; } @@ -926,6 +933,9 @@ CachedTileView* RenderCache::FindTileView(uint32_t base, uint32_t pitch, case ColorRenderTargetFormat::k_2_10_10_10_FLOAT_unknown: format = uint32_t(ColorRenderTargetFormat::k_2_10_10_10_FLOAT); break; + default: + // Other types as-is. + break; } } @@ -1165,6 +1175,9 @@ void RenderCache::BlitToImage(VkCommandBuffer command_buffer, case ColorRenderTargetFormat::k_2_10_10_10_FLOAT_unknown: format = uint32_t(ColorRenderTargetFormat::k_2_10_10_10_FLOAT); break; + default: + // Rest are OK + break; } } @@ -1278,6 +1291,9 @@ void RenderCache::ClearEDRAMColor(VkCommandBuffer command_buffer, case ColorRenderTargetFormat::k_2_10_10_10_FLOAT_unknown: format = ColorRenderTargetFormat::k_2_10_10_10_FLOAT; break; + default: + // Rest are OK + break; } uint32_t tile_width = num_samples == MsaaSamples::k4X ? 40 : 80; diff --git a/src/xenia/gpu/vulkan/render_cache.h b/src/xenia/gpu/vulkan/render_cache.h index 6872bca9d..a015dc8ca 100644 --- a/src/xenia/gpu/vulkan/render_cache.h +++ b/src/xenia/gpu/vulkan/render_cache.h @@ -84,7 +84,7 @@ class CachedTileView { } VkExtent2D GetSize() const { - return {key.tile_width * 80ul, key.tile_height * 16ul}; + return {key.tile_width * 80u, key.tile_height * 16u}; } private: diff --git a/src/xenia/gpu/vulkan/texture_cache.cc b/src/xenia/gpu/vulkan/texture_cache.cc index 464a3ac14..b2bdd5819 100644 --- a/src/xenia/gpu/vulkan/texture_cache.cc +++ b/src/xenia/gpu/vulkan/texture_cache.cc @@ -1116,8 +1116,10 @@ void TextureCache::WritebackTexture(Texture* texture) { auto command_buffer = wb_command_pool_->AcquireEntry(); VkCommandBufferBeginInfo begin_info = { - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr, - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, nullptr, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + nullptr, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + nullptr, }; vkBeginCommandBuffer(command_buffer, &begin_info); diff --git a/src/xenia/gpu/vulkan/vulkan_command_processor.cc b/src/xenia/gpu/vulkan/vulkan_command_processor.cc index fd7852f15..4653a71ed 100644 --- a/src/xenia/gpu/vulkan/vulkan_command_processor.cc +++ b/src/xenia/gpu/vulkan/vulkan_command_processor.cc @@ -122,7 +122,9 @@ bool VulkanCommandProcessor::SetupContext() { } VkEventCreateInfo info = { - VK_STRUCTURE_TYPE_EVENT_CREATE_INFO, nullptr, 0, + VK_STRUCTURE_TYPE_EVENT_CREATE_INFO, + nullptr, + 0, }; status = vkCreateEvent(*device_, &info, nullptr, @@ -469,7 +471,8 @@ void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr, nullptr, 1, &barrier); VkRect2D src_rect = { - {0, 0}, {frontbuffer_width, frontbuffer_height}, + {0, 0}, + {frontbuffer_width, frontbuffer_height}, }; blitter_->BlitTexture2D( copy_commands, current_batch_fence_, @@ -1032,7 +1035,8 @@ bool VulkanCommandProcessor::IssueCopy() { if (is_color_source) { // Source from a color target. uint32_t color_info[4] = { - regs[XE_GPU_REG_RB_COLOR_INFO].u32, regs[XE_GPU_REG_RB_COLOR1_INFO].u32, + regs[XE_GPU_REG_RB_COLOR_INFO].u32, + regs[XE_GPU_REG_RB_COLOR1_INFO].u32, regs[XE_GPU_REG_RB_COLOR2_INFO].u32, regs[XE_GPU_REG_RB_COLOR3_INFO].u32, }; @@ -1142,11 +1146,11 @@ bool VulkanCommandProcessor::IssueCopy() { VkFilter filter = is_color_source ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; switch (copy_command) { case CopyCommand::kRaw: - /* - render_cache_->RawCopyToImage(command_buffer, edram_base, - texture->image, texture->image_layout, is_color_source, resolve_offset, - resolve_extent); break; - */ + /* + render_cache_->RawCopyToImage(command_buffer, edram_base, + texture->image, texture->image_layout, is_color_source, resolve_offset, + resolve_extent); break; + */ case CopyCommand::kConvert: { /* diff --git a/src/xenia/gpu/vulkan/vulkan_graphics_system.cc b/src/xenia/gpu/vulkan/vulkan_graphics_system.cc index 4d4aac23d..83e8210ae 100644 --- a/src/xenia/gpu/vulkan/vulkan_graphics_system.cc +++ b/src/xenia/gpu/vulkan/vulkan_graphics_system.cc @@ -27,8 +27,8 @@ namespace xe { namespace gpu { namespace vulkan { -using xe::ui::vulkan::CheckResult; using xe::ui::RawImage; +using xe::ui::vulkan::CheckResult; VulkanGraphicsSystem::VulkanGraphicsSystem() {} VulkanGraphicsSystem::~VulkanGraphicsSystem() = default; @@ -50,7 +50,8 @@ X_STATUS VulkanGraphicsSystem::Setup(cpu::Processor* processor, // Create our own command pool we can use for captures. VkCommandPoolCreateInfo create_info = { - VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, nullptr, + VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + nullptr, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, device_->queue_family_index(), @@ -93,8 +94,10 @@ std::unique_ptr VulkanGraphicsSystem::Capture() { } VkCommandBufferBeginInfo begin_info = { - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr, - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, nullptr, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + nullptr, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + nullptr, }; vkBeginCommandBuffer(cmd, &begin_info); diff --git a/src/xenia/hid/hid_demo.cc b/src/xenia/hid/hid_demo.cc index 0f11a4922..3ea662a0a 100644 --- a/src/xenia/hid/hid_demo.cc +++ b/src/xenia/hid/hid_demo.cc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2015 Ben Vanik. All rights reserved. * + * Copyright 2017 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -15,7 +15,6 @@ #include "xenia/base/clock.h" #include "xenia/base/logging.h" #include "xenia/base/main.h" -#include "xenia/base/platform_win.h" #include "xenia/base/threading.h" #include "xenia/hid/input_system.h" #include "xenia/ui/gl/gl_provider.h" @@ -117,11 +116,11 @@ int hid_demo_main(const std::vector& args) { auto& io = window->imgui_drawer()->GetIO(); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(-1, 0)); - ImGui::Begin("main_window", nullptr, ImGuiWindowFlags_NoMove | - ImGuiWindowFlags_NoResize | - ImGuiWindowFlags_NoTitleBar | - ImGuiWindowFlags_NoScrollbar | - ImGuiWindowFlags_NoSavedSettings); + ImGui::Begin("main_window", nullptr, + ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_NoTitleBar | + ImGuiWindowFlags_NoScrollbar | + ImGuiWindowFlags_NoSavedSettings); ImGui::SetWindowPos(ImVec2(0, 0)); ImGui::SetWindowSize(io.DisplaySize); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(4, 4)); diff --git a/src/xenia/kernel/util/object_table.cc b/src/xenia/kernel/util/object_table.cc index 6ccd63b26..857ca883b 100644 --- a/src/xenia/kernel/util/object_table.cc +++ b/src/xenia/kernel/util/object_table.cc @@ -213,9 +213,8 @@ std::vector> ObjectTable::GetAllObjects() { for (uint32_t slot = 0; slot < table_capacity_; slot++) { auto& entry = table_[slot]; - if (entry.object && - std::find(results.begin(), results.end(), entry.object) == - results.end()) { + if (entry.object && std::find(results.begin(), results.end(), + entry.object) == results.end()) { entry.object->Retain(); results.push_back(object_ref(entry.object)); } diff --git a/src/xenia/kernel/util/shim_utils.h b/src/xenia/kernel/util/shim_utils.h index f8248f4eb..81128b2a7 100644 --- a/src/xenia/kernel/util/shim_utils.h +++ b/src/xenia/kernel/util/shim_utils.h @@ -474,7 +474,9 @@ xe::cpu::Export* RegisterExport(R (*fn)(Ps&...), const char* name, static void Trampoline(PPCContext* ppc_context) { ++export_entry->function_data.call_count; Param::Init init = { - ppc_context, sizeof...(Ps), 0, + ppc_context, + sizeof...(Ps), + 0, }; auto params = std::make_tuple(Ps(init)...); if (export_entry->tags & xe::cpu::ExportTag::kLog && @@ -507,7 +509,8 @@ xe::cpu::Export* RegisterExport(void (*fn)(Ps&...), const char* name, static void Trampoline(PPCContext* ppc_context) { ++export_entry->function_data.call_count; Param::Init init = { - ppc_context, sizeof...(Ps), + ppc_context, + sizeof...(Ps), }; auto params = std::make_tuple(Ps(init)...); if (export_entry->tags & xe::cpu::ExportTag::kLog && diff --git a/src/xenia/kernel/util/xex2.h b/src/xenia/kernel/util/xex2.h index 796878d9b..64f2ab0de 100644 --- a/src/xenia/kernel/util/xex2.h +++ b/src/xenia/kernel/util/xex2.h @@ -15,7 +15,9 @@ namespace xe {} // namespace xe -typedef struct { int reserved; } xe_xex2_options_t; +typedef struct { + int reserved; +} xe_xex2_options_t; struct xe_xex2; typedef struct xe_xex2* xe_xex2_ref; diff --git a/src/xenia/kernel/xam/xam_avatar.cc b/src/xenia/kernel/xam/xam_avatar.cc index 68c3f9f7b..3c2049b38 100644 --- a/src/xenia/kernel/xam/xam_avatar.cc +++ b/src/xenia/kernel/xam/xam_avatar.cc @@ -24,7 +24,7 @@ dword_result_t XamAvatarInitialize( lpdword_t function_ptrs, // 20b, 5 pointers lpunknown_t unk5, // ptr in data segment dword_t unk6 // flags - 0x00300000, 0x30, etc - ) { +) { // Negative to fail. Game should immediately call XamAvatarShutdown. return ~0u; } diff --git a/src/xenia/kernel/xbdm/xbdm_misc.cc b/src/xenia/kernel/xbdm/xbdm_misc.cc index b2e86da15..2075a8c3c 100644 --- a/src/xenia/kernel/xbdm/xbdm_misc.cc +++ b/src/xenia/kernel/xbdm/xbdm_misc.cc @@ -47,6 +47,6 @@ DECLARE_XBDM_EXPORT(DmFindPdbSignature, ExportTag::kStub | ExportTag::kDebug); void RegisterMiscExports(xe::cpu::ExportResolver* export_resolver, KernelState* kernel_state) {} -} // namespace xboxkrnl +} // namespace xbdm } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_audio.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_audio.cc index d74a9cf51..fb3ad1d6a 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_audio.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_audio.cc @@ -7,13 +7,13 @@ ****************************************************************************** */ -#include "xenia/xbox.h" #include "xenia/apu/audio_system.h" #include "xenia/base/logging.h" #include "xenia/emulator.h" #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/xboxkrnl/xboxkrnl_private.h" +#include "xenia/xbox.h" namespace xe { namespace kernel { diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_crypt.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_crypt.cc index df0d4361f..86f0d301b 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_crypt.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_crypt.cc @@ -7,11 +7,11 @@ ****************************************************************************** */ -#include "xenia/xbox.h" #include "xenia/base/logging.h" #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/xboxkrnl/xboxkrnl_private.h" +#include "xenia/xbox.h" #include "third_party/crypto/TinySHA1.hpp" #include "third_party/crypto/des/des.cpp" diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_debug.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_debug.cc index f69a812b9..45510bac2 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_debug.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_debug.cc @@ -7,13 +7,13 @@ ****************************************************************************** */ -#include "xenia/xbox.h" #include "xenia/base/debugging.h" #include "xenia/base/logging.h" #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/xboxkrnl/xboxkrnl_private.h" #include "xenia/kernel/xthread.h" +#include "xenia/xbox.h" namespace xe { namespace kernel { diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_hal.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_hal.cc index b1426ee8d..658275483 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_hal.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_hal.cc @@ -7,11 +7,11 @@ ****************************************************************************** */ -#include "xenia/xbox.h" #include "xenia/base/logging.h" #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/xboxkrnl/xboxkrnl_private.h" +#include "xenia/xbox.h" namespace xe { namespace kernel { diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc index 01446abf3..c01a7c5f6 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc @@ -7,7 +7,6 @@ ****************************************************************************** */ -#include "xenia/xbox.h" #include "xenia/base/logging.h" #include "xenia/base/memory.h" #include "xenia/cpu/processor.h" @@ -19,6 +18,7 @@ #include "xenia/kernel/xiocompletion.h" #include "xenia/kernel/xthread.h" #include "xenia/vfs/device.h" +#include "xenia/xbox.h" namespace xe { namespace kernel { diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_misc.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_misc.cc index b8267b0ab..2524c396f 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_misc.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_misc.cc @@ -7,12 +7,12 @@ ****************************************************************************** */ -#include "xenia/xbox.h" #include "xenia/base/logging.h" #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/xboxkrnl/xboxkrnl_private.h" #include "xenia/kernel/xthread.h" +#include "xenia/xbox.h" namespace xe { namespace kernel { diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc index 0aa0bb799..d647e2f8c 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc @@ -7,7 +7,6 @@ ****************************************************************************** */ -#include "xenia/xbox.h" #include "xenia/base/logging.h" #include "xenia/cpu/processor.h" #include "xenia/kernel/kernel_state.h" @@ -15,6 +14,7 @@ #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/util/xex2.h" #include "xenia/kernel/xboxkrnl/xboxkrnl_private.h" +#include "xenia/xbox.h" namespace xe { namespace kernel { diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc index 898e5e3a6..55a55c559 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc @@ -7,7 +7,6 @@ ****************************************************************************** */ -#include "xenia/xbox.h" #include "xenia/base/logging.h" #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/util/shim_utils.h" @@ -15,6 +14,7 @@ #include "xenia/kernel/xobject.h" #include "xenia/kernel/xsemaphore.h" #include "xenia/kernel/xthread.h" +#include "xenia/xbox.h" namespace xe { namespace kernel { diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc index f4d99e6c4..d5ef2d661 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc @@ -559,13 +559,12 @@ int32_t format_core(PPCContext* ppc_context, FormatData& data, ArgList& args, if (!is_wide) { length = 0; - for (auto s = (const uint8_t *)str; cap > 0 && *s; ++s, cap--) { + for (auto s = (const uint8_t*)str; cap > 0 && *s; ++s, cap--) { length++; } } else { length = 0; - for (auto s = (const uint16_t *)str; cap > 0 && *s; - ++s, cap--) { + for (auto s = (const uint16_t*)str; cap > 0 && *s; ++s, cap--) { length++; } } diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_usbcam.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_usbcam.cc index bda5d4b7a..28c85abb1 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_usbcam.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_usbcam.cc @@ -7,11 +7,11 @@ ****************************************************************************** */ -#include "xenia/xbox.h" #include "xenia/base/logging.h" #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/xboxkrnl/xboxkrnl_private.h" +#include "xenia/xbox.h" namespace xe { namespace kernel { diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_video.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_video.cc index 8a7609bc5..560cec820 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_video.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_video.cc @@ -257,7 +257,7 @@ dword_result_t VdInitializeScalerCommandBuffer( lpvoid_t dest_ptr, // Points to the first 80000000h where the memcpy // sources from. dword_t dest_count // Count in words. - ) { +) { // We could fake the commands here, but I'm not sure the game checks for // anything but success (non-zero ret). // For now, we just fill it with NOPs. diff --git a/src/xenia/memory.cc b/src/xenia/memory.cc index 7291db681..9bf8b565e 100644 --- a/src/xenia/memory.cc +++ b/src/xenia/memory.cc @@ -209,39 +209,57 @@ static const struct { } map_info[] = { // (1024mb) - virtual 4k pages { - 0x00000000, 0x3FFFFFFF, 0x0000000000000000ull, + 0x00000000, + 0x3FFFFFFF, + 0x0000000000000000ull, }, // (1024mb) - virtual 64k pages (cont) { - 0x40000000, 0x7EFFFFFF, 0x0000000040000000ull, + 0x40000000, + 0x7EFFFFFF, + 0x0000000040000000ull, }, // (16mb) - GPU writeback + 15mb of XPS? { - 0x7F000000, 0x7FFFFFFF, 0x0000000100000000ull, + 0x7F000000, + 0x7FFFFFFF, + 0x0000000100000000ull, }, // (256mb) - xex 64k pages { - 0x80000000, 0x8FFFFFFF, 0x0000000080000000ull, + 0x80000000, + 0x8FFFFFFF, + 0x0000000080000000ull, }, // (256mb) - xex 4k pages { - 0x90000000, 0x9FFFFFFF, 0x0000000080000000ull, + 0x90000000, + 0x9FFFFFFF, + 0x0000000080000000ull, }, // (512mb) - physical 64k pages { - 0xA0000000, 0xBFFFFFFF, 0x0000000100000000ull, + 0xA0000000, + 0xBFFFFFFF, + 0x0000000100000000ull, }, // - physical 16mb pages { - 0xC0000000, 0xDFFFFFFF, 0x0000000100000000ull, + 0xC0000000, + 0xDFFFFFFF, + 0x0000000100000000ull, }, // - physical 4k pages { - 0xE0000000, 0xFFFFFFFF, 0x0000000100000000ull, + 0xE0000000, + 0xFFFFFFFF, + 0x0000000100000000ull, }, // - physical raw { - 0x100000000, 0x11FFFFFFF, 0x0000000100000000ull, + 0x100000000, + 0x11FFFFFFF, + 0x0000000100000000ull, }, }; int Memory::MapViews(uint8_t* mapping_base) { diff --git a/src/xenia/tools/api-scanner/api_scanner_loader.cc b/src/xenia/tools/api-scanner/api_scanner_loader.cc index b94b72aff..5d642c511 100644 --- a/src/xenia/tools/api-scanner/api_scanner_loader.cc +++ b/src/xenia/tools/api-scanner/api_scanner_loader.cc @@ -179,5 +179,5 @@ bool apiscanner_loader::ExtractImports(const void* addr, const size_t length, return true; } -} // tools -} // xe +} // namespace tools +} // namespace xe diff --git a/src/xenia/tools/api-scanner/api_scanner_loader.h b/src/xenia/tools/api-scanner/api_scanner_loader.h index 2d26ebda9..9aa8d7fe9 100644 --- a/src/xenia/tools/api-scanner/api_scanner_loader.h +++ b/src/xenia/tools/api-scanner/api_scanner_loader.h @@ -56,5 +56,5 @@ class apiscanner_loader { bool ExtractImports(const void* addr, const size_t length, title& info); }; -} // tools -} // xe +} // namespace tools +} // namespace xe diff --git a/src/xenia/ui/file_picker_gtk.cc b/src/xenia/ui/file_picker_gtk.cc new file mode 100644 index 000000000..dce28772d --- /dev/null +++ b/src/xenia/ui/file_picker_gtk.cc @@ -0,0 +1,70 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2016 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/ui/file_picker.h" + +#include +#include +#include +#include "xenia/base/assert.h" +#include "xenia/base/platform_linux.h" + +namespace xe { +namespace ui { + +class GtkFilePicker : public FilePicker { + public: + GtkFilePicker(); + ~GtkFilePicker() override; + + bool Show(void* parent_window_handle) override; + + private: +}; + +std::unique_ptr FilePicker::Create() { + return std::make_unique(); +} + +GtkFilePicker::GtkFilePicker() = default; + +GtkFilePicker::~GtkFilePicker() = default; + +bool GtkFilePicker::Show(void* parent_window_handle) { + // TODO(benvanik): FileSaveDialog. + assert_true(mode() == Mode::kOpen); + // TODO(benvanik): folder dialogs. + assert_true(type() == Type::kFile); + GtkWidget* dialog; + gint res; + + dialog = gtk_file_chooser_dialog_new( + "Open File", (GtkWindow*)parent_window_handle, + GTK_FILE_CHOOSER_ACTION_OPEN, "_Cancel", GTK_RESPONSE_CANCEL, "_Open", + GTK_RESPONSE_ACCEPT, NULL); + + res = gtk_dialog_run(GTK_DIALOG(dialog)); + char* filename; + if (res == GTK_RESPONSE_ACCEPT) { + GtkFileChooser* chooser = GTK_FILE_CHOOSER(dialog); + filename = gtk_file_chooser_get_filename(chooser); + std::vector selected_files; + std::wstring_convert> converter; + std::wstring ws_filename = converter.from_bytes(filename); + selected_files.push_back(ws_filename); + set_selected_files(selected_files); + gtk_widget_destroy(dialog); + return true; + } + gtk_widget_destroy(dialog); + return false; +} + +} // namespace ui +} // namespace xe diff --git a/src/xenia/ui/gl/gl.h b/src/xenia/ui/gl/gl.h index c2e35a907..796248803 100644 --- a/src/xenia/ui/gl/gl.h +++ b/src/xenia/ui/gl/gl.h @@ -23,6 +23,10 @@ extern "C" GLEWContext* glewGetContext(); // required. typedef struct WGLEWContextStruct WGLEWContext; extern "C" WGLEWContext* wglewGetContext(); -#endif // XE_PLATFORM_WIN32 +#elif XE_PLATFORM_LINUX +typedef struct GLXEWContextStruct GLXEWContext; +extern "C" GLXEWContext* glxewGetContext(); + +#endif #endif // XENIA_UI_GL_GL_H_ diff --git a/src/xenia/ui/gl/gl_context.cc b/src/xenia/ui/gl/gl_context.cc index c908aaf40..a1c94ef9e 100644 --- a/src/xenia/ui/gl/gl_context.cc +++ b/src/xenia/ui/gl/gl_context.cc @@ -17,14 +17,10 @@ #include "xenia/base/assert.h" #include "xenia/base/logging.h" #include "xenia/base/math.h" -#include "xenia/base/platform_win.h" #include "xenia/base/profiling.h" #include "xenia/ui/gl/gl_immediate_drawer.h" #include "xenia/ui/window.h" -// TODO(benvanik): move win32 code to _win? -#include "third_party/GL/wglew.h" - DEFINE_bool(thread_safe_gl, false, "Only allow one GL context to be active at a time."); @@ -43,14 +39,9 @@ namespace xe { namespace ui { namespace gl { -static std::recursive_mutex global_gl_mutex_; +std::recursive_mutex GLContext::global_gl_mutex_; -thread_local GLEWContext* tls_glew_context_ = nullptr; -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) { +void GLContext::FatalGLError(std::string error) { xe::FatalError( error + "\nEnsure you have the latest drivers for your GPU and that it supports " @@ -58,223 +49,10 @@ void FatalGLError(std::string error) { "of supported GPUs."); } -std::unique_ptr GLContext::Create(GraphicsProvider* provider, - Window* target_window, - GLContext* share_context) { - auto context = - std::unique_ptr(new GLContext(provider, target_window)); - if (!context->Initialize(share_context)) { - return nullptr; - } - context->AssertExtensionsPresent(); - return context; -} - GLContext::GLContext(GraphicsProvider* provider, Window* target_window) - : GraphicsContext(provider, target_window) { - glew_context_.reset(new GLEWContext()); - wglew_context_.reset(new WGLEWContext()); -} + : GraphicsContext(provider, target_window) {} -GLContext::~GLContext() { - MakeCurrent(); - blitter_.Shutdown(); - immediate_drawer_.reset(); - ClearCurrent(); - if (glrc_) { - wglDeleteContext(glrc_); - } - if (dc_) { - ReleaseDC(HWND(target_window_->native_handle()), dc_); - } -} - -bool GLContext::Initialize(GLContext* share_context) { - dc_ = GetDC(HWND(target_window_->native_handle())); - - PIXELFORMATDESCRIPTOR pfd = {0}; - pfd.nSize = sizeof(pfd); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = 32; - pfd.cDepthBits = 32; - pfd.iLayerType = PFD_MAIN_PLANE; - int pixel_format = ChoosePixelFormat(dc_, &pfd); - if (!pixel_format) { - FatalGLError("Unable to choose pixel format."); - return false; - } - if (!SetPixelFormat(dc_, pixel_format, &pfd)) { - FatalGLError("Unable to set pixel format."); - return false; - } - - HGLRC temp_context = wglCreateContext(dc_); - if (!temp_context) { - FatalGLError("Unable to create temporary GL context."); - return false; - } - wglMakeCurrent(dc_, temp_context); - - tls_glew_context_ = glew_context_.get(); - tls_wglew_context_ = wglew_context_.get(); - if (glewInit() != GLEW_OK) { - FatalGLError("Unable to initialize GLEW."); - return false; - } - if (wglewInit() != GLEW_OK) { - FatalGLError("Unable to initialize WGLEW."); - return false; - } - - if (!WGLEW_ARB_create_context) { - FatalGLError("WGL_ARG_create_context not supported by GL ICD."); - return false; - } - - if (GLEW_ARB_robustness) { - robust_access_supported_ = true; - } - - int context_flags = 0; - if (FLAGS_gl_debug) { - context_flags |= WGL_CONTEXT_DEBUG_BIT_ARB; - } - if (robust_access_supported_) { - context_flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; - } - - int attrib_list[] = { - WGL_CONTEXT_MAJOR_VERSION_ARB, - 4, - WGL_CONTEXT_MINOR_VERSION_ARB, - 5, - WGL_CONTEXT_FLAGS_ARB, - context_flags, - WGL_CONTEXT_PROFILE_MASK_ARB, - WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, - WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, - robust_access_supported_ ? WGL_LOSE_CONTEXT_ON_RESET_ARB : 0, - 0}; - - glrc_ = wglCreateContextAttribsARB( - dc_, share_context ? share_context->glrc_ : nullptr, attrib_list); - wglMakeCurrent(nullptr, nullptr); - wglDeleteContext(temp_context); - if (!glrc_) { - FatalGLError("Unable to create real GL context."); - return false; - } - - if (!MakeCurrent()) { - FatalGLError("Could not make real GL context current."); - return false; - } - - XELOGI("Successfully created OpenGL context:"); - XELOGI(" GL_VENDOR: %s", glGetString(GL_VENDOR)); - XELOGI(" GL_VERSION: %s", glGetString(GL_VERSION)); - XELOGI(" GL_RENDERER: %s", glGetString(GL_RENDERER)); - XELOGI(" GL_SHADING_LANGUAGE_VERSION: %s", - glGetString(GL_SHADING_LANGUAGE_VERSION)); - - while (glGetError()) { - // Clearing errors. - } - - SetupDebugging(); - - if (!blitter_.Initialize()) { - FatalGLError("Unable to initialize blitter."); - ClearCurrent(); - return false; - } - - immediate_drawer_ = std::make_unique(this); - - ClearCurrent(); - - return true; -} - -std::unique_ptr GLContext::CreateOffscreen( - GraphicsProvider* provider, GLContext* parent_context) { - assert_not_null(parent_context->glrc_); - - HGLRC new_glrc = nullptr; - { - GraphicsContextLock context_lock(parent_context); - - int context_flags = 0; - if (FLAGS_gl_debug) { - context_flags |= WGL_CONTEXT_DEBUG_BIT_ARB; - } - - bool robust_access_supported = parent_context->robust_access_supported_; - if (robust_access_supported) { - context_flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; - } - - int attrib_list[] = { - WGL_CONTEXT_MAJOR_VERSION_ARB, - 4, - WGL_CONTEXT_MINOR_VERSION_ARB, - 5, - WGL_CONTEXT_FLAGS_ARB, - context_flags, - WGL_CONTEXT_PROFILE_MASK_ARB, - WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, - WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, - robust_access_supported ? WGL_LOSE_CONTEXT_ON_RESET_ARB : 0, - 0}; - new_glrc = wglCreateContextAttribsARB(parent_context->dc_, - parent_context->glrc_, attrib_list); - if (!new_glrc) { - FatalGLError("Could not create shared context."); - return nullptr; - } - } - - auto new_context = std::unique_ptr( - new GLContext(provider, parent_context->target_window_)); - new_context->glrc_ = new_glrc; - new_context->dc_ = - GetDC(HWND(parent_context->target_window_->native_handle())); - new_context->robust_access_supported_ = - parent_context->robust_access_supported_; - if (!new_context->MakeCurrent()) { - FatalGLError("Could not make new GL context current."); - return nullptr; - } - if (!glGetString(GL_EXTENSIONS)) { - new_context->ClearCurrent(); - FatalGLError("New GL context did not have extensions."); - return nullptr; - } - - if (glewInit() != GLEW_OK) { - new_context->ClearCurrent(); - FatalGLError("Unable to initialize GLEW on shared context."); - return nullptr; - } - if (wglewInit() != GLEW_OK) { - new_context->ClearCurrent(); - FatalGLError("Unable to initialize WGLEW on shared context."); - return nullptr; - } - - new_context->SetupDebugging(); - - if (!new_context->blitter_.Initialize()) { - FatalGLError("Unable to initialize blitter on shared context."); - return nullptr; - } - - new_context->ClearCurrent(); - - return new_context; -} +GLContext::~GLContext() {} void GLContext::AssertExtensionsPresent() { if (!MakeCurrent()) { @@ -436,40 +214,6 @@ ImmediateDrawer* GLContext::immediate_drawer() { return immediate_drawer_.get(); } -bool GLContext::is_current() { - return tls_glew_context_ == glew_context_.get(); -} - -bool GLContext::MakeCurrent() { - SCOPE_profile_cpu_f("gpu"); - if (FLAGS_thread_safe_gl) { - global_gl_mutex_.lock(); - } - - if (!wglMakeCurrent(dc_, glrc_)) { - if (FLAGS_thread_safe_gl) { - global_gl_mutex_.unlock(); - } - FatalGLError("Unable to make GL context current."); - return false; - } - tls_glew_context_ = glew_context_.get(); - tls_wglew_context_ = wglew_context_.get(); - return true; -} - -void GLContext::ClearCurrent() { - if (!FLAGS_disable_gl_context_reset) { - wglMakeCurrent(nullptr, nullptr); - } - tls_glew_context_ = nullptr; - tls_wglew_context_ = nullptr; - - if (FLAGS_thread_safe_gl) { - global_gl_mutex_.unlock(); - } -} - bool GLContext::WasLost() { if (!robust_access_supported_) { // Can't determine if we lost the context. @@ -484,7 +228,7 @@ bool GLContext::WasLost() { if (status != GL_NO_ERROR) { // Graphics card reset. XELOGE("============= TDR detected on context %p! Context %s =============", - glrc_, status == GL_GUILTY_CONTEXT_RESET ? "guilty" : "innocent"); + handle(), status == GL_GUILTY_CONTEXT_RESET ? "guilty" : "innocent"); context_lost_ = true; return true; } @@ -492,24 +236,6 @@ bool GLContext::WasLost() { return false; } -void GLContext::BeginSwap() { - SCOPE_profile_cpu_i("gpu", "xe::ui::gl::GLContext::BeginSwap"); - float clear_color[] = {238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 1.0f}; - if (FLAGS_random_clear_color) { - clear_color[0] = - rand() / static_cast(RAND_MAX); // NOLINT(runtime/threadsafe_fn) - clear_color[1] = 1.0f; - clear_color[2] = 0.0f; - clear_color[3] = 1.0f; - } - glClearNamedFramebufferfv(0, GL_COLOR, 0, clear_color); -} - -void GLContext::EndSwap() { - SCOPE_profile_cpu_i("gpu", "xe::ui::gl::GLContext::EndSwap"); - SwapBuffers(dc_); -} - std::unique_ptr GLContext::Capture() { GraphicsContextLock lock(this); diff --git a/src/xenia/ui/gl/gl_context.h b/src/xenia/ui/gl/gl_context.h index a60e2d4ed..d71e209b2 100644 --- a/src/xenia/ui/gl/gl_context.h +++ b/src/xenia/ui/gl/gl_context.h @@ -13,6 +13,7 @@ #include #include +#include #include "xenia/ui/gl/blitter.h" #include "xenia/ui/gl/gl.h" @@ -20,9 +21,13 @@ DECLARE_bool(thread_safe_gl); -// TODO(benvanik): hide Win32 stuff. -typedef struct HDC__* HDC; -typedef struct HGLRC__* HGLRC; +DECLARE_bool(disable_gl_context_reset); + +DECLARE_bool(random_clear_color); + +DECLARE_bool(gl_debug); +DECLARE_bool(gl_debug_output); +DECLARE_bool(gl_debug_output_synchronous); namespace xe { namespace ui { @@ -37,18 +42,33 @@ class GLContext : public GraphicsContext { ImmediateDrawer* immediate_drawer() override; - bool is_current() override; - bool MakeCurrent() override; - void ClearCurrent() override; + virtual bool is_current() override = 0; + virtual bool MakeCurrent() override = 0; + virtual void ClearCurrent() override = 0; bool WasLost() override; - void BeginSwap() override; - void EndSwap() override; - + virtual void BeginSwap() override = 0; + virtual void EndSwap() override = 0; std::unique_ptr Capture() override; Blitter* blitter() { return &blitter_; } + protected: + Blitter blitter_; + std::unique_ptr immediate_drawer_; + + static std::recursive_mutex global_gl_mutex_; + bool context_lost_ = false; + bool robust_access_supported_ = false; + static void FatalGLError(std::string error); + virtual bool Initialize(GLContext* share_context) = 0; + virtual void* handle() = 0; + GLContext(GraphicsProvider* provider, Window* target_window); + void SetupDebugging(); + void AssertExtensionsPresent(); + void DebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, + GLsizei length, const GLchar* message); + private: friend class GLProvider; @@ -59,31 +79,11 @@ class GLContext : public GraphicsContext { GLContext* parent_context); private: - GLContext(GraphicsProvider* provider, Window* target_window); - - bool Initialize(GLContext* share_context); - void AssertExtensionsPresent(); - - void SetupDebugging(); - void DebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, - GLsizei length, const GLchar* message); static void GLAPIENTRY DebugMessageThunk(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, GLvoid* user_param); - - HDC dc_ = nullptr; - HGLRC glrc_ = nullptr; - - std::unique_ptr glew_context_; - std::unique_ptr wglew_context_; - - Blitter blitter_; - std::unique_ptr immediate_drawer_; - - bool context_lost_ = false; - bool robust_access_supported_ = false; }; } // namespace gl diff --git a/src/xenia/ui/gl/gl_context_win.cc b/src/xenia/ui/gl/gl_context_win.cc new file mode 100644 index 000000000..0ca66146c --- /dev/null +++ b/src/xenia/ui/gl/gl_context_win.cc @@ -0,0 +1,315 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/ui/gl/gl_context_win.h" + +#include + +#include +#include + +#include "xenia/base/assert.h" +#include "xenia/base/logging.h" +#include "xenia/base/math.h" +#include "xenia/base/platform_win.h" +#include "xenia/base/profiling.h" +#include "xenia/ui/gl/gl_immediate_drawer.h" +#include "xenia/ui/window.h" + +#include "third_party/GL/wglew.h" + +namespace xe { +namespace ui { +namespace gl { + +thread_local GLEWContext* tls_glew_context_ = nullptr; +thread_local WGLEWContext* tls_wglew_context_ = nullptr; +extern "C" GLEWContext* glewGetContext() { return tls_glew_context_; } +extern "C" WGLEWContext* wglewGetContext() { return tls_wglew_context_; } + +std::unique_ptr GLContext::Create(GraphicsProvider* provider, + Window* target_window, + GLContext* share_context) { + auto context = + std::unique_ptr(new WGLContext(provider, target_window)); + if (!context->Initialize(share_context)) { + return nullptr; + } + context->AssertExtensionsPresent(); + return context; +} + +std::unique_ptr GLContext::CreateOffscreen( + GraphicsProvider* provider, GLContext* parent_context) { + return WGLContext::CreateOffscreen(provider, + static_cast(parent_context)); +} + +WGLContext::WGLContext(GraphicsProvider* provider, Window* target_window) + : GLContext(provider, target_window) { + glew_context_.reset(new GLEWContext()); + wglew_context_.reset(new WGLEWContext()); +} + +WGLContext::~WGLContext() { + MakeCurrent(); + blitter_.Shutdown(); + immediate_drawer_.reset(); + ClearCurrent(); + if (glrc_) { + wglDeleteContext(glrc_); + } + if (dc_) { + ReleaseDC(HWND(target_window_->native_handle()), dc_); + } +} + +bool WGLContext::Initialize(GLContext* share_context_) { + WGLContext* share_context = static_cast(share_context_); + dc_ = GetDC(HWND(target_window_->native_handle())); + + PIXELFORMATDESCRIPTOR pfd = {0}; + pfd.nSize = sizeof(pfd); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 32; + pfd.cDepthBits = 32; + pfd.iLayerType = PFD_MAIN_PLANE; + int pixel_format = ChoosePixelFormat(dc_, &pfd); + if (!pixel_format) { + FatalGLError("Unable to choose pixel format."); + return false; + } + if (!SetPixelFormat(dc_, pixel_format, &pfd)) { + FatalGLError("Unable to set pixel format."); + return false; + } + + HGLRC temp_context = wglCreateContext(dc_); + if (!temp_context) { + FatalGLError("Unable to create temporary GL context."); + return false; + } + wglMakeCurrent(dc_, temp_context); + + tls_glew_context_ = glew_context_.get(); + tls_wglew_context_ = wglew_context_.get(); + if (glewInit() != GLEW_OK) { + FatalGLError("Unable to initialize GLEW."); + return false; + } + if (wglewInit() != GLEW_OK) { + FatalGLError("Unable to initialize WGLEW."); + return false; + } + + if (!WGLEW_ARB_create_context) { + FatalGLError("WGL_ARG_create_context not supported by GL ICD."); + return false; + } + + if (GLEW_ARB_robustness) { + robust_access_supported_ = true; + } + + int context_flags = 0; + if (FLAGS_gl_debug) { + context_flags |= WGL_CONTEXT_DEBUG_BIT_ARB; + } + if (robust_access_supported_) { + context_flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; + } + + int attrib_list[] = { + WGL_CONTEXT_MAJOR_VERSION_ARB, + 4, + WGL_CONTEXT_MINOR_VERSION_ARB, + 5, + WGL_CONTEXT_FLAGS_ARB, + context_flags, + WGL_CONTEXT_PROFILE_MASK_ARB, + WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, + WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + robust_access_supported_ ? WGL_LOSE_CONTEXT_ON_RESET_ARB : 0, + 0}; + + glrc_ = wglCreateContextAttribsARB( + dc_, share_context ? share_context->glrc_ : nullptr, attrib_list); + wglMakeCurrent(nullptr, nullptr); + wglDeleteContext(temp_context); + if (!glrc_) { + FatalGLError("Unable to create real GL context."); + return false; + } + + if (!MakeCurrent()) { + FatalGLError("Could not make real GL context current."); + return false; + } + + XELOGI("Successfully created OpenGL context:"); + XELOGI(" GL_VENDOR: %s", glGetString(GL_VENDOR)); + XELOGI(" GL_VERSION: %s", glGetString(GL_VERSION)); + XELOGI(" GL_RENDERER: %s", glGetString(GL_RENDERER)); + XELOGI(" GL_SHADING_LANGUAGE_VERSION: %s", + glGetString(GL_SHADING_LANGUAGE_VERSION)); + + while (glGetError()) { + // Clearing errors. + } + + SetupDebugging(); + + if (!blitter_.Initialize()) { + FatalGLError("Unable to initialize blitter."); + ClearCurrent(); + return false; + } + + immediate_drawer_ = std::make_unique(this); + + ClearCurrent(); + + return true; +} + +std::unique_ptr WGLContext::CreateOffscreen( + GraphicsProvider* provider, WGLContext* parent_context) { + assert_not_null(parent_context->glrc_); + + HGLRC new_glrc = nullptr; + { + GraphicsContextLock context_lock(parent_context); + + int context_flags = 0; + if (FLAGS_gl_debug) { + context_flags |= WGL_CONTEXT_DEBUG_BIT_ARB; + } + + bool robust_access_supported = parent_context->robust_access_supported_; + if (robust_access_supported) { + context_flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; + } + + int attrib_list[] = { + WGL_CONTEXT_MAJOR_VERSION_ARB, + 4, + WGL_CONTEXT_MINOR_VERSION_ARB, + 5, + WGL_CONTEXT_FLAGS_ARB, + context_flags, + WGL_CONTEXT_PROFILE_MASK_ARB, + WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, + WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + robust_access_supported ? WGL_LOSE_CONTEXT_ON_RESET_ARB : 0, + 0}; + new_glrc = wglCreateContextAttribsARB(parent_context->dc_, + parent_context->glrc_, attrib_list); + if (!new_glrc) { + FatalGLError("Could not create shared context."); + return nullptr; + } + } + + auto new_context = std::unique_ptr( + new WGLContext(provider, parent_context->target_window_)); + new_context->glrc_ = new_glrc; + new_context->dc_ = + GetDC(HWND(parent_context->target_window_->native_handle())); + new_context->robust_access_supported_ = + parent_context->robust_access_supported_; + if (!new_context->MakeCurrent()) { + FatalGLError("Could not make new GL context current."); + return nullptr; + } + if (!glGetString(GL_EXTENSIONS)) { + new_context->ClearCurrent(); + FatalGLError("New GL context did not have extensions."); + return nullptr; + } + + if (glewInit() != GLEW_OK) { + new_context->ClearCurrent(); + FatalGLError("Unable to initialize GLEW on shared context."); + return nullptr; + } + if (wglewInit() != GLEW_OK) { + new_context->ClearCurrent(); + FatalGLError("Unable to initialize WGLEW on shared context."); + return nullptr; + } + + new_context->SetupDebugging(); + + if (!new_context->blitter_.Initialize()) { + FatalGLError("Unable to initialize blitter on shared context."); + return nullptr; + } + + new_context->ClearCurrent(); + + return new_context; +} + +bool WGLContext::is_current() { + return tls_glew_context_ == glew_context_.get(); +} + +bool WGLContext::MakeCurrent() { + SCOPE_profile_cpu_f("gpu"); + if (FLAGS_thread_safe_gl) { + global_gl_mutex_.lock(); + } + + if (!wglMakeCurrent(dc_, glrc_)) { + if (FLAGS_thread_safe_gl) { + global_gl_mutex_.unlock(); + } + FatalGLError("Unable to make GL context current."); + return false; + } + tls_glew_context_ = glew_context_.get(); + tls_wglew_context_ = wglew_context_.get(); + return true; +} + +void WGLContext::ClearCurrent() { + if (!FLAGS_disable_gl_context_reset) { + wglMakeCurrent(nullptr, nullptr); + } + tls_glew_context_ = nullptr; + tls_wglew_context_ = nullptr; + + if (FLAGS_thread_safe_gl) { + global_gl_mutex_.unlock(); + } +} + +void WGLContext::BeginSwap() { + SCOPE_profile_cpu_i("gpu", "xe::ui::gl::WGLContext::BeginSwap"); + float clear_color[] = {238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 1.0f}; + if (FLAGS_random_clear_color) { + clear_color[0] = + rand() / static_cast(RAND_MAX); // NOLINT(runtime/threadsafe_fn) + clear_color[1] = 1.0f; + clear_color[2] = 0.0f; + clear_color[3] = 1.0f; + } + glClearNamedFramebufferfv(0, GL_COLOR, 0, clear_color); +} + +void WGLContext::EndSwap() { + SCOPE_profile_cpu_i("gpu", "xe::ui::gl::WGLContext::EndSwap"); + SwapBuffers(dc_); +} + +} // namespace gl +} // namespace ui +} // namespace xe diff --git a/src/xenia/ui/gl/gl_context_win.h b/src/xenia/ui/gl/gl_context_win.h new file mode 100644 index 000000000..772de4d3e --- /dev/null +++ b/src/xenia/ui/gl/gl_context_win.h @@ -0,0 +1,64 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_UI_GL_WGL_CONTEXT_H_ +#define XENIA_UI_GL_WGL_CONTEXT_H_ + +#include + +#include + +#include "xenia/ui/gl/blitter.h" +#include "xenia/ui/gl/gl.h" +#include "xenia/ui/gl/gl_context.h" +#include "xenia/ui/graphics_context.h" + +typedef struct HDC__* HDC; +typedef struct HGLRC__* HGLRC; + +namespace xe { +namespace ui { +namespace gl { + +class GLImmediateDrawer; +class GLProvider; + +class WGLContext : public GLContext { + public: + ~WGLContext() override; + + bool is_current() override; + bool MakeCurrent() override; + void ClearCurrent() override; + + void BeginSwap() override; + void EndSwap() override; + + protected: + friend class GLContext; + WGLContext(GraphicsProvider* provider, Window* target_window); + static std::unique_ptr CreateOffscreen( + GraphicsProvider* provider, WGLContext* parent_context); + + bool Initialize(GLContext* share_context) override; + void* handle() override { return glrc_; } + + private: + HDC dc_ = nullptr; + HGLRC glrc_ = nullptr; + + std::unique_ptr glew_context_; + std::unique_ptr wglew_context_; +}; + +} // namespace gl +} // namespace ui +} // namespace xe + +#endif // XENIA_UI_GL_GL_CONTEXT_H_ diff --git a/src/xenia/ui/gl/gl_context_x11.cc b/src/xenia/ui/gl/gl_context_x11.cc new file mode 100644 index 000000000..fc4b3176b --- /dev/null +++ b/src/xenia/ui/gl/gl_context_x11.cc @@ -0,0 +1,323 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/ui/gl/gl_context_x11.h" + +#include + +#include +#include +#include + +#include "third_party/GL/glxew.h" +#include "xenia/base/assert.h" +#include "xenia/base/logging.h" +#include "xenia/base/math.h" +#include "xenia/base/platform_linux.h" +#include "xenia/base/profiling.h" +#include "xenia/ui/gl/gl_immediate_drawer.h" +#include "xenia/ui/window.h" + +namespace xe { +namespace ui { +namespace gl { + +thread_local GLEWContext* tls_glew_context_ = nullptr; +thread_local GLXEWContext* tls_glxew_context_ = nullptr; +extern "C" GLEWContext* glewGetContext() { return tls_glew_context_; } +extern "C" GLXEWContext* glxewGetContext() { return tls_glxew_context_; } + +std::unique_ptr GLContext::Create(GraphicsProvider* provider, + Window* target_window, + GLContext* share_context) { + auto context = + std::unique_ptr(new GLXContext(provider, target_window)); + if (!context->Initialize(share_context)) { + return nullptr; + } + context->AssertExtensionsPresent(); + return context; +} + +std::unique_ptr GLContext::CreateOffscreen( + GraphicsProvider* provider, GLContext* parent_context) { + return GLXContext::CreateOffscreen(provider, + static_cast(parent_context)); +} + +GLXContext::GLXContext(GraphicsProvider* provider, Window* target_window) + : GLContext(provider, target_window) { + glew_context_.reset(new GLEWContext()); + glxew_context_.reset(new GLXEWContext()); +} + +GLXContext::~GLXContext() { + MakeCurrent(); + blitter_.Shutdown(); + immediate_drawer_.reset(); + ClearCurrent(); + if (glx_context_) { + glXDestroyContext(disp_, glx_context_); + } + if (draw_area_) { + gtk_widget_destroy(draw_area_); + } +} + +bool GLXContext::Initialize(GLContext* share_context) { + GtkWidget* window = GTK_WIDGET(target_window_->native_handle()); + GtkWidget* draw_area = gtk_drawing_area_new(); + int32_t width; + int32_t height; + gtk_window_get_size(GTK_WINDOW(window), &width, &height); + gtk_widget_set_size_request(draw_area, width, height); + gtk_container_add(GTK_CONTAINER(window), draw_area); + GdkVisual* visual = gdk_screen_get_system_visual(gdk_screen_get_default()); + + GdkDisplay* gdk_display = gtk_widget_get_display(window); + Display* display = gdk_x11_display_get_xdisplay(gdk_display); + disp_ = display; + ::Window root = gdk_x11_get_default_root_xwindow(); + static int vis_attrib_list[] = {GLX_RGBA, GLX_DEPTH_SIZE, 24, + GLX_DOUBLEBUFFER, None}; + XVisualInfo* vi = glXChooseVisual(display, 0, vis_attrib_list); + if (vi == NULL) { + FatalGLError("No matching visuals for X display"); + return false; + } + + cmap_ = XCreateColormap(display, root, vi->visual, AllocNone); + + ::GLXContext temp_context = glXCreateContext(display, vi, NULL, GL_TRUE); + if (!temp_context) { + FatalGLError("Unable to create temporary GLX context"); + return false; + } + xid_ = GDK_WINDOW_XID(gtk_widget_get_window(window)); + glXMakeCurrent(display, xid_, temp_context); + + tls_glew_context_ = glew_context_.get(); + tls_glxew_context_ = glxew_context_.get(); + if (glewInit() != GLEW_OK) { + FatalGLError("Unable to initialize GLEW."); + return false; + } + if (glxewInit() != GLEW_OK) { + FatalGLError("Unable to initialize GLXEW."); + return false; + } + + if (!GLXEW_ARB_create_context) { + FatalGLError("GLX_ARB_create_context not supported by GL ICD."); + return false; + } + + if (GLEW_ARB_robustness) { + robust_access_supported_ = true; + } + + int context_flags = 0; + if (FLAGS_gl_debug) { + context_flags |= GLX_CONTEXT_DEBUG_BIT_ARB; + } + if (robust_access_supported_) { + context_flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; + } + + int attrib_list[] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, + 4, + GLX_CONTEXT_MINOR_VERSION_ARB, + 5, + GLX_CONTEXT_FLAGS_ARB, + context_flags, + GLX_CONTEXT_PROFILE_MASK_ARB, + GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, + GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + robust_access_supported_ ? GLX_LOSE_CONTEXT_ON_RESET_ARB : 0, + 0}; + GLXContext* share_context_glx = static_cast(share_context); + glx_context_ = glXCreateContextAttribsARB( + display, nullptr, + share_context ? share_context_glx->glx_context_ : nullptr, True, + attrib_list); + glXMakeCurrent(display, 0, nullptr); + glXDestroyContext(display, temp_context); + if (!glx_context_) { + FatalGLError("Unable to create real GL context."); + return false; + } + + if (!MakeCurrent()) { + FatalGLError("Could not make real GL context current."); + return false; + } + + XELOGI("Successfully created OpenGL context:"); + XELOGI(" GL_VENDOR: %s", glGetString(GL_VENDOR)); + XELOGI(" GL_VERSION: %s", glGetString(GL_VERSION)); + XELOGI(" GL_RENDERER: %s", glGetString(GL_RENDERER)); + XELOGI(" GL_SHADING_LANGUAGE_VERSION: %s", + glGetString(GL_SHADING_LANGUAGE_VERSION)); + + while (glGetError()) { + // Clearing errors. + } + + SetupDebugging(); + + if (!blitter_.Initialize()) { + FatalGLError("Unable to initialize blitter."); + ClearCurrent(); + return false; + } + + immediate_drawer_ = std::make_unique(this); + + ClearCurrent(); + + return true; +} + +std::unique_ptr GLXContext::CreateOffscreen( + GraphicsProvider* provider, GLXContext* parent_context) { + assert_not_null(parent_context->glx_context_); + + ::GLXContext new_glrc; + { + GraphicsContextLock context_lock(parent_context); + + int context_flags = 0; + if (FLAGS_gl_debug) { + context_flags |= GLX_CONTEXT_DEBUG_BIT_ARB; + } + + bool robust_access_supported = parent_context->robust_access_supported_; + if (robust_access_supported) { + context_flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; + } + + int attrib_list[] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, + 4, + GLX_CONTEXT_MINOR_VERSION_ARB, + 5, + GLX_CONTEXT_FLAGS_ARB, + context_flags, + GLX_CONTEXT_PROFILE_MASK_ARB, + GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, + GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, + robust_access_supported ? GLX_LOSE_CONTEXT_ON_RESET_ARB : 0, + 0}; + new_glrc = glXCreateContextAttribsARB(parent_context->disp_, nullptr, + parent_context->glx_context_, True, + attrib_list); + if (!new_glrc) { + FatalGLError("Could not create shared context."); + return nullptr; + } + } + + auto new_context = std::unique_ptr( + new GLXContext(provider, parent_context->target_window_)); + new_context->glx_context_ = new_glrc; + new_context->window_ = parent_context->window_; + new_context->draw_area_ = parent_context->draw_area_; + new_context->disp_ = parent_context->disp_; + new_context->xid_ = parent_context->xid_; + new_context->robust_access_supported_ = + parent_context->robust_access_supported_; + if (!new_context->MakeCurrent()) { + FatalGLError("Could not make new GL context current."); + return nullptr; + } + if (!glGetString(GL_EXTENSIONS)) { + new_context->ClearCurrent(); + FatalGLError("New GL context did not have extensions."); + return nullptr; + } + + if (glewInit() != GLEW_OK) { + new_context->ClearCurrent(); + FatalGLError("Unable to initialize GLEW on shared context."); + return nullptr; + } + if (glxewInit() != GLEW_OK) { + new_context->ClearCurrent(); + FatalGLError("Unable to initialize GLXEW on shared context."); + return nullptr; + } + + new_context->SetupDebugging(); + + if (!new_context->blitter_.Initialize()) { + FatalGLError("Unable to initialize blitter on shared context."); + return nullptr; + } + + new_context->ClearCurrent(); + + return new_context; +} + +bool GLXContext::is_current() { + return tls_glew_context_ == glew_context_.get(); +} + +bool GLXContext::MakeCurrent() { + SCOPE_profile_cpu_f("gpu"); + if (FLAGS_thread_safe_gl) { + global_gl_mutex_.lock(); + } + + if (!glXMakeCurrent(disp_, xid_, glx_context_)) { + if (FLAGS_thread_safe_gl) { + global_gl_mutex_.unlock(); + } + FatalGLError("Unable to make GL context current."); + return false; + } + tls_glew_context_ = glew_context_.get(); + tls_glxew_context_ = glxew_context_.get(); + return true; +} + +void GLXContext::ClearCurrent() { + if (!FLAGS_disable_gl_context_reset) { + glXMakeCurrent(disp_, 0, nullptr); + } + tls_glew_context_ = nullptr; + tls_glxew_context_ = nullptr; + + if (FLAGS_thread_safe_gl) { + global_gl_mutex_.unlock(); + } +} + +void GLXContext::BeginSwap() { + SCOPE_profile_cpu_i("gpu", "xe::ui::gl::GLXContext::BeginSwap"); + float clear_color[] = {238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 1.0f}; + if (FLAGS_random_clear_color) { + clear_color[0] = + rand() / static_cast(RAND_MAX); // NOLINT(runtime/threadsafe_fn) + clear_color[1] = 1.0f; + clear_color[2] = 0.0f; + clear_color[3] = 1.0f; + } + glClearNamedFramebufferfv(0, GL_COLOR, 0, clear_color); +} + +void GLXContext::EndSwap() { + SCOPE_profile_cpu_i("gpu", "xe::ui::gl::GLXContext::EndSwap"); + glXSwapBuffers(disp_, xid_); +} + +} // namespace gl +} // namespace ui +} // namespace xe diff --git a/src/xenia/ui/gl/gl_context_x11.h b/src/xenia/ui/gl/gl_context_x11.h new file mode 100644 index 000000000..6eea7fdb7 --- /dev/null +++ b/src/xenia/ui/gl/gl_context_x11.h @@ -0,0 +1,69 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_UI_GL_GLX_CONTEXT_H_ +#define XENIA_UI_GL_GLX_CONTEXT_H_ + +#include + +#include + +#include "third_party/GL/glxew.h" +#include "xenia/base/platform_linux.h" +#include "xenia/ui/gl/blitter.h" +#include "xenia/ui/gl/gl.h" +#include "xenia/ui/gl/gl_context.h" +#include "xenia/ui/graphics_context.h" + +DECLARE_bool(thread_safe_gl); + +namespace xe { +namespace ui { +namespace gl { + +class GLImmediateDrawer; +class GLProvider; + +class GLXContext : public GLContext { + public: + ~GLXContext() override; + + bool is_current() override; + + bool MakeCurrent() override; + void ClearCurrent() override; + + void BeginSwap() override; + void EndSwap() override; + + protected: + static std::unique_ptr CreateOffscreen( + GraphicsProvider* provider, GLXContext* parent_context); + + bool Initialize(GLContext* share_context) override; + void* handle() override { return glx_context_; } + + private: + friend class GLContext; + GLXContext(GraphicsProvider* provider, Window* target_window); + std::unique_ptr glew_context_; + std::unique_ptr glxew_context_; + ::GLXContext glx_context_; + GtkWidget* window_; + GtkWidget* draw_area_; + Colormap cmap_; + Display* disp_; + int xid_; +}; + +} // namespace gl +} // namespace ui +} // namespace xe + +#endif // XENIA_UI_GL_GL_CONTEXT_H_ diff --git a/src/xenia/ui/imgui_drawer.cc b/src/xenia/ui/imgui_drawer.cc index 62d3c1d6b..642e5ec45 100644 --- a/src/xenia/ui/imgui_drawer.cc +++ b/src/xenia/ui/imgui_drawer.cc @@ -143,7 +143,8 @@ void ImGuiDrawer::SetupFont() { font_config.OversampleH = font_config.OversampleV = 1; font_config.PixelSnapH = true; static const ImWchar font_glyph_ranges[] = { - 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x0020, + 0x00FF, // Basic Latin + Latin Supplement 0, }; io.Fonts->AddFontFromMemoryCompressedBase85TTF( diff --git a/src/xenia/ui/loop_gtk.cc b/src/xenia/ui/loop_gtk.cc new file mode 100644 index 000000000..8beb967e5 --- /dev/null +++ b/src/xenia/ui/loop_gtk.cc @@ -0,0 +1,78 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2016 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/ui/loop_gtk.h" + +#include "xenia/base/assert.h" + +namespace xe { +namespace ui { + +class PostedFn { + public: + explicit PostedFn(std::function fn) : fn_(std::move(fn)) {} + void Call() { fn_(); } + + private: + std::function fn_; +}; + +std::unique_ptr Loop::Create() { return std::make_unique(); } + +GTKLoop::GTKLoop() : thread_id_() { + gtk_init(nullptr, nullptr); + xe::threading::Fence init_fence; + thread_ = std::thread([&init_fence, this]() { + xe::threading::set_name("GTK Loop"); + + thread_id_ = std::this_thread::get_id(); + init_fence.Signal(); + + ThreadMain(); + + quit_fence_.Signal(); + }); + init_fence.Wait(); +} + +GTKLoop::~GTKLoop() { + Quit(); + thread_.join(); +} + +void GTKLoop::ThreadMain() { gtk_main(); } + +bool GTKLoop::is_on_loop_thread() { + return thread_id_ == std::this_thread::get_id(); +} + +gboolean _posted_fn_thunk(gpointer posted_fn) { + PostedFn* Fn = reinterpret_cast(posted_fn); + Fn->Call(); + return G_SOURCE_REMOVE; +} + +void GTKLoop::Post(std::function fn) { + assert_true(thread_id_ != std::thread::id()); + gdk_threads_add_idle(_posted_fn_thunk, + reinterpret_cast(new PostedFn(std::move(fn)))); +} + +void GTKLoop::PostDelayed(std::function fn, uint64_t delay_millis) { + gdk_threads_add_timeout( + delay_millis, _posted_fn_thunk, + reinterpret_cast(new PostedFn(std::move(fn)))); +} + +void GTKLoop::Quit() { assert_true(thread_id_ != std::thread::id()); } + +void GTKLoop::AwaitQuit() { quit_fence_.Wait(); } + +} // namespace ui +} // namespace xe diff --git a/src/xenia/ui/loop_gtk.h b/src/xenia/ui/loop_gtk.h new file mode 100644 index 000000000..4e24d8915 --- /dev/null +++ b/src/xenia/ui/loop_gtk.h @@ -0,0 +1,50 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2016 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_UI_LOOP_GTK_H_ +#define XENIA_UI_LOOP_GTK_H_ + +#include +#include +#include + +#include "xenia/base/platform_linux.h" +#include "xenia/base/threading.h" +#include "xenia/ui/loop.h" + +namespace xe { +namespace ui { + +class GTKWindow; + +class GTKLoop : public Loop { + public: + GTKLoop(); + ~GTKLoop() override; + + bool is_on_loop_thread() override; + + void Post(std::function fn) override; + void PostDelayed(std::function fn, uint64_t delay_millis) override; + + void Quit() override; + void AwaitQuit() override; + + private: + void ThreadMain(); + + std::thread::id thread_id_; + std::thread thread_; + xe::threading::Fence quit_fence_; +}; + +} // namespace ui +} // namespace xe + +#endif // XENIA_UI_LOOP_GTK_H_ diff --git a/src/xenia/ui/menu_item.h b/src/xenia/ui/menu_item.h index 4cdc5cca2..ca45a5b8b 100644 --- a/src/xenia/ui/menu_item.h +++ b/src/xenia/ui/menu_item.h @@ -12,6 +12,7 @@ #include #include +#include #include #include "xenia/ui/ui_event.h" diff --git a/src/xenia/ui/vulkan/blitter.cc b/src/xenia/ui/vulkan/blitter.cc index 5e838313e..251d02098 100644 --- a/src/xenia/ui/vulkan/blitter.cc +++ b/src/xenia/ui/vulkan/blitter.cc @@ -256,7 +256,10 @@ void Blitter::BlitTexture2D(VkCommandBuffer command_buffer, VkFence fence, vkCmdSetViewport(command_buffer, 0, 1, &viewport); VkRect2D scissor = { - dst_offset.x, dst_offset.y, dst_extents.width, dst_extents.height, + dst_offset.x, + dst_offset.y, + dst_extents.width, + dst_extents.height, }; vkCmdSetScissor(command_buffer, 0, 1, &scissor); @@ -305,7 +308,10 @@ void Blitter::BlitTexture2D(VkCommandBuffer command_buffer, VkFence fence, &vtx_constants); PixPushConstants pix_constants = { - 0, 0, 0, swap_channels ? 1 : 0, + 0, + 0, + 0, + swap_channels ? 1 : 0, }; vkCmdPushConstants(command_buffer, pipeline_layout_, VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(VtxPushConstants), @@ -540,7 +546,8 @@ VkPipeline Blitter::CreatePipeline(VkRenderPass render_pass, dynamic_state_info.pNext = nullptr; dynamic_state_info.flags = 0; VkDynamicState dynamic_states[] = { - VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, }; dynamic_state_info.dynamicStateCount = static_cast(xe::countof(dynamic_states)); diff --git a/src/xenia/ui/vulkan/vulkan.h b/src/xenia/ui/vulkan/vulkan.h index 7a7e64f10..38a4400f7 100644 --- a/src/xenia/ui/vulkan/vulkan.h +++ b/src/xenia/ui/vulkan/vulkan.h @@ -16,6 +16,8 @@ #if XE_PLATFORM_WIN32 #define VK_USE_PLATFORM_WIN32_KHR 1 +#elif XE_PLATFORM_LINUX +#define VK_USE_PLATFORM_XCB_KHR 1 #else #error Platform not yet supported. #endif // XE_PLATFORM_WIN32 diff --git a/src/xenia/ui/vulkan/vulkan_context.cc b/src/xenia/ui/vulkan/vulkan_context.cc index 381fb0ab7..da3d323be 100644 --- a/src/xenia/ui/vulkan/vulkan_context.cc +++ b/src/xenia/ui/vulkan/vulkan_context.cc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2016 Ben Vanik. All rights reserved. * + * Copyright 2017 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -25,6 +25,10 @@ #include "xenia/ui/vulkan/vulkan_util.h" #include "xenia/ui/window.h" +#if XE_PLATFORM_LINUX +#include "xenia/ui/window_gtk.h" +#endif + namespace xe { namespace ui { namespace vulkan { @@ -61,6 +65,29 @@ bool VulkanContext::Initialize() { auto err = vkCreateWin32SurfaceKHR(*provider->instance(), &create_info, nullptr, &surface); CheckResult(err, "vkCreateWin32SurfaceKHR"); +#elif XE_PLATFORM_LINUX +#ifdef GDK_WINDOWING_X11 + GtkWidget* window_handle = + static_cast(target_window_->native_handle()); + GdkDisplay* gdk_display = gtk_widget_get_display(window_handle); + assert(GDK_IS_X11_DISPLAY(gdk_display)); + xcb_connection_t* connection = + XGetXCBConnection(gdk_x11_display_get_xdisplay(gdk_display)); + xcb_window_t window = + gdk_x11_window_get_xid(gtk_widget_get_window(window_handle)); + VkXcbSurfaceCreateInfoKHR create_info; + create_info.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; + create_info.pNext = nullptr; + create_info.flags = 0; + create_info.connection = static_cast( + target_window_->native_platform_handle()); + create_info.window = static_cast(window); + auto err = vkCreateXcbSurfaceKHR(*provider->instance(), &create_info, + nullptr, &surface); + CheckResult(err, "vkCreateXcbSurfaceKHR"); +#else +#error Unsupported GDK Backend on Linux. +#endif // GDK_WINDOWING_X11 #else #error Platform not yet implemented. #endif // XE_PLATFORM_WIN32 diff --git a/src/xenia/ui/vulkan/vulkan_device.cc b/src/xenia/ui/vulkan/vulkan_device.cc index 166a18b01..b8ded460e 100644 --- a/src/xenia/ui/vulkan/vulkan_device.cc +++ b/src/xenia/ui/vulkan/vulkan_device.cc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2016 Ben Vanik. All rights reserved. * + * Copyright 2017 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -12,6 +12,7 @@ #include #include +#include #include #include diff --git a/src/xenia/ui/vulkan/vulkan_immediate_drawer.cc b/src/xenia/ui/vulkan/vulkan_immediate_drawer.cc index 9f4b42427..6024f859a 100644 --- a/src/xenia/ui/vulkan/vulkan_immediate_drawer.cc +++ b/src/xenia/ui/vulkan/vulkan_immediate_drawer.cc @@ -224,7 +224,9 @@ class VulkanImmediateTexture : public ImmediateTexture { view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; view_info.format = VK_FORMAT_R8G8B8A8_UNORM; view_info.components = { - VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, + VK_COMPONENT_SWIZZLE_R, + VK_COMPONENT_SWIZZLE_G, + VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A, }; view_info.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; @@ -597,7 +599,8 @@ VulkanImmediateDrawer::VulkanImmediateDrawer(VulkanContext* graphics_context) dynamic_state_info.pNext = nullptr; dynamic_state_info.flags = 0; VkDynamicState dynamic_states[] = { - VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, }; dynamic_state_info.dynamicStateCount = static_cast(xe::countof(dynamic_states)); diff --git a/src/xenia/ui/vulkan/vulkan_instance.cc b/src/xenia/ui/vulkan/vulkan_instance.cc index cb7a3ee91..3c51dfa1a 100644 --- a/src/xenia/ui/vulkan/vulkan_instance.cc +++ b/src/xenia/ui/vulkan/vulkan_instance.cc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2016 Ben Vanik. All rights reserved. * + * Copyright 2017 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -26,6 +26,10 @@ #include "xenia/ui/vulkan/vulkan_util.h" #include "xenia/ui/window.h" +#if XE_PLATFORM_LINUX +#include "xenia/ui/window_gtk.h" +#endif + #define VK_API_VERSION VK_API_VERSION_1_0 namespace xe { @@ -385,6 +389,29 @@ bool VulkanInstance::QueryDevices(Window* any_target_window) { create_info.hwnd = static_cast(any_target_window->native_handle()); err = vkCreateWin32SurfaceKHR(handle, &create_info, nullptr, &any_surface); CheckResult(err, "vkCreateWin32SurfaceKHR"); +#elif XE_PLATFORM_LINUX +#ifdef GDK_WINDOWING_X11 + GtkWidget* window_handle = + static_cast(any_target_window->native_handle()); + GdkDisplay* gdk_display = gtk_widget_get_display(window_handle); + assert(GDK_IS_X11_DISPLAY(gdk_display)); + xcb_connection_t* connection = + XGetXCBConnection(gdk_x11_display_get_xdisplay(gdk_display)); + xcb_window_t window = + gdk_x11_window_get_xid(gtk_widget_get_window(window_handle)); + VkXcbSurfaceCreateInfoKHR create_info; + create_info.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; + create_info.pNext = nullptr; + create_info.flags = 0; + create_info.connection = static_cast( + any_target_window->native_platform_handle()); + create_info.window = static_cast(window); + auto err = + vkCreateXcbSurfaceKHR(handle, &create_info, nullptr, &any_surface); + CheckResult(err, "vkCreateXcbSurfaceKHR"); +#else +#error Unsupported GDK Backend on Linux. +#endif // GDK_WINDOWING_X11 #else #error Platform not yet implemented. #endif // XE_PLATFORM_WIN32 diff --git a/src/xenia/ui/window_demo.cc b/src/xenia/ui/window_demo.cc index 454864a92..13b3689af 100644 --- a/src/xenia/ui/window_demo.cc +++ b/src/xenia/ui/window_demo.cc @@ -15,7 +15,6 @@ #include "xenia/base/clock.h" #include "xenia/base/logging.h" #include "xenia/base/main.h" -#include "xenia/base/platform_win.h" #include "xenia/base/profiling.h" #include "xenia/base/threading.h" #include "xenia/ui/graphics_provider.h" diff --git a/src/xenia/ui/window_gtk.cc b/src/xenia/ui/window_gtk.cc new file mode 100644 index 000000000..2e94f6ddc --- /dev/null +++ b/src/xenia/ui/window_gtk.cc @@ -0,0 +1,451 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2016 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include "xenia/base/assert.h" +#include "xenia/base/logging.h" +#include "xenia/base/platform_linux.h" +#include "xenia/ui/window_gtk.h" + +namespace xe { +namespace ui { + +class FnWrapper { + public: + explicit FnWrapper(std::function fn) : fn_(std::move(fn)) {} + void Call() { fn_(); } + + private: + std::function fn_; +}; + +std::unique_ptr Window::Create(Loop* loop, const std::wstring& title) { + return std::make_unique(loop, title); +} + +GTKWindow::GTKWindow(Loop* loop, const std::wstring& title) + : Window(loop, title) {} + +GTKWindow::~GTKWindow() { + OnDestroy(); + if (window_) { + gtk_widget_destroy(window_); + window_ = nullptr; + } +} + +bool GTKWindow::Initialize() { return OnCreate(); } + +void gtk_event_handler_(GtkWidget* widget, GdkEvent* event, gpointer data) { + GTKWindow* window = reinterpret_cast(data); + switch (event->type) { + case GDK_OWNER_CHANGE: + window->HandleWindowOwnerChange(&(event->owner_change)); + break; + case GDK_VISIBILITY_NOTIFY: + window->HandleWindowVisibility(&(event->visibility)); + break; + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + window->HandleKeyboard(&(event->key)); + break; + case GDK_SCROLL: + case GDK_BUTTON_PRESS: + case GDK_MOTION_NOTIFY: + window->HandleMouse(&(event->any)); + break; + case GDK_FOCUS_CHANGE: + window->HandleWindowFocus(&(event->focus_change)); + break; + case GDK_CONFIGURE: + window->HandleWindowResize(&(event->configure)); + default: + // Do nothing + return; + } +} + +void GTKWindow::Create() { + window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(window_), (gchar*)title_.c_str()); + gtk_window_set_default_size(GTK_WINDOW(window_), 1280, 720); + gtk_widget_show_all(window_); + g_signal_connect(G_OBJECT(window_), "destroy", G_CALLBACK(gtk_main_quit), + NULL); + g_signal_connect(G_OBJECT(window_), "event", G_CALLBACK(gtk_event_handler_), + reinterpret_cast(this)); +} + +bool GTKWindow::OnCreate() { + loop()->PostSynchronous([this]() { this->Create(); }); + return super::OnCreate(); +} + +void GTKWindow::OnDestroy() { super::OnDestroy(); } + +void GTKWindow::OnClose() { + if (!closing_ && window_) { + closing_ = true; + gtk_widget_destroy(window_); + window_ = nullptr; + } + super::OnClose(); +} + +bool GTKWindow::set_title(const std::wstring& title) { + if (!super::set_title(title)) { + return false; + } + gtk_window_set_title(GTK_WINDOW(window_), (gchar*)title.c_str()); + return true; +} + +bool GTKWindow::SetIcon(const void* buffer, size_t size) { + // TODO(dougvj) Set icon after changin buffer to the correct format. (the + // call is gtk_window_set_icon) + return false; +} + +bool GTKWindow::is_fullscreen() const { return fullscreen_; } + +void GTKWindow::ToggleFullscreen(bool fullscreen) { + if (fullscreen == is_fullscreen()) { + return; + } + + fullscreen_ = fullscreen; + + if (fullscreen) { + gtk_window_fullscreen(GTK_WINDOW(window_)); + } else { + gtk_window_unfullscreen(GTK_WINDOW(window_)); + } +} + +bool GTKWindow::is_bordered() const { + return gtk_window_get_decorated(GTK_WINDOW(window_)); +} + +void GTKWindow::set_bordered(bool enabled) { + if (is_fullscreen()) { + // Don't screw with the borders if we're fullscreen. + return; + } + + gtk_window_set_decorated(GTK_WINDOW(window_), enabled); +} + +void GTKWindow::set_cursor_visible(bool value) { + if (is_cursor_visible_ == value) { + return; + } + if (value) { + // TODO(dougvj) Show and hide cursor + } else { + } +} + +void GTKWindow::set_focus(bool value) { + if (has_focus_ == value) { + return; + } + if (window_) { + if (value) { + gtk_window_activate_focus(GTK_WINDOW(window_)); + } else { + // TODO(dougvj) Check to see if we need to do something here to unset + // the focus. + } + } else { + has_focus_ = value; + } +} + +void GTKWindow::Resize(int32_t width, int32_t height) { + gtk_window_resize(GTK_WINDOW(window_), width, height); +} + +void GTKWindow::Resize(int32_t left, int32_t top, int32_t right, + int32_t bottom) { + // TODO(dougvj) Verify that this is the desired behavior from this call + gtk_window_move(GTK_WINDOW(window_), left, top); + gtk_window_resize(GTK_WINDOW(window_), left - right, top - bottom); +} + +void GTKWindow::OnResize(UIEvent* e) { + int32_t width; + int32_t height; + gtk_window_get_size(GTK_WINDOW(window_), &width, &height); + if (width != width_ || height != height_) { + width_ = width; + height_ = height; + Layout(); + } + super::OnResize(e); +} + +void GTKWindow::Invalidate() { + super::Invalidate(); + // TODO(dougvj) I am not sure what this is supposed to do +} + +void GTKWindow::Close() { + if (closing_) { + return; + } + closing_ = true; + Close(); + OnClose(); +} + +void GTKWindow::OnMainMenuChange() { + // We need to store the old handle for detachment + static GtkWidget* box = nullptr; + auto main_menu = reinterpret_cast(main_menu_.get()); + if (main_menu && !is_fullscreen()) { + if (box) gtk_widget_destroy(box); + GtkWidget* menu = main_menu->handle(); + box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); + gtk_box_pack_start(GTK_BOX(box), menu, FALSE, FALSE, 3); + gtk_container_add(GTK_CONTAINER(window_), box); + } +} + +bool GTKWindow::HandleWindowOwnerChange(GdkEventOwnerChange* event) { + if (event->type == GDK_OWNER_CHANGE) { + if (event->reason == GDK_OWNER_CHANGE_DESTROY) { + OnDestroy(); + } else if (event->reason == GDK_OWNER_CHANGE_CLOSE) { + closing_ = true; + Close(); + OnClose(); + } + return true; + } + return false; +} + +bool GTKWindow::HandleWindowResize(GdkEventConfigure* event) { + if (event->type == GDK_CONFIGURE) { + auto e = UIEvent(this); + OnResize(&e); + return true; + } + return false; +} + +bool GTKWindow::HandleWindowVisibility(GdkEventVisibility* event) { + // TODO(dougvj) The gdk docs say that this is deprecated because modern window + // managers composite everything and nothing is truly hidden. + if (event->type == GDK_VISIBILITY_NOTIFY) { + if (event->state == GDK_VISIBILITY_UNOBSCURED) { + auto e = UIEvent(this); + OnVisible(&e); + } else { + auto e = UIEvent(this); + OnHidden(&e); + } + return true; + } + return false; +} + +bool GTKWindow::HandleWindowFocus(GdkEventFocus* event) { + if (event->type == GDK_FOCUS_CHANGE) { + if (!event->in) { + has_focus_ = false; + auto e = UIEvent(this); + OnLostFocus(&e); + } else { + has_focus_ = true; + auto e = UIEvent(this); + OnGotFocus(&e); + } + return true; + } + return false; +} + +bool GTKWindow::HandleMouse(GdkEventAny* event) { + MouseEvent::Button button = MouseEvent::Button::kNone; + int32_t dx = 0; + int32_t dy = 0; + int32_t x = 0; + int32_t y = 0; + switch (event->type) { + default: + // Double click/etc? + return true; + case GDK_BUTTON_PRESS: + case GDK_BUTTON_RELEASE: { + GdkEventButton* e = reinterpret_cast(event); + switch (e->button) { + case 1: + button = MouseEvent::Button::kLeft; + break; + case 3: + button = MouseEvent::Button::kRight; + break; + case 2: + button = MouseEvent::Button::kMiddle; + break; + case 4: + button = MouseEvent::Button::kX1; + break; + case 5: + button = MouseEvent::Button::kX2; + break; + } + x = e->x; + y = e->y; + break; + } + case GDK_MOTION_NOTIFY: { + GdkEventMotion* e = reinterpret_cast(event); + x = e->x; + y = e->y; + break; + } + case GDK_SCROLL: { + GdkEventScroll* e = reinterpret_cast(event); + x = e->x; + y = e->y; + dx = e->delta_x; + dy = e->delta_y; + break; + } + } + + auto e = MouseEvent(this, button, x, y, dx, dy); + switch (event->type) { + case GDK_BUTTON_PRESS: + OnMouseDown(&e); + break; + case GDK_BUTTON_RELEASE: + OnMouseUp(&e); + break; + case GDK_MOTION_NOTIFY: + OnMouseMove(&e); + break; + case GDK_SCROLL: + OnMouseWheel(&e); + break; + default: + return false; + } + return e.is_handled(); +} + +bool GTKWindow::HandleKeyboard(GdkEventKey* event) { + unsigned int modifiers = event->state; + bool shift_pressed = modifiers & GDK_SHIFT_MASK; + bool ctrl_pressed = modifiers & GDK_CONTROL_MASK; + bool alt_pressed = modifiers & GDK_META_MASK; + bool super_pressed = modifiers & GDK_SUPER_MASK; + auto e = + KeyEvent(this, event->hardware_keycode, 1, event->type == GDK_KEY_RELEASE, + shift_pressed, ctrl_pressed, alt_pressed, super_pressed); + switch (event->type) { + case GDK_KEY_PRESS: + OnKeyDown(&e); + break; + case GDK_KEY_RELEASE: + OnKeyUp(&e); + break; + // TODO(dougvj) GDK doesn't have a KEY CHAR event, so we will have to + // figure out its equivalent here to call OnKeyChar(&e); + default: + return false; + } + return e.is_handled(); +} + +std::unique_ptr MenuItem::Create(Type type, + const std::wstring& text, + const std::wstring& hotkey, + std::function callback) { + return std::make_unique(type, text, hotkey, callback); +} + +static void _menu_activate_callback(GtkWidget* menu, gpointer data) { + auto fn = reinterpret_cast(data); + fn->Call(); + delete fn; +} + +GTKMenuItem::GTKMenuItem(Type type, const std::wstring& text, + const std::wstring& hotkey, + std::function callback) + : MenuItem(type, text, hotkey, std::move(callback)) { + switch (type) { + case MenuItem::Type::kNormal: + default: + menu_ = gtk_menu_bar_new(); + break; + case MenuItem::Type::kPopup: + menu_ = gtk_menu_item_new_with_label((gchar*)xe::to_string(text).c_str()); + break; + case MenuItem::Type::kSeparator: + menu_ = gtk_separator_menu_item_new(); + break; + case MenuItem::Type::kString: + auto full_name = text; + if (!hotkey.empty()) { + full_name += L"\t" + hotkey; + } + menu_ = gtk_menu_item_new_with_label( + (gchar*)xe::to_string(full_name).c_str()); + break; + } + if (GTK_IS_MENU_ITEM(menu_)) + g_signal_connect(menu_, "activate", G_CALLBACK(_menu_activate_callback), + (gpointer) new FnWrapper(callback)); +} + +GTKMenuItem::~GTKMenuItem() { + if (menu_) { + } +} + +void GTKMenuItem::OnChildAdded(MenuItem* generic_child_item) { + auto child_item = static_cast(generic_child_item); + switch (child_item->type()) { + case MenuItem::Type::kNormal: + // Nothing special. + break; + case MenuItem::Type::kPopup: + if (GTK_IS_MENU_ITEM(menu_)) { + assert(gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_)) == nullptr); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_), child_item->handle()); + } else { + gtk_menu_shell_append(GTK_MENU_SHELL(menu_), child_item->handle()); + } + break; + case MenuItem::Type::kSeparator: + case MenuItem::Type::kString: + assert(GTK_IS_MENU_ITEM(menu_)); + // Get sub menu and if it doesn't exist create it + GtkWidget* submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_)); + if (submenu == nullptr) { + submenu = gtk_menu_new(); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_), submenu); + } + gtk_menu_shell_append(GTK_MENU_SHELL(submenu), child_item->handle()); + break; + } +} + +// TODO(dougvj) +void GTKMenuItem::OnChildRemoved(MenuItem* generic_child_item) { + assert_always(); +} + +} // namespace ui +} // namespace xe diff --git a/src/xenia/ui/window_gtk.h b/src/xenia/ui/window_gtk.h new file mode 100644 index 000000000..b19248e18 --- /dev/null +++ b/src/xenia/ui/window_gtk.h @@ -0,0 +1,102 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2016 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_UI_WINDOW_GTK_H_ +#define XENIA_UI_WINDOW_GTK_H_ + +#include +#include + +#include "xenia/base/platform_linux.h" +#include "xenia/ui/menu_item.h" +#include "xenia/ui/window.h" + +namespace xe { +namespace ui { + +class GTKWindow : public Window { + using super = Window; + + public: + GTKWindow(Loop* loop, const std::wstring& title); + ~GTKWindow() override; + + NativePlatformHandle native_platform_handle() const override { + return nullptr; + } + NativeWindowHandle native_handle() const override { return window_; } + + bool set_title(const std::wstring& title) override; + + bool SetIcon(const void* buffer, size_t size) override; + + bool is_fullscreen() const override; + void ToggleFullscreen(bool fullscreen) override; + + bool is_bordered() const override; + void set_bordered(bool enabled) override; + + void set_cursor_visible(bool value) override; + void set_focus(bool value) override; + + void Resize(int32_t width, int32_t height) override; + void Resize(int32_t left, int32_t top, int32_t right, + int32_t bottom) override; + + bool Initialize() override; + void Invalidate() override; + void Close() override; + + protected: + bool OnCreate() override; + void OnMainMenuChange() override; + void OnDestroy() override; + void OnClose() override; + + void OnResize(UIEvent* e) override; + + private: + void Create(); + GtkWidget* window_; + + friend void gtk_event_handler_(GtkWidget*, GdkEvent*, gpointer); + bool HandleMouse(GdkEventAny* event); + bool HandleKeyboard(GdkEventKey* event); + bool HandleWindowResize(GdkEventConfigure* event); + bool HandleWindowFocus(GdkEventFocus* event); + bool HandleWindowVisibility(GdkEventVisibility* event); + bool HandleWindowOwnerChange(GdkEventOwnerChange* event); + + bool closing_ = false; + bool fullscreen_ = false; +}; + +class GTKMenuItem : public MenuItem { + public: + GTKMenuItem(Type type, const std::wstring& text, const std::wstring& hotkey, + std::function callback); + ~GTKMenuItem() override; + + GtkWidget* handle() { return menu_; } + using MenuItem::OnSelected; + + protected: + void OnChildAdded(MenuItem* child_item) override; + void OnChildRemoved(MenuItem* child_item) override; + GTKMenuItem* parent_ = nullptr; + GTKMenuItem* child_ = nullptr; + + private: + GtkWidget* menu_ = nullptr; +}; + +} // namespace ui +} // namespace xe + +#endif // XENIA_UI_WINDOW_WIN_H_ diff --git a/third_party/glslang-spirv/SpvBuilder.cpp b/third_party/glslang-spirv/SpvBuilder.cpp index 13a6c946a..36bededc5 100644 --- a/third_party/glslang-spirv/SpvBuilder.cpp +++ b/third_party/glslang-spirv/SpvBuilder.cpp @@ -77,7 +77,7 @@ Id Builder::import(const char* name) { Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport); import->addStringOperand(name); - + imports.push_back(std::unique_ptr(import)); return import->getResultId(); } @@ -244,7 +244,7 @@ Id Builder::makeStructResultType(Id type0, Id type1) type = groupedTypes[OpTypeStruct][t]; if (type->getNumOperands() != 2) continue; - if (type->getIdOperand(0) != type0 || + if (type->getIdOperand(0) != type0 || type->getIdOperand(1) != type1) continue; return type->getResultId(); @@ -626,7 +626,7 @@ Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, bool Builder::isConstantOpCode(Op opcode) const { switch (opcode) { - case OpUndef: + case OpUndef: case OpConstantTrue: case OpConstantFalse: case OpConstant: @@ -743,7 +743,7 @@ Id Builder::makeDoubleConstant(double d, bool specConstant) return c->getResultId(); } -Id Builder::findCompositeConstant(Op typeClass, std::vector& comps) const +Id Builder::findCompositeConstant(Op typeClass, const std::vector& comps) const { Instruction* constant = 0; bool found = false; @@ -772,7 +772,7 @@ Id Builder::findCompositeConstant(Op typeClass, std::vector& comps) const } // Comments in header -Id Builder::makeCompositeConstant(Id typeId, std::vector& members, bool specConstant) +Id Builder::makeCompositeConstant(Id typeId, const std::vector& members, bool specConstant) { Op opcode = specConstant ? OpSpecConstantComposite : OpConstantComposite; assert(typeId); @@ -1022,7 +1022,7 @@ Id Builder::createLoad(Id lValue) } // Comments in header -Id Builder::createAccessChain(StorageClass storageClass, Id base, std::vector& offsets) +Id Builder::createAccessChain(StorageClass storageClass, Id base, const std::vector& offsets) { // Figure out the final resulting type. spv::Id typeId = getTypeId(base); @@ -1089,7 +1089,7 @@ Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned i return insert->getResultId(); } -Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, std::vector& indexes) +Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, const std::vector& indexes) { Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert); insert->addIdOperand(object); @@ -1210,7 +1210,7 @@ Id Builder::createOp(Op opCode, Id typeId, const std::vector& operands) return op->getResultId(); } -Id Builder::createFunctionCall(spv::Function* function, std::vector& args) +Id Builder::createFunctionCall(spv::Function* function, const std::vector& args) { Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall); op->addIdOperand(function->getId()); @@ -1647,7 +1647,7 @@ Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, b } // OpCompositeConstruct -Id Builder::createCompositeConstruct(Id typeId, std::vector& constituents) +Id Builder::createCompositeConstruct(Id typeId, const std::vector& constituents) { assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 && getNumTypeConstituents(typeId) == (int)constituents.size())); @@ -1848,7 +1848,7 @@ void Builder::If::makeEndIf() } // Comments in header -void Builder::makeSwitch(Id selector, int numSegments, std::vector& caseValues, std::vector& valueIndexToSegment, int defaultSegment, +void Builder::makeSwitch(Id selector, int numSegments, const std::vector& caseValues, const std::vector& valueIndexToSegment, int defaultSegment, std::vector& segmentBlocks) { Function& function = buildPoint->getParent(); diff --git a/third_party/glslang-spirv/SpvBuilder.h b/third_party/glslang-spirv/SpvBuilder.h index 7eae4fe91..28f846578 100644 --- a/third_party/glslang-spirv/SpvBuilder.h +++ b/third_party/glslang-spirv/SpvBuilder.h @@ -192,7 +192,7 @@ public: Id makeDoubleConstant(double d, bool specConstant = false); // Turn the array of constants into a proper spv constant of the requested type. - Id makeCompositeConstant(Id type, std::vector& comps, bool specConst = false); + Id makeCompositeConstant(Id type, const std::vector& comps, bool specConst = false); // Methods for adding information outside the CFG. Instruction* addEntryPoint(ExecutionModel, Function*, const char* name); @@ -240,7 +240,7 @@ public: Id createLoad(Id lValue); // Create an OpAccessChain instruction - Id createAccessChain(StorageClass, Id base, std::vector& offsets); + Id createAccessChain(StorageClass, Id base, const std::vector& offsets); // Create an OpArrayLength instruction Id createArrayLength(Id base, unsigned int member); @@ -249,7 +249,7 @@ public: Id createCompositeExtract(Id composite, Id typeId, unsigned index); Id createCompositeExtract(Id composite, Id typeId, std::vector& indexes); Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index); - Id createCompositeInsert(Id object, Id composite, Id typeId, std::vector& indexes); + Id createCompositeInsert(Id object, Id composite, Id typeId, const std::vector& indexes); Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex); Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex); @@ -263,7 +263,7 @@ public: Id createBinOp(Op, Id typeId, Id operand1, Id operand2); Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3); Id createOp(Op, Id typeId, const std::vector& operands); - Id createFunctionCall(spv::Function*, std::vector&); + Id createFunctionCall(spv::Function*, const std::vector&); // Take an rvalue (source) and a set of channels to extract from it to // make a new rvalue, which is returned. @@ -296,7 +296,7 @@ public: // Generally, the type of 'scalar' does not need to be the same type as the components in 'vector'. // The type of the created vector is a vector of components of the same type as the scalar. // - // Note: One of the arguments will change, with the result coming back that way rather than + // Note: One of the arguments will change, with the result coming back that way rather than // through the return value. void promoteScalar(Decoration precision, Id& left, Id& right); @@ -341,7 +341,7 @@ public: Id createCompositeCompare(Decoration precision, Id, Id, bool /* true if for equal, false if for not-equal */); // OpCompositeConstruct - Id createCompositeConstruct(Id typeId, std::vector& constituents); + Id createCompositeConstruct(Id typeId, const std::vector& constituents); // vector or scalar constructor Id createConstructor(Decoration precision, const std::vector& sources, Id resultTypeId); @@ -383,7 +383,7 @@ public: // Returns the right set of basic blocks to start each code segment with, so that the caller's // recursion stack can hold the memory for it. // - void makeSwitch(Id condition, int numSegments, std::vector& caseValues, std::vector& valueToSegment, int defaultSegment, + void makeSwitch(Id condition, int numSegments, const std::vector& caseValues, const std::vector& valueToSegment, int defaultSegment, std::vector& segmentBB); // return argument // Add a branch to the innermost switch's merge block. @@ -525,7 +525,7 @@ public: Id makeIntConstant(Id typeId, unsigned value, bool specConstant); Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) const; Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2) const; - Id findCompositeConstant(Op typeClass, std::vector& comps) const; + Id findCompositeConstant(Op typeClass, const std::vector& comps) const; Id collapseAccessChain(); void transferAccessChainSwizzle(bool dynamic); void simplifyAccessChainSwizzle(); diff --git a/third_party/vulkan/loader/premake5.lua b/third_party/vulkan/loader/premake5.lua index 15d05f44c..e653b278b 100644 --- a/third_party/vulkan/loader/premake5.lua +++ b/third_party/vulkan/loader/premake5.lua @@ -30,6 +30,9 @@ project("vulkan-loader") removefiles("dirent_on_windows.c") filter("platforms:Linux") defines({ + "VK_USE_PLATFORM_XCB_KHR", [[SYSCONFDIR="\"/etc\""]], + [[FALLBACK_CONFIG_DIRS="\"/etc/xdg\""]], [[DATADIR="\"/usr/share\""]], + [[FALLBACK_DATA_DIRS="\"/usr/share:/usr/local/share\""]], }) diff --git a/tools/build/scripts/platform_files.lua b/tools/build/scripts/platform_files.lua index b6d2e9ecc..4c887115e 100644 --- a/tools/build/scripts/platform_files.lua +++ b/tools/build/scripts/platform_files.lua @@ -13,6 +13,8 @@ local function match_platform_files(base_path, base_match) removefiles({base_path.."/".."**_test.cc"}) removefiles({base_path.."/".."**_posix.h", base_path.."/".."**_posix.cc"}) removefiles({base_path.."/".."**_linux.h", base_path.."/".."**_linux.cc"}) + removefiles({base_path.."/".."**_x11.h", base_path.."/".."**_x11.cc"}) + removefiles({base_path.."/".."**_gtk.h", base_path.."/".."**_gtk.cc"}) removefiles({base_path.."/".."**_mac.h", base_path.."/".."**_mac.cc"}) removefiles({base_path.."/".."**_win.h", base_path.."/".."**_win.cc"}) filter("platforms:Windows") @@ -26,6 +28,10 @@ local function match_platform_files(base_path, base_match) base_path.."/"..base_match.."_posix.cc", base_path.."/"..base_match.."_linux.h", base_path.."/"..base_match.."_linux.cc", + base_path.."/"..base_match.."_x11.h", + base_path.."/"..base_match.."_x11.cc", + base_path.."/"..base_match.."_gtk.h", + base_path.."/"..base_match.."_gtk.cc", }) filter({}) end diff --git a/xb b/xb new file mode 120000 index 000000000..e841366c6 --- /dev/null +++ b/xb @@ -0,0 +1 @@ +xenia-build \ No newline at end of file