Compare commits
60 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eec9aace60 | ||
|
|
429320aee8 | ||
|
|
46366c6dca | ||
|
|
25298d1c02 | ||
|
|
9ba812485a | ||
|
|
7dd2764f2a | ||
|
|
47a724780f | ||
|
|
5f7e73c74a | ||
|
|
f6e8e61e3e | ||
|
|
815189eaf3 | ||
|
|
5b2cb22a04 | ||
|
|
edbde7a220 | ||
|
|
00f65af8b2 | ||
|
|
e05c86aa3c | ||
|
|
d197246880 | ||
|
|
204d198d16 | ||
|
|
c61857286d | ||
|
|
77b11b927c | ||
|
|
bafee97589 | ||
|
|
133504b74b | ||
|
|
ac1bfe228f | ||
|
|
8ed2748820 | ||
|
|
e10903cab9 | ||
|
|
4bdacdedc1 | ||
|
|
32854a2992 | ||
|
|
6d25fe6c9a | ||
|
|
189741b521 | ||
|
|
df47cfc32c | ||
|
|
29559930e9 | ||
|
|
14c03b9748 | ||
|
|
8254f238b9 | ||
|
|
7105204a7e | ||
|
|
1e1f7b3234 | ||
|
|
f32b2bcd20 | ||
|
|
975931e8fa | ||
|
|
d6ae9c68f8 | ||
|
|
b7d80c127f | ||
|
|
5286a7bc4c | ||
|
|
41aec2773f | ||
|
|
36350d3f78 | ||
|
|
fae07919af | ||
|
|
8aef8f39d8 | ||
|
|
7347cdb651 | ||
|
|
f1f91ad468 | ||
|
|
7220056974 | ||
|
|
60e923046e | ||
|
|
7fe455e42e | ||
|
|
a5c212516c | ||
|
|
e482dd82b9 | ||
|
|
f919498f8f | ||
|
|
a2fb5a13b2 | ||
|
|
e7f10de11a | ||
|
|
a578df4c6b | ||
|
|
20a46790d7 | ||
|
|
cd27f211c8 | ||
|
|
fdcc161323 | ||
|
|
f138731e2f | ||
|
|
55d6b095e5 | ||
|
|
5ba7b11ba4 | ||
|
|
762b8ad448 |
@@ -370,7 +370,7 @@ if (ENABLE_SDL2)
|
||||
if (YUZU_USE_BUNDLED_SDL2)
|
||||
# Detect toolchain and platform
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64)
|
||||
set(SDL2_VER "SDL2-2.0.16")
|
||||
set(SDL2_VER "SDL2-2.0.18")
|
||||
else()
|
||||
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.")
|
||||
endif()
|
||||
@@ -390,7 +390,7 @@ if (ENABLE_SDL2)
|
||||
elseif (YUZU_USE_EXTERNAL_SDL2)
|
||||
message(STATUS "Using SDL2 from externals.")
|
||||
else()
|
||||
find_package(SDL2 2.0.16 REQUIRED)
|
||||
find_package(SDL2 2.0.18 REQUIRED)
|
||||
|
||||
# Some installations don't set SDL2_LIBRARIES
|
||||
if("${SDL2_LIBRARIES}" STREQUAL "")
|
||||
|
||||
@@ -17,7 +17,7 @@ It is written in C++ with portability in mind, and we actively maintain builds f
|
||||
alt="Azure Mainline CI Build Status">
|
||||
</a>
|
||||
<a href="https://discord.com/invite/u77vRWY">
|
||||
<img src="https://img.shields.io/discord/398318088170242053?color=%237289DA&label=yuzu&logo=discord&logoColor=white"
|
||||
<img src="https://img.shields.io/discord/398318088170242053?color=5865F2&label=yuzu&logo=discord&logoColor=white"
|
||||
alt="Discord">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
4
externals/CMakeLists.txt
vendored
4
externals/CMakeLists.txt
vendored
@@ -44,10 +44,6 @@ target_include_directories(mbedtls PUBLIC ./mbedtls/include)
|
||||
add_library(microprofile INTERFACE)
|
||||
target_include_directories(microprofile INTERFACE ./microprofile)
|
||||
|
||||
# Unicorn
|
||||
add_library(unicorn-headers INTERFACE)
|
||||
target_include_directories(unicorn-headers INTERFACE ./unicorn/include)
|
||||
|
||||
# libusb
|
||||
if (NOT LIBUSB_FOUND OR YUZU_USE_BUNDLED_LIBUSB)
|
||||
add_subdirectory(libusb)
|
||||
|
||||
2
externals/SDL
vendored
2
externals/SDL
vendored
Submodule externals/SDL updated: 25f9ed87ff...2e9821423a
18
externals/find-modules/FindUnicorn.cmake
vendored
18
externals/find-modules/FindUnicorn.cmake
vendored
@@ -1,18 +0,0 @@
|
||||
# Exports:
|
||||
# LIBUNICORN_FOUND
|
||||
# LIBUNICORN_INCLUDE_DIR
|
||||
# LIBUNICORN_LIBRARY
|
||||
|
||||
find_path(LIBUNICORN_INCLUDE_DIR
|
||||
unicorn/unicorn.h
|
||||
HINTS $ENV{UNICORNDIR}
|
||||
PATH_SUFFIXES include)
|
||||
|
||||
find_library(LIBUNICORN_LIBRARY
|
||||
NAMES unicorn
|
||||
HINTS $ENV{UNICORNDIR})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(unicorn DEFAULT_MSG
|
||||
LIBUNICORN_LIBRARY LIBUNICORN_INCLUDE_DIR)
|
||||
mark_as_advanced(LIBUNICORN_INCLUDE_DIR LIBUNICORN_LIBRARY)
|
||||
@@ -24,6 +24,7 @@ if (MSVC)
|
||||
# /W3 - Level 3 warnings
|
||||
# /MP - Multi-threaded compilation
|
||||
# /Zi - Output debugging information
|
||||
# /Zm - Specifies the precompiled header memory allocation limit
|
||||
# /Zo - Enhanced debug info for optimized builds
|
||||
# /permissive- - Enables stricter C++ standards conformance checks
|
||||
# /EHsc - C++-only exception handling semantics
|
||||
@@ -36,6 +37,7 @@ if (MSVC)
|
||||
add_compile_options(
|
||||
/MP
|
||||
/Zi
|
||||
/Zm200
|
||||
/Zo
|
||||
/permissive-
|
||||
/EHsc
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstring>
|
||||
#include "audio_core/delay_line.h"
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <iterator>
|
||||
|
||||
@@ -114,6 +114,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
|
||||
SUB(Service, NGCT) \
|
||||
SUB(Service, NIFM) \
|
||||
SUB(Service, NIM) \
|
||||
SUB(Service, NOTIF) \
|
||||
SUB(Service, NPNS) \
|
||||
SUB(Service, NS) \
|
||||
SUB(Service, NVDRV) \
|
||||
|
||||
@@ -82,6 +82,7 @@ enum class Class : u8 {
|
||||
Service_NGCT, ///< The NGCT (No Good Content for Terra) service
|
||||
Service_NIFM, ///< The NIFM (Network interface) service
|
||||
Service_NIM, ///< The NIM service
|
||||
Service_NOTIF, ///< The NOTIF (Notification) service
|
||||
Service_NPNS, ///< The NPNS service
|
||||
Service_NS, ///< The NS services
|
||||
Service_NVDRV, ///< The NVDRV (Nvidia driver) service
|
||||
|
||||
@@ -15,26 +15,26 @@
|
||||
namespace Common {
|
||||
|
||||
u64 EstimateRDTSCFrequency() {
|
||||
const auto milli_10 = std::chrono::milliseconds{10};
|
||||
// get current time
|
||||
// Discard the first result measuring the rdtsc.
|
||||
_mm_mfence();
|
||||
const u64 tscStart = __rdtsc();
|
||||
const auto startTime = std::chrono::high_resolution_clock::now();
|
||||
// wait roughly 3 seconds
|
||||
while (true) {
|
||||
auto milli = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::high_resolution_clock::now() - startTime);
|
||||
if (milli.count() >= 3000)
|
||||
break;
|
||||
std::this_thread::sleep_for(milli_10);
|
||||
}
|
||||
const auto endTime = std::chrono::high_resolution_clock::now();
|
||||
__rdtsc();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{1});
|
||||
_mm_mfence();
|
||||
const u64 tscEnd = __rdtsc();
|
||||
// calculate difference
|
||||
const u64 timer_diff =
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(endTime - startTime).count();
|
||||
const u64 tsc_diff = tscEnd - tscStart;
|
||||
__rdtsc();
|
||||
|
||||
// Get the current time.
|
||||
const auto start_time = std::chrono::steady_clock::now();
|
||||
_mm_mfence();
|
||||
const u64 tsc_start = __rdtsc();
|
||||
// Wait for 200 milliseconds.
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{200});
|
||||
const auto end_time = std::chrono::steady_clock::now();
|
||||
_mm_mfence();
|
||||
const u64 tsc_end = __rdtsc();
|
||||
// Calculate differences.
|
||||
const u64 timer_diff = static_cast<u64>(
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count());
|
||||
const u64 tsc_diff = tsc_end - tsc_start;
|
||||
const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, timer_diff);
|
||||
return tsc_freq;
|
||||
}
|
||||
|
||||
@@ -179,6 +179,8 @@ add_library(core STATIC
|
||||
hle/kernel/k_client_port.h
|
||||
hle/kernel/k_client_session.cpp
|
||||
hle/kernel/k_client_session.h
|
||||
hle/kernel/k_code_memory.cpp
|
||||
hle/kernel/k_code_memory.h
|
||||
hle/kernel/k_condition_variable.cpp
|
||||
hle/kernel/k_condition_variable.h
|
||||
hle/kernel/k_event.cpp
|
||||
@@ -408,6 +410,8 @@ add_library(core STATIC
|
||||
hle/service/glue/glue.h
|
||||
hle/service/glue/glue_manager.cpp
|
||||
hle/service/glue/glue_manager.h
|
||||
hle/service/glue/notif.cpp
|
||||
hle/service/glue/notif.h
|
||||
hle/service/grc/grc.cpp
|
||||
hle/service/grc/grc.h
|
||||
hle/service/hid/hid.cpp
|
||||
|
||||
@@ -866,7 +866,52 @@ void EmulatedController::SetLedPattern() {
|
||||
}
|
||||
}
|
||||
|
||||
void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles) {
|
||||
supported_style_tag = supported_styles;
|
||||
if (!is_connected) {
|
||||
return;
|
||||
}
|
||||
if (!IsControllerSupported()) {
|
||||
LOG_ERROR(Service_HID, "Controller type {} is not supported. Disconnecting controller",
|
||||
npad_type);
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
bool EmulatedController::IsControllerSupported() const {
|
||||
switch (npad_type) {
|
||||
case NpadStyleIndex::ProController:
|
||||
return supported_style_tag.fullkey;
|
||||
case NpadStyleIndex::Handheld:
|
||||
return supported_style_tag.handheld;
|
||||
case NpadStyleIndex::JoyconDual:
|
||||
return supported_style_tag.joycon_dual;
|
||||
case NpadStyleIndex::JoyconLeft:
|
||||
return supported_style_tag.joycon_left;
|
||||
case NpadStyleIndex::JoyconRight:
|
||||
return supported_style_tag.joycon_right;
|
||||
case NpadStyleIndex::GameCube:
|
||||
return supported_style_tag.gamecube;
|
||||
case NpadStyleIndex::Pokeball:
|
||||
return supported_style_tag.palma;
|
||||
case NpadStyleIndex::NES:
|
||||
return supported_style_tag.lark;
|
||||
case NpadStyleIndex::SNES:
|
||||
return supported_style_tag.lucia;
|
||||
case NpadStyleIndex::N64:
|
||||
return supported_style_tag.lagoon;
|
||||
case NpadStyleIndex::SegaGenesis:
|
||||
return supported_style_tag.lager;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void EmulatedController::Connect() {
|
||||
if (!IsControllerSupported()) {
|
||||
LOG_ERROR(Service_HID, "Controller type {} is not supported", npad_type);
|
||||
return;
|
||||
}
|
||||
{
|
||||
std::lock_guard lock{mutex};
|
||||
if (is_configuring) {
|
||||
|
||||
@@ -160,6 +160,13 @@ public:
|
||||
*/
|
||||
NpadStyleIndex GetNpadStyleIndex(bool get_temporary_value = false) const;
|
||||
|
||||
/**
|
||||
* Sets the supported controller types. Disconnects the controller if current type is not
|
||||
* supported
|
||||
* @param supported_styles bitflag with supported types
|
||||
*/
|
||||
void SetSupportedNpadStyleTag(NpadStyleTag supported_styles);
|
||||
|
||||
/// Sets the connected status to true
|
||||
void Connect();
|
||||
|
||||
@@ -310,6 +317,12 @@ private:
|
||||
/// Set the params for TAS devices
|
||||
void LoadTASParams();
|
||||
|
||||
/**
|
||||
* Checks the current controller type against the supported_style_tag
|
||||
* @return true if the controller is supported
|
||||
*/
|
||||
bool IsControllerSupported() const;
|
||||
|
||||
/**
|
||||
* Updates the button status of the controller
|
||||
* @param callback A CallbackStatus containing the button status
|
||||
@@ -354,6 +367,7 @@ private:
|
||||
|
||||
NpadIdType npad_id_type;
|
||||
NpadStyleIndex npad_type{NpadStyleIndex::None};
|
||||
NpadStyleTag supported_style_tag{NpadStyleSet::All};
|
||||
bool is_connected{false};
|
||||
bool is_configuring{false};
|
||||
f32 motion_sensitivity{0.01f};
|
||||
|
||||
@@ -108,6 +108,16 @@ const EmulatedController* HIDCore::GetEmulatedControllerByIndex(std::size_t inde
|
||||
|
||||
void HIDCore::SetSupportedStyleTag(NpadStyleTag style_tag) {
|
||||
supported_style_tag.raw = style_tag.raw;
|
||||
player_1->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
player_2->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
player_3->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
player_4->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
player_5->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
player_6->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
player_7->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
player_8->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
other->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
handheld->SetSupportedNpadStyleTag(supported_style_tag);
|
||||
}
|
||||
|
||||
NpadStyleTag HIDCore::GetSupportedStyleTag() const {
|
||||
@@ -135,6 +145,16 @@ NpadIdType HIDCore::GetFirstNpadId() const {
|
||||
return NpadIdType::Player1;
|
||||
}
|
||||
|
||||
NpadIdType HIDCore::GetFirstDisconnectedNpadId() const {
|
||||
for (std::size_t player_index = 0; player_index < available_controllers; ++player_index) {
|
||||
const auto* const controller = GetEmulatedControllerByIndex(player_index);
|
||||
if (!controller->IsConnected()) {
|
||||
return controller->GetNpadIdType();
|
||||
}
|
||||
}
|
||||
return NpadIdType::Player1;
|
||||
}
|
||||
|
||||
void HIDCore::EnableAllControllerConfiguration() {
|
||||
player_1->EnableConfiguration();
|
||||
player_2->EnableConfiguration();
|
||||
|
||||
@@ -45,6 +45,9 @@ public:
|
||||
/// Returns the first connected npad id
|
||||
NpadIdType GetFirstNpadId() const;
|
||||
|
||||
/// Returns the first disconnected npad id
|
||||
NpadIdType GetFirstDisconnectedNpadId() const;
|
||||
|
||||
/// Sets all emulated controllers into configuring mode.
|
||||
void EnableAllControllerConfiguration();
|
||||
|
||||
@@ -73,7 +76,7 @@ private:
|
||||
std::unique_ptr<EmulatedController> handheld;
|
||||
std::unique_ptr<EmulatedConsole> console;
|
||||
std::unique_ptr<EmulatedDevices> devices;
|
||||
NpadStyleTag supported_style_tag;
|
||||
NpadStyleTag supported_style_tag{NpadStyleSet::All};
|
||||
};
|
||||
|
||||
} // namespace Core::HID
|
||||
|
||||
@@ -256,6 +256,8 @@ enum class NpadStyleSet : u32 {
|
||||
Lager = 1U << 11,
|
||||
SystemExt = 1U << 29,
|
||||
System = 1U << 30,
|
||||
|
||||
All = 0xFFFFFFFFU,
|
||||
};
|
||||
static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size");
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "core/core.h"
|
||||
#include "core/hardware_properties.h"
|
||||
#include "core/hle/kernel/init/init_slab_setup.h"
|
||||
#include "core/hle/kernel/k_code_memory.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_memory_layout.h"
|
||||
#include "core/hle/kernel/k_memory_manager.h"
|
||||
@@ -32,6 +33,7 @@ namespace Kernel::Init {
|
||||
HANDLER(KPort, (SLAB_COUNT(KPort)), ##__VA_ARGS__) \
|
||||
HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \
|
||||
HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \
|
||||
HANDLER(KCodeMemory, (SLAB_COUNT(KCodeMemory)), ##__VA_ARGS__) \
|
||||
HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \
|
||||
HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__)
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "core/hle/kernel/k_class_token.h"
|
||||
#include "core/hle/kernel/k_client_port.h"
|
||||
#include "core/hle/kernel/k_client_session.h"
|
||||
#include "core/hle/kernel/k_code_memory.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_port.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
@@ -48,7 +49,7 @@ static_assert(ClassToken<KWritableEvent> == 0b10001001'00000000);
|
||||
static_assert(ClassToken<KTransferMemory> == 0b10010001'00000000);
|
||||
// static_assert(ClassToken<KDeviceAddressSpace> == 0b01100001'00000000);
|
||||
// static_assert(ClassToken<KSessionRequest> == 0b10100001'00000000);
|
||||
// static_assert(ClassToken<KCodeMemory> == 0b11000001'00000000);
|
||||
static_assert(ClassToken<KCodeMemory> == 0b11000001'00000000);
|
||||
|
||||
// Ensure that the token hierarchy is correct.
|
||||
|
||||
@@ -79,7 +80,7 @@ static_assert(ClassToken<KWritableEvent> == ((0b10001001 << 8) | ClassToken<KAut
|
||||
static_assert(ClassToken<KTransferMemory> == ((0b10010001 << 8) | ClassToken<KAutoObject>));
|
||||
// static_assert(ClassToken<KDeviceAddressSpace> == ((0b01100001 << 8) | ClassToken<KAutoObject>));
|
||||
// static_assert(ClassToken<KSessionRequest> == ((0b10100001 << 8) | ClassToken<KAutoObject>));
|
||||
// static_assert(ClassToken<KCodeMemory> == ((0b11000001 << 8) | ClassToken<KAutoObject>));
|
||||
static_assert(ClassToken<KCodeMemory> == ((0b11000001 << 8) | ClassToken<KAutoObject>));
|
||||
|
||||
// Ensure that the token hierarchy reflects the class hierarchy.
|
||||
|
||||
|
||||
146
src/core/hle/kernel/k_code_memory.cpp
Normal file
146
src/core/hle/kernel/k_code_memory.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/device_memory.h"
|
||||
#include "core/hle/kernel/k_auto_object.h"
|
||||
#include "core/hle/kernel/k_code_memory.h"
|
||||
#include "core/hle/kernel/k_light_lock.h"
|
||||
#include "core/hle/kernel/k_memory_block.h"
|
||||
#include "core/hle/kernel/k_page_linked_list.h"
|
||||
#include "core/hle/kernel/k_page_table.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/slab_helpers.h"
|
||||
#include "core/hle/kernel/svc_types.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
KCodeMemory::KCodeMemory(KernelCore& kernel_)
|
||||
: KAutoObjectWithSlabHeapAndContainer{kernel_}, m_lock(kernel_) {}
|
||||
|
||||
ResultCode KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr, size_t size) {
|
||||
// Set members.
|
||||
m_owner = kernel.CurrentProcess();
|
||||
|
||||
// Get the owner page table.
|
||||
auto& page_table = m_owner->PageTable();
|
||||
|
||||
// Construct the page group.
|
||||
KMemoryInfo kBlockInfo = page_table.QueryInfo(addr);
|
||||
m_page_group = KPageLinkedList(kBlockInfo.GetAddress(), kBlockInfo.GetNumPages());
|
||||
|
||||
// Lock the memory.
|
||||
R_TRY(page_table.LockForCodeMemory(addr, size))
|
||||
|
||||
// Clear the memory.
|
||||
for (const auto& block : m_page_group.Nodes()) {
|
||||
std::memset(device_memory.GetPointer(block.GetAddress()), 0xFF, block.GetSize());
|
||||
}
|
||||
|
||||
// Set remaining tracking members.
|
||||
m_address = addr;
|
||||
m_is_initialized = true;
|
||||
m_is_owner_mapped = false;
|
||||
m_is_mapped = false;
|
||||
|
||||
// We succeeded.
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
void KCodeMemory::Finalize() {
|
||||
// Unlock.
|
||||
if (!m_is_mapped && !m_is_owner_mapped) {
|
||||
const size_t size = m_page_group.GetNumPages() * PageSize;
|
||||
m_owner->PageTable().UnlockForCodeMemory(m_address, size);
|
||||
}
|
||||
}
|
||||
|
||||
ResultCode KCodeMemory::Map(VAddr address, size_t size) {
|
||||
// Validate the size.
|
||||
R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
|
||||
|
||||
// Lock ourselves.
|
||||
KScopedLightLock lk(m_lock);
|
||||
|
||||
// Ensure we're not already mapped.
|
||||
R_UNLESS(!m_is_mapped, ResultInvalidState);
|
||||
|
||||
// Map the memory.
|
||||
R_TRY(kernel.CurrentProcess()->PageTable().MapPages(
|
||||
address, m_page_group, KMemoryState::CodeOut, KMemoryPermission::UserReadWrite));
|
||||
|
||||
// Mark ourselves as mapped.
|
||||
m_is_mapped = true;
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KCodeMemory::Unmap(VAddr address, size_t size) {
|
||||
// Validate the size.
|
||||
R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
|
||||
|
||||
// Lock ourselves.
|
||||
KScopedLightLock lk(m_lock);
|
||||
|
||||
// Unmap the memory.
|
||||
R_TRY(kernel.CurrentProcess()->PageTable().UnmapPages(address, m_page_group,
|
||||
KMemoryState::CodeOut));
|
||||
|
||||
// Mark ourselves as unmapped.
|
||||
m_is_mapped = false;
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm) {
|
||||
// Validate the size.
|
||||
R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
|
||||
|
||||
// Lock ourselves.
|
||||
KScopedLightLock lk(m_lock);
|
||||
|
||||
// Ensure we're not already mapped.
|
||||
R_UNLESS(!m_is_owner_mapped, ResultInvalidState);
|
||||
|
||||
// Convert the memory permission.
|
||||
KMemoryPermission k_perm{};
|
||||
switch (perm) {
|
||||
case Svc::MemoryPermission::Read:
|
||||
k_perm = KMemoryPermission::UserRead;
|
||||
break;
|
||||
case Svc::MemoryPermission::ReadExecute:
|
||||
k_perm = KMemoryPermission::UserReadExecute;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Map the memory.
|
||||
R_TRY(
|
||||
m_owner->PageTable().MapPages(address, m_page_group, KMemoryState::GeneratedCode, k_perm));
|
||||
|
||||
// Mark ourselves as mapped.
|
||||
m_is_owner_mapped = true;
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KCodeMemory::UnmapFromOwner(VAddr address, size_t size) {
|
||||
// Validate the size.
|
||||
R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
|
||||
|
||||
// Lock ourselves.
|
||||
KScopedLightLock lk(m_lock);
|
||||
|
||||
// Unmap the memory.
|
||||
R_TRY(m_owner->PageTable().UnmapPages(address, m_page_group, KMemoryState::GeneratedCode));
|
||||
|
||||
// Mark ourselves as unmapped.
|
||||
m_is_owner_mapped = false;
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
66
src/core/hle/kernel/k_code_memory.h
Normal file
66
src/core/hle/kernel/k_code_memory.h
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/device_memory.h"
|
||||
#include "core/hle/kernel/k_auto_object.h"
|
||||
#include "core/hle/kernel/k_light_lock.h"
|
||||
#include "core/hle/kernel/k_page_linked_list.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/slab_helpers.h"
|
||||
#include "core/hle/kernel/svc_types.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
enum class CodeMemoryOperation : u32 {
|
||||
Map = 0,
|
||||
MapToOwner = 1,
|
||||
Unmap = 2,
|
||||
UnmapFromOwner = 3,
|
||||
};
|
||||
|
||||
class KCodeMemory final
|
||||
: public KAutoObjectWithSlabHeapAndContainer<KCodeMemory, KAutoObjectWithList> {
|
||||
KERNEL_AUTOOBJECT_TRAITS(KCodeMemory, KAutoObject);
|
||||
|
||||
public:
|
||||
explicit KCodeMemory(KernelCore& kernel_);
|
||||
|
||||
ResultCode Initialize(Core::DeviceMemory& device_memory, VAddr address, size_t size);
|
||||
void Finalize();
|
||||
|
||||
ResultCode Map(VAddr address, size_t size);
|
||||
ResultCode Unmap(VAddr address, size_t size);
|
||||
ResultCode MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm);
|
||||
ResultCode UnmapFromOwner(VAddr address, size_t size);
|
||||
|
||||
bool IsInitialized() const {
|
||||
return m_is_initialized;
|
||||
}
|
||||
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
|
||||
|
||||
KProcess* GetOwner() const {
|
||||
return m_owner;
|
||||
}
|
||||
VAddr GetSourceAddress() const {
|
||||
return m_address;
|
||||
}
|
||||
size_t GetSize() const {
|
||||
return m_is_initialized ? m_page_group.GetNumPages() * PageSize : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
KPageLinkedList m_page_group{};
|
||||
KProcess* m_owner{};
|
||||
VAddr m_address{};
|
||||
KLightLock m_lock;
|
||||
bool m_is_initialized{};
|
||||
bool m_is_owner_mapped{};
|
||||
bool m_is_mapped{};
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
@@ -131,6 +131,26 @@ enum class KMemoryPermission : u8 {
|
||||
|
||||
UserMask = static_cast<u8>(Svc::MemoryPermission::Read | Svc::MemoryPermission::Write |
|
||||
Svc::MemoryPermission::Execute),
|
||||
|
||||
KernelShift = 3,
|
||||
|
||||
KernelRead = Read << KernelShift,
|
||||
KernelWrite = Write << KernelShift,
|
||||
KernelExecute = Execute << KernelShift,
|
||||
|
||||
NotMapped = (1 << (2 * KernelShift)),
|
||||
|
||||
KernelReadWrite = KernelRead | KernelWrite,
|
||||
KernelReadExecute = KernelRead | KernelExecute,
|
||||
|
||||
UserRead = Read | KernelRead,
|
||||
UserWrite = Write | KernelWrite,
|
||||
UserExecute = Execute,
|
||||
|
||||
UserReadWrite = UserRead | UserWrite,
|
||||
UserReadExecute = UserRead | UserExecute,
|
||||
|
||||
IpcLockChangeMask = NotMapped | UserReadWrite
|
||||
};
|
||||
DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission);
|
||||
|
||||
|
||||
@@ -27,6 +27,10 @@ public:
|
||||
return num_pages;
|
||||
}
|
||||
|
||||
constexpr std::size_t GetSize() const {
|
||||
return GetNumPages() * PageSize;
|
||||
}
|
||||
|
||||
private:
|
||||
u64 addr{};
|
||||
std::size_t num_pages{};
|
||||
|
||||
@@ -368,6 +368,33 @@ ResultCode KPageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, st
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size,
|
||||
KPageTable& src_page_table, VAddr src_addr) {
|
||||
std::lock_guard lock{page_table_lock};
|
||||
|
||||
const std::size_t num_pages{size / PageSize};
|
||||
|
||||
// Check that the memory is mapped in the destination process.
|
||||
size_t num_allocator_blocks;
|
||||
R_TRY(CheckMemoryState(&num_allocator_blocks, dst_addr, size, KMemoryState::All,
|
||||
KMemoryState::SharedCode, KMemoryPermission::UserReadWrite,
|
||||
KMemoryPermission::UserReadWrite, KMemoryAttribute::All,
|
||||
KMemoryAttribute::None));
|
||||
|
||||
// Check that the memory is mapped in the source process.
|
||||
R_TRY(src_page_table.CheckMemoryState(src_addr, size, KMemoryState::FlagCanMapProcess,
|
||||
KMemoryState::FlagCanMapProcess, KMemoryPermission::None,
|
||||
KMemoryPermission::None, KMemoryAttribute::All,
|
||||
KMemoryAttribute::None));
|
||||
|
||||
CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap));
|
||||
|
||||
// Apply the memory block update.
|
||||
block_manager->Update(dst_addr, num_pages, KMemoryState::Free, KMemoryPermission::None,
|
||||
KMemoryAttribute::None);
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
void KPageTable::MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end) {
|
||||
auto node{page_linked_list.Nodes().begin()};
|
||||
PAddr map_addr{node->GetAddress()};
|
||||
@@ -942,6 +969,60 @@ ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size)
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) {
|
||||
std::lock_guard lock{page_table_lock};
|
||||
|
||||
KMemoryPermission new_perm = KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite;
|
||||
|
||||
KMemoryPermission old_perm{};
|
||||
|
||||
if (const ResultCode result{CheckMemoryState(
|
||||
nullptr, &old_perm, nullptr, addr, size, KMemoryState::FlagCanCodeMemory,
|
||||
KMemoryState::FlagCanCodeMemory, KMemoryPermission::Mask,
|
||||
KMemoryPermission::UserReadWrite, KMemoryAttribute::All, KMemoryAttribute::None)};
|
||||
result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm;
|
||||
|
||||
block_manager->UpdateLock(
|
||||
addr, size / PageSize,
|
||||
[](KMemoryBlockManager::iterator block, KMemoryPermission permission) {
|
||||
block->ShareToDevice(permission);
|
||||
},
|
||||
new_perm);
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size) {
|
||||
std::lock_guard lock{page_table_lock};
|
||||
|
||||
KMemoryPermission new_perm = KMemoryPermission::UserReadWrite;
|
||||
|
||||
KMemoryPermission old_perm{};
|
||||
|
||||
if (const ResultCode result{CheckMemoryState(
|
||||
nullptr, &old_perm, nullptr, addr, size, KMemoryState::FlagCanCodeMemory,
|
||||
KMemoryState::FlagCanCodeMemory, KMemoryPermission::None, KMemoryPermission::None,
|
||||
KMemoryAttribute::All, KMemoryAttribute::Locked)};
|
||||
result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm;
|
||||
|
||||
block_manager->UpdateLock(
|
||||
addr, size / PageSize,
|
||||
[](KMemoryBlockManager::iterator block, KMemoryPermission permission) {
|
||||
block->UnshareToDevice(permission);
|
||||
},
|
||||
new_perm);
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) {
|
||||
block_manager = std::make_unique<KMemoryBlockManager>(start, end);
|
||||
|
||||
@@ -1231,4 +1312,42 @@ ResultCode KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermissi
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::CheckMemoryState(size_t* out_blocks_needed, VAddr addr, size_t size,
|
||||
KMemoryState state_mask, KMemoryState state,
|
||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||
KMemoryAttribute attr_mask, KMemoryAttribute attr) const {
|
||||
// Get information about the first block.
|
||||
const VAddr last_addr = addr + size - 1;
|
||||
KMemoryBlockManager::const_iterator it{block_manager->FindIterator(addr)};
|
||||
KMemoryInfo info = it->GetMemoryInfo();
|
||||
|
||||
// If the start address isn't aligned, we need a block.
|
||||
const size_t blocks_for_start_align =
|
||||
(Common::AlignDown(addr, PageSize) != info.GetAddress()) ? 1 : 0;
|
||||
|
||||
while (true) {
|
||||
// Validate against the provided masks.
|
||||
R_TRY(CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr));
|
||||
|
||||
// Break once we're done.
|
||||
if (last_addr <= info.GetLastAddress()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Advance our iterator.
|
||||
it++;
|
||||
info = it->GetMemoryInfo();
|
||||
}
|
||||
|
||||
// If the end address isn't aligned, we need a block.
|
||||
const size_t blocks_for_end_align =
|
||||
(Common::AlignUp(addr + size, PageSize) != info.GetEndAddress()) ? 1 : 0;
|
||||
|
||||
if (out_blocks_needed != nullptr) {
|
||||
*out_blocks_needed = blocks_for_start_align + blocks_for_end_align;
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -33,6 +33,8 @@ public:
|
||||
KMemoryPermission perm);
|
||||
ResultCode MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
|
||||
ResultCode UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
|
||||
ResultCode UnmapProcessMemory(VAddr dst_addr, std::size_t size, KPageTable& src_page_table,
|
||||
VAddr src_addr);
|
||||
ResultCode MapPhysicalMemory(VAddr addr, std::size_t size);
|
||||
ResultCode UnmapPhysicalMemory(VAddr addr, std::size_t size);
|
||||
ResultCode UnmapMemory(VAddr addr, std::size_t size);
|
||||
@@ -55,6 +57,8 @@ public:
|
||||
KMemoryPermission perm, PAddr map_addr = 0);
|
||||
ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size);
|
||||
ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size);
|
||||
ResultCode LockForCodeMemory(VAddr addr, std::size_t size);
|
||||
ResultCode UnlockForCodeMemory(VAddr addr, std::size_t size);
|
||||
|
||||
Common::PageTable& PageTableImpl() {
|
||||
return page_table_impl;
|
||||
@@ -115,6 +119,10 @@ private:
|
||||
return CheckMemoryState(nullptr, nullptr, nullptr, addr, size, state_mask, state, perm_mask,
|
||||
perm, attr_mask, attr, ignore_attr);
|
||||
}
|
||||
ResultCode CheckMemoryState(size_t* out_blocks_needed, VAddr addr, size_t size,
|
||||
KMemoryState state_mask, KMemoryState state,
|
||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||
KMemoryAttribute attr_mask, KMemoryAttribute attr) const;
|
||||
|
||||
std::recursive_mutex page_table_lock;
|
||||
std::unique_ptr<KMemoryBlockManager> block_manager;
|
||||
|
||||
@@ -53,6 +53,7 @@ class KSharedMemoryInfo;
|
||||
class KThread;
|
||||
class KTransferMemory;
|
||||
class KWritableEvent;
|
||||
class KCodeMemory;
|
||||
class PhysicalCore;
|
||||
class ServiceThread;
|
||||
class Synchronization;
|
||||
@@ -326,6 +327,8 @@ public:
|
||||
return slab_heap_container->transfer_memory;
|
||||
} else if constexpr (std::is_same_v<T, KWritableEvent>) {
|
||||
return slab_heap_container->writeable_event;
|
||||
} else if constexpr (std::is_same_v<T, KCodeMemory>) {
|
||||
return slab_heap_container->code_memory;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,6 +380,7 @@ private:
|
||||
KSlabHeap<KThread> thread;
|
||||
KSlabHeap<KTransferMemory> transfer_memory;
|
||||
KSlabHeap<KWritableEvent> writeable_event;
|
||||
KSlabHeap<KCodeMemory> code_memory;
|
||||
};
|
||||
|
||||
std::unique_ptr<SlabHeapContainer> slab_heap_container;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/k_client_port.h"
|
||||
#include "core/hle/kernel/k_client_session.h"
|
||||
#include "core/hle/kernel/k_code_memory.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_handle_table.h"
|
||||
#include "core/hle/kernel/k_memory_block.h"
|
||||
@@ -1197,6 +1198,22 @@ constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) {
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool IsValidMapCodeMemoryPermission(Svc::MemoryPermission perm) {
|
||||
return perm == Svc::MemoryPermission::ReadWrite;
|
||||
}
|
||||
|
||||
constexpr bool IsValidMapToOwnerCodeMemoryPermission(Svc::MemoryPermission perm) {
|
||||
return perm == Svc::MemoryPermission::Read || perm == Svc::MemoryPermission::ReadExecute;
|
||||
}
|
||||
|
||||
constexpr bool IsValidUnmapCodeMemoryPermission(Svc::MemoryPermission perm) {
|
||||
return perm == Svc::MemoryPermission::None;
|
||||
}
|
||||
|
||||
constexpr bool IsValidUnmapFromOwnerCodeMemoryPermission(Svc::MemoryPermission perm) {
|
||||
return perm == Svc::MemoryPermission::None;
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address,
|
||||
@@ -1306,6 +1323,195 @@ static ResultCode SetProcessMemoryPermission(Core::System& system, Handle proces
|
||||
return page_table.SetProcessMemoryPermission(address, size, ConvertToKMemoryPermission(perm));
|
||||
}
|
||||
|
||||
static ResultCode MapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle,
|
||||
VAddr src_address, u64 size) {
|
||||
LOG_TRACE(Kernel_SVC,
|
||||
"called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}",
|
||||
dst_address, process_handle, src_address, size);
|
||||
|
||||
// Validate the address/size.
|
||||
R_UNLESS(Common::IsAligned(dst_address, PageSize), ResultInvalidAddress);
|
||||
R_UNLESS(Common::IsAligned(src_address, PageSize), ResultInvalidAddress);
|
||||
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
|
||||
R_UNLESS(size > 0, ResultInvalidSize);
|
||||
R_UNLESS((dst_address < dst_address + size), ResultInvalidCurrentMemory);
|
||||
R_UNLESS((src_address < src_address + size), ResultInvalidCurrentMemory);
|
||||
|
||||
// Get the processes.
|
||||
KProcess* dst_process = system.CurrentProcess();
|
||||
KScopedAutoObject src_process =
|
||||
dst_process->GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle);
|
||||
R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle);
|
||||
|
||||
// Get the page tables.
|
||||
auto& dst_pt = dst_process->PageTable();
|
||||
auto& src_pt = src_process->PageTable();
|
||||
|
||||
// Validate that the mapping is in range.
|
||||
R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory);
|
||||
R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState::SharedCode),
|
||||
ResultInvalidMemoryRegion);
|
||||
|
||||
// Create a new page group.
|
||||
KMemoryInfo kBlockInfo = dst_pt.QueryInfo(dst_address);
|
||||
KPageLinkedList pg(kBlockInfo.GetAddress(), kBlockInfo.GetNumPages());
|
||||
|
||||
// Map the group.
|
||||
R_TRY(dst_pt.MapPages(dst_address, pg, KMemoryState::SharedCode,
|
||||
KMemoryPermission::UserReadWrite));
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
static ResultCode UnmapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle,
|
||||
VAddr src_address, u64 size) {
|
||||
LOG_TRACE(Kernel_SVC,
|
||||
"called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}",
|
||||
dst_address, process_handle, src_address, size);
|
||||
|
||||
// Validate the address/size.
|
||||
R_UNLESS(Common::IsAligned(dst_address, PageSize), ResultInvalidAddress);
|
||||
R_UNLESS(Common::IsAligned(src_address, PageSize), ResultInvalidAddress);
|
||||
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
|
||||
R_UNLESS(size > 0, ResultInvalidSize);
|
||||
R_UNLESS((dst_address < dst_address + size), ResultInvalidCurrentMemory);
|
||||
R_UNLESS((src_address < src_address + size), ResultInvalidCurrentMemory);
|
||||
|
||||
// Get the processes.
|
||||
KProcess* dst_process = system.CurrentProcess();
|
||||
KScopedAutoObject src_process =
|
||||
dst_process->GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle);
|
||||
R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle);
|
||||
|
||||
// Get the page tables.
|
||||
auto& dst_pt = dst_process->PageTable();
|
||||
auto& src_pt = src_process->PageTable();
|
||||
|
||||
// Validate that the mapping is in range.
|
||||
R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory);
|
||||
R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState::SharedCode),
|
||||
ResultInvalidMemoryRegion);
|
||||
|
||||
// Unmap the memory.
|
||||
R_TRY(dst_pt.UnmapProcessMemory(dst_address, size, src_pt, src_address));
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
static ResultCode CreateCodeMemory(Core::System& system, Handle* out, VAddr address, size_t size) {
|
||||
LOG_TRACE(Kernel_SVC, "called, handle_out=0x{:X}, address=0x{:X}, size=0x{:X}",
|
||||
static_cast<void*>(out), address, size);
|
||||
// Get kernel instance.
|
||||
auto& kernel = system.Kernel();
|
||||
|
||||
// Validate address / size.
|
||||
R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
|
||||
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
|
||||
R_UNLESS(size > 0, ResultInvalidSize);
|
||||
R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
|
||||
|
||||
// Create the code memory.
|
||||
|
||||
KCodeMemory* code_mem = KCodeMemory::Create(kernel);
|
||||
R_UNLESS(code_mem != nullptr, ResultOutOfResource);
|
||||
|
||||
// Verify that the region is in range.
|
||||
R_UNLESS(system.CurrentProcess()->PageTable().Contains(address, size),
|
||||
ResultInvalidCurrentMemory);
|
||||
|
||||
// Initialize the code memory.
|
||||
R_TRY(code_mem->Initialize(system.DeviceMemory(), address, size));
|
||||
|
||||
// Register the code memory.
|
||||
KCodeMemory::Register(kernel, code_mem);
|
||||
|
||||
// Add the code memory to the handle table.
|
||||
R_TRY(system.CurrentProcess()->GetHandleTable().Add(out, code_mem));
|
||||
|
||||
code_mem->Close();
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
static ResultCode ControlCodeMemory(Core::System& system, Handle code_memory_handle, u32 operation,
|
||||
VAddr address, size_t size, Svc::MemoryPermission perm) {
|
||||
|
||||
LOG_TRACE(Kernel_SVC,
|
||||
"called, code_memory_handle=0x{:X}, operation=0x{:X}, address=0x{:X}, size=0x{:X}, "
|
||||
"permission=0x{:X}",
|
||||
code_memory_handle, operation, address, size, perm);
|
||||
|
||||
// Validate the address / size.
|
||||
R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
|
||||
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
|
||||
R_UNLESS(size > 0, ResultInvalidSize);
|
||||
R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
|
||||
|
||||
// Get the code memory from its handle.
|
||||
KScopedAutoObject code_mem =
|
||||
system.CurrentProcess()->GetHandleTable().GetObject<KCodeMemory>(code_memory_handle);
|
||||
R_UNLESS(code_mem.IsNotNull(), ResultInvalidHandle);
|
||||
|
||||
// NOTE: Here, Atmosphere extends the SVC to allow code memory operations on one's own process.
|
||||
// This enables homebrew usage of these SVCs for JIT.
|
||||
|
||||
// Perform the operation.
|
||||
switch (static_cast<CodeMemoryOperation>(operation)) {
|
||||
case CodeMemoryOperation::Map: {
|
||||
// Check that the region is in range.
|
||||
R_UNLESS(
|
||||
system.CurrentProcess()->PageTable().CanContain(address, size, KMemoryState::CodeOut),
|
||||
ResultInvalidMemoryRegion);
|
||||
|
||||
// Check the memory permission.
|
||||
R_UNLESS(IsValidMapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
|
||||
|
||||
// Map the memory.
|
||||
R_TRY(code_mem->Map(address, size));
|
||||
} break;
|
||||
case CodeMemoryOperation::Unmap: {
|
||||
// Check that the region is in range.
|
||||
R_UNLESS(
|
||||
system.CurrentProcess()->PageTable().CanContain(address, size, KMemoryState::CodeOut),
|
||||
ResultInvalidMemoryRegion);
|
||||
|
||||
// Check the memory permission.
|
||||
R_UNLESS(IsValidUnmapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
|
||||
|
||||
// Unmap the memory.
|
||||
R_TRY(code_mem->Unmap(address, size));
|
||||
} break;
|
||||
case CodeMemoryOperation::MapToOwner: {
|
||||
// Check that the region is in range.
|
||||
R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size,
|
||||
KMemoryState::GeneratedCode),
|
||||
ResultInvalidMemoryRegion);
|
||||
|
||||
// Check the memory permission.
|
||||
R_UNLESS(IsValidMapToOwnerCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
|
||||
|
||||
// Map the memory to its owner.
|
||||
R_TRY(code_mem->MapToOwner(address, size, perm));
|
||||
} break;
|
||||
case CodeMemoryOperation::UnmapFromOwner: {
|
||||
// Check that the region is in range.
|
||||
R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size,
|
||||
KMemoryState::GeneratedCode),
|
||||
ResultInvalidMemoryRegion);
|
||||
|
||||
// Check the memory permission.
|
||||
R_UNLESS(IsValidUnmapFromOwnerCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
|
||||
|
||||
// Unmap the memory from its owner.
|
||||
R_TRY(code_mem->UnmapFromOwner(address, size));
|
||||
} break;
|
||||
default:
|
||||
return ResultInvalidEnumValue;
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address,
|
||||
VAddr page_info_address, Handle process_handle,
|
||||
VAddr address) {
|
||||
@@ -2600,8 +2806,8 @@ static const FunctionDef SVC_Table_64[] = {
|
||||
{0x48, nullptr, "MapPhysicalMemoryUnsafe"},
|
||||
{0x49, nullptr, "UnmapPhysicalMemoryUnsafe"},
|
||||
{0x4A, nullptr, "SetUnsafeLimit"},
|
||||
{0x4B, nullptr, "CreateCodeMemory"},
|
||||
{0x4C, nullptr, "ControlCodeMemory"},
|
||||
{0x4B, SvcWrap64<CreateCodeMemory>, "CreateCodeMemory"},
|
||||
{0x4C, SvcWrap64<ControlCodeMemory>, "ControlCodeMemory"},
|
||||
{0x4D, nullptr, "SleepSystem"},
|
||||
{0x4E, nullptr, "ReadWriteRegister"},
|
||||
{0x4F, nullptr, "SetProcessActivity"},
|
||||
@@ -2641,8 +2847,8 @@ static const FunctionDef SVC_Table_64[] = {
|
||||
{0x71, nullptr, "ManageNamedPort"},
|
||||
{0x72, nullptr, "ConnectToPort"},
|
||||
{0x73, SvcWrap64<SetProcessMemoryPermission>, "SetProcessMemoryPermission"},
|
||||
{0x74, nullptr, "MapProcessMemory"},
|
||||
{0x75, nullptr, "UnmapProcessMemory"},
|
||||
{0x74, SvcWrap64<MapProcessMemory>, "MapProcessMemory"},
|
||||
{0x75, SvcWrap64<UnmapProcessMemory>, "UnmapProcessMemory"},
|
||||
{0x76, SvcWrap64<QueryProcessMemory>, "QueryProcessMemory"},
|
||||
{0x77, SvcWrap64<MapProcessCodeMemory>, "MapProcessCodeMemory"},
|
||||
{0x78, SvcWrap64<UnmapProcessCodeMemory>, "UnmapProcessCodeMemory"},
|
||||
|
||||
@@ -73,6 +73,23 @@ void SvcWrap64(Core::System& system) {
|
||||
.raw);
|
||||
}
|
||||
|
||||
// Used by MapProcessMemory and UnmapProcessMemory
|
||||
template <ResultCode func(Core::System&, u64, u32, u64, u64)>
|
||||
void SvcWrap64(Core::System& system) {
|
||||
FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1)),
|
||||
Param(system, 2), Param(system, 3))
|
||||
.raw);
|
||||
}
|
||||
|
||||
// Used by ControlCodeMemory
|
||||
template <ResultCode func(Core::System&, Handle, u32, u64, u64, Svc::MemoryPermission)>
|
||||
void SvcWrap64(Core::System& system) {
|
||||
FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)),
|
||||
static_cast<u32>(Param(system, 1)), Param(system, 2), Param(system, 3),
|
||||
static_cast<Svc::MemoryPermission>(Param(system, 4)))
|
||||
.raw);
|
||||
}
|
||||
|
||||
template <ResultCode func(Core::System&, u32*)>
|
||||
void SvcWrap64(Core::System& system) {
|
||||
u32 param = 0;
|
||||
@@ -301,6 +318,16 @@ void SvcWrap64(Core::System& system) {
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
// Used by CreateCodeMemory
|
||||
template <ResultCode func(Core::System&, Handle*, u64, u64)>
|
||||
void SvcWrap64(Core::System& system) {
|
||||
u32 param_1 = 0;
|
||||
const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2)).raw;
|
||||
|
||||
system.CurrentArmInterface().SetReg(1, param_1);
|
||||
FuncReturn(system, retval);
|
||||
}
|
||||
|
||||
template <ResultCode func(Core::System&, Handle*, u64, u32, u32)>
|
||||
void SvcWrap64(Core::System& system) {
|
||||
u32 param_1 = 0;
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "core/hle/service/apm/apm_controller.h"
|
||||
#include "core/hle/service/apm/apm_interface.h"
|
||||
#include "core/hle/service/bcat/backend/backend.h"
|
||||
#include "core/hle/service/caps/caps.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/ns/ns.h"
|
||||
#include "core/hle/service/nvflinger/nvflinger.h"
|
||||
@@ -298,7 +299,7 @@ ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nv
|
||||
{91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"},
|
||||
{100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"},
|
||||
{110, nullptr, "SetApplicationAlbumUserData"},
|
||||
{120, nullptr, "SaveCurrentScreenshot"},
|
||||
{120, &ISelfController::SaveCurrentScreenshot, "SaveCurrentScreenshot"},
|
||||
{130, nullptr, "SetRecordVolumeMuted"},
|
||||
{1000, nullptr, "GetDebugStorageChannel"},
|
||||
};
|
||||
@@ -579,6 +580,17 @@ void ISelfController::SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestCo
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void ISelfController::SaveCurrentScreenshot(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const auto album_report_option = rp.PopEnum<Capture::AlbumReportOption>();
|
||||
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called. album_report_option={}", album_report_option);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
AppletMessageQueue::AppletMessageQueue(Core::System& system)
|
||||
: service_context{system, "AppletMessageQueue"} {
|
||||
on_new_message = service_context.CreateEvent("AMMessageQueue:OnMessageReceived");
|
||||
|
||||
@@ -151,6 +151,7 @@ private:
|
||||
void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx);
|
||||
void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx);
|
||||
void SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx);
|
||||
void SaveCurrentScreenshot(Kernel::HLERequestContext& ctx);
|
||||
|
||||
enum class ScreenshotPermission : u32 {
|
||||
Inherit = 0,
|
||||
|
||||
@@ -96,7 +96,7 @@ private:
|
||||
|
||||
bool DecodeOpusData(u32& consumed, u32& sample_count, const std::vector<u8>& input,
|
||||
std::vector<opus_int16>& output, u64* out_performance_time) const {
|
||||
const auto start_time = std::chrono::high_resolution_clock::now();
|
||||
const auto start_time = std::chrono::steady_clock::now();
|
||||
const std::size_t raw_output_sz = output.size() * sizeof(opus_int16);
|
||||
if (sizeof(OpusPacketHeader) > input.size()) {
|
||||
LOG_ERROR(Audio, "Input is smaller than the header size, header_sz={}, input_sz={}",
|
||||
@@ -135,7 +135,7 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto end_time = std::chrono::high_resolution_clock::now() - start_time;
|
||||
const auto end_time = std::chrono::steady_clock::now() - start_time;
|
||||
sample_count = out_sample_count;
|
||||
consumed = static_cast<u32>(sizeof(OpusPacketHeader) + hdr.size);
|
||||
if (out_performance_time != nullptr) {
|
||||
|
||||
@@ -24,7 +24,7 @@ enum class AlbumImageOrientation {
|
||||
Orientation3 = 3,
|
||||
};
|
||||
|
||||
enum class AlbumReportOption {
|
||||
enum class AlbumReportOption : s32 {
|
||||
Disable = 0,
|
||||
Enable = 1,
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "core/hle/service/glue/bgtc.h"
|
||||
#include "core/hle/service/glue/ectx.h"
|
||||
#include "core/hle/service/glue/glue.h"
|
||||
#include "core/hle/service/glue/notif.h"
|
||||
|
||||
namespace Service::Glue {
|
||||
|
||||
@@ -24,6 +25,9 @@ void InstallInterfaces(Core::System& system) {
|
||||
|
||||
// Error Context
|
||||
std::make_shared<ECTX_AW>(system)->InstallAsService(system.ServiceManager());
|
||||
|
||||
// Notification Services for application
|
||||
std::make_shared<NOTIF_A>(system)->InstallAsService(system.ServiceManager());
|
||||
}
|
||||
|
||||
} // namespace Service::Glue
|
||||
|
||||
44
src/core/hle/service/glue/notif.cpp
Normal file
44
src/core/hle/service/glue/notif.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/service/glue/notif.h"
|
||||
|
||||
namespace Service::Glue {
|
||||
|
||||
NOTIF_A::NOTIF_A(Core::System& system_) : ServiceFramework{system_, "notif:a"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{500, nullptr, "RegisterAlarmSetting"},
|
||||
{510, nullptr, "UpdateAlarmSetting"},
|
||||
{520, &NOTIF_A::ListAlarmSettings, "ListAlarmSettings"},
|
||||
{530, nullptr, "LoadApplicationParameter"},
|
||||
{540, nullptr, "DeleteAlarmSetting"},
|
||||
{1000, &NOTIF_A::Initialize, "Initialize"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
NOTIF_A::~NOTIF_A() = default;
|
||||
|
||||
void NOTIF_A::ListAlarmSettings(Kernel::HLERequestContext& ctx) {
|
||||
// Returns an array of AlarmSetting
|
||||
constexpr s32 alarm_count = 0;
|
||||
|
||||
LOG_WARNING(Service_NOTIF, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(alarm_count);
|
||||
}
|
||||
|
||||
void NOTIF_A::Initialize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NOTIF, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
} // namespace Service::Glue
|
||||
25
src/core/hle/service/glue/notif.h
Normal file
25
src/core/hle/service/glue/notif.h
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Service::Glue {
|
||||
|
||||
class NOTIF_A final : public ServiceFramework<NOTIF_A> {
|
||||
public:
|
||||
explicit NOTIF_A(Core::System& system_);
|
||||
~NOTIF_A() override;
|
||||
|
||||
private:
|
||||
void ListAlarmSettings(Kernel::HLERequestContext& ctx);
|
||||
void Initialize(Kernel::HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
} // namespace Service::Glue
|
||||
@@ -110,7 +110,7 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type,
|
||||
UpdateControllerAt(npad_type, npad_id, is_connected);
|
||||
break;
|
||||
case Core::HID::ControllerTriggerType::Battery: {
|
||||
if (!controller.is_connected) {
|
||||
if (!controller.device->IsConnected()) {
|
||||
return;
|
||||
}
|
||||
auto& shared_memory = controller.shared_memory_entry;
|
||||
@@ -126,8 +126,11 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type,
|
||||
}
|
||||
|
||||
void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
|
||||
LOG_DEBUG(Service_HID, "Npad connected {}", npad_id);
|
||||
auto& controller = GetControllerFromNpadIdType(npad_id);
|
||||
if (!IsControllerSupported(controller.device->GetNpadStyleIndex())) {
|
||||
return;
|
||||
}
|
||||
LOG_DEBUG(Service_HID, "Npad connected {}", npad_id);
|
||||
const auto controller_type = controller.device->GetNpadStyleIndex();
|
||||
auto& shared_memory = controller.shared_memory_entry;
|
||||
if (controller_type == Core::HID::NpadStyleIndex::None) {
|
||||
@@ -147,7 +150,6 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
|
||||
shared_memory.system_properties.is_vertical.Assign(1);
|
||||
shared_memory.system_properties.use_plus.Assign(1);
|
||||
shared_memory.system_properties.use_minus.Assign(1);
|
||||
shared_memory.assignment_mode = NpadJoyAssignmentMode::Single;
|
||||
shared_memory.applet_footer.type = AppletFooterUiType::SwitchProController;
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::Handheld:
|
||||
@@ -163,21 +165,30 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::JoyconDual:
|
||||
shared_memory.style_tag.joycon_dual.Assign(1);
|
||||
shared_memory.device_type.joycon_left.Assign(1);
|
||||
shared_memory.device_type.joycon_right.Assign(1);
|
||||
shared_memory.system_properties.is_vertical.Assign(1);
|
||||
shared_memory.system_properties.use_plus.Assign(1);
|
||||
shared_memory.system_properties.use_minus.Assign(1);
|
||||
if (controller.is_dual_left_connected) {
|
||||
shared_memory.device_type.joycon_left.Assign(1);
|
||||
shared_memory.system_properties.use_minus.Assign(1);
|
||||
}
|
||||
if (controller.is_dual_right_connected) {
|
||||
shared_memory.device_type.joycon_right.Assign(1);
|
||||
shared_memory.system_properties.use_plus.Assign(1);
|
||||
}
|
||||
shared_memory.system_properties.use_directional_buttons.Assign(1);
|
||||
shared_memory.system_properties.is_vertical.Assign(1);
|
||||
shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual;
|
||||
shared_memory.applet_footer.type = AppletFooterUiType::JoyDual;
|
||||
if (controller.is_dual_left_connected && controller.is_dual_right_connected) {
|
||||
shared_memory.applet_footer.type = AppletFooterUiType::JoyDual;
|
||||
} else if (controller.is_dual_left_connected) {
|
||||
shared_memory.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly;
|
||||
} else {
|
||||
shared_memory.applet_footer.type = AppletFooterUiType::JoyDualRightOnly;
|
||||
}
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::JoyconLeft:
|
||||
shared_memory.style_tag.joycon_left.Assign(1);
|
||||
shared_memory.device_type.joycon_left.Assign(1);
|
||||
shared_memory.system_properties.is_horizontal.Assign(1);
|
||||
shared_memory.system_properties.use_minus.Assign(1);
|
||||
shared_memory.assignment_mode = NpadJoyAssignmentMode::Single;
|
||||
shared_memory.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal;
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::JoyconRight:
|
||||
@@ -185,7 +196,6 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
|
||||
shared_memory.device_type.joycon_right.Assign(1);
|
||||
shared_memory.system_properties.is_horizontal.Assign(1);
|
||||
shared_memory.system_properties.use_plus.Assign(1);
|
||||
shared_memory.assignment_mode = NpadJoyAssignmentMode::Single;
|
||||
shared_memory.applet_footer.type = AppletFooterUiType::JoyRightHorizontal;
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::GameCube:
|
||||
@@ -197,7 +207,6 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
|
||||
case Core::HID::NpadStyleIndex::Pokeball:
|
||||
shared_memory.style_tag.palma.Assign(1);
|
||||
shared_memory.device_type.palma.Assign(1);
|
||||
shared_memory.assignment_mode = NpadJoyAssignmentMode::Single;
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::NES:
|
||||
shared_memory.style_tag.lark.Assign(1);
|
||||
@@ -255,19 +264,7 @@ void Controller_NPad::OnInit() {
|
||||
|
||||
if (hid_core.GetSupportedStyleTag().raw == Core::HID::NpadStyleSet::None) {
|
||||
// We want to support all controllers
|
||||
Core::HID::NpadStyleTag style{};
|
||||
style.handheld.Assign(1);
|
||||
style.joycon_left.Assign(1);
|
||||
style.joycon_right.Assign(1);
|
||||
style.joycon_dual.Assign(1);
|
||||
style.fullkey.Assign(1);
|
||||
style.gamecube.Assign(1);
|
||||
style.palma.Assign(1);
|
||||
style.lark.Assign(1);
|
||||
style.lucia.Assign(1);
|
||||
style.lagoon.Assign(1);
|
||||
style.lager.Assign(1);
|
||||
hid_core.SetSupportedStyleTag(style);
|
||||
hid_core.SetSupportedStyleTag({Core::HID::NpadStyleSet::All});
|
||||
}
|
||||
|
||||
supported_npad_id_types.resize(npad_id_list.size());
|
||||
@@ -452,11 +449,15 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
|
||||
case Core::HID::NpadStyleIndex::JoyconDual:
|
||||
pad_state.connection_status.raw = 0;
|
||||
pad_state.connection_status.is_connected.Assign(1);
|
||||
pad_state.connection_status.is_left_connected.Assign(1);
|
||||
pad_state.connection_status.is_right_connected.Assign(1);
|
||||
if (controller.is_dual_left_connected) {
|
||||
pad_state.connection_status.is_left_connected.Assign(1);
|
||||
libnx_state.connection_status.is_left_connected.Assign(1);
|
||||
}
|
||||
if (controller.is_dual_right_connected) {
|
||||
pad_state.connection_status.is_right_connected.Assign(1);
|
||||
libnx_state.connection_status.is_right_connected.Assign(1);
|
||||
}
|
||||
|
||||
libnx_state.connection_status.is_left_connected.Assign(1);
|
||||
libnx_state.connection_status.is_right_connected.Assign(1);
|
||||
pad_state.sampling_number =
|
||||
npad.joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||
npad.joy_dual_lifo.WriteNextEntry(pad_state);
|
||||
@@ -696,7 +697,7 @@ Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode
|
||||
return communication_mode;
|
||||
}
|
||||
|
||||
void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id,
|
||||
void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceType npad_device_type,
|
||||
NpadJoyAssignmentMode assignment_mode) {
|
||||
if (!IsNpadIdValid(npad_id)) {
|
||||
LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
|
||||
@@ -707,6 +708,62 @@ void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id,
|
||||
if (controller.shared_memory_entry.assignment_mode != assignment_mode) {
|
||||
controller.shared_memory_entry.assignment_mode = assignment_mode;
|
||||
}
|
||||
|
||||
if (!controller.device->IsConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (assignment_mode == NpadJoyAssignmentMode::Dual) {
|
||||
if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft) {
|
||||
DisconnectNpad(npad_id);
|
||||
controller.is_dual_left_connected = true;
|
||||
controller.is_dual_right_connected = false;
|
||||
UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true);
|
||||
return;
|
||||
}
|
||||
if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) {
|
||||
DisconnectNpad(npad_id);
|
||||
controller.is_dual_left_connected = false;
|
||||
controller.is_dual_right_connected = true;
|
||||
UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// This is for NpadJoyAssignmentMode::Single
|
||||
|
||||
// Only JoyconDual get affected by this function
|
||||
if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::JoyconDual) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (controller.is_dual_left_connected && !controller.is_dual_right_connected) {
|
||||
DisconnectNpad(npad_id);
|
||||
UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true);
|
||||
return;
|
||||
}
|
||||
if (!controller.is_dual_left_connected && controller.is_dual_right_connected) {
|
||||
DisconnectNpad(npad_id);
|
||||
UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// We have two controllers connected to the same npad_id we need to split them
|
||||
const auto npad_id_2 = hid_core.GetFirstDisconnectedNpadId();
|
||||
auto& controller_2 = GetControllerFromNpadIdType(npad_id_2);
|
||||
DisconnectNpad(npad_id);
|
||||
if (npad_device_type == NpadJoyDeviceType::Left) {
|
||||
UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true);
|
||||
controller_2.is_dual_left_connected = false;
|
||||
controller_2.is_dual_right_connected = true;
|
||||
UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_2, true);
|
||||
} else {
|
||||
UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true);
|
||||
controller_2.is_dual_left_connected = true;
|
||||
controller_2.is_dual_right_connected = false;
|
||||
UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_2, true);
|
||||
}
|
||||
}
|
||||
|
||||
bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id,
|
||||
@@ -916,6 +973,7 @@ void Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) {
|
||||
}
|
||||
|
||||
auto& shared_memory_entry = controller.shared_memory_entry;
|
||||
// Don't reset shared_memory_entry.assignment_mode this value is persistent
|
||||
shared_memory_entry.style_tag.raw = Core::HID::NpadStyleSet::None; // Zero out
|
||||
shared_memory_entry.device_type.raw = 0;
|
||||
shared_memory_entry.system_properties.raw = 0;
|
||||
@@ -932,9 +990,10 @@ void Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) {
|
||||
.left = {},
|
||||
.right = {},
|
||||
};
|
||||
shared_memory_entry.assignment_mode = NpadJoyAssignmentMode::Dual;
|
||||
shared_memory_entry.applet_footer.type = AppletFooterUiType::None;
|
||||
|
||||
controller.is_dual_left_connected = true;
|
||||
controller.is_dual_right_connected = true;
|
||||
controller.is_connected = false;
|
||||
controller.device->Disconnect();
|
||||
SignalStyleSetChangedEvent(npad_id);
|
||||
@@ -1031,19 +1090,70 @@ void Controller_NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1,
|
||||
npad_id_2);
|
||||
return;
|
||||
}
|
||||
auto& controller_1 = GetControllerFromNpadIdType(npad_id_1).device;
|
||||
auto& controller_2 = GetControllerFromNpadIdType(npad_id_2).device;
|
||||
auto& controller_1 = GetControllerFromNpadIdType(npad_id_1);
|
||||
auto& controller_2 = GetControllerFromNpadIdType(npad_id_2);
|
||||
const auto controller_style_1 = controller_1.device->GetNpadStyleIndex();
|
||||
const auto controller_style_2 = controller_2.device->GetNpadStyleIndex();
|
||||
bool merge_controllers = false;
|
||||
|
||||
// If the controllers at both npad indices form a pair of left and right joycons, merge them.
|
||||
// Otherwise, do nothing.
|
||||
if ((controller_1->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft &&
|
||||
controller_2->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) ||
|
||||
(controller_2->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft &&
|
||||
controller_1->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight)) {
|
||||
if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconLeft &&
|
||||
controller_style_2 == Core::HID::NpadStyleIndex::JoyconRight) {
|
||||
merge_controllers = true;
|
||||
}
|
||||
if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft &&
|
||||
controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight) {
|
||||
merge_controllers = true;
|
||||
}
|
||||
if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual &&
|
||||
controller_style_2 == Core::HID::NpadStyleIndex::JoyconRight &&
|
||||
controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected) {
|
||||
merge_controllers = true;
|
||||
}
|
||||
if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual &&
|
||||
controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft &&
|
||||
!controller_1.is_dual_left_connected && controller_1.is_dual_right_connected) {
|
||||
merge_controllers = true;
|
||||
}
|
||||
if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual &&
|
||||
controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight &&
|
||||
controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) {
|
||||
merge_controllers = true;
|
||||
}
|
||||
if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual &&
|
||||
controller_style_1 == Core::HID::NpadStyleIndex::JoyconLeft &&
|
||||
!controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) {
|
||||
merge_controllers = true;
|
||||
}
|
||||
if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual &&
|
||||
controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual &&
|
||||
controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected &&
|
||||
!controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) {
|
||||
merge_controllers = true;
|
||||
}
|
||||
if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual &&
|
||||
controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual &&
|
||||
!controller_1.is_dual_left_connected && controller_1.is_dual_right_connected &&
|
||||
controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) {
|
||||
merge_controllers = true;
|
||||
}
|
||||
|
||||
if (merge_controllers) {
|
||||
// Disconnect the joycon at the second id and connect the dual joycon at the first index.
|
||||
DisconnectNpad(npad_id_2);
|
||||
controller_1.is_dual_left_connected = true;
|
||||
controller_1.is_dual_right_connected = true;
|
||||
AddNewControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_1);
|
||||
return;
|
||||
}
|
||||
LOG_WARNING(Service_HID,
|
||||
"Controllers can't be merged npad_id_1:{}, npad_id_2:{}, type_1:{}, type_2:{}, "
|
||||
"dual_1(left/right):{}/{}, dual_2(left/right):{}/{}",
|
||||
npad_id_1, npad_id_2, controller_1.device->GetNpadStyleIndex(),
|
||||
controller_2.device->GetNpadStyleIndex(), controller_1.is_dual_left_connected,
|
||||
controller_1.is_dual_right_connected, controller_2.is_dual_left_connected,
|
||||
controller_2.is_dual_right_connected);
|
||||
}
|
||||
|
||||
void Controller_NPad::StartLRAssignmentMode() {
|
||||
@@ -1072,13 +1182,18 @@ bool Controller_NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1,
|
||||
const auto& controller_2 = GetControllerFromNpadIdType(npad_id_2).device;
|
||||
const auto type_index_1 = controller_1->GetNpadStyleIndex();
|
||||
const auto type_index_2 = controller_2->GetNpadStyleIndex();
|
||||
const auto is_connected_1 = controller_1->IsConnected();
|
||||
const auto is_connected_2 = controller_2->IsConnected();
|
||||
|
||||
if (!IsControllerSupported(type_index_1) || !IsControllerSupported(type_index_2)) {
|
||||
if (!IsControllerSupported(type_index_1) && is_connected_1) {
|
||||
return false;
|
||||
}
|
||||
if (!IsControllerSupported(type_index_2) && is_connected_2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AddNewControllerAt(type_index_2, npad_id_1);
|
||||
AddNewControllerAt(type_index_1, npad_id_2);
|
||||
UpdateControllerAt(type_index_2, npad_id_1, is_connected_2);
|
||||
UpdateControllerAt(type_index_1, npad_id_2, is_connected_1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -113,7 +113,8 @@ public:
|
||||
void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_);
|
||||
NpadCommunicationMode GetNpadCommunicationMode() const;
|
||||
|
||||
void SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyAssignmentMode assignment_mode);
|
||||
void SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceType npad_device_type,
|
||||
NpadJoyAssignmentMode assignment_mode);
|
||||
|
||||
bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index,
|
||||
const Core::HID::VibrationValue& vibration_value);
|
||||
@@ -464,7 +465,10 @@ private:
|
||||
std::array<VibrationData, 2> vibration{};
|
||||
bool unintended_home_button_input_protection{};
|
||||
bool is_connected{};
|
||||
Core::HID::NpadStyleIndex npad_type{Core::HID::NpadStyleIndex::None};
|
||||
|
||||
// Dual joycons can have only one side connected
|
||||
bool is_dual_left_connected{true};
|
||||
bool is_dual_right_connected{true};
|
||||
|
||||
// Motion parameters
|
||||
bool sixaxis_at_rest{true};
|
||||
|
||||
@@ -293,8 +293,8 @@ Hid::Hid(Core::System& system_)
|
||||
{132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"},
|
||||
{133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"},
|
||||
{134, &Hid::SetNpadAnalogStickUseCenterClamp, "SetNpadAnalogStickUseCenterClamp"},
|
||||
{135, nullptr, "SetNpadCaptureButtonAssignment"},
|
||||
{136, nullptr, "ClearNpadCaptureButtonAssignment"},
|
||||
{135, &Hid::SetNpadCaptureButtonAssignment, "SetNpadCaptureButtonAssignment"},
|
||||
{136, &Hid::ClearNpadCaptureButtonAssignment, "ClearNpadCaptureButtonAssignment"},
|
||||
{200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"},
|
||||
{201, &Hid::SendVibrationValue, "SendVibrationValue"},
|
||||
{202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"},
|
||||
@@ -975,35 +975,35 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyAssignmentMode::Single);
|
||||
.SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyDeviceType::Left,
|
||||
Controller_NPad::NpadJoyAssignmentMode::Single);
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.npad_id, parameters.applet_resource_user_id);
|
||||
LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
|
||||
// TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
Core::HID::NpadIdType npad_id;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
u64 npad_joy_device_type;
|
||||
Controller_NPad::NpadJoyDeviceType npad_joy_device_type;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyAssignmentMode::Single);
|
||||
.SetNpadMode(parameters.npad_id, parameters.npad_joy_device_type,
|
||||
Controller_NPad::NpadJoyAssignmentMode::Single);
|
||||
|
||||
LOG_WARNING(Service_HID,
|
||||
"(STUBBED) called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
|
||||
parameters.npad_id, parameters.applet_resource_user_id,
|
||||
parameters.npad_joy_device_type);
|
||||
LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
|
||||
parameters.npad_id, parameters.applet_resource_user_id,
|
||||
parameters.npad_joy_device_type);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
@@ -1021,10 +1021,10 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
applet_resource->GetController<Controller_NPad>(HidController::NPad)
|
||||
.SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyAssignmentMode::Dual);
|
||||
.SetNpadMode(parameters.npad_id, {}, Controller_NPad::NpadJoyAssignmentMode::Dual);
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.npad_id, parameters.applet_resource_user_id);
|
||||
LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
@@ -1186,6 +1186,37 @@ void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void Hid::SetNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
Core::HID::NpadStyleSet npad_styleset;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
Core::HID::NpadButton button;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(Service_HID,
|
||||
"(STUBBED) called, npad_styleset={}, applet_resource_user_id={}, button={}",
|
||||
parameters.npad_styleset, parameters.applet_resource_user_id, parameters.button);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void Hid::ClearNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
|
||||
applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
|
||||
|
||||
@@ -136,6 +136,8 @@ private:
|
||||
void IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx);
|
||||
void EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx);
|
||||
void SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx);
|
||||
void SetNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx);
|
||||
void ClearNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx);
|
||||
void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx);
|
||||
void SendVibrationValue(Kernel::HLERequestContext& ctx);
|
||||
void GetActualVibrationValue(Kernel::HLERequestContext& ctx);
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// Copyright 2019 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
@@ -125,8 +125,9 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
|
||||
}
|
||||
metadata.Print();
|
||||
|
||||
const auto static_modules = {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3",
|
||||
"subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"};
|
||||
const auto static_modules = {"rtld", "main", "subsdk0", "subsdk1", "subsdk2",
|
||||
"subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7",
|
||||
"subsdk8", "subsdk9", "sdk"};
|
||||
|
||||
// Use the NSO module loader to figure out the code layout
|
||||
std::size_t code_size{};
|
||||
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
explicit PerfStats(u64 title_id_);
|
||||
~PerfStats();
|
||||
|
||||
using Clock = std::chrono::high_resolution_clock;
|
||||
using Clock = std::chrono::steady_clock;
|
||||
|
||||
void BeginSystemFrame();
|
||||
void EndSystemFrame();
|
||||
@@ -87,7 +87,7 @@ private:
|
||||
|
||||
class SpeedLimiter {
|
||||
public:
|
||||
using Clock = std::chrono::high_resolution_clock;
|
||||
using Clock = std::chrono::steady_clock;
|
||||
|
||||
void DoSpeedLimiting(std::chrono::microseconds current_system_time_us);
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
add_library(shader_recompiler STATIC
|
||||
backend/bindings.h
|
||||
backend/glasm/emit_context.cpp
|
||||
backend/glasm/emit_context.h
|
||||
backend/glasm/emit_glasm.cpp
|
||||
backend/glasm/emit_glasm.h
|
||||
backend/glasm/emit_glasm_barriers.cpp
|
||||
@@ -22,10 +20,10 @@ add_library(shader_recompiler STATIC
|
||||
backend/glasm/emit_glasm_special.cpp
|
||||
backend/glasm/emit_glasm_undefined.cpp
|
||||
backend/glasm/emit_glasm_warp.cpp
|
||||
backend/glasm/glasm_emit_context.cpp
|
||||
backend/glasm/glasm_emit_context.h
|
||||
backend/glasm/reg_alloc.cpp
|
||||
backend/glasm/reg_alloc.h
|
||||
backend/glsl/emit_context.cpp
|
||||
backend/glsl/emit_context.h
|
||||
backend/glsl/emit_glsl.cpp
|
||||
backend/glsl/emit_glsl.h
|
||||
backend/glsl/emit_glsl_atomic.cpp
|
||||
@@ -47,10 +45,10 @@ add_library(shader_recompiler STATIC
|
||||
backend/glsl/emit_glsl_special.cpp
|
||||
backend/glsl/emit_glsl_undefined.cpp
|
||||
backend/glsl/emit_glsl_warp.cpp
|
||||
backend/glsl/glsl_emit_context.cpp
|
||||
backend/glsl/glsl_emit_context.h
|
||||
backend/glsl/var_alloc.cpp
|
||||
backend/glsl/var_alloc.h
|
||||
backend/spirv/emit_context.cpp
|
||||
backend/spirv/emit_context.h
|
||||
backend/spirv/emit_spirv.cpp
|
||||
backend/spirv/emit_spirv.h
|
||||
backend/spirv/emit_spirv_atomic.cpp
|
||||
@@ -72,6 +70,8 @@ add_library(shader_recompiler STATIC
|
||||
backend/spirv/emit_spirv_special.cpp
|
||||
backend/spirv/emit_spirv_undefined.cpp
|
||||
backend/spirv/emit_spirv_warp.cpp
|
||||
backend/spirv/spirv_emit_context.cpp
|
||||
backend/spirv/spirv_emit_context.h
|
||||
environment.h
|
||||
exception.h
|
||||
frontend/ir/abstract_syntax_list.h
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
#include "common/div_ceil.h"
|
||||
#include "common/settings.h"
|
||||
#include "shader_recompiler/backend/bindings.h"
|
||||
#include "shader_recompiler/backend/glasm/emit_context.h"
|
||||
#include "shader_recompiler/backend/glasm/emit_glasm.h"
|
||||
#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
|
||||
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/ir_emitter.h"
|
||||
#include "shader_recompiler/frontend/ir/program.h"
|
||||
#include "shader_recompiler/profile.h"
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
|
||||
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
||||
|
||||
namespace Shader::Backend::GLASM {
|
||||
|
||||
void EmitBarrier(EmitContext& ctx) {
|
||||
ctx.Add("BAR;");
|
||||
}
|
||||
|
||||
void EmitWorkgroupMemoryBarrier(EmitContext& ctx) {
|
||||
ctx.Add("MEMBAR.CTA;");
|
||||
}
|
||||
|
||||
void EmitDeviceMemoryBarrier(EmitContext& ctx) {
|
||||
ctx.Add("MEMBAR;");
|
||||
}
|
||||
|
||||
} // namespace Shader::Backend::GLASM
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "shader_recompiler/backend/glasm/emit_context.h"
|
||||
#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
|
||||
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
namespace Shader::Backend::GLASM {
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "shader_recompiler/backend/glasm/emit_context.h"
|
||||
#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
|
||||
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
namespace Shader::Backend::GLASM {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glasm/emit_context.h"
|
||||
#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
|
||||
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
#include "shader_recompiler/profile.h"
|
||||
#include "shader_recompiler/shader_info.h"
|
||||
@@ -335,6 +335,35 @@ void EmitSetFragDepth(EmitContext& ctx, ScalarF32 value) {
|
||||
ctx.Add("MOV.F result.depth.z,{};", value);
|
||||
}
|
||||
|
||||
void EmitWorkgroupId(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.Add("MOV.S {},invocation.groupid;", inst);
|
||||
}
|
||||
|
||||
void EmitLocalInvocationId(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.Add("MOV.S {},invocation.localid;", inst);
|
||||
}
|
||||
|
||||
void EmitInvocationId(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.Add("MOV.S {}.x,primitive_invocation.x;", inst);
|
||||
}
|
||||
|
||||
void EmitSampleId(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.Add("MOV.S {}.x,fragment.sampleid.x;", inst);
|
||||
}
|
||||
|
||||
void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.Add("MOV.S {}.x,fragment.helperthread.x;", inst);
|
||||
}
|
||||
|
||||
void EmitYDirection(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.uses_y_direction = true;
|
||||
ctx.Add("MOV.F {}.x,y_direction[0].w;", inst);
|
||||
}
|
||||
|
||||
void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.Add("MOV.F {}.x,scaling[0].z;", inst);
|
||||
}
|
||||
|
||||
void EmitLoadLocal(EmitContext& ctx, IR::Inst& inst, ScalarU32 word_offset) {
|
||||
ctx.Add("MOV.U {},lmem[{}].x;", inst, word_offset);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
|
||||
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
||||
|
||||
namespace Shader::Backend::GLASM {
|
||||
|
||||
void EmitJoin(EmitContext&) {
|
||||
throw NotImplementedException("Join shouldn't be emitted");
|
||||
}
|
||||
|
||||
void EmitDemoteToHelperInvocation(EmitContext& ctx) {
|
||||
ctx.Add("KIL TR.x;");
|
||||
}
|
||||
|
||||
} // namespace Shader::Backend::GLASM
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glasm/emit_context.h"
|
||||
#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
|
||||
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/modifiers.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glasm/emit_context.h"
|
||||
#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
|
||||
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/modifiers.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "shader_recompiler/backend/glasm/emit_context.h"
|
||||
#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
|
||||
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/modifiers.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "shader_recompiler/backend/glasm/emit_context.h"
|
||||
#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
|
||||
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
namespace Shader::Backend::GLASM {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
|
||||
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
||||
|
||||
namespace Shader::Backend::GLASM {
|
||||
|
||||
void EmitLogicalOr(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) {
|
||||
ctx.Add("OR.S {},{},{};", inst, a, b);
|
||||
}
|
||||
|
||||
void EmitLogicalAnd(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) {
|
||||
ctx.Add("AND.S {},{},{};", inst, a, b);
|
||||
}
|
||||
|
||||
void EmitLogicalXor(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) {
|
||||
ctx.Add("XOR.S {},{},{};", inst, a, b);
|
||||
}
|
||||
|
||||
void EmitLogicalNot(EmitContext& ctx, IR::Inst& inst, ScalarS32 value) {
|
||||
ctx.Add("SEQ.S {},{},0;", inst, value);
|
||||
}
|
||||
|
||||
} // namespace Shader::Backend::GLASM
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glasm/emit_context.h"
|
||||
#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
|
||||
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/program.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
#include "shader_recompiler/runtime_info.h"
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glasm/emit_context.h"
|
||||
#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
|
||||
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/program.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
@@ -17,110 +17,6 @@ namespace Shader::Backend::GLASM {
|
||||
|
||||
#define NotImplemented() throw NotImplementedException("GLASM instruction {}", __LINE__)
|
||||
|
||||
static void DefinePhi(EmitContext& ctx, IR::Inst& phi) {
|
||||
switch (phi.Type()) {
|
||||
case IR::Type::U1:
|
||||
case IR::Type::U32:
|
||||
case IR::Type::F32:
|
||||
ctx.reg_alloc.Define(phi);
|
||||
break;
|
||||
case IR::Type::U64:
|
||||
case IR::Type::F64:
|
||||
ctx.reg_alloc.LongDefine(phi);
|
||||
break;
|
||||
default:
|
||||
throw NotImplementedException("Phi node type {}", phi.Type());
|
||||
}
|
||||
}
|
||||
|
||||
void EmitPhi(EmitContext& ctx, IR::Inst& phi) {
|
||||
const size_t num_args{phi.NumArgs()};
|
||||
for (size_t i = 0; i < num_args; ++i) {
|
||||
ctx.reg_alloc.Consume(phi.Arg(i));
|
||||
}
|
||||
if (!phi.Definition<Id>().is_valid) {
|
||||
// The phi node wasn't forward defined
|
||||
DefinePhi(ctx, phi);
|
||||
}
|
||||
}
|
||||
|
||||
void EmitVoid(EmitContext&) {}
|
||||
|
||||
void EmitReference(EmitContext& ctx, const IR::Value& value) {
|
||||
ctx.reg_alloc.Consume(value);
|
||||
}
|
||||
|
||||
void EmitPhiMove(EmitContext& ctx, const IR::Value& phi_value, const IR::Value& value) {
|
||||
IR::Inst& phi{RegAlloc::AliasInst(*phi_value.Inst())};
|
||||
if (!phi.Definition<Id>().is_valid) {
|
||||
// The phi node wasn't forward defined
|
||||
DefinePhi(ctx, phi);
|
||||
}
|
||||
const Register phi_reg{ctx.reg_alloc.Consume(IR::Value{&phi})};
|
||||
const Value eval_value{ctx.reg_alloc.Consume(value)};
|
||||
|
||||
if (phi_reg == eval_value) {
|
||||
return;
|
||||
}
|
||||
switch (phi.Flags<IR::Type>()) {
|
||||
case IR::Type::U1:
|
||||
case IR::Type::U32:
|
||||
case IR::Type::F32:
|
||||
ctx.Add("MOV.S {}.x,{};", phi_reg, ScalarS32{eval_value});
|
||||
break;
|
||||
case IR::Type::U64:
|
||||
case IR::Type::F64:
|
||||
ctx.Add("MOV.U64 {}.x,{};", phi_reg, ScalarRegister{eval_value});
|
||||
break;
|
||||
default:
|
||||
throw NotImplementedException("Phi node type {}", phi.Type());
|
||||
}
|
||||
}
|
||||
|
||||
void EmitJoin(EmitContext& ctx) {
|
||||
NotImplemented();
|
||||
}
|
||||
|
||||
void EmitDemoteToHelperInvocation(EmitContext& ctx) {
|
||||
ctx.Add("KIL TR.x;");
|
||||
}
|
||||
|
||||
void EmitBarrier(EmitContext& ctx) {
|
||||
ctx.Add("BAR;");
|
||||
}
|
||||
|
||||
void EmitWorkgroupMemoryBarrier(EmitContext& ctx) {
|
||||
ctx.Add("MEMBAR.CTA;");
|
||||
}
|
||||
|
||||
void EmitDeviceMemoryBarrier(EmitContext& ctx) {
|
||||
ctx.Add("MEMBAR;");
|
||||
}
|
||||
|
||||
void EmitPrologue(EmitContext& ctx) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void EmitEpilogue(EmitContext& ctx) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void EmitEmitVertex(EmitContext& ctx, ScalarS32 stream) {
|
||||
if (stream.type == Type::U32 && stream.imm_u32 == 0) {
|
||||
ctx.Add("EMIT;");
|
||||
} else {
|
||||
ctx.Add("EMITS {};", stream);
|
||||
}
|
||||
}
|
||||
|
||||
void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) {
|
||||
if (!stream.IsImmediate()) {
|
||||
LOG_WARNING(Shader_GLASM, "Stream is not immediate");
|
||||
}
|
||||
ctx.reg_alloc.Consume(stream);
|
||||
ctx.Add("ENDPRIM;");
|
||||
}
|
||||
|
||||
void EmitGetRegister(EmitContext& ctx) {
|
||||
NotImplemented();
|
||||
}
|
||||
@@ -185,55 +81,6 @@ void EmitSetOFlag(EmitContext& ctx) {
|
||||
NotImplemented();
|
||||
}
|
||||
|
||||
void EmitWorkgroupId(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.Add("MOV.S {},invocation.groupid;", inst);
|
||||
}
|
||||
|
||||
void EmitLocalInvocationId(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.Add("MOV.S {},invocation.localid;", inst);
|
||||
}
|
||||
|
||||
void EmitInvocationId(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.Add("MOV.S {}.x,primitive_invocation.x;", inst);
|
||||
}
|
||||
|
||||
void EmitSampleId(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.Add("MOV.S {}.x,fragment.sampleid.x;", inst);
|
||||
}
|
||||
|
||||
void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.Add("MOV.S {}.x,fragment.helperthread.x;", inst);
|
||||
}
|
||||
|
||||
void EmitYDirection(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.uses_y_direction = true;
|
||||
ctx.Add("MOV.F {}.x,y_direction[0].w;", inst);
|
||||
}
|
||||
|
||||
void EmitResolutionDownFactor(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.Add("MOV.F {}.x,scaling[0].z;", inst);
|
||||
}
|
||||
|
||||
void EmitUndefU1(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.Add("MOV.S {}.x,0;", inst);
|
||||
}
|
||||
|
||||
void EmitUndefU8(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.Add("MOV.S {}.x,0;", inst);
|
||||
}
|
||||
|
||||
void EmitUndefU16(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.Add("MOV.S {}.x,0;", inst);
|
||||
}
|
||||
|
||||
void EmitUndefU32(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.Add("MOV.S {}.x,0;", inst);
|
||||
}
|
||||
|
||||
void EmitUndefU64(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.LongAdd("MOV.S64 {}.x,0;", inst);
|
||||
}
|
||||
|
||||
void EmitGetZeroFromOp(EmitContext& ctx) {
|
||||
NotImplemented();
|
||||
}
|
||||
@@ -258,20 +105,4 @@ void EmitGetInBoundsFromOp(EmitContext& ctx) {
|
||||
NotImplemented();
|
||||
}
|
||||
|
||||
void EmitLogicalOr(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) {
|
||||
ctx.Add("OR.S {},{},{};", inst, a, b);
|
||||
}
|
||||
|
||||
void EmitLogicalAnd(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) {
|
||||
ctx.Add("AND.S {},{},{};", inst, a, b);
|
||||
}
|
||||
|
||||
void EmitLogicalXor(EmitContext& ctx, IR::Inst& inst, ScalarS32 a, ScalarS32 b) {
|
||||
ctx.Add("XOR.S {},{},{};", inst, a, b);
|
||||
}
|
||||
|
||||
void EmitLogicalNot(EmitContext& ctx, IR::Inst& inst, ScalarS32 value) {
|
||||
ctx.Add("SEQ.S {},{},0;", inst, value);
|
||||
}
|
||||
|
||||
} // namespace Shader::Backend::GLASM
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "shader_recompiler/backend/glasm/emit_context.h"
|
||||
#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
|
||||
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
namespace Shader::Backend::GLASM {
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "shader_recompiler/backend/glasm/emit_context.h"
|
||||
#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
|
||||
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
namespace Shader::Backend::GLASM {
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
|
||||
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
namespace Shader::Backend::GLASM {
|
||||
|
||||
static void DefinePhi(EmitContext& ctx, IR::Inst& phi) {
|
||||
switch (phi.Type()) {
|
||||
case IR::Type::U1:
|
||||
case IR::Type::U32:
|
||||
case IR::Type::F32:
|
||||
ctx.reg_alloc.Define(phi);
|
||||
break;
|
||||
case IR::Type::U64:
|
||||
case IR::Type::F64:
|
||||
ctx.reg_alloc.LongDefine(phi);
|
||||
break;
|
||||
default:
|
||||
throw NotImplementedException("Phi node type {}", phi.Type());
|
||||
}
|
||||
}
|
||||
|
||||
void EmitPhi(EmitContext& ctx, IR::Inst& phi) {
|
||||
const size_t num_args{phi.NumArgs()};
|
||||
for (size_t i = 0; i < num_args; ++i) {
|
||||
ctx.reg_alloc.Consume(phi.Arg(i));
|
||||
}
|
||||
if (!phi.Definition<Id>().is_valid) {
|
||||
// The phi node wasn't forward defined
|
||||
DefinePhi(ctx, phi);
|
||||
}
|
||||
}
|
||||
|
||||
void EmitVoid(EmitContext&) {}
|
||||
|
||||
void EmitReference(EmitContext& ctx, const IR::Value& value) {
|
||||
ctx.reg_alloc.Consume(value);
|
||||
}
|
||||
|
||||
void EmitPhiMove(EmitContext& ctx, const IR::Value& phi_value, const IR::Value& value) {
|
||||
IR::Inst& phi{RegAlloc::AliasInst(*phi_value.Inst())};
|
||||
if (!phi.Definition<Id>().is_valid) {
|
||||
// The phi node wasn't forward defined
|
||||
DefinePhi(ctx, phi);
|
||||
}
|
||||
const Register phi_reg{ctx.reg_alloc.Consume(IR::Value{&phi})};
|
||||
const Value eval_value{ctx.reg_alloc.Consume(value)};
|
||||
|
||||
if (phi_reg == eval_value) {
|
||||
return;
|
||||
}
|
||||
switch (phi.Flags<IR::Type>()) {
|
||||
case IR::Type::U1:
|
||||
case IR::Type::U32:
|
||||
case IR::Type::F32:
|
||||
ctx.Add("MOV.S {}.x,{};", phi_reg, ScalarS32{eval_value});
|
||||
break;
|
||||
case IR::Type::U64:
|
||||
case IR::Type::F64:
|
||||
ctx.Add("MOV.U64 {}.x,{};", phi_reg, ScalarRegister{eval_value});
|
||||
break;
|
||||
default:
|
||||
throw NotImplementedException("Phi node type {}", phi.Type());
|
||||
}
|
||||
}
|
||||
|
||||
void EmitPrologue(EmitContext&) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void EmitEpilogue(EmitContext&) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void EmitEmitVertex(EmitContext& ctx, ScalarS32 stream) {
|
||||
if (stream.type == Type::U32 && stream.imm_u32 == 0) {
|
||||
ctx.Add("EMIT;");
|
||||
} else {
|
||||
ctx.Add("EMITS {};", stream);
|
||||
}
|
||||
}
|
||||
|
||||
void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) {
|
||||
if (!stream.IsImmediate()) {
|
||||
LOG_WARNING(Shader_GLASM, "Stream is not immediate");
|
||||
}
|
||||
ctx.reg_alloc.Consume(stream);
|
||||
ctx.Add("ENDPRIM;");
|
||||
}
|
||||
|
||||
} // namespace Shader::Backend::GLASM
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
|
||||
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
||||
|
||||
namespace Shader::Backend::GLASM {
|
||||
|
||||
void EmitUndefU1(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.Add("MOV.S {}.x,0;", inst);
|
||||
}
|
||||
|
||||
void EmitUndefU8(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.Add("MOV.S {}.x,0;", inst);
|
||||
}
|
||||
|
||||
void EmitUndefU16(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.Add("MOV.S {}.x,0;", inst);
|
||||
}
|
||||
|
||||
void EmitUndefU32(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.Add("MOV.S {}.x,0;", inst);
|
||||
}
|
||||
|
||||
void EmitUndefU64(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.LongAdd("MOV.S64 {}.x,0;", inst);
|
||||
}
|
||||
|
||||
} // namespace Shader::Backend::GLASM
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "shader_recompiler/backend/glasm/emit_context.h"
|
||||
#include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
|
||||
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
#include "shader_recompiler/profile.h"
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/bindings.h"
|
||||
#include "shader_recompiler/backend/glasm/emit_context.h"
|
||||
#include "shader_recompiler/backend/glasm/emit_glasm.h"
|
||||
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/program.h"
|
||||
#include "shader_recompiler/profile.h"
|
||||
#include "shader_recompiler/runtime_info.h"
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "shader_recompiler/backend/glasm/emit_context.h"
|
||||
#include "shader_recompiler/backend/glasm/glasm_emit_context.h"
|
||||
#include "shader_recompiler/backend/glasm/reg_alloc.h"
|
||||
#include "shader_recompiler/exception.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
|
||||
#include "common/div_ceil.h"
|
||||
#include "common/settings.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_glsl.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
||||
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/ir_emitter.h"
|
||||
|
||||
namespace Shader::Backend::GLSL {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
||||
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
namespace Shader::Backend::GLSL {
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
||||
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
namespace Shader::Backend::GLSL {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
||||
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
namespace Shader::Backend::GLSL {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
||||
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
namespace Shader::Backend::GLSL {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
||||
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
#include "shader_recompiler/profile.h"
|
||||
#include "shader_recompiler/runtime_info.h"
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
||||
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
|
||||
#include "shader_recompiler/exception.h"
|
||||
|
||||
namespace Shader::Backend::GLSL {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
||||
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
namespace Shader::Backend::GLSL {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
||||
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/modifiers.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
||||
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/modifiers.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
#include "shader_recompiler/profile.h"
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
||||
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
namespace Shader::Backend::GLSL {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
||||
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
namespace Shader::Backend::GLSL {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
||||
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
#include "shader_recompiler/profile.h"
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
||||
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
||||
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
namespace Shader::Backend::GLSL {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
||||
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
namespace Shader::Backend::GLSL {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
||||
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/program.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
#include "shader_recompiler/profile.h"
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
||||
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
|
||||
|
||||
namespace Shader::Backend::GLSL {
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
||||
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
#include "shader_recompiler/profile.h"
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "shader_recompiler/backend/bindings.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||
#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/program.h"
|
||||
#include "shader_recompiler/profile.h"
|
||||
#include "shader_recompiler/runtime_info.h"
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "common/settings.h"
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
||||
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/basic_block.h"
|
||||
#include "shader_recompiler/frontend/ir/program.h"
|
||||
|
||||
|
||||
@@ -6,13 +6,11 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <sirit/sirit.h>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "shader_recompiler/backend/bindings.h"
|
||||
#include "shader_recompiler/backend/spirv/emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/program.h"
|
||||
#include "shader_recompiler/profile.h"
|
||||
#include "shader_recompiler/runtime_info.h"
|
||||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
||||
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
||||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
namespace {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
||||
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/modifiers.h"
|
||||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
||||
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
||||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
||||
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/modifiers.h"
|
||||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
||||
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
||||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
namespace {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
||||
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
||||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
||||
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
||||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
namespace {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
||||
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/modifiers.h"
|
||||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
||||
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/modifiers.h"
|
||||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
||||
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
||||
#include "shader_recompiler/frontend/ir/modifiers.h"
|
||||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
||||
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
||||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
namespace {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv_instructions.h"
|
||||
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
||||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user