From fa653cce5d0385fd33e1e56391c4aa7b6facbe53 Mon Sep 17 00:00:00 2001 From: Triang3l Date: Sat, 26 Jun 2021 16:19:41 +0300 Subject: [PATCH 01/42] [Kernel] Fix a comment length lint issue --- src/xenia/kernel/xam/xam_user.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/xenia/kernel/xam/xam_user.cc b/src/xenia/kernel/xam/xam_user.cc index 11457e822..536643bfb 100644 --- a/src/xenia/kernel/xam/xam_user.cc +++ b/src/xenia/kernel/xam/xam_user.cc @@ -547,7 +547,8 @@ DECLARE_XAM_EXPORT1(XamUserAreUsersFriends, kUserProfiles, kStub); dword_result_t XamShowSigninUI(dword_t unk, dword_t unk_mask) { // Mask values vary. Probably matching user types? Local/remote? - // To fix game modes that display a 4 profile signin UI (even if playing alone): + // To fix game modes that display a 4 profile signin UI (even if playing + // alone): // XN_SYS_SIGNINCHANGED kernel_state()->BroadcastNotification(0x0000000A, 1); // Games seem to sit and loop until we trigger this notification: From 458dbba4ae53e37e72f992476fd733bf68bcf4d4 Mon Sep 17 00:00:00 2001 From: gibbed Date: Sat, 26 Jun 2021 12:19:51 -0500 Subject: [PATCH 02/42] Ensure that logging waits before shutting down. - Ensure that logging waits until everything is written before shutting down. - Fix a bug where a new log line would not be written until the next log line had been appended. --- src/xenia/base/logging.cc | 77 +++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 36 deletions(-) diff --git a/src/xenia/base/logging.cc b/src/xenia/base/logging.cc index 0b195e85a..cf610ad39 100644 --- a/src/xenia/base/logging.cc +++ b/src/xenia/base/logging.cc @@ -58,7 +58,7 @@ struct LogLine { size_t buffer_length; uint32_t thread_id; uint16_t _pad_0; // (2b) padding - uint8_t _pad_1; // (1b) padding + bool terminate; char prefix_char; }; @@ -81,8 +81,7 @@ class Logger { explicit Logger(const std::string_view app_name) : wait_strategy_(), claim_strategy_(kBlockCount, wait_strategy_), - consumed_(wait_strategy_), - running_(true) { + consumed_(wait_strategy_) { claim_strategy_.add_claim_barrier(consumed_); write_thread_ = @@ -91,7 +90,7 @@ class Logger { } ~Logger() { - running_ = false; + AppendLine(0, '\0', nullptr, 0, true); // append a terminator xe::threading::Wait(write_thread_.get(), true); } @@ -124,7 +123,6 @@ class Logger { std::vector> sinks_; - std::atomic running_; std::unique_ptr write_thread_; void Write(const char* buf, size_t size) { @@ -153,19 +151,15 @@ class Logger { auto available_sequence = claim_strategy_.wait_until_published( next_range.last(), last_sequence); - auto available_difference = - dp::difference(available_sequence, next_sequence); - size_t read_count = 0; - if (available_difference > 0 && - static_cast(available_difference) >= desired_count) { - auto available_range = dp::sequence_range( - next_sequence, static_cast(available_difference)); + { + auto available_range = next_range; auto available_count = available_range.size(); rb.set_write_offset(BlockOffset(available_range.end())); + bool terminate = false; for (size_t i = available_range.first(); i != available_range.end();) { rb.set_read_offset(BlockOffset(i)); @@ -182,24 +176,26 @@ class Logger { read_count += needed_count; i += needed_count; - char prefix[] = { - line.prefix_char, - '>', - ' ', - '?', // Thread ID gets placed here (8 chars). - '?', - '?', - '?', - '?', - '?', - '?', - '?', - ' ', - 0, - }; - fmt::format_to_n(prefix + 3, sizeof(prefix) - 3, "{:08X}", - line.thread_id); - Write(prefix, sizeof(prefix) - 1); + if (line.prefix_char) { + char prefix[] = { + line.prefix_char, + '>', + ' ', + '?', // Thread ID gets placed here (8 chars). + '?', + '?', + '?', + '?', + '?', + '?', + '?', + ' ', + 0, + }; + fmt::format_to_n(prefix + 3, sizeof(prefix) - 3, "{:08X}", + line.thread_id); + Write(prefix, sizeof(prefix) - 1); + } if (line.buffer_length) { // Get access to the line data - which may be split in the ring @@ -228,8 +224,16 @@ class Logger { const char suffix[1] = {'\n'}; Write(suffix, 1); } + + if (line.terminate) { + terminate = true; + } } } + + if (terminate) { + break; + } } if (read_count) { @@ -237,7 +241,7 @@ class Logger { auto read_range = dp::sequence_range(next_sequence, read_count); next_sequence = read_range.end(); last_sequence = read_range.last(); - consumed_.publish(read_range.last()); + consumed_.publish(last_sequence); desired_count = 1; @@ -249,9 +253,6 @@ class Logger { idle_loops = 0; } else { - if (!running_) { - break; - } if (idle_loops >= 1000) { // Introduce a waiting period. xe::threading::Sleep(std::chrono::milliseconds(50)); @@ -264,7 +265,8 @@ class Logger { public: void AppendLine(uint32_t thread_id, const char prefix_char, - const char* buffer_data, size_t buffer_length) { + const char* buffer_data, size_t buffer_length, + bool terminate = false) { size_t count = BlockCount(sizeof(LogLine) + buffer_length); auto range = claim_strategy_.claim(count); @@ -278,9 +280,12 @@ class Logger { line.buffer_length = buffer_length; line.thread_id = thread_id; line.prefix_char = prefix_char; + line.terminate = terminate; rb.Write(&line, sizeof(LogLine)); - rb.Write(buffer_data, buffer_length); + if (buffer_length) { + rb.Write(buffer_data, buffer_length); + } claim_strategy_.publish(range); } From 6bd96a5091386cf4fea7145bb4db9b96c323daaa Mon Sep 17 00:00:00 2001 From: gibbed Date: Sat, 26 Jun 2021 12:23:42 -0500 Subject: [PATCH 03/42] Remove unconditional block in logging. Remove unconditional block in logging. This was done so the previous commit shows an actual useful diff. --- src/xenia/base/logging.cc | 131 +++++++++++++++++++------------------- 1 file changed, 64 insertions(+), 67 deletions(-) diff --git a/src/xenia/base/logging.cc b/src/xenia/base/logging.cc index cf610ad39..d88a94879 100644 --- a/src/xenia/base/logging.cc +++ b/src/xenia/base/logging.cc @@ -152,88 +152,85 @@ class Logger { next_range.last(), last_sequence); size_t read_count = 0; + auto available_range = next_range; + auto available_count = available_range.size(); - { - auto available_range = next_range; - auto available_count = available_range.size(); + rb.set_write_offset(BlockOffset(available_range.end())); - rb.set_write_offset(BlockOffset(available_range.end())); + bool terminate = false; + for (size_t i = available_range.first(); i != available_range.end();) { + rb.set_read_offset(BlockOffset(i)); - bool terminate = false; - for (size_t i = available_range.first(); i != available_range.end();) { - rb.set_read_offset(BlockOffset(i)); + LogLine line; + rb.Read(&line, sizeof(line)); - LogLine line; - rb.Read(&line, sizeof(line)); + auto needed_count = BlockCount(sizeof(LogLine) + line.buffer_length); + if (read_count + needed_count > available_count) { + // More blocks are needed for a complete line. + desired_count = needed_count; + break; + } else { + // Enough blocks to read this log line, advance by that many. + read_count += needed_count; + i += needed_count; - auto needed_count = BlockCount(sizeof(LogLine) + line.buffer_length); - if (read_count + needed_count > available_count) { - // More blocks are needed for a complete line. - desired_count = needed_count; - break; - } else { - // Enough blocks to read this log line, advance by that many. - read_count += needed_count; - i += needed_count; + if (line.prefix_char) { + char prefix[] = { + line.prefix_char, + '>', + ' ', + '?', // Thread ID gets placed here (8 chars). + '?', + '?', + '?', + '?', + '?', + '?', + '?', + ' ', + 0, + }; + fmt::format_to_n(prefix + 3, sizeof(prefix) - 3, "{:08X}", + line.thread_id); + Write(prefix, sizeof(prefix) - 1); + } - if (line.prefix_char) { - char prefix[] = { - line.prefix_char, - '>', - ' ', - '?', // Thread ID gets placed here (8 chars). - '?', - '?', - '?', - '?', - '?', - '?', - '?', - ' ', - 0, - }; - fmt::format_to_n(prefix + 3, sizeof(prefix) - 3, "{:08X}", - line.thread_id); - Write(prefix, sizeof(prefix) - 1); + if (line.buffer_length) { + // Get access to the line data - which may be split in the ring + // buffer - and write it out in parts. + auto line_range = rb.BeginRead(line.buffer_length); + Write(reinterpret_cast(line_range.first), + line_range.first_length); + if (line_range.second_length) { + Write(reinterpret_cast(line_range.second), + line_range.second_length); } - if (line.buffer_length) { - // Get access to the line data - which may be split in the ring - // buffer - and write it out in parts. - auto line_range = rb.BeginRead(line.buffer_length); - Write(reinterpret_cast(line_range.first), - line_range.first_length); - if (line_range.second_length) { - Write(reinterpret_cast(line_range.second), - line_range.second_length); - } - - // Always ensure there is a newline. - char last_char = - line_range.second - ? line_range.second[line_range.second_length - 1] - : line_range.first[line_range.first_length - 1]; - if (last_char != '\n') { - const char suffix[1] = {'\n'}; - Write(suffix, 1); - } - - rb.EndRead(std::move(line_range)); - } else { - // Always ensure there is a newline. + // Always ensure there is a newline. + char last_char = + line_range.second + ? line_range.second[line_range.second_length - 1] + : line_range.first[line_range.first_length - 1]; + if (last_char != '\n') { const char suffix[1] = {'\n'}; Write(suffix, 1); } - if (line.terminate) { - terminate = true; - } + rb.EndRead(std::move(line_range)); + } else { + // Always ensure there is a newline. + const char suffix[1] = {'\n'}; + Write(suffix, 1); + } + + if (line.terminate) { + terminate = true; } } + } - if (terminate) { - break; - } + if (terminate) { + break; } if (read_count) { From 5c516cc3411a465fe3c319d50b2c8fe2e16f2109 Mon Sep 17 00:00:00 2001 From: gibbed Date: Sat, 26 Jun 2021 12:42:47 -0500 Subject: [PATCH 04/42] Add missing break in logging. --- src/xenia/base/logging.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xenia/base/logging.cc b/src/xenia/base/logging.cc index d88a94879..6464a2b8c 100644 --- a/src/xenia/base/logging.cc +++ b/src/xenia/base/logging.cc @@ -225,6 +225,7 @@ class Logger { if (line.terminate) { terminate = true; + break; } } } From 9ca8180976d59d7e32d6669d4399ccb1987ba087 Mon Sep 17 00:00:00 2001 From: Joel Linn Date: Tue, 15 Dec 2020 19:39:30 +0100 Subject: [PATCH 05/42] Add CI file for drone.io --- .appveyor.yml | 1 + .drone.yml | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 214 insertions(+) create mode 100644 .drone.yml diff --git a/.appveyor.yml b/.appveyor.yml index 4329b47e0..54ad4f01b 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -8,6 +8,7 @@ skip_tags: true skip_commits: files: + - .drone.yml - .github/** - .travis.yml - docs/** diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 000000000..b8985f502 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,213 @@ +--- +kind: pipeline +type: docker +name: lint + +# Run this in a separate pipeline so that it will build even if this fails +steps: +- name: lint + image: xeniaproject/buildenv:2021-06-21 + commands: + - ./xenia-build lint --all + +--- +kind: pipeline +type: docker +name: x86_64-linux +platform: + os: linux + arch: amd64 + +# Some expressions in this file are duplicates. Scripting support is +# available using jsonnet but increases complexity +# https://docs.drone.io/pipeline/scripting/jsonnet/ + +# These volumes will be mounted at the build directory, allowing to +# run different premake toolchains from the same source tree +volumes: +- name: build-premake + temp: {} +- name: build-cmake + temp: {} + +steps: +# +# Setup the source tree +# +- name: clone-submodules + image: xeniaproject/buildenv:2021-06-21 + commands: + - pwd + # May miss recursive submodules (but faster than xb setup) + - git submodule update --init --depth 1 -j $(nproc) + + +# +# Setup the two build systems +# + +# Native premake Makefiles for production +- name: toolchain-premake + image: xeniaproject/buildenv:2021-06-21 + volumes: + - name: build-premake + path: /drone/src/build + commands: + - $CXX --version + - $AR --version + - python3 --version + - ./xenia-build premake + depends_on: + - clone-submodules + +# Development toolchain +- name: toolchain-cmake + image: xeniaproject/buildenv:2021-06-21 + volumes: + - name: build-cmake + path: /drone/src/build + commands: + - | + ./xenia-build premake --devenv=cmake + cd build + for c in Debug Release + do + mkdir cmake-$c + cd cmake-$c + cmake -DCMAKE_BUILD_TYPE=$c .. + cd .. + done + depends_on: + # Premake itself needs to be build first: + - toolchain-premake + + +# +# Building +# + +- name: build-premake-debug-all + image: xeniaproject/buildenv:2021-06-21 + volumes: + - name: build-premake + path: /drone/src/build + commands: + - ./xenia-build build --no_premake -j$(nproc) --config=Debug + depends_on: + - toolchain-premake + +- name: build-premake-release-tests + image: xeniaproject/buildenv:2021-06-21 + volumes: + - name: build-premake + path: /drone/src/build + commands: + - ./xenia-build build --no_premake -j$(nproc) --config=Release --target=xenia-base-tests + depends_on: + - toolchain-premake + +- name: build-premake-release-all + image: xeniaproject/buildenv:2021-06-21 + volumes: + - name: build-premake + path: /drone/src/build + commands: + - ./xenia-build build --no_premake -j$(nproc) --config=Release + depends_on: + - build-premake-release-tests + +- name: build-cmake-debug-all + image: xeniaproject/buildenv:2021-06-21 + volumes: + - name: build-cmake + path: /drone/src/build + commands: + - cd build/cmake-Debug + - cmake --build . -j$(nproc) + depends_on: + - toolchain-cmake + +- name: build-cmake-release-tests + image: xeniaproject/buildenv:2021-06-21 + volumes: + - name: build-cmake + path: /drone/src/build + commands: + - cd build/cmake-Release + - cmake --build . -j$(nproc) --target xenia-base-tests + depends_on: + - toolchain-cmake + +- name: build-cmake-release-all + image: xeniaproject/buildenv:2021-06-21 + volumes: + - name: build-cmake + path: /drone/src/build + commands: + - cd build/cmake-Release + - cmake --build . -j$(nproc) + depends_on: + - build-cmake-release-tests + + +# +# Tests +# + +- name: test-premake + image: xeniaproject/buildenv:2021-06-21 + volumes: + - name: build-premake + path: /drone/src/build + commands: + - ./build/bin/Linux/Release/xenia-base-tests + depends_on: + - build-premake-release-tests + +- name: test-cmake + image: xeniaproject/buildenv:2021-06-21 + volumes: + - name: build-cmake + path: /drone/src/build + commands: + - ./build/bin/Linux/Release/xenia-base-tests + depends_on: + - build-cmake-release-tests + + +# +# Stat +# + +- name: stat + image: xeniaproject/buildenv:2021-06-21 + volumes: + - name: build-premake + path: /build-premake + - name: build-cmake + path: /build-cmake + commands: + - | + header() { + SEP='============================================================' + echo + echo $SEP + echo $@ + echo $SEP + } + + for v in premake cmake + do + for c in Debug Release + do + header $v $c + p=/build-$v/bin/Linux/$c + ls -la $p + sha256sum $p/* + done + done + depends_on: + - build-premake-debug-all + - build-premake-release-all + - build-cmake-debug-all + - build-cmake-release-all From c5e55ad9fc09e7d21d6e248e0d108b49935bf67a Mon Sep 17 00:00:00 2001 From: Joel Linn Date: Wed, 5 May 2021 22:40:48 +0200 Subject: [PATCH 06/42] Update build badge in readme - Replace travis with drone.io --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b47f9551a..24599aed2 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Discussing illegal activities will get you banned. Buildbot | Status -------- | ------ [Windows](https://ci.appveyor.com/project/benvanik/xenia/branch/master) | [![Build status](https://ci.appveyor.com/api/projects/status/ftqiy86kdfawyx3a/branch/master?svg=true)](https://ci.appveyor.com/project/benvanik/xenia/branch/master) -[Linux](https://travis-ci.org/xenia-project/xenia) | [![Build status](https://travis-ci.org/xenia-project/xenia.svg?branch=master)](https://travis-ci.org/xenia-project/xenia) +[Linux](https://cloud.drone.io/xenia-project/xenia) | [![Build status](https://cloud.drone.io/api/badges/xenia-project/xenia/status.svg)](https://cloud.drone.io/xenia-project/xenia) Quite a few real games run. Quite a few don't. See the [Game compatibility list](https://github.com/xenia-project/game-compatibility/issues) From ecfba56090c42389b4b680c468374a4cb608f7ae Mon Sep 17 00:00:00 2001 From: Joel Linn Date: Sun, 20 Jun 2021 18:50:43 +0200 Subject: [PATCH 07/42] Remove .travis.yml Free building on travis-ci.org ceased --- .travis.yml | 73 ----------------------------------------------------- 1 file changed, 73 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 188278034..000000000 --- a/.travis.yml +++ /dev/null @@ -1,73 +0,0 @@ -# Make Travis use docker (for faster builds, in theory). - -language: cpp -os: - - linux - -dist: bionic -addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-9 - packages: - - clang-9 - - clang-format-9 - - llvm-9-dev - - g++-8 - - python3 - - libc++-dev - - libc++abi-dev - - libgtk-3-dev - - libpthread-stubs0-dev - - libsdl2-dev - #- libvulkan1 - #- libvulkan-dev - - libx11-dev - - liblz4-dev - -jobs: - include: - - env: C_COMPILER=clang-9 CXX_COMPILER=clang++-9 AR_COMPILER=llvm-ar-9 LINT=true - - env: C_COMPILER=clang-9 CXX_COMPILER=clang++-9 AR_COMPILER=llvm-ar-9 BUILD=true CONFIG=Debug - - env: C_COMPILER=clang-9 CXX_COMPILER=clang++-9 AR_COMPILER=llvm-ar-9 BUILD=true CONFIG=Release - -git: - # We handle submodules ourselves in xenia-build setup. - submodules: false - -before_script: - - export LIBVULKAN_VERSION=1.1.70 - - export CXX=$CXX_COMPILER - - export CC=$C_COMPILER - - export AR=$AR_COMPILER - # Dump useful info. - - $CXX --version - - $AR_COMPILER --version - - python3 --version - - clang-format-9 --version - - clang-format-9 -style=file -dump-config - # Add Vulkan dependencies. - - travis_retry wget http://mirrors.kernel.org/ubuntu/pool/universe/v/vulkan/libvulkan1_$LIBVULKAN_VERSION+dfsg1-1_amd64.deb - - travis_retry wget http://mirrors.kernel.org/ubuntu/pool/universe/v/vulkan/libvulkan-dev_$LIBVULKAN_VERSION+dfsg1-1_amd64.deb - - if [[ $BUILD == true ]]; then sudo dpkg -i libvulkan1_$LIBVULKAN_VERSION+dfsg1-1_amd64.deb libvulkan-dev_$LIBVULKAN_VERSION+dfsg1-1_amd64.deb; fi - # Prepare environment (pull dependencies, build tools). - - travis_retry ./xenia-build setup - -script: - # Run linter. - - if [[ $LINT == true ]]; then ./xenia-build lint --all; fi - - # Build and run base tests. - - if [[ $BUILD == true ]]; then ./xenia-build build --config=$CONFIG --target=xenia-base-tests; fi - - if [[ $BUILD == true ]]; then ./build/bin/Linux/$CONFIG/xenia-base-tests; fi - # Build and run ppc tests. - - 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 - - # Build all of xenia. - - 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). - #- ./xenia-build test --config=debug --no-build -- --enable_haswell_instructions=true From d87bf995e148707c88389dda177cf6fbcfe57b34 Mon Sep 17 00:00:00 2001 From: Joel Linn Date: Sun, 20 Jun 2021 20:42:57 +0200 Subject: [PATCH 08/42] Satisfy linter Apply changes suggested by clang-format-12 --- src/xenia/cpu/hir/value.cc | 7 ++++--- src/xenia/cpu/ppc/ppc_emit_control.cc | 4 ++-- src/xenia/cpu/xex_module.cc | 9 +++++---- src/xenia/kernel/xam/xam_user.cc | 5 +++-- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/xenia/cpu/hir/value.cc b/src/xenia/cpu/hir/value.cc index 666648b03..3dab4cca2 100644 --- a/src/xenia/cpu/hir/value.cc +++ b/src/xenia/cpu/hir/value.cc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -426,8 +426,9 @@ void Value::MulHi(Value* other, bool is_unsigned) { (uint32_t)other->constant.i32) >> 32); } else { - constant.i32 = (int32_t)( - ((int64_t)constant.i32 * (int64_t)other->constant.i32) >> 32); + constant.i32 = + (int32_t)(((int64_t)constant.i32 * (int64_t)other->constant.i32) >> + 32); } break; case INT64_TYPE: diff --git a/src/xenia/cpu/ppc/ppc_emit_control.cc b/src/xenia/cpu/ppc/ppc_emit_control.cc index 4452c55ea..c439549cb 100644 --- a/src/xenia/cpu/ppc/ppc_emit_control.cc +++ b/src/xenia/cpu/ppc/ppc_emit_control.cc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -806,6 +806,6 @@ void RegisterEmitCategoryControl() { XEREGISTERINSTR(mtmsrd); } +} // namespace ppc } // namespace cpu } // namespace xe -} // namespace xe diff --git a/src/xenia/cpu/xex_module.cc b/src/xenia/cpu/xex_module.cc index 83fbc2139..672d44666 100644 --- a/src/xenia/cpu/xex_module.cc +++ b/src/xenia/cpu/xex_module.cc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2020 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -832,9 +832,10 @@ int XexModule::ReadPEHeaders() { // offsetof seems to be unable to find OptionalHeader. #define offsetof1(type, member) ((std::size_t) & (((type*)0)->member)) #define IMAGE_FIRST_SECTION1(ntheader) \ - ((PIMAGE_SECTION_HEADER)( \ - (uint8_t*)ntheader + offsetof1(IMAGE_NT_HEADERS, OptionalHeader) + \ - ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader)) + ((PIMAGE_SECTION_HEADER)((uint8_t*)ntheader + \ + offsetof1(IMAGE_NT_HEADERS, OptionalHeader) + \ + ((PIMAGE_NT_HEADERS)(ntheader)) \ + ->FileHeader.SizeOfOptionalHeader)) // Quick scan to determine bounds of sections. size_t upper_address = 0; diff --git a/src/xenia/kernel/xam/xam_user.cc b/src/xenia/kernel/xam/xam_user.cc index 536643bfb..3e56e4632 100644 --- a/src/xenia/kernel/xam/xam_user.cc +++ b/src/xenia/kernel/xam/xam_user.cc @@ -277,8 +277,9 @@ uint32_t xeXamUserReadProfileSettingsEx(uint32_t title_id, uint32_t user_index, auto setting = user_profile->GetSetting(setting_id); std::memset(out_setting, 0, sizeof(X_USER_READ_PROFILE_SETTING)); - out_setting->from = - !setting || !setting->is_set ? 0 : setting->is_title_specific() ? 2 : 1; + out_setting->from = !setting || !setting->is_set ? 0 + : setting->is_title_specific() ? 2 + : 1; out_setting->user_index = static_cast(user_index); out_setting->setting_id = setting_id; From 771f8fb292ca3b6224e2ccbc96fde6fbf52d9dbb Mon Sep 17 00:00:00 2001 From: gibbed Date: Sun, 27 Jun 2021 19:57:59 -0500 Subject: [PATCH 09/42] Fix HostPathFile access checks. Fix HostPathFile access checks to additionally check generic access. --- src/xenia/vfs/devices/host_path_file.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/xenia/vfs/devices/host_path_file.cc b/src/xenia/vfs/devices/host_path_file.cc index 366273ae6..fd7e9f6fa 100644 --- a/src/xenia/vfs/devices/host_path_file.cc +++ b/src/xenia/vfs/devices/host_path_file.cc @@ -25,7 +25,8 @@ void HostPathFile::Destroy() { delete this; } X_STATUS HostPathFile::ReadSync(void* buffer, size_t buffer_length, size_t byte_offset, size_t* out_bytes_read) { - if (!(file_access_ & FileAccess::kFileReadData)) { + if (!(file_access_ & + (FileAccess::kGenericRead | FileAccess::kFileReadData))) { return X_STATUS_ACCESS_DENIED; } @@ -39,8 +40,8 @@ X_STATUS HostPathFile::ReadSync(void* buffer, size_t buffer_length, X_STATUS HostPathFile::WriteSync(const void* buffer, size_t buffer_length, size_t byte_offset, size_t* out_bytes_written) { - if (!(file_access_ & - (FileAccess::kFileWriteData | FileAccess::kFileAppendData))) { + if (!(file_access_ & (FileAccess::kGenericWrite | FileAccess::kFileWriteData | + FileAccess::kFileAppendData))) { return X_STATUS_ACCESS_DENIED; } @@ -53,7 +54,8 @@ X_STATUS HostPathFile::WriteSync(const void* buffer, size_t buffer_length, } X_STATUS HostPathFile::SetLength(size_t length) { - if (!(file_access_ & FileAccess::kFileWriteData)) { + if (!(file_access_ & + (FileAccess::kGenericWrite | FileAccess::kFileWriteData))) { return X_STATUS_ACCESS_DENIED; } From 14eeb9432644abc00e3b771be0685f2a72387d20 Mon Sep 17 00:00:00 2001 From: Gliniak Date: Mon, 25 Jan 2021 08:49:48 +0100 Subject: [PATCH 10/42] [Kernel/IO] IoCompletion: Removed !wait_ticks check - Marked IoCompletion as frequently used functions - Added correct behaviour to wait_ticks 0 --- src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc | 10 +++++++--- src/xenia/kernel/xiocompletion.cc | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc index 7a2d797e8..62d07e12c 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc @@ -458,7 +458,8 @@ dword_result_t NtSetIoCompletion(dword_t handle, dword_t key_context, port->QueueNotification(notification); return X_STATUS_SUCCESS; } -DECLARE_XBOXKRNL_EXPORT1(NtSetIoCompletion, kFileSystem, kImplemented); +DECLARE_XBOXKRNL_EXPORT2(NtSetIoCompletion, kFileSystem, kImplemented, + kHighFrequency); // Dequeues a packet from the completion port. dword_result_t NtRemoveIoCompletion( @@ -473,7 +474,9 @@ dword_result_t NtRemoveIoCompletion( status = X_STATUS_INVALID_HANDLE; } - uint64_t timeout_ticks = timeout ? static_cast(*timeout) : 0u; + uint64_t timeout_ticks = + timeout ? static_cast(*timeout) + : static_cast(std::numeric_limits::min()); XIOCompletion::IONotification notification; if (port->WaitForNotification(timeout_ticks, ¬ification)) { if (key_context) { @@ -493,7 +496,8 @@ dword_result_t NtRemoveIoCompletion( return status; } -DECLARE_XBOXKRNL_EXPORT1(NtRemoveIoCompletion, kFileSystem, kImplemented); +DECLARE_XBOXKRNL_EXPORT2(NtRemoveIoCompletion, kFileSystem, kImplemented, + kHighFrequency); dword_result_t NtQueryFullAttributesFile( pointer_t obj_attribs, diff --git a/src/xenia/kernel/xiocompletion.cc b/src/xenia/kernel/xiocompletion.cc index 94d49a5f5..638a0a3ef 100644 --- a/src/xenia/kernel/xiocompletion.cc +++ b/src/xenia/kernel/xiocompletion.cc @@ -30,7 +30,7 @@ bool XIOCompletion::WaitForNotification(uint64_t wait_ticks, IONotification* notify) { auto ms = std::chrono::milliseconds(TimeoutTicksToMs(wait_ticks)); auto res = threading::Wait(notification_semaphore_.get(), false, ms); - if (res == threading::WaitResult::kSuccess || !wait_ticks) { + if (res == threading::WaitResult::kSuccess) { std::unique_lock lock(notification_lock_); assert_false(notifications_.empty()); From 432470266c913e1e868984839a786e4f66fcc355 Mon Sep 17 00:00:00 2001 From: Atvaark Date: Wed, 2 Oct 2019 23:21:50 +0200 Subject: [PATCH 11/42] [Core] Fix reading UTF-8 BOM config files --- src/xenia/config.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/xenia/config.cc b/src/xenia/config.cc index 59027e900..be19bccda 100644 --- a/src/xenia/config.cc +++ b/src/xenia/config.cc @@ -25,6 +25,14 @@ std::shared_ptr ParseFile( throw cpptoml::parse_exception(xe::path_to_utf8(filename) + " could not be opened for parsing"); } + // since cpptoml can't parse files with a UTF-8 BOM we need to skip them + char bom[3]; + file.read(bom, sizeof(bom)); + if (file.fail() || bom[0] != '\xEF' || bom[1] != '\xBB' || bom[2] != '\xBF') { + file.clear(); + file.seekg(0); + } + cpptoml::parser p(file); return p.parse(); } From afde40ab6c95e5c53e6c2072469165b86dd3fdb2 Mon Sep 17 00:00:00 2001 From: Cancerous Date: Mon, 19 Aug 2019 12:35:01 -0400 Subject: [PATCH 12/42] XAM fixes. Updated PR from Permanulled PR #1150. - [XAM] Stub XGI messages. - [XAM] Stub XLiveBase GetServiceInfo message. - [XAM] Stub error out of NetDll_WSARecvFrom. - [XAM] Stub XamSessionRefObjByHandle. Improves Aegis Wings, Jetpac, Metal Slug 3, and State of Decay. Co-authored-by: PermaNulled --- src/xenia/kernel/xam/apps/xgi_app.cc | 19 ++++++++++++++++--- src/xenia/kernel/xam/apps/xlivebase_app.cc | 18 ++++++++++++++---- src/xenia/kernel/xam/xam_net.cc | 6 ++++-- src/xenia/kernel/xam/xam_user.cc | 6 ++++-- 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/xenia/kernel/xam/apps/xgi_app.cc b/src/xenia/kernel/xam/apps/xgi_app.cc index c77665209..771341cdb 100644 --- a/src/xenia/kernel/xam/apps/xgi_app.cc +++ b/src/xenia/kernel/xam/apps/xgi_app.cc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2015 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -80,8 +80,10 @@ X_HRESULT XgiApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, return X_E_SUCCESS; } case 0x000B0011: { - // TODO(DrChat): Figure out what this is again - } break; + // TODO(PermaNull): reverse buffer contents. + XELOGD("XGISessionDelete"); + return X_STATUS_SUCCESS; + } case 0x000B0012: { assert_true(buffer_length == 0x14); uint32_t session_ptr = xe::load_and_swap(buffer + 0x0); @@ -95,6 +97,17 @@ X_HRESULT XgiApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, user_count, unk_0, user_index_array, private_slots_array); return X_E_SUCCESS; } + case 0x000B0014: { + // Gets Jetpac XBLA in game + // get high score table? + XELOGD("XGI_unknown"); + return X_STATUS_SUCCESS; + } + case 0x000B0015: { + // send high scores? + XELOGD("XGI_unknown"); + return X_STATUS_SUCCESS; + } case 0x000B0041: { assert_true(!buffer_length || buffer_length == 32); // 00000000 2789fecc 00000000 00000000 200491e0 00000000 200491f0 20049340 diff --git a/src/xenia/kernel/xam/apps/xlivebase_app.cc b/src/xenia/kernel/xam/apps/xlivebase_app.cc index d35692ca8..b8c72caf1 100644 --- a/src/xenia/kernel/xam/apps/xlivebase_app.cc +++ b/src/xenia/kernel/xam/apps/xlivebase_app.cc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2015 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -41,18 +41,28 @@ X_HRESULT XLiveBaseApp::DispatchMessageSync(uint32_t message, xe::store_and_swap(buffer + 0, 1); // XONLINE_NAT_OPEN return X_E_SUCCESS; } + case 0x00058007: { + // Occurs if title calls XOnlineGetServiceInfo, expects dwServiceId + // and pServiceInfo. pServiceInfo should contain pointer to + // XONLINE_SERVICE_INFO structure. + XELOGD("CXLiveLogon::GetServiceInfo({:08X}, {:08X})", buffer_ptr, + buffer_length); + return 1229; // ERROR_CONNECTION_INVALID + } case 0x00058020: { // 0x00058004 is called right before this. // We should create a XamEnumerate-able empty list here, but I'm not // sure of the format. // buffer_length seems to be the same ptr sent to 0x00058004. - XELOGD("XLiveBaseFriendsCreateEnumerator({:08X}, {:08X}) unimplemented", + XELOGD("CXLiveFriends::Enumerate({:08X}, {:08X}) unimplemented", buffer_ptr, buffer_length); return X_E_FAIL; } case 0x00058023: { - XELOGD("XliveBaseUnk58023({:08X}, {:08X}) unimplemented", buffer_ptr, - buffer_length); + XELOGD( + "CXLiveMessaging::XMessageGameInviteGetAcceptedInfo({:08X}, {:08X}) " + "unimplemented", + buffer_ptr, buffer_length); return X_E_FAIL; } case 0x00058046: { diff --git a/src/xenia/kernel/xam/xam_net.cc b/src/xenia/kernel/xam/xam_net.cc index e1507cb00..fc3c83a24 100644 --- a/src/xenia/kernel/xam/xam_net.cc +++ b/src/xenia/kernel/xam/xam_net.cc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -306,7 +306,9 @@ dword_result_t NetDll_WSARecvFrom(dword_t caller, dword_t socket, //} } - return 0; + // we're not going to be receiving packets any time soon + // return error so we don't wait on that - Cancerous + return -1; } DECLARE_XAM_EXPORT1(NetDll_WSARecvFrom, kNetworking, kStub); diff --git a/src/xenia/kernel/xam/xam_user.cc b/src/xenia/kernel/xam/xam_user.cc index 3e56e4632..096a59b11 100644 --- a/src/xenia/kernel/xam/xam_user.cc +++ b/src/xenia/kernel/xam/xam_user.cc @@ -780,8 +780,10 @@ DECLARE_XAM_EXPORT1(XamSessionCreateHandle, kUserProfiles, kStub); dword_result_t XamSessionRefObjByHandle(dword_t handle, lpdword_t obj_ptr) { assert_true(handle == 0xCAFEDEAD); - *obj_ptr = 0; - return X_ERROR_FUNCTION_FAILED; + // TODO(PermaNull): Implement this properly, + // For the time being returning 0xDEADF00D will prevent crashing. + *obj_ptr = 0xDEADF00D; + return X_ERROR_SUCCESS; } DECLARE_XAM_EXPORT1(XamSessionRefObjByHandle, kUserProfiles, kStub); From 44bfba4b0e2059cbb950e61c73921c02ddaf7987 Mon Sep 17 00:00:00 2001 From: Joel Linn Date: Mon, 28 Jun 2021 17:26:43 +0200 Subject: [PATCH 13/42] [CI] Print clang-format version. --- .drone.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.drone.yml b/.drone.yml index b8985f502..a8c2c21d3 100644 --- a/.drone.yml +++ b/.drone.yml @@ -8,6 +8,7 @@ steps: - name: lint image: xeniaproject/buildenv:2021-06-21 commands: + - clang-format --version - ./xenia-build lint --all --- From be1a666066aa8762e45bd53b2322071e7a24b4df Mon Sep 17 00:00:00 2001 From: ztjohnst Date: Fri, 31 Jul 2020 22:27:18 -0400 Subject: [PATCH 14/42] [Base] Change behavior of has_console_attached(). [Base] Change has_console_attached() so that it no longer proves true if Xenia is launched from a Windows Terminal. --- src/xenia/base/main_win.cc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/xenia/base/main_win.cc b/src/xenia/base/main_win.cc index 6162d3846..6cf80b7ae 100644 --- a/src/xenia/base/main_win.cc +++ b/src/xenia/base/main_win.cc @@ -38,11 +38,29 @@ bool has_console_attached_ = true; bool has_console_attached() { return has_console_attached_; } +bool has_shell_environment_variable() { + size_t size = 0; + // Check if SHELL exists + // If it doesn't, then we are in a Windows Terminal + auto error = getenv_s(&size, nullptr, 0, "SHELL"); + if (error) { + return false; + } + return !!size; +} + void AttachConsole() { if (!cvars::enable_console) { return; } + bool has_console = ::AttachConsole(ATTACH_PARENT_PROCESS) == TRUE; + if (!has_console || !has_shell_environment_variable()) { + // We weren't launched from a console, so just return. + has_console_attached_ = false; + return; + } + AllocConsole(); has_console_attached_ = true; From a77ed6f4a7eb3a4f8abe5b33f6a31384f30b3092 Mon Sep 17 00:00:00 2001 From: ztjohnst Date: Fri, 31 Jul 2020 22:42:05 -0400 Subject: [PATCH 15/42] [Base] Add ShowInfoMB / ShowErrorMB functions. [Base] Add ShowInfoMessageBox / ShowErrorMessageBox functions. --- src/xenia/base/logging.cc | 14 ++++++++++++++ src/xenia/base/logging.h | 5 +++++ 2 files changed, 19 insertions(+) diff --git a/src/xenia/base/logging.cc b/src/xenia/base/logging.cc index 6464a2b8c..d928ec56a 100644 --- a/src/xenia/base/logging.cc +++ b/src/xenia/base/logging.cc @@ -363,4 +363,18 @@ void FatalError(const std::string_view str) { std::exit(1); } +void ShowInfoMessageBox(std::string m) { +#if XE_PLATFORM_WIN32 + MessageBoxW(NULL, (LPCWSTR)xe::to_utf16(m).c_str(), L"Xenia Help", + MB_OK | MB_ICONINFORMATION | MB_APPLMODAL | MB_SETFOREGROUND); +#endif // WIN32 +} + +void ShowErrorMessageBox(std::string m) { +#if XE_PLATFORM_WIN32 + MessageBoxW(NULL, (LPCWSTR)xe::path_to_utf16(m).c_str(), L"Xenia Error", + MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND); +#endif // WIN32 +} + } // namespace xe diff --git a/src/xenia/base/logging.h b/src/xenia/base/logging.h index d2df15cce..e3144a056 100644 --- a/src/xenia/base/logging.h +++ b/src/xenia/base/logging.h @@ -95,6 +95,11 @@ void AppendLogLine(LogLevel log_level, const char prefix_char, // Logs a fatal error and aborts the program. void FatalError(const std::string_view str); +// Shows error box +void ShowErrorMessageBox(std::string m); + +// Show info box +void ShowInfoMessageBox(std::string m); } // namespace xe #if XE_OPTION_ENABLE_LOGGING From bf5f700f9ebb4d2ed1686b34f01e610229c24356 Mon Sep 17 00:00:00 2001 From: ztjohnst Date: Fri, 31 Jul 2020 22:44:56 -0400 Subject: [PATCH 16/42] [Base] Fix invalid cvar args causing silent exit. [Base] Fix invalid cvar arguments causing Xenia to silently exit. --- src/xenia/base/cvar.cc | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/xenia/base/cvar.cc b/src/xenia/base/cvar.cc index bd6b0c254..2b9856a23 100644 --- a/src/xenia/base/cvar.cc +++ b/src/xenia/base/cvar.cc @@ -14,6 +14,9 @@ #define UTF_CPP_CPLUSPLUS 201703L #include "third_party/utfcpp/source/utf8.h" +#include "xenia/base/logging.h" +#include "xenia/base/main.h" + namespace utfcpp = utf8; using u8_citer = utfcpp::iterator; @@ -61,7 +64,12 @@ void ParseLaunchArguments(int& argc, char**& argv, auto result = options.parse(argc, argv); if (result.count("help")) { - PrintHelpAndExit(); + if (xe::has_console_attached()) { + PrintHelpAndExit(); + } else { + xe::ShowInfoMessageBox(options.help({""})); + exit(0); + } } for (auto& it : *CmdVars) { @@ -78,8 +86,15 @@ void ParseLaunchArguments(int& argc, char**& argv, } } } catch (const cxxopts::OptionException& e) { - std::cout << e.what() << std::endl; - PrintHelpAndExit(); + if (xe::has_console_attached()) { + std::cout << e.what() << std::endl; + PrintHelpAndExit(); + } else { + std::string m = + "Invalid launch options were given.\n" + options.help({""}); + xe::ShowErrorMessageBox(m); + exit(0); + } } } From 80cafd9358c0a1eabcfaa80c43ac896dd012e335 Mon Sep 17 00:00:00 2001 From: gibbed Date: Mon, 28 Jun 2021 11:08:57 -0500 Subject: [PATCH 17/42] [Base] Clean up simple message box utility. --- src/xenia/base/cvar.cc | 6 ++++-- src/xenia/base/logging.cc | 21 +++------------------ src/xenia/base/logging.h | 5 ----- src/xenia/base/system.h | 9 +++++++++ src/xenia/base/system_linux.cc | 4 ++++ src/xenia/base/system_win.cc | 24 ++++++++++++++++++++++++ 6 files changed, 44 insertions(+), 25 deletions(-) diff --git a/src/xenia/base/cvar.cc b/src/xenia/base/cvar.cc index 2b9856a23..2f48c6c46 100644 --- a/src/xenia/base/cvar.cc +++ b/src/xenia/base/cvar.cc @@ -16,6 +16,7 @@ #include "xenia/base/logging.h" #include "xenia/base/main.h" +#include "xenia/base/system.h" namespace utfcpp = utf8; @@ -67,7 +68,8 @@ void ParseLaunchArguments(int& argc, char**& argv, if (xe::has_console_attached()) { PrintHelpAndExit(); } else { - xe::ShowInfoMessageBox(options.help({""})); + xe::ShowSimpleMessageBox(xe::SimpleMessageBoxType::Help, + options.help({""})); exit(0); } } @@ -92,7 +94,7 @@ void ParseLaunchArguments(int& argc, char**& argv, } else { std::string m = "Invalid launch options were given.\n" + options.help({""}); - xe::ShowErrorMessageBox(m); + xe::ShowSimpleMessageBox(xe::SimpleMessageBoxType::Error, m); exit(0); } } diff --git a/src/xenia/base/logging.cc b/src/xenia/base/logging.cc index d928ec56a..02fa787a4 100644 --- a/src/xenia/base/logging.cc +++ b/src/xenia/base/logging.cc @@ -26,6 +26,7 @@ #include "xenia/base/memory.h" #include "xenia/base/ring_buffer.h" #include "xenia/base/string.h" +#include "xenia/base/system.h" #include "xenia/base/threading.h" // For MessageBox: @@ -353,28 +354,12 @@ void logging::AppendLogLine(LogLevel log_level, const char prefix_char, void FatalError(const std::string_view str) { logging::AppendLogLine(LogLevel::Error, 'X', str); -#if XE_PLATFORM_WIN32 if (!xe::has_console_attached()) { - MessageBoxW(NULL, (LPCWSTR)xe::to_utf16(str).c_str(), L"Xenia Error", - MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND); + ShowSimpleMessageBox(SimpleMessageBoxType::Error, str); } -#endif // WIN32 + ShutdownLogging(); std::exit(1); } -void ShowInfoMessageBox(std::string m) { -#if XE_PLATFORM_WIN32 - MessageBoxW(NULL, (LPCWSTR)xe::to_utf16(m).c_str(), L"Xenia Help", - MB_OK | MB_ICONINFORMATION | MB_APPLMODAL | MB_SETFOREGROUND); -#endif // WIN32 -} - -void ShowErrorMessageBox(std::string m) { -#if XE_PLATFORM_WIN32 - MessageBoxW(NULL, (LPCWSTR)xe::path_to_utf16(m).c_str(), L"Xenia Error", - MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND); -#endif // WIN32 -} - } // namespace xe diff --git a/src/xenia/base/logging.h b/src/xenia/base/logging.h index e3144a056..d2df15cce 100644 --- a/src/xenia/base/logging.h +++ b/src/xenia/base/logging.h @@ -95,11 +95,6 @@ void AppendLogLine(LogLevel log_level, const char prefix_char, // Logs a fatal error and aborts the program. void FatalError(const std::string_view str); -// Shows error box -void ShowErrorMessageBox(std::string m); - -// Show info box -void ShowInfoMessageBox(std::string m); } // namespace xe #if XE_OPTION_ENABLE_LOGGING diff --git a/src/xenia/base/system.h b/src/xenia/base/system.h index 9ffbfa88f..75594db63 100644 --- a/src/xenia/base/system.h +++ b/src/xenia/base/system.h @@ -20,6 +20,15 @@ namespace xe { void LaunchWebBrowser(const std::string& url); void LaunchFileExplorer(const std::filesystem::path& path); +enum class SimpleMessageBoxType { + Help, + Warning, + Error, +}; + +// This is expected to block the caller until the message box is closed. +void ShowSimpleMessageBox(SimpleMessageBoxType type, std::string_view message); + } // namespace xe #endif // XENIA_BASE_SYSTEM_H_ diff --git a/src/xenia/base/system_linux.cc b/src/xenia/base/system_linux.cc index 80773618a..368acd172 100644 --- a/src/xenia/base/system_linux.cc +++ b/src/xenia/base/system_linux.cc @@ -25,4 +25,8 @@ void LaunchWebBrowser(const std::string& url) { void LaunchFileExplorer(const std::filesystem::path& path) { assert_always(); } +void ShowSimpleMessageBox(SimpleMessageBoxType type, std::string_view message) { + assert_always(); +} + } // namespace xe diff --git a/src/xenia/base/system_win.cc b/src/xenia/base/system_win.cc index 0b6198445..8094ddb90 100644 --- a/src/xenia/base/system_win.cc +++ b/src/xenia/base/system_win.cc @@ -24,4 +24,28 @@ void LaunchFileExplorer(const std::filesystem::path& url) { SW_SHOWNORMAL); } +void ShowSimpleMessageBox(SimpleMessageBoxType type, + const std::string_view message) { + const wchar_t* title; + std::u16string wide_message = xe::to_utf16(message); + DWORD type_flags = MB_OK | MB_APPLMODAL | MB_SETFOREGROUND; + switch (type) { + default: + case SimpleMessageBoxType::Help: + title = L"Xenia Help"; + type_flags |= MB_ICONINFORMATION; + break; + case SimpleMessageBoxType::Warning: + title = L"Xenia Warning"; + type_flags |= MB_ICONWARNING; + break; + case SimpleMessageBoxType::Error: + title = L"Xenia Error"; + type_flags |= MB_ICONERROR; + break; + } + MessageBoxW(nullptr, reinterpret_cast(wide_message.c_str()), title, + type_flags); +} + } // namespace xe From 92242f3f7d68ed30e8a493795a159e308d69ace5 Mon Sep 17 00:00:00 2001 From: gibbed Date: Mon, 28 Jun 2021 11:27:36 -0500 Subject: [PATCH 18/42] [Base] Attach console on cvar help/failure. [Base] Attempt attaching to console on cvar help/failure. --- src/xenia/base/cvar.cc | 2 ++ src/xenia/base/main.h | 2 ++ src/xenia/base/main_posix.cc | 2 ++ src/xenia/base/main_win.cc | 8 +++----- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/xenia/base/cvar.cc b/src/xenia/base/cvar.cc index 2f48c6c46..cd85c7a68 100644 --- a/src/xenia/base/cvar.cc +++ b/src/xenia/base/cvar.cc @@ -65,6 +65,7 @@ void ParseLaunchArguments(int& argc, char**& argv, auto result = options.parse(argc, argv); if (result.count("help")) { + xe::AttachConsole(); if (xe::has_console_attached()) { PrintHelpAndExit(); } else { @@ -88,6 +89,7 @@ void ParseLaunchArguments(int& argc, char**& argv, } } } catch (const cxxopts::OptionException& e) { + xe::AttachConsole(); if (xe::has_console_attached()) { std::cout << e.what() << std::endl; PrintHelpAndExit(); diff --git a/src/xenia/base/main.h b/src/xenia/base/main.h index 792fee5d6..324abfe71 100644 --- a/src/xenia/base/main.h +++ b/src/xenia/base/main.h @@ -22,6 +22,8 @@ namespace xe { // Returns true if there is a user-visible console attached to receive stdout. bool has_console_attached(); +void AttachConsole(); + // Extern defined by user code. This must be present for the application to // launch. struct EntryInfo { diff --git a/src/xenia/base/main_posix.cc b/src/xenia/base/main_posix.cc index 1e5e9e526..8d14f9219 100644 --- a/src/xenia/base/main_posix.cc +++ b/src/xenia/base/main_posix.cc @@ -18,6 +18,8 @@ namespace xe { bool has_console_attached() { return true; } +void AttachConsole() {} + } // namespace xe extern "C" int main(int argc, char** argv) { diff --git a/src/xenia/base/main_win.cc b/src/xenia/base/main_win.cc index 6cf80b7ae..6cbf8c9ae 100644 --- a/src/xenia/base/main_win.cc +++ b/src/xenia/base/main_win.cc @@ -50,10 +50,6 @@ bool has_shell_environment_variable() { } void AttachConsole() { - if (!cvars::enable_console) { - return; - } - bool has_console = ::AttachConsole(ATTACH_PARENT_PROCESS) == TRUE; if (!has_console || !has_shell_environment_variable()) { // We weren't launched from a console, so just return. @@ -145,7 +141,9 @@ int Main() { // Attach a console so we can write output to stdout. If the user hasn't // redirected output themselves it'll pop up a window. - xe::AttachConsole(); + if (cvars::enable_console) { + xe::AttachConsole(); + } // Setup COM on the main thread. // NOTE: this may fail if COM has already been initialized - that's OK. From 6c0d03fad3d4c59868a0c8a37b89db2911294079 Mon Sep 17 00:00:00 2001 From: gibbed Date: Sat, 19 Jun 2021 16:53:50 -0500 Subject: [PATCH 19/42] [CPU] Reduce complexity of Value::Round. --- src/xenia/cpu/hir/value.cc | 71 +++++++++++--------------------------- 1 file changed, 20 insertions(+), 51 deletions(-) diff --git a/src/xenia/cpu/hir/value.cc b/src/xenia/cpu/hir/value.cc index 3dab4cca2..28ed07ee7 100644 --- a/src/xenia/cpu/hir/value.cc +++ b/src/xenia/cpu/hir/value.cc @@ -245,65 +245,34 @@ void Value::Convert(TypeName target_type, RoundMode round_mode) { } } +template +T __inline RoundValue(RoundMode round_mode, T value) { + switch (round_mode) { + case ROUND_TO_ZERO: + return std::trunc(value); + case ROUND_TO_NEAREST: + return std::round(value); + case ROUND_TO_MINUS_INFINITY: + return std::floor(value); + case ROUND_TO_POSITIVE_INFINITY: + return std::ceil(value); + default: + assert_unhandled_case(round_mode); + return value; + } +} + void Value::Round(RoundMode round_mode) { switch (type) { case FLOAT32_TYPE: - switch (round_mode) { - case ROUND_TO_ZERO: - constant.f32 = std::trunc(constant.f32); - break; - case ROUND_TO_NEAREST: - constant.f32 = std::round(constant.f32); - return; - case ROUND_TO_MINUS_INFINITY: - constant.f32 = std::floor(constant.f32); - break; - case ROUND_TO_POSITIVE_INFINITY: - constant.f32 = std::ceil(constant.f32); - break; - default: - assert_unhandled_case(round_mode); - return; - } + constant.f32 = RoundValue(round_mode, constant.f32); return; case FLOAT64_TYPE: - switch (round_mode) { - case ROUND_TO_ZERO: - constant.f64 = std::trunc(constant.f64); - break; - case ROUND_TO_NEAREST: - constant.f64 = std::round(constant.f64); - return; - case ROUND_TO_MINUS_INFINITY: - constant.f64 = std::floor(constant.f64); - break; - case ROUND_TO_POSITIVE_INFINITY: - constant.f64 = std::ceil(constant.f64); - break; - default: - assert_unhandled_case(round_mode); - return; - } + constant.f64 = RoundValue(round_mode, constant.f64); return; case VEC128_TYPE: for (int i = 0; i < 4; i++) { - switch (round_mode) { - case ROUND_TO_ZERO: - constant.v128.f32[i] = std::trunc(constant.v128.f32[i]); - break; - case ROUND_TO_NEAREST: - constant.v128.f32[i] = std::round(constant.v128.f32[i]); - break; - case ROUND_TO_MINUS_INFINITY: - constant.v128.f32[i] = std::floor(constant.v128.f32[i]); - break; - case ROUND_TO_POSITIVE_INFINITY: - constant.v128.f32[i] = std::ceil(constant.v128.f32[i]); - break; - default: - assert_unhandled_case(round_mode); - return; - } + constant.v128.f32[i] = RoundValue(round_mode, constant.v128.f32[i]); } return; default: From f4cfa65c7aa80184bd65be9443f3098b52978ba3 Mon Sep 17 00:00:00 2001 From: gibbed Date: Mon, 28 Jun 2021 12:04:56 -0500 Subject: [PATCH 20/42] [Base] Fix natvis for new endian_store. --- src/xenia/base/debug_visualizers.natvis | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/xenia/base/debug_visualizers.natvis b/src/xenia/base/debug_visualizers.natvis index e0022ed70..8cc0aba8e 100644 --- a/src/xenia/base/debug_visualizers.natvis +++ b/src/xenia/base/debug_visualizers.natvis @@ -1,8 +1,8 @@ - - + + {(((value & 0xFF00000000000000) >> 56) | ((value & 0x00FF000000000000) >> 40) | @@ -14,7 +14,7 @@ ((value & 0x00000000000000FF) << 56))} - + {(((value & 0xFF00000000000000) >> 56) | ((value & 0x00FF000000000000) >> 40) | @@ -27,7 +27,7 @@ - + {(((value & 0xFF000000) >> 24) | ((value & 0x00FF0000) >> 8) | @@ -35,7 +35,7 @@ ((value & 0x000000FF) << 24))} - + {(((value & 0xFF000000) >> 24) | ((value & 0x00FF0000) >> 8) | @@ -44,25 +44,25 @@ - + {(((value & 0xFF00) >> 8) | ((value & 0x00FF) << 8))} - + {(((value & 0xFF00) >> 8) | ((value & 0x00FF) << 8))} - + {value} - + {value} From 5826b1389956abfeed6a07e6ed4bf8d4250f745f Mon Sep 17 00:00:00 2001 From: gibbed Date: Mon, 28 Jun 2021 12:07:04 -0500 Subject: [PATCH 21/42] [XAM] Flag NetDll_WSARecvFrom as high frequency. --- src/xenia/kernel/xam/xam_net.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xenia/kernel/xam/xam_net.cc b/src/xenia/kernel/xam/xam_net.cc index fc3c83a24..dbdff9dc1 100644 --- a/src/xenia/kernel/xam/xam_net.cc +++ b/src/xenia/kernel/xam/xam_net.cc @@ -310,7 +310,7 @@ dword_result_t NetDll_WSARecvFrom(dword_t caller, dword_t socket, // return error so we don't wait on that - Cancerous return -1; } -DECLARE_XAM_EXPORT1(NetDll_WSARecvFrom, kNetworking, kStub); +DECLARE_XAM_EXPORT2(NetDll_WSARecvFrom, kNetworking, kStub, kHighFrequency); // If the socket is a VDP socket, buffer 0 is the game data length, and buffer 1 // is the unencrypted game data. From 8caf8d1c1dda5c1c0104539d149708393cbcc943 Mon Sep 17 00:00:00 2001 From: gibbed Date: Mon, 28 Jun 2021 12:09:07 -0500 Subject: [PATCH 22/42] [xboxkrnl] Upgrade DbgPrint logs to info. --- src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc index 5c5090299..4ea9c7f1f 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc @@ -830,7 +830,7 @@ SHIM_CALL DbgPrint_shim(PPCContext* ppc_context, KernelState* kernel_state) { return; } - XELOGD("(DbgPrint) {}", data.str()); + XELOGI("(DbgPrint) {}", data.str()); SHIM_SET_RETURN_32(X_STATUS_SUCCESS); } From e84ef132ae5a98ad235b93c2838c5a812be8db1b Mon Sep 17 00:00:00 2001 From: gibbed Date: Mon, 28 Jun 2021 12:10:22 -0500 Subject: [PATCH 23/42] [xboxkrnl] Log strings for string formatters. --- src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc index 4ea9c7f1f..bc6e71397 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc @@ -841,8 +841,8 @@ SHIM_CALL _snprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) { int32_t buffer_count = SHIM_GET_ARG_32(1); uint32_t format_ptr = SHIM_GET_ARG_32(2); - XELOGD("_snprintf({:08X}, {}, {:08X}, ...)", buffer_ptr, buffer_count, - format_ptr); + XELOGD("_snprintf({:08X}, {}, {:08X}({}), ...)", buffer_ptr, buffer_count, + format_ptr, xe::load_and_swap(SHIM_MEM_ADDR(format_ptr))); if (buffer_ptr == 0 || buffer_count <= 0 || format_ptr == 0) { SHIM_SET_RETURN_32(-1); @@ -877,7 +877,8 @@ SHIM_CALL sprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) { uint32_t buffer_ptr = SHIM_GET_ARG_32(0); uint32_t format_ptr = SHIM_GET_ARG_32(1); - XELOGD("sprintf({:08X}, {:08X}, ...)", buffer_ptr, format_ptr); + XELOGD("sprintf({:08X}, {:08X}({}), ...)", buffer_ptr, format_ptr, + xe::load_and_swap(SHIM_MEM_ADDR(format_ptr))); if (buffer_ptr == 0 || format_ptr == 0) { SHIM_SET_RETURN_32(-1); @@ -906,8 +907,10 @@ SHIM_CALL _snwprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) { int32_t buffer_count = SHIM_GET_ARG_32(1); uint32_t format_ptr = SHIM_GET_ARG_32(2); - XELOGD("_snwprintf({:08X}, {}, {:08X}, ...)", buffer_ptr, buffer_count, - format_ptr); + XELOGD("_snwprintf({:08X}, {}, {:08X}({}), ...)", buffer_ptr, buffer_count, + format_ptr, + xe::to_utf8( + xe::load_and_swap(SHIM_MEM_ADDR(format_ptr)))); if (buffer_ptr == 0 || buffer_count <= 0 || format_ptr == 0) { SHIM_SET_RETURN_32(-1); @@ -942,7 +945,9 @@ SHIM_CALL swprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) { uint32_t buffer_ptr = SHIM_GET_ARG_32(0); uint32_t format_ptr = SHIM_GET_ARG_32(1); - XELOGD("swprintf({:08X}, {:08X}, ...)", buffer_ptr, format_ptr); + XELOGD("swprintf({:08X}, {:08X}({}), ...)", buffer_ptr, format_ptr, + xe::to_utf8( + xe::load_and_swap(SHIM_MEM_ADDR(format_ptr)))); if (buffer_ptr == 0 || format_ptr == 0) { SHIM_SET_RETURN_32(-1); @@ -972,8 +977,9 @@ SHIM_CALL _vsnprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) { uint32_t format_ptr = SHIM_GET_ARG_32(2); uint32_t arg_ptr = SHIM_GET_ARG_32(3); - XELOGD("_vsnprintf({:08X}, {}, {:08X}, {:08X})", buffer_ptr, buffer_count, - format_ptr, arg_ptr); + XELOGD("_vsnprintf({:08X}, {}, {:08X}({}), {:08X})", buffer_ptr, buffer_count, + format_ptr, xe::load_and_swap(SHIM_MEM_ADDR(format_ptr)), + arg_ptr); if (buffer_ptr == 0 || buffer_count <= 0 || format_ptr == 0) { SHIM_SET_RETURN_32(-1); @@ -1012,8 +1018,11 @@ SHIM_CALL _vsnwprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) { uint32_t format_ptr = SHIM_GET_ARG_32(2); uint32_t arg_ptr = SHIM_GET_ARG_32(3); - XELOGD("_vsnwprintf({:08X}, {}, {:08X}, {:08X})", buffer_ptr, buffer_count, - format_ptr, arg_ptr); + XELOGD( + "_vsnwprintf({:08X}, {}, {:08X}({}), {:08X})", buffer_ptr, buffer_count, + format_ptr, + xe::to_utf8(xe::load_and_swap(SHIM_MEM_ADDR(format_ptr))), + arg_ptr); if (buffer_ptr == 0 || buffer_count <= 0 || format_ptr == 0) { SHIM_SET_RETURN_32(-1); @@ -1051,7 +1060,8 @@ SHIM_CALL vsprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) { uint32_t format_ptr = SHIM_GET_ARG_32(1); uint32_t arg_ptr = SHIM_GET_ARG_32(2); - XELOGD("vsprintf({:08X}, {:08X}, {:08X})", buffer_ptr, format_ptr, arg_ptr); + XELOGD("vsprintf({:08X}, {:08X}({}), {:08X})", buffer_ptr, format_ptr, + xe::load_and_swap(SHIM_MEM_ADDR(format_ptr)), arg_ptr); if (buffer_ptr == 0 || format_ptr == 0) { SHIM_SET_RETURN_32(-1); @@ -1079,7 +1089,10 @@ SHIM_CALL _vscwprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) { uint32_t format_ptr = SHIM_GET_ARG_32(0); uint32_t arg_ptr = SHIM_GET_ARG_32(1); - XELOGD("_vscwprintf({:08X}, {:08X})", format_ptr, arg_ptr); + XELOGD( + "_vscwprintf({:08X}({}), {:08X})", format_ptr, + xe::to_utf8(xe::load_and_swap(SHIM_MEM_ADDR(format_ptr))), + arg_ptr); if (format_ptr == 0) { SHIM_SET_RETURN_32(-1); @@ -1102,7 +1115,10 @@ SHIM_CALL vswprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) { uint32_t format_ptr = SHIM_GET_ARG_32(1); uint32_t arg_ptr = SHIM_GET_ARG_32(2); - XELOGD("vswprintf({:08X}, {:08X}, {:08X})", buffer_ptr, format_ptr, arg_ptr); + XELOGD( + "vswprintf({:08X}, {:08X}({}), {:08X})", buffer_ptr, format_ptr, + xe::to_utf8(xe::load_and_swap(SHIM_MEM_ADDR(format_ptr))), + arg_ptr); if (buffer_ptr == 0 || format_ptr == 0) { SHIM_SET_RETURN_32(-1); From a12f775c23ed60d502d34c07cedcfbaacb323794 Mon Sep 17 00:00:00 2001 From: gibbed Date: Mon, 28 Jun 2021 12:22:13 -0500 Subject: [PATCH 24/42] [Base] LaunchWebBrowser now takes a string view. --- src/xenia/base/system.h | 2 +- src/xenia/base/system_linux.cc | 5 +++-- src/xenia/base/system_win.cc | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/xenia/base/system.h b/src/xenia/base/system.h index 75594db63..e69a95eb5 100644 --- a/src/xenia/base/system.h +++ b/src/xenia/base/system.h @@ -17,7 +17,7 @@ namespace xe { -void LaunchWebBrowser(const std::string& url); +void LaunchWebBrowser(const std::string_view url); void LaunchFileExplorer(const std::filesystem::path& path); enum class SimpleMessageBoxType { diff --git a/src/xenia/base/system_linux.cc b/src/xenia/base/system_linux.cc index 368acd172..7be020cda 100644 --- a/src/xenia/base/system_linux.cc +++ b/src/xenia/base/system_linux.cc @@ -18,8 +18,9 @@ namespace xe { -void LaunchWebBrowser(const std::string& url) { - auto cmd = "xdg-open " + url; +void LaunchWebBrowser(const std::string_view url) { + auto cmd = std::string("xdg-open "); + cmd.append(url); system(cmd.c_str()); } diff --git a/src/xenia/base/system_win.cc b/src/xenia/base/system_win.cc index 8094ddb90..ae77ae1d4 100644 --- a/src/xenia/base/system_win.cc +++ b/src/xenia/base/system_win.cc @@ -13,9 +13,9 @@ namespace xe { -void LaunchWebBrowser(const std::string& url) { - auto temp = xe::to_utf16(url); - ShellExecuteW(nullptr, L"open", reinterpret_cast(temp.c_str()), +void LaunchWebBrowser(const std::string_view url) { + auto wide_url = xe::to_utf16(url); + ShellExecuteW(nullptr, L"open", reinterpret_cast(wide_url.c_str()), nullptr, nullptr, SW_SHOWNORMAL); } From fa8e2ee7882513aad3fd3b73e058ada430567cd9 Mon Sep 17 00:00:00 2001 From: gibbed Date: Mon, 28 Jun 2021 12:23:16 -0500 Subject: [PATCH 25/42] [VFS] Suppress error msg for ShaderDumpxe:\CB. [VFS] Suppress error message for ShaderDumpxe:\CompareBackends. --- src/xenia/vfs/virtual_file_system.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/xenia/vfs/virtual_file_system.cc b/src/xenia/vfs/virtual_file_system.cc index c0f888318..01f4761e6 100644 --- a/src/xenia/vfs/virtual_file_system.cc +++ b/src/xenia/vfs/virtual_file_system.cc @@ -117,7 +117,11 @@ Entry* VirtualFileSystem::ResolvePath(const std::string_view path) { return xe::utf8::starts_with(normalized_path, d->mount_path()); }); if (it == devices_.cend()) { - XELOGE("ResolvePath({}) failed - device not found", path); + // Supress logging the error for ShaderDumpxe:\CompareBackEnds as this is + // not an actual problem nor something we care about. + if (path != "ShaderDumpxe:\\CompareBackEnds") { + XELOGE("ResolvePath({}) failed - device not found", path); + } return nullptr; } From f2a68e4b852931ca1d47bb0ebf8205c6a0af6cf5 Mon Sep 17 00:00:00 2001 From: gibbed Date: Mon, 28 Jun 2021 12:33:05 -0500 Subject: [PATCH 26/42] [Base] ByteStream assert cleanup. --- src/xenia/base/byte_stream.cc | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/xenia/base/byte_stream.cc b/src/xenia/base/byte_stream.cc index cdd69a1ba..3775cfc91 100644 --- a/src/xenia/base/byte_stream.cc +++ b/src/xenia/base/byte_stream.cc @@ -20,18 +20,19 @@ ByteStream::ByteStream(uint8_t* data, size_t data_length, size_t offset) ByteStream::~ByteStream() = default; -void ByteStream::Advance(size_t num_bytes) { offset_ += num_bytes; } +void ByteStream::Advance(size_t num_bytes) { + assert_true(offset_ + num_bytes <= data_length_); + offset_ += num_bytes; +} void ByteStream::Read(uint8_t* buf, size_t len) { - assert_true(offset_ < data_length_); - + assert_true(offset_ + len <= data_length_); std::memcpy(buf, data_ + offset_, len); Advance(len); } void ByteStream::Write(const uint8_t* buf, size_t len) { - assert_true(offset_ < data_length_); - + assert_true(offset_ + len <= data_length_); std::memcpy(data_ + offset_, buf, len); Advance(len); } @@ -41,7 +42,6 @@ std::string ByteStream::Read() { std::string str; uint32_t len = Read(); str.resize(len); - Read(reinterpret_cast(&str[0]), len); return str; } @@ -49,9 +49,8 @@ std::string ByteStream::Read() { template <> std::u16string ByteStream::Read() { std::u16string str; - uint32_t len = Read(); + size_t len = Read(); str.resize(len); - Read(reinterpret_cast(&str[0]), len * 2); return str; } From c6259241a2f4b9cec35c6a7c22ee87d83c343868 Mon Sep 17 00:00:00 2001 From: gibbed Date: Mon, 28 Jun 2021 12:35:07 -0500 Subject: [PATCH 27/42] [GPU] Complain when command packet is 0xCDCDCDCD. --- src/xenia/gpu/command_processor.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/xenia/gpu/command_processor.cc b/src/xenia/gpu/command_processor.cc index 28e5a9c1f..53af72115 100644 --- a/src/xenia/gpu/command_processor.cc +++ b/src/xenia/gpu/command_processor.cc @@ -517,6 +517,10 @@ bool CommandProcessor::ExecutePacket(RingBuffer* reader) { return true; } + if (packet == 0xCDCDCDCD) { + XELOGW("GPU packet is CDCDCDCD - probably read uninitialized memory!"); + } + switch (packet_type) { case 0x00: return ExecutePacketType0(reader, packet); From 0cf4cab59b205cd5ad6d763ab792e81144947fbf Mon Sep 17 00:00:00 2001 From: gibbed Date: Mon, 28 Jun 2021 12:48:27 -0500 Subject: [PATCH 28/42] [CPU] Add syscall handler. --- src/xenia/cpu/ppc/ppc_emit_control.cc | 4 ++++ src/xenia/cpu/ppc/ppc_frontend.cc | 13 +++++++++++++ src/xenia/cpu/ppc/ppc_frontend.h | 1 + 3 files changed, 18 insertions(+) diff --git a/src/xenia/cpu/ppc/ppc_emit_control.cc b/src/xenia/cpu/ppc/ppc_emit_control.cc index c439549cb..ec09ea458 100644 --- a/src/xenia/cpu/ppc/ppc_emit_control.cc +++ b/src/xenia/cpu/ppc/ppc_emit_control.cc @@ -426,6 +426,10 @@ int InstrEmit_sc(PPCHIRBuilder& f, const InstrData& i) { // Game code should only ever use LEV=0. // LEV=2 is to signify 'call import' from Xenia. // TODO(gibbed): syscalls! + if (i.SC.LEV == 0) { + f.CallExtern(f.builtins()->syscall_handler); + return 0; + } if (i.SC.LEV == 2) { f.CallExtern(f.function()); return 0; diff --git a/src/xenia/cpu/ppc/ppc_frontend.cc b/src/xenia/cpu/ppc/ppc_frontend.cc index 1696cadfa..594414fe4 100644 --- a/src/xenia/cpu/ppc/ppc_frontend.cc +++ b/src/xenia/cpu/ppc/ppc_frontend.cc @@ -10,6 +10,7 @@ #include "xenia/cpu/ppc/ppc_frontend.h" #include "xenia/base/atomic.h" +#include "xenia/base/logging.h" #include "xenia/cpu/ppc/ppc_context.h" #include "xenia/cpu/ppc/ppc_emit.h" #include "xenia/cpu/ppc/ppc_opcode_info.h" @@ -78,6 +79,16 @@ void LeaveGlobalLock(PPCContext* ppc_context, void* arg0, void* arg1) { global_mutex->unlock(); } +void SyscallHandler(PPCContext* ppc_context, void* arg0, void* arg1) { + uint64_t syscall_number = ppc_context->r[0]; + switch (syscall_number) { + default: + assert_unhandled_case(syscall_number); + XELOGE("Unhandled syscall {}!", syscall_number); + break; + } +} + bool PPCFrontend::Initialize() { void* arg0 = reinterpret_cast(&xe::global_critical_region::mutex()); void* arg1 = reinterpret_cast(&builtins_.global_lock_count); @@ -87,6 +98,8 @@ bool PPCFrontend::Initialize() { processor_->DefineBuiltin("EnterGlobalLock", EnterGlobalLock, arg0, arg1); builtins_.leave_global_lock = processor_->DefineBuiltin("LeaveGlobalLock", LeaveGlobalLock, arg0, arg1); + builtins_.syscall_handler = processor_->DefineBuiltin( + "SyscallHandler", SyscallHandler, nullptr, nullptr); return true; } diff --git a/src/xenia/cpu/ppc/ppc_frontend.h b/src/xenia/cpu/ppc/ppc_frontend.h index 7a6acd63b..d2a41c76c 100644 --- a/src/xenia/cpu/ppc/ppc_frontend.h +++ b/src/xenia/cpu/ppc/ppc_frontend.h @@ -33,6 +33,7 @@ struct PPCBuiltins { Function* check_global_lock; Function* enter_global_lock; Function* leave_global_lock; + Function* syscall_handler; }; class PPCFrontend { From ead4818e25fbc0d552f4af64d56bae1a991f6ed3 Mon Sep 17 00:00:00 2001 From: gibbed Date: Mon, 28 Jun 2021 13:44:22 -0500 Subject: [PATCH 29/42] [xboxkrnl] Optional string formatter logging. --- src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc | 80 ++++++++++++------- 1 file changed, 51 insertions(+), 29 deletions(-) diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc index bc6e71397..ff56a8889 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc @@ -19,6 +19,9 @@ #include "xenia/kernel/xthread.h" #include "xenia/xbox.h" +DEFINE_bool(log_string_format_kernel_calls, false, + "Log kernel calls with the kHighFrequency tag.", "Logging"); + namespace xe { namespace kernel { namespace xboxkrnl { @@ -841,8 +844,11 @@ SHIM_CALL _snprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) { int32_t buffer_count = SHIM_GET_ARG_32(1); uint32_t format_ptr = SHIM_GET_ARG_32(2); - XELOGD("_snprintf({:08X}, {}, {:08X}({}), ...)", buffer_ptr, buffer_count, - format_ptr, xe::load_and_swap(SHIM_MEM_ADDR(format_ptr))); + if (cvars::log_high_frequency_kernel_calls) { + XELOGD("_snprintf({:08X}, {}, {:08X}({}), ...)", buffer_ptr, buffer_count, + format_ptr, + xe::load_and_swap(SHIM_MEM_ADDR(format_ptr))); + } if (buffer_ptr == 0 || buffer_count <= 0 || format_ptr == 0) { SHIM_SET_RETURN_32(-1); @@ -877,8 +883,10 @@ SHIM_CALL sprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) { uint32_t buffer_ptr = SHIM_GET_ARG_32(0); uint32_t format_ptr = SHIM_GET_ARG_32(1); - XELOGD("sprintf({:08X}, {:08X}({}), ...)", buffer_ptr, format_ptr, - xe::load_and_swap(SHIM_MEM_ADDR(format_ptr))); + if (cvars::log_high_frequency_kernel_calls) { + XELOGD("sprintf({:08X}, {:08X}({}), ...)", buffer_ptr, format_ptr, + xe::load_and_swap(SHIM_MEM_ADDR(format_ptr))); + } if (buffer_ptr == 0 || format_ptr == 0) { SHIM_SET_RETURN_32(-1); @@ -907,10 +915,12 @@ SHIM_CALL _snwprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) { int32_t buffer_count = SHIM_GET_ARG_32(1); uint32_t format_ptr = SHIM_GET_ARG_32(2); - XELOGD("_snwprintf({:08X}, {}, {:08X}({}), ...)", buffer_ptr, buffer_count, - format_ptr, - xe::to_utf8( - xe::load_and_swap(SHIM_MEM_ADDR(format_ptr)))); + if (cvars::log_high_frequency_kernel_calls) { + XELOGD("_snwprintf({:08X}, {}, {:08X}({}), ...)", buffer_ptr, buffer_count, + format_ptr, + xe::to_utf8( + xe::load_and_swap(SHIM_MEM_ADDR(format_ptr)))); + } if (buffer_ptr == 0 || buffer_count <= 0 || format_ptr == 0) { SHIM_SET_RETURN_32(-1); @@ -945,9 +955,11 @@ SHIM_CALL swprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) { uint32_t buffer_ptr = SHIM_GET_ARG_32(0); uint32_t format_ptr = SHIM_GET_ARG_32(1); - XELOGD("swprintf({:08X}, {:08X}({}), ...)", buffer_ptr, format_ptr, - xe::to_utf8( - xe::load_and_swap(SHIM_MEM_ADDR(format_ptr)))); + if (cvars::log_high_frequency_kernel_calls) { + XELOGD("swprintf({:08X}, {:08X}({}), ...)", buffer_ptr, format_ptr, + xe::to_utf8( + xe::load_and_swap(SHIM_MEM_ADDR(format_ptr)))); + } if (buffer_ptr == 0 || format_ptr == 0) { SHIM_SET_RETURN_32(-1); @@ -977,9 +989,11 @@ SHIM_CALL _vsnprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) { uint32_t format_ptr = SHIM_GET_ARG_32(2); uint32_t arg_ptr = SHIM_GET_ARG_32(3); - XELOGD("_vsnprintf({:08X}, {}, {:08X}({}), {:08X})", buffer_ptr, buffer_count, - format_ptr, xe::load_and_swap(SHIM_MEM_ADDR(format_ptr)), - arg_ptr); + if (cvars::log_high_frequency_kernel_calls) { + XELOGD("_vsnprintf({:08X}, {}, {:08X}({}), {:08X})", buffer_ptr, + buffer_count, format_ptr, + xe::load_and_swap(SHIM_MEM_ADDR(format_ptr)), arg_ptr); + } if (buffer_ptr == 0 || buffer_count <= 0 || format_ptr == 0) { SHIM_SET_RETURN_32(-1); @@ -1018,11 +1032,13 @@ SHIM_CALL _vsnwprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) { uint32_t format_ptr = SHIM_GET_ARG_32(2); uint32_t arg_ptr = SHIM_GET_ARG_32(3); - XELOGD( - "_vsnwprintf({:08X}, {}, {:08X}({}), {:08X})", buffer_ptr, buffer_count, - format_ptr, - xe::to_utf8(xe::load_and_swap(SHIM_MEM_ADDR(format_ptr))), - arg_ptr); + if (cvars::log_high_frequency_kernel_calls) { + XELOGD("_vsnwprintf({:08X}, {}, {:08X}({}), {:08X})", buffer_ptr, + buffer_count, format_ptr, + xe::to_utf8( + xe::load_and_swap(SHIM_MEM_ADDR(format_ptr))), + arg_ptr); + } if (buffer_ptr == 0 || buffer_count <= 0 || format_ptr == 0) { SHIM_SET_RETURN_32(-1); @@ -1060,8 +1076,10 @@ SHIM_CALL vsprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) { uint32_t format_ptr = SHIM_GET_ARG_32(1); uint32_t arg_ptr = SHIM_GET_ARG_32(2); - XELOGD("vsprintf({:08X}, {:08X}({}), {:08X})", buffer_ptr, format_ptr, - xe::load_and_swap(SHIM_MEM_ADDR(format_ptr)), arg_ptr); + if (cvars::log_high_frequency_kernel_calls) { + XELOGD("vsprintf({:08X}, {:08X}({}), {:08X})", buffer_ptr, format_ptr, + xe::load_and_swap(SHIM_MEM_ADDR(format_ptr)), arg_ptr); + } if (buffer_ptr == 0 || format_ptr == 0) { SHIM_SET_RETURN_32(-1); @@ -1089,10 +1107,12 @@ SHIM_CALL _vscwprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) { uint32_t format_ptr = SHIM_GET_ARG_32(0); uint32_t arg_ptr = SHIM_GET_ARG_32(1); - XELOGD( - "_vscwprintf({:08X}({}), {:08X})", format_ptr, - xe::to_utf8(xe::load_and_swap(SHIM_MEM_ADDR(format_ptr))), - arg_ptr); + if (cvars::log_high_frequency_kernel_calls) { + XELOGD("_vscwprintf({:08X}({}), {:08X})", format_ptr, + xe::to_utf8( + xe::load_and_swap(SHIM_MEM_ADDR(format_ptr))), + arg_ptr); + } if (format_ptr == 0) { SHIM_SET_RETURN_32(-1); @@ -1115,10 +1135,12 @@ SHIM_CALL vswprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) { uint32_t format_ptr = SHIM_GET_ARG_32(1); uint32_t arg_ptr = SHIM_GET_ARG_32(2); - XELOGD( - "vswprintf({:08X}, {:08X}({}), {:08X})", buffer_ptr, format_ptr, - xe::to_utf8(xe::load_and_swap(SHIM_MEM_ADDR(format_ptr))), - arg_ptr); + if (cvars::log_high_frequency_kernel_calls) { + XELOGD("vswprintf({:08X}, {:08X}({}), {:08X})", buffer_ptr, format_ptr, + xe::to_utf8( + xe::load_and_swap(SHIM_MEM_ADDR(format_ptr))), + arg_ptr); + } if (buffer_ptr == 0 || format_ptr == 0) { SHIM_SET_RETURN_32(-1); From 8daef932070cef9e8b606a3bdd125c59b98fbc51 Mon Sep 17 00:00:00 2001 From: gibbed Date: Mon, 28 Jun 2021 19:23:38 -0500 Subject: [PATCH 30/42] [APU] XMA register table cleanup, documentation. - [APU] Clean up XMA register table. - [APU] Document observed register ranges in the XMA register table. --- src/xenia/apu/xma_decoder.cc | 37 +++++----- src/xenia/apu/xma_decoder.h | 4 +- src/xenia/apu/xma_register_file.cc | 5 +- src/xenia/apu/xma_register_file.h | 21 ++---- src/xenia/apu/xma_register_table.inc | 100 +++++++++++++++++---------- 5 files changed, 94 insertions(+), 73 deletions(-) diff --git a/src/xenia/apu/xma_decoder.cc b/src/xenia/apu/xma_decoder.cc index b15bd7fe2..cd04ebd91 100644 --- a/src/xenia/apu/xma_decoder.cc +++ b/src/xenia/apu/xma_decoder.cc @@ -123,7 +123,7 @@ X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) { sizeof(XMA_CONTEXT_DATA) * kContextCount, 256, kSystemHeapPhysical); context_data_last_ptr_ = context_data_first_ptr_ + (sizeof(XMA_CONTEXT_DATA) * kContextCount - 1); - register_file_[XE_XMA_REG_CONTEXT_ARRAY_ADDRESS].u32 = + register_file_[XmaRegister::ContextArrayAddress] = memory()->GetPhysicalAddress(context_data_first_ptr_); // Setup XMA contexts. @@ -134,7 +134,7 @@ X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) { assert_always(); } } - register_file_[XE_XMA_REG_NEXT_CONTEXT_INDEX].u32 = 1; + register_file_[XmaRegister::NextContextIndex] = 1; context_bitmap_.Resize(kContextCount); worker_running_ = true; @@ -254,27 +254,29 @@ bool XmaDecoder::BlockOnContext(uint32_t guest_ptr, bool poll) { } uint32_t XmaDecoder::ReadRegister(uint32_t addr) { - uint32_t r = (addr & 0xFFFF) / 4; + auto r = (addr & 0xFFFF) / 4; assert_true(r < XmaRegisterFile::kRegisterCount); switch (r) { - case XE_XMA_REG_CURRENT_CONTEXT_INDEX: { + case XmaRegister::ContextArrayAddress: + break; + case XmaRegister::CurrentContextIndex: { // 0606h (1818h) is rotating context processing # set to hardware ID of // context being processed. // If bit 200h is set, the locking code will possibly collide on hardware // IDs and error out, so we should never set it (I think?). uint32_t& current_context_index = - register_file_[XE_XMA_REG_CURRENT_CONTEXT_INDEX].u32; + register_file_[XmaRegister::CurrentContextIndex]; uint32_t& next_context_index = - register_file_[XE_XMA_REG_NEXT_CONTEXT_INDEX].u32; + register_file_[XmaRegister::NextContextIndex]; // To prevent games from seeing a stuck XMA context, return a rotating // number. current_context_index = next_context_index; next_context_index = (next_context_index + 1) % kContextCount; break; } - default: { + default: const auto register_info = register_file_.GetRegisterInfo(r); if (register_info) { XELOGW("XMA: Read from unhandled register ({:04X}, {})", r, @@ -283,10 +285,9 @@ uint32_t XmaDecoder::ReadRegister(uint32_t addr) { XELOGW("XMA: Read from unknown register ({:04X})", r); } break; - } } - return xe::byte_swap(register_file_.values[r].u32); + return xe::byte_swap(register_file_[r]); } void XmaDecoder::WriteRegister(uint32_t addr, uint32_t value) { @@ -296,16 +297,16 @@ void XmaDecoder::WriteRegister(uint32_t addr, uint32_t value) { value = xe::byte_swap(value); assert_true(r < XmaRegisterFile::kRegisterCount); - register_file_.values[r].u32 = value; + register_file_[r] = value; - if (r >= XE_XMA_REG_CONTEXT_KICK_0 && r <= XE_XMA_REG_CONTEXT_KICK_9) { + if (r >= XmaRegister::Context0Kick && r <= XmaRegister::Context9Kick) { // Context kick command. // This will kick off the given hardware contexts. // Basically, this kicks the SPU and says "hey, decode that audio!" // XMAEnableContext // The context ID is a bit in the range of the entire context array. - uint32_t base_context_id = (r - XE_XMA_REG_CONTEXT_KICK_0) * 32; + uint32_t base_context_id = (r - XmaRegister::Context0Kick) * 32; for (int i = 0; value && i < 32; ++i, value >>= 1) { if (value & 1) { uint32_t context_id = base_context_id + i; @@ -315,11 +316,11 @@ void XmaDecoder::WriteRegister(uint32_t addr, uint32_t value) { } // Signal the decoder thread to start processing. work_event_->Set(); - } else if (r >= XE_XMA_REG_CONTEXT_LOCK_0 && r <= XE_XMA_REG_CONTEXT_LOCK_9) { + } else if (r >= XmaRegister::Context0Lock && r <= XmaRegister::Context9Lock) { // Context lock command. // This requests a lock by flagging the context. // XMADisableContext - uint32_t base_context_id = (r - XE_XMA_REG_CONTEXT_LOCK_0) * 32; + uint32_t base_context_id = (r - XmaRegister::Context0Lock) * 32; for (int i = 0; value && i < 32; ++i, value >>= 1) { if (value & 1) { uint32_t context_id = base_context_id + i; @@ -328,12 +329,12 @@ void XmaDecoder::WriteRegister(uint32_t addr, uint32_t value) { } } // Signal the decoder thread to start processing. - work_event_->Set(); - } else if (r >= XE_XMA_REG_CONTEXT_CLEAR_0 && - r <= XE_XMA_REG_CONTEXT_CLEAR_9) { + // work_event_->Set(); + } else if (r >= XmaRegister::Context0Clear && + r <= XmaRegister::Context9Clear) { // Context clear command. // This will reset the given hardware contexts. - uint32_t base_context_id = (r - XE_XMA_REG_CONTEXT_CLEAR_0) * 32; + uint32_t base_context_id = (r - XmaRegister::Context0Clear) * 32; for (int i = 0; value && i < 32; ++i, value >>= 1) { if (value & 1) { uint32_t context_id = base_context_id + i; diff --git a/src/xenia/apu/xma_decoder.h b/src/xenia/apu/xma_decoder.h index 228a7290d..73da02c2e 100644 --- a/src/xenia/apu/xma_decoder.h +++ b/src/xenia/apu/xma_decoder.h @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -37,7 +37,7 @@ class XmaDecoder { void Shutdown(); uint32_t context_array_ptr() const { - return register_file_.values[XE_XMA_REG_CONTEXT_ARRAY_ADDRESS].u32; + return register_file_[XmaRegister::ContextArrayAddress]; } uint32_t AllocateContext(); diff --git a/src/xenia/apu/xma_register_file.cc b/src/xenia/apu/xma_register_file.cc index d3383b9cb..ee45b2811 100644 --- a/src/xenia/apu/xma_register_file.cc +++ b/src/xenia/apu/xma_register_file.cc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2014 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -20,10 +20,9 @@ XmaRegisterFile::XmaRegisterFile() { std::memset(values, 0, sizeof(values)); } const XmaRegisterInfo* XmaRegisterFile::GetRegisterInfo(uint32_t index) { switch (index) { -#define XE_XMA_REGISTER(index, type, name) \ +#define XE_XMA_REGISTER(index, name) \ case index: { \ static const XmaRegisterInfo reg_info = { \ - XmaRegisterInfo::Type::type, \ #name, \ }; \ return ®_info; \ diff --git a/src/xenia/apu/xma_register_file.h b/src/xenia/apu/xma_register_file.h index 09154b9ad..e2e924c57 100644 --- a/src/xenia/apu/xma_register_file.h +++ b/src/xenia/apu/xma_register_file.h @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2014 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -16,18 +16,13 @@ namespace xe { namespace apu { -enum XmaRegister { -#define XE_XMA_REGISTER(index, type, name) XE_XMA_REG_##name = index, +struct XmaRegister { +#define XE_XMA_REGISTER(index, name) static const uint32_t name = index; #include "xenia/apu/xma_register_table.inc" #undef XE_XMA_REGISTER }; struct XmaRegisterInfo { - enum class Type { - kDword, - kFloat, - }; - Type type; const char* name; }; @@ -38,14 +33,10 @@ class XmaRegisterFile { static const XmaRegisterInfo* GetRegisterInfo(uint32_t index); static const size_t kRegisterCount = (0xFFFF + 1) / 4; - union RegisterValue { - uint32_t u32; - float f32; - }; - RegisterValue values[kRegisterCount]; + uint32_t values[kRegisterCount]; - RegisterValue& operator[](int reg) { return values[reg]; } - RegisterValue& operator[](XmaRegister reg) { return values[reg]; } + uint32_t operator[](uint32_t reg) const { return values[reg]; } + uint32_t& operator[](uint32_t reg) { return values[reg]; } }; } // namespace apu diff --git a/src/xenia/apu/xma_register_table.inc b/src/xenia/apu/xma_register_table.inc index 49b32e26f..1703c2e9f 100644 --- a/src/xenia/apu/xma_register_table.inc +++ b/src/xenia/apu/xma_register_table.inc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -10,42 +10,72 @@ // This is a partial file designed to be included by other files when // constructing various tables. -//#define XE_XMA_REGISTER(index, type, name) +#ifndef XE_XMA_REGISTER +#define XE_XMA_REGISTER(index, name) +#define __XE_XMA_REGISTER_UNSET +#endif -XE_XMA_REGISTER(0x0600, kDword, CONTEXT_ARRAY_ADDRESS) +#ifndef XE_XMA_REGISTER_CONTEXT_GROUP +#define XE_XMA_REGISTER_CONTEXT_GROUP(index, suffix) \ + XE_XMA_REGISTER(index + 0, Context0##suffix) \ + XE_XMA_REGISTER(index + 1, Context1##suffix) \ + XE_XMA_REGISTER(index + 2, Context2##suffix) \ + XE_XMA_REGISTER(index + 3, Context3##suffix) \ + XE_XMA_REGISTER(index + 4, Context4##suffix) \ + XE_XMA_REGISTER(index + 5, Context5##suffix) \ + XE_XMA_REGISTER(index + 6, Context6##suffix) \ + XE_XMA_REGISTER(index + 7, Context7##suffix) \ + XE_XMA_REGISTER(index + 8, Context8##suffix) \ + XE_XMA_REGISTER(index + 9, Context9##suffix) +#endif -XE_XMA_REGISTER(0x0606, kDword, CURRENT_CONTEXT_INDEX) -XE_XMA_REGISTER(0x0607, kDword, NEXT_CONTEXT_INDEX) +// 0x0000..0x001F : ??? +// 0x0020..0x03FF : all 0xFFs? +// 0x0400..0x043F : ??? +// 0x0440..0x047F : all 0xFFs? +// 0x0480..0x048B : ??? +// 0x048C..0x04C0 : all 0xFFs? +// 0x04C1..0x04CB : ??? +// 0x04CC..0x04FF : all 0xFFs? +// 0x0500..0x051F : ??? +// 0x0520..0x057F : all 0xFFs? +// 0x0580..0x058F : ??? +// 0x0590..0x05FF : all 0xFFs? -XE_XMA_REGISTER(0x0650, kDword, CONTEXT_KICK_0) -XE_XMA_REGISTER(0x0651, kDword, CONTEXT_KICK_1) -XE_XMA_REGISTER(0x0652, kDword, CONTEXT_KICK_2) -XE_XMA_REGISTER(0x0653, kDword, CONTEXT_KICK_3) -XE_XMA_REGISTER(0x0654, kDword, CONTEXT_KICK_4) -XE_XMA_REGISTER(0x0655, kDword, CONTEXT_KICK_5) -XE_XMA_REGISTER(0x0656, kDword, CONTEXT_KICK_6) -XE_XMA_REGISTER(0x0657, kDword, CONTEXT_KICK_7) -XE_XMA_REGISTER(0x0658, kDword, CONTEXT_KICK_8) -XE_XMA_REGISTER(0x0659, kDword, CONTEXT_KICK_9) +// XMA stuff is probably only 0x0600..0x06FF +//---------------------------------------------------------------------------// -XE_XMA_REGISTER(0x0690, kDword, CONTEXT_LOCK_0) -XE_XMA_REGISTER(0x0691, kDword, CONTEXT_LOCK_1) -XE_XMA_REGISTER(0x0692, kDword, CONTEXT_LOCK_2) -XE_XMA_REGISTER(0x0693, kDword, CONTEXT_LOCK_3) -XE_XMA_REGISTER(0x0694, kDword, CONTEXT_LOCK_4) -XE_XMA_REGISTER(0x0695, kDword, CONTEXT_LOCK_5) -XE_XMA_REGISTER(0x0696, kDword, CONTEXT_LOCK_6) -XE_XMA_REGISTER(0x0697, kDword, CONTEXT_LOCK_7) -XE_XMA_REGISTER(0x0698, kDword, CONTEXT_LOCK_8) -XE_XMA_REGISTER(0x0699, kDword, CONTEXT_LOCK_9) +XE_XMA_REGISTER(0x0600, ContextArrayAddress) +// 0x0601..0x0605 : ??? +XE_XMA_REGISTER(0x0606, CurrentContextIndex) +XE_XMA_REGISTER(0x0607, NextContextIndex) +// 0x0608 : ??? +// 0x0609..0x060F : zero? +XE_XMA_REGISTER_CONTEXT_GROUP(0x0610, Unknown610) +// 0x061A..0x061F : zero? +XE_XMA_REGISTER_CONTEXT_GROUP(0x0620, Unknown620) +// 0x062A..0x0641 : zero? +// 0x0642..0x0644 : ??? +// 0x0645..0x064F : zero? +XE_XMA_REGISTER_CONTEXT_GROUP(0x0650, Kick) +// 0x065A..0x065F : zero? +XE_XMA_REGISTER_CONTEXT_GROUP(0x0660, Unknown660) +// 0x066A..0x0681 : zero? +// 0x0682..0x0684 : ??? +// 0x0685..0x068F : zero? +XE_XMA_REGISTER_CONTEXT_GROUP(0x0690, Lock) +// 0x069A..0x069F : zero? +XE_XMA_REGISTER_CONTEXT_GROUP(0x06A0, Clear) -XE_XMA_REGISTER(0x06A0, kDword, CONTEXT_CLEAR_0) -XE_XMA_REGISTER(0x06A1, kDword, CONTEXT_CLEAR_1) -XE_XMA_REGISTER(0x06A2, kDword, CONTEXT_CLEAR_2) -XE_XMA_REGISTER(0x06A3, kDword, CONTEXT_CLEAR_3) -XE_XMA_REGISTER(0x06A4, kDword, CONTEXT_CLEAR_4) -XE_XMA_REGISTER(0x06A5, kDword, CONTEXT_CLEAR_5) -XE_XMA_REGISTER(0x06A6, kDword, CONTEXT_CLEAR_6) -XE_XMA_REGISTER(0x06A7, kDword, CONTEXT_CLEAR_7) -XE_XMA_REGISTER(0x06A8, kDword, CONTEXT_CLEAR_8) -XE_XMA_REGISTER(0x06A9, kDword, CONTEXT_CLEAR_9) +//---------------------------------------------------------------------------// + +// 0x0700..0x07FF : all 0xFFs? +// 0x0800..0x17FF : ??? +// 0x1800..0x2FFF : all 0xFFs? +// 0x3000..0x30FF : ??? +// 0x3100..0x3FFF : all 0xFFs? + +#ifdef __XE_XMA_REGISTER_UNSET +#undef __XE_XMA_REGISTER_UNSET +#undef XE_XMA_REGISTER +#endif From 997d0555dbd6358dffd2950097424993763051af Mon Sep 17 00:00:00 2001 From: gibbed Date: Mon, 28 Jun 2021 19:36:43 -0500 Subject: [PATCH 31/42] Lint/format .inc files. --- src/xenia/kernel/util/export_table_post.inc | 3 +-- src/xenia/kernel/util/export_table_pre.inc | 5 ++--- src/xenia/kernel/util/ordinal_table_post.inc | 3 +-- src/xenia/kernel/util/ordinal_table_pre.inc | 7 ++----- src/xenia/kernel/xam/xam_module_export_groups.inc | 2 +- src/xenia/kernel/xam/xam_table.inc | 3 ++- src/xenia/kernel/xbdm/xbdm_table.inc | 3 ++- src/xenia/kernel/xboxkrnl/xboxkrnl_table.inc | 3 ++- xenia-build | 2 +- 9 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/xenia/kernel/util/export_table_post.inc b/src/xenia/kernel/util/export_table_post.inc index 7c3909fb9..8a69c1db3 100644 --- a/src/xenia/kernel/util/export_table_post.inc +++ b/src/xenia/kernel/util/export_table_post.inc @@ -2,13 +2,12 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ // Post-include file for an export table. - #undef FLAG #undef XE_EXPORT diff --git a/src/xenia/kernel/util/export_table_pre.inc b/src/xenia/kernel/util/export_table_pre.inc index e17068901..7647dcead 100644 --- a/src/xenia/kernel/util/export_table_pre.inc +++ b/src/xenia/kernel/util/export_table_pre.inc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -22,8 +22,7 @@ * my_module_export_table, xe::countof(my_module_export_table)); */ - #define XE_EXPORT(module, ordinal, name, type) \ xe::cpu::Export(ordinal, xe::cpu::Export::Type::type, #name) -#define FLAG(t) kXEKernelExportFlag##t +#define FLAG(t) kXEKernelExportFlag##t diff --git a/src/xenia/kernel/util/ordinal_table_post.inc b/src/xenia/kernel/util/ordinal_table_post.inc index 722b2da06..62c881976 100644 --- a/src/xenia/kernel/util/ordinal_table_post.inc +++ b/src/xenia/kernel/util/ordinal_table_post.inc @@ -2,12 +2,11 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ // Post-include file for an ordinal table. - #undef XE_EXPORT diff --git a/src/xenia/kernel/util/ordinal_table_pre.inc b/src/xenia/kernel/util/ordinal_table_pre.inc index 612156693..015b65f57 100644 --- a/src/xenia/kernel/util/ordinal_table_pre.inc +++ b/src/xenia/kernel/util/ordinal_table_pre.inc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -21,7 +21,4 @@ * #include "xenia/kernel/util/ordinal_table_post.inc" */ - -#define XE_EXPORT(module, ordinal, name, type) \ - name = ordinal - +#define XE_EXPORT(module, ordinal, name, type) name = ordinal diff --git a/src/xenia/kernel/xam/xam_module_export_groups.inc b/src/xenia/kernel/xam/xam_module_export_groups.inc index da6a363c6..563b789a5 100644 --- a/src/xenia/kernel/xam/xam_module_export_groups.inc +++ b/src/xenia/kernel/xam/xam_module_export_groups.inc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2020 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ diff --git a/src/xenia/kernel/xam/xam_table.inc b/src/xenia/kernel/xam/xam_table.inc index 0bc4f02e6..2e22f5629 100644 --- a/src/xenia/kernel/xam/xam_table.inc +++ b/src/xenia/kernel/xam/xam_table.inc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -10,6 +10,7 @@ // This is a partial file designed to be included by other files when // constructing various tables. +// clang-format off XE_EXPORT(xam, 0x00000001, NetDll_WSAStartup, kFunction), XE_EXPORT(xam, 0x00000002, NetDll_WSACleanup, kFunction), diff --git a/src/xenia/kernel/xbdm/xbdm_table.inc b/src/xenia/kernel/xbdm/xbdm_table.inc index 62a5ad75e..ab217b3ab 100644 --- a/src/xenia/kernel/xbdm/xbdm_table.inc +++ b/src/xenia/kernel/xbdm/xbdm_table.inc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -10,6 +10,7 @@ // This is a partial file designed to be included by other files when // constructing various tables. +// clang-format off XE_EXPORT(xbdm, 0x00000001, DmAllocatePool, kFunction), XE_EXPORT(xbdm, 0x00000002, DmAllocatePoolWithTag, kFunction), diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_table.inc b/src/xenia/kernel/xboxkrnl/xboxkrnl_table.inc index 3d6f6cc6f..0e0447055 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_table.inc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_table.inc @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * + * Copyright 2021 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -10,6 +10,7 @@ // This is a partial file designed to be included by other files when // constructing various tables. +// clang-format off XE_EXPORT(xboxkrnl, 0x00000001, DbgBreakPoint, kFunction), XE_EXPORT(xboxkrnl, 0x00000002, DbgBreakPointWithStatus, kFunction), diff --git a/xenia-build b/xenia-build index fdc31459a..6bba02562 100755 --- a/xenia-build +++ b/xenia-build @@ -1324,7 +1324,7 @@ def find_xenia_source_files(): return [os.path.join(root, name) for root, dirs, files in os.walk('src') for name in files - if name.endswith(('.cc', '.c', '.h', '.inl'))] + if name.endswith(('.cc', '.c', '.h', '.inl', '.inc'))] def find_all_source_files(): From a0ed4ec71134d64b0fbfc624dbcca0d38897806d Mon Sep 17 00:00:00 2001 From: gibbed Date: Mon, 28 Jun 2021 19:39:24 -0500 Subject: [PATCH 32/42] [xboxkrnl] Fix xeRtlNtStatusToDosError logging. --- src/xenia/kernel/xboxkrnl/xboxkrnl_error.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_error.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_error.cc index cd41c0858..3a27d490b 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_error.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_error.cc @@ -997,7 +997,7 @@ uint32_t xeRtlNtStatusToDosError(uint32_t source_status) { if (!result) { break; } - XELOGI("RtlNtStatusToDosError {:X} => {:X}", status, result); + XELOGI("xeRtlNtStatusToDosError {:X} => {:X}", status, result); return result; } ++error_table; @@ -1007,7 +1007,7 @@ uint32_t xeRtlNtStatusToDosError(uint32_t source_status) { return status & 0xFFFF; } - XELOGE("RtlNtStatusToDosError lookup NOT IMPLEMENTED"); + XELOGE("xeRtlNtStatusToDosError lookup NOT IMPLEMENTED"); return 317; // ERROR_MR_MID_NOT_FOUND } From fb0c354b2fcecbc7901416b2a1bb6025f1084a5c Mon Sep 17 00:00:00 2001 From: gibbed Date: Mon, 28 Jun 2021 19:40:25 -0500 Subject: [PATCH 33/42] [xboxkrnl] Trim DbgPrint messages. --- src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc index ff56a8889..f350fd9e5 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_strings.cc @@ -833,7 +833,14 @@ SHIM_CALL DbgPrint_shim(PPCContext* ppc_context, KernelState* kernel_state) { return; } - XELOGI("(DbgPrint) {}", data.str()); + // trim whitespace from end of message + auto str = data.str(); + str.erase(std::find_if(str.rbegin(), str.rend(), + [](uint8_t c) { return !std::isspace(c); }) + .base(), + str.end()); + + XELOGI("(DbgPrint) {}", str); SHIM_SET_RETURN_32(X_STATUS_SUCCESS); } From a3535be416c8baaa969a637e09a2300bd87737be Mon Sep 17 00:00:00 2001 From: gibbed Date: Tue, 29 Jun 2021 02:39:34 -0500 Subject: [PATCH 34/42] [CPU] Suppress C4065 warning in SyscallHandler. --- src/xenia/cpu/ppc/ppc_frontend.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xenia/cpu/ppc/ppc_frontend.cc b/src/xenia/cpu/ppc/ppc_frontend.cc index 594414fe4..33d6f892d 100644 --- a/src/xenia/cpu/ppc/ppc_frontend.cc +++ b/src/xenia/cpu/ppc/ppc_frontend.cc @@ -86,6 +86,7 @@ void SyscallHandler(PPCContext* ppc_context, void* arg0, void* arg1) { assert_unhandled_case(syscall_number); XELOGE("Unhandled syscall {}!", syscall_number); break; +#pragma warning(suppress : 4065) } } From e23a9b76081ea29c637ac1f6cb2a1b8c4580f422 Mon Sep 17 00:00:00 2001 From: emoose Date: Mon, 28 Jun 2021 21:27:29 +0100 Subject: [PATCH 35/42] [Kernel] Add APC support to NtWriteFile --- src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc | 31 +++++++++++++----------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc index 62d07e12c..38d557eef 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc @@ -357,11 +357,7 @@ dword_result_t NtWriteFile(dword_t file_handle, dword_t event_handle, pointer_t io_status_block, lpvoid_t buffer, dword_t buffer_length, lpqword_t byte_offset_ptr) { - // Async not supported yet. - assert_zero(apc_routine); - X_STATUS result = X_STATUS_SUCCESS; - uint32_t info = 0; // Grab event to signal. bool signal_event = false; @@ -386,30 +382,37 @@ dword_result_t NtWriteFile(dword_t file_handle, dword_t event_handle, buffer.guest_address(), buffer_length, byte_offset_ptr ? static_cast(*byte_offset_ptr) : -1, &bytes_written, apc_context); - if (XSUCCEEDED(result)) { - info = bytes_written; + + if (io_status_block) { + io_status_block->status = result; + io_status_block->information = static_cast(bytes_written); + } + + // Queue the APC callback. It must be delivered via the APC mechanism even + // though were are completing immediately. + // Low bit probably means do not queue to IO ports. + if ((uint32_t)apc_routine & ~1) { + if (apc_context) { + auto thread = XThread::GetCurrentThread(); + thread->EnqueueApc(static_cast(apc_routine) & ~1u, + apc_context, io_status_block, 0); + } } if (!file->is_synchronous()) { result = X_STATUS_PENDING; } - if (io_status_block) { - io_status_block->status = X_STATUS_SUCCESS; - io_status_block->information = info; - } - // Mark that we should signal the event now. We do this after // we have written the info out. signal_event = true; } else { // X_STATUS_PENDING if not returning immediately. result = X_STATUS_PENDING; - info = 0; if (io_status_block) { - io_status_block->status = X_STATUS_SUCCESS; - io_status_block->information = info; + io_status_block->status = X_STATUS_PENDING; + io_status_block->information = 0; } } } From 480791a05662a05c7b34be95e27be51705847ed5 Mon Sep 17 00:00:00 2001 From: Joel Linn Date: Tue, 29 Jun 2021 23:32:22 +0200 Subject: [PATCH 36/42] [Base] Implement message boxes on Linux --- src/xenia/base/main_posix.cc | 5 +++- src/xenia/base/system.h | 2 +- src/xenia/base/system_linux.cc | 43 +++++++++++++++++++++++++++++++--- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/xenia/base/main_posix.cc b/src/xenia/base/main_posix.cc index 8d14f9219..d3f0ef403 100644 --- a/src/xenia/base/main_posix.cc +++ b/src/xenia/base/main_posix.cc @@ -7,6 +7,9 @@ ****************************************************************************** */ +#include +#include + #include "xenia/base/cvar.h" #include "xenia/base/main.h" @@ -16,7 +19,7 @@ namespace xe { -bool has_console_attached() { return true; } +bool has_console_attached() { return isatty(fileno(stdin)) == 1; } void AttachConsole() {} diff --git a/src/xenia/base/system.h b/src/xenia/base/system.h index e69a95eb5..4bd0eac2b 100644 --- a/src/xenia/base/system.h +++ b/src/xenia/base/system.h @@ -11,7 +11,7 @@ #define XENIA_BASE_SYSTEM_H_ #include -#include +#include #include "xenia/base/string.h" diff --git a/src/xenia/base/system_linux.cc b/src/xenia/base/system_linux.cc index 7be020cda..920c9ab9e 100644 --- a/src/xenia/base/system_linux.cc +++ b/src/xenia/base/system_linux.cc @@ -7,15 +7,20 @@ ****************************************************************************** */ +#include +#include #include -#include +#include #include "xenia/base/assert.h" -#include "xenia/base/platform_linux.h" +#include "xenia/base/logging.h" #include "xenia/base/string.h" #include "xenia/base/system.h" +// Use headers in third party to not depend on system sdl headers for building +#include "third_party/SDL2/include/SDL.h" + namespace xe { void LaunchWebBrowser(const std::string_view url) { @@ -27,7 +32,39 @@ void LaunchWebBrowser(const std::string_view url) { void LaunchFileExplorer(const std::filesystem::path& path) { assert_always(); } void ShowSimpleMessageBox(SimpleMessageBoxType type, std::string_view message) { - assert_always(); + void* libsdl2 = dlopen("libSDL2.so", RTLD_LAZY | RTLD_LOCAL); + assert_not_null(libsdl2); + if (libsdl2) { + auto* pSDL_ShowSimpleMessageBox = + reinterpret_cast( + dlsym(libsdl2, "SDL_ShowSimpleMessageBox")); + assert_not_null(pSDL_ShowSimpleMessageBox); + if (pSDL_ShowSimpleMessageBox) { + Uint32 flags; + const char* title; + char* message_copy = reinterpret_cast(alloca(message.size() + 1)); + std::memcpy(message_copy, message.data(), message.size()); + message_copy[message.size()] = '\0'; + + switch (type) { + default: + case SimpleMessageBoxType::Help: + title = "Xenia Help"; + flags = SDL_MESSAGEBOX_INFORMATION; + break; + case SimpleMessageBoxType::Warning: + title = "Xenia Warning"; + flags = SDL_MESSAGEBOX_WARNING; + break; + case SimpleMessageBoxType::Error: + title = "Xenia Error"; + flags = SDL_MESSAGEBOX_ERROR; + break; + } + pSDL_ShowSimpleMessageBox(flags, title, message_copy, NULL); + } + dlclose(libsdl2); + } } } // namespace xe From b18f73b9494d22b9e0727e664af358768be63440 Mon Sep 17 00:00:00 2001 From: gibbed Date: Wed, 30 Jun 2021 02:29:42 -0500 Subject: [PATCH 37/42] [Kernel] Add make_object template. --- src/xenia/kernel/xobject.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/xenia/kernel/xobject.h b/src/xenia/kernel/xobject.h index aaf11c881..11d8ecb3c 100644 --- a/src/xenia/kernel/xobject.h +++ b/src/xenia/kernel/xobject.h @@ -348,6 +348,12 @@ bool operator!=(std::nullptr_t _Left, const object_ref<_Ty>& _Right) noexcept { return (!(_Left == _Right)); } +template +std::enable_if_t::value, object_ref> make_object( + Args&&... args) { + return object_ref(new T(std::forward(args)...)); +} + template object_ref retain_object(T* ptr) { if (ptr) ptr->Retain(); From e8fda5878c3a3d10ed2874e95bc3f8c98f6f19c7 Mon Sep 17 00:00:00 2001 From: gibbed Date: Fri, 4 Dec 2020 14:52:05 -0600 Subject: [PATCH 38/42] [XAM] Enumerator improvements. - [Kernel] XEnumerator::WriteItems no longer cares about provided buffer size, since we know the size when the XEnumerator was created. - [Kernel] Added XStaticEnumerator template. Previous XStaticEnumerator renamed to XStaticUntypedEnumerator. - [XAM] Deferred xeXamEnumerate. --- src/xenia/kernel/xam/apps/xam_app.cc | 3 +- src/xenia/kernel/xam/xam_content.cc | 7 ++- src/xenia/kernel/xam/xam_content_aggregate.cc | 26 +++++---- src/xenia/kernel/xam/xam_content_device.cc | 7 +-- src/xenia/kernel/xam/xam_enum.cc | 54 ++++++++----------- src/xenia/kernel/xam/xam_user.cc | 5 +- src/xenia/kernel/xenumerator.cc | 31 +++++------ src/xenia/kernel/xenumerator.h | 50 +++++++++++------ 8 files changed, 92 insertions(+), 91 deletions(-) diff --git a/src/xenia/kernel/xam/apps/xam_app.cc b/src/xenia/kernel/xam/apps/xam_app.cc index 664e1e60f..ded317b41 100644 --- a/src/xenia/kernel/xam/apps/xam_app.cc +++ b/src/xenia/kernel/xam/apps/xam_app.cc @@ -57,8 +57,7 @@ X_HRESULT XamApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, std::memset(buffer, 0, data->buffer_size); } uint32_t item_count = 0; - auto result = e->WriteItems(data->buffer_ptr, buffer, data->buffer_size, - &item_count); + auto result = e->WriteItems(data->buffer_ptr, buffer, &item_count); if (result == X_ERROR_SUCCESS && item_count >= 1) { if (data->length_ptr) { diff --git a/src/xenia/kernel/xam/xam_content.cc b/src/xenia/kernel/xam/xam_content.cc index b708b163b..514cac962 100644 --- a/src/xenia/kernel/xam/xam_content.cc +++ b/src/xenia/kernel/xam/xam_content.cc @@ -86,8 +86,8 @@ dword_result_t XamContentCreateEnumerator(dword_t user_index, dword_t device_id, *buffer_size_ptr = sizeof(XCONTENT_DATA) * items_per_enumerate; } - auto e = object_ref(new XStaticEnumerator( - kernel_state(), items_per_enumerate, sizeof(XCONTENT_DATA))); + auto e = make_object>(kernel_state(), + items_per_enumerate); auto result = e->Initialize(0xFF, 0xFE, 0x20005, 0x20007, 0); if (XFAILED(result)) { return result; @@ -99,8 +99,7 @@ dword_result_t XamContentCreateEnumerator(dword_t user_index, dword_t device_id, static_cast(DummyDeviceId::HDD), XContentType(uint32_t(content_type))); for (const auto& content_data : content_datas) { - auto item = reinterpret_cast(e->AppendItem()); - assert_not_null(item); + auto item = e->AppendItem(); *item = content_data; } } diff --git a/src/xenia/kernel/xam/xam_content_aggregate.cc b/src/xenia/kernel/xam/xam_content_aggregate.cc index 3de7b1566..765619002 100644 --- a/src/xenia/kernel/xam/xam_content_aggregate.cc +++ b/src/xenia/kernel/xam/xam_content_aggregate.cc @@ -23,7 +23,7 @@ namespace xe { namespace kernel { namespace xam { -void AddODDContentTest(object_ref e, +void AddODDContentTest(object_ref> e, XContentType content_type) { auto root_entry = kernel_state()->file_system()->ResolvePath( "game:\\Content\\0000000000000000"); @@ -62,13 +62,15 @@ void AddODDContentTest(object_ref e, break; } - auto item = reinterpret_cast(e->AppendItem()); + auto item = e->AppendItem(); assert_not_null(item); - item->device_id = static_cast(DummyDeviceId::ODD); - item->content_type = content_type; - item->set_display_name(to_utf16(content_entry->name())); - item->set_file_name(content_entry->name()); - item->title_id = title_id; + if (item) { + item->device_id = static_cast(DummyDeviceId::ODD); + item->content_type = content_type; + item->set_display_name(to_utf16(content_entry->name())); + item->set_file_name(content_entry->name()); + item->title_id = title_id; + } } } } @@ -86,8 +88,8 @@ dword_result_t XamContentAggregateCreateEnumerator(qword_t xuid, return X_E_INVALIDARG; } - auto e = object_ref(new XStaticEnumerator( - kernel_state(), 1, sizeof(XCONTENT_AGGREGATE_DATA))); + auto e = make_object>( + kernel_state(), 1); X_KENUMERATOR_CONTENT_AGGREGATE* extra; auto result = e->Initialize(0xFF, 0xFE, 0x2000E, 0x20010, 0, &extra); if (XFAILED(result)) { @@ -116,9 +118,11 @@ dword_result_t XamContentAggregateCreateEnumerator(qword_t xuid, static_cast(DummyDeviceId::HDD), content_type_enum, title_id); for (const auto& content_data : content_datas) { - auto item = reinterpret_cast(e->AppendItem()); + auto item = e->AppendItem(); assert_not_null(item); - *item = content_data; + if (item) { + *item = content_data; + } } } } diff --git a/src/xenia/kernel/xam/xam_content_device.cc b/src/xenia/kernel/xam/xam_content_device.cc index d0aaa34f1..e4312de95 100644 --- a/src/xenia/kernel/xam/xam_content_device.cc +++ b/src/xenia/kernel/xam/xam_content_device.cc @@ -139,8 +139,8 @@ dword_result_t XamContentCreateDeviceEnumerator(dword_t content_type, *buffer_size_ptr = sizeof(X_CONTENT_DEVICE_DATA) * max_count; } - auto e = object_ref(new XStaticEnumerator( - kernel_state(), max_count, sizeof(X_CONTENT_DEVICE_DATA))); + auto e = make_object>(kernel_state(), + max_count); auto result = e->Initialize(0xFE, 0xFE, 0x2000A, 0x20009, 0); if (XFAILED(result)) { return result; @@ -148,7 +148,8 @@ dword_result_t XamContentCreateDeviceEnumerator(dword_t content_type, for (const auto& device_info : dummy_device_infos_) { // Copy our dummy device into the enumerator - auto device_data = (X_CONTENT_DEVICE_DATA*)e->AppendItem(); + auto device_data = e->AppendItem(); + assert_not_null(device_data); if (device_data) { device_data->device_id = static_cast(device_info->device_id); device_data->device_type = diff --git a/src/xenia/kernel/xam/xam_enum.cc b/src/xenia/kernel/xam/xam_enum.cc index ce496a523..cd511c37a 100644 --- a/src/xenia/kernel/xam/xam_enum.cc +++ b/src/xenia/kernel/xam/xam_enum.cc @@ -32,49 +32,37 @@ uint32_t xeXamEnumerate(uint32_t handle, uint32_t flags, lpvoid_t buffer_ptr, uint32_t overlapped_ptr) { assert_true(flags == 0); - X_RESULT result; - uint32_t item_count = 0; - auto e = kernel_state()->object_table()->LookupObject(handle); if (!e) { - result = X_ERROR_INVALID_HANDLE; - } else if (!buffer_ptr) { - result = X_ERROR_INVALID_PARAMETER; - } else { - size_t needed_buffer_size = e->item_size() * e->items_per_enumerate(); - - uint32_t actual_buffer_size = buffer_size; - if (buffer_size == e->items_per_enumerate()) { - actual_buffer_size = static_cast(needed_buffer_size); - // Known culprits: - // Final Fight: Double Impact (saves) - XELOGW( - "Broken usage of XamEnumerate! buffer size={:X} vs actual " - "size={:X} (item size={:X}, items per enumerate={})", - buffer_size, actual_buffer_size, e->item_size(), - e->items_per_enumerate()); - } - - result = X_ERROR_INSUFFICIENT_BUFFER; - if (actual_buffer_size >= needed_buffer_size) { - buffer_ptr.Zero(actual_buffer_size); - result = - e->WriteItems(buffer_ptr.guest_address(), buffer_ptr.as(), - actual_buffer_size, &item_count); - } + return X_ERROR_INVALID_HANDLE; } + auto run = [e, buffer_ptr](uint32_t& extended_error, + uint32_t& length) -> X_RESULT { + X_RESULT result; + uint32_t item_count; + if (!buffer_ptr) { + result = X_ERROR_INVALID_PARAMETER; + item_count = 0; + } else { + result = e->WriteItems(buffer_ptr.guest_address(), + buffer_ptr.as(), &item_count); + } + extended_error = X_HRESULT_FROM_WIN32(result); + length = item_count; + return result; + }; + if (items_returned) { assert_true(!overlapped_ptr); + uint32_t extended_error; + uint32_t item_count; + X_RESULT result = run(extended_error, item_count); *items_returned = result == X_ERROR_SUCCESS ? item_count : 0; return result; } else if (overlapped_ptr) { assert_true(!items_returned); - kernel_state()->CompleteOverlappedImmediateEx( - overlapped_ptr, - result == X_ERROR_SUCCESS ? X_ERROR_SUCCESS : X_ERROR_FUNCTION_FAILED, - X_HRESULT_FROM_WIN32(result), - result == X_ERROR_SUCCESS ? item_count : 0); + kernel_state()->CompleteOverlappedDeferredEx(run, overlapped_ptr); return X_ERROR_IO_PENDING; } else { assert_always(); diff --git a/src/xenia/kernel/xam/xam_user.cc b/src/xenia/kernel/xam/xam_user.cc index 096a59b11..aed0c765b 100644 --- a/src/xenia/kernel/xam/xam_user.cc +++ b/src/xenia/kernel/xam/xam_user.cc @@ -608,7 +608,7 @@ class XStaticAchievementEnumerator : public XEnumerator { } uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data, - uint32_t buffer_size, uint32_t* written_count) override { + uint32_t* written_count) override { size_t count = std::min(items_.size() - current_item_, items_per_enumerate()); if (!count) { @@ -616,9 +616,6 @@ class XStaticAchievementEnumerator : public XEnumerator { } size_t size = count * item_size(); - if (size > buffer_size) { - return X_ERROR_INSUFFICIENT_BUFFER; - } auto details = reinterpret_cast(buffer_data); size_t string_offset = diff --git a/src/xenia/kernel/xenumerator.cc b/src/xenia/kernel/xenumerator.cc index 4b5ea7216..3aee21136 100644 --- a/src/xenia/kernel/xenumerator.cc +++ b/src/xenia/kernel/xenumerator.cc @@ -21,7 +21,7 @@ XEnumerator::XEnumerator(KernelState* kernel_state, size_t items_per_enumerate, XEnumerator::~XEnumerator() = default; X_STATUS XEnumerator::Initialize(uint32_t user_index, uint32_t app_id, - uint32_t message, uint32_t message2, + uint32_t open_message, uint32_t close_message, uint32_t flags, uint32_t extra_size, void** extra_buffer) { auto native_object = CreateNative(sizeof(X_KENUMERATOR) + extra_size); @@ -30,8 +30,8 @@ X_STATUS XEnumerator::Initialize(uint32_t user_index, uint32_t app_id, } auto guest_object = reinterpret_cast(native_object); guest_object->app_id = app_id; - guest_object->message = message; - guest_object->message2 = message2; + guest_object->open_message = open_message; + guest_object->close_message = close_message; guest_object->user_index = user_index; guest_object->items_per_enumerate = static_cast(items_per_enumerate_); @@ -44,32 +44,27 @@ X_STATUS XEnumerator::Initialize(uint32_t user_index, uint32_t app_id, } X_STATUS XEnumerator::Initialize(uint32_t user_index, uint32_t app_id, - uint32_t message, uint32_t message2, + uint32_t open_message, uint32_t close_message, uint32_t flags) { - return Initialize(user_index, app_id, message, message2, flags, 0, nullptr); + return Initialize(user_index, app_id, open_message, close_message, flags, 0, + nullptr); } -uint8_t* XStaticEnumerator::AppendItem() { - buffer_.resize(++item_count_ * item_size()); - auto ptr = - const_cast(buffer_.data() + (item_count_ - 1) * item_size()); - return ptr; +uint8_t* XStaticUntypedEnumerator::AppendItem() { + size_t offset = buffer_.size(); + buffer_.resize(offset + item_size()); + return const_cast(&buffer_.data()[offset]); } -uint32_t XStaticEnumerator::WriteItems(uint32_t buffer_ptr, - uint8_t* buffer_data, - uint32_t buffer_size, - uint32_t* written_count) { +uint32_t XStaticUntypedEnumerator::WriteItems(uint32_t buffer_ptr, + uint8_t* buffer_data, + uint32_t* written_count) { size_t count = std::min(item_count_ - current_item_, items_per_enumerate()); if (!count) { return X_ERROR_NO_MORE_FILES; } size_t size = count * item_size(); - if (size > buffer_size) { - return X_ERROR_INSUFFICIENT_BUFFER; - } - size_t offset = current_item_ * item_size(); std::memcpy(buffer_data, buffer_.data() + offset, size); diff --git a/src/xenia/kernel/xenumerator.h b/src/xenia/kernel/xenumerator.h index 3af03241d..7b2218e97 100644 --- a/src/xenia/kernel/xenumerator.h +++ b/src/xenia/kernel/xenumerator.h @@ -22,8 +22,8 @@ namespace kernel { struct X_KENUMERATOR { be app_id; - be message; - be message2; + be open_message; + be close_message; be user_index; be items_per_enumerate; be flags; @@ -43,19 +43,21 @@ class XEnumerator : public XObject { size_t item_size); virtual ~XEnumerator(); - X_STATUS Initialize(uint32_t user_index, uint32_t app_id, uint32_t message, - uint32_t message2, uint32_t flags, uint32_t extra_size, - void** extra_buffer); + X_STATUS Initialize(uint32_t user_index, uint32_t app_id, + uint32_t open_message, uint32_t close_message, + uint32_t flags, uint32_t extra_size, void** extra_buffer); - X_STATUS Initialize(uint32_t user_index, uint32_t app_id, uint32_t message, - uint32_t message2, uint32_t flags); + X_STATUS Initialize(uint32_t user_index, uint32_t app_id, + uint32_t open_message, uint32_t close_message, + uint32_t flags); template - X_STATUS Initialize(uint32_t user_index, uint32_t app_id, uint32_t message, - uint32_t message2, uint32_t flags, T** extra) { + X_STATUS Initialize(uint32_t user_index, uint32_t app_id, + uint32_t open_message, uint32_t close_message, + uint32_t flags, T** extra) { void* dummy; - auto result = Initialize(user_index, app_id, message, message2, flags, - static_cast(sizeof(T)), &dummy); + auto result = Initialize(user_index, app_id, open_message, close_message, + flags, static_cast(sizeof(T)), &dummy); if (extra) { *extra = XFAILED(result) ? nullptr : static_cast(dummy); } @@ -63,7 +65,6 @@ class XEnumerator : public XObject { } virtual uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data, - uint32_t buffer_size, uint32_t* written_count) = 0; size_t item_size() const { return item_size_; } @@ -74,10 +75,10 @@ class XEnumerator : public XObject { size_t item_size_; }; -class XStaticEnumerator : public XEnumerator { +class XStaticUntypedEnumerator : public XEnumerator { public: - XStaticEnumerator(KernelState* kernel_state, size_t items_per_enumerate, - size_t item_size) + XStaticUntypedEnumerator(KernelState* kernel_state, + size_t items_per_enumerate, size_t item_size) : XEnumerator(kernel_state, items_per_enumerate, item_size), item_count_(0), current_item_(0) {} @@ -87,7 +88,7 @@ class XStaticEnumerator : public XEnumerator { uint8_t* AppendItem(); uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data, - uint32_t buffer_size, uint32_t* written_count) override; + uint32_t* written_count) override; private: size_t item_count_; @@ -95,6 +96,23 @@ class XStaticEnumerator : public XEnumerator { std::vector buffer_; }; +template +class XStaticEnumerator : public XStaticUntypedEnumerator { + public: + XStaticEnumerator(KernelState* kernel_state, size_t items_per_enumerate) + : XStaticUntypedEnumerator(kernel_state, items_per_enumerate, sizeof(T)) { + } + + T* AppendItem() { + return reinterpret_cast(XStaticUntypedEnumerator::AppendItem()); + } + + void AppendItem(const T& item) { + auto ptr = AppendItem(); + item.Write(ptr); + } +}; + } // namespace kernel } // namespace xe From 4498a28568b629d7929cfdfbc35ff374e0a0e3ab Mon Sep 17 00:00:00 2001 From: gibbed Date: Wed, 30 Jun 2021 03:05:16 -0500 Subject: [PATCH 39/42] [XAM] Deferred xeXamContentCreate. --- src/xenia/kernel/xam/xam_content.cc | 165 +++++++++++++++------------- 1 file changed, 86 insertions(+), 79 deletions(-) diff --git a/src/xenia/kernel/xam/xam_content.cc b/src/xenia/kernel/xam/xam_content.cc index 514cac962..690edd6ca 100644 --- a/src/xenia/kernel/xam/xam_content.cc +++ b/src/xenia/kernel/xam/xam_content.cc @@ -123,7 +123,6 @@ dword_result_t xeXamContentCreate(dword_t user_index, lpstring_t root_name, lpdword_t license_mask_ptr, dword_t cache_size, qword_t content_size, lpvoid_t overlapped_ptr) { - X_RESULT result = X_ERROR_INVALID_PARAMETER; XCONTENT_AGGREGATE_DATA content_data; if (content_data_size == sizeof(XCONTENT_DATA)) { content_data = *content_data_ptr.as(); @@ -131,91 +130,99 @@ dword_result_t xeXamContentCreate(dword_t user_index, lpstring_t root_name, content_data = *content_data_ptr.as(); } else { assert_always(); - return result; + return X_ERROR_INVALID_PARAMETER; } auto content_manager = kernel_state()->content_manager(); - bool create = false; - bool open = false; - switch (flags & 0xF) { - case 1: // CREATE_NEW - // Fail if exists. - if (content_manager->ContentExists(content_data)) { - result = X_ERROR_ALREADY_EXISTS; - } else { - create = true; - } - break; - case 2: // CREATE_ALWAYS - // Overwrite existing, if any. - if (content_manager->ContentExists(content_data)) { - content_manager->DeleteContent(content_data); - create = true; - } else { - create = true; - } - break; - case 3: // OPEN_EXISTING - // Open only if exists. - if (!content_manager->ContentExists(content_data)) { - result = X_ERROR_PATH_NOT_FOUND; - } else { - open = true; - } - break; - case 4: // OPEN_ALWAYS - // Create if needed. - if (!content_manager->ContentExists(content_data)) { - create = true; - } else { - open = true; - } - break; - case 5: // TRUNCATE_EXISTING - // Fail if doesn't exist, if does exist delete and recreate. - if (!content_manager->ContentExists(content_data)) { - result = X_ERROR_PATH_NOT_FOUND; - } else { - content_manager->DeleteContent(content_data); - create = true; - } - break; - default: - assert_unhandled_case(flags & 0xF); - break; + + if (overlapped_ptr && disposition_ptr) { + *disposition_ptr = 0; } - // creation result - // 0 = ? - // 1 = created - // 2 = opened - uint32_t disposition = create ? 1 : 2; - if (disposition_ptr) { - // In case when overlapped_ptr exist we should clear disposition_ptr first - // however we're executing it immediately, so it's not required - *disposition_ptr = disposition; - } - - if (create) { - result = content_manager->CreateContent(root_name.value(), content_data); - } else if (open) { - result = content_manager->OpenContent(root_name.value(), content_data); - } - - if (license_mask_ptr && XSUCCEEDED(result)) { - *license_mask_ptr = 0; // Stub! - } - - if (overlapped_ptr) { - X_RESULT extended_error = X_HRESULT_FROM_WIN32(result); - if (int32_t(extended_error) < 0) { - result = X_ERROR_FUNCTION_FAILED; + auto run = [content_manager, root_name, flags, content_data, disposition_ptr, + license_mask_ptr](uint32_t& extended_error, + uint32_t& length) -> X_RESULT { + X_RESULT result = X_ERROR_INVALID_PARAMETER; + bool create = false; + bool open = false; + switch (flags & 0xF) { + case 1: // CREATE_NEW + // Fail if exists. + if (content_manager->ContentExists(content_data)) { + result = X_ERROR_ALREADY_EXISTS; + } else { + create = true; + } + break; + case 2: // CREATE_ALWAYS + // Overwrite existing, if any. + if (content_manager->ContentExists(content_data)) { + content_manager->DeleteContent(content_data); + create = true; + } else { + create = true; + } + break; + case 3: // OPEN_EXISTING + // Open only if exists. + if (!content_manager->ContentExists(content_data)) { + result = X_ERROR_PATH_NOT_FOUND; + } else { + open = true; + } + break; + case 4: // OPEN_ALWAYS + // Create if needed. + if (!content_manager->ContentExists(content_data)) { + create = true; + } else { + open = true; + } + break; + case 5: // TRUNCATE_EXISTING + // Fail if doesn't exist, if does exist delete and recreate. + if (!content_manager->ContentExists(content_data)) { + result = X_ERROR_PATH_NOT_FOUND; + } else { + content_manager->DeleteContent(content_data); + create = true; + } + break; + default: + assert_unhandled_case(flags & 0xF); + break; } - kernel_state()->CompleteOverlappedImmediateEx(overlapped_ptr, result, - extended_error, disposition); - return X_ERROR_IO_PENDING; - } else { + + // creation result + // 0 = ? + // 1 = created + // 2 = opened + uint32_t disposition = create ? 1 : 2; + if (disposition_ptr) { + *disposition_ptr = disposition; + } + + if (create) { + result = content_manager->CreateContent(root_name.value(), content_data); + } else if (open) { + result = content_manager->OpenContent(root_name.value(), content_data); + } + + if (license_mask_ptr && XSUCCEEDED(result)) { + *license_mask_ptr = 0; // Stub! + } + + extended_error = X_HRESULT_FROM_WIN32(result); + length = disposition; return result; + }; + + if (!overlapped_ptr) { + uint32_t extended_error, length; + return run(extended_error, length); + } else { + kernel_state()->CompleteOverlappedDeferredEx(run, overlapped_ptr); + return X_ERROR_IO_PENDING; } } From ddee85f0be00b3311a258a5ac3faee5e32b91de2 Mon Sep 17 00:00:00 2001 From: gibbed Date: Wed, 30 Jun 2021 13:23:49 -0500 Subject: [PATCH 40/42] [Kernel] Fix XStaticUntypedEnumerator item count. [Kernel] Fix XStaticUntypedEnumerator not tracking item count. Somehow this didn't make it into PR #1862. --- src/xenia/kernel/xenumerator.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xenia/kernel/xenumerator.cc b/src/xenia/kernel/xenumerator.cc index 3aee21136..dcaa6a07a 100644 --- a/src/xenia/kernel/xenumerator.cc +++ b/src/xenia/kernel/xenumerator.cc @@ -53,6 +53,7 @@ X_STATUS XEnumerator::Initialize(uint32_t user_index, uint32_t app_id, uint8_t* XStaticUntypedEnumerator::AppendItem() { size_t offset = buffer_.size(); buffer_.resize(offset + item_size()); + item_count_++; return const_cast(&buffer_.data()[offset]); } From 1cf12ec70b22c4eda28dea7fd8edf44900b098d6 Mon Sep 17 00:00:00 2001 From: Triang3l Date: Thu, 1 Jul 2021 23:32:26 +0300 Subject: [PATCH 41/42] [UI/HID] ui::VirtualKey enum --- src/xenia/app/emulator_window.cc | 35 +- src/xenia/base/byte_order.h | 13 +- src/xenia/base/profiling.cc | 29 +- src/xenia/base/profiling.h | 5 +- src/xenia/gpu/trace_viewer.cc | 3 +- src/xenia/hid/hid_demo.cc | 81 ++--- src/xenia/hid/input.h | 38 +- src/xenia/hid/sdl/sdl_input_driver.cc | 97 +++--- src/xenia/hid/winkey/winkey_input_driver.cc | 186 +++++----- src/xenia/hid/winkey/winkey_input_driver.h | 3 +- src/xenia/ui/imgui_drawer.cc | 92 ++--- src/xenia/ui/imgui_drawer.h | 3 + src/xenia/ui/ui_event.h | 15 +- src/xenia/ui/virtual_key.h | 362 ++++++++++++++++++++ src/xenia/ui/window.cc | 17 +- src/xenia/ui/window_demo.cc | 9 +- src/xenia/ui/window_gtk.cc | 8 +- src/xenia/ui/window_win.cc | 3 +- 18 files changed, 675 insertions(+), 324 deletions(-) create mode 100644 src/xenia/ui/virtual_key.h diff --git a/src/xenia/app/emulator_window.cc b/src/xenia/app/emulator_window.cc index a47edf27b..658303906 100644 --- a/src/xenia/app/emulator_window.cc +++ b/src/xenia/app/emulator_window.cc @@ -24,6 +24,7 @@ #include "xenia/ui/file_picker.h" #include "xenia/ui/imgui_dialog.h" #include "xenia/ui/imgui_drawer.h" +#include "xenia/ui/virtual_key.h" // Autogenerated by `xb premake`. #include "build/version.h" @@ -93,49 +94,49 @@ bool EmulatorWindow::Initialize() { window_->on_key_down.AddListener([this](KeyEvent* e) { bool handled = true; - switch (e->key_code()) { - case 0x4F: { // o + switch (e->virtual_key()) { + case ui::VirtualKey::kO: { if (e->is_ctrl_pressed()) { FileOpen(); } } break; - case 0x6A: { // numpad * + case ui::VirtualKey::kMultiply: { CpuTimeScalarReset(); } break; - case 0x6D: { // numpad minus + case ui::VirtualKey::kSubtract: { CpuTimeScalarSetHalf(); } break; - case 0x6B: { // numpad plus + case ui::VirtualKey::kAdd: { CpuTimeScalarSetDouble(); } break; - case 0x72: { // F3 + case ui::VirtualKey::kF3: { Profiler::ToggleDisplay(); } break; - case 0x73: { // VK_F4 + case ui::VirtualKey::kF4: { GpuTraceFrame(); } break; - case 0x74: { // VK_F5 + case ui::VirtualKey::kF5: { GpuClearCaches(); } break; - case 0x76: { // VK_F7 + case ui::VirtualKey::kF7: { // Save to file // TODO: Choose path based on user input, or from options // TODO: Spawn a new thread to do this. emulator()->SaveToFile("test.sav"); } break; - case 0x77: { // VK_F8 + case ui::VirtualKey::kF8: { // Restore from file // TODO: Choose path from user // TODO: Spawn a new thread to do this. emulator()->RestoreFromFile("test.sav"); } break; - case 0x7A: { // VK_F11 + case ui::VirtualKey::kF11: { ToggleFullscreen(); } break; - case 0x1B: { // VK_ESCAPE - // Allow users to escape fullscreen (but not enter it). + case ui::VirtualKey::kEscape: { + // Allow users to escape fullscreen (but not enter it). if (window_->is_fullscreen()) { window_->ToggleFullscreen(false); } else { @@ -143,18 +144,18 @@ bool EmulatorWindow::Initialize() { } } break; - case 0x13: { // VK_PAUSE + case ui::VirtualKey::kPause: { CpuBreakIntoDebugger(); } break; - case 0x03: { // VK_CANCEL + case ui::VirtualKey::kCancel: { CpuBreakIntoHostDebugger(); } break; - case 0x70: { // VK_F1 + case ui::VirtualKey::kF1: { ShowHelpWebsite(); } break; - case 0x71: { // VK_F2 + case ui::VirtualKey::kF2: { ShowCommitID(); } break; diff --git a/src/xenia/base/byte_order.h b/src/xenia/base/byte_order.h index abbf41606..1a3c63b2f 100644 --- a/src/xenia/base/byte_order.h +++ b/src/xenia/base/byte_order.h @@ -81,20 +81,23 @@ inline T byte_swap(T value) { template struct endian_store { endian_store() = default; - endian_store(const T& src) { + endian_store(const T& src) { set(src); } + endian_store(const endian_store& other) { set(other); } + operator T() const { return get(); } + + void set(const T& src) { if constexpr (std::endian::native == E) { value = src; } else { value = xe::byte_swap(src); } } - endian_store(const endian_store& other) { value = other.value; } - operator T() const { + void set(const endian_store& other) { value = other.value; } + T get() const { if constexpr (std::endian::native == E) { return value; - } else { - return xe::byte_swap(value); } + return xe::byte_swap(value); } endian_store& operator+=(int a) { diff --git a/src/xenia/base/profiling.cc b/src/xenia/base/profiling.cc index a28f6e26b..bf24d4f7d 100644 --- a/src/xenia/base/profiling.cc +++ b/src/xenia/base/profiling.cc @@ -30,6 +30,7 @@ #include "xenia/base/assert.h" #include "xenia/base/cvar.h" #include "xenia/base/profiling.h" +#include "xenia/ui/virtual_key.h" #include "xenia/ui/window.h" #if XE_OPTION_PROFILING @@ -112,31 +113,35 @@ void Profiler::ThreadEnter(const char* name) { void Profiler::ThreadExit() { MicroProfileOnThreadExit(); } -bool Profiler::OnKeyDown(int key_code) { +bool Profiler::OnKeyDown(ui::VirtualKey virtual_key) { // https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx - switch (key_code) { - case VK_OEM_3: // ` + switch (virtual_key) { + case ui::VirtualKey::kOem3: // ` MicroProfileTogglePause(); return true; #if XE_OPTION_PROFILING_UI - case VK_TAB: + case ui::VirtualKey::kTab: MicroProfileToggleDisplayMode(); return true; - case 0x31: // 1 + case ui::VirtualKey::k1: MicroProfileModKey(1); return true; #endif // XE_OPTION_PROFILING_UI + default: + break; } return false; } -bool Profiler::OnKeyUp(int key_code) { - switch (key_code) { +bool Profiler::OnKeyUp(ui::VirtualKey virtual_key) { + switch (virtual_key) { #if XE_OPTION_PROFILING_UI - case 0x31: // 1 + case ui::VirtualKey::k1: MicroProfileModKey(0); return true; #endif // XE_OPTION_PROFILING_UI + default: + break; } return false; } @@ -219,14 +224,14 @@ void Profiler::set_window(ui::Window* window) { // Watch for toggle/mode keys and such. window_->on_key_down.AddListener([](ui::KeyEvent* e) { if (Profiler::is_visible()) { - Profiler::OnKeyDown(e->key_code()); + Profiler::OnKeyDown(e->virtual_key()); e->set_handled(true); window_->Invalidate(); } }); window_->on_key_up.AddListener([](ui::KeyEvent* e) { if (Profiler::is_visible()) { - Profiler::OnKeyUp(e->key_code()); + Profiler::OnKeyUp(e->virtual_key()); e->set_handled(true); window_->Invalidate(); } @@ -257,8 +262,8 @@ void Profiler::Shutdown() {} uint32_t Profiler::GetColor(const char* str) { return 0; } void Profiler::ThreadEnter(const char* name) {} void Profiler::ThreadExit() {} -bool Profiler::OnKeyDown(int key_code) { return false; } -bool Profiler::OnKeyUp(int key_code) { return false; } +bool Profiler::OnKeyDown(ui::VirtualKey virtual_key) { return false; } +bool Profiler::OnKeyUp(ui::VirtualKey virtual_key) { return false; } void Profiler::OnMouseDown(bool left_button, bool right_button) {} void Profiler::OnMouseUp() {} void Profiler::OnMouseMove(int x, int y) {} diff --git a/src/xenia/base/profiling.h b/src/xenia/base/profiling.h index d6cc42d41..a55600d7e 100644 --- a/src/xenia/base/profiling.h +++ b/src/xenia/base/profiling.h @@ -13,6 +13,7 @@ #include #include "xenia/base/string.h" +#include "xenia/ui/virtual_key.h" #if XE_PLATFORM_WIN32 #define XE_OPTION_PROFILING 1 @@ -171,8 +172,8 @@ class Profiler { // Deactivates the calling thread for profiling. static void ThreadExit(); - static bool OnKeyDown(int key_code); - static bool OnKeyUp(int key_code); + static bool OnKeyDown(ui::VirtualKey virtual_key); + static bool OnKeyUp(ui::VirtualKey virtual_key); static void OnMouseDown(bool left_button, bool right_button); static void OnMouseUp(); static void OnMouseMove(int x, int y); diff --git a/src/xenia/gpu/trace_viewer.cc b/src/xenia/gpu/trace_viewer.cc index f632267fa..cfc82bf2a 100644 --- a/src/xenia/gpu/trace_viewer.cc +++ b/src/xenia/gpu/trace_viewer.cc @@ -28,6 +28,7 @@ #include "xenia/memory.h" #include "xenia/ui/file_picker.h" #include "xenia/ui/imgui_drawer.h" +#include "xenia/ui/virtual_key.h" #include "xenia/ui/window.h" #include "xenia/xbox.h" @@ -135,7 +136,7 @@ bool TraceViewer::Setup() { window_->set_imgui_input_enabled(true); window_->on_key_char.AddListener([&](xe::ui::KeyEvent* e) { - if (e->key_code() == 0x74 /* VK_F5 */) { + if (e->virtual_key() == xe::ui::VirtualKey::kF5) { graphics_system_->ClearCaches(); e->set_handled(true); } diff --git a/src/xenia/hid/hid_demo.cc b/src/xenia/hid/hid_demo.cc index 44d8c780c..c1a81f533 100644 --- a/src/xenia/hid/hid_demo.cc +++ b/src/xenia/hid/hid_demo.cc @@ -10,8 +10,8 @@ #include #include #include -#include #include +#include #include "third_party/fmt/include/fmt/format.h" #include "third_party/imgui/imgui.h" @@ -23,6 +23,7 @@ #include "xenia/hid/hid_flags.h" #include "xenia/hid/input_system.h" #include "xenia/ui/imgui_drawer.h" +#include "xenia/ui/virtual_key.h" #include "xenia/ui/vulkan/vulkan_provider.h" #include "xenia/ui/window.h" @@ -281,44 +282,42 @@ void DrawInputGetState() { ImGui::EndChild(); } -static const std::map::type, - const std::string> - vk_pretty = { - {X_INPUT_GAMEPAD_VK_A, "A"}, - {X_INPUT_GAMEPAD_VK_B, "B"}, - {X_INPUT_GAMEPAD_VK_X, "X"}, - {X_INPUT_GAMEPAD_VK_Y, "Y"}, - {X_INPUT_GAMEPAD_VK_RSHOULDER, "R Shoulder"}, - {X_INPUT_GAMEPAD_VK_LSHOULDER, "L Shoulder"}, - {X_INPUT_GAMEPAD_VK_LTRIGGER, "L Trigger"}, - {X_INPUT_GAMEPAD_VK_RTRIGGER, "R Trigger"}, +static const std::unordered_map kVkPretty = { + {ui::VirtualKey::kXInputPadA, "A"}, + {ui::VirtualKey::kXInputPadB, "B"}, + {ui::VirtualKey::kXInputPadX, "X"}, + {ui::VirtualKey::kXInputPadY, "Y"}, + {ui::VirtualKey::kXInputPadRShoulder, "R Shoulder"}, + {ui::VirtualKey::kXInputPadLShoulder, "L Shoulder"}, + {ui::VirtualKey::kXInputPadLTrigger, "L Trigger"}, + {ui::VirtualKey::kXInputPadRTrigger, "R Trigger"}, - {X_INPUT_GAMEPAD_VK_DPAD_UP, "DPad up"}, - {X_INPUT_GAMEPAD_VK_DPAD_DOWN, "DPad down"}, - {X_INPUT_GAMEPAD_VK_DPAD_LEFT, "DPad left"}, - {X_INPUT_GAMEPAD_VK_DPAD_RIGHT, "DPad right"}, - {X_INPUT_GAMEPAD_VK_START, "Start"}, - {X_INPUT_GAMEPAD_VK_BACK, "Back"}, - {X_INPUT_GAMEPAD_VK_LTHUMB_PRESS, "L Thumb press"}, - {X_INPUT_GAMEPAD_VK_RTHUMB_PRESS, "R Thumb press"}, + {ui::VirtualKey::kXInputPadDpadUp, "DPad up"}, + {ui::VirtualKey::kXInputPadDpadDown, "DPad down"}, + {ui::VirtualKey::kXInputPadDpadLeft, "DPad left"}, + {ui::VirtualKey::kXInputPadDpadRight, "DPad right"}, + {ui::VirtualKey::kXInputPadStart, "Start"}, + {ui::VirtualKey::kXInputPadBack, "Back"}, + {ui::VirtualKey::kXInputPadLThumbPress, "L Thumb press"}, + {ui::VirtualKey::kXInputPadRThumbPress, "R Thumb press"}, - {X_INPUT_GAMEPAD_VK_LTHUMB_UP, "L Thumb up"}, - {X_INPUT_GAMEPAD_VK_LTHUMB_DOWN, "L Thumb down"}, - {X_INPUT_GAMEPAD_VK_LTHUMB_RIGHT, "L Thumb right"}, - {X_INPUT_GAMEPAD_VK_LTHUMB_LEFT, "L Thumb left"}, - {X_INPUT_GAMEPAD_VK_LTHUMB_UPLEFT, "L Thumb up & left"}, - {X_INPUT_GAMEPAD_VK_LTHUMB_UPRIGHT, "L Thumb up & right"}, - {X_INPUT_GAMEPAD_VK_LTHUMB_DOWNRIGHT, "L Thumb down & right"}, - {X_INPUT_GAMEPAD_VK_LTHUMB_DOWNLEFT, "L Thumb down & left"}, + {ui::VirtualKey::kXInputPadLThumbUp, "L Thumb up"}, + {ui::VirtualKey::kXInputPadLThumbDown, "L Thumb down"}, + {ui::VirtualKey::kXInputPadLThumbRight, "L Thumb right"}, + {ui::VirtualKey::kXInputPadLThumbLeft, "L Thumb left"}, + {ui::VirtualKey::kXInputPadLThumbUpLeft, "L Thumb up & left"}, + {ui::VirtualKey::kXInputPadLThumbUpRight, "L Thumb up & right"}, + {ui::VirtualKey::kXInputPadLThumbDownRight, "L Thumb down & right"}, + {ui::VirtualKey::kXInputPadLThumbDownLeft, "L Thumb down & left"}, - {X_INPUT_GAMEPAD_VK_RTHUMB_UP, "R Thumb up"}, - {X_INPUT_GAMEPAD_VK_RTHUMB_DOWN, "R Thumb down"}, - {X_INPUT_GAMEPAD_VK_RTHUMB_RIGHT, "R Thumb right"}, - {X_INPUT_GAMEPAD_VK_RTHUMB_LEFT, "R Thumb left"}, - {X_INPUT_GAMEPAD_VK_RTHUMB_UPLEFT, "R Thumb up & left"}, - {X_INPUT_GAMEPAD_VK_RTHUMB_UPRIGHT, "R Thumb up & right"}, - {X_INPUT_GAMEPAD_VK_RTHUMB_DOWNRIGHT, "R Thumb down & right"}, - {X_INPUT_GAMEPAD_VK_RTHUMB_DOWNLEFT, "R Thumb down & left"}, + {ui::VirtualKey::kXInputPadRThumbUp, "R Thumb up"}, + {ui::VirtualKey::kXInputPadRThumbDown, "R Thumb down"}, + {ui::VirtualKey::kXInputPadRThumbRight, "R Thumb right"}, + {ui::VirtualKey::kXInputPadRThumbLeft, "R Thumb left"}, + {ui::VirtualKey::kXInputPadRThumbUpLeft, "R Thumb up & left"}, + {ui::VirtualKey::kXInputPadRThumbUpRight, "R Thumb up & right"}, + {ui::VirtualKey::kXInputPadRThumbDownRight, "R Thumb down & right"}, + {ui::VirtualKey::kXInputPadRThumbDownLeft, "R Thumb down & left"}, }; void DrawUserInputGetKeystroke(uint32_t user_index, bool poll, @@ -354,10 +353,12 @@ void DrawUserInputGetKeystroke(uint32_t user_index, bool poll, break; } - const auto key_search = vk_pretty.find(stroke.virtual_key); - const auto key = key_search != vk_pretty.end() - ? key_search->second - : fmt::format("0x{:04x}", stroke.virtual_key); + ui::VirtualKey virtual_key = ui::VirtualKey(stroke.virtual_key.get()); + const auto key_search = kVkPretty.find(virtual_key); + std::string key = + key_search != kVkPretty.cend() + ? key_search->second + : fmt::format("0x{:04x}", uint16_t(virtual_key)); event_log.emplace_front(fmt::format( "{:>6} {:>9}ms {:<20} {} {} {}", ImGui::GetFrameCount(), dur, key, diff --git a/src/xenia/hid/input.h b/src/xenia/hid/input.h index 9ebec0108..82202a391 100644 --- a/src/xenia/hid/input.h +++ b/src/xenia/hid/input.h @@ -46,43 +46,7 @@ enum X_INPUT_GAMEPAD_BUTTON { X_INPUT_GAMEPAD_Y = 0x8000, }; -enum X_INPUT_GAMEPAD_VK { - X_INPUT_GAMEPAD_VK_A = 0x5800, - X_INPUT_GAMEPAD_VK_B = 0x5801, - X_INPUT_GAMEPAD_VK_X = 0x5802, - X_INPUT_GAMEPAD_VK_Y = 0x5803, - X_INPUT_GAMEPAD_VK_RSHOULDER = 0x5804, - X_INPUT_GAMEPAD_VK_LSHOULDER = 0x5805, - X_INPUT_GAMEPAD_VK_LTRIGGER = 0x5806, - X_INPUT_GAMEPAD_VK_RTRIGGER = 0x5807, - - X_INPUT_GAMEPAD_VK_DPAD_UP = 0x5810, - X_INPUT_GAMEPAD_VK_DPAD_DOWN = 0x5811, - X_INPUT_GAMEPAD_VK_DPAD_LEFT = 0x5812, - X_INPUT_GAMEPAD_VK_DPAD_RIGHT = 0x5813, - X_INPUT_GAMEPAD_VK_START = 0x5814, - X_INPUT_GAMEPAD_VK_BACK = 0x5815, - X_INPUT_GAMEPAD_VK_LTHUMB_PRESS = 0x5816, - X_INPUT_GAMEPAD_VK_RTHUMB_PRESS = 0x5817, - - X_INPUT_GAMEPAD_VK_LTHUMB_UP = 0x5820, - X_INPUT_GAMEPAD_VK_LTHUMB_DOWN = 0x5821, - X_INPUT_GAMEPAD_VK_LTHUMB_RIGHT = 0x5822, - X_INPUT_GAMEPAD_VK_LTHUMB_LEFT = 0x5823, - X_INPUT_GAMEPAD_VK_LTHUMB_UPLEFT = 0x5824, - X_INPUT_GAMEPAD_VK_LTHUMB_UPRIGHT = 0x5825, - X_INPUT_GAMEPAD_VK_LTHUMB_DOWNRIGHT = 0x5826, - X_INPUT_GAMEPAD_VK_LTHUMB_DOWNLEFT = 0x5827, - - X_INPUT_GAMEPAD_VK_RTHUMB_UP = 0x5830, - X_INPUT_GAMEPAD_VK_RTHUMB_DOWN = 0x5831, - X_INPUT_GAMEPAD_VK_RTHUMB_RIGHT = 0x5832, - X_INPUT_GAMEPAD_VK_RTHUMB_LEFT = 0x5833, - X_INPUT_GAMEPAD_VK_RTHUMB_UPLEFT = 0x5834, - X_INPUT_GAMEPAD_VK_RTHUMB_UPRIGHT = 0x5835, - X_INPUT_GAMEPAD_VK_RTHUMB_DOWNRIGHT = 0x5836, - X_INPUT_GAMEPAD_VK_RTHUMB_DOWNLEFT = 0x5837, -}; +// For VK_PAD, use ui::VirtualKey. enum X_INPUT_KEYSTROKE_FLAGS { X_INPUT_KEYSTROKE_KEYDOWN = 0x0001, diff --git a/src/xenia/hid/sdl/sdl_input_driver.cc b/src/xenia/hid/sdl/sdl_input_driver.cc index 27a00c80d..914f31bb8 100644 --- a/src/xenia/hid/sdl/sdl_input_driver.cc +++ b/src/xenia/hid/sdl/sdl_input_driver.cc @@ -20,6 +20,7 @@ #include "xenia/base/logging.h" #include "xenia/helper/sdl/sdl_helper.h" #include "xenia/hid/hid_flags.h" +#include "xenia/ui/virtual_key.h" #include "xenia/ui/window.h" // TODO(joellinn) make this path relative to the config folder. @@ -238,48 +239,46 @@ X_RESULT SDLInputDriver::GetKeystroke(uint32_t users, uint32_t flags, // The order of this list is also the order in which events are send if // multiple buttons change at once. static_assert(sizeof(X_INPUT_GAMEPAD::buttons) == 2); - static constexpr std::array::type, - 34> - vk_lookup = { - // 00 - True buttons from xinput button field - X_INPUT_GAMEPAD_VK_DPAD_UP, - X_INPUT_GAMEPAD_VK_DPAD_DOWN, - X_INPUT_GAMEPAD_VK_DPAD_LEFT, - X_INPUT_GAMEPAD_VK_DPAD_RIGHT, - X_INPUT_GAMEPAD_VK_START, - X_INPUT_GAMEPAD_VK_BACK, - X_INPUT_GAMEPAD_VK_LTHUMB_PRESS, - X_INPUT_GAMEPAD_VK_RTHUMB_PRESS, - X_INPUT_GAMEPAD_VK_LSHOULDER, - X_INPUT_GAMEPAD_VK_RSHOULDER, - 0, /* Guide has no VK */ - 0, /* Unknown */ - X_INPUT_GAMEPAD_VK_A, - X_INPUT_GAMEPAD_VK_B, - X_INPUT_GAMEPAD_VK_X, - X_INPUT_GAMEPAD_VK_Y, - // 16 - Fake buttons generated from analog inputs - X_INPUT_GAMEPAD_VK_LTRIGGER, - X_INPUT_GAMEPAD_VK_RTRIGGER, - // 18 - X_INPUT_GAMEPAD_VK_LTHUMB_UP, - X_INPUT_GAMEPAD_VK_LTHUMB_DOWN, - X_INPUT_GAMEPAD_VK_LTHUMB_RIGHT, - X_INPUT_GAMEPAD_VK_LTHUMB_LEFT, - X_INPUT_GAMEPAD_VK_LTHUMB_UPLEFT, - X_INPUT_GAMEPAD_VK_LTHUMB_UPRIGHT, - X_INPUT_GAMEPAD_VK_LTHUMB_DOWNRIGHT, - X_INPUT_GAMEPAD_VK_LTHUMB_DOWNLEFT, - // 26 - X_INPUT_GAMEPAD_VK_RTHUMB_UP, - X_INPUT_GAMEPAD_VK_RTHUMB_DOWN, - X_INPUT_GAMEPAD_VK_RTHUMB_RIGHT, - X_INPUT_GAMEPAD_VK_RTHUMB_LEFT, - X_INPUT_GAMEPAD_VK_RTHUMB_UPLEFT, - X_INPUT_GAMEPAD_VK_RTHUMB_UPRIGHT, - X_INPUT_GAMEPAD_VK_RTHUMB_DOWNRIGHT, - X_INPUT_GAMEPAD_VK_RTHUMB_DOWNLEFT, - }; + static constexpr std::array kVkLookup = { + // 00 - True buttons from xinput button field + ui::VirtualKey::kXInputPadDpadUp, + ui::VirtualKey::kXInputPadDpadDown, + ui::VirtualKey::kXInputPadDpadLeft, + ui::VirtualKey::kXInputPadDpadRight, + ui::VirtualKey::kXInputPadStart, + ui::VirtualKey::kXInputPadBack, + ui::VirtualKey::kXInputPadLThumbPress, + ui::VirtualKey::kXInputPadRThumbPress, + ui::VirtualKey::kXInputPadLShoulder, + ui::VirtualKey::kXInputPadRShoulder, + ui::VirtualKey::kNone, /* Guide has no VK */ + ui::VirtualKey::kNone, /* Unknown */ + ui::VirtualKey::kXInputPadA, + ui::VirtualKey::kXInputPadB, + ui::VirtualKey::kXInputPadX, + ui::VirtualKey::kXInputPadY, + // 16 - Fake buttons generated from analog inputs + ui::VirtualKey::kXInputPadLTrigger, + ui::VirtualKey::kXInputPadRTrigger, + // 18 + ui::VirtualKey::kXInputPadLThumbUp, + ui::VirtualKey::kXInputPadLThumbDown, + ui::VirtualKey::kXInputPadLThumbRight, + ui::VirtualKey::kXInputPadLThumbLeft, + ui::VirtualKey::kXInputPadLThumbUpLeft, + ui::VirtualKey::kXInputPadLThumbUpRight, + ui::VirtualKey::kXInputPadLThumbDownRight, + ui::VirtualKey::kXInputPadLThumbDownLeft, + // 26 + ui::VirtualKey::kXInputPadRThumbUp, + ui::VirtualKey::kXInputPadRThumbDown, + ui::VirtualKey::kXInputPadRThumbRight, + ui::VirtualKey::kXInputPadRThumbLeft, + ui::VirtualKey::kXInputPadRThumbUpLeft, + ui::VirtualKey::kXInputPadRThumbUpRight, + ui::VirtualKey::kXInputPadRThumbDownRight, + ui::VirtualKey::kXInputPadRThumbDownLeft, + }; auto is_active = this->is_active(); @@ -319,9 +318,9 @@ X_RESULT SDLInputDriver::GetKeystroke(uint32_t users, uint32_t flags, if (last.repeat_state == RepeatState::Repeating && (last.repeat_time + HID_SDL_REPEAT_RATE < guest_now)) { last.repeat_time = guest_now; - auto vk = vk_lookup.at(last.repeat_butt_idx); - assert_not_zero(vk); - out_keystroke->virtual_key = vk; + ui::VirtualKey vk = kVkLookup.at(last.repeat_butt_idx); + assert_true(vk != ui::VirtualKey::kNone); + out_keystroke->virtual_key = uint16_t(vk); out_keystroke->unicode = 0; out_keystroke->user_index = user_index; out_keystroke->hid_code = 0; @@ -340,17 +339,17 @@ X_RESULT SDLInputDriver::GetKeystroke(uint32_t users, uint32_t flags, // up before THUMB_LEFT is down. for (auto [clear_pass, i] = std::tuple{true, 0}; i < 2; clear_pass = false, i++) { - for (uint8_t i = 0; i < std::size(vk_lookup); i++) { + for (uint8_t i = 0; i < uint8_t(std::size(kVkLookup)); i++) { auto fbutton = uint64_t(1) << i; if (!(butts_changed & fbutton)) { continue; } - auto vk = vk_lookup.at(i); - if (!vk) { + ui::VirtualKey vk = kVkLookup.at(last.repeat_butt_idx); + if (vk == ui::VirtualKey::kNone) { continue; } - out_keystroke->virtual_key = vk; + out_keystroke->virtual_key = uint16_t(vk); out_keystroke->unicode = 0; out_keystroke->user_index = user_index; out_keystroke->hid_code = 0; diff --git a/src/xenia/hid/winkey/winkey_input_driver.cc b/src/xenia/hid/winkey/winkey_input_driver.cc index 18e192578..ba0b12cdf 100644 --- a/src/xenia/hid/winkey/winkey_input_driver.cc +++ b/src/xenia/hid/winkey/winkey_input_driver.cc @@ -12,6 +12,7 @@ #include "xenia/base/platform_win.h" #include "xenia/hid/hid_flags.h" #include "xenia/hid/input_system.h" +#include "xenia/ui/virtual_key.h" #include "xenia/ui/window.h" namespace xe { @@ -29,7 +30,7 @@ WinKeyInputDriver::WinKeyInputDriver(xe::ui::Window* window) auto global_lock = global_critical_region_.Acquire(); KeyEvent key; - key.vkey = evt->key_code(); + key.virtual_key = evt->virtual_key(); key.transition = true; key.prev_state = evt->prev_state(); key.repeat_count = evt->repeat_count(); @@ -43,7 +44,7 @@ WinKeyInputDriver::WinKeyInputDriver(xe::ui::Window* window) auto global_lock = global_critical_region_.Acquire(); KeyEvent key; - key.vkey = evt->key_code(); + key.virtual_key = evt->virtual_key(); key.transition = false; key.prev_state = evt->prev_state(); key.repeat_count = evt->repeat_count(); @@ -241,7 +242,7 @@ X_RESULT WinKeyInputDriver::GetKeystroke(uint32_t user_index, uint32_t flags, X_RESULT result = X_ERROR_EMPTY; - uint16_t virtual_key = 0; + ui::VirtualKey xinput_virtual_key = ui::VirtualKey::kNone; uint16_t unicode = 0; uint16_t keystroke_flags = 0; uint8_t hid_code = 0; @@ -258,100 +259,93 @@ X_RESULT WinKeyInputDriver::GetKeystroke(uint32_t user_index, uint32_t flags, key_events_.pop(); } - // TODO(DrChat): Some other way to toggle this... - if (IS_KEY_TOGGLED(VK_CAPITAL)) { - // dpad toggled - if (evt.vkey == (0x41)) { - // A - virtual_key = 0x5812; // VK_PAD_DPAD_LEFT - } else if (evt.vkey == (0x44)) { - // D - virtual_key = 0x5813; // VK_PAD_DPAD_RIGHT - } else if (evt.vkey == (0x53)) { - // S - virtual_key = 0x5811; // VK_PAD_DPAD_DOWN - } else if (evt.vkey == (0x57)) { - // W - virtual_key = 0x5810; // VK_PAD_DPAD_UP - } - } else { - // left stick - if (evt.vkey == (0x57)) { - // W - virtual_key = 0x5820; // VK_PAD_LTHUMB_UP - } - if (evt.vkey == (0x53)) { - // S - virtual_key = 0x5821; // VK_PAD_LTHUMB_DOWN - } - if (evt.vkey == (0x44)) { - // D - virtual_key = 0x5822; // VK_PAD_LTHUMB_RIGHT - } - if (evt.vkey == (0x41)) { - // A - virtual_key = 0x5823; // VK_PAD_LTHUMB_LEFT - } + switch (evt.virtual_key) { + case ui::VirtualKey::kOem1: // ; + xinput_virtual_key = ui::VirtualKey::kXInputPadA; + break; + case ui::VirtualKey::kOem7: // ' + xinput_virtual_key = ui::VirtualKey::kXInputPadB; + break; + case ui::VirtualKey::kL: + xinput_virtual_key = ui::VirtualKey::kXInputPadX; + break; + case ui::VirtualKey::kP: + xinput_virtual_key = ui::VirtualKey::kXInputPadY; + break; + case ui::VirtualKey::k3: + xinput_virtual_key = ui::VirtualKey::kXInputPadRShoulder; + break; + case ui::VirtualKey::k1: + xinput_virtual_key = ui::VirtualKey::kXInputPadLShoulder; + break; + case ui::VirtualKey::kQ: + case ui::VirtualKey::kI: + xinput_virtual_key = ui::VirtualKey::kXInputPadLTrigger; + break; + case ui::VirtualKey::kE: + case ui::VirtualKey::kO: + xinput_virtual_key = ui::VirtualKey::kXInputPadRTrigger; + break; + case ui::VirtualKey::kX: + xinput_virtual_key = ui::VirtualKey::kXInputPadStart; + break; + case ui::VirtualKey::kZ: + xinput_virtual_key = ui::VirtualKey::kXInputPadBack; + break; + case ui::VirtualKey::kUp: + xinput_virtual_key = ui::VirtualKey::kXInputPadRThumbUp; + break; + case ui::VirtualKey::kDown: + xinput_virtual_key = ui::VirtualKey::kXInputPadRThumbDown; + break; + case ui::VirtualKey::kRight: + xinput_virtual_key = ui::VirtualKey::kXInputPadRThumbRight; + break; + case ui::VirtualKey::kLeft: + xinput_virtual_key = ui::VirtualKey::kXInputPadRThumbLeft; + break; + default: + // TODO(DrChat): Some other way to toggle this... + if (IS_KEY_TOGGLED(VK_CAPITAL) || IS_KEY_DOWN(VK_SHIFT)) { + // D-pad toggled. + switch (evt.virtual_key) { + case ui::VirtualKey::kW: + xinput_virtual_key = ui::VirtualKey::kXInputPadDpadUp; + break; + case ui::VirtualKey::kS: + xinput_virtual_key = ui::VirtualKey::kXInputPadDpadDown; + break; + case ui::VirtualKey::kA: + xinput_virtual_key = ui::VirtualKey::kXInputPadDpadLeft; + break; + case ui::VirtualKey::kD: + xinput_virtual_key = ui::VirtualKey::kXInputPadDpadRight; + break; + default: + break; + } + } else { + // Left thumbstick. + switch (evt.virtual_key) { + case ui::VirtualKey::kW: + xinput_virtual_key = ui::VirtualKey::kXInputPadLThumbUp; + break; + case ui::VirtualKey::kS: + xinput_virtual_key = ui::VirtualKey::kXInputPadLThumbDown; + break; + case ui::VirtualKey::kA: + xinput_virtual_key = ui::VirtualKey::kXInputPadLThumbLeft; + break; + case ui::VirtualKey::kD: + xinput_virtual_key = ui::VirtualKey::kXInputPadLThumbRight; + break; + default: + break; + } + } } - // Right stick - if (evt.vkey == (0x26)) { - // Up - virtual_key = 0x5830; - } - if (evt.vkey == (0x28)) { - // Down - virtual_key = 0x5831; - } - if (evt.vkey == (0x27)) { - // Right - virtual_key = 0x5832; - } - if (evt.vkey == (0x25)) { - // Left - virtual_key = 0x5833; - } - - if (evt.vkey == (0x4C)) { - // L - virtual_key = 0x5802; // VK_PAD_X - } else if (evt.vkey == (VK_OEM_7)) { - // ' - virtual_key = 0x5801; // VK_PAD_B - } else if (evt.vkey == (VK_OEM_1)) { - // ; - virtual_key = 0x5800; // VK_PAD_A - } else if (evt.vkey == (0x50)) { - // P - virtual_key = 0x5803; // VK_PAD_Y - } - - if (evt.vkey == (0x58)) { - // X - virtual_key = 0x5814; // VK_PAD_START - } - if (evt.vkey == (0x5A)) { - // Z - virtual_key = 0x5815; // VK_PAD_BACK - } - if (evt.vkey == (0x51) || evt.vkey == (0x49)) { - // Q / I - virtual_key = 0x5806; // VK_PAD_LTRIGGER - } - if (evt.vkey == (0x45) || evt.vkey == (0x4F)) { - // E / O - virtual_key = 0x5807; // VK_PAD_RTRIGGER - } - if (evt.vkey == (0x31)) { - // 1 - virtual_key = 0x5805; // VK_PAD_LSHOULDER - } - if (evt.vkey == (0x33)) { - // 3 - virtual_key = 0x5804; // VK_PAD_RSHOULDER - } - - if (virtual_key != 0) { + if (xinput_virtual_key != ui::VirtualKey::kNone) { if (evt.transition == true) { keystroke_flags |= 0x0001; // XINPUT_KEYSTROKE_KEYDOWN } else if (evt.transition == false) { @@ -365,7 +359,7 @@ X_RESULT WinKeyInputDriver::GetKeystroke(uint32_t user_index, uint32_t flags, result = X_ERROR_SUCCESS; } - out_keystroke->virtual_key = virtual_key; + out_keystroke->virtual_key = uint16_t(xinput_virtual_key); out_keystroke->unicode = unicode; out_keystroke->flags = keystroke_flags; out_keystroke->user_index = 0; diff --git a/src/xenia/hid/winkey/winkey_input_driver.h b/src/xenia/hid/winkey/winkey_input_driver.h index 2bc923f39..f015b7416 100644 --- a/src/xenia/hid/winkey/winkey_input_driver.h +++ b/src/xenia/hid/winkey/winkey_input_driver.h @@ -14,6 +14,7 @@ #include "xenia/base/mutex.h" #include "xenia/hid/input_driver.h" +#include "xenia/ui/virtual_key.h" namespace xe { namespace hid { @@ -35,7 +36,7 @@ class WinKeyInputDriver : public InputDriver { protected: struct KeyEvent { - int vkey = 0; + ui::VirtualKey virtual_key = ui::VirtualKey::kNone; int repeat_count = 0; bool transition = false; // going up(false) or going down(true) bool prev_state = false; // down(true) or up(false) diff --git a/src/xenia/ui/imgui_drawer.cc b/src/xenia/ui/imgui_drawer.cc index 158c9248a..276cea114 100644 --- a/src/xenia/ui/imgui_drawer.cc +++ b/src/xenia/ui/imgui_drawer.cc @@ -12,6 +12,7 @@ #include "third_party/imgui/imgui.h" #include "xenia/base/assert.h" #include "xenia/base/logging.h" +#include "xenia/base/math.h" #include "xenia/ui/window.h" namespace xe { @@ -107,23 +108,23 @@ void ImGuiDrawer::Initialize() { style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 1.00f, 0.00f, 0.21f); style.Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); - io.KeyMap[ImGuiKey_Tab] = 0x09; // VK_TAB; - io.KeyMap[ImGuiKey_LeftArrow] = 0x25; - io.KeyMap[ImGuiKey_RightArrow] = 0x27; - io.KeyMap[ImGuiKey_UpArrow] = 0x26; - io.KeyMap[ImGuiKey_DownArrow] = 0x28; - io.KeyMap[ImGuiKey_Home] = 0x24; - io.KeyMap[ImGuiKey_End] = 0x23; - io.KeyMap[ImGuiKey_Delete] = 0x2E; - io.KeyMap[ImGuiKey_Backspace] = 0x08; - io.KeyMap[ImGuiKey_Enter] = 0x0D; - io.KeyMap[ImGuiKey_Escape] = 0x1B; - io.KeyMap[ImGuiKey_A] = 'A'; - io.KeyMap[ImGuiKey_C] = 'C'; - io.KeyMap[ImGuiKey_V] = 'V'; - io.KeyMap[ImGuiKey_X] = 'X'; - io.KeyMap[ImGuiKey_Y] = 'Y'; - io.KeyMap[ImGuiKey_Z] = 'Z'; + io.KeyMap[ImGuiKey_Tab] = int(ui::VirtualKey::kTab); + io.KeyMap[ImGuiKey_LeftArrow] = int(ui::VirtualKey::kLeft); + io.KeyMap[ImGuiKey_RightArrow] = int(ui::VirtualKey::kRight); + io.KeyMap[ImGuiKey_UpArrow] = int(ui::VirtualKey::kUp); + io.KeyMap[ImGuiKey_DownArrow] = int(ui::VirtualKey::kDown); + io.KeyMap[ImGuiKey_Home] = int(ui::VirtualKey::kHome); + io.KeyMap[ImGuiKey_End] = int(ui::VirtualKey::kEnd); + io.KeyMap[ImGuiKey_Delete] = int(ui::VirtualKey::kDelete); + io.KeyMap[ImGuiKey_Backspace] = int(ui::VirtualKey::kBack); + io.KeyMap[ImGuiKey_Enter] = int(ui::VirtualKey::kReturn); + io.KeyMap[ImGuiKey_Escape] = int(ui::VirtualKey::kEscape); + io.KeyMap[ImGuiKey_A] = int(ui::VirtualKey::kA); + io.KeyMap[ImGuiKey_C] = int(ui::VirtualKey::kC); + io.KeyMap[ImGuiKey_V] = int(ui::VirtualKey::kV); + io.KeyMap[ImGuiKey_X] = int(ui::VirtualKey::kX); + io.KeyMap[ImGuiKey_Y] = int(ui::VirtualKey::kY); + io.KeyMap[ImGuiKey_Z] = int(ui::VirtualKey::kZ); } void ImGuiDrawer::SetupFont() { @@ -228,36 +229,16 @@ void ImGuiDrawer::RenderDrawLists() { } } -void ImGuiDrawer::OnKeyDown(KeyEvent* e) { - auto& io = GetIO(); - io.KeysDown[e->key_code()] = true; - switch (e->key_code()) { - case 16: { - io.KeyShift = true; - } break; - case 17: { - io.KeyCtrl = true; - } break; - } -} +void ImGuiDrawer::OnKeyDown(KeyEvent* e) { OnKey(e, true); } -void ImGuiDrawer::OnKeyUp(KeyEvent* e) { - auto& io = GetIO(); - io.KeysDown[e->key_code()] = false; - switch (e->key_code()) { - case 16: { - io.KeyShift = false; - } break; - case 17: { - io.KeyCtrl = false; - } break; - } -} +void ImGuiDrawer::OnKeyUp(KeyEvent* e) { OnKey(e, false); } void ImGuiDrawer::OnKeyChar(KeyEvent* e) { auto& io = GetIO(); - if (e->key_code() > 0 && e->key_code() < 0x10000) { - io.AddInputCharacter(e->key_code()); + // TODO(Triang3l): Accept the Unicode character. + unsigned int character = static_cast(e->virtual_key()); + if (character > 0 && character < 0x10000) { + io.AddInputCharacter(character); e->set_handled(true); } } @@ -327,5 +308,30 @@ void ImGuiDrawer::OnMouseWheel(MouseEvent* e) { io.MouseWheel += float(e->dy() / 120.0f); } +void ImGuiDrawer::OnKey(KeyEvent* e, bool is_down) { + auto& io = GetIO(); + VirtualKey virtual_key = e->virtual_key(); + if (size_t(virtual_key) < xe::countof(io.KeysDown)) { + io.KeysDown[size_t(virtual_key)] = is_down; + } + switch (virtual_key) { + case VirtualKey::kShift: + io.KeyShift = is_down; + break; + case VirtualKey::kControl: + io.KeyCtrl = is_down; + break; + case VirtualKey::kMenu: + // FIXME(Triang3l): Doesn't work in xenia-ui-window-demo. + io.KeyAlt = is_down; + break; + case VirtualKey::kLWin: + io.KeySuper = is_down; + break; + default: + break; + } +} + } // namespace ui } // namespace xe diff --git a/src/xenia/ui/imgui_drawer.h b/src/xenia/ui/imgui_drawer.h index 7163e7a1a..2c370b2aa 100644 --- a/src/xenia/ui/imgui_drawer.h +++ b/src/xenia/ui/imgui_drawer.h @@ -57,6 +57,9 @@ class ImGuiDrawer : public WindowListener { ImGuiContext* internal_state_ = nullptr; std::unique_ptr font_texture_; + + private: + void OnKey(KeyEvent* e, bool is_down); }; } // namespace ui diff --git a/src/xenia/ui/ui_event.h b/src/xenia/ui/ui_event.h index 9fd4734ba..993eda672 100644 --- a/src/xenia/ui/ui_event.h +++ b/src/xenia/ui/ui_event.h @@ -12,6 +12,8 @@ #include +#include "xenia/ui/virtual_key.h" + namespace xe { namespace ui { @@ -42,11 +44,12 @@ class FileDropEvent : public UIEvent { class KeyEvent : public UIEvent { public: - KeyEvent(Window* target, int key_code, int repeat_count, bool prev_state, - bool modifier_shift_pressed, bool modifier_ctrl_pressed, - bool modifier_alt_pressed, bool modifier_super_pressed) + KeyEvent(Window* target, VirtualKey virtual_key, int repeat_count, + bool prev_state, bool modifier_shift_pressed, + bool modifier_ctrl_pressed, bool modifier_alt_pressed, + bool modifier_super_pressed) : UIEvent(target), - key_code_(key_code), + virtual_key_(virtual_key), repeat_count_(repeat_count), prev_state_(prev_state), modifier_shift_pressed_(modifier_shift_pressed), @@ -58,7 +61,7 @@ class KeyEvent : public UIEvent { bool is_handled() const { return handled_; } void set_handled(bool value) { handled_ = value; } - int key_code() const { return key_code_; } + VirtualKey virtual_key() const { return virtual_key_; } int repeat_count() const { return repeat_count_; } bool prev_state() const { return prev_state_; } @@ -70,7 +73,7 @@ class KeyEvent : public UIEvent { private: bool handled_ = false; - int key_code_ = 0; + VirtualKey virtual_key_ = VirtualKey::kNone; int repeat_count_ = 0; bool prev_state_ = false; // Key previously down(true) or up(false) diff --git a/src/xenia/ui/virtual_key.h b/src/xenia/ui/virtual_key.h new file mode 100644 index 000000000..8bda0667a --- /dev/null +++ b/src/xenia/ui/virtual_key.h @@ -0,0 +1,362 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2021 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_UI_VIRTUAL_KEY_H_ +#define XENIA_UI_VIRTUAL_KEY_H_ + +#include + +namespace xe { +namespace ui { + +// Windows and Xbox 360 / XInput virtual key enumeration. +// This is what platform-specific keys should be translated to, for both HID +// keystroke emulation and Xenia-internal UI events. On Windows, the translation +// is a simple cast. +// This is uint16_t as it's WPARAM (which was 16-bit back in Win16 days, where +// virtual key codes were added), and XINPUT_KEYSTROKE stores the virtual key as +// a WORD. In some cases (see kPacket), bits above 16 may be used as well, but +// VK_ on Windows are defined up to 0xFF (0xFE not counting the reserved 0xFF) +// as of Windows SDK 10.0.19041.0, and XInput virtual key codes are 16-bit. +// Base virtual key codes as of _WIN32_WINNT 0x0500 (Windows 2000, which the +// Xbox 360's kernel is based on), virtual key codes added later are marked +// explicitly as such. +enum class VirtualKey : uint16_t { + // Not a valid key - MapVirtualKey returns zero when there is no translation. + kNone, + + kLButton = 0x01, + kRButton = 0x02, + kCancel = 0x03, // Control-break. + kMButton = 0x04, // Not contiguous with kLButton and kRButton. + + kXButton1 = 0x05, // Not contiguous with kLButton and kRButton. + kXButton2 = 0x06, // Not contiguous with kLButton and kRButton. + + kBack = 0x08, // Backspace. + kTab = 0x09, + + kClear = 0x0C, + kReturn = 0x0D, // Enter. + + kShift = 0x10, + kControl = 0x11, // Ctrl. + kMenu = 0x12, // Alt. + kPause = 0x13, + kCapital = 0x14, // Caps Lock. + + kKana = 0x15, + kHangeul = 0x15, // Old name. + kHangul = 0x15, + kImeOn = 0x16, + kJunja = 0x17, + kFinal = 0x18, + kHanja = 0x19, + kKanji = 0x19, + kImeOff = 0x1A, + + kEscape = 0x1B, + + kConvert = 0x1C, + kNonConvert = 0x1D, + kAccept = 0x1E, + kModeChange = 0x1F, + + kSpace = 0x20, + kPrior = 0x21, // Page Up. + kNext = 0x22, // Page Down. + kEnd = 0x23, + kHome = 0x24, + kLeft = 0x25, + kUp = 0x26, + kRight = 0x27, + kDown = 0x28, + kSelect = 0x29, + kPrint = 0x2A, + kExecute = 0x2B, + kSnapshot = 0x2C, + kInsert = 0x2D, + kDelete = 0x2E, + kHelp = 0x2F, + + // Same as ASCII '0' - '9'. + k0 = 0x30, + k1 = 0x31, + k2 = 0x32, + k3 = 0x33, + k4 = 0x34, + k5 = 0x35, + k6 = 0x36, + k7 = 0x37, + k8 = 0x38, + k9 = 0x39, + + // Same as ASCII 'A' - 'Z'. + kA = 0x41, + kB = 0x42, + kC = 0x43, + kD = 0x44, + kE = 0x45, + kF = 0x46, + kG = 0x47, + kH = 0x48, + kI = 0x49, + kJ = 0x4A, + kK = 0x4B, + kL = 0x4C, + kM = 0x4D, + kN = 0x4E, + kO = 0x4F, + kP = 0x50, + kQ = 0x51, + kR = 0x52, + kS = 0x53, + kT = 0x54, + kU = 0x55, + kV = 0x56, + kW = 0x57, + kX = 0x58, + kY = 0x59, + kZ = 0x5A, + + kLWin = 0x5B, + kRWin = 0x5C, + kApps = 0x5D, + + kSleep = 0x5F, + + kNumpad0 = 0x60, + kNumpad1 = 0x61, + kNumpad2 = 0x62, + kNumpad3 = 0x63, + kNumpad4 = 0x64, + kNumpad5 = 0x65, + kNumpad6 = 0x66, + kNumpad7 = 0x67, + kNumpad8 = 0x68, + kNumpad9 = 0x69, + kMultiply = 0x6A, + kAdd = 0x6B, + kSeparator = 0x6C, + kSubtract = 0x6D, + kDecimal = 0x6E, + kDivide = 0x6F, + kF1 = 0x70, + kF2 = 0x71, + kF3 = 0x72, + kF4 = 0x73, + kF5 = 0x74, + kF6 = 0x75, + kF7 = 0x76, + kF8 = 0x77, + kF9 = 0x78, + kF10 = 0x79, + kF11 = 0x7A, + kF12 = 0x7B, + kF13 = 0x7C, + kF14 = 0x7D, + kF15 = 0x7E, + kF16 = 0x7F, + kF17 = 0x80, + kF18 = 0x81, + kF19 = 0x82, + kF20 = 0x83, + kF21 = 0x84, + kF22 = 0x85, + kF23 = 0x86, + kF24 = 0x87, + + // VK_NAVIGATION_* added in _WIN32_WINNT 0x0604, but marked as reserved in + // WinUser.h and not documented on MSDN. + kNavigationView = 0x88, + kNavigationMenu = 0x89, + kNavigationUp = 0x8A, + kNavigationDown = 0x8B, + kNavigationLeft = 0x8C, + kNavigationRight = 0x8D, + kNavigationAccept = 0x8E, + kNavigationCancel = 0x8F, + + kNumLock = 0x90, + kScroll = 0x91, + + // NEC PC-9800 keyboard. + kOemNecEqual = 0x92, // '=' key on the numpad. + + // Fujitsu/OASYS keyboard. + kOemFjJisho = 0x92, // 'Dictionary' key. + kOemFjMasshou = 0x93, // 'Unregister word' key. + kOemFjTouroku = 0x94, // 'Register word' key. + kOemFjLOya = 0x95, // 'Left OYAYUBI' key. + kOemFjROya = 0x96, // 'Right OYAYUBI' key. + + // Left and right Alt, Ctrl and Shift virtual keys. + // On Windows (from WinUser.h): + // "Used only as parameters to GetAsyncKeyState() and GetKeyState(). + // No other API or message will distinguish left and right keys in this way." + kLShift = 0xA0, + kRShift = 0xA1, + kLControl = 0xA2, + kRControl = 0xA3, + kLMenu = 0xA4, + kRMenu = 0xA5, + + kBrowserBack = 0xA6, + kBrowserForward = 0xA7, + kBrowserRefresh = 0xA8, + kBrowserStop = 0xA9, + kBrowserSearch = 0xAA, + kBrowserFavorites = 0xAB, + kBrowserHome = 0xAC, + + kVolumeMute = 0xAD, + kVolumeDown = 0xAE, + kVolumeUp = 0xAF, + kMediaNextTrack = 0xB0, + kMediaPrevTrack = 0xB1, + kMediaStop = 0xB2, + kMediaPlayPause = 0xB3, + kLaunchMail = 0xB4, + kLaunchMediaSelect = 0xB5, + kLaunchApp1 = 0xB6, + kLaunchApp2 = 0xB7, + + kOem1 = 0xBA, // ';:' for the US. + kOemPlus = 0xBB, // '+' for any country. + kOemComma = 0xBC, // ',' for any country. + kOemMinus = 0xBD, // '-' for any country. + kOemPeriod = 0xBE, // '.' for any country. + kOem2 = 0xBF, // '/?' for the US. + kOem3 = 0xC0, // '`~' for the US. + + // VK_GAMEPAD_* (since _WIN32_WINNT 0x0604) virtual key codes are marked as + // reserved in WinUser.h and are mostly not documented on MSDN (with the + // exception of the Xbox Device Portal Remote Input REST API in the "UWP on + // Xbox One" section). + // Xenia uses VK_PAD_* (kXInputPad*) for HID emulation internally instead + // because XInput is the API used for the Xbox 360 controller. + // To avoid confusion between VK_GAMEPAD_* and VK_PAD_*, here they are + // prefixed with kXboxOne and kXInput respectively. + kXboxOneGamepadA = 0xC3, + kXboxOneGamepadB = 0xC4, + kXboxOneGamepadX = 0xC5, + kXboxOneGamepadY = 0xC6, + kXboxOneGamepadRightShoulder = 0xC7, + kXboxOneGamepadLeftShoulder = 0xC8, + kXboxOneGamepadLeftTrigger = 0xC9, + kXboxOneGamepadRightTrigger = 0xCA, + kXboxOneGamepadDpadUp = 0xCB, + kXboxOneGamepadDpadDown = 0xCC, + kXboxOneGamepadDpadLeft = 0xCD, + kXboxOneGamepadDpadRight = 0xCE, + kXboxOneGamepadMenu = 0xCF, + kXboxOneGamepadView = 0xD0, + kXboxOneGamepadLeftThumbstickButton = 0xD1, + kXboxOneGamepadRightThumbstickButton = 0xD2, + kXboxOneGamepadLeftThumbstickUp = 0xD3, + kXboxOneGamepadLeftThumbstickDown = 0xD4, + kXboxOneGamepadLeftThumbstickRight = 0xD5, + kXboxOneGamepadLeftThumbstickLeft = 0xD6, + kXboxOneGamepadRightThumbstickUp = 0xD7, + kXboxOneGamepadRightThumbstickDown = 0xD8, + kXboxOneGamepadRightThumbstickRight = 0xD9, + kXboxOneGamepadRightThumbstickLeft = 0xDA, + + kOem4 = 0xDB, // '[{' for the US. + kOem5 = 0xDC, // '\|' for the US. + kOem6 = 0xDD, // ']}' for the US. + kOem7 = 0xDE, // ''"' for the US. + kOem8 = 0xDF, + + kOemAx = 0xE1, // 'AX' key on the Japanese AX keyboard. + kOem102 = 0xE2, // "<>" or "\|" on the RT 102-key keyboard. + kIcoHelp = 0xE3, // Help key on the Olivetti keyboard (ICO). + kIco00 = 0xE4, // 00 key on the ICO. + + kProcessKey = 0xE5, + + kIcoClear = 0xE6, + + // From MSDN: + // "Used to pass Unicode characters as if they were keystrokes. The VK_PACKET + // key is the low word of a 32-bit Virtual Key value used for non-keyboard + // input methods." + kPacket = 0xE7, + + // Nokia/Ericsson. + kOemReset = 0xE9, + kOemJump = 0xEA, + kOemPa1 = 0xEB, + kOemPa2 = 0xEC, + kOemPa3 = 0xED, + kOemWsCtrl = 0xEE, + kOemCuSel = 0xEF, + kOemAttn = 0xF0, + kOemFinish = 0xF1, + kOemCopy = 0xF2, + kOemAuto = 0xF3, + kOemEnlW = 0xF4, + kOemBackTab = 0xF5, + + kAttn = 0xF6, + kCrSel = 0xF7, + kExSel = 0xF8, + kErEof = 0xF9, + kPlay = 0xFA, + kZoom = 0xFB, + kNoName = 0xFC, + kPa1 = 0xFD, + kOemClear = 0xFE, + + // VK_PAD_* from XInput.h for XInputGetKeystroke. kXInput prefix added to + // distinguish from VK_GAMEPAD_*, added much later for the Xbox One + // controller. + + kXInputPadA = 0x5800, + kXInputPadB = 0x5801, + kXInputPadX = 0x5802, + kXInputPadY = 0x5803, + // RShoulder before LShoulder, not a typo. + kXInputPadRShoulder = 0x5804, + kXInputPadLShoulder = 0x5805, + kXInputPadLTrigger = 0x5806, + kXInputPadRTrigger = 0x5807, + + kXInputPadDpadUp = 0x5810, + kXInputPadDpadDown = 0x5811, + kXInputPadDpadLeft = 0x5812, + kXInputPadDpadRight = 0x5813, + kXInputPadStart = 0x5814, + kXInputPadBack = 0x5815, + kXInputPadLThumbPress = 0x5816, + kXInputPadRThumbPress = 0x5817, + + kXInputPadLThumbUp = 0x5820, + kXInputPadLThumbDown = 0x5821, + kXInputPadLThumbRight = 0x5822, + kXInputPadLThumbLeft = 0x5823, + kXInputPadLThumbUpLeft = 0x5824, + kXInputPadLThumbUpRight = 0x5825, + kXInputPadLThumbDownRight = 0x5826, + kXInputPadLThumbDownLeft = 0x5827, + + kXInputPadRThumbUp = 0x5830, + kXInputPadRThumbDown = 0x5831, + kXInputPadRThumbRight = 0x5832, + kXInputPadRThumbLeft = 0x5833, + kXInputPadRThumbUpLeft = 0x5834, + kXInputPadRThumbUpRight = 0x5835, + kXInputPadRThumbDownRight = 0x5836, + kXInputPadRThumbDownLeft = 0x5837, +}; + +} // namespace ui +} // namespace xe + +#endif // XENIA_UI_VIRTUAL_KEY_H_ diff --git a/src/xenia/ui/window.cc b/src/xenia/ui/window.cc index 1273b61f0..47a2b874c 100644 --- a/src/xenia/ui/window.cc +++ b/src/xenia/ui/window.cc @@ -259,20 +259,21 @@ void Window::OnLostFocus(UIEvent* e) { void Window::OnKeyPress(KeyEvent* e, bool is_down, bool is_char) { if (!is_char) { - switch (e->key_code()) { - case 16: + switch (e->virtual_key()) { + case VirtualKey::kShift: modifier_shift_pressed_ = is_down; break; - case 17: + case VirtualKey::kControl: modifier_cntrl_pressed_ = is_down; break; - // case xx: - // // alt ?? - // modifier_alt_pressed_ = is_down; - // break; - case 91: + case VirtualKey::kMenu: + modifier_alt_pressed_ = is_down; + break; + case VirtualKey::kLWin: modifier_super_pressed_ = is_down; break; + default: + break; } } } diff --git a/src/xenia/ui/window_demo.cc b/src/xenia/ui/window_demo.cc index a6a05140a..dd191fa7f 100644 --- a/src/xenia/ui/window_demo.cc +++ b/src/xenia/ui/window_demo.cc @@ -18,6 +18,7 @@ #include "xenia/ui/graphics_provider.h" #include "xenia/ui/imgui_dialog.h" #include "xenia/ui/imgui_drawer.h" +#include "xenia/ui/virtual_key.h" #include "xenia/ui/window.h" namespace xe { @@ -92,10 +93,12 @@ int window_demo_main(const std::vector& args) { loop->on_quit.AddListener([&window](xe::ui::UIEvent* e) { window.reset(); }); window->on_key_down.AddListener([](xe::ui::KeyEvent* e) { - switch (e->key_code()) { - case 0x72: { // F3 + switch (e->virtual_key()) { + case VirtualKey::kF3: Profiler::ToggleDisplay(); - } break; + break; + default: + break; } }); diff --git a/src/xenia/ui/window_gtk.cc b/src/xenia/ui/window_gtk.cc index 56248bd2d..9dbeccad5 100644 --- a/src/xenia/ui/window_gtk.cc +++ b/src/xenia/ui/window_gtk.cc @@ -12,6 +12,7 @@ #include "xenia/base/assert.h" #include "xenia/base/logging.h" #include "xenia/base/platform_linux.h" +#include "xenia/ui/virtual_key.h" #include "xenia/ui/window_gtk.h" namespace xe { @@ -350,9 +351,10 @@ bool GTKWindow::HandleKeyboard(GdkEventKey* event) { 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); + // TODO(Triang3l): event->hardware_keycode to VirtualKey translation. + auto e = KeyEvent(this, VirtualKey(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); diff --git a/src/xenia/ui/window_win.cc b/src/xenia/ui/window_win.cc index 954502364..c5bfc780a 100644 --- a/src/xenia/ui/window_win.cc +++ b/src/xenia/ui/window_win.cc @@ -17,6 +17,7 @@ #include "xenia/base/filesystem.h" #include "xenia/base/logging.h" #include "xenia/base/platform_win.h" +#include "xenia/ui/virtual_key.h" namespace xe { namespace ui { @@ -706,7 +707,7 @@ bool Win32Window::HandleMouse(UINT message, WPARAM wParam, LPARAM lParam) { bool Win32Window::HandleKeyboard(UINT message, WPARAM wParam, LPARAM lParam) { auto e = KeyEvent( - this, static_cast(wParam), lParam & 0xFFFF0000, !!(lParam & 0x2), + this, VirtualKey(wParam), lParam & 0xFFFF0000, !!(lParam & 0x2), !!(GetKeyState(VK_SHIFT) & 0x80), !!(GetKeyState(VK_CONTROL) & 0x80), !!(GetKeyState(VK_MENU) & 0x80), !!(GetKeyState(VK_LWIN) & 0x80)); switch (message) { From 458e4e1a316d6e804cf2c19adc204b230ca75fcc Mon Sep 17 00:00:00 2001 From: Triang3l Date: Thu, 1 Jul 2021 23:43:01 +0300 Subject: [PATCH 42/42] [GPU] Official RB name from RDNA/GCN/TeraScale/Xenos docs/news --- src/xenia/gpu/registers.h | 13 +++++++++---- src/xenia/gpu/xenos.h | 8 ++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/xenia/gpu/registers.h b/src/xenia/gpu/registers.h index 9ff038d89..2fc23b2c8 100644 --- a/src/xenia/gpu/registers.h +++ b/src/xenia/gpu/registers.h @@ -507,10 +507,15 @@ union alignas(uint32_t) PA_SC_WINDOW_SCISSOR_BR { static_assert_size(PA_SC_WINDOW_SCISSOR_BR, sizeof(uint32_t)); /******************************************************************************* - ___ ___ - | _ \ _ ) - | / _ \ - |_|_\___/ + ___ ___ _ _ ___ ___ ___ + | _ \ __| \| | \| __| _ \ + | / _|| .` | |) | _|| / + |_|_\___|_|\_|___/|___|_|_\ + + ___ _ ___ _ _____ _ _ ___ + | _ ) /_\ / __| |/ / __| \| | \ + | _ \/ _ \ (__| ' <| _|| .` | |) | + |___/_/ \_\___|_|\_\___|_|\_|___/ *******************************************************************************/ diff --git a/src/xenia/gpu/xenos.h b/src/xenia/gpu/xenos.h index 98fd8741b..d3a202dd6 100644 --- a/src/xenia/gpu/xenos.h +++ b/src/xenia/gpu/xenos.h @@ -194,10 +194,10 @@ enum class SurfaceNumFormat : uint32_t { kFloat = 7, }; -// The EDRAM is an opaque block of memory accessible by the RB pipeline stage of -// the GPU, which performs output-merger functionality (color render target -// writing and blending, depth and stencil testing) and resolve (copy) -// operations. +// The EDRAM is an opaque block of memory accessible by the RB (render backend) +// pipeline stage of the GPU, which performs output-merger functionality (color +// render target writing and blending, depth and stencil testing) and resolve +// (copy) operations. // // Data in the 10 MiB of EDRAM is laid out as 2048 tiles on 80x16 32bpp MSAA // samples. With 2x MSAA, one pixel consists of 1x2 samples, and with 4x, it