Compare commits

...

50 Commits

Author SHA1 Message Date
german77
133f497f84 controller_applet: Only populate supported controllers 2022-01-01 21:42:17 -06:00
Mai M
eb7d361657 Merge pull request #7654 from Morph1984/dynarmic
externals: Update dynarmic to 28714ee7
2021-12-31 02:49:16 -05:00
Morph
af89f7683d externals: Update dynarmic to 28714ee7
Reduces compilation times on MSVC.
2021-12-30 22:28:27 -05:00
bunnei
667a8ae163 Merge pull request #7647 from german77/toad
core/hid: Fix controller type validation
2021-12-30 16:54:35 -08:00
german77
9ee5c4ec56 core/hid: Fix controller type validation 2021-12-29 22:51:53 -06:00
bunnei
5e58271903 Merge pull request #7635 from bunnei/set-heap-size
core: hle: kernel: Updated implementation of svcSetHeapSize.
2021-12-29 20:30:12 -08:00
bunnei
279c7bcc1a Merge pull request #7618 from goldenx86/patch-4
Increase boost requirement to 1.78.0
2021-12-28 16:25:37 -08:00
Matías Locatti
c7235e67ef Empty spaces 2021-12-28 18:50:51 -03:00
Matías Locatti
840d5520d2 Changes to avoid warnings in SSE4.2 optimized SPIR-V 2021-12-28 17:35:55 -03:00
bunnei
091463a429 core: hle: kernel: Updated implementation of svcSetHeapSize.
- Updates our svcSetHeapSize with latest HOS, furthermore allowing heap size to properly be extended/shrunk.
- Validated with tests https://github.com/Atmosphere-NX/Atmosphere/blob/master/tests/TestSvc/source/test_set_heap_size.cpp.
2021-12-28 01:25:20 -08:00
bunnei
f67605e6aa Merge pull request #7622 from ameerj/vk-rescale-invalid-ptr
vk_texture_cache: Fix invalidated pointer access
2021-12-28 00:46:37 -08:00
bunnei
9a0648ff0a Merge pull request #7621 from bunnei/set-mem-perm
core: hle: kernel: Implement SetMemoryPermission.
2021-12-27 23:33:11 -08:00
bunnei
c9e4acc4e2 Merge pull request #7630 from ameerj/glasm-get-int
emit_glasm_context_get_set: Fix GetAttribute return value type.
2021-12-27 16:35:11 -08:00
bunnei
292dfac25e Merge pull request #7620 from bunnei/kernel-thread-x18
core: hle: kernel: KThread: X18 should be a cryptographically random number.
2021-12-25 00:42:54 -08:00
ameerj
37addf7a94 emit_glasm_context_get_set: Fix GetAttribute return value type.
GetAttribute expects an F32 result type at the IR level, this fixes the return value of attributes which were not returning an F32
2021-12-24 20:45:07 -05:00
bunnei
8a48c4ed1c Merge pull request #7623 from ameerj/unused-func
blit_image: Remove unused function
2021-12-23 22:21:28 -08:00
ameerj
cbc0f0a66e blit_image: Remove unused function 2021-12-23 21:06:32 -05:00
ameerj
481b210c0d vk_texture_cache: Fix invalidated pointer access
The vulkan ImageView held a reference to its source image for rescale status checking. This pointer is sometimes invalidated when the texture cache slot_images container is resized.
To avoid an invalid pointer dereference, the ImageView now holds a reference to the container itself.
2021-12-23 20:55:48 -05:00
bunnei
4e7a6639d2 core: hle: kernel: Implement SetMemoryPermission.
- Not seen in any games yet, but validated with kernel tests.
2021-12-23 01:10:36 -08:00
bunnei
a0c7d93b84 core: hle: kernel: KThread: X18 should be a cryptographically random number.
- This was added with firmware 11.0.0 (https://switchbrew.org/wiki/11.0.0).
    - X18 is OR'd by kernel with 1, to make sure it is odd.
2021-12-23 00:03:39 -08:00
bunnei
516325eba8 Merge pull request #7614 from liushuyu/fix-linux-inhibit
main: Fix wake lock (prevent sleep) in Flatpak
2021-12-22 16:53:54 -08:00
Matías Locatti
e0193e2be5 Increase boost requirement to 1.78.0
Liu's finding, this allows to build yuzu on VS 2022.
Ignore at will.
2021-12-22 16:10:21 -03:00
Fernando S
b85f5b1332 Merge pull request #7616 from bunnei/fix-get-idle-ticks
hle: kernel: svc: GetInfo: Fix error checking with IdleTickCount.
2021-12-22 17:39:17 +01:00
Fernando S
648c7b4ed6 Merge pull request #7375 from vonchenplus/convert_legacy
Convert all legacy attributes to generic attributes
2021-12-22 17:36:05 +01:00
liushuyu
14fc1bec17 main: reword inhibit reason 2021-12-22 02:33:01 -07:00
liushuyu
fa7abafa5f main: fix wake lock in Flatpak ...
... by using the XDP system
2021-12-22 02:27:09 -07:00
bunnei
36df305b13 Merge pull request #7599 from FernandoS27/primrestart-vulkan
Vulkan: Fix Primitive Restart and implement Logical Operations
2021-12-22 00:19:23 -08:00
bunnei
f1eff447bb Merge pull request #7602 from jbeich/freebsd-vaapi
build: enable VA-API on FreeBSD
2021-12-21 22:46:49 -08:00
bunnei
49e3c073a5 hle: kernel: svc: GetInfo: Fix error checking with IdleTickCount.
- Enforce tha the supplied handle is invalid, not valid.
- This gets Witcher 3 booting.
2021-12-21 22:41:23 -08:00
bunnei
6991d447d4 Merge pull request #7604 from ameerj/fullscreen-render-window
main: Make separate render window fullscreen toggle on the monitor it resides in
2021-12-21 18:05:11 -08:00
bunnei
b30a1d49ff Merge pull request #7608 from Tatsh/scm-ver-override
Allow overriding SCM version info
2021-12-21 16:07:27 -08:00
bunnei
5e24f7ed31 Merge pull request #7481 from german77/gyro-bias
service/hid: Improve console motion accuracy
2021-12-21 00:13:54 -08:00
bunnei
cf221ca92d Merge pull request #7609 from Tatsh/file-assoc
dist/XDG: add more file associations
2021-12-20 21:55:43 -08:00
Andrew Udvare
59c6f45e7a dist/XDG: add more file associations 2021-12-20 19:18:02 -05:00
Andrew Udvare
caf38725ae Allow overriding SCM version info
If the build is from a non-repository, these functions will return empty. This
patch allows using defines to CMake to set version info such as
-DGIT_BRANCH=master.
2021-12-20 19:13:07 -05:00
bunnei
ee6d40d414 Merge pull request #7597 from bunnei/remove-global-lock
core: hle: Remove global HLE lock.
2021-12-20 14:24:50 -08:00
bunnei
eb4ea7e5c7 Merge pull request #7603 from ameerj/here-we-go-again
kernel: Manually destroy the current process during shut down
2021-12-19 02:09:53 -08:00
ameerj
55650c5b75 kernel: Manually destroy the current process during shut down
Avoids a memory leak.
2021-12-19 01:38:25 -05:00
Jan Beich
e57b13ad94 video_core/codecs: re-enable VAAPI/VDPAU on BSDs after 72aa418b0b 2021-12-18 20:57:30 +00:00
Jan Beich
1a9576fdff cmake: enable VA-API on more Unix-like after 0be4e402e2 2021-12-18 20:57:30 +00:00
vonchenplus
4908a07c20 Address format clang 2021-12-18 14:27:07 +08:00
Fernando Sahmkow
6c00151d17 Vulkan: Fix the checks for primitive restart extension. 2021-12-18 07:17:08 +01:00
vonchenplus
6ebc972c2b Remove spirv handle legacy related code 2021-12-18 14:08:50 +08:00
vonchenplus
94652e122d Remove glsl handle legacy related code 2021-12-18 14:03:40 +08:00
Feng Chen
e49184e606 Merge branch 'yuzu-emu:master' into convert_legacy 2021-12-18 13:57:14 +08:00
Fernando Sahmkow
14d2c77f91 Vulkan: implement Logical Operations. 2021-12-18 06:52:28 +01:00
Fernando Sahmkow
6430fc29a9 Vulkan: Implement VK_EXT_primitive_topology_list_restart 2021-12-18 05:47:48 +01:00
bunnei
c73841500a core: hle: Remove global HLE lock.
- This was added early on as a hack to protect against some concurrency issues.
- It's not clear that this serves any purpose anymore, and if it does, individual components should be fixed rather than using a global recursive mutex.
2021-12-17 16:05:51 -08:00
Narr the Reg
316f80af87 service/hid: Improve console motion accuracy 2021-12-12 23:26:04 -06:00
Feng Chen
4dd85f86a8 Implement convert legacy to generic 2021-11-19 22:53:58 +08:00
63 changed files with 640 additions and 626 deletions

View File

@@ -229,7 +229,7 @@ elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR YUZU_USE_BUNDLED_BOOST)
include_directories(SYSTEM "${Boost_INCLUDE_DIRS}")
else()
message(STATUS "Boost 1.73.0 or newer not found, falling back to Conan")
list(APPEND CONAN_REQUIRED_LIBS "boost/1.73.0")
list(APPEND CONAN_REQUIRED_LIBS "boost/1.78.0")
endif()
# Attempt to locate any packages that are required and report the missing ones in CONAN_REQUIRED_LIBS
@@ -249,7 +249,7 @@ if(ENABLE_QT)
# Check for system Qt on Linux, fallback to bundled Qt
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
if (NOT YUZU_USE_BUNDLED_QT)
find_package(Qt5 ${QT_VERSION} COMPONENTS Widgets)
find_package(Qt5 ${QT_VERSION} COMPONENTS Widgets DBus)
endif()
if (NOT Qt5_FOUND OR YUZU_USE_BUNDLED_QT)
# Check for dependencies, then enable bundled Qt download
@@ -508,7 +508,7 @@ set(FFmpeg_COMPONENTS
avutil
swscale)
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
if (UNIX AND NOT APPLE)
Include(FindPkgConfig REQUIRED)
pkg_check_modules(LIBVA libva)
endif()

View File

@@ -11,9 +11,15 @@ find_package(Git QUIET PATHS "${GIT_EXECUTABLE}")
# generate git/build information
include(GetGitRevisionDescription)
get_git_head_revision(GIT_REF_SPEC GIT_REV)
git_describe(GIT_DESC --always --long --dirty)
git_branch_name(GIT_BRANCH)
if(NOT GIT_REF_SPEC)
get_git_head_revision(GIT_REF_SPEC GIT_REV)
endif()
if(NOT GIT_DESC)
git_describe(GIT_DESC --always --long --dirty)
endif()
if (NOT GIT_BRANCH)
git_branch_name(GIT_BRANCH)
endif()
get_timestamp(BUILD_DATE)
# Generate cpp with Git revision from template

2
dist/yuzu.desktop vendored
View File

@@ -8,5 +8,5 @@ Icon=yuzu
TryExec=yuzu
Exec=yuzu %f
Categories=Game;Emulator;Qt;
MimeType=application/x-nx-nro;application/x-nx-nso;
MimeType=application/x-nx-nro;application/x-nx-nso;application/x-nx-nsp;application/x-nx-xci;
Keywords=Switch;Nintendo;

15
dist/yuzu.xml vendored
View File

@@ -15,4 +15,19 @@
<glob pattern="*.nso"/>
<magic><match value="NSO" type="string" offset="0"/></magic>
</mime-type>
<mime-type type="application/x-nx-nsp">
<comment>Nintendo Switch Package</comment>
<acronym>NSP</acronym>
<icon name="yuzu"/>
<glob pattern="*.nsp"/>
<magic><match value="PFS" type="string" offset="0"/></magic>
</mime-type>
<mime-type type="application/x-nx-xci">
<comment>Nintendo Switch Card Image</comment>
<acronym>XCI</acronym>
<icon name="yuzu"/>
<glob pattern="*.xci"/>
</mime-type>
</mime-info>

View File

@@ -22,6 +22,11 @@ add_custom_command(OUTPUT scm_rev.cpp
-DTITLE_BAR_FORMAT_RUNNING=${TITLE_BAR_FORMAT_RUNNING}
-DBUILD_TAG=${BUILD_TAG}
-DBUILD_ID=${DISPLAY_VERSION}
-DGIT_REF_SPEC=${GIT_REF_SPEC}
-DGIT_REV=${GIT_REV}
-DGIT_DESC=${GIT_DESC}
-DGIT_BRANCH=${GIT_BRANCH}
-DBUILD_FULLNAME=${BUILD_FULLNAME}
-DGIT_EXECUTABLE=${GIT_EXECUTABLE}
-P ${CMAKE_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake
DEPENDS

View File

@@ -265,8 +265,6 @@ add_library(core STATIC
hle/kernel/svc_wrap.h
hle/kernel/time_manager.cpp
hle/kernel/time_manager.h
hle/lock.cpp
hle/lock.h
hle/result.h
hle/service/acc/acc.cpp
hle/service/acc/acc.h

View File

@@ -45,26 +45,26 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb
// Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld
if (parameters.allow_pro_controller) {
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
controller->Connect();
controller->Connect(true);
} else if (parameters.allow_dual_joycons) {
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual);
controller->Connect();
controller->Connect(true);
} else if (parameters.allow_left_joycon && parameters.allow_right_joycon) {
// Assign left joycons to even player indices and right joycons to odd player indices.
// We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and
// a right Joycon for Player 2 in 2 Player Assist mode.
if (index % 2 == 0) {
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconLeft);
controller->Connect();
controller->Connect(true);
} else {
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight);
controller->Connect();
controller->Connect(true);
}
} else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld &&
!Settings::values.use_docked_mode.GetValue()) {
// We should *never* reach here under any normal circumstances.
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
controller->Connect();
controller->Connect(true);
} else {
UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!");
}

View File

@@ -161,7 +161,10 @@ void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {
motion.rotation = emulated.GetGyroscope();
motion.orientation = emulated.GetOrientation();
motion.quaternion = emulated.GetQuaternion();
motion.gyro_bias = emulated.GetGyroBias();
motion.is_at_rest = !emulated.IsMoving(motion_sensitivity);
// Find what is this value
motion.verticalization_error = 0.0f;
TriggerOnChange(ConsoleTriggerType::Motion);
}

View File

@@ -50,6 +50,8 @@ struct ConsoleMotion {
Common::Vec3f rotation{};
std::array<Common::Vec3f, 3> orientation{};
Common::Quaternion<f32> quaternion{};
Common::Vec3f gyro_bias{};
f32 verticalization_error{};
bool is_at_rest{};
};

View File

@@ -886,8 +886,9 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles)
}
}
bool EmulatedController::IsControllerSupported() const {
switch (npad_type) {
bool EmulatedController::IsControllerSupported(bool use_temporary_value) const {
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
switch (type) {
case NpadStyleIndex::ProController:
return supported_style_tag.fullkey;
case NpadStyleIndex::Handheld:
@@ -915,9 +916,10 @@ bool EmulatedController::IsControllerSupported() const {
}
}
void EmulatedController::Connect() {
if (!IsControllerSupported()) {
LOG_ERROR(Service_HID, "Controller type {} is not supported", npad_type);
void EmulatedController::Connect(bool use_temporary_value) {
if (!IsControllerSupported(use_temporary_value)) {
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
LOG_ERROR(Service_HID, "Controller type {} is not supported", type);
return;
}
{

View File

@@ -167,8 +167,11 @@ public:
*/
void SetSupportedNpadStyleTag(NpadStyleTag supported_styles);
/// Sets the connected status to true
void Connect();
/**
* Sets the connected status to true
* @param use_temporary_value If true tmp_npad_type will be used
*/
void Connect(bool use_temporary_value = false);
/// Sets the connected status to false
void Disconnect();
@@ -319,9 +322,10 @@ private:
/**
* Checks the current controller type against the supported_style_tag
* @param use_temporary_value If true tmp_npad_type will be used
* @return true if the controller is supported
*/
bool IsControllerSupported() const;
bool IsControllerSupported(bool use_temporary_value = false) const;
/**
* Updates the button status of the controller

View File

@@ -23,11 +23,11 @@ void MotionInput::SetAcceleration(const Common::Vec3f& acceleration) {
}
void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) {
gyro = gyroscope - gyro_drift;
gyro = gyroscope - gyro_bias;
// Auto adjust drift to minimize drift
if (!IsMoving(0.1f)) {
gyro_drift = (gyro_drift * 0.9999f) + (gyroscope * 0.0001f);
gyro_bias = (gyro_bias * 0.9999f) + (gyroscope * 0.0001f);
}
if (gyro.Length2() < gyro_threshold) {
@@ -41,8 +41,8 @@ void MotionInput::SetQuaternion(const Common::Quaternion<f32>& quaternion) {
quat = quaternion;
}
void MotionInput::SetGyroDrift(const Common::Vec3f& drift) {
gyro_drift = drift;
void MotionInput::SetGyroBias(const Common::Vec3f& bias) {
gyro_bias = bias;
}
void MotionInput::SetGyroThreshold(f32 threshold) {
@@ -192,6 +192,10 @@ Common::Vec3f MotionInput::GetGyroscope() const {
return gyro;
}
Common::Vec3f MotionInput::GetGyroBias() const {
return gyro_bias;
}
Common::Quaternion<f32> MotionInput::GetQuaternion() const {
return quat;
}

View File

@@ -24,7 +24,7 @@ public:
void SetAcceleration(const Common::Vec3f& acceleration);
void SetGyroscope(const Common::Vec3f& gyroscope);
void SetQuaternion(const Common::Quaternion<f32>& quaternion);
void SetGyroDrift(const Common::Vec3f& drift);
void SetGyroBias(const Common::Vec3f& bias);
void SetGyroThreshold(f32 threshold);
void EnableReset(bool reset);
@@ -36,6 +36,7 @@ public:
[[nodiscard]] std::array<Common::Vec3f, 3> GetOrientation() const;
[[nodiscard]] Common::Vec3f GetAcceleration() const;
[[nodiscard]] Common::Vec3f GetGyroscope() const;
[[nodiscard]] Common::Vec3f GetGyroBias() const;
[[nodiscard]] Common::Vec3f GetRotations() const;
[[nodiscard]] Common::Quaternion<f32> GetQuaternion() const;
@@ -69,7 +70,7 @@ private:
Common::Vec3f gyro;
// Vector to be substracted from gyro measurements
Common::Vec3f gyro_drift;
Common::Vec3f gyro_bias;
// Minimum gyro amplitude to detect if the device is moving
f32 gyro_threshold = 0.0f;

View File

@@ -120,7 +120,7 @@ static_assert(static_cast<u32>(KMemoryState::CodeOut) == 0x00402015);
enum class KMemoryPermission : u8 {
None = 0,
Mask = static_cast<u8>(~None),
All = static_cast<u8>(~None),
Read = 1 << 0,
Write = 1 << 1,

View File

@@ -264,9 +264,9 @@ ResultCode KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_
ASSERT(heap_last < stack_start || stack_last < heap_start);
ASSERT(heap_last < kmap_start || kmap_last < heap_start);
current_heap_addr = heap_region_start;
heap_capacity = 0;
physical_memory_usage = 0;
current_heap_end = heap_region_start;
max_heap_size = 0;
mapped_physical_memory_size = 0;
memory_pool = pool;
page_table_impl.Resize(address_space_width, PageBits);
@@ -306,7 +306,7 @@ ResultCode KPageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std:
KMemoryState state{};
KMemoryPermission perm{};
CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, src_addr, size, KMemoryState::All,
KMemoryState::Normal, KMemoryPermission::Mask,
KMemoryState::Normal, KMemoryPermission::All,
KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask,
KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
@@ -465,7 +465,7 @@ ResultCode KPageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
MapPhysicalMemory(page_linked_list, addr, end_addr);
physical_memory_usage += remaining_size;
mapped_physical_memory_size += remaining_size;
const std::size_t num_pages{size / PageSize};
block_manager->Update(addr, num_pages, KMemoryState::Free, KMemoryPermission::None,
@@ -507,7 +507,7 @@ ResultCode KPageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) {
auto process{system.Kernel().CurrentProcess()};
process->GetResourceLimit()->Release(LimitableResource::PhysicalMemory, mapped_size);
physical_memory_usage -= mapped_size;
mapped_physical_memory_size -= mapped_size;
return ResultSuccess;
}
@@ -554,7 +554,7 @@ ResultCode KPageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) {
KMemoryState src_state{};
CASCADE_CODE(CheckMemoryState(
&src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias,
KMemoryState::FlagCanAlias, KMemoryPermission::Mask, KMemoryPermission::ReadAndWrite,
KMemoryState::FlagCanAlias, KMemoryPermission::All, KMemoryPermission::ReadAndWrite,
KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
if (IsRegionMapped(dst_addr, size)) {
@@ -593,7 +593,7 @@ ResultCode KPageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) {
KMemoryState src_state{};
CASCADE_CODE(CheckMemoryState(
&src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias,
KMemoryState::FlagCanAlias, KMemoryPermission::Mask, KMemoryPermission::None,
KMemoryState::FlagCanAlias, KMemoryPermission::All, KMemoryPermission::None,
KMemoryAttribute::Mask, KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped));
KMemoryPermission dst_perm{};
@@ -784,7 +784,7 @@ ResultCode KPageTable::ReserveTransferMemory(VAddr addr, std::size_t size, KMemo
CASCADE_CODE(CheckMemoryState(
&state, nullptr, &attribute, addr, size,
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, KMemoryPermission::Mask,
KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, KMemoryPermission::All,
KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, KMemoryAttribute::None,
KMemoryAttribute::IpcAndDeviceMapped));
@@ -806,6 +806,33 @@ ResultCode KPageTable::ResetTransferMemory(VAddr addr, std::size_t size) {
KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped));
block_manager->Update(addr, size / PageSize, state, KMemoryPermission::ReadAndWrite);
return ResultSuccess;
}
ResultCode KPageTable::SetMemoryPermission(VAddr addr, std::size_t size,
Svc::MemoryPermission svc_perm) {
const size_t num_pages = size / PageSize;
// Lock the table.
std::lock_guard lock{page_table_lock};
// Verify we can change the memory permission.
KMemoryState old_state;
KMemoryPermission old_perm;
R_TRY(this->CheckMemoryState(
std::addressof(old_state), std::addressof(old_perm), nullptr, addr, size,
KMemoryState::FlagCanReprotect, KMemoryState::FlagCanReprotect, KMemoryPermission::None,
KMemoryPermission::None, KMemoryAttribute::All, KMemoryAttribute::None));
// Determine new perm.
const KMemoryPermission new_perm = ConvertToKMemoryPermission(svc_perm);
R_SUCCEED_IF(old_perm == new_perm);
// Perform mapping operation.
R_TRY(Operate(addr, num_pages, new_perm, OperationType::ChangePermissions));
// Update the blocks.
block_manager->Update(addr, num_pages, old_state, new_perm, KMemoryAttribute::None);
return ResultSuccess;
}
@@ -832,61 +859,125 @@ ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryA
return ResultSuccess;
}
ResultCode KPageTable::SetHeapCapacity(std::size_t new_heap_capacity) {
ResultCode KPageTable::SetMaxHeapSize(std::size_t size) {
// Lock the table.
std::lock_guard lock{page_table_lock};
heap_capacity = new_heap_capacity;
// Only process page tables are allowed to set heap size.
ASSERT(!this->IsKernel());
max_heap_size = size;
return ResultSuccess;
}
ResultVal<VAddr> KPageTable::SetHeapSize(std::size_t size) {
ResultCode KPageTable::SetHeapSize(VAddr* out, std::size_t size) {
// Try to perform a reduction in heap, instead of an extension.
VAddr cur_address{};
std::size_t allocation_size{};
{
// Lock the table.
std::lock_guard lk(page_table_lock);
if (size > heap_region_end - heap_region_start) {
return ResultOutOfMemory;
// Validate that setting heap size is possible at all.
R_UNLESS(!is_kernel, ResultOutOfMemory);
R_UNLESS(size <= static_cast<std::size_t>(heap_region_end - heap_region_start),
ResultOutOfMemory);
R_UNLESS(size <= max_heap_size, ResultOutOfMemory);
if (size < GetHeapSize()) {
// The size being requested is less than the current size, so we need to free the end of
// the heap.
// Validate memory state.
std::size_t num_allocator_blocks;
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks),
heap_region_start + size, GetHeapSize() - size,
KMemoryState::All, KMemoryState::Normal,
KMemoryPermission::All, KMemoryPermission::ReadAndWrite,
KMemoryAttribute::All, KMemoryAttribute::None));
// Unmap the end of the heap.
const auto num_pages = (GetHeapSize() - size) / PageSize;
R_TRY(Operate(heap_region_start + size, num_pages, KMemoryPermission::None,
OperationType::Unmap));
// Release the memory from the resource limit.
system.Kernel().CurrentProcess()->GetResourceLimit()->Release(
LimitableResource::PhysicalMemory, num_pages * PageSize);
// Apply the memory block update.
block_manager->Update(heap_region_start + size, num_pages, KMemoryState::Free,
KMemoryPermission::None, KMemoryAttribute::None);
// Update the current heap end.
current_heap_end = heap_region_start + size;
// Set the output.
*out = heap_region_start;
return ResultSuccess;
} else if (size == GetHeapSize()) {
// The size requested is exactly the current size.
*out = heap_region_start;
return ResultSuccess;
} else {
// We have to allocate memory. Determine how much to allocate and where while the table
// is locked.
cur_address = current_heap_end;
allocation_size = size - GetHeapSize();
}
}
const u64 previous_heap_size{GetHeapSize()};
// Reserve memory for the heap extension.
KScopedResourceReservation memory_reservation(
system.Kernel().CurrentProcess()->GetResourceLimit(), LimitableResource::PhysicalMemory,
allocation_size);
R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
UNIMPLEMENTED_IF_MSG(previous_heap_size > size, "Heap shrink is unimplemented");
// Allocate pages for the heap extension.
KPageLinkedList page_linked_list;
R_TRY(system.Kernel().MemoryManager().Allocate(page_linked_list, allocation_size / PageSize,
memory_pool));
// Increase the heap size
// Map the pages.
{
std::lock_guard lock{page_table_lock};
// Lock the table.
std::lock_guard lk(page_table_lock);
const u64 delta{size - previous_heap_size};
// Ensure that the heap hasn't changed since we began executing.
ASSERT(cur_address == current_heap_end);
// Reserve memory for the heap extension.
KScopedResourceReservation memory_reservation(
system.Kernel().CurrentProcess()->GetResourceLimit(), LimitableResource::PhysicalMemory,
delta);
// Check the memory state.
std::size_t num_allocator_blocks{};
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), current_heap_end,
allocation_size, KMemoryState::All, KMemoryState::Free,
KMemoryPermission::None, KMemoryPermission::None,
KMemoryAttribute::None, KMemoryAttribute::None));
if (!memory_reservation.Succeeded()) {
LOG_ERROR(Kernel, "Could not reserve heap extension of size {:X} bytes", delta);
return ResultLimitReached;
// Map the pages.
const auto num_pages = allocation_size / PageSize;
R_TRY(Operate(current_heap_end, num_pages, page_linked_list, OperationType::MapGroup));
// Clear all the newly allocated pages.
for (std::size_t cur_page = 0; cur_page < num_pages; ++cur_page) {
std::memset(system.Memory().GetPointer(current_heap_end + (cur_page * PageSize)), 0,
PageSize);
}
KPageLinkedList page_linked_list;
const std::size_t num_pages{delta / PageSize};
CASCADE_CODE(
system.Kernel().MemoryManager().Allocate(page_linked_list, num_pages, memory_pool));
if (IsRegionMapped(current_heap_addr, delta)) {
return ResultInvalidCurrentMemory;
}
CASCADE_CODE(
Operate(current_heap_addr, num_pages, page_linked_list, OperationType::MapGroup));
// Succeeded in allocation, commit the resource reservation
// We succeeded, so commit our memory reservation.
memory_reservation.Commit();
block_manager->Update(current_heap_addr, num_pages, KMemoryState::Normal,
KMemoryPermission::ReadAndWrite);
// Apply the memory block update.
block_manager->Update(current_heap_end, num_pages, KMemoryState::Normal,
KMemoryPermission::ReadAndWrite, KMemoryAttribute::None);
current_heap_addr = heap_region_start + size;
// Update the current heap end.
current_heap_end = heap_region_start + size;
// Set the output.
*out = heap_region_start;
return ResultSuccess;
}
return heap_region_start;
}
ResultVal<VAddr> KPageTable::AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align,
@@ -978,7 +1069,7 @@ ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) {
if (const ResultCode result{CheckMemoryState(
nullptr, &old_perm, nullptr, addr, size, KMemoryState::FlagCanCodeMemory,
KMemoryState::FlagCanCodeMemory, KMemoryPermission::Mask,
KMemoryState::FlagCanCodeMemory, KMemoryPermission::All,
KMemoryPermission::UserReadWrite, KMemoryAttribute::All, KMemoryAttribute::None)};
result.IsError()) {
return result;
@@ -1031,9 +1122,8 @@ ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) {
bool KPageTable::IsRegionMapped(VAddr address, u64 size) {
return CheckMemoryState(address, size, KMemoryState::All, KMemoryState::Free,
KMemoryPermission::Mask, KMemoryPermission::None,
KMemoryAttribute::Mask, KMemoryAttribute::None,
KMemoryAttribute::IpcAndDeviceMapped)
KMemoryPermission::All, KMemoryPermission::None, KMemoryAttribute::Mask,
KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)
.IsError();
}

View File

@@ -47,10 +47,11 @@ public:
KMemoryInfo QueryInfo(VAddr addr);
ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm);
ResultCode ResetTransferMemory(VAddr addr, std::size_t size);
ResultCode SetMemoryPermission(VAddr addr, std::size_t size, Svc::MemoryPermission perm);
ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask,
KMemoryAttribute value);
ResultCode SetHeapCapacity(std::size_t new_heap_capacity);
ResultVal<VAddr> SetHeapSize(std::size_t size);
ResultCode SetMaxHeapSize(std::size_t size);
ResultCode SetHeapSize(VAddr* out, std::size_t size);
ResultVal<VAddr> AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align,
bool is_map_only, VAddr region_start,
std::size_t region_num_pages, KMemoryState state,
@@ -182,14 +183,15 @@ public:
constexpr VAddr GetAliasCodeRegionSize() const {
return alias_code_region_end - alias_code_region_start;
}
size_t GetNormalMemorySize() {
std::lock_guard lk(page_table_lock);
return GetHeapSize() + mapped_physical_memory_size;
}
constexpr std::size_t GetAddressSpaceWidth() const {
return address_space_width;
}
constexpr std::size_t GetHeapSize() {
return current_heap_addr - heap_region_start;
}
constexpr std::size_t GetTotalHeapSize() {
return GetHeapSize() + physical_memory_usage;
constexpr std::size_t GetHeapSize() const {
return current_heap_end - heap_region_start;
}
constexpr bool IsInsideAddressSpace(VAddr address, std::size_t size) const {
return address_space_start <= address && address + size - 1 <= address_space_end - 1;
@@ -269,10 +271,8 @@ private:
VAddr code_region_end{};
VAddr alias_code_region_start{};
VAddr alias_code_region_end{};
VAddr current_heap_addr{};
std::size_t heap_capacity{};
std::size_t physical_memory_usage{};
std::size_t mapped_physical_memory_size{};
std::size_t max_heap_size{};
std::size_t max_physical_memory_size{};
std::size_t address_space_width{};

View File

@@ -28,7 +28,6 @@
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/svc_results.h"
#include "core/hle/lock.h"
#include "core/memory.h"
namespace Kernel {
@@ -173,7 +172,7 @@ void KProcess::DecrementThreadCount() {
u64 KProcess::GetTotalPhysicalMemoryAvailable() const {
const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) +
page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size +
page_table->GetNormalMemorySize() + GetSystemResourceSize() + image_size +
main_thread_stack_size};
if (const auto pool_size = kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application);
capacity != pool_size) {
@@ -190,7 +189,7 @@ u64 KProcess::GetTotalPhysicalMemoryAvailableWithoutSystemResource() const {
}
u64 KProcess::GetTotalPhysicalMemoryUsed() const {
return image_size + main_thread_stack_size + page_table->GetTotalHeapSize() +
return image_size + main_thread_stack_size + page_table->GetNormalMemorySize() +
GetSystemResourceSize();
}
@@ -411,8 +410,8 @@ void KProcess::Run(s32 main_thread_priority, u64 stack_size) {
resource_limit->Reserve(LimitableResource::Threads, 1);
resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size);
const std::size_t heap_capacity{memory_usage_capacity - main_thread_stack_size - image_size};
ASSERT(!page_table->SetHeapCapacity(heap_capacity).IsError());
const std::size_t heap_capacity{memory_usage_capacity - (main_thread_stack_size + image_size)};
ASSERT(!page_table->SetMaxHeapSize(heap_capacity).IsError());
ChangeStatus(ProcessStatus::Running);
@@ -543,7 +542,6 @@ void KProcess::FreeTLSRegion(VAddr tls_address) {
}
void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) {
std::lock_guard lock{HLE::g_hle_lock};
const auto ReprotectSegment = [&](const CodeSet::Segment& segment,
KMemoryPermission permission) {
page_table->SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission);

View File

@@ -26,6 +26,7 @@
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
#include "core/hle/kernel/k_system_control.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_thread_queue.h"
#include "core/hle/kernel/kernel.h"
@@ -50,6 +51,7 @@ static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context,
VAddr entry_point, u64 arg) {
context = {};
context.cpu_registers[0] = arg;
context.cpu_registers[18] = Kernel::KSystemControl::GenerateRandomU64() | 1;
context.pc = entry_point;
context.sp = stack_top;
// TODO(merry): Perform a hardware test to determine the below value.

View File

@@ -182,7 +182,10 @@ struct KernelCore::Impl {
// Shutdown all processes.
if (current_process) {
current_process->Finalize();
current_process->Close();
// current_process->Close();
// TODO: The current process should be destroyed based on accurate ref counting after
// calling Close(). Adding a manual Destroy() call instead to avoid a memory leak.
current_process->Destroy();
current_process = nullptr;
}

View File

@@ -41,7 +41,6 @@
#include "core/hle/kernel/svc_results.h"
#include "core/hle/kernel/svc_types.h"
#include "core/hle/kernel/svc_wrap.h"
#include "core/hle/lock.h"
#include "core/hle/result.h"
#include "core/memory.h"
#include "core/reporter.h"
@@ -136,25 +135,15 @@ enum class ResourceLimitValueType {
} // Anonymous namespace
/// Set the process heap to a given Size. It can both extend and shrink the heap.
static ResultCode SetHeapSize(Core::System& system, VAddr* heap_addr, u64 heap_size) {
std::lock_guard lock{HLE::g_hle_lock};
LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size);
static ResultCode SetHeapSize(Core::System& system, VAddr* out_address, u64 size) {
LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", size);
// Size must be a multiple of 0x200000 (2MB) and be equal to or less than 8GB.
if ((heap_size % 0x200000) != 0) {
LOG_ERROR(Kernel_SVC, "The heap size is not a multiple of 2MB, heap_size=0x{:016X}",
heap_size);
return ResultInvalidSize;
}
// Validate size.
R_UNLESS(Common::IsAligned(size, HeapSizeAlignment), ResultInvalidSize);
R_UNLESS(size < MainMemorySizeMax, ResultInvalidSize);
if (heap_size >= 0x200000000) {
LOG_ERROR(Kernel_SVC, "The heap size is not less than 8GB, heap_size=0x{:016X}", heap_size);
return ResultInvalidSize;
}
auto& page_table{system.Kernel().CurrentProcess()->PageTable()};
CASCADE_RESULT(*heap_addr, page_table.SetHeapSize(heap_size));
// Set the heap size.
R_TRY(system.Kernel().CurrentProcess()->PageTable().SetHeapSize(out_address, size));
return ResultSuccess;
}
@@ -166,9 +155,38 @@ static ResultCode SetHeapSize32(Core::System& system, u32* heap_addr, u32 heap_s
return result;
}
constexpr bool IsValidSetMemoryPermission(MemoryPermission perm) {
switch (perm) {
case MemoryPermission::None:
case MemoryPermission::Read:
case MemoryPermission::ReadWrite:
return true;
default:
return false;
}
}
static ResultCode SetMemoryPermission(Core::System& system, VAddr address, u64 size,
MemoryPermission perm) {
// 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);
// Validate the permission.
R_UNLESS(IsValidSetMemoryPermission(perm), ResultInvalidNewMemoryPermission);
// Validate that the region is in range for the current process.
auto& page_table = system.Kernel().CurrentProcess()->PageTable();
R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
// Set the memory attribute.
return page_table.SetMemoryPermission(address, size, perm);
}
static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 size, u32 mask,
u32 attribute) {
std::lock_guard lock{HLE::g_hle_lock};
LOG_DEBUG(Kernel_SVC,
"called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address,
size, mask, attribute);
@@ -212,7 +230,6 @@ static ResultCode SetMemoryAttribute32(Core::System& system, u32 address, u32 si
/// Maps a memory range into a different range.
static ResultCode MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) {
std::lock_guard lock{HLE::g_hle_lock};
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
src_addr, size);
@@ -232,7 +249,6 @@ static ResultCode MapMemory32(Core::System& system, u32 dst_addr, u32 src_addr,
/// Unmaps a region that was previously mapped with svcMapMemory
static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) {
std::lock_guard lock{HLE::g_hle_lock};
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
src_addr, size);
@@ -642,7 +658,6 @@ static void OutputDebugString(Core::System& system, VAddr address, u64 len) {
/// Gets system/memory information for the current process
static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle handle,
u64 info_sub_id) {
std::lock_guard lock{HLE::g_hle_lock};
LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id,
info_sub_id, handle);
@@ -886,22 +901,17 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle
return ResultSuccess;
}
case GetInfoType::IdleTickCount: {
if (handle == 0) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}",
static_cast<Handle>(handle));
return ResultInvalidHandle;
}
// Verify the input handle is invalid.
R_UNLESS(handle == InvalidHandle, ResultInvalidHandle);
if (info_sub_id != 0xFFFFFFFFFFFFFFFF &&
info_sub_id != system.Kernel().CurrentPhysicalCoreIndex()) {
LOG_ERROR(Kernel_SVC, "Core is not the current core, got {}", info_sub_id);
return ResultInvalidCombination;
}
// Verify the requested core is valid.
const bool core_valid =
(info_sub_id == static_cast<u64>(-1ULL)) ||
(info_sub_id == static_cast<u64>(system.Kernel().CurrentPhysicalCoreIndex()));
R_UNLESS(core_valid, ResultInvalidCombination);
const auto& scheduler = *system.Kernel().CurrentScheduler();
const auto* const idle_thread = scheduler.GetIdleThread();
*result = idle_thread->GetCpuTime();
// Get the idle tick count.
*result = system.Kernel().CurrentScheduler()->GetIdleThread()->GetCpuTime();
return ResultSuccess;
}
default:
@@ -924,7 +934,6 @@ static ResultCode GetInfo32(Core::System& system, u32* result_low, u32* result_h
/// Maps memory at a desired address
static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) {
std::lock_guard lock{HLE::g_hle_lock};
LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size);
if (!Common::Is4KBAligned(addr)) {
@@ -978,7 +987,6 @@ static ResultCode MapPhysicalMemory32(Core::System& system, u32 addr, u32 size)
/// Unmaps memory previously mapped via MapPhysicalMemory
static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size) {
std::lock_guard lock{HLE::g_hle_lock};
LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size);
if (!Common::Is4KBAligned(addr)) {
@@ -1520,7 +1528,6 @@ static ResultCode ControlCodeMemory(Core::System& system, Handle code_memory_han
static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address,
VAddr page_info_address, Handle process_handle,
VAddr address) {
std::lock_guard lock{HLE::g_hle_lock};
LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address);
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
@@ -2738,7 +2745,7 @@ static const FunctionDef SVC_Table_32[] = {
static const FunctionDef SVC_Table_64[] = {
{0x00, nullptr, "Unknown"},
{0x01, SvcWrap64<SetHeapSize>, "SetHeapSize"},
{0x02, nullptr, "SetMemoryPermission"},
{0x02, SvcWrap64<SetMemoryPermission>, "SetMemoryPermission"},
{0x03, SvcWrap64<SetMemoryAttribute>, "SetMemoryAttribute"},
{0x04, SvcWrap64<MapMemory>, "MapMemory"},
{0x05, SvcWrap64<UnmapMemory>, "UnmapMemory"},

View File

@@ -5,6 +5,7 @@
#pragma once
#include "common/common_types.h"
#include "common/literals.h"
namespace Kernel {
using Handle = u32;
@@ -12,9 +13,13 @@ using Handle = u32;
namespace Kernel::Svc {
using namespace Common::Literals;
constexpr s32 ArgumentHandleCountMax = 0x40;
constexpr u32 HandleWaitMask{1u << 30};
constexpr inline std::size_t HeapSizeAlignment = 2_MiB;
constexpr inline Handle InvalidHandle = Handle(0);
enum PseudoHandle : Handle {

View File

@@ -249,6 +249,14 @@ void SvcWrap64(Core::System& system) {
func(system, Param(system, 0), Param(system, 1), static_cast<u32>(Param(system, 2))).raw);
}
// Used by SetMemoryPermission
template <ResultCode func(Core::System&, u64, u64, Svc::MemoryPermission)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
static_cast<Svc::MemoryPermission>(Param(system, 2)))
.raw);
}
// Used by MapSharedMemory
template <ResultCode func(Core::System&, Handle, u64, u64, Svc::MemoryPermission)>
void SvcWrap64(Core::System& system) {

View File

@@ -1,9 +0,0 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <core/hle/lock.h>
namespace HLE {
std::recursive_mutex g_hle_lock;
}

View File

@@ -1,18 +0,0 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <mutex>
namespace HLE {
/*
* Synchronizes access to the internal HLE kernel structures, it is acquired when a guest
* application thread performs a syscall. It should be acquired by any host threads that read or
* modify the HLE kernel state. Note: Any operation that directly or indirectly reads from or writes
* to the emulated memory is not protected by this mutex, and should be avoided in any threads other
* than the CPU thread.
*/
extern std::recursive_mutex g_hle_lock;
} // namespace HLE

View File

@@ -6,7 +6,6 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/lock.h"
#include "core/hle/service/bcat/backend/backend.h"
namespace Service::BCAT {
@@ -29,10 +28,6 @@ DeliveryCacheProgressImpl& ProgressServiceBackend::GetImpl() {
return impl;
}
void ProgressServiceBackend::SetNeedHLELock(bool need) {
need_hle_lock = need;
}
void ProgressServiceBackend::SetTotalSize(u64 size) {
impl.total_bytes = size;
SignalUpdate();
@@ -88,12 +83,7 @@ void ProgressServiceBackend::FinishDownload(ResultCode result) {
}
void ProgressServiceBackend::SignalUpdate() {
if (need_hle_lock) {
std::lock_guard lock(HLE::g_hle_lock);
update_event->GetWritableEvent().Signal();
} else {
update_event->GetWritableEvent().Signal();
}
update_event->GetWritableEvent().Signal();
}
Backend::Backend(DirectoryGetter getter) : dir_getter(std::move(getter)) {}

View File

@@ -71,10 +71,6 @@ class ProgressServiceBackend {
public:
~ProgressServiceBackend();
// Clients should call this with true if any of the functions are going to be called from a
// non-HLE thread and this class need to lock the hle mutex. (default is false)
void SetNeedHLELock(bool need);
// Sets the number of bytes total in the entire download.
void SetTotalSize(u64 size);
@@ -109,7 +105,6 @@ private:
DeliveryCacheProgressImpl impl{};
Kernel::KEvent* update_event;
bool need_hle_lock = false;
};
// A class representing an abstract backend for BCAT functionality.

View File

@@ -33,15 +33,14 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti
const auto& last_entry = seven_sixaxis_lifo.ReadCurrentEntry().state;
next_seven_sixaxis_state.sampling_number = last_entry.sampling_number + 1;
// Try to read sixaxis sensor states
const auto motion_status = console->GetMotion();
last_global_timestamp = core_timing.GetGlobalTimeNs().count();
console_six_axis.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest;
// This value increments every time the switch goes to sleep
next_seven_sixaxis_state.unknown = 1;
next_seven_sixaxis_state.timestamp = last_global_timestamp - last_saved_timestamp;
next_seven_sixaxis_state.accel = motion_status.accel;
// Zero gyro values as they just mess up with the camera
// Note: Probably a correct sensivity setting must be set
next_seven_sixaxis_state.gyro = {};
next_seven_sixaxis_state.gyro = motion_status.gyro;
next_seven_sixaxis_state.quaternion = {
{
motion_status.quaternion.xyz.y,
@@ -52,9 +51,9 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti
};
console_six_axis.sampling_number++;
// TODO(German77): Find the purpose of those values
console_six_axis.verticalization_error = 0.0f;
console_six_axis.gyro_bias = {0.0f, 0.0f, 0.0f};
console_six_axis.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest;
console_six_axis.verticalization_error = motion_status.verticalization_error;
console_six_axis.gyro_bias = motion_status.gyro_bias;
// Update console six axis shared memory
std::memcpy(data + SHARED_MEMORY_OFFSET, &console_six_axis, sizeof(console_six_axis));
@@ -69,7 +68,6 @@ void Controller_ConsoleSixAxis::SetTransferMemoryPointer(u8* t_mem) {
}
void Controller_ConsoleSixAxis::ResetTimestamp() {
seven_sixaxis_lifo.buffer_count = 0;
seven_sixaxis_lifo.buffer_tail = 0;
last_saved_timestamp = last_global_timestamp;
}
} // namespace Service::HID

View File

@@ -39,8 +39,9 @@ public:
private:
struct SevenSixAxisState {
INSERT_PADDING_WORDS(4); // unused
s64 sampling_number{};
INSERT_PADDING_WORDS(2); // unused
u64 timestamp{};
u64 sampling_number{};
u64 unknown{};
Common::Vec3f accel{};
Common::Vec3f gyro{};
@@ -52,9 +53,10 @@ private:
struct ConsoleSharedMemory {
u64 sampling_number{};
bool is_seven_six_axis_sensor_at_rest{};
INSERT_PADDING_BYTES(4); // padding
INSERT_PADDING_BYTES(3); // padding
f32 verticalization_error{};
Common::Vec3f gyro_bias{};
INSERT_PADDING_BYTES(4); // padding
};
static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size");
@@ -64,6 +66,8 @@ private:
Core::HID::EmulatedConsole* console;
u8* transfer_memory = nullptr;
bool is_transfer_memory_set = false;
u64 last_saved_timestamp{};
u64 last_global_timestamp{};
ConsoleSharedMemory console_six_axis{};
SevenSixAxisState next_seven_sixaxis_state{};
};

View File

@@ -9,7 +9,6 @@
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/lock.h"
#include "core/hle/service/nfp/nfp.h"
#include "core/hle/service/nfp/nfp_user.h"
@@ -337,7 +336,6 @@ void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
}
bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
std::lock_guard lock{HLE::g_hle_lock};
if (buffer.size() < sizeof(AmiiboFile)) {
return false;
}

View File

@@ -86,7 +86,7 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, Scal
}
switch (attr) {
case IR::Attribute::PrimitiveId:
ctx.Add("MOV.S {}.x,primitive.id;", inst);
ctx.Add("MOV.F {}.x,primitive.id;", inst);
break;
case IR::Attribute::PositionX:
case IR::Attribute::PositionY:
@@ -113,13 +113,13 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, Scal
ctx.Add("MOV.F {}.x,vertex.tesscoord.{};", inst, swizzle);
break;
case IR::Attribute::InstanceId:
ctx.Add("MOV.S {}.x,{}.instance;", inst, ctx.attrib_name);
ctx.Add("MOV.F {}.x,{}.instance;", inst, ctx.attrib_name);
break;
case IR::Attribute::VertexId:
ctx.Add("MOV.S {}.x,{}.id;", inst, ctx.attrib_name);
ctx.Add("MOV.F {}.x,{}.id;", inst, ctx.attrib_name);
break;
case IR::Attribute::FrontFace:
ctx.Add("CMP.S {}.x,{}.facing.x,0,-1;", inst, ctx.attrib_name);
ctx.Add("CMP.F {}.x,{}.facing.x,0,-1;", inst, ctx.attrib_name);
break;
default:
throw NotImplementedException("Get attribute {}", attr);

View File

@@ -176,7 +176,7 @@ void EmitCode(EmitContext& ctx, const IR::Program& program) {
}
std::string GlslVersionSpecifier(const EmitContext& ctx) {
if (ctx.uses_y_direction || ctx.info.stores.Legacy() || ctx.info.loads.Legacy()) {
if (ctx.uses_y_direction) {
return " compatibility";
}
return "";

View File

@@ -98,10 +98,6 @@ void GetCbuf16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, const
GetCbuf(ctx, ret, binding, offset, 16, cast, bit_offset);
}
}
u32 TexCoordIndex(IR::Attribute attr) {
return (static_cast<u32>(attr) - static_cast<u32>(IR::Attribute::FixedFncTexture0S)) / 4;
}
} // Anonymous namespace
void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
@@ -190,18 +186,6 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr,
ctx.AddF32("{}=in_attr{}{}.{};", inst, index, InputVertexIndex(ctx, vertex), swizzle);
return;
}
// GLSL only exposes 8 legacy texcoords
if (attr >= IR::Attribute::FixedFncTexture8S && attr <= IR::Attribute::FixedFncTexture9Q) {
LOG_WARNING(Shader_GLSL, "GLSL does not allow access to gl_TexCoord[{}]",
TexCoordIndex(attr));
ctx.AddF32("{}=0.f;", inst);
return;
}
if (attr >= IR::Attribute::FixedFncTexture0S && attr <= IR::Attribute::FixedFncTexture7Q) {
const u32 index{TexCoordIndex(attr)};
ctx.AddF32("{}=gl_TexCoord[{}].{};", inst, index, swizzle);
return;
}
switch (attr) {
case IR::Attribute::PrimitiveId:
ctx.AddF32("{}=itof(gl_PrimitiveID);", inst);
@@ -215,16 +199,6 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr,
ctx.AddF32("{}={}{}.{};", inst, input_decorator, ctx.position_name, swizzle);
break;
}
case IR::Attribute::ColorFrontDiffuseR:
case IR::Attribute::ColorFrontDiffuseG:
case IR::Attribute::ColorFrontDiffuseB:
case IR::Attribute::ColorFrontDiffuseA:
if (ctx.stage == Stage::Fragment) {
ctx.AddF32("{}=gl_Color.{};", inst, swizzle);
} else {
ctx.AddF32("{}=gl_FrontColor.{};", inst, swizzle);
}
break;
case IR::Attribute::PointSpriteS:
case IR::Attribute::PointSpriteT:
ctx.AddF32("{}=gl_PointCoord.{};", inst, swizzle);
@@ -264,17 +238,6 @@ void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view val
}
const u32 element{static_cast<u32>(attr) % 4};
const char swizzle{"xyzw"[element]};
// GLSL only exposes 8 legacy texcoords
if (attr >= IR::Attribute::FixedFncTexture8S && attr <= IR::Attribute::FixedFncTexture9Q) {
LOG_WARNING(Shader_GLSL, "GLSL does not allow access to gl_TexCoord[{}]",
TexCoordIndex(attr));
return;
}
if (attr >= IR::Attribute::FixedFncTexture0S && attr <= IR::Attribute::FixedFncTexture7Q) {
const u32 index{TexCoordIndex(attr)};
ctx.Add("gl_TexCoord[{}].{}={};", index, swizzle, value);
return;
}
switch (attr) {
case IR::Attribute::Layer:
if (ctx.stage != Stage::Geometry &&
@@ -312,33 +275,6 @@ void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view val
case IR::Attribute::PositionW:
ctx.Add("gl_Position.{}={};", swizzle, value);
break;
case IR::Attribute::ColorFrontDiffuseR:
case IR::Attribute::ColorFrontDiffuseG:
case IR::Attribute::ColorFrontDiffuseB:
case IR::Attribute::ColorFrontDiffuseA:
ctx.Add("gl_FrontColor.{}={};", swizzle, value);
break;
case IR::Attribute::ColorFrontSpecularR:
case IR::Attribute::ColorFrontSpecularG:
case IR::Attribute::ColorFrontSpecularB:
case IR::Attribute::ColorFrontSpecularA:
ctx.Add("gl_FrontSecondaryColor.{}={};", swizzle, value);
break;
case IR::Attribute::ColorBackDiffuseR:
case IR::Attribute::ColorBackDiffuseG:
case IR::Attribute::ColorBackDiffuseB:
case IR::Attribute::ColorBackDiffuseA:
ctx.Add("gl_BackColor.{}={};", swizzle, value);
break;
case IR::Attribute::ColorBackSpecularR:
case IR::Attribute::ColorBackSpecularG:
case IR::Attribute::ColorBackSpecularB:
case IR::Attribute::ColorBackSpecularA:
ctx.Add("gl_BackSecondaryColor.{}={};", swizzle, value);
break;
case IR::Attribute::FogCoordinate:
ctx.Add("gl_FogFragCoord={};", value);
break;
case IR::Attribute::ClipDistance0:
case IR::Attribute::ClipDistance1:
case IR::Attribute::ClipDistance2:

View File

@@ -211,27 +211,6 @@ std::string_view OutputPrimitive(OutputTopology topology) {
throw InvalidArgument("Invalid output topology {}", topology);
}
void SetupLegacyOutPerVertex(EmitContext& ctx, std::string& header) {
if (!ctx.info.stores.Legacy()) {
return;
}
if (ctx.info.stores.FixedFunctionTexture()) {
header += "vec4 gl_TexCoord[8];";
}
if (ctx.info.stores.AnyComponent(IR::Attribute::ColorFrontDiffuseR)) {
header += "vec4 gl_FrontColor;";
}
if (ctx.info.stores.AnyComponent(IR::Attribute::ColorFrontSpecularR)) {
header += "vec4 gl_FrontSecondaryColor;";
}
if (ctx.info.stores.AnyComponent(IR::Attribute::ColorBackDiffuseR)) {
header += "vec4 gl_BackColor;";
}
if (ctx.info.stores.AnyComponent(IR::Attribute::ColorBackSpecularR)) {
header += "vec4 gl_BackSecondaryColor;";
}
}
void SetupOutPerVertex(EmitContext& ctx, std::string& header) {
if (!StoresPerVertexAttributes(ctx.stage)) {
return;
@@ -250,7 +229,6 @@ void SetupOutPerVertex(EmitContext& ctx, std::string& header) {
ctx.profile.support_viewport_index_layer_non_geometry && ctx.stage != Stage::Geometry) {
header += "int gl_ViewportIndex;";
}
SetupLegacyOutPerVertex(ctx, header);
header += "};";
if (ctx.info.stores[IR::Attribute::ViewportIndex] && ctx.stage == Stage::Geometry) {
header += "out int gl_ViewportIndex;";
@@ -282,21 +260,6 @@ void SetupInPerVertex(EmitContext& ctx, std::string& header) {
}
header += "}gl_in[gl_MaxPatchVertices];";
}
void SetupLegacyInPerFragment(EmitContext& ctx, std::string& header) {
if (!ctx.info.loads.Legacy()) {
return;
}
header += "in gl_PerFragment{";
if (ctx.info.loads.FixedFunctionTexture()) {
header += "vec4 gl_TexCoord[8];";
}
if (ctx.info.loads.AnyComponent(IR::Attribute::ColorFrontDiffuseR)) {
header += "vec4 gl_Color;";
}
header += "};";
}
} // Anonymous namespace
EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_,
@@ -361,7 +324,6 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile
}
SetupOutPerVertex(*this, header);
SetupInPerVertex(*this, header);
SetupLegacyInPerFragment(*this, header);
for (size_t index = 0; index < IR::NUM_GENERICS; ++index) {
if (!info.loads.Generic(index) || !runtime_info.previous_stage_stores.Generic(index)) {

View File

@@ -30,11 +30,20 @@ struct FuncTraits<ReturnType_ (*)(Args...)> {
using ArgType = std::tuple_element_t<I, std::tuple<Args...>>;
};
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4702) // Ignore unreachable code warning
#endif
template <auto func, typename... Args>
void SetDefinition(EmitContext& ctx, IR::Inst* inst, Args... args) {
inst->SetDefinition<Id>(func(ctx, std::forward<Args>(args)...));
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif
template <typename ArgType>
ArgType Arg(EmitContext& ctx, const IR::Value& arg) {
if constexpr (std::is_same_v<ArgType, Id>) {

View File

@@ -44,14 +44,6 @@ Id AttrPointer(EmitContext& ctx, Id pointer_type, Id vertex, Id base, Args&&...
}
}
bool IsLegacyAttribute(IR::Attribute attribute) {
return (attribute >= IR::Attribute::ColorFrontDiffuseR &&
attribute <= IR::Attribute::ColorBackSpecularA) ||
attribute == IR::Attribute::FogCoordinate ||
(attribute >= IR::Attribute::FixedFncTexture0S &&
attribute <= IR::Attribute::FixedFncTexture9Q);
}
template <typename... Args>
Id OutputAccessChain(EmitContext& ctx, Id result_type, Id base, Args&&... args) {
if (ctx.stage == Stage::TessellationControl) {
@@ -83,17 +75,6 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
return OutputAccessChain(ctx, ctx.output_f32, info.id, index_id);
}
}
if (IsLegacyAttribute(attr)) {
if (attr == IR::Attribute::FogCoordinate) {
return OutputAccessChain(ctx, ctx.output_f32, ctx.OutputLegacyAttribute(attr),
ctx.Const(0u));
} else {
const u32 element{static_cast<u32>(attr) % 4};
const Id element_id{ctx.Const(element)};
return OutputAccessChain(ctx, ctx.output_f32, ctx.OutputLegacyAttribute(attr),
element_id);
}
}
switch (attr) {
case IR::Attribute::PointSize:
return ctx.output_point_size;
@@ -327,18 +308,6 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
const Id value{ctx.OpLoad(type->id, pointer)};
return type->needs_cast ? ctx.OpBitcast(ctx.F32[1], value) : value;
}
if (IsLegacyAttribute(attr)) {
if (attr == IR::Attribute::FogCoordinate) {
const Id attr_ptr{AttrPointer(ctx, ctx.input_f32, vertex,
ctx.InputLegacyAttribute(attr), ctx.Const(0u))};
return ctx.OpLoad(ctx.F32[1], attr_ptr);
} else {
const Id element_id{ctx.Const(element)};
const Id attr_ptr{AttrPointer(ctx, ctx.input_f32, vertex,
ctx.InputLegacyAttribute(attr), element_id)};
return ctx.OpLoad(ctx.F32[1], attr_ptr);
}
}
switch (attr) {
case IR::Attribute::PrimitiveId:
return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.primitive_id));

View File

@@ -18,8 +18,6 @@
namespace Shader::Backend::SPIRV {
namespace {
constexpr size_t NUM_FIXEDFNCTEXTURE = 10;
enum class Operation {
Increment,
Decrement,
@@ -432,34 +430,6 @@ Id DescType(EmitContext& ctx, Id sampled_type, Id pointer_type, u32 count) {
return pointer_type;
}
}
size_t FindAndSetNextUnusedLocation(std::bitset<IR::NUM_GENERICS>& used_locations,
size_t& start_offset) {
for (size_t location = start_offset; location < used_locations.size(); ++location) {
if (!used_locations.test(location)) {
start_offset = location;
used_locations.set(location);
return location;
}
}
throw RuntimeError("Unable to get an unused location for legacy attribute");
}
Id DefineLegacyInput(EmitContext& ctx, std::bitset<IR::NUM_GENERICS>& used_locations,
size_t& start_offset) {
const Id id{DefineInput(ctx, ctx.F32[4], true)};
const size_t location = FindAndSetNextUnusedLocation(used_locations, start_offset);
ctx.Decorate(id, spv::Decoration::Location, location);
return id;
}
Id DefineLegacyOutput(EmitContext& ctx, std::bitset<IR::NUM_GENERICS>& used_locations,
size_t& start_offset, std::optional<u32> invocations) {
const Id id{DefineOutput(ctx, ctx.F32[4], invocations)};
const size_t location = FindAndSetNextUnusedLocation(used_locations, start_offset);
ctx.Decorate(id, spv::Decoration::Location, location);
return id;
}
} // Anonymous namespace
void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) {
@@ -543,64 +513,6 @@ Id EmitContext::BitOffset16(const IR::Value& offset) {
return OpBitwiseAnd(U32[1], OpShiftLeftLogical(U32[1], Def(offset), Const(3u)), Const(16u));
}
Id EmitContext::InputLegacyAttribute(IR::Attribute attribute) {
if (attribute >= IR::Attribute::ColorFrontDiffuseR &&
attribute <= IR::Attribute::ColorFrontDiffuseA) {
return input_front_color;
}
if (attribute >= IR::Attribute::ColorFrontSpecularR &&
attribute <= IR::Attribute::ColorFrontSpecularA) {
return input_front_secondary_color;
}
if (attribute >= IR::Attribute::ColorBackDiffuseR &&
attribute <= IR::Attribute::ColorBackDiffuseA) {
return input_back_color;
}
if (attribute >= IR::Attribute::ColorBackSpecularR &&
attribute <= IR::Attribute::ColorBackSpecularA) {
return input_back_secondary_color;
}
if (attribute == IR::Attribute::FogCoordinate) {
return input_fog_frag_coord;
}
if (attribute >= IR::Attribute::FixedFncTexture0S &&
attribute <= IR::Attribute::FixedFncTexture9Q) {
u32 index =
(static_cast<u32>(attribute) - static_cast<u32>(IR::Attribute::FixedFncTexture0S)) / 4;
return input_fixed_fnc_textures[index];
}
throw InvalidArgument("Attribute is not legacy attribute {}", attribute);
}
Id EmitContext::OutputLegacyAttribute(IR::Attribute attribute) {
if (attribute >= IR::Attribute::ColorFrontDiffuseR &&
attribute <= IR::Attribute::ColorFrontDiffuseA) {
return output_front_color;
}
if (attribute >= IR::Attribute::ColorFrontSpecularR &&
attribute <= IR::Attribute::ColorFrontSpecularA) {
return output_front_secondary_color;
}
if (attribute >= IR::Attribute::ColorBackDiffuseR &&
attribute <= IR::Attribute::ColorBackDiffuseA) {
return output_back_color;
}
if (attribute >= IR::Attribute::ColorBackSpecularR &&
attribute <= IR::Attribute::ColorBackSpecularA) {
return output_back_secondary_color;
}
if (attribute == IR::Attribute::FogCoordinate) {
return output_fog_frag_coord;
}
if (attribute >= IR::Attribute::FixedFncTexture0S &&
attribute <= IR::Attribute::FixedFncTexture9Q) {
u32 index =
(static_cast<u32>(attribute) - static_cast<u32>(IR::Attribute::FixedFncTexture0S)) / 4;
return output_fixed_fnc_textures[index];
}
throw InvalidArgument("Attribute is not legacy attribute {}", attribute);
}
void EmitContext::DefineCommonTypes(const Info& info) {
void_id = TypeVoid();
@@ -1389,7 +1301,6 @@ void EmitContext::DefineInputs(const IR::Program& program) {
loads[IR::Attribute::TessellationEvaluationPointV]) {
tess_coord = DefineInput(*this, F32[3], false, spv::BuiltIn::TessCoord);
}
std::bitset<IR::NUM_GENERICS> used_locations{};
for (size_t index = 0; index < IR::NUM_GENERICS; ++index) {
const AttributeType input_type{runtime_info.generic_input_types[index]};
if (!runtime_info.previous_stage_stores.Generic(index)) {
@@ -1401,7 +1312,6 @@ void EmitContext::DefineInputs(const IR::Program& program) {
if (input_type == AttributeType::Disabled) {
continue;
}
used_locations.set(index);
const Id type{GetAttributeType(*this, input_type)};
const Id id{DefineInput(*this, type, true)};
Decorate(id, spv::Decoration::Location, static_cast<u32>(index));
@@ -1427,30 +1337,6 @@ void EmitContext::DefineInputs(const IR::Program& program) {
break;
}
}
size_t previous_unused_location = 0;
if (loads.AnyComponent(IR::Attribute::ColorFrontDiffuseR)) {
input_front_color = DefineLegacyInput(*this, used_locations, previous_unused_location);
}
if (loads.AnyComponent(IR::Attribute::ColorFrontSpecularR)) {
input_front_secondary_color =
DefineLegacyInput(*this, used_locations, previous_unused_location);
}
if (loads.AnyComponent(IR::Attribute::ColorBackDiffuseR)) {
input_back_color = DefineLegacyInput(*this, used_locations, previous_unused_location);
}
if (loads.AnyComponent(IR::Attribute::ColorBackSpecularR)) {
input_back_secondary_color =
DefineLegacyInput(*this, used_locations, previous_unused_location);
}
if (loads.AnyComponent(IR::Attribute::FogCoordinate)) {
input_fog_frag_coord = DefineLegacyInput(*this, used_locations, previous_unused_location);
}
for (size_t index = 0; index < NUM_FIXEDFNCTEXTURE; ++index) {
if (loads.AnyComponent(IR::Attribute::FixedFncTexture0S + index * 4)) {
input_fixed_fnc_textures[index] =
DefineLegacyInput(*this, used_locations, previous_unused_location);
}
}
if (stage == Stage::TessellationEval) {
for (size_t index = 0; index < info.uses_patches.size(); ++index) {
if (!info.uses_patches[index]) {
@@ -1501,38 +1387,9 @@ void EmitContext::DefineOutputs(const IR::Program& program) {
viewport_mask = DefineOutput(*this, TypeArray(U32[1], Const(1u)), std::nullopt,
spv::BuiltIn::ViewportMaskNV);
}
std::bitset<IR::NUM_GENERICS> used_locations{};
for (size_t index = 0; index < IR::NUM_GENERICS; ++index) {
if (info.stores.Generic(index)) {
DefineGenericOutput(*this, index, invocations);
used_locations.set(index);
}
}
size_t previous_unused_location = 0;
if (info.stores.AnyComponent(IR::Attribute::ColorFrontDiffuseR)) {
output_front_color =
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
}
if (info.stores.AnyComponent(IR::Attribute::ColorFrontSpecularR)) {
output_front_secondary_color =
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
}
if (info.stores.AnyComponent(IR::Attribute::ColorBackDiffuseR)) {
output_back_color =
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
}
if (info.stores.AnyComponent(IR::Attribute::ColorBackSpecularR)) {
output_back_secondary_color =
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
}
if (info.stores.AnyComponent(IR::Attribute::FogCoordinate)) {
output_fog_frag_coord =
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
}
for (size_t index = 0; index < NUM_FIXEDFNCTEXTURE; ++index) {
if (info.stores.AnyComponent(IR::Attribute::FixedFncTexture0S + index * 4)) {
output_fixed_fnc_textures[index] =
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
}
}
switch (stage) {

View File

@@ -113,9 +113,6 @@ public:
[[nodiscard]] Id BitOffset8(const IR::Value& offset);
[[nodiscard]] Id BitOffset16(const IR::Value& offset);
Id InputLegacyAttribute(IR::Attribute attribute);
Id OutputLegacyAttribute(IR::Attribute attribute);
Id Const(u32 value) {
return Constant(U32[1], value);
}
@@ -281,22 +278,10 @@ public:
Id write_global_func_u32x4{};
Id input_position{};
Id input_front_color{};
Id input_front_secondary_color{};
Id input_back_color{};
Id input_back_secondary_color{};
Id input_fog_frag_coord{};
std::array<Id, 10> input_fixed_fnc_textures{};
std::array<Id, 32> input_generics{};
Id output_point_size{};
Id output_position{};
Id output_front_color{};
Id output_front_secondary_color{};
Id output_back_color{};
Id output_back_secondary_color{};
Id output_fog_frag_coord{};
std::array<Id, 10> output_fixed_fnc_textures{};
std::array<std::array<GenericElementInfo, 4>, 32> output_generics{};
Id output_tess_level_outer{};

View File

@@ -224,6 +224,8 @@ enum class Attribute : u64 {
constexpr size_t NUM_GENERICS = 32;
constexpr size_t NUM_FIXEDFNCTEXTURE = 10;
[[nodiscard]] bool IsGeneric(Attribute attribute) noexcept;
[[nodiscard]] u32 GenericAttributeIndex(Attribute attribute);

View File

@@ -5,6 +5,7 @@
#include <algorithm>
#include <memory>
#include <vector>
#include <queue>
#include "common/settings.h"
#include "shader_recompiler/exception.h"
@@ -127,6 +128,42 @@ void AddNVNStorageBuffers(IR::Program& program) {
});
}
}
bool IsLegacyAttribute(IR::Attribute attribute) {
return (attribute >= IR::Attribute::ColorFrontDiffuseR &&
attribute <= IR::Attribute::ColorBackSpecularA) ||
attribute == IR::Attribute::FogCoordinate ||
(attribute >= IR::Attribute::FixedFncTexture0S &&
attribute <= IR::Attribute::FixedFncTexture9Q);
}
std::map<IR::Attribute, IR::Attribute> GenerateLegacyToGenericMappings(
const VaryingState& state, std::queue<IR::Attribute> ununsed_generics) {
std::map<IR::Attribute, IR::Attribute> mapping;
for (size_t index = 0; index < 4; ++index) {
auto attr = IR::Attribute::ColorFrontDiffuseR + index * 4;
if (state.AnyComponent(attr)) {
for (size_t i = 0; i < 4; ++i) {
mapping.insert({attr + i, ununsed_generics.front() + i});
}
ununsed_generics.pop();
}
}
if (state[IR::Attribute::FogCoordinate]) {
mapping.insert({IR::Attribute::FogCoordinate, ununsed_generics.front()});
ununsed_generics.pop();
}
for (size_t index = 0; index < IR::NUM_FIXEDFNCTEXTURE; ++index) {
auto attr = IR::Attribute::FixedFncTexture0S + index * 4;
if (state.AnyComponent(attr)) {
for (size_t i = 0; i < 4; ++i) {
mapping.insert({attr + i, ununsed_generics.front() + i});
}
ununsed_generics.pop();
}
}
return mapping;
}
} // Anonymous namespace
IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Block>& block_pool,
@@ -226,4 +263,62 @@ IR::Program MergeDualVertexPrograms(IR::Program& vertex_a, IR::Program& vertex_b
return result;
}
void ConvertLegacyToGeneric(IR::Program& program, const Shader::RuntimeInfo& runtime_info) {
auto& stores = program.info.stores;
if (stores.Legacy()) {
std::queue<IR::Attribute> ununsed_output_generics{};
for (size_t index = 0; index < IR::NUM_GENERICS; ++index) {
if (!stores.Generic(index)) {
ununsed_output_generics.push(IR::Attribute::Generic0X + index * 4);
}
}
auto mappings = GenerateLegacyToGenericMappings(stores, ununsed_output_generics);
for (IR::Block* const block : program.post_order_blocks) {
for (IR::Inst& inst : block->Instructions()) {
switch (inst.GetOpcode()) {
case IR::Opcode::SetAttribute: {
const auto attr = inst.Arg(0).Attribute();
if (IsLegacyAttribute(attr)) {
stores.Set(mappings[attr], true);
inst.SetArg(0, Shader::IR::Value(mappings[attr]));
}
break;
}
default:
break;
}
}
}
}
auto& loads = program.info.loads;
if (loads.Legacy()) {
std::queue<IR::Attribute> ununsed_input_generics{};
for (size_t index = 0; index < IR::NUM_GENERICS; ++index) {
const AttributeType input_type{runtime_info.generic_input_types[index]};
if (!runtime_info.previous_stage_stores.Generic(index) || !loads.Generic(index) ||
input_type == AttributeType::Disabled) {
ununsed_input_generics.push(IR::Attribute::Generic0X + index * 4);
}
}
auto mappings = GenerateLegacyToGenericMappings(loads, ununsed_input_generics);
for (IR::Block* const block : program.post_order_blocks) {
for (IR::Inst& inst : block->Instructions()) {
switch (inst.GetOpcode()) {
case IR::Opcode::GetAttribute: {
const auto attr = inst.Arg(0).Attribute();
if (IsLegacyAttribute(attr)) {
loads.Set(mappings[attr], true);
inst.SetArg(0, Shader::IR::Value(mappings[attr]));
}
break;
}
default:
break;
}
}
}
}
}
} // namespace Shader::Maxwell

View File

@@ -10,6 +10,7 @@
#include "shader_recompiler/frontend/maxwell/control_flow.h"
#include "shader_recompiler/host_translate_info.h"
#include "shader_recompiler/object_pool.h"
#include "shader_recompiler/runtime_info.h"
namespace Shader::Maxwell {
@@ -20,4 +21,7 @@ namespace Shader::Maxwell {
[[nodiscard]] IR::Program MergeDualVertexPrograms(IR::Program& vertex_a, IR::Program& vertex_b,
Environment& env_vertex_b);
[[nodiscard]] void ConvertLegacyToGeneric(IR::Program& program,
const Shader::RuntimeInfo& runtime_info);
} // namespace Shader::Maxwell

View File

@@ -53,7 +53,8 @@ struct VaryingState {
return AnyComponent(IR::Attribute::ColorFrontDiffuseR) ||
AnyComponent(IR::Attribute::ColorFrontSpecularR) ||
AnyComponent(IR::Attribute::ColorBackDiffuseR) ||
AnyComponent(IR::Attribute::ColorBackSpecularR) || FixedFunctionTexture();
AnyComponent(IR::Attribute::ColorBackSpecularR) || FixedFunctionTexture() ||
mask[static_cast<size_t>(IR::Attribute::FogCoordinate)];
}
[[nodiscard]] bool FixedFunctionTexture() const noexcept {

View File

@@ -32,7 +32,7 @@ constexpr std::array PREFERRED_GPU_DECODERS = {
#ifdef _WIN32
AV_HWDEVICE_TYPE_D3D11VA,
AV_HWDEVICE_TYPE_DXVA2,
#elif defined(__linux__)
#elif defined(__unix__)
AV_HWDEVICE_TYPE_VAAPI,
AV_HWDEVICE_TYPE_VDPAU,
#endif

View File

@@ -42,6 +42,7 @@ namespace {
using Shader::Backend::GLASM::EmitGLASM;
using Shader::Backend::GLSL::EmitGLSL;
using Shader::Backend::SPIRV::EmitSPIRV;
using Shader::Maxwell::ConvertLegacyToGeneric;
using Shader::Maxwell::MergeDualVertexPrograms;
using Shader::Maxwell::TranslateProgram;
using VideoCommon::ComputeEnvironment;
@@ -462,12 +463,14 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
MakeRuntimeInfo(key, program, previous_program, glasm_use_storage_buffers, use_glasm)};
switch (device.GetShaderBackend()) {
case Settings::ShaderBackend::GLSL:
ConvertLegacyToGeneric(program, runtime_info);
sources[stage_index] = EmitGLSL(profile, runtime_info, program, binding);
break;
case Settings::ShaderBackend::GLASM:
sources[stage_index] = EmitGLASM(profile, runtime_info, program, binding);
break;
case Settings::ShaderBackend::SPIRV:
ConvertLegacyToGeneric(program, runtime_info);
sources_spirv[stage_index] = EmitSPIRV(profile, runtime_info, program, binding);
break;
}

View File

@@ -1047,7 +1047,7 @@ bool Image::ScaleDown(bool ignore) {
}
ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info,
ImageId image_id_, Image& image)
ImageId image_id_, Image& image, const SlotVector<Image>&)
: VideoCommon::ImageViewBase{info, image.info, image_id_}, views{runtime.null_image_views} {
const Device& device = runtime.device;
if (True(image.flags & ImageFlagBits::Converted)) {

View File

@@ -36,6 +36,7 @@ using VideoCommon::ImageViewType;
using VideoCommon::NUM_RT;
using VideoCommon::Region2D;
using VideoCommon::RenderTargets;
using VideoCommon::SlotVector;
struct ImageBufferMap {
~ImageBufferMap();
@@ -234,7 +235,8 @@ class ImageView : public VideoCommon::ImageViewBase {
friend Image;
public:
explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&);
explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&,
const SlotVector<Image>&);
explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo&,
const VideoCommon::ImageViewInfo&, GPUVAddr);
explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info,

View File

@@ -518,53 +518,6 @@ void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_frameb
scheduler.InvalidateState();
}
void BlitImageHelper::ConvertColor(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
ImageView& src_image_view, u32 up_scale, u32 down_shift) {
const VkPipelineLayout layout = *one_texture_pipeline_layout;
const VkImageView src_view = src_image_view.ColorView();
const VkSampler sampler = *nearest_sampler;
const VkExtent2D extent{
.width = std::max((src_image_view.size.width * up_scale) >> down_shift, 1U),
.height = std::max((src_image_view.size.height * up_scale) >> down_shift, 1U),
};
scheduler.RequestRenderpass(dst_framebuffer);
scheduler.Record([pipeline, layout, sampler, src_view, extent, up_scale, down_shift,
this](vk::CommandBuffer cmdbuf) {
const VkOffset2D offset{
.x = 0,
.y = 0,
};
const VkViewport viewport{
.x = 0.0f,
.y = 0.0f,
.width = static_cast<float>(extent.width),
.height = static_cast<float>(extent.height),
.minDepth = 0.0f,
.maxDepth = 0.0f,
};
const VkRect2D scissor{
.offset = offset,
.extent = extent,
};
const PushConstants push_constants{
.tex_scale = {viewport.width, viewport.height},
.tex_offset = {0.0f, 0.0f},
};
const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view);
// TODO: Barriers
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
nullptr);
cmdbuf.SetViewport(0, viewport);
cmdbuf.SetScissor(0, scissor);
cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
cmdbuf.Draw(3, 1, 0, 0);
});
scheduler.InvalidateState();
}
void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
ImageView& src_image_view) {
const VkPipelineLayout layout = *two_textures_pipeline_layout;

View File

@@ -60,9 +60,6 @@ private:
void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
const ImageView& src_image_view);
void ConvertColor(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
ImageView& src_image_view, u32 up_scale, u32 down_shift);
void ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
ImageView& src_image_view);

View File

@@ -605,7 +605,11 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
.flags = 0,
.topology = input_assembly_topology,
.primitiveRestartEnable = key.state.primitive_restart_enable != 0 &&
SupportsPrimitiveRestart(input_assembly_topology),
((input_assembly_topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST &&
device.IsTopologyListPrimitiveRestartSupported()) ||
SupportsPrimitiveRestart(input_assembly_topology) ||
(input_assembly_topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST &&
device.IsPatchListPrimitiveRestartSupported())),
};
const VkPipelineTessellationStateCreateInfo tessellation_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,
@@ -613,7 +617,6 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
.flags = 0,
.patchControlPoints = key.state.patch_control_points_minus_one.Value() + 1,
};
std::array<VkViewportSwizzleNV, Maxwell::NumViewports> swizzles;
std::ranges::transform(key.state.viewport_swizzles, swizzles.begin(), UnpackViewportSwizzle);
const VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{
@@ -748,8 +751,8 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.logicOpEnable = VK_FALSE,
.logicOp = VK_LOGIC_OP_COPY,
.logicOpEnable = key.state.logic_op_enable != 0,
.logicOp = static_cast<VkLogicOp>(key.state.logic_op.Value()),
.attachmentCount = static_cast<u32>(cb_attachments.size()),
.pAttachments = cb_attachments.data(),
.blendConstants = {},

View File

@@ -48,6 +48,7 @@ MICROPROFILE_DECLARE(Vulkan_PipelineCache);
namespace {
using Shader::Backend::SPIRV::EmitSPIRV;
using Shader::Maxwell::ConvertLegacyToGeneric;
using Shader::Maxwell::MergeDualVertexPrograms;
using Shader::Maxwell::TranslateProgram;
using VideoCommon::ComputeEnvironment;
@@ -543,6 +544,7 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
infos[stage_index] = &program.info;
const auto runtime_info{MakeRuntimeInfo(programs, key, program, previous_stage)};
ConvertLegacyToGeneric(program, runtime_info);
const std::vector<u32> code{EmitSPIRV(profile, runtime_info, program, binding)};
device.SaveShader(code);
modules[stage_index] = BuildShader(device, code);

View File

@@ -1473,8 +1473,7 @@ bool Image::BlitScaleHelper(bool scale_up) {
ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info,
ImageId image_id_, Image& image)
: VideoCommon::ImageViewBase{info, image.info, image_id_}, device{&runtime.device},
src_image{&image}, image_handle{image.Handle()},
samples(ConvertSampleCount(image.info.num_samples)) {
image_handle{image.Handle()}, samples(ConvertSampleCount(image.info.num_samples)) {
using Shader::TextureType;
const VkImageAspectFlags aspect_mask = ImageViewAspectMask(info);
@@ -1557,6 +1556,12 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
}
}
ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info,
ImageId image_id_, Image& image, const SlotVector<Image>& slot_imgs)
: ImageView{runtime, info, image_id_, image} {
slot_images = &slot_imgs;
}
ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info,
const VideoCommon::ImageViewInfo& view_info, GPUVAddr gpu_addr_)
: VideoCommon::ImageViewBase{info, view_info}, gpu_addr{gpu_addr_},
@@ -1613,10 +1618,12 @@ VkImageView ImageView::StorageView(Shader::TextureType texture_type,
}
bool ImageView::IsRescaled() const noexcept {
if (!src_image) {
if (!slot_images) {
return false;
}
return src_image->IsRescaled();
const auto& slots = *slot_images;
const auto& src_image = slots[image_id];
return src_image.IsRescaled();
}
vk::ImageView ImageView::MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask) {

View File

@@ -23,6 +23,7 @@ using VideoCommon::ImageId;
using VideoCommon::NUM_RT;
using VideoCommon::Region2D;
using VideoCommon::RenderTargets;
using VideoCommon::SlotVector;
using VideoCore::Surface::PixelFormat;
class ASTCDecoderPass;
@@ -170,6 +171,8 @@ private:
class ImageView : public VideoCommon::ImageViewBase {
public:
explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&);
explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&,
const SlotVector<Image>&);
explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo&,
const VideoCommon::ImageViewInfo&, GPUVAddr);
explicit ImageView(TextureCacheRuntime&, const VideoCommon::NullImageViewParams&);
@@ -226,7 +229,7 @@ private:
[[nodiscard]] vk::ImageView MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask);
const Device* device = nullptr;
const Image* src_image{};
const SlotVector<Image>* slot_images = nullptr;
std::array<vk::ImageView, Shader::NUM_TEXTURE_TYPES> image_views;
std::unique_ptr<StorageViews> storage_views;

View File

@@ -1397,7 +1397,8 @@ ImageViewId TextureCache<P>::FindOrEmplaceImageView(ImageId image_id, const Imag
if (const ImageViewId image_view_id = image.FindView(info); image_view_id) {
return image_view_id;
}
const ImageViewId image_view_id = slot_image_views.insert(runtime, info, image_id, image);
const ImageViewId image_view_id =
slot_image_views.insert(runtime, info, image_id, image, slot_images);
image.InsertView(info, image_view_id);
return image_view_id;
}

View File

@@ -271,7 +271,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
.tessellationShader = true,
.sampleRateShading = true,
.dualSrcBlend = true,
.logicOp = false,
.logicOp = true,
.multiDrawIndirect = false,
.drawIndirectFirstInstance = false,
.depthClamp = true,
@@ -433,6 +433,19 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
LOG_INFO(Render_Vulkan, "Device doesn't support uint8 indexes");
}
VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT primitive_topology_list_restart;
if (is_topology_list_restart_supported || is_patch_list_restart_supported) {
primitive_topology_list_restart = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT,
.pNext = nullptr,
.primitiveTopologyListRestart = is_topology_list_restart_supported,
.primitiveTopologyPatchListRestart = is_patch_list_restart_supported,
};
SetNext(next, primitive_topology_list_restart);
} else {
LOG_INFO(Render_Vulkan, "Device doesn't support list topology primitive restart");
}
VkPhysicalDeviceTransformFeedbackFeaturesEXT transform_feedback;
if (ext_transform_feedback) {
transform_feedback = {
@@ -891,6 +904,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
bool has_ext_provoking_vertex{};
bool has_ext_vertex_input_dynamic_state{};
bool has_ext_line_rasterization{};
bool has_ext_primitive_topology_list_restart{};
for (const std::string& extension : supported_extensions) {
const auto test = [&](std::optional<std::reference_wrapper<bool>> status, const char* name,
bool push) {
@@ -915,6 +929,8 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
test(has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false);
test(ext_depth_range_unrestricted, VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true);
test(ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true);
test(has_ext_primitive_topology_list_restart,
VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_EXTENSION_NAME, true);
test(ext_sampler_filter_minmax, VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME, true);
test(ext_shader_viewport_index_layer, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME,
true);
@@ -1113,6 +1129,19 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
khr_pipeline_executable_properties = true;
}
}
if (has_ext_primitive_topology_list_restart) {
VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT primitive_topology_list_restart{};
primitive_topology_list_restart.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT;
primitive_topology_list_restart.pNext = nullptr;
features.pNext = &primitive_topology_list_restart;
physical.GetFeatures2KHR(features);
is_topology_list_restart_supported =
primitive_topology_list_restart.primitiveTopologyListRestart;
is_patch_list_restart_supported =
primitive_topology_list_restart.primitiveTopologyPatchListRestart;
}
if (has_khr_image_format_list && has_khr_swapchain_mutable_format) {
extensions.push_back(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME);
extensions.push_back(VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME);

View File

@@ -238,6 +238,16 @@ public:
return khr_workgroup_memory_explicit_layout;
}
/// Returns true if the device supports VK_EXT_primitive_topology_list_restart.
bool IsTopologyListPrimitiveRestartSupported() const {
return is_topology_list_restart_supported;
}
/// Returns true if the device supports VK_EXT_primitive_topology_list_restart.
bool IsPatchListPrimitiveRestartSupported() const {
return is_patch_list_restart_supported;
}
/// Returns true if the device supports VK_EXT_index_type_uint8.
bool IsExtIndexTypeUint8Supported() const {
return ext_index_type_uint8;
@@ -401,6 +411,9 @@ private:
bool is_shader_int16_supported{}; ///< Support for int16.
bool is_shader_storage_image_multisample{}; ///< Support for image operations on MSAA images.
bool is_blit_depth_stencil_supported{}; ///< Support for blitting from and to depth stencil.
bool is_topology_list_restart_supported{}; ///< Support for primitive restart with list
///< topologies.
bool is_patch_list_restart_supported{}; ///< Support for primitive restart with list patch.
bool nv_viewport_swizzle{}; ///< Support for VK_NV_viewport_swizzle.
bool nv_viewport_array2{}; ///< Support for VK_NV_viewport_array2.
bool nv_geometry_shader_passthrough{}; ///< Support for VK_NV_geometry_shader_passthrough.

View File

@@ -251,6 +251,9 @@ target_include_directories(yuzu PRIVATE ../../externals/Vulkan-Headers/include)
if (NOT WIN32)
target_include_directories(yuzu PRIVATE ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
endif()
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
target_link_libraries(yuzu PRIVATE Qt5::DBus)
endif()
target_compile_definitions(yuzu PRIVATE
# Use QStringBuilder for string concatenation to reduce

View File

@@ -12,7 +12,6 @@
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
#include "core/hle/lock.h"
#include "core/hle/service/hid/controllers/npad.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/sm/sm.h"
@@ -34,7 +33,7 @@ void UpdateController(Core::HID::EmulatedController* controller,
}
controller->SetNpadStyleIndex(controller_type);
if (connected) {
controller->Connect();
controller->Connect(true);
}
}
@@ -401,36 +400,66 @@ void QtControllerSelectorDialog::SetSupportedControllers() {
}
void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index) {
const auto npad_style_set = system.HIDCore().GetSupportedStyleTag();
auto& pairs = index_controller_type_pairs[player_index];
pairs.clear();
emulated_controllers[player_index]->clear();
pairs.emplace_back(emulated_controllers[player_index]->count(),
Core::HID::NpadStyleIndex::ProController);
emulated_controllers[player_index]->addItem(tr("Pro Controller"));
const auto add_item = [&](Core::HID::NpadStyleIndex controller_type,
const QString& controller_name) {
pairs.emplace_back(emulated_controllers[player_index]->count(), controller_type);
emulated_controllers[player_index]->addItem(controller_name);
};
pairs.emplace_back(emulated_controllers[player_index]->count(),
Core::HID::NpadStyleIndex::JoyconDual);
emulated_controllers[player_index]->addItem(tr("Dual Joycons"));
pairs.emplace_back(emulated_controllers[player_index]->count(),
Core::HID::NpadStyleIndex::JoyconLeft);
emulated_controllers[player_index]->addItem(tr("Left Joycon"));
pairs.emplace_back(emulated_controllers[player_index]->count(),
Core::HID::NpadStyleIndex::JoyconRight);
emulated_controllers[player_index]->addItem(tr("Right Joycon"));
if (player_index == 0) {
pairs.emplace_back(emulated_controllers[player_index]->count(),
Core::HID::NpadStyleIndex::Handheld);
emulated_controllers[player_index]->addItem(tr("Handheld"));
if (npad_style_set.fullkey == 1) {
add_item(Core::HID::NpadStyleIndex::ProController, tr("Pro Controller"));
}
pairs.emplace_back(emulated_controllers[player_index]->count(),
Core::HID::NpadStyleIndex::GameCube);
emulated_controllers[player_index]->addItem(tr("GameCube Controller"));
if (npad_style_set.joycon_dual == 1) {
add_item(Core::HID::NpadStyleIndex::JoyconDual, tr("Dual Joycons"));
}
if (npad_style_set.joycon_left == 1) {
add_item(Core::HID::NpadStyleIndex::JoyconLeft, tr("Left Joycon"));
}
if (npad_style_set.joycon_right == 1) {
add_item(Core::HID::NpadStyleIndex::JoyconRight, tr("Right Joycon"));
}
if (player_index == 0 && npad_style_set.handheld == 1) {
add_item(Core::HID::NpadStyleIndex::Handheld, tr("Handheld"));
}
if (npad_style_set.gamecube == 1) {
add_item(Core::HID::NpadStyleIndex::GameCube, tr("GameCube Controller"));
}
// Disable all unsupported controllers
if (!Settings::values.enable_all_controllers) {
return;
}
if (npad_style_set.palma == 1) {
add_item(Core::HID::NpadStyleIndex::Pokeball, tr("Poke Ball Plus"));
}
if (npad_style_set.lark == 1) {
add_item(Core::HID::NpadStyleIndex::NES, tr("NES Controller"));
}
if (npad_style_set.lucia == 1) {
add_item(Core::HID::NpadStyleIndex::SNES, tr("SNES Controller"));
}
if (npad_style_set.lagoon == 1) {
add_item(Core::HID::NpadStyleIndex::N64, tr("N64 Controller"));
}
if (npad_style_set.lager == 1) {
add_item(Core::HID::NpadStyleIndex::SegaGenesis, tr("Sega Genesis"));
}
}
Core::HID::NpadStyleIndex QtControllerSelectorDialog::GetControllerTypeFromIndex(
@@ -664,7 +693,5 @@ void QtControllerSelector::ReconfigureControllers(
}
void QtControllerSelector::MainWindowReconfigureFinished() {
// Acquire the HLE mutex
std::lock_guard lock(HLE::g_hle_lock);
callback();
}

View File

@@ -3,7 +3,6 @@
// Refer to the license.txt file included.
#include <QDateTime>
#include "core/hle/lock.h"
#include "yuzu/applets/qt_error.h"
#include "yuzu/main.h"
@@ -57,7 +56,5 @@ void QtErrorDisplay::ShowCustomErrorText(ResultCode error, std::string dialog_te
}
void QtErrorDisplay::MainWindowFinishedError() {
// Acquire the HLE mutex
std::lock_guard lock{HLE::g_hle_lock};
callback();
}

View File

@@ -14,7 +14,6 @@
#include "common/fs/path_util.h"
#include "common/string_util.h"
#include "core/constants.h"
#include "core/hle/lock.h"
#include "yuzu/applets/qt_profile_select.h"
#include "yuzu/main.h"
#include "yuzu/util/controller_navigation.h"
@@ -170,7 +169,5 @@ void QtProfileSelector::SelectProfile(
}
void QtProfileSelector::MainWindowFinishedSelection(std::optional<Common::UUID> uuid) {
// Acquire the HLE mutex
std::lock_guard lock{HLE::g_hle_lock};
callback(uuid);
}

View File

@@ -599,11 +599,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
if (is_connected) {
if (type == Core::HID::NpadStyleIndex::Handheld) {
emulated_controller_p1->Disconnect();
emulated_controller_handheld->Connect();
emulated_controller_handheld->Connect(true);
emulated_controller = emulated_controller_handheld;
} else {
emulated_controller_handheld->Disconnect();
emulated_controller_p1->Connect();
emulated_controller_p1->Connect(true);
emulated_controller = emulated_controller_p1;
}
}
@@ -718,7 +718,7 @@ void ConfigureInputPlayer::LoadConfiguration() {
void ConfigureInputPlayer::ConnectPlayer(bool connected) {
ui->groupConnectedController->setChecked(connected);
if (connected) {
emulated_controller->Connect();
emulated_controller->Connect(true);
} else {
emulated_controller->Disconnect();
}
@@ -907,78 +907,63 @@ void ConfigureInputPlayer::UpdateUI() {
}
void ConfigureInputPlayer::SetConnectableControllers() {
Core::HID::NpadStyleTag npad_style_set = hid_core.GetSupportedStyleTag();
const auto npad_style_set = hid_core.GetSupportedStyleTag();
index_controller_type_pairs.clear();
ui->comboControllerType->clear();
const auto add_item = [&](Core::HID::NpadStyleIndex controller_type,
const QString& controller_name) {
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), controller_type);
ui->comboControllerType->addItem(controller_name);
};
if (npad_style_set.fullkey == 1) {
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
Core::HID::NpadStyleIndex::ProController);
ui->comboControllerType->addItem(tr("Pro Controller"));
add_item(Core::HID::NpadStyleIndex::ProController, tr("Pro Controller"));
}
if (npad_style_set.joycon_dual == 1) {
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
Core::HID::NpadStyleIndex::JoyconDual);
ui->comboControllerType->addItem(tr("Dual Joycons"));
add_item(Core::HID::NpadStyleIndex::JoyconDual, tr("Dual Joycons"));
}
if (npad_style_set.joycon_left == 1) {
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
Core::HID::NpadStyleIndex::JoyconLeft);
ui->comboControllerType->addItem(tr("Left Joycon"));
add_item(Core::HID::NpadStyleIndex::JoyconLeft, tr("Left Joycon"));
}
if (npad_style_set.joycon_right == 1) {
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
Core::HID::NpadStyleIndex::JoyconRight);
ui->comboControllerType->addItem(tr("Right Joycon"));
add_item(Core::HID::NpadStyleIndex::JoyconRight, tr("Right Joycon"));
}
if (player_index == 0 && npad_style_set.handheld == 1) {
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
Core::HID::NpadStyleIndex::Handheld);
ui->comboControllerType->addItem(tr("Handheld"));
add_item(Core::HID::NpadStyleIndex::Handheld, tr("Handheld"));
}
if (npad_style_set.gamecube == 1) {
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
Core::HID::NpadStyleIndex::GameCube);
ui->comboControllerType->addItem(tr("GameCube Controller"));
add_item(Core::HID::NpadStyleIndex::GameCube, tr("GameCube Controller"));
}
// Disable all unsupported controllers
if (!Settings::values.enable_all_controllers) {
return;
}
if (npad_style_set.palma == 1) {
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
Core::HID::NpadStyleIndex::Pokeball);
ui->comboControllerType->addItem(tr("Poke Ball Plus"));
add_item(Core::HID::NpadStyleIndex::Pokeball, tr("Poke Ball Plus"));
}
if (npad_style_set.lark == 1) {
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
Core::HID::NpadStyleIndex::NES);
ui->comboControllerType->addItem(tr("NES Controller"));
add_item(Core::HID::NpadStyleIndex::NES, tr("NES Controller"));
}
if (npad_style_set.lucia == 1) {
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
Core::HID::NpadStyleIndex::SNES);
ui->comboControllerType->addItem(tr("SNES Controller"));
add_item(Core::HID::NpadStyleIndex::SNES, tr("SNES Controller"));
}
if (npad_style_set.lagoon == 1) {
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
Core::HID::NpadStyleIndex::N64);
ui->comboControllerType->addItem(tr("N64 Controller"));
add_item(Core::HID::NpadStyleIndex::N64, tr("N64 Controller"));
}
if (npad_style_set.lager == 1) {
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
Core::HID::NpadStyleIndex::SegaGenesis);
ui->comboControllerType->addItem(tr("Sega Genesis"));
add_item(Core::HID::NpadStyleIndex::SegaGenesis, tr("Sega Genesis"));
}
}

View File

@@ -1236,11 +1236,58 @@ void GMainWindow::OnDisplayTitleBars(bool show) {
}
}
#ifdef __linux__
static std::optional<QDBusObjectPath> HoldWakeLockLinux(u32 window_id = 0) {
if (!QDBusConnection::sessionBus().isConnected()) {
return {};
}
// reference: https://flatpak.github.io/xdg-desktop-portal/#gdbus-org.freedesktop.portal.Inhibit
QDBusInterface xdp(QString::fromLatin1("org.freedesktop.portal.Desktop"),
QString::fromLatin1("/org/freedesktop/portal/desktop"),
QString::fromLatin1("org.freedesktop.portal.Inhibit"));
if (!xdp.isValid()) {
LOG_WARNING(Frontend, "Couldn't connect to XDP D-Bus endpoint");
return {};
}
QVariantMap options = {};
//: TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the
//: computer from sleeping
options.insert(QString::fromLatin1("reason"),
QCoreApplication::translate("GMainWindow", "yuzu is running a game"));
// 0x4: Suspend lock; 0x8: Idle lock
QDBusReply<QDBusObjectPath> reply =
xdp.call(QString::fromLatin1("Inhibit"),
QString::fromLatin1("x11:") + QString::number(window_id, 16), 12U, options);
if (reply.isValid()) {
return reply.value();
}
LOG_WARNING(Frontend, "Couldn't read Inhibit reply from XDP: {}",
reply.error().message().toStdString());
return {};
}
static void ReleaseWakeLockLinux(QDBusObjectPath lock) {
if (!QDBusConnection::sessionBus().isConnected()) {
return;
}
QDBusInterface unlocker(QString::fromLatin1("org.freedesktop.portal.Desktop"), lock.path(),
QString::fromLatin1("org.freedesktop.portal.Request"));
unlocker.call(QString::fromLatin1("Close"));
}
#endif // __linux__
void GMainWindow::PreventOSSleep() {
#ifdef _WIN32
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
#elif defined(HAVE_SDL2)
SDL_DisableScreenSaver();
#ifdef __linux__
auto reply = HoldWakeLockLinux(winId());
if (reply) {
wake_lock = std::move(reply.value());
}
#endif
#endif
}
@@ -1249,6 +1296,11 @@ void GMainWindow::AllowOSSleep() {
SetThreadExecutionState(ES_CONTINUOUS);
#elif defined(HAVE_SDL2)
SDL_EnableScreenSaver();
#ifdef __linux__
if (!wake_lock.path().isEmpty()) {
ReleaseWakeLockLinux(wake_lock);
}
#endif
#endif
}

View File

@@ -17,6 +17,12 @@
#include "yuzu/compatibility_list.h"
#include "yuzu/hotkeys.h"
#ifdef __linux__
#include <QVariant>
#include <QtDBus/QDBusInterface>
#include <QtDBus/QtDBus>
#endif
class Config;
class EmuThread;
class GameList;
@@ -394,6 +400,9 @@ private:
// Applets
QtSoftwareKeyboardDialog* software_keyboard = nullptr;
#ifdef __linux__
QDBusObjectPath wake_lock{};
#endif
protected:
void dropEvent(QDropEvent* event) override;