Compare commits

...

33 Commits

Author SHA1 Message Date
Fernando Sahmkow
a60b669ef4 MacroHLE: Add MultidrawIndirect HLE Macro. 2022-10-01 20:57:00 -04:00
bunnei
d9e375acc3 Merge pull request #8910 from vonchenplus/astc_decode_error
video_core: Modify astc texture decode error fill value
2022-09-30 15:34:11 -07:00
bunnei
dbb9d601df Merge pull request #8934 from german77/palma_release
service: hid: Partially implement palma controller
2022-09-29 12:48:28 -07:00
Morph
2e3aad41aa Merge pull request #8993 from lat9nq/drop-linuxdeploy
ci/linux: Drop linuxdeploy usage
2022-09-28 20:10:47 -04:00
bunnei
9015a512c2 Merge pull request #8940 from german77/silence
yuzu: Silence some clang warnings
2022-09-28 14:37:23 -07:00
Morph
0f6007b405 Merge pull request #8989 from merryhime/loader-nullptr
core/loader: Return nullptr if file is nullptr
2022-09-27 10:59:46 -04:00
lat9nq
ad9f97cd8d ci/linux: Drop linuxdeploy usage
Recent versions of Docker appear to cause the Qt linuxdeploy plugin to
throw a boost file copy error.

This switches from linuxdeploy to a script of mine I've been working on
for a while.
2022-09-26 00:35:03 -04:00
Merry
f55ed1cab0 core/loader: Return nullptr if file is nullptr 2022-09-25 19:31:35 +01:00
bunnei
465c46387d Merge pull request #8920 from abouvier/cmake-git
cmake: fix git detection
2022-09-24 23:11:45 -07:00
Narr the Reg
23589ad9b8 service: hid: Partially implement palma controller 2022-09-25 00:13:12 -05:00
bunnei
1b1b99fbd5 Merge pull request #8941 from Kelebek1/single_core_sucks
Do not try to pause core timing from the audio thread when using single-core
2022-09-23 22:40:30 -07:00
Morph
d794ced303 Merge pull request #8945 from Tachi107/typos
chore: fix some typos
2022-09-23 20:28:43 -04:00
Morph
5082efef6c Merge pull request #8948 from german77/order
yuzu: sort input profiles by name
2022-09-23 20:28:35 -04:00
Morph
86ccc87111 Merge pull request #8933 from lat9nq/ci-use-apprun-sh
ci/linux: Use AppRun.sh to start AppImage
2022-09-23 20:28:28 -04:00
Morph
12baf88dc8 Merge pull request #8930 from lat9nq/disable-vulkan-check
yuzu qt: Add option to disable startup Vulkan check
2022-09-23 20:28:13 -04:00
Narr the Reg
f711d1ce52 yuzu: sort input profiles by name 2022-09-23 12:31:35 -05:00
Morph
70abb13a43 Merge pull request #8943 from lioncash/netiface
sockets: Make fd member variable protected
2022-09-23 09:08:07 -04:00
Morph
c2c3f2c3e7 Merge pull request #8939 from lioncash/render
audio_renderer: Make GetCommandBuffer() take a u32
2022-09-23 09:07:52 -04:00
Morph
3b77dec188 Merge pull request #8938 from lioncash/manager
audio_manager: Minor cleanup related changes
2022-09-23 09:07:38 -04:00
Lioncash
c8da75b7ed sockets: Make fd member variable protected
Other things shouldn't be able to directly mess around with the
descriptor
2022-09-22 08:20:54 -04:00
Kelebek1
56b8a9ba6e Do not try to pause core timing from the audio thread when using single-core 2022-09-22 01:23:57 +01:00
Narr the Reg
5a74ced59a yuzu: Silence some clang warnings 2022-09-21 11:51:31 -05:00
Lioncash
c891497b61 audio_renderer: Make GetCommandBuffer() take a u32
This function is only ever called with unsigned types, and all of the
other interface functions take session_id as a u32, so this makes the
class a little more consistent.
2022-09-21 10:00:57 -04:00
Lioncash
00616c7ad8 audio_manager: Forward declare result type
Moves the include into the cpp file to lessen header dependencies.
2022-09-21 09:43:59 -04:00
Lioncash
75d6fe3669 audio_manager: Remove redundant cast in ThreadFunc()
We can just use a local here to get rid of a second cast.
2022-09-21 09:35:22 -04:00
Lioncash
e48e22eb52 audio_manager: move std::functions in SetOutManager/SetInManager
Prevents unnecessary reallocations in the event the captured variables
are larger than the internal std::function buffer.
2022-09-21 09:32:15 -04:00
Lioncash
da0fd51642 audio_manager: Remove unused forward declarations
Allows us to get rid of some unnecessary forward declarations and
includes.
2022-09-21 09:29:35 -04:00
Lioncash
08d81e0bd8 audio_manager: Remove unused sessions_started member variable
This isn't used, so it can be removed.
2022-09-21 09:28:05 -04:00
Lioncash
b59b967280 audio_manager: Remove dependence on system state
This isn't used by the class, so this can be removed for the time being.
2022-09-21 09:26:42 -04:00
lat9nq
37b4f79b54 ci/linux: Use AppRun.sh to start AppImage
The current AppRun is more difficult to update. This script still
uses the old version of AppImageKit-checkrt, but now we use the shell
script version so we can set our own environment variables as the
application starts up.

This specific version searches for and sets the correct root CA file to
prevent SSL errors in yuzu.
2022-09-20 18:57:27 -04:00
lat9nq
89af4bfba8 yuzu qt: Add option to disable startup Vulkan check
The startup check apparently confuses other programs when yuzu launches
2 processes and then quickly closes one of them. Though this isn't
really our issues it's also not a big deal for me to add an option to
work around that issue.
2022-09-19 14:46:12 -04:00
Alexandre Bouvier
7239470dad cmake: fix git detection 2022-09-18 00:04:35 +02:00
FengChen
88007077e2 video_core: Modify astc texture decode error fill value 2022-09-15 17:04:44 +08:00
33 changed files with 1030 additions and 164 deletions

View File

@@ -33,16 +33,14 @@ DESTDIR="$PWD/AppDir" ninja install
rm -vf AppDir/usr/bin/yuzu-cmd AppDir/usr/bin/yuzu-tester
# Download tools needed to build an AppImage
wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/linuxdeploy-x86_64.AppImage
wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/linuxdeploy-plugin-qt-x86_64.AppImage
wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/AppRun-patched-x86_64
wget -nc https://raw.githubusercontent.com/lat9nq/deploy/main/linux/deploy-linux.sh
wget -nc https://raw.githubusercontent.com/yuzu-emu/AppImageKit-checkrt/old/AppRun.sh
wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/exec-x86_64.so
# Set executable bit
chmod 755 \
AppRun-patched-x86_64 \
deploy-linux.sh \
AppRun.sh \
exec-x86_64.so \
linuxdeploy-x86_64.AppImage \
linuxdeploy-plugin-qt-x86_64.AppImage
# Workaround for https://github.com/AppImage/AppImageKit/issues/828
export APPIMAGE_EXTRACT_AND_RUN=1
@@ -52,7 +50,7 @@ mkdir -p AppDir/usr/optional/libstdc++
mkdir -p AppDir/usr/optional/libgcc_s
# Deploy yuzu's needed dependencies
./linuxdeploy-x86_64.AppImage --appdir AppDir --plugin qt
DEPLOY_QT=1 ./deploy-linux.sh AppDir/usr/bin/yuzu AppDir
# Workaround for libQt5MultimediaGstTools indirectly requiring libwayland-client and breaking Vulkan usage on end-user systems
find AppDir -type f -regex '.*libwayland-client\.so.*' -delete -print
@@ -60,6 +58,6 @@ find AppDir -type f -regex '.*libwayland-client\.so.*' -delete -print
# Workaround for building yuzu with GCC 10 but also trying to distribute it to Ubuntu 18.04 et al.
# See https://github.com/darealshinji/AppImageKit-checkrt
cp exec-x86_64.so AppDir/usr/optional/exec.so
cp AppRun-patched-x86_64 AppDir/AppRun
cp AppRun.sh AppDir/AppRun
cp --dereference /usr/lib/x86_64-linux-gnu/libstdc++.so.6 AppDir/usr/optional/libstdc++/libstdc++.so.6
cp --dereference /lib/x86_64-linux-gnu/libgcc_s.so.1 AppDir/usr/optional/libgcc_s/libgcc_s.so.1

View File

@@ -7,11 +7,6 @@ function(get_timestamp _var)
set(${_var} "${timestamp}" PARENT_SCOPE)
endfunction()
list(APPEND CMAKE_MODULE_PATH "${SRC_DIR}/externals/cmake-modules")
# Find the package here with the known path so that the GetGit commands can find it as well
find_package(Git QUIET PATHS "${GIT_EXECUTABLE}")
# generate git/build information
include(GetGitRevisionDescription)
if(NOT GIT_REF_SPEC)
@@ -29,6 +24,7 @@ get_timestamp(BUILD_DATE)
# Also if this is a CI build, add the build name (ie: Nightly, Canary) to the scm_rev file as well
set(REPO_NAME "")
set(BUILD_VERSION "0")
set(BUILD_ID ${DISPLAY_VERSION})
if (BUILD_REPOSITORY)
# regex capture the string nightly or canary into CMAKE_MATCH_1
string(REGEX MATCH "yuzu-emu/yuzu-?(.*)" OUTVAR ${BUILD_REPOSITORY})
@@ -57,6 +53,4 @@ if (BUILD_REPOSITORY)
endif()
endif()
# The variable SRC_DIR must be passed into the script
# (since it uses the current build directory for all values of CMAKE_*_DIR)
configure_file("${SRC_DIR}/src/common/scm_rev.cpp.in" "scm_rev.cpp" @ONLY)
configure_file(scm_rev.cpp.in scm_rev.cpp @ONLY)

View File

@@ -8,7 +8,7 @@
namespace AudioCore {
AudioCore::AudioCore(Core::System& system) : audio_manager{std::make_unique<AudioManager>(system)} {
AudioCore::AudioCore(Core::System& system) : audio_manager{std::make_unique<AudioManager>()} {
CreateSinks();
// Must be created after the sinks
adsp = std::make_unique<AudioRenderer::ADSP::ADSP>(system, *output_sink);

View File

@@ -1,14 +1,13 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "audio_core/audio_in_manager.h"
#include "audio_core/audio_manager.h"
#include "audio_core/audio_out_manager.h"
#include "core/core.h"
#include "core/hle/service/audio/errors.h"
namespace AudioCore {
AudioManager::AudioManager(Core::System& system_) : system{system_} {
AudioManager::AudioManager() {
thread = std::jthread([this]() { ThreadFunc(); });
}
@@ -27,7 +26,7 @@ Result AudioManager::SetOutManager(BufferEventFunc buffer_func) {
const auto index{events.GetManagerIndex(Event::Type::AudioOutManager)};
if (buffer_events[index] == nullptr) {
buffer_events[index] = buffer_func;
buffer_events[index] = std::move(buffer_func);
needs_update = true;
events.SetAudioEvent(Event::Type::AudioOutManager, true);
}
@@ -43,7 +42,7 @@ Result AudioManager::SetInManager(BufferEventFunc buffer_func) {
const auto index{events.GetManagerIndex(Event::Type::AudioInManager)};
if (buffer_events[index] == nullptr) {
buffer_events[index] = buffer_func;
buffer_events[index] = std::move(buffer_func);
needs_update = true;
events.SetAudioEvent(Event::Type::AudioInManager, true);
}
@@ -60,19 +59,21 @@ void AudioManager::ThreadFunc() {
running = true;
while (running) {
auto timed_out{events.Wait(l, std::chrono::seconds(2))};
const auto timed_out{events.Wait(l, std::chrono::seconds(2))};
if (events.CheckAudioEventSet(Event::Type::Max)) {
break;
}
for (size_t i = 0; i < buffer_events.size(); i++) {
if (events.CheckAudioEventSet(Event::Type(i)) || timed_out) {
const auto event_type = static_cast<Event::Type>(i);
if (events.CheckAudioEventSet(event_type) || timed_out) {
if (buffer_events[i]) {
buffer_events[i]();
}
}
events.SetAudioEvent(Event::Type(i), false);
events.SetAudioEvent(event_type, false);
}
}
}

View File

@@ -10,22 +10,11 @@
#include <thread>
#include "audio_core/audio_event.h"
#include "core/hle/service/audio/errors.h"
namespace Core {
class System;
}
union Result;
namespace AudioCore {
namespace AudioOut {
class Manager;
}
namespace AudioIn {
class Manager;
}
/**
* The AudioManager's main purpose is to wait for buffer events for the audio in and out managers,
* and call an associated callback to release buffers.
@@ -43,7 +32,7 @@ class AudioManager {
using BufferEventFunc = std::function<void()>;
public:
explicit AudioManager(Core::System& system);
explicit AudioManager();
/**
* Shutdown the audio manager.
@@ -80,10 +69,6 @@ private:
*/
void ThreadFunc();
/// Core system
Core::System& system;
/// Have sessions started palying?
bool sessions_started{};
/// Is the main thread running?
std::atomic<bool> running{};
/// Unused

View File

@@ -47,7 +47,7 @@ RenderMessage AudioRenderer_Mailbox::ADSPWaitMessage() {
return msg;
}
CommandBuffer& AudioRenderer_Mailbox::GetCommandBuffer(const s32 session_id) {
CommandBuffer& AudioRenderer_Mailbox::GetCommandBuffer(const u32 session_id) {
return command_buffers[session_id];
}

View File

@@ -83,7 +83,7 @@ public:
* @param session_id - The session id to get (0 or 1).
* @return The command buffer.
*/
CommandBuffer& GetCommandBuffer(s32 session_id);
CommandBuffer& GetCommandBuffer(u32 session_id);
/**
* Set the command buffer with the given session id (0 or 1).

View File

@@ -214,8 +214,13 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz
// video play out without attempting to stall.
// Can hopefully remove this later with a more complete NVDEC implementation.
const auto nvdec_active{system.AudioCore().IsNVDECActive()};
if (!nvdec_active && queued_buffers > max_queue_size) {
// Core timing cannot be paused in single-core mode, so Stall ends up being called over and over
// and never recovers to a normal state, so just skip attempting to sync things on single-core.
if (system.IsMulticore() && !nvdec_active && queued_buffers > max_queue_size) {
Stall();
} else if (system.IsMulticore() && queued_buffers <= max_queue_size) {
Unstall();
}
while (frames_written < num_frames) {
@@ -255,7 +260,7 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz
std::memcpy(&last_frame[0], &output_buffer[(frames_written - 1) * frame_size],
frame_size_bytes);
if (stalled && queued_buffers <= max_queue_size) {
if (system.IsMulticore() && queued_buffers <= max_queue_size) {
Unstall();
}
}

View File

@@ -14,32 +14,7 @@ if (DEFINED ENV{DISPLAYVERSION})
set(DISPLAY_VERSION $ENV{DISPLAYVERSION})
endif ()
# Pass the path to git to the GenerateSCMRev.cmake as well
find_package(Git QUIET)
add_custom_command(OUTPUT scm_rev.cpp
COMMAND ${CMAKE_COMMAND}
-DSRC_DIR=${PROJECT_SOURCE_DIR}
-DBUILD_REPOSITORY=${BUILD_REPOSITORY}
-DTITLE_BAR_FORMAT_IDLE=${TITLE_BAR_FORMAT_IDLE}
-DTITLE_BAR_FORMAT_RUNNING=${TITLE_BAR_FORMAT_RUNNING}
-DBUILD_TAG=${BUILD_TAG}
-DBUILD_ID=${DISPLAY_VERSION}
-DGIT_REF_SPEC=${GIT_REF_SPEC}
-DGIT_REV=${GIT_REV}
-DGIT_DESC=${GIT_DESC}
-DGIT_BRANCH=${GIT_BRANCH}
-DBUILD_FULLNAME=${BUILD_FULLNAME}
-DGIT_EXECUTABLE=${GIT_EXECUTABLE}
-P ${PROJECT_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake
DEPENDS
# Check that the scm_rev files haven't changed
"${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in"
"${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.h"
# technically we should regenerate if the git version changed, but its not worth the effort imo
"${PROJECT_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake"
VERBATIM
)
include(GenerateSCMRev)
add_library(common STATIC
algorithm.h
@@ -117,7 +92,7 @@ add_library(common STATIC
quaternion.h
reader_writer_queue.h
ring_buffer.h
scm_rev.cpp
${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp
scm_rev.h
scope_exit.h
settings.cpp

View File

@@ -531,6 +531,7 @@ struct Values {
Setting<bool> use_auto_stub{false, "use_auto_stub"};
Setting<bool> enable_all_controllers{false, "enable_all_controllers"};
Setting<bool> create_crash_dumps{false, "create_crash_dumps"};
Setting<bool> perform_vulkan_check{true, "perform_vulkan_check"};
// Miscellaneous
Setting<std::string> log_filter{"*:Info", "log_filter"};

View File

@@ -460,6 +460,8 @@ add_library(core STATIC
hle/service/hid/controllers/mouse.h
hle/service/hid/controllers/npad.cpp
hle/service/hid/controllers/npad.h
hle/service/hid/controllers/palma.cpp
hle/service/hid/controllers/palma.h
hle/service/hid/controllers/stubbed.cpp
hle/service/hid/controllers/stubbed.h
hle/service/hid/controllers/touchscreen.cpp

View File

@@ -660,7 +660,6 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
ASSERT(false);
break;
case Core::HID::NpadStyleIndex::ProController:
case Core::HID::NpadStyleIndex::Pokeball:
set_motion_state(sixaxis_fullkey_state, motion_state[0]);
break;
case Core::HID::NpadStyleIndex::Handheld:
@@ -676,6 +675,11 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
case Core::HID::NpadStyleIndex::JoyconRight:
set_motion_state(sixaxis_right_lifo_state, motion_state[1]);
break;
case Core::HID::NpadStyleIndex::Pokeball:
using namespace std::literals::chrono_literals;
set_motion_state(sixaxis_fullkey_state, motion_state[0]);
sixaxis_fullkey_state.delta_time = std::chrono::nanoseconds(15ms).count();
break;
default:
break;
}

View File

@@ -0,0 +1,229 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core_timing.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/service/hid/controllers/palma.h"
#include "core/hle/service/kernel_helpers.h"
namespace Service::HID {
Controller_Palma::Controller_Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
KernelHelpers::ServiceContext& service_context_)
: ControllerBase{hid_core_}, service_context{service_context_} {
controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
operation_complete_event = service_context.CreateEvent("hid:PalmaOperationCompleteEvent");
}
Controller_Palma::~Controller_Palma() = default;
void Controller_Palma::OnInit() {}
void Controller_Palma::OnRelease() {}
void Controller_Palma::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
if (!IsControllerActivated()) {
return;
}
}
Result Controller_Palma::GetPalmaConnectionHandle(Core::HID::NpadIdType npad_id,
PalmaConnectionHandle& handle) {
active_handle.npad_id = npad_id;
handle = active_handle;
return ResultSuccess;
}
Result Controller_Palma::InitializePalma(const PalmaConnectionHandle& handle) {
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
ActivateController();
return ResultSuccess;
}
Kernel::KReadableEvent& Controller_Palma::AcquirePalmaOperationCompleteEvent(
const PalmaConnectionHandle& handle) const {
if (handle.npad_id != active_handle.npad_id) {
LOG_ERROR(Service_HID, "Invalid npad id {}", handle.npad_id);
}
return operation_complete_event->GetReadableEvent();
}
Result Controller_Palma::GetPalmaOperationInfo(const PalmaConnectionHandle& handle,
PalmaOperationType& operation_type,
PalmaOperationData& data) const {
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
operation_type = operation.operation;
data = operation.data;
return ResultSuccess;
}
Result Controller_Palma::PlayPalmaActivity(const PalmaConnectionHandle& handle,
u64 palma_activity) {
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
operation.operation = PalmaOperationType::PlayActivity;
operation.result = PalmaResultSuccess;
operation.data = {};
operation_complete_event->GetWritableEvent().Signal();
return ResultSuccess;
}
Result Controller_Palma::SetPalmaFrModeType(const PalmaConnectionHandle& handle,
PalmaFrModeType fr_mode_) {
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
fr_mode = fr_mode_;
return ResultSuccess;
}
Result Controller_Palma::ReadPalmaStep(const PalmaConnectionHandle& handle) {
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
operation.operation = PalmaOperationType::ReadStep;
operation.result = PalmaResultSuccess;
operation.data = {};
operation_complete_event->GetWritableEvent().Signal();
return ResultSuccess;
}
Result Controller_Palma::EnablePalmaStep(const PalmaConnectionHandle& handle, bool is_enabled) {
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
return ResultSuccess;
}
Result Controller_Palma::ResetPalmaStep(const PalmaConnectionHandle& handle) {
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
return ResultSuccess;
}
void Controller_Palma::ReadPalmaApplicationSection() {}
void Controller_Palma::WritePalmaApplicationSection() {}
Result Controller_Palma::ReadPalmaUniqueCode(const PalmaConnectionHandle& handle) {
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
operation.operation = PalmaOperationType::ReadUniqueCode;
operation.result = PalmaResultSuccess;
operation.data = {};
operation_complete_event->GetWritableEvent().Signal();
return ResultSuccess;
}
Result Controller_Palma::SetPalmaUniqueCodeInvalid(const PalmaConnectionHandle& handle) {
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
operation.operation = PalmaOperationType::SetUniqueCodeInvalid;
operation.result = PalmaResultSuccess;
operation.data = {};
operation_complete_event->GetWritableEvent().Signal();
return ResultSuccess;
}
void Controller_Palma::WritePalmaActivityEntry() {}
Result Controller_Palma::WritePalmaRgbLedPatternEntry(const PalmaConnectionHandle& handle,
u64 unknown) {
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
operation.operation = PalmaOperationType::WriteRgbLedPatternEntry;
operation.result = PalmaResultSuccess;
operation.data = {};
operation_complete_event->GetWritableEvent().Signal();
return ResultSuccess;
}
Result Controller_Palma::WritePalmaWaveEntry(const PalmaConnectionHandle& handle, PalmaWaveSet wave,
u8* t_mem, u64 size) {
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
operation.operation = PalmaOperationType::WriteWaveEntry;
operation.result = PalmaResultSuccess;
operation.data = {};
operation_complete_event->GetWritableEvent().Signal();
return ResultSuccess;
}
Result Controller_Palma::SetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle,
s32 database_id_version_) {
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
database_id_version = database_id_version_;
operation.operation = PalmaOperationType::ReadDataBaseIdentificationVersion;
operation.result = PalmaResultSuccess;
operation.data[0] = {};
operation_complete_event->GetWritableEvent().Signal();
return ResultSuccess;
}
Result Controller_Palma::GetPalmaDataBaseIdentificationVersion(
const PalmaConnectionHandle& handle) {
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
operation.operation = PalmaOperationType::ReadDataBaseIdentificationVersion;
operation.result = PalmaResultSuccess;
operation.data = {};
operation.data[0] = static_cast<u8>(database_id_version);
operation_complete_event->GetWritableEvent().Signal();
return ResultSuccess;
}
void Controller_Palma::SuspendPalmaFeature() {}
Result Controller_Palma::GetPalmaOperationResult(const PalmaConnectionHandle& handle) const {
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
return operation.result;
}
void Controller_Palma::ReadPalmaPlayLog() {}
void Controller_Palma::ResetPalmaPlayLog() {}
void Controller_Palma::SetIsPalmaAllConnectable(bool is_all_connectable) {
// If true controllers are able to be paired
is_connectable = is_all_connectable;
}
void Controller_Palma::SetIsPalmaPairedConnectable() {}
Result Controller_Palma::PairPalma(const PalmaConnectionHandle& handle) {
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
// TODO: Do something
return ResultSuccess;
}
void Controller_Palma::SetPalmaBoostMode(bool boost_mode) {}
void Controller_Palma::CancelWritePalmaWaveEntry() {}
void Controller_Palma::EnablePalmaBoostMode() {}
void Controller_Palma::GetPalmaBluetoothAddress() {}
void Controller_Palma::SetDisallowedPalmaConnection() {}
} // namespace Service::HID

View File

@@ -0,0 +1,163 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/errors.h"
namespace Kernel {
class KEvent;
class KReadableEvent;
} // namespace Kernel
namespace Service::KernelHelpers {
class ServiceContext;
}
namespace Core::HID {
class EmulatedController;
} // namespace Core::HID
namespace Service::HID {
class Controller_Palma final : public ControllerBase {
public:
using PalmaOperationData = std::array<u8, 0x140>;
// This is nn::hid::PalmaOperationType
enum class PalmaOperationType {
PlayActivity,
SetFrModeType,
ReadStep,
EnableStep,
ResetStep,
ReadApplicationSection,
WriteApplicationSection,
ReadUniqueCode,
SetUniqueCodeInvalid,
WriteActivityEntry,
WriteRgbLedPatternEntry,
WriteWaveEntry,
ReadDataBaseIdentificationVersion,
WriteDataBaseIdentificationVersion,
SuspendFeature,
ReadPlayLog,
ResetPlayLog,
};
// This is nn::hid::PalmaWaveSet
enum class PalmaWaveSet : u64 {
Small,
Medium,
Large,
};
// This is nn::hid::PalmaFrModeType
enum class PalmaFrModeType : u64 {
Off,
B01,
B02,
B03,
Downloaded,
};
// This is nn::hid::PalmaFeature
enum class PalmaFeature : u64 {
FrMode,
RumbleFeedback,
Step,
MuteSwitch,
};
// This is nn::hid::PalmaOperationInfo
struct PalmaOperationInfo {
PalmaOperationType operation{};
Result result{PalmaResultSuccess};
PalmaOperationData data{};
};
static_assert(sizeof(PalmaOperationInfo) == 0x148, "PalmaOperationInfo is an invalid size");
// This is nn::hid::PalmaActivityEntry
struct PalmaActivityEntry {
u32 rgb_led_pattern_index;
INSERT_PADDING_BYTES(2);
PalmaWaveSet wave_set;
u32 wave_index;
INSERT_PADDING_BYTES(12);
};
static_assert(sizeof(PalmaActivityEntry) == 0x20, "PalmaActivityEntry is an invalid size");
struct PalmaConnectionHandle {
Core::HID::NpadIdType npad_id;
INSERT_PADDING_BYTES(4); // Unknown
};
static_assert(sizeof(PalmaConnectionHandle) == 0x8,
"PalmaConnectionHandle has incorrect size.");
explicit Controller_Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
KernelHelpers::ServiceContext& service_context_);
~Controller_Palma() override;
// Called when the controller is initialized
void OnInit() override;
// When the controller is released
void OnRelease() override;
// When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
Result GetPalmaConnectionHandle(Core::HID::NpadIdType npad_id, PalmaConnectionHandle& handle);
Result InitializePalma(const PalmaConnectionHandle& handle);
Kernel::KReadableEvent& AcquirePalmaOperationCompleteEvent(
const PalmaConnectionHandle& handle) const;
Result GetPalmaOperationInfo(const PalmaConnectionHandle& handle,
PalmaOperationType& operation_type,
PalmaOperationData& data) const;
Result PlayPalmaActivity(const PalmaConnectionHandle& handle, u64 palma_activity);
Result SetPalmaFrModeType(const PalmaConnectionHandle& handle, PalmaFrModeType fr_mode_);
Result ReadPalmaStep(const PalmaConnectionHandle& handle);
Result EnablePalmaStep(const PalmaConnectionHandle& handle, bool is_enabled);
Result ResetPalmaStep(const PalmaConnectionHandle& handle);
Result ReadPalmaUniqueCode(const PalmaConnectionHandle& handle);
Result SetPalmaUniqueCodeInvalid(const PalmaConnectionHandle& handle);
Result WritePalmaRgbLedPatternEntry(const PalmaConnectionHandle& handle, u64 unknown);
Result WritePalmaWaveEntry(const PalmaConnectionHandle& handle, PalmaWaveSet wave, u8* t_mem,
u64 size);
Result SetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle,
s32 database_id_version_);
Result GetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle);
Result GetPalmaOperationResult(const PalmaConnectionHandle& handle) const;
void SetIsPalmaAllConnectable(bool is_all_connectable);
Result PairPalma(const PalmaConnectionHandle& handle);
void SetPalmaBoostMode(bool boost_mode);
private:
void ReadPalmaApplicationSection();
void WritePalmaApplicationSection();
void WritePalmaActivityEntry();
void SuspendPalmaFeature();
void ReadPalmaPlayLog();
void ResetPalmaPlayLog();
void SetIsPalmaPairedConnectable();
void CancelWritePalmaWaveEntry();
void EnablePalmaBoostMode();
void GetPalmaBluetoothAddress();
void SetDisallowedPalmaConnection();
bool is_connectable{};
s32 database_id_version{};
PalmaOperationInfo operation{};
PalmaFrModeType fr_mode{};
PalmaConnectionHandle active_handle{};
Core::HID::EmulatedController* controller;
Kernel::KEvent* operation_complete_event;
KernelHelpers::ServiceContext& service_context;
};
} // namespace Service::HID

View File

@@ -7,6 +7,7 @@
namespace Service::HID {
constexpr Result PalmaResultSuccess{ErrorModule::HID, 0};
constexpr Result NpadInvalidHandle{ErrorModule::HID, 100};
constexpr Result NpadDeviceIndexOutOfRange{ErrorModule::HID, 107};
constexpr Result VibrationInvalidStyleIndex{ErrorModule::HID, 122};
@@ -17,6 +18,7 @@ constexpr Result NpadIsDualJoycon{ErrorModule::HID, 601};
constexpr Result NpadIsSameType{ErrorModule::HID, 602};
constexpr Result InvalidNpadId{ErrorModule::HID, 709};
constexpr Result NpadNotConnected{ErrorModule::HID, 710};
constexpr Result InvalidPalmaHandle{ErrorModule::HID, 3302};
} // namespace Service::HID

View File

@@ -27,6 +27,7 @@
#include "core/hle/service/hid/controllers/keyboard.h"
#include "core/hle/service/hid/controllers/mouse.h"
#include "core/hle/service/hid/controllers/npad.h"
#include "core/hle/service/hid/controllers/palma.h"
#include "core/hle/service/hid/controllers/stubbed.h"
#include "core/hle/service/hid/controllers/touchscreen.h"
#include "core/hle/service/hid/controllers/xpad.h"
@@ -60,6 +61,7 @@ IAppletResource::IAppletResource(Core::System& system_,
MakeControllerWithServiceContext<Controller_NPad>(HidController::NPad, shared_memory);
MakeController<Controller_Gesture>(HidController::Gesture, shared_memory);
MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor, shared_memory);
MakeControllerWithServiceContext<Controller_Palma>(HidController::Palma, shared_memory);
// Homebrew doesn't try to activate some controllers, so we activate them by default
GetController<Controller_NPad>(HidController::NPad).ActivateController();
@@ -310,36 +312,36 @@ Hid::Hid(Core::System& system_)
{406, nullptr, "GetNpadLeftRightInterfaceType"},
{407, nullptr, "GetNpadOfHighestBatteryLevel"},
{408, nullptr, "GetNpadOfHighestBatteryLevelForJoyRight"},
{500, nullptr, "GetPalmaConnectionHandle"},
{501, nullptr, "InitializePalma"},
{502, nullptr, "AcquirePalmaOperationCompleteEvent"},
{503, nullptr, "GetPalmaOperationInfo"},
{504, nullptr, "PlayPalmaActivity"},
{505, nullptr, "SetPalmaFrModeType"},
{506, nullptr, "ReadPalmaStep"},
{507, nullptr, "EnablePalmaStep"},
{508, nullptr, "ResetPalmaStep"},
{509, nullptr, "ReadPalmaApplicationSection"},
{510, nullptr, "WritePalmaApplicationSection"},
{511, nullptr, "ReadPalmaUniqueCode"},
{512, nullptr, "SetPalmaUniqueCodeInvalid"},
{513, nullptr, "WritePalmaActivityEntry"},
{514, nullptr, "WritePalmaRgbLedPatternEntry"},
{515, nullptr, "WritePalmaWaveEntry"},
{516, nullptr, "SetPalmaDataBaseIdentificationVersion"},
{517, nullptr, "GetPalmaDataBaseIdentificationVersion"},
{518, nullptr, "SuspendPalmaFeature"},
{519, nullptr, "GetPalmaOperationResult"},
{520, nullptr, "ReadPalmaPlayLog"},
{521, nullptr, "ResetPalmaPlayLog"},
{500, &Hid::GetPalmaConnectionHandle, "GetPalmaConnectionHandle"},
{501, &Hid::InitializePalma, "InitializePalma"},
{502, &Hid::AcquirePalmaOperationCompleteEvent, "AcquirePalmaOperationCompleteEvent"},
{503, &Hid::GetPalmaOperationInfo, "GetPalmaOperationInfo"},
{504, &Hid::PlayPalmaActivity, "PlayPalmaActivity"},
{505, &Hid::SetPalmaFrModeType, "SetPalmaFrModeType"},
{506, &Hid::ReadPalmaStep, "ReadPalmaStep"},
{507, &Hid::EnablePalmaStep, "EnablePalmaStep"},
{508, &Hid::ResetPalmaStep, "ResetPalmaStep"},
{509, &Hid::ReadPalmaApplicationSection, "ReadPalmaApplicationSection"},
{510, &Hid::WritePalmaApplicationSection, "WritePalmaApplicationSection"},
{511, &Hid::ReadPalmaUniqueCode, "ReadPalmaUniqueCode"},
{512, &Hid::SetPalmaUniqueCodeInvalid, "SetPalmaUniqueCodeInvalid"},
{513, &Hid::WritePalmaActivityEntry, "WritePalmaActivityEntry"},
{514, &Hid::WritePalmaRgbLedPatternEntry, "WritePalmaRgbLedPatternEntry"},
{515, &Hid::WritePalmaWaveEntry, "WritePalmaWaveEntry"},
{516, &Hid::SetPalmaDataBaseIdentificationVersion, "SetPalmaDataBaseIdentificationVersion"},
{517, &Hid::GetPalmaDataBaseIdentificationVersion, "GetPalmaDataBaseIdentificationVersion"},
{518, &Hid::SuspendPalmaFeature, "SuspendPalmaFeature"},
{519, &Hid::GetPalmaOperationResult, "GetPalmaOperationResult"},
{520, &Hid::ReadPalmaPlayLog, "ReadPalmaPlayLog"},
{521, &Hid::ResetPalmaPlayLog, "ResetPalmaPlayLog"},
{522, &Hid::SetIsPalmaAllConnectable, "SetIsPalmaAllConnectable"},
{523, nullptr, "SetIsPalmaPairedConnectable"},
{524, nullptr, "PairPalma"},
{523, &Hid::SetIsPalmaPairedConnectable, "SetIsPalmaPairedConnectable"},
{524, &Hid::PairPalma, "PairPalma"},
{525, &Hid::SetPalmaBoostMode, "SetPalmaBoostMode"},
{526, nullptr, "CancelWritePalmaWaveEntry"},
{527, nullptr, "EnablePalmaBoostMode"},
{528, nullptr, "GetPalmaBluetoothAddress"},
{529, nullptr, "SetDisallowedPalmaConnection"},
{526, &Hid::CancelWritePalmaWaveEntry, "CancelWritePalmaWaveEntry"},
{527, &Hid::EnablePalmaBoostMode, "EnablePalmaBoostMode"},
{528, &Hid::GetPalmaBluetoothAddress, "GetPalmaBluetoothAddress"},
{529, &Hid::SetDisallowedPalmaConnection, "SetDisallowedPalmaConnection"},
{1000, &Hid::SetNpadCommunicationMode, "SetNpadCommunicationMode"},
{1001, &Hid::GetNpadCommunicationMode, "GetNpadCommunicationMode"},
{1002, &Hid::SetTouchScreenConfiguration, "SetTouchScreenConfiguration"},
@@ -1878,14 +1880,361 @@ void Hid::IsUsbFullKeyControllerEnabled(Kernel::HLERequestContext& ctx) {
rb.Push(false);
}
void Hid::SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) {
void Hid::GetPalmaConnectionHandle(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
const auto is_palma_all_connectable{rp.Pop<bool>()};
struct Parameters {
Core::HID::NpadIdType npad_id;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
parameters.npad_id, parameters.applet_resource_user_id);
Controller_Palma::PalmaConnectionHandle handle;
auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
const auto result = controller.GetPalmaConnectionHandle(parameters.npad_id, handle);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(result);
rb.PushRaw(handle);
}
void Hid::InitializePalma(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
const auto result = controller.InitializePalma(connection_handle);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void Hid::AcquirePalmaOperationCompleteEvent(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(controller.AcquirePalmaOperationCompleteEvent(connection_handle));
}
void Hid::GetPalmaOperationInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
Controller_Palma::PalmaOperationType operation_type;
Controller_Palma::PalmaOperationData data;
auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
const auto result = controller.GetPalmaOperationInfo(connection_handle, operation_type, data);
if (result.IsError()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
ctx.WriteBuffer(data);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(result);
rb.Push(static_cast<u64>(operation_type));
}
void Hid::PlayPalmaActivity(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
const auto palma_activity{rp.Pop<u64>()};
LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, palma_activity={}",
connection_handle.npad_id, palma_activity);
auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
const auto result = controller.PlayPalmaActivity(connection_handle, palma_activity);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void Hid::SetPalmaFrModeType(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
const auto fr_mode{rp.PopEnum<Controller_Palma::PalmaFrModeType>()};
LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, fr_mode={}",
connection_handle.npad_id, fr_mode);
auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
const auto result = controller.SetPalmaFrModeType(connection_handle, fr_mode);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void Hid::ReadPalmaStep(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
const auto result = controller.ReadPalmaStep(connection_handle);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void Hid::EnablePalmaStep(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
bool is_enabled;
INSERT_PADDING_WORDS_NOINIT(1);
Controller_Palma::PalmaConnectionHandle connection_handle;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, is_enabled={}",
parameters.connection_handle.npad_id, parameters.is_enabled);
auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
const auto result =
controller.EnablePalmaStep(parameters.connection_handle, parameters.is_enabled);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void Hid::ResetPalmaStep(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
const auto result = controller.ResetPalmaStep(connection_handle);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void Hid::ReadPalmaApplicationSection(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Hid::WritePalmaApplicationSection(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Hid::ReadPalmaUniqueCode(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
applet_resource->GetController<Controller_Palma>(HidController::Palma)
.ReadPalmaUniqueCode(connection_handle);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Hid::SetPalmaUniqueCodeInvalid(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
applet_resource->GetController<Controller_Palma>(HidController::Palma)
.SetPalmaUniqueCodeInvalid(connection_handle);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Hid::WritePalmaActivityEntry(Kernel::HLERequestContext& ctx) {
LOG_CRITICAL(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Hid::WritePalmaRgbLedPatternEntry(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
const auto unknown{rp.Pop<u64>()};
const auto buffer = ctx.ReadBuffer();
LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, unknown={}",
connection_handle.npad_id, unknown);
applet_resource->GetController<Controller_Palma>(HidController::Palma)
.WritePalmaRgbLedPatternEntry(connection_handle, unknown);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Hid::WritePalmaWaveEntry(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
const auto wave_set{rp.PopEnum<Controller_Palma::PalmaWaveSet>()};
const auto unknown{rp.Pop<u64>()};
const auto t_mem_size{rp.Pop<u64>()};
const auto t_mem_handle{ctx.GetCopyHandle(0)};
const auto size{rp.Pop<u64>()};
ASSERT_MSG(t_mem_size == 0x3000, "t_mem_size is not 0x3000 bytes");
auto t_mem =
system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle);
if (t_mem.IsNull()) {
LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultUnknown);
return;
}
ASSERT_MSG(t_mem->GetSize() == 0x3000, "t_mem has incorrect size");
LOG_WARNING(Service_HID,
"(STUBBED) called, applet_resource_user_id={}, is_palma_all_connectable={}",
applet_resource_user_id, is_palma_all_connectable);
"(STUBBED) called, connection_handle={}, wave_set={}, unkown={}, "
"t_mem_handle=0x{:08X}, t_mem_size={}, size={}",
connection_handle.npad_id, wave_set, unknown, t_mem_handle, t_mem_size, size);
applet_resource->GetController<Controller_Palma>(HidController::Palma)
.WritePalmaWaveEntry(connection_handle, wave_set,
system.Memory().GetPointer(t_mem->GetSourceAddress()), t_mem_size);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Hid::SetPalmaDataBaseIdentificationVersion(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
s32 database_id_version;
INSERT_PADDING_WORDS_NOINIT(1);
Controller_Palma::PalmaConnectionHandle connection_handle;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, database_id_version={}",
parameters.connection_handle.npad_id, parameters.database_id_version);
applet_resource->GetController<Controller_Palma>(HidController::Palma)
.SetPalmaDataBaseIdentificationVersion(parameters.connection_handle,
parameters.database_id_version);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Hid::GetPalmaDataBaseIdentificationVersion(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
applet_resource->GetController<Controller_Palma>(HidController::Palma)
.GetPalmaDataBaseIdentificationVersion(connection_handle);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Hid::SuspendPalmaFeature(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Hid::GetPalmaOperationResult(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
const auto result = applet_resource->GetController<Controller_Palma>(HidController::Palma)
.GetPalmaOperationResult(connection_handle);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void Hid::ReadPalmaPlayLog(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Hid::ResetPalmaPlayLog(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Hid::SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
bool is_palma_all_connectable;
INSERT_PADDING_BYTES_NOINIT(7);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_HID,
"(STUBBED) called, is_palma_all_connectable={},applet_resource_user_id={}",
parameters.is_palma_all_connectable, parameters.applet_resource_user_id);
applet_resource->GetController<Controller_Palma>(HidController::Palma)
.SetIsPalmaAllConnectable(parameters.is_palma_all_connectable);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Hid::SetIsPalmaPairedConnectable(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Hid::PairPalma(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
applet_resource->GetController<Controller_Palma>(HidController::Palma)
.PairPalma(connection_handle);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -1897,6 +2246,37 @@ void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called, palma_boost_mode={}", palma_boost_mode);
applet_resource->GetController<Controller_Palma>(HidController::Palma)
.SetPalmaBoostMode(palma_boost_mode);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Hid::CancelWritePalmaWaveEntry(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Hid::EnablePalmaBoostMode(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Hid::GetPalmaBluetoothAddress(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Hid::SetDisallowedPalmaConnection(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}

View File

@@ -33,6 +33,7 @@ enum class HidController : std::size_t {
NPad,
Gesture,
ConsoleSixAxisSensor,
Palma,
MaxControllers,
};
@@ -166,8 +167,36 @@ private:
void FinalizeSevenSixAxisSensor(Kernel::HLERequestContext& ctx);
void ResetSevenSixAxisSensorTimestamp(Kernel::HLERequestContext& ctx);
void IsUsbFullKeyControllerEnabled(Kernel::HLERequestContext& ctx);
void GetPalmaConnectionHandle(Kernel::HLERequestContext& ctx);
void InitializePalma(Kernel::HLERequestContext& ctx);
void AcquirePalmaOperationCompleteEvent(Kernel::HLERequestContext& ctx);
void GetPalmaOperationInfo(Kernel::HLERequestContext& ctx);
void PlayPalmaActivity(Kernel::HLERequestContext& ctx);
void SetPalmaFrModeType(Kernel::HLERequestContext& ctx);
void ReadPalmaStep(Kernel::HLERequestContext& ctx);
void EnablePalmaStep(Kernel::HLERequestContext& ctx);
void ResetPalmaStep(Kernel::HLERequestContext& ctx);
void ReadPalmaApplicationSection(Kernel::HLERequestContext& ctx);
void WritePalmaApplicationSection(Kernel::HLERequestContext& ctx);
void ReadPalmaUniqueCode(Kernel::HLERequestContext& ctx);
void SetPalmaUniqueCodeInvalid(Kernel::HLERequestContext& ctx);
void WritePalmaActivityEntry(Kernel::HLERequestContext& ctx);
void WritePalmaRgbLedPatternEntry(Kernel::HLERequestContext& ctx);
void WritePalmaWaveEntry(Kernel::HLERequestContext& ctx);
void SetPalmaDataBaseIdentificationVersion(Kernel::HLERequestContext& ctx);
void GetPalmaDataBaseIdentificationVersion(Kernel::HLERequestContext& ctx);
void SuspendPalmaFeature(Kernel::HLERequestContext& ctx);
void GetPalmaOperationResult(Kernel::HLERequestContext& ctx);
void ReadPalmaPlayLog(Kernel::HLERequestContext& ctx);
void ResetPalmaPlayLog(Kernel::HLERequestContext& ctx);
void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx);
void SetIsPalmaPairedConnectable(Kernel::HLERequestContext& ctx);
void PairPalma(Kernel::HLERequestContext& ctx);
void SetPalmaBoostMode(Kernel::HLERequestContext& ctx);
void CancelWritePalmaWaveEntry(Kernel::HLERequestContext& ctx);
void EnablePalmaBoostMode(Kernel::HLERequestContext& ctx);
void GetPalmaBluetoothAddress(Kernel::HLERequestContext& ctx);
void SetDisallowedPalmaConnection(Kernel::HLERequestContext& ctx);
void SetNpadCommunicationMode(Kernel::HLERequestContext& ctx);
void GetNpadCommunicationMode(Kernel::HLERequestContext& ctx);
void SetTouchScreenConfiguration(Kernel::HLERequestContext& ctx);

View File

@@ -542,7 +542,8 @@ Result IRS::IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_h
Core::IrSensor::DeviceFormat& IRS::GetIrCameraSharedMemoryDeviceEntry(
const Core::IrSensor::IrCameraHandle& camera_handle) {
ASSERT_MSG(sizeof(StatusManager::device) > camera_handle.npad_id, "invalid npad_id");
const auto npad_id_max_index = static_cast<u8>(sizeof(StatusManager::device));
ASSERT_MSG(camera_handle.npad_id < npad_id_max_index, "invalid npad_id");
return shared_memory->device[camera_handle.npad_id];
}

View File

@@ -364,7 +364,7 @@ std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) {
std::vector<WSAPOLLFD> host_pollfds(pollfds.size());
std::transform(pollfds.begin(), pollfds.end(), host_pollfds.begin(), [](PollFD fd) {
WSAPOLLFD result;
result.fd = fd.socket->fd;
result.fd = fd.socket->GetFD();
result.events = TranslatePollEvents(fd.events);
result.revents = 0;
return result;
@@ -430,12 +430,12 @@ std::pair<SocketBase::AcceptResult, Errno> Socket::Accept() {
return {AcceptResult{}, GetAndLogLastError()};
}
AcceptResult result;
result.socket = std::make_unique<Socket>();
result.socket->fd = new_socket;
ASSERT(addrlen == sizeof(sockaddr_in));
result.sockaddr_in = TranslateToSockAddrIn(addr);
AcceptResult result{
.socket = std::make_unique<Socket>(new_socket),
.sockaddr_in = TranslateToSockAddrIn(addr),
};
return {std::move(result), Errno::SUCCESS};
}

View File

@@ -32,6 +32,10 @@ public:
std::unique_ptr<SocketBase> socket;
SockAddrIn sockaddr_in;
};
SocketBase() = default;
explicit SocketBase(SOCKET fd_) : fd{fd_} {}
virtual ~SocketBase() = default;
virtual SocketBase& operator=(const SocketBase&) = delete;
@@ -89,12 +93,19 @@ public:
virtual void HandleProxyPacket(const ProxyPacket& packet) = 0;
[[nodiscard]] SOCKET GetFD() const {
return fd;
}
protected:
SOCKET fd = INVALID_SOCKET;
};
class Socket : public SocketBase {
public:
Socket() = default;
explicit Socket(SOCKET fd_) : SocketBase{fd_} {}
~Socket() override;
Socket(const Socket&) = delete;

View File

@@ -244,6 +244,10 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V
std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file,
u64 program_id, std::size_t program_index) {
if (!file) {
return nullptr;
}
FileType type = IdentifyFile(file);
const FileType filename_type = GuessFromFilename(file->GetName());

View File

@@ -1065,7 +1065,7 @@ TexelWeightParams DecodeBlockInfo() {
void FillError(ivec3 coord) {
for (uint j = 0; j < block_dims.y; j++) {
for (uint i = 0; i < block_dims.x; i++) {
imageStore(dest_image, coord + ivec3(i, j, 0), vec4(1.0, 1.0, 0.0, 1.0));
imageStore(dest_image, coord + ivec3(i, j, 0), vec4(0.0, 0.0, 0.0, 0.0));
}
}
}

View File

@@ -3,6 +3,8 @@
#include <array>
#include <vector>
#include "common/scope_exit.h"
#include "video_core/dirty_flags.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/macro/macro.h"
#include "video_core/macro/macro_hle.h"
@@ -58,6 +60,7 @@ void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&
maxwell3d.regs.index_array.first = parameters[3];
maxwell3d.regs.reg_array[0x446] = element_base; // vertex id base?
maxwell3d.regs.index_array.count = parameters[1];
maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
maxwell3d.regs.vb_element_base = element_base;
maxwell3d.regs.vb_base_instance = base_instance;
maxwell3d.mme_draw.instance_count = instance_count;
@@ -80,10 +83,67 @@ void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&
maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined;
}
constexpr std::array<std::pair<u64, HLEFunction>, 3> hle_funcs{{
// Multidraw Indirect
void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) {
SCOPE_EXIT({
// Clean everything.
maxwell3d.regs.reg_array[0x446] = 0x0; // vertex id base?
maxwell3d.regs.index_array.count = 0;
maxwell3d.regs.vb_element_base = 0x0;
maxwell3d.regs.vb_base_instance = 0x0;
maxwell3d.mme_draw.instance_count = 0;
maxwell3d.CallMethodFromMME(0x8e3, 0x640);
maxwell3d.CallMethodFromMME(0x8e4, 0x0);
maxwell3d.CallMethodFromMME(0x8e5, 0x0);
maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined;
maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
});
const u32 start_indirect = parameters[0];
const u32 end_indirect = parameters[1];
if (start_indirect >= end_indirect) {
// Nothing to do.
return;
}
const auto topology =
static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[2]);
maxwell3d.regs.draw.topology.Assign(topology);
const u32 padding = parameters[3];
const std::size_t max_draws = parameters[4];
const u32 indirect_words = 5 + padding;
const std::size_t first_draw = start_indirect;
const std::size_t effective_draws = end_indirect - start_indirect;
const std::size_t last_draw = start_indirect + std::min(effective_draws, max_draws);
for (std::size_t index = first_draw; index < last_draw; index++) {
const std::size_t base = index * indirect_words + 5;
const u32 num_vertices = parameters[base];
const u32 instance_count = parameters[base + 1];
const u32 first_index = parameters[base + 2];
const u32 base_vertex = parameters[base + 3];
const u32 base_instance = parameters[base + 4];
maxwell3d.regs.index_array.first = first_index;
maxwell3d.regs.reg_array[0x446] = base_vertex;
maxwell3d.regs.index_array.count = num_vertices;
maxwell3d.regs.vb_element_base = base_vertex;
maxwell3d.regs.vb_base_instance = base_instance;
maxwell3d.mme_draw.instance_count = instance_count;
maxwell3d.CallMethodFromMME(0x8e3, 0x640);
maxwell3d.CallMethodFromMME(0x8e4, base_vertex);
maxwell3d.CallMethodFromMME(0x8e5, base_instance);
maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
if (maxwell3d.ShouldExecute()) {
maxwell3d.Rasterizer().Draw(true, true);
}
maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined;
}
}
constexpr std::array<std::pair<u64, HLEFunction>, 4> hle_funcs{{
{0x771BB18C62444DA0, &HLE_771BB18C62444DA0},
{0x0D61FC9FAAC9FCAD, &HLE_0D61FC9FAAC9FCAD},
{0x0217920100488FF7, &HLE_0217920100488FF7},
{0x3F5E74B9C9A50164, &HLE_3F5E74B9C9A50164},
}};
class HLEMacroImpl final : public CachedMacro {
@@ -99,6 +159,7 @@ private:
Engines::Maxwell3D& maxwell3d;
HLEFunction func;
};
} // Anonymous namespace
HLEMacro::HLEMacro(Engines::Maxwell3D& maxwell3d_) : maxwell3d{maxwell3d_} {}

View File

@@ -1413,7 +1413,7 @@ static void FillVoidExtentLDR(InputBitStream& strm, std::span<u32> outBuf, u32 b
static void FillError(std::span<u32> outBuf, u32 blockWidth, u32 blockHeight) {
for (u32 j = 0; j < blockHeight; j++) {
for (u32 i = 0; i < blockWidth; i++) {
outBuf[j * blockWidth + i] = 0xFFFF00FF;
outBuf[j * blockWidth + i] = 0x00000000;
}
}
}

View File

@@ -291,7 +291,7 @@ bool QtControllerSelectorDialog::CheckIfParametersMet() {
// Here, we check and validate the current configuration against all applicable parameters.
const auto num_connected_players = static_cast<int>(
std::count_if(player_groupboxes.begin(), player_groupboxes.end(),
[this](const QGroupBox* player) { return player->isChecked(); }));
[](const QGroupBox* player) { return player->isChecked(); }));
const auto min_supported_players = parameters.enable_single_mode ? 1 : parameters.min_players;
const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players;

View File

@@ -546,6 +546,7 @@ void Config::ReadDebuggingValues() {
ReadBasicSetting(Settings::values.use_auto_stub);
ReadBasicSetting(Settings::values.enable_all_controllers);
ReadBasicSetting(Settings::values.create_crash_dumps);
ReadBasicSetting(Settings::values.perform_vulkan_check);
qt_config->endGroup();
}
@@ -1162,6 +1163,7 @@ void Config::SaveDebuggingValues() {
WriteBasicSetting(Settings::values.disable_macro_jit);
WriteBasicSetting(Settings::values.enable_all_controllers);
WriteBasicSetting(Settings::values.create_crash_dumps);
WriteBasicSetting(Settings::values.perform_vulkan_check);
qt_config->endGroup();
}

View File

@@ -77,6 +77,7 @@ void ConfigureDebug::SetConfiguration() {
ui->disable_loop_safety_checks->setChecked(
Settings::values.disable_shader_loop_safety_checks.GetValue());
ui->extended_logging->setChecked(Settings::values.extended_logging.GetValue());
ui->perform_vulkan_check->setChecked(Settings::values.perform_vulkan_check.GetValue());
#ifdef YUZU_USE_QT_WEB_ENGINE
ui->disable_web_applet->setChecked(UISettings::values.disable_web_applet.GetValue());
@@ -117,6 +118,7 @@ void ConfigureDebug::ApplyConfiguration() {
ui->disable_loop_safety_checks->isChecked();
Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked();
Settings::values.extended_logging = ui->extended_logging->isChecked();
Settings::values.perform_vulkan_check = ui->perform_vulkan_check->isChecked();
UISettings::values.disable_web_applet = ui->disable_web_applet->isChecked();
Debugger::ToggleConsole();
Common::Log::Filter filter;

View File

@@ -313,6 +313,16 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="perform_vulkan_check">
<property name="toolTip">
<string>Enables yuzu to check for a working Vulkan environment when the program starts up. Disable this if this is causing issues with external programs seeing yuzu.</string>
</property>
<property name="text">
<string>Perform Startup Vulkan Check</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@@ -163,10 +163,9 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
[this, input_subsystem, &hid_core] {
CallConfigureDialog<ConfigureRingController>(*this, input_subsystem, hid_core);
});
connect(advanced, &ConfigureInputAdvanced::CallCameraDialog,
[this, input_subsystem, &hid_core] {
CallConfigureDialog<ConfigureCamera>(*this, input_subsystem);
});
connect(advanced, &ConfigureInputAdvanced::CallCameraDialog, [this, input_subsystem] {
CallConfigureDialog<ConfigureCamera>(*this, input_subsystem);
});
connect(ui->vibrationButton, &QPushButton::clicked,
[this, &hid_core] { CallConfigureDialog<ConfigureVibration>(*this, hid_core); });

View File

@@ -67,6 +67,8 @@ std::vector<std::string> InputProfiles::GetInputProfileNames() {
profile_names.push_back(profile_name);
}
std::stable_sort(profile_names.begin(), profile_names.end());
return profile_names;
}

View File

@@ -2000,7 +2000,7 @@ static bool RomFSRawCopy(QProgressDialog& dialog, const FileSys::VirtualDir& src
}
void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type) {
const QString entry_type = [this, type] {
const QString entry_type = [type] {
switch (type) {
case InstalledEntryType::Game:
return tr("Contents");
@@ -2097,7 +2097,7 @@ void GMainWindow::RemoveAddOnContent(u64 program_id, const QString& entry_type)
void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target,
const std::string& game_path) {
const QString question = [this, target] {
const QString question = [target] {
switch (target) {
case GameListRemoveTarget::GlShaderCache:
return tr("Delete OpenGL Transferable Shader Cache?");
@@ -4086,7 +4086,8 @@ int main(int argc, char* argv[]) {
}
#endif
if (StartupChecks(argv[0], &has_broken_vulkan)) {
if (StartupChecks(argv[0], &has_broken_vulkan,
Settings::values.perform_vulkan_check.GetValue())) {
return 0;
}

View File

@@ -57,7 +57,7 @@ bool CheckEnvVars(bool* is_child) {
return false;
}
bool StartupChecks(const char* arg0, bool* has_broken_vulkan) {
bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulkan_check) {
#ifdef _WIN32
// Set the startup variable for child processes
const bool env_var_set = SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, ENV_VAR_ENABLED_TEXT);
@@ -67,29 +67,32 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan) {
return false;
}
PROCESS_INFORMATION process_info;
std::memset(&process_info, '\0', sizeof(process_info));
if (perform_vulkan_check) {
// Spawn child process that performs Vulkan check
PROCESS_INFORMATION process_info;
std::memset(&process_info, '\0', sizeof(process_info));
if (!SpawnChild(arg0, &process_info, 0)) {
return false;
}
if (!SpawnChild(arg0, &process_info, 0)) {
return false;
}
// Wait until the processs exits and get exit code from it
WaitForSingleObject(process_info.hProcess, INFINITE);
DWORD exit_code = STILL_ACTIVE;
const int err = GetExitCodeProcess(process_info.hProcess, &exit_code);
if (err == 0) {
std::fprintf(stderr, "GetExitCodeProcess failed with error %d\n", GetLastError());
}
// Wait until the processs exits and get exit code from it
WaitForSingleObject(process_info.hProcess, INFINITE);
DWORD exit_code = STILL_ACTIVE;
const int err = GetExitCodeProcess(process_info.hProcess, &exit_code);
if (err == 0) {
std::fprintf(stderr, "GetExitCodeProcess failed with error %d\n", GetLastError());
}
// Vulkan is broken if the child crashed (return value is not zero)
*has_broken_vulkan = (exit_code != 0);
// Vulkan is broken if the child crashed (return value is not zero)
*has_broken_vulkan = (exit_code != 0);
if (CloseHandle(process_info.hProcess) == 0) {
std::fprintf(stderr, "CloseHandle failed with error %d\n", GetLastError());
}
if (CloseHandle(process_info.hThread) == 0) {
std::fprintf(stderr, "CloseHandle failed with error %d\n", GetLastError());
if (CloseHandle(process_info.hProcess) == 0) {
std::fprintf(stderr, "CloseHandle failed with error %d\n", GetLastError());
}
if (CloseHandle(process_info.hThread) == 0) {
std::fprintf(stderr, "CloseHandle failed with error %d\n", GetLastError());
}
}
if (!SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, nullptr)) {
@@ -98,26 +101,28 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan) {
}
#elif defined(YUZU_UNIX)
const pid_t pid = fork();
if (pid == 0) {
CheckVulkan();
return true;
} else if (pid == -1) {
const int err = errno;
std::fprintf(stderr, "fork failed with error %d\n", err);
return false;
}
if (perform_vulkan_check) {
const pid_t pid = fork();
if (pid == 0) {
CheckVulkan();
return true;
} else if (pid == -1) {
const int err = errno;
std::fprintf(stderr, "fork failed with error %d\n", err);
return false;
}
// Get exit code from child process
int status;
const int r_val = wait(&status);
if (r_val == -1) {
const int err = errno;
std::fprintf(stderr, "wait failed with error %d\n", err);
return false;
// Get exit code from child process
int status;
const int r_val = wait(&status);
if (r_val == -1) {
const int err = errno;
std::fprintf(stderr, "wait failed with error %d\n", err);
return false;
}
// Vulkan is broken if the child crashed (return value is not zero)
*has_broken_vulkan = (status != 0);
}
// Vulkan is broken if the child crashed (return value is not zero)
*has_broken_vulkan = (status != 0);
#endif
return false;
}

View File

@@ -13,7 +13,7 @@ constexpr char ENV_VAR_ENABLED_TEXT[] = "ON";
void CheckVulkan();
bool CheckEnvVars(bool* is_child);
bool StartupChecks(const char* arg0, bool* has_broken_vulkan);
bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulkan_check);
#ifdef _WIN32
bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags);