Merge branch 'master' into vulkan
This commit is contained in:
commit
9bb104b354
|
@ -8,6 +8,7 @@ skip_tags: true
|
||||||
|
|
||||||
skip_commits:
|
skip_commits:
|
||||||
files:
|
files:
|
||||||
|
- .drone.yml
|
||||||
- .github/**
|
- .github/**
|
||||||
- .travis.yml
|
- .travis.yml
|
||||||
- docs/**
|
- docs/**
|
||||||
|
|
|
@ -0,0 +1,214 @@
|
||||||
|
---
|
||||||
|
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:
|
||||||
|
- clang-format --version
|
||||||
|
- ./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
|
73
.travis.yml
73
.travis.yml
|
@ -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
|
|
|
@ -24,7 +24,7 @@ Discussing illegal activities will get you banned.
|
||||||
Buildbot | Status
|
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)
|
[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.
|
Quite a few real games run. Quite a few don't.
|
||||||
See the [Game compatibility list](https://github.com/xenia-project/game-compatibility/issues)
|
See the [Game compatibility list](https://github.com/xenia-project/game-compatibility/issues)
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "xenia/ui/file_picker.h"
|
#include "xenia/ui/file_picker.h"
|
||||||
#include "xenia/ui/imgui_dialog.h"
|
#include "xenia/ui/imgui_dialog.h"
|
||||||
#include "xenia/ui/imgui_drawer.h"
|
#include "xenia/ui/imgui_drawer.h"
|
||||||
|
#include "xenia/ui/virtual_key.h"
|
||||||
|
|
||||||
// Autogenerated by `xb premake`.
|
// Autogenerated by `xb premake`.
|
||||||
#include "build/version.h"
|
#include "build/version.h"
|
||||||
|
@ -93,49 +94,49 @@ bool EmulatorWindow::Initialize() {
|
||||||
|
|
||||||
window_->on_key_down.AddListener([this](KeyEvent* e) {
|
window_->on_key_down.AddListener([this](KeyEvent* e) {
|
||||||
bool handled = true;
|
bool handled = true;
|
||||||
switch (e->key_code()) {
|
switch (e->virtual_key()) {
|
||||||
case 0x4F: { // o
|
case ui::VirtualKey::kO: {
|
||||||
if (e->is_ctrl_pressed()) {
|
if (e->is_ctrl_pressed()) {
|
||||||
FileOpen();
|
FileOpen();
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case 0x6A: { // numpad *
|
case ui::VirtualKey::kMultiply: {
|
||||||
CpuTimeScalarReset();
|
CpuTimeScalarReset();
|
||||||
} break;
|
} break;
|
||||||
case 0x6D: { // numpad minus
|
case ui::VirtualKey::kSubtract: {
|
||||||
CpuTimeScalarSetHalf();
|
CpuTimeScalarSetHalf();
|
||||||
} break;
|
} break;
|
||||||
case 0x6B: { // numpad plus
|
case ui::VirtualKey::kAdd: {
|
||||||
CpuTimeScalarSetDouble();
|
CpuTimeScalarSetDouble();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case 0x72: { // F3
|
case ui::VirtualKey::kF3: {
|
||||||
Profiler::ToggleDisplay();
|
Profiler::ToggleDisplay();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case 0x73: { // VK_F4
|
case ui::VirtualKey::kF4: {
|
||||||
GpuTraceFrame();
|
GpuTraceFrame();
|
||||||
} break;
|
} break;
|
||||||
case 0x74: { // VK_F5
|
case ui::VirtualKey::kF5: {
|
||||||
GpuClearCaches();
|
GpuClearCaches();
|
||||||
} break;
|
} break;
|
||||||
case 0x76: { // VK_F7
|
case ui::VirtualKey::kF7: {
|
||||||
// Save to file
|
// Save to file
|
||||||
// TODO: Choose path based on user input, or from options
|
// TODO: Choose path based on user input, or from options
|
||||||
// TODO: Spawn a new thread to do this.
|
// TODO: Spawn a new thread to do this.
|
||||||
emulator()->SaveToFile("test.sav");
|
emulator()->SaveToFile("test.sav");
|
||||||
} break;
|
} break;
|
||||||
case 0x77: { // VK_F8
|
case ui::VirtualKey::kF8: {
|
||||||
// Restore from file
|
// Restore from file
|
||||||
// TODO: Choose path from user
|
// TODO: Choose path from user
|
||||||
// TODO: Spawn a new thread to do this.
|
// TODO: Spawn a new thread to do this.
|
||||||
emulator()->RestoreFromFile("test.sav");
|
emulator()->RestoreFromFile("test.sav");
|
||||||
} break;
|
} break;
|
||||||
case 0x7A: { // VK_F11
|
case ui::VirtualKey::kF11: {
|
||||||
ToggleFullscreen();
|
ToggleFullscreen();
|
||||||
} break;
|
} break;
|
||||||
case 0x1B: { // VK_ESCAPE
|
case ui::VirtualKey::kEscape: {
|
||||||
// Allow users to escape fullscreen (but not enter it).
|
// Allow users to escape fullscreen (but not enter it).
|
||||||
if (window_->is_fullscreen()) {
|
if (window_->is_fullscreen()) {
|
||||||
window_->ToggleFullscreen(false);
|
window_->ToggleFullscreen(false);
|
||||||
} else {
|
} else {
|
||||||
|
@ -143,18 +144,18 @@ bool EmulatorWindow::Initialize() {
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case 0x13: { // VK_PAUSE
|
case ui::VirtualKey::kPause: {
|
||||||
CpuBreakIntoDebugger();
|
CpuBreakIntoDebugger();
|
||||||
} break;
|
} break;
|
||||||
case 0x03: { // VK_CANCEL
|
case ui::VirtualKey::kCancel: {
|
||||||
CpuBreakIntoHostDebugger();
|
CpuBreakIntoHostDebugger();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case 0x70: { // VK_F1
|
case ui::VirtualKey::kF1: {
|
||||||
ShowHelpWebsite();
|
ShowHelpWebsite();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case 0x71: { // VK_F2
|
case ui::VirtualKey::kF2: {
|
||||||
ShowCommitID();
|
ShowCommitID();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,7 @@ X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) {
|
||||||
sizeof(XMA_CONTEXT_DATA) * kContextCount, 256, kSystemHeapPhysical);
|
sizeof(XMA_CONTEXT_DATA) * kContextCount, 256, kSystemHeapPhysical);
|
||||||
context_data_last_ptr_ =
|
context_data_last_ptr_ =
|
||||||
context_data_first_ptr_ + (sizeof(XMA_CONTEXT_DATA) * kContextCount - 1);
|
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_);
|
memory()->GetPhysicalAddress(context_data_first_ptr_);
|
||||||
|
|
||||||
// Setup XMA contexts.
|
// Setup XMA contexts.
|
||||||
|
@ -134,7 +134,7 @@ X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) {
|
||||||
assert_always();
|
assert_always();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
register_file_[XE_XMA_REG_NEXT_CONTEXT_INDEX].u32 = 1;
|
register_file_[XmaRegister::NextContextIndex] = 1;
|
||||||
context_bitmap_.Resize(kContextCount);
|
context_bitmap_.Resize(kContextCount);
|
||||||
|
|
||||||
worker_running_ = true;
|
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 XmaDecoder::ReadRegister(uint32_t addr) {
|
||||||
uint32_t r = (addr & 0xFFFF) / 4;
|
auto r = (addr & 0xFFFF) / 4;
|
||||||
|
|
||||||
assert_true(r < XmaRegisterFile::kRegisterCount);
|
assert_true(r < XmaRegisterFile::kRegisterCount);
|
||||||
|
|
||||||
switch (r) {
|
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
|
// 0606h (1818h) is rotating context processing # set to hardware ID of
|
||||||
// context being processed.
|
// context being processed.
|
||||||
// If bit 200h is set, the locking code will possibly collide on hardware
|
// 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?).
|
// IDs and error out, so we should never set it (I think?).
|
||||||
uint32_t& current_context_index =
|
uint32_t& current_context_index =
|
||||||
register_file_[XE_XMA_REG_CURRENT_CONTEXT_INDEX].u32;
|
register_file_[XmaRegister::CurrentContextIndex];
|
||||||
uint32_t& next_context_index =
|
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
|
// To prevent games from seeing a stuck XMA context, return a rotating
|
||||||
// number.
|
// number.
|
||||||
current_context_index = next_context_index;
|
current_context_index = next_context_index;
|
||||||
next_context_index = (next_context_index + 1) % kContextCount;
|
next_context_index = (next_context_index + 1) % kContextCount;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default:
|
||||||
const auto register_info = register_file_.GetRegisterInfo(r);
|
const auto register_info = register_file_.GetRegisterInfo(r);
|
||||||
if (register_info) {
|
if (register_info) {
|
||||||
XELOGW("XMA: Read from unhandled register ({:04X}, {})", r,
|
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);
|
XELOGW("XMA: Read from unknown register ({:04X})", r);
|
||||||
}
|
}
|
||||||
break;
|
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) {
|
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);
|
value = xe::byte_swap(value);
|
||||||
|
|
||||||
assert_true(r < XmaRegisterFile::kRegisterCount);
|
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.
|
// Context kick command.
|
||||||
// This will kick off the given hardware contexts.
|
// This will kick off the given hardware contexts.
|
||||||
// Basically, this kicks the SPU and says "hey, decode that audio!"
|
// Basically, this kicks the SPU and says "hey, decode that audio!"
|
||||||
// XMAEnableContext
|
// XMAEnableContext
|
||||||
|
|
||||||
// The context ID is a bit in the range of the entire context array.
|
// 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) {
|
for (int i = 0; value && i < 32; ++i, value >>= 1) {
|
||||||
if (value & 1) {
|
if (value & 1) {
|
||||||
uint32_t context_id = base_context_id + i;
|
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.
|
// Signal the decoder thread to start processing.
|
||||||
work_event_->Set();
|
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.
|
// Context lock command.
|
||||||
// This requests a lock by flagging the context.
|
// This requests a lock by flagging the context.
|
||||||
// XMADisableContext
|
// 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) {
|
for (int i = 0; value && i < 32; ++i, value >>= 1) {
|
||||||
if (value & 1) {
|
if (value & 1) {
|
||||||
uint32_t context_id = base_context_id + i;
|
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.
|
// Signal the decoder thread to start processing.
|
||||||
work_event_->Set();
|
// work_event_->Set();
|
||||||
} else if (r >= XE_XMA_REG_CONTEXT_CLEAR_0 &&
|
} else if (r >= XmaRegister::Context0Clear &&
|
||||||
r <= XE_XMA_REG_CONTEXT_CLEAR_9) {
|
r <= XmaRegister::Context9Clear) {
|
||||||
// Context clear command.
|
// Context clear command.
|
||||||
// This will reset the given hardware contexts.
|
// 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) {
|
for (int i = 0; value && i < 32; ++i, value >>= 1) {
|
||||||
if (value & 1) {
|
if (value & 1) {
|
||||||
uint32_t context_id = base_context_id + i;
|
uint32_t context_id = base_context_id + i;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* 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. *
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
@ -37,7 +37,7 @@ class XmaDecoder {
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
uint32_t context_array_ptr() const {
|
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();
|
uint32_t AllocateContext();
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* 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. *
|
* 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) {
|
const XmaRegisterInfo* XmaRegisterFile::GetRegisterInfo(uint32_t index) {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
#define XE_XMA_REGISTER(index, type, name) \
|
#define XE_XMA_REGISTER(index, name) \
|
||||||
case index: { \
|
case index: { \
|
||||||
static const XmaRegisterInfo reg_info = { \
|
static const XmaRegisterInfo reg_info = { \
|
||||||
XmaRegisterInfo::Type::type, \
|
|
||||||
#name, \
|
#name, \
|
||||||
}; \
|
}; \
|
||||||
return ®_info; \
|
return ®_info; \
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* 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. *
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
@ -16,18 +16,13 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace apu {
|
namespace apu {
|
||||||
|
|
||||||
enum XmaRegister {
|
struct XmaRegister {
|
||||||
#define XE_XMA_REGISTER(index, type, name) XE_XMA_REG_##name = index,
|
#define XE_XMA_REGISTER(index, name) static const uint32_t name = index;
|
||||||
#include "xenia/apu/xma_register_table.inc"
|
#include "xenia/apu/xma_register_table.inc"
|
||||||
#undef XE_XMA_REGISTER
|
#undef XE_XMA_REGISTER
|
||||||
};
|
};
|
||||||
|
|
||||||
struct XmaRegisterInfo {
|
struct XmaRegisterInfo {
|
||||||
enum class Type {
|
|
||||||
kDword,
|
|
||||||
kFloat,
|
|
||||||
};
|
|
||||||
Type type;
|
|
||||||
const char* name;
|
const char* name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -38,14 +33,10 @@ class XmaRegisterFile {
|
||||||
static const XmaRegisterInfo* GetRegisterInfo(uint32_t index);
|
static const XmaRegisterInfo* GetRegisterInfo(uint32_t index);
|
||||||
|
|
||||||
static const size_t kRegisterCount = (0xFFFF + 1) / 4;
|
static const size_t kRegisterCount = (0xFFFF + 1) / 4;
|
||||||
union RegisterValue {
|
uint32_t values[kRegisterCount];
|
||||||
uint32_t u32;
|
|
||||||
float f32;
|
|
||||||
};
|
|
||||||
RegisterValue values[kRegisterCount];
|
|
||||||
|
|
||||||
RegisterValue& operator[](int reg) { return values[reg]; }
|
uint32_t operator[](uint32_t reg) const { return values[reg]; }
|
||||||
RegisterValue& operator[](XmaRegister reg) { return values[reg]; }
|
uint32_t& operator[](uint32_t reg) { return values[reg]; }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace apu
|
} // namespace apu
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* 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. *
|
* 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
|
// This is a partial file designed to be included by other files when
|
||||||
// constructing various tables.
|
// 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)
|
// 0x0000..0x001F : ???
|
||||||
XE_XMA_REGISTER(0x0607, kDword, NEXT_CONTEXT_INDEX)
|
// 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)
|
// XMA stuff is probably only 0x0600..0x06FF
|
||||||
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)
|
|
||||||
|
|
||||||
XE_XMA_REGISTER(0x0690, kDword, CONTEXT_LOCK_0)
|
XE_XMA_REGISTER(0x0600, ContextArrayAddress)
|
||||||
XE_XMA_REGISTER(0x0691, kDword, CONTEXT_LOCK_1)
|
// 0x0601..0x0605 : ???
|
||||||
XE_XMA_REGISTER(0x0692, kDword, CONTEXT_LOCK_2)
|
XE_XMA_REGISTER(0x0606, CurrentContextIndex)
|
||||||
XE_XMA_REGISTER(0x0693, kDword, CONTEXT_LOCK_3)
|
XE_XMA_REGISTER(0x0607, NextContextIndex)
|
||||||
XE_XMA_REGISTER(0x0694, kDword, CONTEXT_LOCK_4)
|
// 0x0608 : ???
|
||||||
XE_XMA_REGISTER(0x0695, kDword, CONTEXT_LOCK_5)
|
// 0x0609..0x060F : zero?
|
||||||
XE_XMA_REGISTER(0x0696, kDword, CONTEXT_LOCK_6)
|
XE_XMA_REGISTER_CONTEXT_GROUP(0x0610, Unknown610)
|
||||||
XE_XMA_REGISTER(0x0697, kDword, CONTEXT_LOCK_7)
|
// 0x061A..0x061F : zero?
|
||||||
XE_XMA_REGISTER(0x0698, kDword, CONTEXT_LOCK_8)
|
XE_XMA_REGISTER_CONTEXT_GROUP(0x0620, Unknown620)
|
||||||
XE_XMA_REGISTER(0x0699, kDword, CONTEXT_LOCK_9)
|
// 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)
|
// 0x0700..0x07FF : all 0xFFs?
|
||||||
XE_XMA_REGISTER(0x06A3, kDword, CONTEXT_CLEAR_3)
|
// 0x0800..0x17FF : ???
|
||||||
XE_XMA_REGISTER(0x06A4, kDword, CONTEXT_CLEAR_4)
|
// 0x1800..0x2FFF : all 0xFFs?
|
||||||
XE_XMA_REGISTER(0x06A5, kDword, CONTEXT_CLEAR_5)
|
// 0x3000..0x30FF : ???
|
||||||
XE_XMA_REGISTER(0x06A6, kDword, CONTEXT_CLEAR_6)
|
// 0x3100..0x3FFF : all 0xFFs?
|
||||||
XE_XMA_REGISTER(0x06A7, kDword, CONTEXT_CLEAR_7)
|
|
||||||
XE_XMA_REGISTER(0x06A8, kDword, CONTEXT_CLEAR_8)
|
#ifdef __XE_XMA_REGISTER_UNSET
|
||||||
XE_XMA_REGISTER(0x06A9, kDword, CONTEXT_CLEAR_9)
|
#undef __XE_XMA_REGISTER_UNSET
|
||||||
|
#undef XE_XMA_REGISTER
|
||||||
|
#endif
|
||||||
|
|
|
@ -81,20 +81,23 @@ inline T byte_swap(T value) {
|
||||||
template <typename T, std::endian E>
|
template <typename T, std::endian E>
|
||||||
struct endian_store {
|
struct endian_store {
|
||||||
endian_store() = default;
|
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) {
|
if constexpr (std::endian::native == E) {
|
||||||
value = src;
|
value = src;
|
||||||
} else {
|
} else {
|
||||||
value = xe::byte_swap(src);
|
value = xe::byte_swap(src);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
endian_store(const endian_store& other) { value = other.value; }
|
void set(const endian_store& other) { value = other.value; }
|
||||||
operator T() const {
|
T get() const {
|
||||||
if constexpr (std::endian::native == E) {
|
if constexpr (std::endian::native == E) {
|
||||||
return value;
|
return value;
|
||||||
} else {
|
|
||||||
return xe::byte_swap(value);
|
|
||||||
}
|
}
|
||||||
|
return xe::byte_swap(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
endian_store<T, E>& operator+=(int a) {
|
endian_store<T, E>& operator+=(int a) {
|
||||||
|
|
|
@ -20,18 +20,19 @@ ByteStream::ByteStream(uint8_t* data, size_t data_length, size_t offset)
|
||||||
|
|
||||||
ByteStream::~ByteStream() = default;
|
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) {
|
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);
|
std::memcpy(buf, data_ + offset_, len);
|
||||||
Advance(len);
|
Advance(len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ByteStream::Write(const uint8_t* buf, size_t 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);
|
std::memcpy(data_ + offset_, buf, len);
|
||||||
Advance(len);
|
Advance(len);
|
||||||
}
|
}
|
||||||
|
@ -41,7 +42,6 @@ std::string ByteStream::Read() {
|
||||||
std::string str;
|
std::string str;
|
||||||
uint32_t len = Read<uint32_t>();
|
uint32_t len = Read<uint32_t>();
|
||||||
str.resize(len);
|
str.resize(len);
|
||||||
|
|
||||||
Read(reinterpret_cast<uint8_t*>(&str[0]), len);
|
Read(reinterpret_cast<uint8_t*>(&str[0]), len);
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
@ -49,9 +49,8 @@ std::string ByteStream::Read() {
|
||||||
template <>
|
template <>
|
||||||
std::u16string ByteStream::Read() {
|
std::u16string ByteStream::Read() {
|
||||||
std::u16string str;
|
std::u16string str;
|
||||||
uint32_t len = Read<uint32_t>();
|
size_t len = Read<uint32_t>();
|
||||||
str.resize(len);
|
str.resize(len);
|
||||||
|
|
||||||
Read(reinterpret_cast<uint8_t*>(&str[0]), len * 2);
|
Read(reinterpret_cast<uint8_t*>(&str[0]), len * 2);
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,10 @@
|
||||||
#define UTF_CPP_CPLUSPLUS 201703L
|
#define UTF_CPP_CPLUSPLUS 201703L
|
||||||
#include "third_party/utfcpp/source/utf8.h"
|
#include "third_party/utfcpp/source/utf8.h"
|
||||||
|
|
||||||
|
#include "xenia/base/logging.h"
|
||||||
|
#include "xenia/base/main.h"
|
||||||
|
#include "xenia/base/system.h"
|
||||||
|
|
||||||
namespace utfcpp = utf8;
|
namespace utfcpp = utf8;
|
||||||
|
|
||||||
using u8_citer = utfcpp::iterator<std::string_view::const_iterator>;
|
using u8_citer = utfcpp::iterator<std::string_view::const_iterator>;
|
||||||
|
@ -61,7 +65,14 @@ void ParseLaunchArguments(int& argc, char**& argv,
|
||||||
|
|
||||||
auto result = options.parse(argc, argv);
|
auto result = options.parse(argc, argv);
|
||||||
if (result.count("help")) {
|
if (result.count("help")) {
|
||||||
PrintHelpAndExit();
|
xe::AttachConsole();
|
||||||
|
if (xe::has_console_attached()) {
|
||||||
|
PrintHelpAndExit();
|
||||||
|
} else {
|
||||||
|
xe::ShowSimpleMessageBox(xe::SimpleMessageBoxType::Help,
|
||||||
|
options.help({""}));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& it : *CmdVars) {
|
for (auto& it : *CmdVars) {
|
||||||
|
@ -78,8 +89,16 @@ void ParseLaunchArguments(int& argc, char**& argv,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (const cxxopts::OptionException& e) {
|
} catch (const cxxopts::OptionException& e) {
|
||||||
std::cout << e.what() << std::endl;
|
xe::AttachConsole();
|
||||||
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::ShowSimpleMessageBox(xe::SimpleMessageBoxType::Error, m);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||||
|
|
||||||
<!-- Automatically convert endianness for xe::be -->
|
<!-- Automatically convert endianness for xe::endian_store<,1> -->
|
||||||
<Type Name="xe::be<unsigned __int64>">
|
<Type Name="xe::endian_store<unsigned __int64, 1>">
|
||||||
<DisplayString>
|
<DisplayString>
|
||||||
{(((value & 0xFF00000000000000) >> 56) |
|
{(((value & 0xFF00000000000000) >> 56) |
|
||||||
((value & 0x00FF000000000000) >> 40) |
|
((value & 0x00FF000000000000) >> 40) |
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
((value & 0x00000000000000FF) << 56))}
|
((value & 0x00000000000000FF) << 56))}
|
||||||
</DisplayString>
|
</DisplayString>
|
||||||
</Type>
|
</Type>
|
||||||
<Type Name="xe::be<__int64>">
|
<Type Name="xe::endian_store<__int64, 1>">
|
||||||
<DisplayString>
|
<DisplayString>
|
||||||
{(((value & 0xFF00000000000000) >> 56) |
|
{(((value & 0xFF00000000000000) >> 56) |
|
||||||
((value & 0x00FF000000000000) >> 40) |
|
((value & 0x00FF000000000000) >> 40) |
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
</DisplayString>
|
</DisplayString>
|
||||||
</Type>
|
</Type>
|
||||||
|
|
||||||
<Type Name="xe::be<unsigned int>">
|
<Type Name="xe::endian_store<unsigned int, 1>">
|
||||||
<DisplayString>
|
<DisplayString>
|
||||||
{(((value & 0xFF000000) >> 24) |
|
{(((value & 0xFF000000) >> 24) |
|
||||||
((value & 0x00FF0000) >> 8) |
|
((value & 0x00FF0000) >> 8) |
|
||||||
|
@ -35,7 +35,7 @@
|
||||||
((value & 0x000000FF) << 24))}
|
((value & 0x000000FF) << 24))}
|
||||||
</DisplayString>
|
</DisplayString>
|
||||||
</Type>
|
</Type>
|
||||||
<Type Name="xe::be<int>">
|
<Type Name="xe::endian_store<int, 1>">
|
||||||
<DisplayString>
|
<DisplayString>
|
||||||
{(((value & 0xFF000000) >> 24) |
|
{(((value & 0xFF000000) >> 24) |
|
||||||
((value & 0x00FF0000) >> 8) |
|
((value & 0x00FF0000) >> 8) |
|
||||||
|
@ -44,25 +44,25 @@
|
||||||
</DisplayString>
|
</DisplayString>
|
||||||
</Type>
|
</Type>
|
||||||
|
|
||||||
<Type Name="xe::be<unsigned short>">
|
<Type Name="xe::endian_store<unsigned short, 1>">
|
||||||
<DisplayString>
|
<DisplayString>
|
||||||
{(((value & 0xFF00) >> 8) |
|
{(((value & 0xFF00) >> 8) |
|
||||||
((value & 0x00FF) << 8))}
|
((value & 0x00FF) << 8))}
|
||||||
</DisplayString>
|
</DisplayString>
|
||||||
</Type>
|
</Type>
|
||||||
<Type Name="xe::be<short>">
|
<Type Name="xe::endian_store<short, 1>">
|
||||||
<DisplayString>
|
<DisplayString>
|
||||||
{(((value & 0xFF00) >> 8) |
|
{(((value & 0xFF00) >> 8) |
|
||||||
((value & 0x00FF) << 8))}
|
((value & 0x00FF) << 8))}
|
||||||
</DisplayString>
|
</DisplayString>
|
||||||
</Type>
|
</Type>
|
||||||
|
|
||||||
<Type Name="xe::be<unsigned char>">
|
<Type Name="xe::endian_store<unsigned char, 1>">
|
||||||
<DisplayString>
|
<DisplayString>
|
||||||
{value}
|
{value}
|
||||||
</DisplayString>
|
</DisplayString>
|
||||||
</Type>
|
</Type>
|
||||||
<Type Name="xe::be<char>">
|
<Type Name="xe::endian_store<char, 1>">
|
||||||
<DisplayString>
|
<DisplayString>
|
||||||
{value}
|
{value}
|
||||||
</DisplayString>
|
</DisplayString>
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "xenia/base/memory.h"
|
#include "xenia/base/memory.h"
|
||||||
#include "xenia/base/ring_buffer.h"
|
#include "xenia/base/ring_buffer.h"
|
||||||
#include "xenia/base/string.h"
|
#include "xenia/base/string.h"
|
||||||
|
#include "xenia/base/system.h"
|
||||||
#include "xenia/base/threading.h"
|
#include "xenia/base/threading.h"
|
||||||
|
|
||||||
// For MessageBox:
|
// For MessageBox:
|
||||||
|
@ -58,7 +59,7 @@ struct LogLine {
|
||||||
size_t buffer_length;
|
size_t buffer_length;
|
||||||
uint32_t thread_id;
|
uint32_t thread_id;
|
||||||
uint16_t _pad_0; // (2b) padding
|
uint16_t _pad_0; // (2b) padding
|
||||||
uint8_t _pad_1; // (1b) padding
|
bool terminate;
|
||||||
char prefix_char;
|
char prefix_char;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -81,8 +82,7 @@ class Logger {
|
||||||
explicit Logger(const std::string_view app_name)
|
explicit Logger(const std::string_view app_name)
|
||||||
: wait_strategy_(),
|
: wait_strategy_(),
|
||||||
claim_strategy_(kBlockCount, wait_strategy_),
|
claim_strategy_(kBlockCount, wait_strategy_),
|
||||||
consumed_(wait_strategy_),
|
consumed_(wait_strategy_) {
|
||||||
running_(true) {
|
|
||||||
claim_strategy_.add_claim_barrier(consumed_);
|
claim_strategy_.add_claim_barrier(consumed_);
|
||||||
|
|
||||||
write_thread_ =
|
write_thread_ =
|
||||||
|
@ -91,7 +91,7 @@ class Logger {
|
||||||
}
|
}
|
||||||
|
|
||||||
~Logger() {
|
~Logger() {
|
||||||
running_ = false;
|
AppendLine(0, '\0', nullptr, 0, true); // append a terminator
|
||||||
xe::threading::Wait(write_thread_.get(), true);
|
xe::threading::Wait(write_thread_.get(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +124,6 @@ class Logger {
|
||||||
|
|
||||||
std::vector<std::unique_ptr<LogSink>> sinks_;
|
std::vector<std::unique_ptr<LogSink>> sinks_;
|
||||||
|
|
||||||
std::atomic<bool> running_;
|
|
||||||
std::unique_ptr<xe::threading::Thread> write_thread_;
|
std::unique_ptr<xe::threading::Thread> write_thread_;
|
||||||
|
|
||||||
void Write(const char* buf, size_t size) {
|
void Write(const char* buf, size_t size) {
|
||||||
|
@ -153,35 +152,30 @@ class Logger {
|
||||||
auto available_sequence = claim_strategy_.wait_until_published(
|
auto available_sequence = claim_strategy_.wait_until_published(
|
||||||
next_range.last(), last_sequence);
|
next_range.last(), last_sequence);
|
||||||
|
|
||||||
auto available_difference =
|
|
||||||
dp::difference(available_sequence, next_sequence);
|
|
||||||
|
|
||||||
size_t read_count = 0;
|
size_t read_count = 0;
|
||||||
|
auto available_range = next_range;
|
||||||
|
auto available_count = available_range.size();
|
||||||
|
|
||||||
if (available_difference > 0 &&
|
rb.set_write_offset(BlockOffset(available_range.end()));
|
||||||
static_cast<size_t>(available_difference) >= desired_count) {
|
|
||||||
auto available_range = dp::sequence_range(
|
|
||||||
next_sequence, static_cast<size_t>(available_difference));
|
|
||||||
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));
|
||||||
|
|
||||||
for (size_t i = available_range.first(); i != available_range.end();) {
|
LogLine line;
|
||||||
rb.set_read_offset(BlockOffset(i));
|
rb.Read(&line, sizeof(line));
|
||||||
|
|
||||||
LogLine line;
|
auto needed_count = BlockCount(sizeof(LogLine) + line.buffer_length);
|
||||||
rb.Read(&line, sizeof(line));
|
if (read_count + needed_count > available_count) {
|
||||||
|
// More blocks are needed for a complete line.
|
||||||
auto needed_count = BlockCount(sizeof(LogLine) + line.buffer_length);
|
desired_count = needed_count;
|
||||||
if (read_count + needed_count > available_count) {
|
break;
|
||||||
// More blocks are needed for a complete line.
|
} else {
|
||||||
desired_count = needed_count;
|
// Enough blocks to read this log line, advance by that many.
|
||||||
break;
|
read_count += needed_count;
|
||||||
} else {
|
i += needed_count;
|
||||||
// Enough blocks to read this log line, advance by that many.
|
|
||||||
read_count += needed_count;
|
|
||||||
i += needed_count;
|
|
||||||
|
|
||||||
|
if (line.prefix_char) {
|
||||||
char prefix[] = {
|
char prefix[] = {
|
||||||
line.prefix_char,
|
line.prefix_char,
|
||||||
'>',
|
'>',
|
||||||
|
@ -200,44 +194,53 @@ class Logger {
|
||||||
fmt::format_to_n(prefix + 3, sizeof(prefix) - 3, "{:08X}",
|
fmt::format_to_n(prefix + 3, sizeof(prefix) - 3, "{:08X}",
|
||||||
line.thread_id);
|
line.thread_id);
|
||||||
Write(prefix, sizeof(prefix) - 1);
|
Write(prefix, sizeof(prefix) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (line.buffer_length) {
|
if (line.buffer_length) {
|
||||||
// Get access to the line data - which may be split in the ring
|
// Get access to the line data - which may be split in the ring
|
||||||
// buffer - and write it out in parts.
|
// buffer - and write it out in parts.
|
||||||
auto line_range = rb.BeginRead(line.buffer_length);
|
auto line_range = rb.BeginRead(line.buffer_length);
|
||||||
Write(reinterpret_cast<const char*>(line_range.first),
|
Write(reinterpret_cast<const char*>(line_range.first),
|
||||||
line_range.first_length);
|
line_range.first_length);
|
||||||
if (line_range.second_length) {
|
if (line_range.second_length) {
|
||||||
Write(reinterpret_cast<const char*>(line_range.second),
|
Write(reinterpret_cast<const char*>(line_range.second),
|
||||||
line_range.second_length);
|
line_range.second_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always ensure there is a newline.
|
// Always ensure there is a newline.
|
||||||
char last_char =
|
char last_char =
|
||||||
line_range.second
|
line_range.second
|
||||||
? line_range.second[line_range.second_length - 1]
|
? line_range.second[line_range.second_length - 1]
|
||||||
: line_range.first[line_range.first_length - 1];
|
: line_range.first[line_range.first_length - 1];
|
||||||
if (last_char != '\n') {
|
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.
|
|
||||||
const char suffix[1] = {'\n'};
|
const char suffix[1] = {'\n'};
|
||||||
Write(suffix, 1);
|
Write(suffix, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (terminate) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (read_count) {
|
if (read_count) {
|
||||||
// Advance by the number of blocks we read.
|
// Advance by the number of blocks we read.
|
||||||
auto read_range = dp::sequence_range(next_sequence, read_count);
|
auto read_range = dp::sequence_range(next_sequence, read_count);
|
||||||
next_sequence = read_range.end();
|
next_sequence = read_range.end();
|
||||||
last_sequence = read_range.last();
|
last_sequence = read_range.last();
|
||||||
consumed_.publish(read_range.last());
|
consumed_.publish(last_sequence);
|
||||||
|
|
||||||
desired_count = 1;
|
desired_count = 1;
|
||||||
|
|
||||||
|
@ -249,9 +252,6 @@ class Logger {
|
||||||
|
|
||||||
idle_loops = 0;
|
idle_loops = 0;
|
||||||
} else {
|
} else {
|
||||||
if (!running_) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (idle_loops >= 1000) {
|
if (idle_loops >= 1000) {
|
||||||
// Introduce a waiting period.
|
// Introduce a waiting period.
|
||||||
xe::threading::Sleep(std::chrono::milliseconds(50));
|
xe::threading::Sleep(std::chrono::milliseconds(50));
|
||||||
|
@ -264,7 +264,8 @@ class Logger {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void AppendLine(uint32_t thread_id, const char prefix_char,
|
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);
|
size_t count = BlockCount(sizeof(LogLine) + buffer_length);
|
||||||
|
|
||||||
auto range = claim_strategy_.claim(count);
|
auto range = claim_strategy_.claim(count);
|
||||||
|
@ -278,9 +279,12 @@ class Logger {
|
||||||
line.buffer_length = buffer_length;
|
line.buffer_length = buffer_length;
|
||||||
line.thread_id = thread_id;
|
line.thread_id = thread_id;
|
||||||
line.prefix_char = prefix_char;
|
line.prefix_char = prefix_char;
|
||||||
|
line.terminate = terminate;
|
||||||
|
|
||||||
rb.Write(&line, sizeof(LogLine));
|
rb.Write(&line, sizeof(LogLine));
|
||||||
rb.Write(buffer_data, buffer_length);
|
if (buffer_length) {
|
||||||
|
rb.Write(buffer_data, buffer_length);
|
||||||
|
}
|
||||||
|
|
||||||
claim_strategy_.publish(range);
|
claim_strategy_.publish(range);
|
||||||
}
|
}
|
||||||
|
@ -350,12 +354,10 @@ void logging::AppendLogLine(LogLevel log_level, const char prefix_char,
|
||||||
void FatalError(const std::string_view str) {
|
void FatalError(const std::string_view str) {
|
||||||
logging::AppendLogLine(LogLevel::Error, 'X', str);
|
logging::AppendLogLine(LogLevel::Error, 'X', str);
|
||||||
|
|
||||||
#if XE_PLATFORM_WIN32
|
|
||||||
if (!xe::has_console_attached()) {
|
if (!xe::has_console_attached()) {
|
||||||
MessageBoxW(NULL, (LPCWSTR)xe::to_utf16(str).c_str(), L"Xenia Error",
|
ShowSimpleMessageBox(SimpleMessageBoxType::Error, str);
|
||||||
MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
|
|
||||||
}
|
}
|
||||||
#endif // WIN32
|
|
||||||
ShutdownLogging();
|
ShutdownLogging();
|
||||||
std::exit(1);
|
std::exit(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ namespace xe {
|
||||||
// Returns true if there is a user-visible console attached to receive stdout.
|
// Returns true if there is a user-visible console attached to receive stdout.
|
||||||
bool has_console_attached();
|
bool has_console_attached();
|
||||||
|
|
||||||
|
void AttachConsole();
|
||||||
|
|
||||||
// Extern defined by user code. This must be present for the application to
|
// Extern defined by user code. This must be present for the application to
|
||||||
// launch.
|
// launch.
|
||||||
struct EntryInfo {
|
struct EntryInfo {
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "xenia/base/cvar.h"
|
#include "xenia/base/cvar.h"
|
||||||
#include "xenia/base/main.h"
|
#include "xenia/base/main.h"
|
||||||
|
|
||||||
|
@ -16,7 +19,9 @@
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
||||||
bool has_console_attached() { return true; }
|
bool has_console_attached() { return isatty(fileno(stdin)) == 1; }
|
||||||
|
|
||||||
|
void AttachConsole() {}
|
||||||
|
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
|
|
|
@ -38,8 +38,22 @@ bool has_console_attached_ = true;
|
||||||
|
|
||||||
bool has_console_attached() { return has_console_attached_; }
|
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() {
|
void AttachConsole() {
|
||||||
if (!cvars::enable_console) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +141,9 @@ int Main() {
|
||||||
|
|
||||||
// Attach a console so we can write output to stdout. If the user hasn't
|
// Attach a console so we can write output to stdout. If the user hasn't
|
||||||
// redirected output themselves it'll pop up a window.
|
// redirected output themselves it'll pop up a window.
|
||||||
xe::AttachConsole();
|
if (cvars::enable_console) {
|
||||||
|
xe::AttachConsole();
|
||||||
|
}
|
||||||
|
|
||||||
// Setup COM on the main thread.
|
// Setup COM on the main thread.
|
||||||
// NOTE: this may fail if COM has already been initialized - that's OK.
|
// NOTE: this may fail if COM has already been initialized - that's OK.
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "xenia/base/assert.h"
|
#include "xenia/base/assert.h"
|
||||||
#include "xenia/base/cvar.h"
|
#include "xenia/base/cvar.h"
|
||||||
#include "xenia/base/profiling.h"
|
#include "xenia/base/profiling.h"
|
||||||
|
#include "xenia/ui/virtual_key.h"
|
||||||
#include "xenia/ui/window.h"
|
#include "xenia/ui/window.h"
|
||||||
|
|
||||||
#if XE_OPTION_PROFILING
|
#if XE_OPTION_PROFILING
|
||||||
|
@ -112,31 +113,35 @@ void Profiler::ThreadEnter(const char* name) {
|
||||||
|
|
||||||
void Profiler::ThreadExit() { MicroProfileOnThreadExit(); }
|
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
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
|
||||||
switch (key_code) {
|
switch (virtual_key) {
|
||||||
case VK_OEM_3: // `
|
case ui::VirtualKey::kOem3: // `
|
||||||
MicroProfileTogglePause();
|
MicroProfileTogglePause();
|
||||||
return true;
|
return true;
|
||||||
#if XE_OPTION_PROFILING_UI
|
#if XE_OPTION_PROFILING_UI
|
||||||
case VK_TAB:
|
case ui::VirtualKey::kTab:
|
||||||
MicroProfileToggleDisplayMode();
|
MicroProfileToggleDisplayMode();
|
||||||
return true;
|
return true;
|
||||||
case 0x31: // 1
|
case ui::VirtualKey::k1:
|
||||||
MicroProfileModKey(1);
|
MicroProfileModKey(1);
|
||||||
return true;
|
return true;
|
||||||
#endif // XE_OPTION_PROFILING_UI
|
#endif // XE_OPTION_PROFILING_UI
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Profiler::OnKeyUp(int key_code) {
|
bool Profiler::OnKeyUp(ui::VirtualKey virtual_key) {
|
||||||
switch (key_code) {
|
switch (virtual_key) {
|
||||||
#if XE_OPTION_PROFILING_UI
|
#if XE_OPTION_PROFILING_UI
|
||||||
case 0x31: // 1
|
case ui::VirtualKey::k1:
|
||||||
MicroProfileModKey(0);
|
MicroProfileModKey(0);
|
||||||
return true;
|
return true;
|
||||||
#endif // XE_OPTION_PROFILING_UI
|
#endif // XE_OPTION_PROFILING_UI
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -219,14 +224,14 @@ void Profiler::set_window(ui::Window* window) {
|
||||||
// Watch for toggle/mode keys and such.
|
// Watch for toggle/mode keys and such.
|
||||||
window_->on_key_down.AddListener([](ui::KeyEvent* e) {
|
window_->on_key_down.AddListener([](ui::KeyEvent* e) {
|
||||||
if (Profiler::is_visible()) {
|
if (Profiler::is_visible()) {
|
||||||
Profiler::OnKeyDown(e->key_code());
|
Profiler::OnKeyDown(e->virtual_key());
|
||||||
e->set_handled(true);
|
e->set_handled(true);
|
||||||
window_->Invalidate();
|
window_->Invalidate();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
window_->on_key_up.AddListener([](ui::KeyEvent* e) {
|
window_->on_key_up.AddListener([](ui::KeyEvent* e) {
|
||||||
if (Profiler::is_visible()) {
|
if (Profiler::is_visible()) {
|
||||||
Profiler::OnKeyUp(e->key_code());
|
Profiler::OnKeyUp(e->virtual_key());
|
||||||
e->set_handled(true);
|
e->set_handled(true);
|
||||||
window_->Invalidate();
|
window_->Invalidate();
|
||||||
}
|
}
|
||||||
|
@ -257,8 +262,8 @@ void Profiler::Shutdown() {}
|
||||||
uint32_t Profiler::GetColor(const char* str) { return 0; }
|
uint32_t Profiler::GetColor(const char* str) { return 0; }
|
||||||
void Profiler::ThreadEnter(const char* name) {}
|
void Profiler::ThreadEnter(const char* name) {}
|
||||||
void Profiler::ThreadExit() {}
|
void Profiler::ThreadExit() {}
|
||||||
bool Profiler::OnKeyDown(int key_code) { return false; }
|
bool Profiler::OnKeyDown(ui::VirtualKey virtual_key) { return false; }
|
||||||
bool Profiler::OnKeyUp(int key_code) { return false; }
|
bool Profiler::OnKeyUp(ui::VirtualKey virtual_key) { return false; }
|
||||||
void Profiler::OnMouseDown(bool left_button, bool right_button) {}
|
void Profiler::OnMouseDown(bool left_button, bool right_button) {}
|
||||||
void Profiler::OnMouseUp() {}
|
void Profiler::OnMouseUp() {}
|
||||||
void Profiler::OnMouseMove(int x, int y) {}
|
void Profiler::OnMouseMove(int x, int y) {}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "xenia/base/string.h"
|
#include "xenia/base/string.h"
|
||||||
|
#include "xenia/ui/virtual_key.h"
|
||||||
|
|
||||||
#if XE_PLATFORM_WIN32
|
#if XE_PLATFORM_WIN32
|
||||||
#define XE_OPTION_PROFILING 1
|
#define XE_OPTION_PROFILING 1
|
||||||
|
@ -171,8 +172,8 @@ class Profiler {
|
||||||
// Deactivates the calling thread for profiling.
|
// Deactivates the calling thread for profiling.
|
||||||
static void ThreadExit();
|
static void ThreadExit();
|
||||||
|
|
||||||
static bool OnKeyDown(int key_code);
|
static bool OnKeyDown(ui::VirtualKey virtual_key);
|
||||||
static bool OnKeyUp(int key_code);
|
static bool OnKeyUp(ui::VirtualKey virtual_key);
|
||||||
static void OnMouseDown(bool left_button, bool right_button);
|
static void OnMouseDown(bool left_button, bool right_button);
|
||||||
static void OnMouseUp();
|
static void OnMouseUp();
|
||||||
static void OnMouseMove(int x, int y);
|
static void OnMouseMove(int x, int y);
|
||||||
|
|
|
@ -11,15 +11,24 @@
|
||||||
#define XENIA_BASE_SYSTEM_H_
|
#define XENIA_BASE_SYSTEM_H_
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <string>
|
#include <string_view>
|
||||||
|
|
||||||
#include "xenia/base/string.h"
|
#include "xenia/base/string.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
||||||
void LaunchWebBrowser(const std::string& url);
|
void LaunchWebBrowser(const std::string_view url);
|
||||||
void LaunchFileExplorer(const std::filesystem::path& path);
|
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
|
} // namespace xe
|
||||||
|
|
||||||
#endif // XENIA_BASE_SYSTEM_H_
|
#endif // XENIA_BASE_SYSTEM_H_
|
||||||
|
|
|
@ -7,22 +7,64 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <alloca.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include <string>
|
#include <cstring>
|
||||||
|
|
||||||
#include "xenia/base/assert.h"
|
#include "xenia/base/assert.h"
|
||||||
#include "xenia/base/platform_linux.h"
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/base/string.h"
|
#include "xenia/base/string.h"
|
||||||
#include "xenia/base/system.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 {
|
namespace xe {
|
||||||
|
|
||||||
void LaunchWebBrowser(const std::string& url) {
|
void LaunchWebBrowser(const std::string_view url) {
|
||||||
auto cmd = "xdg-open " + url;
|
auto cmd = std::string("xdg-open ");
|
||||||
|
cmd.append(url);
|
||||||
system(cmd.c_str());
|
system(cmd.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaunchFileExplorer(const std::filesystem::path& path) { assert_always(); }
|
void LaunchFileExplorer(const std::filesystem::path& path) { assert_always(); }
|
||||||
|
|
||||||
|
void ShowSimpleMessageBox(SimpleMessageBoxType type, std::string_view message) {
|
||||||
|
void* libsdl2 = dlopen("libSDL2.so", RTLD_LAZY | RTLD_LOCAL);
|
||||||
|
assert_not_null(libsdl2);
|
||||||
|
if (libsdl2) {
|
||||||
|
auto* pSDL_ShowSimpleMessageBox =
|
||||||
|
reinterpret_cast<decltype(SDL_ShowSimpleMessageBox)*>(
|
||||||
|
dlsym(libsdl2, "SDL_ShowSimpleMessageBox"));
|
||||||
|
assert_not_null(pSDL_ShowSimpleMessageBox);
|
||||||
|
if (pSDL_ShowSimpleMessageBox) {
|
||||||
|
Uint32 flags;
|
||||||
|
const char* title;
|
||||||
|
char* message_copy = reinterpret_cast<char*>(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
|
} // namespace xe
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
||||||
void LaunchWebBrowser(const std::string& url) {
|
void LaunchWebBrowser(const std::string_view url) {
|
||||||
auto temp = xe::to_utf16(url);
|
auto wide_url = xe::to_utf16(url);
|
||||||
ShellExecuteW(nullptr, L"open", reinterpret_cast<LPCWSTR>(temp.c_str()),
|
ShellExecuteW(nullptr, L"open", reinterpret_cast<LPCWSTR>(wide_url.c_str()),
|
||||||
nullptr, nullptr, SW_SHOWNORMAL);
|
nullptr, nullptr, SW_SHOWNORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,4 +24,28 @@ void LaunchFileExplorer(const std::filesystem::path& url) {
|
||||||
SW_SHOWNORMAL);
|
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<LPCWSTR>(wide_message.c_str()), title,
|
||||||
|
type_flags);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -25,6 +25,14 @@ std::shared_ptr<cpptoml::table> ParseFile(
|
||||||
throw cpptoml::parse_exception(xe::path_to_utf8(filename) +
|
throw cpptoml::parse_exception(xe::path_to_utf8(filename) +
|
||||||
" could not be opened for parsing");
|
" 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);
|
cpptoml::parser p(file);
|
||||||
return p.parse();
|
return p.parse();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* 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. *
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
@ -245,65 +245,34 @@ void Value::Convert(TypeName target_type, RoundMode round_mode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
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) {
|
void Value::Round(RoundMode round_mode) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case FLOAT32_TYPE:
|
case FLOAT32_TYPE:
|
||||||
switch (round_mode) {
|
constant.f32 = RoundValue(round_mode, constant.f32);
|
||||||
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;
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
case FLOAT64_TYPE:
|
case FLOAT64_TYPE:
|
||||||
switch (round_mode) {
|
constant.f64 = RoundValue(round_mode, constant.f64);
|
||||||
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;
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
case VEC128_TYPE:
|
case VEC128_TYPE:
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
switch (round_mode) {
|
constant.v128.f32[i] = RoundValue(round_mode, constant.v128.f32[i]);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
|
@ -426,8 +395,9 @@ void Value::MulHi(Value* other, bool is_unsigned) {
|
||||||
(uint32_t)other->constant.i32) >>
|
(uint32_t)other->constant.i32) >>
|
||||||
32);
|
32);
|
||||||
} else {
|
} else {
|
||||||
constant.i32 = (int32_t)(
|
constant.i32 =
|
||||||
((int64_t)constant.i32 * (int64_t)other->constant.i32) >> 32);
|
(int32_t)(((int64_t)constant.i32 * (int64_t)other->constant.i32) >>
|
||||||
|
32);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case INT64_TYPE:
|
case INT64_TYPE:
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* 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. *
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
@ -426,6 +426,10 @@ int InstrEmit_sc(PPCHIRBuilder& f, const InstrData& i) {
|
||||||
// Game code should only ever use LEV=0.
|
// Game code should only ever use LEV=0.
|
||||||
// LEV=2 is to signify 'call import' from Xenia.
|
// LEV=2 is to signify 'call import' from Xenia.
|
||||||
// TODO(gibbed): syscalls!
|
// TODO(gibbed): syscalls!
|
||||||
|
if (i.SC.LEV == 0) {
|
||||||
|
f.CallExtern(f.builtins()->syscall_handler);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (i.SC.LEV == 2) {
|
if (i.SC.LEV == 2) {
|
||||||
f.CallExtern(f.function());
|
f.CallExtern(f.function());
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -806,6 +810,6 @@ void RegisterEmitCategoryControl() {
|
||||||
XEREGISTERINSTR(mtmsrd);
|
XEREGISTERINSTR(mtmsrd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace ppc
|
||||||
} // namespace cpu
|
} // namespace cpu
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
} // namespace xe
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "xenia/cpu/ppc/ppc_frontend.h"
|
#include "xenia/cpu/ppc/ppc_frontend.h"
|
||||||
|
|
||||||
#include "xenia/base/atomic.h"
|
#include "xenia/base/atomic.h"
|
||||||
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/cpu/ppc/ppc_context.h"
|
#include "xenia/cpu/ppc/ppc_context.h"
|
||||||
#include "xenia/cpu/ppc/ppc_emit.h"
|
#include "xenia/cpu/ppc/ppc_emit.h"
|
||||||
#include "xenia/cpu/ppc/ppc_opcode_info.h"
|
#include "xenia/cpu/ppc/ppc_opcode_info.h"
|
||||||
|
@ -78,6 +79,17 @@ void LeaveGlobalLock(PPCContext* ppc_context, void* arg0, void* arg1) {
|
||||||
global_mutex->unlock();
|
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;
|
||||||
|
#pragma warning(suppress : 4065)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool PPCFrontend::Initialize() {
|
bool PPCFrontend::Initialize() {
|
||||||
void* arg0 = reinterpret_cast<void*>(&xe::global_critical_region::mutex());
|
void* arg0 = reinterpret_cast<void*>(&xe::global_critical_region::mutex());
|
||||||
void* arg1 = reinterpret_cast<void*>(&builtins_.global_lock_count);
|
void* arg1 = reinterpret_cast<void*>(&builtins_.global_lock_count);
|
||||||
|
@ -87,6 +99,8 @@ bool PPCFrontend::Initialize() {
|
||||||
processor_->DefineBuiltin("EnterGlobalLock", EnterGlobalLock, arg0, arg1);
|
processor_->DefineBuiltin("EnterGlobalLock", EnterGlobalLock, arg0, arg1);
|
||||||
builtins_.leave_global_lock =
|
builtins_.leave_global_lock =
|
||||||
processor_->DefineBuiltin("LeaveGlobalLock", LeaveGlobalLock, arg0, arg1);
|
processor_->DefineBuiltin("LeaveGlobalLock", LeaveGlobalLock, arg0, arg1);
|
||||||
|
builtins_.syscall_handler = processor_->DefineBuiltin(
|
||||||
|
"SyscallHandler", SyscallHandler, nullptr, nullptr);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ struct PPCBuiltins {
|
||||||
Function* check_global_lock;
|
Function* check_global_lock;
|
||||||
Function* enter_global_lock;
|
Function* enter_global_lock;
|
||||||
Function* leave_global_lock;
|
Function* leave_global_lock;
|
||||||
|
Function* syscall_handler;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PPCFrontend {
|
class PPCFrontend {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* 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. *
|
* 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.
|
// offsetof seems to be unable to find OptionalHeader.
|
||||||
#define offsetof1(type, member) ((std::size_t) & (((type*)0)->member))
|
#define offsetof1(type, member) ((std::size_t) & (((type*)0)->member))
|
||||||
#define IMAGE_FIRST_SECTION1(ntheader) \
|
#define IMAGE_FIRST_SECTION1(ntheader) \
|
||||||
((PIMAGE_SECTION_HEADER)( \
|
((PIMAGE_SECTION_HEADER)((uint8_t*)ntheader + \
|
||||||
(uint8_t*)ntheader + offsetof1(IMAGE_NT_HEADERS, OptionalHeader) + \
|
offsetof1(IMAGE_NT_HEADERS, OptionalHeader) + \
|
||||||
((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader))
|
((PIMAGE_NT_HEADERS)(ntheader)) \
|
||||||
|
->FileHeader.SizeOfOptionalHeader))
|
||||||
|
|
||||||
// Quick scan to determine bounds of sections.
|
// Quick scan to determine bounds of sections.
|
||||||
size_t upper_address = 0;
|
size_t upper_address = 0;
|
||||||
|
|
|
@ -517,6 +517,10 @@ bool CommandProcessor::ExecutePacket(RingBuffer* reader) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (packet == 0xCDCDCDCD) {
|
||||||
|
XELOGW("GPU packet is CDCDCDCD - probably read uninitialized memory!");
|
||||||
|
}
|
||||||
|
|
||||||
switch (packet_type) {
|
switch (packet_type) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
return ExecutePacketType0(reader, packet);
|
return ExecutePacketType0(reader, packet);
|
||||||
|
|
|
@ -507,10 +507,15 @@ union alignas(uint32_t) PA_SC_WINDOW_SCISSOR_BR {
|
||||||
static_assert_size(PA_SC_WINDOW_SCISSOR_BR, sizeof(uint32_t));
|
static_assert_size(PA_SC_WINDOW_SCISSOR_BR, sizeof(uint32_t));
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
___ ___
|
___ ___ _ _ ___ ___ ___
|
||||||
| _ \ _ )
|
| _ \ __| \| | \| __| _ \
|
||||||
| / _ \
|
| / _|| .` | |) | _|| /
|
||||||
|_|_\___/
|
|_|_\___|_|\_|___/|___|_|_\
|
||||||
|
|
||||||
|
___ _ ___ _ _____ _ _ ___
|
||||||
|
| _ ) /_\ / __| |/ / __| \| | \
|
||||||
|
| _ \/ _ \ (__| ' <| _|| .` | |) |
|
||||||
|
|___/_/ \_\___|_|\_\___|_|\_|___/
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "xenia/memory.h"
|
#include "xenia/memory.h"
|
||||||
#include "xenia/ui/file_picker.h"
|
#include "xenia/ui/file_picker.h"
|
||||||
#include "xenia/ui/imgui_drawer.h"
|
#include "xenia/ui/imgui_drawer.h"
|
||||||
|
#include "xenia/ui/virtual_key.h"
|
||||||
#include "xenia/ui/window.h"
|
#include "xenia/ui/window.h"
|
||||||
#include "xenia/xbox.h"
|
#include "xenia/xbox.h"
|
||||||
|
|
||||||
|
@ -135,7 +136,7 @@ bool TraceViewer::Setup() {
|
||||||
window_->set_imgui_input_enabled(true);
|
window_->set_imgui_input_enabled(true);
|
||||||
|
|
||||||
window_->on_key_char.AddListener([&](xe::ui::KeyEvent* e) {
|
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();
|
graphics_system_->ClearCaches();
|
||||||
e->set_handled(true);
|
e->set_handled(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -194,10 +194,10 @@ enum class SurfaceNumFormat : uint32_t {
|
||||||
kFloat = 7,
|
kFloat = 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
// The EDRAM is an opaque block of memory accessible by the RB pipeline stage of
|
// The EDRAM is an opaque block of memory accessible by the RB (render backend)
|
||||||
// the GPU, which performs output-merger functionality (color render target
|
// pipeline stage of the GPU, which performs output-merger functionality (color
|
||||||
// writing and blending, depth and stencil testing) and resolve (copy)
|
// render target writing and blending, depth and stencil testing) and resolve
|
||||||
// operations.
|
// (copy) operations.
|
||||||
//
|
//
|
||||||
// Data in the 10 MiB of EDRAM is laid out as 2048 tiles on 80x16 32bpp MSAA
|
// 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
|
// samples. With 2x MSAA, one pixel consists of 1x2 samples, and with 4x, it
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <forward_list>
|
#include <forward_list>
|
||||||
#include <map>
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "third_party/fmt/include/fmt/format.h"
|
#include "third_party/fmt/include/fmt/format.h"
|
||||||
#include "third_party/imgui/imgui.h"
|
#include "third_party/imgui/imgui.h"
|
||||||
|
@ -23,6 +23,7 @@
|
||||||
#include "xenia/hid/hid_flags.h"
|
#include "xenia/hid/hid_flags.h"
|
||||||
#include "xenia/hid/input_system.h"
|
#include "xenia/hid/input_system.h"
|
||||||
#include "xenia/ui/imgui_drawer.h"
|
#include "xenia/ui/imgui_drawer.h"
|
||||||
|
#include "xenia/ui/virtual_key.h"
|
||||||
#include "xenia/ui/vulkan/vulkan_provider.h"
|
#include "xenia/ui/vulkan/vulkan_provider.h"
|
||||||
#include "xenia/ui/window.h"
|
#include "xenia/ui/window.h"
|
||||||
|
|
||||||
|
@ -281,44 +282,42 @@ void DrawInputGetState() {
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const std::map<std::underlying_type<X_INPUT_GAMEPAD_VK>::type,
|
static const std::unordered_map<ui::VirtualKey, const std::string> kVkPretty = {
|
||||||
const std::string>
|
{ui::VirtualKey::kXInputPadA, "A"},
|
||||||
vk_pretty = {
|
{ui::VirtualKey::kXInputPadB, "B"},
|
||||||
{X_INPUT_GAMEPAD_VK_A, "A"},
|
{ui::VirtualKey::kXInputPadX, "X"},
|
||||||
{X_INPUT_GAMEPAD_VK_B, "B"},
|
{ui::VirtualKey::kXInputPadY, "Y"},
|
||||||
{X_INPUT_GAMEPAD_VK_X, "X"},
|
{ui::VirtualKey::kXInputPadRShoulder, "R Shoulder"},
|
||||||
{X_INPUT_GAMEPAD_VK_Y, "Y"},
|
{ui::VirtualKey::kXInputPadLShoulder, "L Shoulder"},
|
||||||
{X_INPUT_GAMEPAD_VK_RSHOULDER, "R Shoulder"},
|
{ui::VirtualKey::kXInputPadLTrigger, "L Trigger"},
|
||||||
{X_INPUT_GAMEPAD_VK_LSHOULDER, "L Shoulder"},
|
{ui::VirtualKey::kXInputPadRTrigger, "R Trigger"},
|
||||||
{X_INPUT_GAMEPAD_VK_LTRIGGER, "L Trigger"},
|
|
||||||
{X_INPUT_GAMEPAD_VK_RTRIGGER, "R Trigger"},
|
|
||||||
|
|
||||||
{X_INPUT_GAMEPAD_VK_DPAD_UP, "DPad up"},
|
{ui::VirtualKey::kXInputPadDpadUp, "DPad up"},
|
||||||
{X_INPUT_GAMEPAD_VK_DPAD_DOWN, "DPad down"},
|
{ui::VirtualKey::kXInputPadDpadDown, "DPad down"},
|
||||||
{X_INPUT_GAMEPAD_VK_DPAD_LEFT, "DPad left"},
|
{ui::VirtualKey::kXInputPadDpadLeft, "DPad left"},
|
||||||
{X_INPUT_GAMEPAD_VK_DPAD_RIGHT, "DPad right"},
|
{ui::VirtualKey::kXInputPadDpadRight, "DPad right"},
|
||||||
{X_INPUT_GAMEPAD_VK_START, "Start"},
|
{ui::VirtualKey::kXInputPadStart, "Start"},
|
||||||
{X_INPUT_GAMEPAD_VK_BACK, "Back"},
|
{ui::VirtualKey::kXInputPadBack, "Back"},
|
||||||
{X_INPUT_GAMEPAD_VK_LTHUMB_PRESS, "L Thumb press"},
|
{ui::VirtualKey::kXInputPadLThumbPress, "L Thumb press"},
|
||||||
{X_INPUT_GAMEPAD_VK_RTHUMB_PRESS, "R Thumb press"},
|
{ui::VirtualKey::kXInputPadRThumbPress, "R Thumb press"},
|
||||||
|
|
||||||
{X_INPUT_GAMEPAD_VK_LTHUMB_UP, "L Thumb up"},
|
{ui::VirtualKey::kXInputPadLThumbUp, "L Thumb up"},
|
||||||
{X_INPUT_GAMEPAD_VK_LTHUMB_DOWN, "L Thumb down"},
|
{ui::VirtualKey::kXInputPadLThumbDown, "L Thumb down"},
|
||||||
{X_INPUT_GAMEPAD_VK_LTHUMB_RIGHT, "L Thumb right"},
|
{ui::VirtualKey::kXInputPadLThumbRight, "L Thumb right"},
|
||||||
{X_INPUT_GAMEPAD_VK_LTHUMB_LEFT, "L Thumb left"},
|
{ui::VirtualKey::kXInputPadLThumbLeft, "L Thumb left"},
|
||||||
{X_INPUT_GAMEPAD_VK_LTHUMB_UPLEFT, "L Thumb up & left"},
|
{ui::VirtualKey::kXInputPadLThumbUpLeft, "L Thumb up & left"},
|
||||||
{X_INPUT_GAMEPAD_VK_LTHUMB_UPRIGHT, "L Thumb up & right"},
|
{ui::VirtualKey::kXInputPadLThumbUpRight, "L Thumb up & right"},
|
||||||
{X_INPUT_GAMEPAD_VK_LTHUMB_DOWNRIGHT, "L Thumb down & right"},
|
{ui::VirtualKey::kXInputPadLThumbDownRight, "L Thumb down & right"},
|
||||||
{X_INPUT_GAMEPAD_VK_LTHUMB_DOWNLEFT, "L Thumb down & left"},
|
{ui::VirtualKey::kXInputPadLThumbDownLeft, "L Thumb down & left"},
|
||||||
|
|
||||||
{X_INPUT_GAMEPAD_VK_RTHUMB_UP, "R Thumb up"},
|
{ui::VirtualKey::kXInputPadRThumbUp, "R Thumb up"},
|
||||||
{X_INPUT_GAMEPAD_VK_RTHUMB_DOWN, "R Thumb down"},
|
{ui::VirtualKey::kXInputPadRThumbDown, "R Thumb down"},
|
||||||
{X_INPUT_GAMEPAD_VK_RTHUMB_RIGHT, "R Thumb right"},
|
{ui::VirtualKey::kXInputPadRThumbRight, "R Thumb right"},
|
||||||
{X_INPUT_GAMEPAD_VK_RTHUMB_LEFT, "R Thumb left"},
|
{ui::VirtualKey::kXInputPadRThumbLeft, "R Thumb left"},
|
||||||
{X_INPUT_GAMEPAD_VK_RTHUMB_UPLEFT, "R Thumb up & left"},
|
{ui::VirtualKey::kXInputPadRThumbUpLeft, "R Thumb up & left"},
|
||||||
{X_INPUT_GAMEPAD_VK_RTHUMB_UPRIGHT, "R Thumb up & right"},
|
{ui::VirtualKey::kXInputPadRThumbUpRight, "R Thumb up & right"},
|
||||||
{X_INPUT_GAMEPAD_VK_RTHUMB_DOWNRIGHT, "R Thumb down & right"},
|
{ui::VirtualKey::kXInputPadRThumbDownRight, "R Thumb down & right"},
|
||||||
{X_INPUT_GAMEPAD_VK_RTHUMB_DOWNLEFT, "R Thumb down & left"},
|
{ui::VirtualKey::kXInputPadRThumbDownLeft, "R Thumb down & left"},
|
||||||
};
|
};
|
||||||
|
|
||||||
void DrawUserInputGetKeystroke(uint32_t user_index, bool poll,
|
void DrawUserInputGetKeystroke(uint32_t user_index, bool poll,
|
||||||
|
@ -354,10 +353,12 @@ void DrawUserInputGetKeystroke(uint32_t user_index, bool poll,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto key_search = vk_pretty.find(stroke.virtual_key);
|
ui::VirtualKey virtual_key = ui::VirtualKey(stroke.virtual_key.get());
|
||||||
const auto key = key_search != vk_pretty.end()
|
const auto key_search = kVkPretty.find(virtual_key);
|
||||||
? key_search->second
|
std::string key =
|
||||||
: fmt::format("0x{:04x}", stroke.virtual_key);
|
key_search != kVkPretty.cend()
|
||||||
|
? key_search->second
|
||||||
|
: fmt::format("0x{:04x}", uint16_t(virtual_key));
|
||||||
event_log.emplace_front(fmt::format(
|
event_log.emplace_front(fmt::format(
|
||||||
"{:>6} {:>9}ms {:<20} {} {} {}", ImGui::GetFrameCount(),
|
"{:>6} {:>9}ms {:<20} {} {} {}", ImGui::GetFrameCount(),
|
||||||
dur, key,
|
dur, key,
|
||||||
|
|
|
@ -46,43 +46,7 @@ enum X_INPUT_GAMEPAD_BUTTON {
|
||||||
X_INPUT_GAMEPAD_Y = 0x8000,
|
X_INPUT_GAMEPAD_Y = 0x8000,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum X_INPUT_GAMEPAD_VK {
|
// For VK_PAD, use ui::VirtualKey.
|
||||||
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,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum X_INPUT_KEYSTROKE_FLAGS {
|
enum X_INPUT_KEYSTROKE_FLAGS {
|
||||||
X_INPUT_KEYSTROKE_KEYDOWN = 0x0001,
|
X_INPUT_KEYSTROKE_KEYDOWN = 0x0001,
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/helper/sdl/sdl_helper.h"
|
#include "xenia/helper/sdl/sdl_helper.h"
|
||||||
#include "xenia/hid/hid_flags.h"
|
#include "xenia/hid/hid_flags.h"
|
||||||
|
#include "xenia/ui/virtual_key.h"
|
||||||
#include "xenia/ui/window.h"
|
#include "xenia/ui/window.h"
|
||||||
|
|
||||||
// TODO(joellinn) make this path relative to the config folder.
|
// 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
|
// The order of this list is also the order in which events are send if
|
||||||
// multiple buttons change at once.
|
// multiple buttons change at once.
|
||||||
static_assert(sizeof(X_INPUT_GAMEPAD::buttons) == 2);
|
static_assert(sizeof(X_INPUT_GAMEPAD::buttons) == 2);
|
||||||
static constexpr std::array<std::underlying_type<X_INPUT_GAMEPAD_VK>::type,
|
static constexpr std::array<ui::VirtualKey, 34> kVkLookup = {
|
||||||
34>
|
// 00 - True buttons from xinput button field
|
||||||
vk_lookup = {
|
ui::VirtualKey::kXInputPadDpadUp,
|
||||||
// 00 - True buttons from xinput button field
|
ui::VirtualKey::kXInputPadDpadDown,
|
||||||
X_INPUT_GAMEPAD_VK_DPAD_UP,
|
ui::VirtualKey::kXInputPadDpadLeft,
|
||||||
X_INPUT_GAMEPAD_VK_DPAD_DOWN,
|
ui::VirtualKey::kXInputPadDpadRight,
|
||||||
X_INPUT_GAMEPAD_VK_DPAD_LEFT,
|
ui::VirtualKey::kXInputPadStart,
|
||||||
X_INPUT_GAMEPAD_VK_DPAD_RIGHT,
|
ui::VirtualKey::kXInputPadBack,
|
||||||
X_INPUT_GAMEPAD_VK_START,
|
ui::VirtualKey::kXInputPadLThumbPress,
|
||||||
X_INPUT_GAMEPAD_VK_BACK,
|
ui::VirtualKey::kXInputPadRThumbPress,
|
||||||
X_INPUT_GAMEPAD_VK_LTHUMB_PRESS,
|
ui::VirtualKey::kXInputPadLShoulder,
|
||||||
X_INPUT_GAMEPAD_VK_RTHUMB_PRESS,
|
ui::VirtualKey::kXInputPadRShoulder,
|
||||||
X_INPUT_GAMEPAD_VK_LSHOULDER,
|
ui::VirtualKey::kNone, /* Guide has no VK */
|
||||||
X_INPUT_GAMEPAD_VK_RSHOULDER,
|
ui::VirtualKey::kNone, /* Unknown */
|
||||||
0, /* Guide has no VK */
|
ui::VirtualKey::kXInputPadA,
|
||||||
0, /* Unknown */
|
ui::VirtualKey::kXInputPadB,
|
||||||
X_INPUT_GAMEPAD_VK_A,
|
ui::VirtualKey::kXInputPadX,
|
||||||
X_INPUT_GAMEPAD_VK_B,
|
ui::VirtualKey::kXInputPadY,
|
||||||
X_INPUT_GAMEPAD_VK_X,
|
// 16 - Fake buttons generated from analog inputs
|
||||||
X_INPUT_GAMEPAD_VK_Y,
|
ui::VirtualKey::kXInputPadLTrigger,
|
||||||
// 16 - Fake buttons generated from analog inputs
|
ui::VirtualKey::kXInputPadRTrigger,
|
||||||
X_INPUT_GAMEPAD_VK_LTRIGGER,
|
// 18
|
||||||
X_INPUT_GAMEPAD_VK_RTRIGGER,
|
ui::VirtualKey::kXInputPadLThumbUp,
|
||||||
// 18
|
ui::VirtualKey::kXInputPadLThumbDown,
|
||||||
X_INPUT_GAMEPAD_VK_LTHUMB_UP,
|
ui::VirtualKey::kXInputPadLThumbRight,
|
||||||
X_INPUT_GAMEPAD_VK_LTHUMB_DOWN,
|
ui::VirtualKey::kXInputPadLThumbLeft,
|
||||||
X_INPUT_GAMEPAD_VK_LTHUMB_RIGHT,
|
ui::VirtualKey::kXInputPadLThumbUpLeft,
|
||||||
X_INPUT_GAMEPAD_VK_LTHUMB_LEFT,
|
ui::VirtualKey::kXInputPadLThumbUpRight,
|
||||||
X_INPUT_GAMEPAD_VK_LTHUMB_UPLEFT,
|
ui::VirtualKey::kXInputPadLThumbDownRight,
|
||||||
X_INPUT_GAMEPAD_VK_LTHUMB_UPRIGHT,
|
ui::VirtualKey::kXInputPadLThumbDownLeft,
|
||||||
X_INPUT_GAMEPAD_VK_LTHUMB_DOWNRIGHT,
|
// 26
|
||||||
X_INPUT_GAMEPAD_VK_LTHUMB_DOWNLEFT,
|
ui::VirtualKey::kXInputPadRThumbUp,
|
||||||
// 26
|
ui::VirtualKey::kXInputPadRThumbDown,
|
||||||
X_INPUT_GAMEPAD_VK_RTHUMB_UP,
|
ui::VirtualKey::kXInputPadRThumbRight,
|
||||||
X_INPUT_GAMEPAD_VK_RTHUMB_DOWN,
|
ui::VirtualKey::kXInputPadRThumbLeft,
|
||||||
X_INPUT_GAMEPAD_VK_RTHUMB_RIGHT,
|
ui::VirtualKey::kXInputPadRThumbUpLeft,
|
||||||
X_INPUT_GAMEPAD_VK_RTHUMB_LEFT,
|
ui::VirtualKey::kXInputPadRThumbUpRight,
|
||||||
X_INPUT_GAMEPAD_VK_RTHUMB_UPLEFT,
|
ui::VirtualKey::kXInputPadRThumbDownRight,
|
||||||
X_INPUT_GAMEPAD_VK_RTHUMB_UPRIGHT,
|
ui::VirtualKey::kXInputPadRThumbDownLeft,
|
||||||
X_INPUT_GAMEPAD_VK_RTHUMB_DOWNRIGHT,
|
};
|
||||||
X_INPUT_GAMEPAD_VK_RTHUMB_DOWNLEFT,
|
|
||||||
};
|
|
||||||
|
|
||||||
auto is_active = this->is_active();
|
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 &&
|
if (last.repeat_state == RepeatState::Repeating &&
|
||||||
(last.repeat_time + HID_SDL_REPEAT_RATE < guest_now)) {
|
(last.repeat_time + HID_SDL_REPEAT_RATE < guest_now)) {
|
||||||
last.repeat_time = guest_now;
|
last.repeat_time = guest_now;
|
||||||
auto vk = vk_lookup.at(last.repeat_butt_idx);
|
ui::VirtualKey vk = kVkLookup.at(last.repeat_butt_idx);
|
||||||
assert_not_zero(vk);
|
assert_true(vk != ui::VirtualKey::kNone);
|
||||||
out_keystroke->virtual_key = vk;
|
out_keystroke->virtual_key = uint16_t(vk);
|
||||||
out_keystroke->unicode = 0;
|
out_keystroke->unicode = 0;
|
||||||
out_keystroke->user_index = user_index;
|
out_keystroke->user_index = user_index;
|
||||||
out_keystroke->hid_code = 0;
|
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.
|
// up before THUMB_LEFT is down.
|
||||||
for (auto [clear_pass, i] = std::tuple{true, 0}; i < 2;
|
for (auto [clear_pass, i] = std::tuple{true, 0}; i < 2;
|
||||||
clear_pass = false, i++) {
|
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;
|
auto fbutton = uint64_t(1) << i;
|
||||||
if (!(butts_changed & fbutton)) {
|
if (!(butts_changed & fbutton)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto vk = vk_lookup.at(i);
|
ui::VirtualKey vk = kVkLookup.at(last.repeat_butt_idx);
|
||||||
if (!vk) {
|
if (vk == ui::VirtualKey::kNone) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_keystroke->virtual_key = vk;
|
out_keystroke->virtual_key = uint16_t(vk);
|
||||||
out_keystroke->unicode = 0;
|
out_keystroke->unicode = 0;
|
||||||
out_keystroke->user_index = user_index;
|
out_keystroke->user_index = user_index;
|
||||||
out_keystroke->hid_code = 0;
|
out_keystroke->hid_code = 0;
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "xenia/base/platform_win.h"
|
#include "xenia/base/platform_win.h"
|
||||||
#include "xenia/hid/hid_flags.h"
|
#include "xenia/hid/hid_flags.h"
|
||||||
#include "xenia/hid/input_system.h"
|
#include "xenia/hid/input_system.h"
|
||||||
|
#include "xenia/ui/virtual_key.h"
|
||||||
#include "xenia/ui/window.h"
|
#include "xenia/ui/window.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
@ -29,7 +30,7 @@ WinKeyInputDriver::WinKeyInputDriver(xe::ui::Window* window)
|
||||||
auto global_lock = global_critical_region_.Acquire();
|
auto global_lock = global_critical_region_.Acquire();
|
||||||
|
|
||||||
KeyEvent key;
|
KeyEvent key;
|
||||||
key.vkey = evt->key_code();
|
key.virtual_key = evt->virtual_key();
|
||||||
key.transition = true;
|
key.transition = true;
|
||||||
key.prev_state = evt->prev_state();
|
key.prev_state = evt->prev_state();
|
||||||
key.repeat_count = evt->repeat_count();
|
key.repeat_count = evt->repeat_count();
|
||||||
|
@ -43,7 +44,7 @@ WinKeyInputDriver::WinKeyInputDriver(xe::ui::Window* window)
|
||||||
auto global_lock = global_critical_region_.Acquire();
|
auto global_lock = global_critical_region_.Acquire();
|
||||||
|
|
||||||
KeyEvent key;
|
KeyEvent key;
|
||||||
key.vkey = evt->key_code();
|
key.virtual_key = evt->virtual_key();
|
||||||
key.transition = false;
|
key.transition = false;
|
||||||
key.prev_state = evt->prev_state();
|
key.prev_state = evt->prev_state();
|
||||||
key.repeat_count = evt->repeat_count();
|
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;
|
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 unicode = 0;
|
||||||
uint16_t keystroke_flags = 0;
|
uint16_t keystroke_flags = 0;
|
||||||
uint8_t hid_code = 0;
|
uint8_t hid_code = 0;
|
||||||
|
@ -258,100 +259,93 @@ X_RESULT WinKeyInputDriver::GetKeystroke(uint32_t user_index, uint32_t flags,
|
||||||
key_events_.pop();
|
key_events_.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(DrChat): Some other way to toggle this...
|
switch (evt.virtual_key) {
|
||||||
if (IS_KEY_TOGGLED(VK_CAPITAL)) {
|
case ui::VirtualKey::kOem1: // ;
|
||||||
// dpad toggled
|
xinput_virtual_key = ui::VirtualKey::kXInputPadA;
|
||||||
if (evt.vkey == (0x41)) {
|
break;
|
||||||
// A
|
case ui::VirtualKey::kOem7: // '
|
||||||
virtual_key = 0x5812; // VK_PAD_DPAD_LEFT
|
xinput_virtual_key = ui::VirtualKey::kXInputPadB;
|
||||||
} else if (evt.vkey == (0x44)) {
|
break;
|
||||||
// D
|
case ui::VirtualKey::kL:
|
||||||
virtual_key = 0x5813; // VK_PAD_DPAD_RIGHT
|
xinput_virtual_key = ui::VirtualKey::kXInputPadX;
|
||||||
} else if (evt.vkey == (0x53)) {
|
break;
|
||||||
// S
|
case ui::VirtualKey::kP:
|
||||||
virtual_key = 0x5811; // VK_PAD_DPAD_DOWN
|
xinput_virtual_key = ui::VirtualKey::kXInputPadY;
|
||||||
} else if (evt.vkey == (0x57)) {
|
break;
|
||||||
// W
|
case ui::VirtualKey::k3:
|
||||||
virtual_key = 0x5810; // VK_PAD_DPAD_UP
|
xinput_virtual_key = ui::VirtualKey::kXInputPadRShoulder;
|
||||||
}
|
break;
|
||||||
} else {
|
case ui::VirtualKey::k1:
|
||||||
// left stick
|
xinput_virtual_key = ui::VirtualKey::kXInputPadLShoulder;
|
||||||
if (evt.vkey == (0x57)) {
|
break;
|
||||||
// W
|
case ui::VirtualKey::kQ:
|
||||||
virtual_key = 0x5820; // VK_PAD_LTHUMB_UP
|
case ui::VirtualKey::kI:
|
||||||
}
|
xinput_virtual_key = ui::VirtualKey::kXInputPadLTrigger;
|
||||||
if (evt.vkey == (0x53)) {
|
break;
|
||||||
// S
|
case ui::VirtualKey::kE:
|
||||||
virtual_key = 0x5821; // VK_PAD_LTHUMB_DOWN
|
case ui::VirtualKey::kO:
|
||||||
}
|
xinput_virtual_key = ui::VirtualKey::kXInputPadRTrigger;
|
||||||
if (evt.vkey == (0x44)) {
|
break;
|
||||||
// D
|
case ui::VirtualKey::kX:
|
||||||
virtual_key = 0x5822; // VK_PAD_LTHUMB_RIGHT
|
xinput_virtual_key = ui::VirtualKey::kXInputPadStart;
|
||||||
}
|
break;
|
||||||
if (evt.vkey == (0x41)) {
|
case ui::VirtualKey::kZ:
|
||||||
// A
|
xinput_virtual_key = ui::VirtualKey::kXInputPadBack;
|
||||||
virtual_key = 0x5823; // VK_PAD_LTHUMB_LEFT
|
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 (xinput_virtual_key != ui::VirtualKey::kNone) {
|
||||||
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 (evt.transition == true) {
|
if (evt.transition == true) {
|
||||||
keystroke_flags |= 0x0001; // XINPUT_KEYSTROKE_KEYDOWN
|
keystroke_flags |= 0x0001; // XINPUT_KEYSTROKE_KEYDOWN
|
||||||
} else if (evt.transition == false) {
|
} else if (evt.transition == false) {
|
||||||
|
@ -365,7 +359,7 @@ X_RESULT WinKeyInputDriver::GetKeystroke(uint32_t user_index, uint32_t flags,
|
||||||
result = X_ERROR_SUCCESS;
|
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->unicode = unicode;
|
||||||
out_keystroke->flags = keystroke_flags;
|
out_keystroke->flags = keystroke_flags;
|
||||||
out_keystroke->user_index = 0;
|
out_keystroke->user_index = 0;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "xenia/base/mutex.h"
|
#include "xenia/base/mutex.h"
|
||||||
#include "xenia/hid/input_driver.h"
|
#include "xenia/hid/input_driver.h"
|
||||||
|
#include "xenia/ui/virtual_key.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace hid {
|
namespace hid {
|
||||||
|
@ -35,7 +36,7 @@ class WinKeyInputDriver : public InputDriver {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct KeyEvent {
|
struct KeyEvent {
|
||||||
int vkey = 0;
|
ui::VirtualKey virtual_key = ui::VirtualKey::kNone;
|
||||||
int repeat_count = 0;
|
int repeat_count = 0;
|
||||||
bool transition = false; // going up(false) or going down(true)
|
bool transition = false; // going up(false) or going down(true)
|
||||||
bool prev_state = false; // down(true) or up(false)
|
bool prev_state = false; // down(true) or up(false)
|
||||||
|
|
|
@ -2,13 +2,12 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* 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. *
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Post-include file for an export table.
|
// Post-include file for an export table.
|
||||||
|
|
||||||
|
|
||||||
#undef FLAG
|
#undef FLAG
|
||||||
#undef XE_EXPORT
|
#undef XE_EXPORT
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* 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. *
|
* 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));
|
* my_module_export_table, xe::countof(my_module_export_table));
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#define XE_EXPORT(module, ordinal, name, type) \
|
#define XE_EXPORT(module, ordinal, name, type) \
|
||||||
xe::cpu::Export(ordinal, xe::cpu::Export::Type::type, #name)
|
xe::cpu::Export(ordinal, xe::cpu::Export::Type::type, #name)
|
||||||
|
|
||||||
#define FLAG(t) kXEKernelExportFlag##t
|
#define FLAG(t) kXEKernelExportFlag##t
|
||||||
|
|
|
@ -2,12 +2,11 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* 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. *
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Post-include file for an ordinal table.
|
// Post-include file for an ordinal table.
|
||||||
|
|
||||||
|
|
||||||
#undef XE_EXPORT
|
#undef XE_EXPORT
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* 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. *
|
* 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"
|
* #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
|
|
||||||
|
|
||||||
|
|
|
@ -57,8 +57,7 @@ X_HRESULT XamApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
|
||||||
std::memset(buffer, 0, data->buffer_size);
|
std::memset(buffer, 0, data->buffer_size);
|
||||||
}
|
}
|
||||||
uint32_t item_count = 0;
|
uint32_t item_count = 0;
|
||||||
auto result = e->WriteItems(data->buffer_ptr, buffer, data->buffer_size,
|
auto result = e->WriteItems(data->buffer_ptr, buffer, &item_count);
|
||||||
&item_count);
|
|
||||||
|
|
||||||
if (result == X_ERROR_SUCCESS && item_count >= 1) {
|
if (result == X_ERROR_SUCCESS && item_count >= 1) {
|
||||||
if (data->length_ptr) {
|
if (data->length_ptr) {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* 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. *
|
* 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;
|
return X_E_SUCCESS;
|
||||||
}
|
}
|
||||||
case 0x000B0011: {
|
case 0x000B0011: {
|
||||||
// TODO(DrChat): Figure out what this is again
|
// TODO(PermaNull): reverse buffer contents.
|
||||||
} break;
|
XELOGD("XGISessionDelete");
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
case 0x000B0012: {
|
case 0x000B0012: {
|
||||||
assert_true(buffer_length == 0x14);
|
assert_true(buffer_length == 0x14);
|
||||||
uint32_t session_ptr = xe::load_and_swap<uint32_t>(buffer + 0x0);
|
uint32_t session_ptr = xe::load_and_swap<uint32_t>(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);
|
user_count, unk_0, user_index_array, private_slots_array);
|
||||||
return X_E_SUCCESS;
|
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: {
|
case 0x000B0041: {
|
||||||
assert_true(!buffer_length || buffer_length == 32);
|
assert_true(!buffer_length || buffer_length == 32);
|
||||||
// 00000000 2789fecc 00000000 00000000 200491e0 00000000 200491f0 20049340
|
// 00000000 2789fecc 00000000 00000000 200491e0 00000000 200491f0 20049340
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* 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. *
|
* 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<uint32_t>(buffer + 0, 1); // XONLINE_NAT_OPEN
|
xe::store_and_swap<uint32_t>(buffer + 0, 1); // XONLINE_NAT_OPEN
|
||||||
return X_E_SUCCESS;
|
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: {
|
case 0x00058020: {
|
||||||
// 0x00058004 is called right before this.
|
// 0x00058004 is called right before this.
|
||||||
// We should create a XamEnumerate-able empty list here, but I'm not
|
// We should create a XamEnumerate-able empty list here, but I'm not
|
||||||
// sure of the format.
|
// sure of the format.
|
||||||
// buffer_length seems to be the same ptr sent to 0x00058004.
|
// 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);
|
buffer_ptr, buffer_length);
|
||||||
return X_E_FAIL;
|
return X_E_FAIL;
|
||||||
}
|
}
|
||||||
case 0x00058023: {
|
case 0x00058023: {
|
||||||
XELOGD("XliveBaseUnk58023({:08X}, {:08X}) unimplemented", buffer_ptr,
|
XELOGD(
|
||||||
buffer_length);
|
"CXLiveMessaging::XMessageGameInviteGetAcceptedInfo({:08X}, {:08X}) "
|
||||||
|
"unimplemented",
|
||||||
|
buffer_ptr, buffer_length);
|
||||||
return X_E_FAIL;
|
return X_E_FAIL;
|
||||||
}
|
}
|
||||||
case 0x00058046: {
|
case 0x00058046: {
|
||||||
|
|
|
@ -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;
|
*buffer_size_ptr = sizeof(XCONTENT_DATA) * items_per_enumerate;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto e = object_ref<XStaticEnumerator>(new XStaticEnumerator(
|
auto e = make_object<XStaticEnumerator<XCONTENT_DATA>>(kernel_state(),
|
||||||
kernel_state(), items_per_enumerate, sizeof(XCONTENT_DATA)));
|
items_per_enumerate);
|
||||||
auto result = e->Initialize(0xFF, 0xFE, 0x20005, 0x20007, 0);
|
auto result = e->Initialize(0xFF, 0xFE, 0x20005, 0x20007, 0);
|
||||||
if (XFAILED(result)) {
|
if (XFAILED(result)) {
|
||||||
return result;
|
return result;
|
||||||
|
@ -99,8 +99,7 @@ dword_result_t XamContentCreateEnumerator(dword_t user_index, dword_t device_id,
|
||||||
static_cast<uint32_t>(DummyDeviceId::HDD),
|
static_cast<uint32_t>(DummyDeviceId::HDD),
|
||||||
XContentType(uint32_t(content_type)));
|
XContentType(uint32_t(content_type)));
|
||||||
for (const auto& content_data : content_datas) {
|
for (const auto& content_data : content_datas) {
|
||||||
auto item = reinterpret_cast<XCONTENT_DATA*>(e->AppendItem());
|
auto item = e->AppendItem();
|
||||||
assert_not_null(item);
|
|
||||||
*item = content_data;
|
*item = content_data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,7 +123,6 @@ dword_result_t xeXamContentCreate(dword_t user_index, lpstring_t root_name,
|
||||||
lpdword_t license_mask_ptr,
|
lpdword_t license_mask_ptr,
|
||||||
dword_t cache_size, qword_t content_size,
|
dword_t cache_size, qword_t content_size,
|
||||||
lpvoid_t overlapped_ptr) {
|
lpvoid_t overlapped_ptr) {
|
||||||
X_RESULT result = X_ERROR_INVALID_PARAMETER;
|
|
||||||
XCONTENT_AGGREGATE_DATA content_data;
|
XCONTENT_AGGREGATE_DATA content_data;
|
||||||
if (content_data_size == sizeof(XCONTENT_DATA)) {
|
if (content_data_size == sizeof(XCONTENT_DATA)) {
|
||||||
content_data = *content_data_ptr.as<XCONTENT_DATA*>();
|
content_data = *content_data_ptr.as<XCONTENT_DATA*>();
|
||||||
|
@ -132,91 +130,99 @@ dword_result_t xeXamContentCreate(dword_t user_index, lpstring_t root_name,
|
||||||
content_data = *content_data_ptr.as<XCONTENT_AGGREGATE_DATA*>();
|
content_data = *content_data_ptr.as<XCONTENT_AGGREGATE_DATA*>();
|
||||||
} else {
|
} else {
|
||||||
assert_always();
|
assert_always();
|
||||||
return result;
|
return X_ERROR_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto content_manager = kernel_state()->content_manager();
|
auto content_manager = kernel_state()->content_manager();
|
||||||
bool create = false;
|
|
||||||
bool open = false;
|
if (overlapped_ptr && disposition_ptr) {
|
||||||
switch (flags & 0xF) {
|
*disposition_ptr = 0;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// creation result
|
auto run = [content_manager, root_name, flags, content_data, disposition_ptr,
|
||||||
// 0 = ?
|
license_mask_ptr](uint32_t& extended_error,
|
||||||
// 1 = created
|
uint32_t& length) -> X_RESULT {
|
||||||
// 2 = opened
|
X_RESULT result = X_ERROR_INVALID_PARAMETER;
|
||||||
uint32_t disposition = create ? 1 : 2;
|
bool create = false;
|
||||||
if (disposition_ptr) {
|
bool open = false;
|
||||||
// In case when overlapped_ptr exist we should clear disposition_ptr first
|
switch (flags & 0xF) {
|
||||||
// however we're executing it immediately, so it's not required
|
case 1: // CREATE_NEW
|
||||||
*disposition_ptr = disposition;
|
// Fail if exists.
|
||||||
}
|
if (content_manager->ContentExists(content_data)) {
|
||||||
|
result = X_ERROR_ALREADY_EXISTS;
|
||||||
if (create) {
|
} else {
|
||||||
result = content_manager->CreateContent(root_name.value(), content_data);
|
create = true;
|
||||||
} else if (open) {
|
}
|
||||||
result = content_manager->OpenContent(root_name.value(), content_data);
|
break;
|
||||||
}
|
case 2: // CREATE_ALWAYS
|
||||||
|
// Overwrite existing, if any.
|
||||||
if (license_mask_ptr && XSUCCEEDED(result)) {
|
if (content_manager->ContentExists(content_data)) {
|
||||||
*license_mask_ptr = 0; // Stub!
|
content_manager->DeleteContent(content_data);
|
||||||
}
|
create = true;
|
||||||
|
} else {
|
||||||
if (overlapped_ptr) {
|
create = true;
|
||||||
X_RESULT extended_error = X_HRESULT_FROM_WIN32(result);
|
}
|
||||||
if (int32_t(extended_error) < 0) {
|
break;
|
||||||
result = X_ERROR_FUNCTION_FAILED;
|
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);
|
// creation result
|
||||||
return X_ERROR_IO_PENDING;
|
// 0 = ?
|
||||||
} else {
|
// 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;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
namespace xam {
|
namespace xam {
|
||||||
|
|
||||||
void AddODDContentTest(object_ref<XStaticEnumerator> e,
|
void AddODDContentTest(object_ref<XStaticEnumerator<XCONTENT_AGGREGATE_DATA>> e,
|
||||||
XContentType content_type) {
|
XContentType content_type) {
|
||||||
auto root_entry = kernel_state()->file_system()->ResolvePath(
|
auto root_entry = kernel_state()->file_system()->ResolvePath(
|
||||||
"game:\\Content\\0000000000000000");
|
"game:\\Content\\0000000000000000");
|
||||||
|
@ -62,13 +62,15 @@ void AddODDContentTest(object_ref<XStaticEnumerator> e,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto item = reinterpret_cast<XCONTENT_AGGREGATE_DATA*>(e->AppendItem());
|
auto item = e->AppendItem();
|
||||||
assert_not_null(item);
|
assert_not_null(item);
|
||||||
item->device_id = static_cast<uint32_t>(DummyDeviceId::ODD);
|
if (item) {
|
||||||
item->content_type = content_type;
|
item->device_id = static_cast<uint32_t>(DummyDeviceId::ODD);
|
||||||
item->set_display_name(to_utf16(content_entry->name()));
|
item->content_type = content_type;
|
||||||
item->set_file_name(content_entry->name());
|
item->set_display_name(to_utf16(content_entry->name()));
|
||||||
item->title_id = title_id;
|
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;
|
return X_E_INVALIDARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto e = object_ref<XStaticEnumerator>(new XStaticEnumerator(
|
auto e = make_object<XStaticEnumerator<XCONTENT_AGGREGATE_DATA>>(
|
||||||
kernel_state(), 1, sizeof(XCONTENT_AGGREGATE_DATA)));
|
kernel_state(), 1);
|
||||||
X_KENUMERATOR_CONTENT_AGGREGATE* extra;
|
X_KENUMERATOR_CONTENT_AGGREGATE* extra;
|
||||||
auto result = e->Initialize(0xFF, 0xFE, 0x2000E, 0x20010, 0, &extra);
|
auto result = e->Initialize(0xFF, 0xFE, 0x2000E, 0x20010, 0, &extra);
|
||||||
if (XFAILED(result)) {
|
if (XFAILED(result)) {
|
||||||
|
@ -116,9 +118,11 @@ dword_result_t XamContentAggregateCreateEnumerator(qword_t xuid,
|
||||||
static_cast<uint32_t>(DummyDeviceId::HDD), content_type_enum,
|
static_cast<uint32_t>(DummyDeviceId::HDD), content_type_enum,
|
||||||
title_id);
|
title_id);
|
||||||
for (const auto& content_data : content_datas) {
|
for (const auto& content_data : content_datas) {
|
||||||
auto item = reinterpret_cast<XCONTENT_AGGREGATE_DATA*>(e->AppendItem());
|
auto item = e->AppendItem();
|
||||||
assert_not_null(item);
|
assert_not_null(item);
|
||||||
*item = content_data;
|
if (item) {
|
||||||
|
*item = content_data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,8 +139,8 @@ dword_result_t XamContentCreateDeviceEnumerator(dword_t content_type,
|
||||||
*buffer_size_ptr = sizeof(X_CONTENT_DEVICE_DATA) * max_count;
|
*buffer_size_ptr = sizeof(X_CONTENT_DEVICE_DATA) * max_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto e = object_ref<XStaticEnumerator>(new XStaticEnumerator(
|
auto e = make_object<XStaticEnumerator<X_CONTENT_DEVICE_DATA>>(kernel_state(),
|
||||||
kernel_state(), max_count, sizeof(X_CONTENT_DEVICE_DATA)));
|
max_count);
|
||||||
auto result = e->Initialize(0xFE, 0xFE, 0x2000A, 0x20009, 0);
|
auto result = e->Initialize(0xFE, 0xFE, 0x2000A, 0x20009, 0);
|
||||||
if (XFAILED(result)) {
|
if (XFAILED(result)) {
|
||||||
return result;
|
return result;
|
||||||
|
@ -148,7 +148,8 @@ dword_result_t XamContentCreateDeviceEnumerator(dword_t content_type,
|
||||||
|
|
||||||
for (const auto& device_info : dummy_device_infos_) {
|
for (const auto& device_info : dummy_device_infos_) {
|
||||||
// Copy our dummy device into the enumerator
|
// 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) {
|
if (device_data) {
|
||||||
device_data->device_id = static_cast<uint32_t>(device_info->device_id);
|
device_data->device_id = static_cast<uint32_t>(device_info->device_id);
|
||||||
device_data->device_type =
|
device_data->device_type =
|
||||||
|
|
|
@ -32,49 +32,37 @@ uint32_t xeXamEnumerate(uint32_t handle, uint32_t flags, lpvoid_t buffer_ptr,
|
||||||
uint32_t overlapped_ptr) {
|
uint32_t overlapped_ptr) {
|
||||||
assert_true(flags == 0);
|
assert_true(flags == 0);
|
||||||
|
|
||||||
X_RESULT result;
|
|
||||||
uint32_t item_count = 0;
|
|
||||||
|
|
||||||
auto e = kernel_state()->object_table()->LookupObject<XEnumerator>(handle);
|
auto e = kernel_state()->object_table()->LookupObject<XEnumerator>(handle);
|
||||||
if (!e) {
|
if (!e) {
|
||||||
result = X_ERROR_INVALID_HANDLE;
|
return 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<uint32_t>(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<uint8_t*>(),
|
|
||||||
actual_buffer_size, &item_count);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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<uint8_t*>(), &item_count);
|
||||||
|
}
|
||||||
|
extended_error = X_HRESULT_FROM_WIN32(result);
|
||||||
|
length = item_count;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
if (items_returned) {
|
if (items_returned) {
|
||||||
assert_true(!overlapped_ptr);
|
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;
|
*items_returned = result == X_ERROR_SUCCESS ? item_count : 0;
|
||||||
return result;
|
return result;
|
||||||
} else if (overlapped_ptr) {
|
} else if (overlapped_ptr) {
|
||||||
assert_true(!items_returned);
|
assert_true(!items_returned);
|
||||||
kernel_state()->CompleteOverlappedImmediateEx(
|
kernel_state()->CompleteOverlappedDeferredEx(run, overlapped_ptr);
|
||||||
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);
|
|
||||||
return X_ERROR_IO_PENDING;
|
return X_ERROR_IO_PENDING;
|
||||||
} else {
|
} else {
|
||||||
assert_always();
|
assert_always();
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* 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. *
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* 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. *
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
@ -306,9 +306,11 @@ 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);
|
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
|
// If the socket is a VDP socket, buffer 0 is the game data length, and buffer 1
|
||||||
// is the unencrypted game data.
|
// is the unencrypted game data.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* 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. *
|
* 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
|
// This is a partial file designed to be included by other files when
|
||||||
// constructing various tables.
|
// constructing various tables.
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
XE_EXPORT(xam, 0x00000001, NetDll_WSAStartup, kFunction),
|
XE_EXPORT(xam, 0x00000001, NetDll_WSAStartup, kFunction),
|
||||||
XE_EXPORT(xam, 0x00000002, NetDll_WSACleanup, kFunction),
|
XE_EXPORT(xam, 0x00000002, NetDll_WSACleanup, kFunction),
|
||||||
|
|
|
@ -277,8 +277,9 @@ uint32_t xeXamUserReadProfileSettingsEx(uint32_t title_id, uint32_t user_index,
|
||||||
auto setting = user_profile->GetSetting(setting_id);
|
auto setting = user_profile->GetSetting(setting_id);
|
||||||
|
|
||||||
std::memset(out_setting, 0, sizeof(X_USER_READ_PROFILE_SETTING));
|
std::memset(out_setting, 0, sizeof(X_USER_READ_PROFILE_SETTING));
|
||||||
out_setting->from =
|
out_setting->from = !setting || !setting->is_set ? 0
|
||||||
!setting || !setting->is_set ? 0 : setting->is_title_specific() ? 2 : 1;
|
: setting->is_title_specific() ? 2
|
||||||
|
: 1;
|
||||||
out_setting->user_index = static_cast<uint32_t>(user_index);
|
out_setting->user_index = static_cast<uint32_t>(user_index);
|
||||||
out_setting->setting_id = setting_id;
|
out_setting->setting_id = setting_id;
|
||||||
|
|
||||||
|
@ -547,7 +548,8 @@ DECLARE_XAM_EXPORT1(XamUserAreUsersFriends, kUserProfiles, kStub);
|
||||||
dword_result_t XamShowSigninUI(dword_t unk, dword_t unk_mask) {
|
dword_result_t XamShowSigninUI(dword_t unk, dword_t unk_mask) {
|
||||||
// Mask values vary. Probably matching user types? Local/remote?
|
// 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
|
// XN_SYS_SIGNINCHANGED
|
||||||
kernel_state()->BroadcastNotification(0x0000000A, 1);
|
kernel_state()->BroadcastNotification(0x0000000A, 1);
|
||||||
// Games seem to sit and loop until we trigger this notification:
|
// Games seem to sit and loop until we trigger this notification:
|
||||||
|
@ -606,7 +608,7 @@ class XStaticAchievementEnumerator : public XEnumerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data,
|
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 =
|
size_t count =
|
||||||
std::min(items_.size() - current_item_, items_per_enumerate());
|
std::min(items_.size() - current_item_, items_per_enumerate());
|
||||||
if (!count) {
|
if (!count) {
|
||||||
|
@ -614,9 +616,6 @@ class XStaticAchievementEnumerator : public XEnumerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size = count * item_size();
|
size_t size = count * item_size();
|
||||||
if (size > buffer_size) {
|
|
||||||
return X_ERROR_INSUFFICIENT_BUFFER;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto details = reinterpret_cast<X_ACHIEVEMENT_DETAILS*>(buffer_data);
|
auto details = reinterpret_cast<X_ACHIEVEMENT_DETAILS*>(buffer_data);
|
||||||
size_t string_offset =
|
size_t string_offset =
|
||||||
|
@ -778,8 +777,10 @@ DECLARE_XAM_EXPORT1(XamSessionCreateHandle, kUserProfiles, kStub);
|
||||||
|
|
||||||
dword_result_t XamSessionRefObjByHandle(dword_t handle, lpdword_t obj_ptr) {
|
dword_result_t XamSessionRefObjByHandle(dword_t handle, lpdword_t obj_ptr) {
|
||||||
assert_true(handle == 0xCAFEDEAD);
|
assert_true(handle == 0xCAFEDEAD);
|
||||||
*obj_ptr = 0;
|
// TODO(PermaNull): Implement this properly,
|
||||||
return X_ERROR_FUNCTION_FAILED;
|
// For the time being returning 0xDEADF00D will prevent crashing.
|
||||||
|
*obj_ptr = 0xDEADF00D;
|
||||||
|
return X_ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
DECLARE_XAM_EXPORT1(XamSessionRefObjByHandle, kUserProfiles, kStub);
|
DECLARE_XAM_EXPORT1(XamSessionRefObjByHandle, kUserProfiles, kStub);
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* 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. *
|
* 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
|
// This is a partial file designed to be included by other files when
|
||||||
// constructing various tables.
|
// constructing various tables.
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
XE_EXPORT(xbdm, 0x00000001, DmAllocatePool, kFunction),
|
XE_EXPORT(xbdm, 0x00000001, DmAllocatePool, kFunction),
|
||||||
XE_EXPORT(xbdm, 0x00000002, DmAllocatePoolWithTag, kFunction),
|
XE_EXPORT(xbdm, 0x00000002, DmAllocatePoolWithTag, kFunction),
|
||||||
|
|
|
@ -997,7 +997,7 @@ uint32_t xeRtlNtStatusToDosError(uint32_t source_status) {
|
||||||
if (!result) {
|
if (!result) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
XELOGI("RtlNtStatusToDosError {:X} => {:X}", status, result);
|
XELOGI("xeRtlNtStatusToDosError {:X} => {:X}", status, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
++error_table;
|
++error_table;
|
||||||
|
@ -1007,7 +1007,7 @@ uint32_t xeRtlNtStatusToDosError(uint32_t source_status) {
|
||||||
return status & 0xFFFF;
|
return status & 0xFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
XELOGE("RtlNtStatusToDosError lookup NOT IMPLEMENTED");
|
XELOGE("xeRtlNtStatusToDosError lookup NOT IMPLEMENTED");
|
||||||
return 317; // ERROR_MR_MID_NOT_FOUND
|
return 317; // ERROR_MR_MID_NOT_FOUND
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -357,11 +357,7 @@ dword_result_t NtWriteFile(dword_t file_handle, dword_t event_handle,
|
||||||
pointer_t<X_IO_STATUS_BLOCK> io_status_block,
|
pointer_t<X_IO_STATUS_BLOCK> io_status_block,
|
||||||
lpvoid_t buffer, dword_t buffer_length,
|
lpvoid_t buffer, dword_t buffer_length,
|
||||||
lpqword_t byte_offset_ptr) {
|
lpqword_t byte_offset_ptr) {
|
||||||
// Async not supported yet.
|
|
||||||
assert_zero(apc_routine);
|
|
||||||
|
|
||||||
X_STATUS result = X_STATUS_SUCCESS;
|
X_STATUS result = X_STATUS_SUCCESS;
|
||||||
uint32_t info = 0;
|
|
||||||
|
|
||||||
// Grab event to signal.
|
// Grab event to signal.
|
||||||
bool signal_event = false;
|
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,
|
buffer.guest_address(), buffer_length,
|
||||||
byte_offset_ptr ? static_cast<uint64_t>(*byte_offset_ptr) : -1,
|
byte_offset_ptr ? static_cast<uint64_t>(*byte_offset_ptr) : -1,
|
||||||
&bytes_written, apc_context);
|
&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<uint32_t>(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<uint32_t>(apc_routine) & ~1u,
|
||||||
|
apc_context, io_status_block, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!file->is_synchronous()) {
|
if (!file->is_synchronous()) {
|
||||||
result = X_STATUS_PENDING;
|
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
|
// Mark that we should signal the event now. We do this after
|
||||||
// we have written the info out.
|
// we have written the info out.
|
||||||
signal_event = true;
|
signal_event = true;
|
||||||
} else {
|
} else {
|
||||||
// X_STATUS_PENDING if not returning immediately.
|
// X_STATUS_PENDING if not returning immediately.
|
||||||
result = X_STATUS_PENDING;
|
result = X_STATUS_PENDING;
|
||||||
info = 0;
|
|
||||||
|
|
||||||
if (io_status_block) {
|
if (io_status_block) {
|
||||||
io_status_block->status = X_STATUS_SUCCESS;
|
io_status_block->status = X_STATUS_PENDING;
|
||||||
io_status_block->information = info;
|
io_status_block->information = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -458,7 +461,8 @@ dword_result_t NtSetIoCompletion(dword_t handle, dword_t key_context,
|
||||||
port->QueueNotification(notification);
|
port->QueueNotification(notification);
|
||||||
return X_STATUS_SUCCESS;
|
return X_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(NtSetIoCompletion, kFileSystem, kImplemented);
|
DECLARE_XBOXKRNL_EXPORT2(NtSetIoCompletion, kFileSystem, kImplemented,
|
||||||
|
kHighFrequency);
|
||||||
|
|
||||||
// Dequeues a packet from the completion port.
|
// Dequeues a packet from the completion port.
|
||||||
dword_result_t NtRemoveIoCompletion(
|
dword_result_t NtRemoveIoCompletion(
|
||||||
|
@ -473,7 +477,9 @@ dword_result_t NtRemoveIoCompletion(
|
||||||
status = X_STATUS_INVALID_HANDLE;
|
status = X_STATUS_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t timeout_ticks = timeout ? static_cast<uint32_t>(*timeout) : 0u;
|
uint64_t timeout_ticks =
|
||||||
|
timeout ? static_cast<uint32_t>(*timeout)
|
||||||
|
: static_cast<uint64_t>(std::numeric_limits<int64_t>::min());
|
||||||
XIOCompletion::IONotification notification;
|
XIOCompletion::IONotification notification;
|
||||||
if (port->WaitForNotification(timeout_ticks, ¬ification)) {
|
if (port->WaitForNotification(timeout_ticks, ¬ification)) {
|
||||||
if (key_context) {
|
if (key_context) {
|
||||||
|
@ -493,7 +499,8 @@ dword_result_t NtRemoveIoCompletion(
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(NtRemoveIoCompletion, kFileSystem, kImplemented);
|
DECLARE_XBOXKRNL_EXPORT2(NtRemoveIoCompletion, kFileSystem, kImplemented,
|
||||||
|
kHighFrequency);
|
||||||
|
|
||||||
dword_result_t NtQueryFullAttributesFile(
|
dword_result_t NtQueryFullAttributesFile(
|
||||||
pointer_t<X_OBJECT_ATTRIBUTES> obj_attribs,
|
pointer_t<X_OBJECT_ATTRIBUTES> obj_attribs,
|
||||||
|
|
|
@ -19,6 +19,9 @@
|
||||||
#include "xenia/kernel/xthread.h"
|
#include "xenia/kernel/xthread.h"
|
||||||
#include "xenia/xbox.h"
|
#include "xenia/xbox.h"
|
||||||
|
|
||||||
|
DEFINE_bool(log_string_format_kernel_calls, false,
|
||||||
|
"Log kernel calls with the kHighFrequency tag.", "Logging");
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
namespace xboxkrnl {
|
namespace xboxkrnl {
|
||||||
|
@ -830,7 +833,14 @@ SHIM_CALL DbgPrint_shim(PPCContext* ppc_context, KernelState* kernel_state) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
XELOGD("(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);
|
SHIM_SET_RETURN_32(X_STATUS_SUCCESS);
|
||||||
}
|
}
|
||||||
|
@ -841,8 +851,11 @@ SHIM_CALL _snprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) {
|
||||||
int32_t buffer_count = SHIM_GET_ARG_32(1);
|
int32_t buffer_count = SHIM_GET_ARG_32(1);
|
||||||
uint32_t format_ptr = SHIM_GET_ARG_32(2);
|
uint32_t format_ptr = SHIM_GET_ARG_32(2);
|
||||||
|
|
||||||
XELOGD("_snprintf({:08X}, {}, {:08X}, ...)", buffer_ptr, buffer_count,
|
if (cvars::log_high_frequency_kernel_calls) {
|
||||||
format_ptr);
|
XELOGD("_snprintf({:08X}, {}, {:08X}({}), ...)", buffer_ptr, buffer_count,
|
||||||
|
format_ptr,
|
||||||
|
xe::load_and_swap<std::string>(SHIM_MEM_ADDR(format_ptr)));
|
||||||
|
}
|
||||||
|
|
||||||
if (buffer_ptr == 0 || buffer_count <= 0 || format_ptr == 0) {
|
if (buffer_ptr == 0 || buffer_count <= 0 || format_ptr == 0) {
|
||||||
SHIM_SET_RETURN_32(-1);
|
SHIM_SET_RETURN_32(-1);
|
||||||
|
@ -877,7 +890,10 @@ SHIM_CALL sprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) {
|
||||||
uint32_t buffer_ptr = SHIM_GET_ARG_32(0);
|
uint32_t buffer_ptr = SHIM_GET_ARG_32(0);
|
||||||
uint32_t format_ptr = SHIM_GET_ARG_32(1);
|
uint32_t format_ptr = SHIM_GET_ARG_32(1);
|
||||||
|
|
||||||
XELOGD("sprintf({:08X}, {:08X}, ...)", buffer_ptr, format_ptr);
|
if (cvars::log_high_frequency_kernel_calls) {
|
||||||
|
XELOGD("sprintf({:08X}, {:08X}({}), ...)", buffer_ptr, format_ptr,
|
||||||
|
xe::load_and_swap<std::string>(SHIM_MEM_ADDR(format_ptr)));
|
||||||
|
}
|
||||||
|
|
||||||
if (buffer_ptr == 0 || format_ptr == 0) {
|
if (buffer_ptr == 0 || format_ptr == 0) {
|
||||||
SHIM_SET_RETURN_32(-1);
|
SHIM_SET_RETURN_32(-1);
|
||||||
|
@ -906,8 +922,12 @@ SHIM_CALL _snwprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) {
|
||||||
int32_t buffer_count = SHIM_GET_ARG_32(1);
|
int32_t buffer_count = SHIM_GET_ARG_32(1);
|
||||||
uint32_t format_ptr = SHIM_GET_ARG_32(2);
|
uint32_t format_ptr = SHIM_GET_ARG_32(2);
|
||||||
|
|
||||||
XELOGD("_snwprintf({:08X}, {}, {:08X}, ...)", buffer_ptr, buffer_count,
|
if (cvars::log_high_frequency_kernel_calls) {
|
||||||
format_ptr);
|
XELOGD("_snwprintf({:08X}, {}, {:08X}({}), ...)", buffer_ptr, buffer_count,
|
||||||
|
format_ptr,
|
||||||
|
xe::to_utf8(
|
||||||
|
xe::load_and_swap<std::u16string>(SHIM_MEM_ADDR(format_ptr))));
|
||||||
|
}
|
||||||
|
|
||||||
if (buffer_ptr == 0 || buffer_count <= 0 || format_ptr == 0) {
|
if (buffer_ptr == 0 || buffer_count <= 0 || format_ptr == 0) {
|
||||||
SHIM_SET_RETURN_32(-1);
|
SHIM_SET_RETURN_32(-1);
|
||||||
|
@ -942,7 +962,11 @@ SHIM_CALL swprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) {
|
||||||
uint32_t buffer_ptr = SHIM_GET_ARG_32(0);
|
uint32_t buffer_ptr = SHIM_GET_ARG_32(0);
|
||||||
uint32_t format_ptr = SHIM_GET_ARG_32(1);
|
uint32_t format_ptr = SHIM_GET_ARG_32(1);
|
||||||
|
|
||||||
XELOGD("swprintf({:08X}, {:08X}, ...)", buffer_ptr, format_ptr);
|
if (cvars::log_high_frequency_kernel_calls) {
|
||||||
|
XELOGD("swprintf({:08X}, {:08X}({}), ...)", buffer_ptr, format_ptr,
|
||||||
|
xe::to_utf8(
|
||||||
|
xe::load_and_swap<std::u16string>(SHIM_MEM_ADDR(format_ptr))));
|
||||||
|
}
|
||||||
|
|
||||||
if (buffer_ptr == 0 || format_ptr == 0) {
|
if (buffer_ptr == 0 || format_ptr == 0) {
|
||||||
SHIM_SET_RETURN_32(-1);
|
SHIM_SET_RETURN_32(-1);
|
||||||
|
@ -972,8 +996,11 @@ SHIM_CALL _vsnprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) {
|
||||||
uint32_t format_ptr = SHIM_GET_ARG_32(2);
|
uint32_t format_ptr = SHIM_GET_ARG_32(2);
|
||||||
uint32_t arg_ptr = SHIM_GET_ARG_32(3);
|
uint32_t arg_ptr = SHIM_GET_ARG_32(3);
|
||||||
|
|
||||||
XELOGD("_vsnprintf({:08X}, {}, {:08X}, {:08X})", buffer_ptr, buffer_count,
|
if (cvars::log_high_frequency_kernel_calls) {
|
||||||
format_ptr, arg_ptr);
|
XELOGD("_vsnprintf({:08X}, {}, {:08X}({}), {:08X})", buffer_ptr,
|
||||||
|
buffer_count, format_ptr,
|
||||||
|
xe::load_and_swap<std::string>(SHIM_MEM_ADDR(format_ptr)), arg_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
if (buffer_ptr == 0 || buffer_count <= 0 || format_ptr == 0) {
|
if (buffer_ptr == 0 || buffer_count <= 0 || format_ptr == 0) {
|
||||||
SHIM_SET_RETURN_32(-1);
|
SHIM_SET_RETURN_32(-1);
|
||||||
|
@ -1012,8 +1039,13 @@ SHIM_CALL _vsnwprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) {
|
||||||
uint32_t format_ptr = SHIM_GET_ARG_32(2);
|
uint32_t format_ptr = SHIM_GET_ARG_32(2);
|
||||||
uint32_t arg_ptr = SHIM_GET_ARG_32(3);
|
uint32_t arg_ptr = SHIM_GET_ARG_32(3);
|
||||||
|
|
||||||
XELOGD("_vsnwprintf({:08X}, {}, {:08X}, {:08X})", buffer_ptr, buffer_count,
|
if (cvars::log_high_frequency_kernel_calls) {
|
||||||
format_ptr, arg_ptr);
|
XELOGD("_vsnwprintf({:08X}, {}, {:08X}({}), {:08X})", buffer_ptr,
|
||||||
|
buffer_count, format_ptr,
|
||||||
|
xe::to_utf8(
|
||||||
|
xe::load_and_swap<std::u16string>(SHIM_MEM_ADDR(format_ptr))),
|
||||||
|
arg_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
if (buffer_ptr == 0 || buffer_count <= 0 || format_ptr == 0) {
|
if (buffer_ptr == 0 || buffer_count <= 0 || format_ptr == 0) {
|
||||||
SHIM_SET_RETURN_32(-1);
|
SHIM_SET_RETURN_32(-1);
|
||||||
|
@ -1051,7 +1083,10 @@ SHIM_CALL vsprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) {
|
||||||
uint32_t format_ptr = SHIM_GET_ARG_32(1);
|
uint32_t format_ptr = SHIM_GET_ARG_32(1);
|
||||||
uint32_t arg_ptr = SHIM_GET_ARG_32(2);
|
uint32_t arg_ptr = SHIM_GET_ARG_32(2);
|
||||||
|
|
||||||
XELOGD("vsprintf({:08X}, {:08X}, {:08X})", buffer_ptr, format_ptr, arg_ptr);
|
if (cvars::log_high_frequency_kernel_calls) {
|
||||||
|
XELOGD("vsprintf({:08X}, {:08X}({}), {:08X})", buffer_ptr, format_ptr,
|
||||||
|
xe::load_and_swap<std::string>(SHIM_MEM_ADDR(format_ptr)), arg_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
if (buffer_ptr == 0 || format_ptr == 0) {
|
if (buffer_ptr == 0 || format_ptr == 0) {
|
||||||
SHIM_SET_RETURN_32(-1);
|
SHIM_SET_RETURN_32(-1);
|
||||||
|
@ -1079,7 +1114,12 @@ SHIM_CALL _vscwprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) {
|
||||||
uint32_t format_ptr = SHIM_GET_ARG_32(0);
|
uint32_t format_ptr = SHIM_GET_ARG_32(0);
|
||||||
uint32_t arg_ptr = SHIM_GET_ARG_32(1);
|
uint32_t arg_ptr = SHIM_GET_ARG_32(1);
|
||||||
|
|
||||||
XELOGD("_vscwprintf({:08X}, {:08X})", format_ptr, arg_ptr);
|
if (cvars::log_high_frequency_kernel_calls) {
|
||||||
|
XELOGD("_vscwprintf({:08X}({}), {:08X})", format_ptr,
|
||||||
|
xe::to_utf8(
|
||||||
|
xe::load_and_swap<std::u16string>(SHIM_MEM_ADDR(format_ptr))),
|
||||||
|
arg_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
if (format_ptr == 0) {
|
if (format_ptr == 0) {
|
||||||
SHIM_SET_RETURN_32(-1);
|
SHIM_SET_RETURN_32(-1);
|
||||||
|
@ -1102,7 +1142,12 @@ SHIM_CALL vswprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) {
|
||||||
uint32_t format_ptr = SHIM_GET_ARG_32(1);
|
uint32_t format_ptr = SHIM_GET_ARG_32(1);
|
||||||
uint32_t arg_ptr = SHIM_GET_ARG_32(2);
|
uint32_t arg_ptr = SHIM_GET_ARG_32(2);
|
||||||
|
|
||||||
XELOGD("vswprintf({:08X}, {:08X}, {:08X})", buffer_ptr, 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<std::u16string>(SHIM_MEM_ADDR(format_ptr))),
|
||||||
|
arg_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
if (buffer_ptr == 0 || format_ptr == 0) {
|
if (buffer_ptr == 0 || format_ptr == 0) {
|
||||||
SHIM_SET_RETURN_32(-1);
|
SHIM_SET_RETURN_32(-1);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
* 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. *
|
* 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
|
// This is a partial file designed to be included by other files when
|
||||||
// constructing various tables.
|
// constructing various tables.
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
XE_EXPORT(xboxkrnl, 0x00000001, DbgBreakPoint, kFunction),
|
XE_EXPORT(xboxkrnl, 0x00000001, DbgBreakPoint, kFunction),
|
||||||
XE_EXPORT(xboxkrnl, 0x00000002, DbgBreakPointWithStatus, kFunction),
|
XE_EXPORT(xboxkrnl, 0x00000002, DbgBreakPointWithStatus, kFunction),
|
||||||
|
|
|
@ -21,7 +21,7 @@ XEnumerator::XEnumerator(KernelState* kernel_state, size_t items_per_enumerate,
|
||||||
XEnumerator::~XEnumerator() = default;
|
XEnumerator::~XEnumerator() = default;
|
||||||
|
|
||||||
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, uint32_t extra_size,
|
uint32_t flags, uint32_t extra_size,
|
||||||
void** extra_buffer) {
|
void** extra_buffer) {
|
||||||
auto native_object = CreateNative(sizeof(X_KENUMERATOR) + extra_size);
|
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<X_KENUMERATOR*>(native_object);
|
auto guest_object = reinterpret_cast<X_KENUMERATOR*>(native_object);
|
||||||
guest_object->app_id = app_id;
|
guest_object->app_id = app_id;
|
||||||
guest_object->message = message;
|
guest_object->open_message = open_message;
|
||||||
guest_object->message2 = message2;
|
guest_object->close_message = close_message;
|
||||||
guest_object->user_index = user_index;
|
guest_object->user_index = user_index;
|
||||||
guest_object->items_per_enumerate =
|
guest_object->items_per_enumerate =
|
||||||
static_cast<uint32_t>(items_per_enumerate_);
|
static_cast<uint32_t>(items_per_enumerate_);
|
||||||
|
@ -44,32 +44,28 @@ X_STATUS XEnumerator::Initialize(uint32_t user_index, uint32_t app_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
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() {
|
uint8_t* XStaticUntypedEnumerator::AppendItem() {
|
||||||
buffer_.resize(++item_count_ * item_size());
|
size_t offset = buffer_.size();
|
||||||
auto ptr =
|
buffer_.resize(offset + item_size());
|
||||||
const_cast<uint8_t*>(buffer_.data() + (item_count_ - 1) * item_size());
|
item_count_++;
|
||||||
return ptr;
|
return const_cast<uint8_t*>(&buffer_.data()[offset]);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t XStaticEnumerator::WriteItems(uint32_t buffer_ptr,
|
uint32_t XStaticUntypedEnumerator::WriteItems(uint32_t buffer_ptr,
|
||||||
uint8_t* buffer_data,
|
uint8_t* buffer_data,
|
||||||
uint32_t buffer_size,
|
uint32_t* written_count) {
|
||||||
uint32_t* written_count) {
|
|
||||||
size_t count = std::min(item_count_ - current_item_, items_per_enumerate());
|
size_t count = std::min(item_count_ - current_item_, items_per_enumerate());
|
||||||
if (!count) {
|
if (!count) {
|
||||||
return X_ERROR_NO_MORE_FILES;
|
return X_ERROR_NO_MORE_FILES;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size = count * item_size();
|
size_t size = count * item_size();
|
||||||
if (size > buffer_size) {
|
|
||||||
return X_ERROR_INSUFFICIENT_BUFFER;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t offset = current_item_ * item_size();
|
size_t offset = current_item_ * item_size();
|
||||||
std::memcpy(buffer_data, buffer_.data() + offset, size);
|
std::memcpy(buffer_data, buffer_.data() + offset, size);
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,8 @@ namespace kernel {
|
||||||
|
|
||||||
struct X_KENUMERATOR {
|
struct X_KENUMERATOR {
|
||||||
be<uint32_t> app_id;
|
be<uint32_t> app_id;
|
||||||
be<uint32_t> message;
|
be<uint32_t> open_message;
|
||||||
be<uint32_t> message2;
|
be<uint32_t> close_message;
|
||||||
be<uint32_t> user_index;
|
be<uint32_t> user_index;
|
||||||
be<uint32_t> items_per_enumerate;
|
be<uint32_t> items_per_enumerate;
|
||||||
be<uint32_t> flags;
|
be<uint32_t> flags;
|
||||||
|
@ -43,19 +43,21 @@ class XEnumerator : public XObject {
|
||||||
size_t item_size);
|
size_t item_size);
|
||||||
virtual ~XEnumerator();
|
virtual ~XEnumerator();
|
||||||
|
|
||||||
X_STATUS Initialize(uint32_t user_index, uint32_t app_id, uint32_t message,
|
X_STATUS Initialize(uint32_t user_index, uint32_t app_id,
|
||||||
uint32_t message2, uint32_t flags, uint32_t extra_size,
|
uint32_t open_message, uint32_t close_message,
|
||||||
void** extra_buffer);
|
uint32_t flags, uint32_t extra_size, void** extra_buffer);
|
||||||
|
|
||||||
X_STATUS Initialize(uint32_t user_index, uint32_t app_id, uint32_t message,
|
X_STATUS Initialize(uint32_t user_index, uint32_t app_id,
|
||||||
uint32_t message2, uint32_t flags);
|
uint32_t open_message, uint32_t close_message,
|
||||||
|
uint32_t flags);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
X_STATUS Initialize(uint32_t user_index, uint32_t app_id, uint32_t message,
|
X_STATUS Initialize(uint32_t user_index, uint32_t app_id,
|
||||||
uint32_t message2, uint32_t flags, T** extra) {
|
uint32_t open_message, uint32_t close_message,
|
||||||
|
uint32_t flags, T** extra) {
|
||||||
void* dummy;
|
void* dummy;
|
||||||
auto result = Initialize(user_index, app_id, message, message2, flags,
|
auto result = Initialize(user_index, app_id, open_message, close_message,
|
||||||
static_cast<uint32_t>(sizeof(T)), &dummy);
|
flags, static_cast<uint32_t>(sizeof(T)), &dummy);
|
||||||
if (extra) {
|
if (extra) {
|
||||||
*extra = XFAILED(result) ? nullptr : static_cast<T*>(dummy);
|
*extra = XFAILED(result) ? nullptr : static_cast<T*>(dummy);
|
||||||
}
|
}
|
||||||
|
@ -63,7 +65,6 @@ class XEnumerator : public XObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data,
|
virtual uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data,
|
||||||
uint32_t buffer_size,
|
|
||||||
uint32_t* written_count) = 0;
|
uint32_t* written_count) = 0;
|
||||||
|
|
||||||
size_t item_size() const { return item_size_; }
|
size_t item_size() const { return item_size_; }
|
||||||
|
@ -74,10 +75,10 @@ class XEnumerator : public XObject {
|
||||||
size_t item_size_;
|
size_t item_size_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class XStaticEnumerator : public XEnumerator {
|
class XStaticUntypedEnumerator : public XEnumerator {
|
||||||
public:
|
public:
|
||||||
XStaticEnumerator(KernelState* kernel_state, size_t items_per_enumerate,
|
XStaticUntypedEnumerator(KernelState* kernel_state,
|
||||||
size_t item_size)
|
size_t items_per_enumerate, size_t item_size)
|
||||||
: XEnumerator(kernel_state, items_per_enumerate, item_size),
|
: XEnumerator(kernel_state, items_per_enumerate, item_size),
|
||||||
item_count_(0),
|
item_count_(0),
|
||||||
current_item_(0) {}
|
current_item_(0) {}
|
||||||
|
@ -87,7 +88,7 @@ class XStaticEnumerator : public XEnumerator {
|
||||||
uint8_t* AppendItem();
|
uint8_t* AppendItem();
|
||||||
|
|
||||||
uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data,
|
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:
|
private:
|
||||||
size_t item_count_;
|
size_t item_count_;
|
||||||
|
@ -95,6 +96,23 @@ class XStaticEnumerator : public XEnumerator {
|
||||||
std::vector<uint8_t> buffer_;
|
std::vector<uint8_t> buffer_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
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<T*>(XStaticUntypedEnumerator::AppendItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppendItem(const T& item) {
|
||||||
|
auto ptr = AppendItem();
|
||||||
|
item.Write(ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ bool XIOCompletion::WaitForNotification(uint64_t wait_ticks,
|
||||||
IONotification* notify) {
|
IONotification* notify) {
|
||||||
auto ms = std::chrono::milliseconds(TimeoutTicksToMs(wait_ticks));
|
auto ms = std::chrono::milliseconds(TimeoutTicksToMs(wait_ticks));
|
||||||
auto res = threading::Wait(notification_semaphore_.get(), false, ms);
|
auto res = threading::Wait(notification_semaphore_.get(), false, ms);
|
||||||
if (res == threading::WaitResult::kSuccess || !wait_ticks) {
|
if (res == threading::WaitResult::kSuccess) {
|
||||||
std::unique_lock<std::mutex> lock(notification_lock_);
|
std::unique_lock<std::mutex> lock(notification_lock_);
|
||||||
assert_false(notifications_.empty());
|
assert_false(notifications_.empty());
|
||||||
|
|
||||||
|
|
|
@ -348,6 +348,12 @@ bool operator!=(std::nullptr_t _Left, const object_ref<_Ty>& _Right) noexcept {
|
||||||
return (!(_Left == _Right));
|
return (!(_Left == _Right));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class T, class... Args>
|
||||||
|
std::enable_if_t<!std::is_array<T>::value, object_ref<T>> make_object(
|
||||||
|
Args&&... args) {
|
||||||
|
return object_ref<T>(new T(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
object_ref<T> retain_object(T* ptr) {
|
object_ref<T> retain_object(T* ptr) {
|
||||||
if (ptr) ptr->Retain();
|
if (ptr) ptr->Retain();
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "third_party/imgui/imgui.h"
|
#include "third_party/imgui/imgui.h"
|
||||||
#include "xenia/base/assert.h"
|
#include "xenia/base/assert.h"
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
|
#include "xenia/base/math.h"
|
||||||
#include "xenia/ui/window.h"
|
#include "xenia/ui/window.h"
|
||||||
|
|
||||||
namespace xe {
|
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_TextSelectedBg] = ImVec4(0.00f, 1.00f, 0.00f, 0.21f);
|
||||||
style.Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
|
style.Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
|
||||||
|
|
||||||
io.KeyMap[ImGuiKey_Tab] = 0x09; // VK_TAB;
|
io.KeyMap[ImGuiKey_Tab] = int(ui::VirtualKey::kTab);
|
||||||
io.KeyMap[ImGuiKey_LeftArrow] = 0x25;
|
io.KeyMap[ImGuiKey_LeftArrow] = int(ui::VirtualKey::kLeft);
|
||||||
io.KeyMap[ImGuiKey_RightArrow] = 0x27;
|
io.KeyMap[ImGuiKey_RightArrow] = int(ui::VirtualKey::kRight);
|
||||||
io.KeyMap[ImGuiKey_UpArrow] = 0x26;
|
io.KeyMap[ImGuiKey_UpArrow] = int(ui::VirtualKey::kUp);
|
||||||
io.KeyMap[ImGuiKey_DownArrow] = 0x28;
|
io.KeyMap[ImGuiKey_DownArrow] = int(ui::VirtualKey::kDown);
|
||||||
io.KeyMap[ImGuiKey_Home] = 0x24;
|
io.KeyMap[ImGuiKey_Home] = int(ui::VirtualKey::kHome);
|
||||||
io.KeyMap[ImGuiKey_End] = 0x23;
|
io.KeyMap[ImGuiKey_End] = int(ui::VirtualKey::kEnd);
|
||||||
io.KeyMap[ImGuiKey_Delete] = 0x2E;
|
io.KeyMap[ImGuiKey_Delete] = int(ui::VirtualKey::kDelete);
|
||||||
io.KeyMap[ImGuiKey_Backspace] = 0x08;
|
io.KeyMap[ImGuiKey_Backspace] = int(ui::VirtualKey::kBack);
|
||||||
io.KeyMap[ImGuiKey_Enter] = 0x0D;
|
io.KeyMap[ImGuiKey_Enter] = int(ui::VirtualKey::kReturn);
|
||||||
io.KeyMap[ImGuiKey_Escape] = 0x1B;
|
io.KeyMap[ImGuiKey_Escape] = int(ui::VirtualKey::kEscape);
|
||||||
io.KeyMap[ImGuiKey_A] = 'A';
|
io.KeyMap[ImGuiKey_A] = int(ui::VirtualKey::kA);
|
||||||
io.KeyMap[ImGuiKey_C] = 'C';
|
io.KeyMap[ImGuiKey_C] = int(ui::VirtualKey::kC);
|
||||||
io.KeyMap[ImGuiKey_V] = 'V';
|
io.KeyMap[ImGuiKey_V] = int(ui::VirtualKey::kV);
|
||||||
io.KeyMap[ImGuiKey_X] = 'X';
|
io.KeyMap[ImGuiKey_X] = int(ui::VirtualKey::kX);
|
||||||
io.KeyMap[ImGuiKey_Y] = 'Y';
|
io.KeyMap[ImGuiKey_Y] = int(ui::VirtualKey::kY);
|
||||||
io.KeyMap[ImGuiKey_Z] = 'Z';
|
io.KeyMap[ImGuiKey_Z] = int(ui::VirtualKey::kZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGuiDrawer::SetupFont() {
|
void ImGuiDrawer::SetupFont() {
|
||||||
|
@ -228,36 +229,16 @@ void ImGuiDrawer::RenderDrawLists() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGuiDrawer::OnKeyDown(KeyEvent* e) {
|
void ImGuiDrawer::OnKeyDown(KeyEvent* e) { OnKey(e, true); }
|
||||||
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::OnKeyUp(KeyEvent* e) {
|
void ImGuiDrawer::OnKeyUp(KeyEvent* e) { OnKey(e, false); }
|
||||||
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::OnKeyChar(KeyEvent* e) {
|
void ImGuiDrawer::OnKeyChar(KeyEvent* e) {
|
||||||
auto& io = GetIO();
|
auto& io = GetIO();
|
||||||
if (e->key_code() > 0 && e->key_code() < 0x10000) {
|
// TODO(Triang3l): Accept the Unicode character.
|
||||||
io.AddInputCharacter(e->key_code());
|
unsigned int character = static_cast<unsigned int>(e->virtual_key());
|
||||||
|
if (character > 0 && character < 0x10000) {
|
||||||
|
io.AddInputCharacter(character);
|
||||||
e->set_handled(true);
|
e->set_handled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -327,5 +308,30 @@ void ImGuiDrawer::OnMouseWheel(MouseEvent* e) {
|
||||||
io.MouseWheel += float(e->dy() / 120.0f);
|
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 ui
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -57,6 +57,9 @@ class ImGuiDrawer : public WindowListener {
|
||||||
|
|
||||||
ImGuiContext* internal_state_ = nullptr;
|
ImGuiContext* internal_state_ = nullptr;
|
||||||
std::unique_ptr<ImmediateTexture> font_texture_;
|
std::unique_ptr<ImmediateTexture> font_texture_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void OnKey(KeyEvent* e, bool is_down);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
|
#include "xenia/ui/virtual_key.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
|
@ -42,11 +44,12 @@ class FileDropEvent : public UIEvent {
|
||||||
|
|
||||||
class KeyEvent : public UIEvent {
|
class KeyEvent : public UIEvent {
|
||||||
public:
|
public:
|
||||||
KeyEvent(Window* target, int key_code, int repeat_count, bool prev_state,
|
KeyEvent(Window* target, VirtualKey virtual_key, int repeat_count,
|
||||||
bool modifier_shift_pressed, bool modifier_ctrl_pressed,
|
bool prev_state, bool modifier_shift_pressed,
|
||||||
bool modifier_alt_pressed, bool modifier_super_pressed)
|
bool modifier_ctrl_pressed, bool modifier_alt_pressed,
|
||||||
|
bool modifier_super_pressed)
|
||||||
: UIEvent(target),
|
: UIEvent(target),
|
||||||
key_code_(key_code),
|
virtual_key_(virtual_key),
|
||||||
repeat_count_(repeat_count),
|
repeat_count_(repeat_count),
|
||||||
prev_state_(prev_state),
|
prev_state_(prev_state),
|
||||||
modifier_shift_pressed_(modifier_shift_pressed),
|
modifier_shift_pressed_(modifier_shift_pressed),
|
||||||
|
@ -58,7 +61,7 @@ class KeyEvent : public UIEvent {
|
||||||
bool is_handled() const { return handled_; }
|
bool is_handled() const { return handled_; }
|
||||||
void set_handled(bool value) { handled_ = value; }
|
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_; }
|
int repeat_count() const { return repeat_count_; }
|
||||||
bool prev_state() const { return prev_state_; }
|
bool prev_state() const { return prev_state_; }
|
||||||
|
@ -70,7 +73,7 @@ class KeyEvent : public UIEvent {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool handled_ = false;
|
bool handled_ = false;
|
||||||
int key_code_ = 0;
|
VirtualKey virtual_key_ = VirtualKey::kNone;
|
||||||
|
|
||||||
int repeat_count_ = 0;
|
int repeat_count_ = 0;
|
||||||
bool prev_state_ = false; // Key previously down(true) or up(false)
|
bool prev_state_ = false; // Key previously down(true) or up(false)
|
||||||
|
|
|
@ -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 <cstdint>
|
||||||
|
|
||||||
|
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_
|
|
@ -259,20 +259,21 @@ void Window::OnLostFocus(UIEvent* e) {
|
||||||
|
|
||||||
void Window::OnKeyPress(KeyEvent* e, bool is_down, bool is_char) {
|
void Window::OnKeyPress(KeyEvent* e, bool is_down, bool is_char) {
|
||||||
if (!is_char) {
|
if (!is_char) {
|
||||||
switch (e->key_code()) {
|
switch (e->virtual_key()) {
|
||||||
case 16:
|
case VirtualKey::kShift:
|
||||||
modifier_shift_pressed_ = is_down;
|
modifier_shift_pressed_ = is_down;
|
||||||
break;
|
break;
|
||||||
case 17:
|
case VirtualKey::kControl:
|
||||||
modifier_cntrl_pressed_ = is_down;
|
modifier_cntrl_pressed_ = is_down;
|
||||||
break;
|
break;
|
||||||
// case xx:
|
case VirtualKey::kMenu:
|
||||||
// // alt ??
|
modifier_alt_pressed_ = is_down;
|
||||||
// modifier_alt_pressed_ = is_down;
|
break;
|
||||||
// break;
|
case VirtualKey::kLWin:
|
||||||
case 91:
|
|
||||||
modifier_super_pressed_ = is_down;
|
modifier_super_pressed_ = is_down;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "xenia/ui/graphics_provider.h"
|
#include "xenia/ui/graphics_provider.h"
|
||||||
#include "xenia/ui/imgui_dialog.h"
|
#include "xenia/ui/imgui_dialog.h"
|
||||||
#include "xenia/ui/imgui_drawer.h"
|
#include "xenia/ui/imgui_drawer.h"
|
||||||
|
#include "xenia/ui/virtual_key.h"
|
||||||
#include "xenia/ui/window.h"
|
#include "xenia/ui/window.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
@ -92,10 +93,12 @@ int window_demo_main(const std::vector<std::string>& args) {
|
||||||
loop->on_quit.AddListener([&window](xe::ui::UIEvent* e) { window.reset(); });
|
loop->on_quit.AddListener([&window](xe::ui::UIEvent* e) { window.reset(); });
|
||||||
|
|
||||||
window->on_key_down.AddListener([](xe::ui::KeyEvent* e) {
|
window->on_key_down.AddListener([](xe::ui::KeyEvent* e) {
|
||||||
switch (e->key_code()) {
|
switch (e->virtual_key()) {
|
||||||
case 0x72: { // F3
|
case VirtualKey::kF3:
|
||||||
Profiler::ToggleDisplay();
|
Profiler::ToggleDisplay();
|
||||||
} break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "xenia/base/assert.h"
|
#include "xenia/base/assert.h"
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/base/platform_linux.h"
|
#include "xenia/base/platform_linux.h"
|
||||||
|
#include "xenia/ui/virtual_key.h"
|
||||||
#include "xenia/ui/window_gtk.h"
|
#include "xenia/ui/window_gtk.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
@ -350,9 +351,10 @@ bool GTKWindow::HandleKeyboard(GdkEventKey* event) {
|
||||||
bool ctrl_pressed = modifiers & GDK_CONTROL_MASK;
|
bool ctrl_pressed = modifiers & GDK_CONTROL_MASK;
|
||||||
bool alt_pressed = modifiers & GDK_META_MASK;
|
bool alt_pressed = modifiers & GDK_META_MASK;
|
||||||
bool super_pressed = modifiers & GDK_SUPER_MASK;
|
bool super_pressed = modifiers & GDK_SUPER_MASK;
|
||||||
auto e =
|
// TODO(Triang3l): event->hardware_keycode to VirtualKey translation.
|
||||||
KeyEvent(this, event->hardware_keycode, 1, event->type == GDK_KEY_RELEASE,
|
auto e = KeyEvent(this, VirtualKey(event->hardware_keycode), 1,
|
||||||
shift_pressed, ctrl_pressed, alt_pressed, super_pressed);
|
event->type == GDK_KEY_RELEASE, shift_pressed, ctrl_pressed,
|
||||||
|
alt_pressed, super_pressed);
|
||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
case GDK_KEY_PRESS:
|
case GDK_KEY_PRESS:
|
||||||
OnKeyDown(&e);
|
OnKeyDown(&e);
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "xenia/base/filesystem.h"
|
#include "xenia/base/filesystem.h"
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/base/platform_win.h"
|
#include "xenia/base/platform_win.h"
|
||||||
|
#include "xenia/ui/virtual_key.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
@ -706,7 +707,7 @@ bool Win32Window::HandleMouse(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||||
|
|
||||||
bool Win32Window::HandleKeyboard(UINT message, WPARAM wParam, LPARAM lParam) {
|
bool Win32Window::HandleKeyboard(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||||
auto e = KeyEvent(
|
auto e = KeyEvent(
|
||||||
this, static_cast<int>(wParam), lParam & 0xFFFF0000, !!(lParam & 0x2),
|
this, VirtualKey(wParam), lParam & 0xFFFF0000, !!(lParam & 0x2),
|
||||||
!!(GetKeyState(VK_SHIFT) & 0x80), !!(GetKeyState(VK_CONTROL) & 0x80),
|
!!(GetKeyState(VK_SHIFT) & 0x80), !!(GetKeyState(VK_CONTROL) & 0x80),
|
||||||
!!(GetKeyState(VK_MENU) & 0x80), !!(GetKeyState(VK_LWIN) & 0x80));
|
!!(GetKeyState(VK_MENU) & 0x80), !!(GetKeyState(VK_LWIN) & 0x80));
|
||||||
switch (message) {
|
switch (message) {
|
||||||
|
|
|
@ -25,7 +25,8 @@ void HostPathFile::Destroy() { delete this; }
|
||||||
|
|
||||||
X_STATUS HostPathFile::ReadSync(void* buffer, size_t buffer_length,
|
X_STATUS HostPathFile::ReadSync(void* buffer, size_t buffer_length,
|
||||||
size_t byte_offset, size_t* out_bytes_read) {
|
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;
|
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,
|
X_STATUS HostPathFile::WriteSync(const void* buffer, size_t buffer_length,
|
||||||
size_t byte_offset,
|
size_t byte_offset,
|
||||||
size_t* out_bytes_written) {
|
size_t* out_bytes_written) {
|
||||||
if (!(file_access_ &
|
if (!(file_access_ & (FileAccess::kGenericWrite | FileAccess::kFileWriteData |
|
||||||
(FileAccess::kFileWriteData | FileAccess::kFileAppendData))) {
|
FileAccess::kFileAppendData))) {
|
||||||
return X_STATUS_ACCESS_DENIED;
|
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) {
|
X_STATUS HostPathFile::SetLength(size_t length) {
|
||||||
if (!(file_access_ & FileAccess::kFileWriteData)) {
|
if (!(file_access_ &
|
||||||
|
(FileAccess::kGenericWrite | FileAccess::kFileWriteData))) {
|
||||||
return X_STATUS_ACCESS_DENIED;
|
return X_STATUS_ACCESS_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,11 @@ Entry* VirtualFileSystem::ResolvePath(const std::string_view path) {
|
||||||
return xe::utf8::starts_with(normalized_path, d->mount_path());
|
return xe::utf8::starts_with(normalized_path, d->mount_path());
|
||||||
});
|
});
|
||||||
if (it == devices_.cend()) {
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1321,7 +1321,7 @@ def find_xenia_source_files():
|
||||||
return [os.path.join(root, name)
|
return [os.path.join(root, name)
|
||||||
for root, dirs, files in os.walk('src')
|
for root, dirs, files in os.walk('src')
|
||||||
for name in files
|
for name in files
|
||||||
if name.endswith(('.cc', '.c', '.h', '.inl'))]
|
if name.endswith(('.cc', '.c', '.h', '.inl', '.inc'))]
|
||||||
|
|
||||||
|
|
||||||
def find_all_source_files():
|
def find_all_source_files():
|
||||||
|
|
Loading…
Reference in New Issue