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