mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-06 20:24:02 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| be67a31c93 | |||
| 11de264541 | |||
| f6e7686038 | |||
| 1dcc574591 | |||
| 5c20f244c9 | |||
| aa4e494c08 |
@@ -63,3 +63,6 @@ artifacts
|
||||
/install*
|
||||
vulkansdk*.exe
|
||||
*.tar.zst
|
||||
|
||||
# Build-time generated external sources
|
||||
externals/generated
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
diff --git a/include/vk_mem_alloc.h b/include/vk_mem_alloc.h
|
||||
index 8df0364..4856064 100644
|
||||
--- a/include/vk_mem_alloc.h
|
||||
+++ b/include/vk_mem_alloc.h
|
||||
@@ -3017,7 +3017,7 @@ remove them if not needed.
|
||||
|
||||
#if defined(__ANDROID_API__) && (__ANDROID_API__ < 16)
|
||||
#include <cstdlib>
|
||||
-static void* vma_aligned_alloc(size_t alignment, size_t size)
|
||||
+static inline void* vma_aligned_alloc(size_t alignment, size_t size)
|
||||
{
|
||||
// alignment must be >= sizeof(void*)
|
||||
if(alignment < sizeof(void*))
|
||||
@@ -3860,7 +3860,7 @@ Returned value is the found element, if present in the collection or place where
|
||||
new element with value (key) should be inserted.
|
||||
*/
|
||||
template <typename CmpLess, typename IterT, typename KeyT>
|
||||
-static IterT VmaBinaryFindFirstNotLess(IterT beg, IterT end, const KeyT& key, const CmpLess& cmp)
|
||||
+static inline IterT VmaBinaryFindFirstNotLess(IterT beg, IterT end, const KeyT& key, const CmpLess& cmp)
|
||||
{
|
||||
size_t down = 0;
|
||||
size_t up = size_t(end - beg);
|
||||
@@ -3898,7 +3898,7 @@ Warning! O(n^2) complexity. Use only inside VMA_HEAVY_ASSERT.
|
||||
T must be pointer type, e.g. VmaAllocation, VmaPool.
|
||||
*/
|
||||
template<typename T>
|
||||
-static bool VmaValidatePointerArray(uint32_t count, const T* arr)
|
||||
+static inline bool VmaValidatePointerArray(uint32_t count, const T* arr)
|
||||
{
|
||||
for (uint32_t i = 0; i < count; ++i)
|
||||
{
|
||||
@@ -4188,13 +4188,13 @@ static void VmaFree(const VkAllocationCallbacks* pAllocationCallbacks, void* ptr
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
-static T* VmaAllocate(const VkAllocationCallbacks* pAllocationCallbacks)
|
||||
+static inline T* VmaAllocate(const VkAllocationCallbacks* pAllocationCallbacks)
|
||||
{
|
||||
return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T), VMA_ALIGN_OF(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
-static T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, size_t count)
|
||||
+static inline T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, size_t count)
|
||||
{
|
||||
return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T) * count, VMA_ALIGN_OF(T));
|
||||
}
|
||||
@@ -4204,14 +4204,14 @@ static T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, si
|
||||
#define vma_new_array(allocator, type, count) new(VmaAllocateArray<type>((allocator), (count)))(type)
|
||||
|
||||
template<typename T>
|
||||
-static void vma_delete(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr)
|
||||
+static inline void vma_delete(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr)
|
||||
{
|
||||
ptr->~T();
|
||||
VmaFree(pAllocationCallbacks, ptr);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
-static void vma_delete_array(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr, size_t count)
|
||||
+static inline void vma_delete_array(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr, size_t count)
|
||||
{
|
||||
if (ptr != VMA_NULL)
|
||||
{
|
||||
@@ -4658,13 +4658,13 @@ void VmaVector<T, AllocatorT>::remove(size_t index)
|
||||
#endif // _VMA_VECTOR_FUNCTIONS
|
||||
|
||||
template<typename T, typename allocatorT>
|
||||
-static void VmaVectorInsert(VmaVector<T, allocatorT>& vec, size_t index, const T& item)
|
||||
+static inline void VmaVectorInsert(VmaVector<T, allocatorT>& vec, size_t index, const T& item)
|
||||
{
|
||||
vec.insert(index, item);
|
||||
}
|
||||
|
||||
template<typename T, typename allocatorT>
|
||||
-static void VmaVectorRemove(VmaVector<T, allocatorT>& vec, size_t index)
|
||||
+static inline void VmaVectorRemove(VmaVector<T, allocatorT>& vec, size_t index)
|
||||
{
|
||||
vec.remove(index);
|
||||
}
|
||||
@@ -10620,19 +10620,19 @@ static void VmaFree(VmaAllocator hAllocator, void* ptr)
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
-static T* VmaAllocate(VmaAllocator hAllocator)
|
||||
+static inline T* VmaAllocate(VmaAllocator hAllocator)
|
||||
{
|
||||
return (T*)VmaMalloc(hAllocator, sizeof(T), VMA_ALIGN_OF(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
-static T* VmaAllocateArray(VmaAllocator hAllocator, size_t count)
|
||||
+static inline T* VmaAllocateArray(VmaAllocator hAllocator, size_t count)
|
||||
{
|
||||
return (T*)VmaMalloc(hAllocator, sizeof(T) * count, VMA_ALIGN_OF(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
-static void vma_delete(VmaAllocator hAllocator, T* ptr)
|
||||
+static inline void vma_delete(VmaAllocator hAllocator, T* ptr)
|
||||
{
|
||||
if(ptr != VMA_NULL)
|
||||
{
|
||||
@@ -10642,7 +10642,7 @@ static void vma_delete(VmaAllocator hAllocator, T* ptr)
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
-static void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count)
|
||||
+static inline void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count)
|
||||
{
|
||||
if(ptr != VMA_NULL)
|
||||
{
|
||||
+5
-4
@@ -3,6 +3,7 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.31)
|
||||
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "15.0" CACHE STRING "macOS deployment target")
|
||||
project(yuzu)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
|
||||
@@ -214,8 +215,6 @@ if(MSVC)
|
||||
endif()
|
||||
|
||||
# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system
|
||||
cmake_dependent_option(YUZU_USE_BUNDLED_SDL3 "Download bundled SDL3 build" "${MSVC}" "NOT ANDROID" OFF)
|
||||
|
||||
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
|
||||
|
||||
set(EXT_DEFAULT OFF)
|
||||
@@ -223,6 +222,8 @@ if (MSVC OR ANDROID)
|
||||
set(EXT_DEFAULT ON)
|
||||
endif()
|
||||
|
||||
option(YUZU_USE_BUNDLED_SDL3 "Download bundled SDL3 build" ${EXT_DEFAULT})
|
||||
|
||||
# ffmpeg
|
||||
option(YUZU_USE_BUNDLED_FFMPEG "Download bundled FFmpeg" ${EXT_DEFAULT})
|
||||
cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from external source" "${SOLARIS}" "NOT WIN32 AND NOT ANDROID" OFF)
|
||||
@@ -238,7 +239,7 @@ option(YUZU_USE_BUNDLED_SIRIT "Download bundled sirit" ${BUNDLED_SIRIT_DEFAULT})
|
||||
# FreeBSD 15+ has libusb, versions below should disable it
|
||||
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "WIN32 OR LINUX OR FREEBSD OR APPLE" OFF)
|
||||
|
||||
cmake_dependent_option(ENABLE_OPENGL "Enable OpenGL" ON "NOT (WIN32 AND ARCHITECTURE_arm64) AND NOT APPLE" OFF)
|
||||
cmake_dependent_option(ENABLE_OPENGL "Enable OpenGL" ON "NOT (WIN32 AND ARCHITECTURE_arm64) AND NOT APPLE AND NOT ANDROID" OFF)
|
||||
mark_as_advanced(FORCE ENABLE_OPENGL)
|
||||
|
||||
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
|
||||
@@ -512,7 +513,7 @@ endfunction()
|
||||
# =============================================
|
||||
|
||||
if (APPLE)
|
||||
foreach(fw Carbon Metal Cocoa IOKit CoreVideo CoreMedia Security UniformTypeIdentifiers)
|
||||
foreach(fw Carbon Metal Cocoa IOKit CoreVideo CoreMedia Security UniformTypeIdentifiers Foundation)
|
||||
find_library(${fw}_LIBRARY ${fw} REQUIRED)
|
||||
list(APPEND PLATFORM_LIBRARIES ${${fw}_LIBRARY})
|
||||
endforeach()
|
||||
|
||||
@@ -83,3 +83,16 @@ Once your request is processed, you will receive a confirmation email with your
|
||||
Alongside the other contribution methods listed up top, you can also choose to contribute through documentation, organization, or community guides. These can be done either through the code contribution methods described above, or created externally and shared via our Discord community.
|
||||
|
||||
If you have an external tool/page that you believe would be handy to integrate/link into Eden, please additionally email our developers at [`developers@eden-emu.dev`](mailto:developers@eden-emu.dev). **Do not submit vibe-coded or AI generated tools or applications**.
|
||||
|
||||
### Non-English Contributions
|
||||
|
||||
If you can't speak English or find more comfortable speaking in your native tongue, you may submit PR, commits, comments, and reviews in other languages. There is no restriction what languages are allowed, but maintainers will use translators if they're unable to understand.
|
||||
|
||||
Triage can speak:
|
||||
|
||||
- Chinese
|
||||
- Portuguese
|
||||
- Russian
|
||||
- Spanish
|
||||
|
||||
Documentation must be in American English, we don't have the capacity to support multilingual manuals. Code comments must remain in English for future referral.
|
||||
|
||||
+5
-16
@@ -1,12 +1,4 @@
|
||||
{
|
||||
"": {
|
||||
"ci": true,
|
||||
"hash": "9f50d993c39529e022ad456163de91ac5934e16faf8fc348f305355fc0a643c534f87ded707e11bd03bcbc0a1760bd20852b6533a67ac0558a078385181cb184",
|
||||
"name": "SDL3",
|
||||
"package": "SDL3",
|
||||
"repo": "crueter-ci/SDL3",
|
||||
"version": "3.4.14-1788231389-147a8ee32d"
|
||||
},
|
||||
"biscuit": {
|
||||
"hash": "1229f345b014f7ca544dedb4edb3311e41ba736f9aa9a67f88b5f26f3c983288c6bb6cdedcfb0b8a02c63088a37e6a0d7ba97d9c2a4d721b213916327cffe28a",
|
||||
"min_version": "0.9.1",
|
||||
@@ -68,10 +60,10 @@
|
||||
},
|
||||
"discord-rpc": {
|
||||
"find_args": "MODULE",
|
||||
"hash": "8213c43dcb0f7d479f5861091d111ed12fbdec1e62e6d729d65a4bc181d82f48a35d5fd3cd5c291f2393ac7c9681eabc6b76609755f55376284c8a8d67e148f3",
|
||||
"hash": "8d680b3a16d6f6bf292ad823cf8635595ff986f2a49f758e3009f505b540a9d75194a8cf44cddea75736a8c3e3b5160166e716a0939ce3f18cc463cf648753fe",
|
||||
"package": "DiscordRPC",
|
||||
"repo": "eden-emulator/discord-rpc",
|
||||
"version": "0d8b2d6a37"
|
||||
"version": "76616d8675"
|
||||
},
|
||||
"enet": {
|
||||
"find_args": "MODULE",
|
||||
@@ -186,12 +178,6 @@
|
||||
"repo": "eden-emulator/oaknut",
|
||||
"version": "v2.0.3"
|
||||
},
|
||||
"oboe": {
|
||||
"bundled": true,
|
||||
"hash": "ce4011afe7345370d4ead3b891cd69a5ef224b129535783586c0ca75051d303ed446e6c7f10bde8da31fff58d6e307f1732a3ffd03b249f9ef1fd48fd4132715",
|
||||
"repo": "google/oboe",
|
||||
"version": "1.10.0"
|
||||
},
|
||||
"openssl": {
|
||||
"hash": "29002ce50cb95a4f4f1d0e9d3f684401fbd4eac34203dc2eef3b6334af5d44aa46bf788b63a6f5c139c383eafb7269ae87a58a9a3ad5912903b9773e545ccc0a",
|
||||
"min_version": "3.0.0",
|
||||
@@ -317,6 +303,9 @@
|
||||
"find_args": "CONFIG",
|
||||
"hash": "deb5902ef8db0e329fbd5f3f4385eb0e26bdd9f14f3a2334823fb3fe18f36bc5d235d620d6e5f6fe3551ec3ea7038638899db8778c09f6d5c278f5ff95c3344b",
|
||||
"package": "VulkanMemoryAllocator",
|
||||
"patches": [
|
||||
"0001-macos-clang.patch"
|
||||
],
|
||||
"repo": "GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator",
|
||||
"version": "v3.3.0"
|
||||
},
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ The following options are desktop only.
|
||||
|
||||
- `ENABLE_LIBUSB` (ON) Enable the use of the libusb input backend (HIGHLY RECOMMENDED)
|
||||
- `ENABLE_OPENGL` (ON) Enable the OpenGL graphics backend
|
||||
- Unavailable on Windows/ARM64
|
||||
- Unavailable on Windows/ARM64 and on Android
|
||||
- You probably shouldn't turn this off.
|
||||
|
||||
### Qt
|
||||
|
||||
Vendored
+37
-43
@@ -136,48 +136,49 @@ if(ENABLE_CUBEB)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (NOT ANDROID)
|
||||
if (NOT YUZU_USE_BUNDLED_SDL3)
|
||||
if (NOT WIN32)
|
||||
# Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
|
||||
# Since 2.0.18 Atomic+Threads required for HIDAPI/libusb (see https://github.com/libsdl-org/SDL/issues/5095)
|
||||
# Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
|
||||
# CPUinfo also required for SDL Audio, at least until 2.28.0 (see https://github.com/libsdl-org/SDL/issues/7809)
|
||||
set(SDL_UNUSED_SUBSYSTEMS
|
||||
File Filesystem
|
||||
Locale Power Render)
|
||||
foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
|
||||
string(TOUPPER ${_SUB} _OPT)
|
||||
set(SDL_${_OPT} OFF)
|
||||
endforeach()
|
||||
if (NOT YUZU_USE_BUNDLED_SDL3)
|
||||
if (NOT WIN32)
|
||||
# Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
|
||||
# Since 2.0.18 Atomic+Threads required for HIDAPI/libusb (see https://github.com/libsdl-org/SDL/issues/5095)
|
||||
# Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
|
||||
# CPUinfo also required for SDL Audio, at least until 2.28.0 (see https://github.com/libsdl-org/SDL/issues/7809)
|
||||
set(SDL_UNUSED_SUBSYSTEMS
|
||||
File Filesystem
|
||||
Locale Power Render)
|
||||
foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
|
||||
string(TOUPPER ${_SUB} _OPT)
|
||||
set(SDL_${_OPT} OFF)
|
||||
endforeach()
|
||||
|
||||
set(HIDAPI ON)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
set(SDL_FILE ON)
|
||||
endif()
|
||||
|
||||
AddJsonPackage(sdl3)
|
||||
else()
|
||||
message(STATUS "Using bundled SDL3")
|
||||
AddJsonPackage(sdl3-ci)
|
||||
set(HIDAPI ON)
|
||||
endif()
|
||||
|
||||
# Normalize SDL3 link target across package variants.
|
||||
# Some SDL3 packages export only SDL3::SDL3-shared or SDL3::SDL3-static.
|
||||
if (NOT TARGET SDL3::SDL3)
|
||||
if (TARGET SDL3::SDL3-shared)
|
||||
add_library(SDL3::SDL3 ALIAS SDL3::SDL3-shared)
|
||||
elseif (TARGET SDL3::SDL3-static)
|
||||
add_library(SDL3::SDL3 ALIAS SDL3::SDL3-static)
|
||||
else()
|
||||
message(FATAL_ERROR "SDL3 package found, but no usable SDL3 target was exported")
|
||||
endif()
|
||||
if (APPLE)
|
||||
set(SDL_FILE ON)
|
||||
endif()
|
||||
|
||||
AddJsonPackage(sdl3)
|
||||
else()
|
||||
message(STATUS "Using bundled SDL3")
|
||||
AddJsonPackage(sdl3-ci)
|
||||
|
||||
# copy sdl java sources for consumption by Gradle
|
||||
if (ANDROID)
|
||||
file(COPY ${SDL3_SOURCE_DIR}/java DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/generated/sdl)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
# Normalize SDL3 link target across package variants.
|
||||
# Some SDL3 packages export only SDL3::SDL3-shared or SDL3::SDL3-static.
|
||||
if (NOT TARGET SDL3::SDL3)
|
||||
if (TARGET SDL3::SDL3-shared)
|
||||
add_library(SDL3::SDL3 ALIAS SDL3::SDL3-shared)
|
||||
elseif (TARGET SDL3::SDL3-static)
|
||||
add_library(SDL3::SDL3 ALIAS SDL3::SDL3-static)
|
||||
else()
|
||||
message(FATAL_ERROR "SDL3 package found, but no usable SDL3 target was exported")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# SPIRV Headers
|
||||
AddJsonPackage(spirv-headers)
|
||||
@@ -385,13 +386,6 @@ if (YUZU_CRASH_DUMPS AND NOT TARGET libbreakpad_client)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# oboe
|
||||
if (ANDROID)
|
||||
AddJsonPackage(oboe)
|
||||
|
||||
add_library(oboe::oboe ALIAS oboe)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
# moltenvk
|
||||
if (NOT YUZU_USE_BUNDLED_MOLTENVK)
|
||||
|
||||
Vendored
+1
@@ -11,6 +11,7 @@
|
||||
#include <limits>
|
||||
#include <span>
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <time.h>
|
||||
|
||||
namespace Tz {
|
||||
|
||||
@@ -272,6 +272,13 @@ android {
|
||||
resValue("string", "app_name_suffixed", "$currentName$suffix")
|
||||
resValue("string", "app_name", "Eden$suffix")
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
named("main") {
|
||||
java.srcDir("${edenDir}/externals/generated/sdl/java")
|
||||
kotlin.srcDir("${edenDir}/externals/generated/sdl/java")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
idea {
|
||||
|
||||
Vendored
+3
@@ -9,6 +9,9 @@
|
||||
-keep class org.ini4j.spi.IniBuilder
|
||||
-keep class org.ini4j.spi.IniFormatter
|
||||
|
||||
-keep class org.libsdl.app.** { *; }
|
||||
-keepclassmembers class org.libsdl.app.** { *; }
|
||||
|
||||
# Suppress warnings for R8
|
||||
-dontwarn org.bouncycastle.jsse.BCSSLParameters
|
||||
-dontwarn org.bouncycastle.jsse.BCSSLSocket
|
||||
|
||||
@@ -16,6 +16,7 @@ import android.widget.TextView
|
||||
import androidx.annotation.Keep
|
||||
import androidx.core.net.toUri
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import org.libsdl.app.SDL
|
||||
import java.lang.ref.WeakReference
|
||||
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
||||
import org.yuzu.yuzu_emu.fragments.CoreErrorDialogFragment
|
||||
@@ -52,6 +53,8 @@ object NativeLibrary {
|
||||
init {
|
||||
try {
|
||||
System.loadLibrary("yuzu-android")
|
||||
SDL.setupJNI()
|
||||
initJvm()
|
||||
} catch (ex: UnsatisfiedLinkError) {
|
||||
error("[NativeLibrary] $ex")
|
||||
}
|
||||
@@ -367,6 +370,7 @@ object NativeLibrary {
|
||||
NetPlayManager.clearChat()
|
||||
}
|
||||
|
||||
external fun initJvm()
|
||||
external fun initMultiplayer()
|
||||
|
||||
@Keep
|
||||
|
||||
@@ -22,7 +22,7 @@ add_library(yuzu-android SHARED
|
||||
set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR})
|
||||
|
||||
target_link_libraries(yuzu-android PRIVATE audio_core common core input_common frontend_common video_core)
|
||||
target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad jnigraphics log)
|
||||
target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad jnigraphics log GLESv2)
|
||||
if (ARCHITECTURE_arm64)
|
||||
target_link_libraries(yuzu-android PRIVATE adrenotools)
|
||||
endif()
|
||||
|
||||
@@ -1730,6 +1730,15 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_loadAmiibo(JNIEnv* env, jobject jobj,
|
||||
return static_cast<jint>(info);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_org_yuzu_yuzu_1emu_NativeLibrary_initJvm(JNIEnv *env, jclass clazz) {
|
||||
JavaVM *vm;
|
||||
if (env->GetJavaVM(&vm) != JNI_OK)
|
||||
return;
|
||||
|
||||
Common::Android::Initialize(vm, env);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_yuzu_yuzu_1emu_NativeLibrary_initMultiplayer(
|
||||
JNIEnv* env, [[maybe_unused]] jobject obj) {
|
||||
|
||||
@@ -800,7 +800,6 @@
|
||||
<string name="theme_mode_dark">تاریک</string>
|
||||
|
||||
<!-- Audio output engines -->
|
||||
<string name="oboe">oboe</string>
|
||||
<string name="cubeb">cubeb</string>
|
||||
|
||||
<!-- Anisotropic filtering options -->
|
||||
|
||||
@@ -465,13 +465,13 @@
|
||||
|
||||
<string-array name="outputEngineEntries">
|
||||
<item>@string/auto</item>
|
||||
<item>@string/oboe</item>
|
||||
<item>@string/sdl3</item>
|
||||
<item>@string/cubeb</item>
|
||||
<item>@string/string_null</item>
|
||||
</string-array>
|
||||
<integer-array name="outputEngineValues">
|
||||
<item>0</item>
|
||||
<item>4</item>
|
||||
<item>2</item>
|
||||
<item>1</item>
|
||||
<item>3</item>
|
||||
</integer-array>
|
||||
|
||||
@@ -1240,7 +1240,7 @@
|
||||
<string name="theme_mode_dark">Dark</string>
|
||||
|
||||
<!-- Audio output engines -->
|
||||
<string name="oboe" translatable="false">oboe</string>
|
||||
<string name="sdl3" translatable="false">SDL3</string>
|
||||
<string name="cubeb" translatable="false">cubeb</string>
|
||||
|
||||
<!-- Anisotropic filtering options -->
|
||||
|
||||
@@ -238,20 +238,11 @@ if (ENABLE_CUBEB)
|
||||
target_compile_definitions(audio_core PRIVATE HAVE_CUBEB=1)
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
target_sources(audio_core PRIVATE
|
||||
sink/oboe_sink.cpp
|
||||
sink/oboe_sink.h)
|
||||
target_sources(audio_core PRIVATE
|
||||
sink/sdl3_sink.cpp
|
||||
sink/sdl3_sink.h)
|
||||
|
||||
target_link_libraries(audio_core PRIVATE oboe)
|
||||
target_compile_definitions(audio_core PUBLIC HAVE_OBOE)
|
||||
else()
|
||||
target_sources(audio_core PRIVATE
|
||||
sink/sdl3_sink.cpp
|
||||
sink/sdl3_sink.h)
|
||||
|
||||
target_link_libraries(audio_core PRIVATE SDL3::SDL3)
|
||||
target_compile_definitions(audio_core PRIVATE HAVE_SDL3)
|
||||
endif()
|
||||
target_link_libraries(audio_core PRIVATE SDL3::SDL3)
|
||||
target_compile_definitions(audio_core PRIVATE HAVE_SDL3)
|
||||
|
||||
create_target_directory_groups(audio_core)
|
||||
|
||||
@@ -1,230 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
#include <oboe/Oboe.h>
|
||||
|
||||
#include "audio_core/common/common.h"
|
||||
#include "audio_core/sink/oboe_sink.h"
|
||||
#include "audio_core/sink/sink_stream.h"
|
||||
#include "common/logging.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "core/core.h"
|
||||
|
||||
namespace AudioCore::Sink {
|
||||
|
||||
class OboeSinkStream final : public SinkStream,
|
||||
public oboe::AudioStreamDataCallback,
|
||||
public oboe::AudioStreamErrorCallback {
|
||||
public:
|
||||
explicit OboeSinkStream(Core::System& system_, StreamType type_, const std::string& name_,
|
||||
u32 system_channels_)
|
||||
: SinkStream(system_, type_) {
|
||||
name = name_;
|
||||
system_channels = system_channels_;
|
||||
|
||||
this->OpenStream();
|
||||
}
|
||||
|
||||
~OboeSinkStream() override {
|
||||
LOG_INFO(Audio_Sink, "Destroyed Oboe stream");
|
||||
}
|
||||
|
||||
void Finalize() override {
|
||||
this->Stop();
|
||||
m_stream.reset();
|
||||
}
|
||||
|
||||
void Start(bool resume = false) override {
|
||||
if (!m_stream || !paused) {
|
||||
return;
|
||||
}
|
||||
|
||||
paused = false;
|
||||
|
||||
if (m_stream->start() != oboe::Result::OK) {
|
||||
LOG_CRITICAL(Audio_Sink, "Error starting Oboe stream");
|
||||
}
|
||||
}
|
||||
|
||||
void Stop() override {
|
||||
if (!m_stream || paused) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->SignalPause();
|
||||
|
||||
if (m_stream->stop() != oboe::Result::OK) {
|
||||
LOG_CRITICAL(Audio_Sink, "Error stopping Oboe stream");
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
static s32 QueryChannelCount(oboe::Direction direction) {
|
||||
std::shared_ptr<oboe::AudioStream> temp_stream;
|
||||
oboe::AudioStreamBuilder builder;
|
||||
|
||||
const auto result = ConfigureBuilder(builder, direction)->openStream(temp_stream);
|
||||
if (result == oboe::Result::OK) {
|
||||
return temp_stream->getChannelCount() >= 6 ? 6 : 2;
|
||||
}
|
||||
|
||||
LOG_ERROR(Audio_Sink, "Failed to open {} stream. Using default channel count 2",
|
||||
direction == oboe::Direction::Output ? "output" : "input");
|
||||
return 2;
|
||||
}
|
||||
|
||||
protected:
|
||||
oboe::DataCallbackResult onAudioReady(oboe::AudioStream*, void* audio_data,
|
||||
s32 num_buffer_frames) override {
|
||||
const size_t num_channels = this->GetDeviceChannels();
|
||||
const size_t frame_size = num_channels;
|
||||
const size_t num_frames = static_cast<size_t>(num_buffer_frames);
|
||||
|
||||
if (type == StreamType::In) {
|
||||
std::span<const s16> input_buffer{reinterpret_cast<const s16*>(audio_data),
|
||||
num_frames * frame_size};
|
||||
this->ProcessAudioIn(input_buffer, num_frames);
|
||||
} else {
|
||||
std::span<s16> output_buffer{reinterpret_cast<s16*>(audio_data),
|
||||
num_frames * frame_size};
|
||||
this->ProcessAudioOutAndRender(output_buffer, num_frames);
|
||||
}
|
||||
|
||||
return oboe::DataCallbackResult::Continue;
|
||||
}
|
||||
|
||||
void onErrorAfterClose(oboe::AudioStream*, oboe::Result) override {
|
||||
LOG_INFO(Audio_Sink, "Audio stream closed, reinitializing");
|
||||
|
||||
if (this->OpenStream()) {
|
||||
m_stream->start();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static oboe::AudioStreamBuilder* ConfigureBuilder(oboe::AudioStreamBuilder& builder,
|
||||
oboe::Direction direction) {
|
||||
// TODO: investigate callback delay issues when using AAudio
|
||||
return builder.setPerformanceMode(oboe::PerformanceMode::LowLatency)
|
||||
->setAudioApi(oboe::AudioApi::OpenSLES)
|
||||
->setDirection(direction)
|
||||
->setSampleRate(TargetSampleRate)
|
||||
->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::High)
|
||||
->setFormat(oboe::AudioFormat::I16)
|
||||
->setFormatConversionAllowed(true)
|
||||
->setUsage(oboe::Usage::Game)
|
||||
->setBufferCapacityInFrames(TargetSampleCount * 2);
|
||||
}
|
||||
|
||||
bool OpenStream() {
|
||||
const auto direction = [&]() {
|
||||
switch (type) {
|
||||
case StreamType::In:
|
||||
return oboe::Direction::Input;
|
||||
case StreamType::Out:
|
||||
case StreamType::Render:
|
||||
return oboe::Direction::Output;
|
||||
default:
|
||||
ASSERT(false);
|
||||
return oboe::Direction::Output;
|
||||
}
|
||||
}();
|
||||
|
||||
const auto expected_channels = QueryChannelCount(direction);
|
||||
const auto expected_mask = [&]() {
|
||||
switch (expected_channels) {
|
||||
case 1:
|
||||
return oboe::ChannelMask::Mono;
|
||||
case 2:
|
||||
return oboe::ChannelMask::Stereo;
|
||||
case 6:
|
||||
return oboe::ChannelMask::CM5Point1;
|
||||
default:
|
||||
ASSERT(false);
|
||||
return oboe::ChannelMask::Unspecified;
|
||||
}
|
||||
}();
|
||||
|
||||
oboe::AudioStreamBuilder builder;
|
||||
const auto result = ConfigureBuilder(builder, direction)
|
||||
->setChannelCount(expected_channels)
|
||||
->setChannelMask(expected_mask)
|
||||
->setChannelConversionAllowed(true)
|
||||
->setDataCallback(this)
|
||||
->setErrorCallback(this)
|
||||
->openStream(m_stream);
|
||||
ASSERT(result == oboe::Result::OK);
|
||||
return result == oboe::Result::OK && this->SetStreamProperties();
|
||||
}
|
||||
|
||||
bool SetStreamProperties() {
|
||||
ASSERT(m_stream);
|
||||
|
||||
m_stream->setBufferSizeInFrames(TargetSampleCount * 2);
|
||||
device_channels = m_stream->getChannelCount();
|
||||
|
||||
const auto sample_rate = m_stream->getSampleRate();
|
||||
const auto buffer_capacity = m_stream->getBufferCapacityInFrames();
|
||||
const auto stream_backend =
|
||||
m_stream->getAudioApi() == oboe::AudioApi::AAudio ? "AAudio" : "OpenSLES";
|
||||
|
||||
LOG_INFO(Audio_Sink, "Opened Oboe {} stream with {} channels sample rate {} capacity {}",
|
||||
stream_backend, device_channels, sample_rate, buffer_capacity);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<oboe::AudioStream> m_stream{};
|
||||
};
|
||||
|
||||
OboeSink::OboeSink() {
|
||||
// TODO: This is not generally knowable
|
||||
// The channel count is distinct based on direction and can change
|
||||
device_channels = OboeSinkStream::QueryChannelCount(oboe::Direction::Output);
|
||||
}
|
||||
|
||||
OboeSink::~OboeSink() = default;
|
||||
|
||||
SinkStream* OboeSink::AcquireSinkStream(Core::System& system, u32 system_channels,
|
||||
const std::string& name, StreamType type) {
|
||||
SinkStreamPtr& stream = sink_streams.emplace_back(
|
||||
std::make_unique<OboeSinkStream>(system, type, name, system_channels));
|
||||
|
||||
return stream.get();
|
||||
}
|
||||
|
||||
void OboeSink::CloseStream(SinkStream* to_remove) {
|
||||
sink_streams.remove_if([&](auto& stream) { return stream.get() == to_remove; });
|
||||
}
|
||||
|
||||
void OboeSink::CloseStreams() {
|
||||
sink_streams.clear();
|
||||
}
|
||||
|
||||
f32 OboeSink::GetDeviceVolume() const {
|
||||
if (sink_streams.empty()) {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
return sink_streams.front()->GetDeviceVolume();
|
||||
}
|
||||
|
||||
void OboeSink::SetDeviceVolume(f32 volume) {
|
||||
for (auto& stream : sink_streams) {
|
||||
stream->SetDeviceVolume(volume);
|
||||
}
|
||||
}
|
||||
|
||||
void OboeSink::SetSystemVolume(f32 volume) {
|
||||
for (auto& stream : sink_streams) {
|
||||
stream->SetSystemVolume(volume);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AudioCore::Sink
|
||||
@@ -1,75 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#include "audio_core/sink/sink.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace AudioCore::Sink {
|
||||
class SinkStream;
|
||||
|
||||
class OboeSink final : public Sink {
|
||||
public:
|
||||
explicit OboeSink();
|
||||
~OboeSink() override;
|
||||
|
||||
/**
|
||||
* Create a new sink stream.
|
||||
*
|
||||
* @param system - Core system.
|
||||
* @param system_channels - Number of channels the audio system expects.
|
||||
* May differ from the device's channel count.
|
||||
* @param name - Name of this stream.
|
||||
* @param type - Type of this stream, render/in/out.
|
||||
*
|
||||
* @return A pointer to the created SinkStream
|
||||
*/
|
||||
SinkStream* AcquireSinkStream(Core::System& system, u32 system_channels,
|
||||
const std::string& name, StreamType type) override;
|
||||
|
||||
/**
|
||||
* Close a given stream.
|
||||
*
|
||||
* @param stream - The stream to close.
|
||||
*/
|
||||
void CloseStream(SinkStream* stream) override;
|
||||
|
||||
/**
|
||||
* Close all streams.
|
||||
*/
|
||||
void CloseStreams() override;
|
||||
|
||||
/**
|
||||
* Get the device volume. Set from calls to the IAudioDevice service.
|
||||
*
|
||||
* @return Volume of the device.
|
||||
*/
|
||||
f32 GetDeviceVolume() const override;
|
||||
|
||||
/**
|
||||
* Set the device volume. Set from calls to the IAudioDevice service.
|
||||
*
|
||||
* @param volume - New volume of the device.
|
||||
*/
|
||||
void SetDeviceVolume(f32 volume) override;
|
||||
|
||||
/**
|
||||
* Set the system volume. Comes from the audio system using this stream.
|
||||
*
|
||||
* @param volume - New volume of the system.
|
||||
*/
|
||||
void SetSystemVolume(f32 volume) override;
|
||||
|
||||
private:
|
||||
/// List of streams managed by this sink
|
||||
std::list<SinkStreamPtr> sink_streams{};
|
||||
};
|
||||
|
||||
} // namespace AudioCore::Sink
|
||||
@@ -10,9 +10,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "audio_core/sink/sink_details.h"
|
||||
#ifdef HAVE_OBOE
|
||||
#include "audio_core/sink/oboe_sink.h"
|
||||
#endif
|
||||
#ifdef HAVE_CUBEB
|
||||
#include "audio_core/sink/cubeb_sink.h"
|
||||
#endif
|
||||
@@ -43,24 +40,8 @@ struct SinkDetails {
|
||||
/// SuitableFn is_suitable; // REVERTED FOR LatencyFn latency ABOVE - DIABLO 3 FIX
|
||||
};
|
||||
|
||||
// NOTE TO PROBABLY FIX LATER FOR ANDROID - the return value "0u" for the first HAVE_OBOE
|
||||
// section below was just copied from the null section so there's a somewhat valid value
|
||||
// being returned, since the previous "true" value probably isn't compatible with the
|
||||
// previous EA-3833 code. (HAVE_OBOE was introduced in a later release.) Eventually need
|
||||
// to change "0u" for something else directly from the oboe_sink.cpp functions.
|
||||
|
||||
// sink_details is ordered in terms of desirability, with the best choice at the top.
|
||||
constexpr SinkDetails sink_details[] = {
|
||||
#ifdef HAVE_OBOE
|
||||
SinkDetails{
|
||||
Settings::AudioEngine::Oboe,
|
||||
[](std::string_view device_id) -> std::unique_ptr<Sink> {
|
||||
return std::make_unique<OboeSink>();
|
||||
},
|
||||
[](bool capture) { return std::vector<std::string>{"Default"}; },
|
||||
[]() { return 0u; },
|
||||
},
|
||||
#endif
|
||||
#ifdef HAVE_CUBEB
|
||||
SinkDetails{
|
||||
Settings::AudioEngine::Cubeb,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "android_common.h"
|
||||
@@ -51,7 +51,7 @@ jstring ToJString(JNIEnv* env, std::u16string_view str) {
|
||||
}
|
||||
|
||||
double GetJDouble(JNIEnv* env, jobject jdouble) {
|
||||
return env->GetDoubleField(jdouble, GetDoubleValueField());
|
||||
return env->CallDoubleMethod(jdouble, GetDoubleValueMethod());
|
||||
}
|
||||
|
||||
jobject ToJDouble(JNIEnv* env, double value) {
|
||||
@@ -59,7 +59,7 @@ jobject ToJDouble(JNIEnv* env, double value) {
|
||||
}
|
||||
|
||||
s32 GetJInteger(JNIEnv* env, jobject jinteger) {
|
||||
return env->GetIntField(jinteger, GetIntegerValueField());
|
||||
return env->CallIntMethod(jinteger, GetIntegerValueMethod());
|
||||
}
|
||||
|
||||
jobject ToJInteger(JNIEnv* env, s32 value) {
|
||||
@@ -67,7 +67,7 @@ jobject ToJInteger(JNIEnv* env, s32 value) {
|
||||
}
|
||||
|
||||
bool GetJBoolean(JNIEnv* env, jobject jboolean) {
|
||||
return env->GetBooleanField(jboolean, GetBooleanValueField());
|
||||
return env->CallBooleanMethod(jboolean, GetBooleanValueMethod());
|
||||
}
|
||||
|
||||
jobject ToJBoolean(JNIEnv* env, bool value) {
|
||||
|
||||
+188
-192
@@ -63,15 +63,15 @@ static jfieldID s_patch_title_id_field;
|
||||
|
||||
static jclass s_double_class;
|
||||
static jmethodID s_double_constructor;
|
||||
static jfieldID s_double_value_field;
|
||||
static jmethodID s_double_value_method;
|
||||
|
||||
static jclass s_integer_class;
|
||||
static jmethodID s_integer_constructor;
|
||||
static jfieldID s_integer_value_field;
|
||||
static jmethodID s_integer_value_method;
|
||||
|
||||
static jclass s_boolean_class;
|
||||
static jmethodID s_boolean_constructor;
|
||||
static jfieldID s_boolean_value_field;
|
||||
static jmethodID s_boolean_value_method;
|
||||
|
||||
static jclass s_player_input_class;
|
||||
static jmethodID s_player_input_constructor;
|
||||
@@ -103,7 +103,6 @@ static jmethodID s_clear_chat;
|
||||
static constexpr jint JNI_VERSION = JNI_VERSION_1_6;
|
||||
|
||||
namespace Common::Android {
|
||||
|
||||
JNIEnv *GetEnvForThread() {
|
||||
thread_local static struct OwnedEnv {
|
||||
OwnedEnv() {
|
||||
@@ -299,8 +298,8 @@ namespace Common::Android {
|
||||
return s_double_constructor;
|
||||
}
|
||||
|
||||
jfieldID GetDoubleValueField() {
|
||||
return s_double_value_field;
|
||||
jmethodID GetDoubleValueMethod() {
|
||||
return s_double_value_method;
|
||||
}
|
||||
|
||||
jclass GetIntegerClass() {
|
||||
@@ -311,8 +310,8 @@ namespace Common::Android {
|
||||
return s_integer_constructor;
|
||||
}
|
||||
|
||||
jfieldID GetIntegerValueField() {
|
||||
return s_integer_value_field;
|
||||
jmethodID GetIntegerValueMethod() {
|
||||
return s_integer_value_method;
|
||||
}
|
||||
|
||||
jclass GetBooleanClass() {
|
||||
@@ -323,8 +322,8 @@ namespace Common::Android {
|
||||
return s_boolean_constructor;
|
||||
}
|
||||
|
||||
jfieldID GetBooleanValueField() {
|
||||
return s_boolean_value_field;
|
||||
jmethodID GetBooleanValueMethod() {
|
||||
return s_boolean_value_method;
|
||||
}
|
||||
|
||||
jclass GetPlayerInputClass() {
|
||||
@@ -429,188 +428,6 @@ namespace Common::Android {
|
||||
|
||||
jint InitFFmpegOnLoad(JavaVM *vm);
|
||||
|
||||
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
s_java_vm = vm;
|
||||
InitFFmpegOnLoad(vm);
|
||||
|
||||
JNIEnv *env;
|
||||
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION) != JNI_OK)
|
||||
return JNI_ERR;
|
||||
|
||||
// Initialize Java classes
|
||||
const jclass native_library_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary");
|
||||
s_native_library_class = reinterpret_cast<jclass>(env->NewGlobalRef(native_library_class));
|
||||
s_disk_cache_progress_class = reinterpret_cast<jclass>(env->NewGlobalRef(
|
||||
env->FindClass("org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress")));
|
||||
s_load_callback_stage_class = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass(
|
||||
"org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress$LoadCallbackStage")));
|
||||
|
||||
const jclass game_dir_class = env->FindClass("org/yuzu/yuzu_emu/model/GameDir");
|
||||
s_game_dir_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_dir_class));
|
||||
s_game_dir_constructor = env->GetMethodID(game_dir_class, "<init>",
|
||||
"(Ljava/lang/String;Z)V");
|
||||
env->DeleteLocalRef(game_dir_class);
|
||||
|
||||
// Initialize methods
|
||||
s_exit_emulation_activity =
|
||||
env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V");
|
||||
s_disk_cache_load_progress =
|
||||
env->GetStaticMethodID(s_disk_cache_progress_class, "loadProgress", "(III)V");
|
||||
s_copy_to_storage = env->GetStaticMethodID(s_native_library_class, "copyFileToStorage",
|
||||
"(Ljava/lang/String;Ljava/lang/String;)Z");
|
||||
s_file_exists = env->GetStaticMethodID(s_native_library_class, "exists",
|
||||
"(Ljava/lang/String;)Z");
|
||||
s_file_extension = env->GetStaticMethodID(s_native_library_class, "getFileExtension",
|
||||
"(Ljava/lang/String;)Ljava/lang/String;");
|
||||
s_on_emulation_started =
|
||||
env->GetStaticMethodID(s_native_library_class, "onEmulationStarted", "()V");
|
||||
s_on_emulation_stopped =
|
||||
env->GetStaticMethodID(s_native_library_class, "onEmulationStopped", "(I)V");
|
||||
s_on_program_changed =
|
||||
env->GetStaticMethodID(s_native_library_class, "onProgramChanged", "(I)V");
|
||||
|
||||
const jclass game_class = env->FindClass("org/yuzu/yuzu_emu/model/Game");
|
||||
s_game_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_class));
|
||||
s_game_constructor = env->GetMethodID(game_class, "<init>",
|
||||
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
|
||||
"String;Ljava/lang/String;Ljava/lang/String;Z)V");
|
||||
s_game_title_field = env->GetFieldID(game_class, "title", "Ljava/lang/String;");
|
||||
s_game_path_field = env->GetFieldID(game_class, "path", "Ljava/lang/String;");
|
||||
s_game_program_id_field = env->GetFieldID(game_class, "programId", "Ljava/lang/String;");
|
||||
s_game_developer_field = env->GetFieldID(game_class, "developer", "Ljava/lang/String;");
|
||||
s_game_version_field = env->GetFieldID(game_class, "version", "Ljava/lang/String;");
|
||||
s_game_is_homebrew_field = env->GetFieldID(game_class, "isHomebrew", "Z");
|
||||
env->DeleteLocalRef(game_class);
|
||||
|
||||
const jclass string_class = env->FindClass("java/lang/String");
|
||||
s_string_class = reinterpret_cast<jclass>(env->NewGlobalRef(string_class));
|
||||
env->DeleteLocalRef(string_class);
|
||||
|
||||
const jclass pair_class = env->FindClass("kotlin/Pair");
|
||||
s_pair_class = reinterpret_cast<jclass>(env->NewGlobalRef(pair_class));
|
||||
s_pair_constructor =
|
||||
env->GetMethodID(pair_class, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V");
|
||||
s_pair_first_field = env->GetFieldID(pair_class, "first", "Ljava/lang/Object;");
|
||||
s_pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;");
|
||||
env->DeleteLocalRef(pair_class);
|
||||
|
||||
const jclass overlay_control_data_class =
|
||||
env->FindClass("org/yuzu/yuzu_emu/overlay/model/OverlayControlData");
|
||||
s_overlay_control_data_class =
|
||||
reinterpret_cast<jclass>(env->NewGlobalRef(overlay_control_data_class));
|
||||
s_overlay_control_data_constructor =
|
||||
env->GetMethodID(overlay_control_data_class, "<init>",
|
||||
"(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;F)V");
|
||||
s_overlay_control_data_id_field =
|
||||
env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;");
|
||||
s_overlay_control_data_enabled_field =
|
||||
env->GetFieldID(overlay_control_data_class, "enabled", "Z");
|
||||
s_overlay_control_data_landscape_position_field =
|
||||
env->GetFieldID(overlay_control_data_class, "landscapePosition", "Lkotlin/Pair;");
|
||||
s_overlay_control_data_portrait_position_field =
|
||||
env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;");
|
||||
s_overlay_control_data_foldable_position_field =
|
||||
env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;");
|
||||
s_overlay_control_data_individual_scale_field =
|
||||
env->GetFieldID(overlay_control_data_class, "individualScale", "F");
|
||||
env->DeleteLocalRef(overlay_control_data_class);
|
||||
|
||||
const jclass patch_class = env->FindClass("org/yuzu/yuzu_emu/model/Patch");
|
||||
s_patch_class = reinterpret_cast<jclass>(env->NewGlobalRef(patch_class));
|
||||
s_patch_constructor = env->GetMethodID(
|
||||
patch_class, "<init>",
|
||||
"(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JI)V");
|
||||
s_patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z");
|
||||
s_patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;");
|
||||
s_patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;");
|
||||
s_patch_type_field = env->GetFieldID(patch_class, "type", "I");
|
||||
s_patch_program_id_field = env->GetFieldID(patch_class, "programId", "Ljava/lang/String;");
|
||||
s_patch_title_id_field = env->GetFieldID(patch_class, "titleId", "Ljava/lang/String;");
|
||||
env->DeleteLocalRef(patch_class);
|
||||
|
||||
const jclass double_class = env->FindClass("java/lang/Double");
|
||||
s_double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class));
|
||||
s_double_constructor = env->GetMethodID(double_class, "<init>", "(D)V");
|
||||
s_double_value_field = env->GetFieldID(double_class, "value", "D");
|
||||
env->DeleteLocalRef(double_class);
|
||||
|
||||
const jclass int_class = env->FindClass("java/lang/Integer");
|
||||
s_integer_class = reinterpret_cast<jclass>(env->NewGlobalRef(int_class));
|
||||
s_integer_constructor = env->GetMethodID(int_class, "<init>", "(I)V");
|
||||
s_integer_value_field = env->GetFieldID(int_class, "value", "I");
|
||||
env->DeleteLocalRef(int_class);
|
||||
|
||||
const jclass boolean_class = env->FindClass("java/lang/Boolean");
|
||||
s_boolean_class = reinterpret_cast<jclass>(env->NewGlobalRef(boolean_class));
|
||||
s_boolean_constructor = env->GetMethodID(boolean_class, "<init>", "(Z)V");
|
||||
s_boolean_value_field = env->GetFieldID(boolean_class, "value", "Z");
|
||||
env->DeleteLocalRef(boolean_class);
|
||||
|
||||
const jclass player_input_class =
|
||||
env->FindClass("org/yuzu/yuzu_emu/features/input/model/PlayerInput");
|
||||
s_player_input_class = reinterpret_cast<jclass>(env->NewGlobalRef(player_input_class));
|
||||
s_player_input_constructor = env->GetMethodID(
|
||||
player_input_class, "<init>",
|
||||
"(Z[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZIJJJJLjava/lang/String;Z)V");
|
||||
s_player_input_connected_field = env->GetFieldID(player_input_class, "connected", "Z");
|
||||
s_player_input_buttons_field =
|
||||
env->GetFieldID(player_input_class, "buttons", "[Ljava/lang/String;");
|
||||
s_player_input_analogs_field =
|
||||
env->GetFieldID(player_input_class, "analogs", "[Ljava/lang/String;");
|
||||
s_player_input_motions_field =
|
||||
env->GetFieldID(player_input_class, "motions", "[Ljava/lang/String;");
|
||||
s_player_input_vibration_enabled_field =
|
||||
env->GetFieldID(player_input_class, "vibrationEnabled", "Z");
|
||||
s_player_input_vibration_strength_field =
|
||||
env->GetFieldID(player_input_class, "vibrationStrength", "I");
|
||||
s_player_input_body_color_left_field =
|
||||
env->GetFieldID(player_input_class, "bodyColorLeft", "J");
|
||||
s_player_input_body_color_right_field =
|
||||
env->GetFieldID(player_input_class, "bodyColorRight", "J");
|
||||
s_player_input_button_color_left_field =
|
||||
env->GetFieldID(player_input_class, "buttonColorLeft", "J");
|
||||
s_player_input_button_color_right_field =
|
||||
env->GetFieldID(player_input_class, "buttonColorRight", "J");
|
||||
s_player_input_profile_name_field =
|
||||
env->GetFieldID(player_input_class, "profileName", "Ljava/lang/String;");
|
||||
s_player_input_use_system_vibrator_field =
|
||||
env->GetFieldID(player_input_class, "useSystemVibrator", "Z");
|
||||
env->DeleteLocalRef(player_input_class);
|
||||
|
||||
const jclass yuzu_input_device_interface =
|
||||
env->FindClass("org/yuzu/yuzu_emu/features/input/YuzuInputDevice");
|
||||
s_yuzu_input_device_interface =
|
||||
reinterpret_cast<jclass>(env->NewGlobalRef(yuzu_input_device_interface));
|
||||
s_yuzu_input_device_get_name =
|
||||
env->GetMethodID(yuzu_input_device_interface, "getName", "()Ljava/lang/String;");
|
||||
s_yuzu_input_device_get_guid =
|
||||
env->GetMethodID(yuzu_input_device_interface, "getGUID", "()Ljava/lang/String;");
|
||||
s_yuzu_input_device_get_port = env->GetMethodID(yuzu_input_device_interface, "getPort",
|
||||
"()I");
|
||||
s_yuzu_input_device_get_supports_vibration =
|
||||
env->GetMethodID(yuzu_input_device_interface, "getSupportsVibration", "()Z");
|
||||
s_yuzu_input_device_vibrate = env->GetMethodID(yuzu_input_device_interface, "vibrate",
|
||||
"(F)V");
|
||||
s_yuzu_input_device_get_axes =
|
||||
env->GetMethodID(yuzu_input_device_interface, "getAxes", "()[Ljava/lang/Integer;");
|
||||
s_yuzu_input_device_has_keys =
|
||||
env->GetMethodID(yuzu_input_device_interface, "hasKeys", "([I)[Z");
|
||||
env->DeleteLocalRef(yuzu_input_device_interface);
|
||||
s_add_netplay_message = env->GetStaticMethodID(s_native_library_class, "addNetPlayMessage",
|
||||
"(ILjava/lang/String;)V");
|
||||
s_clear_chat = env->GetStaticMethodID(s_native_library_class, "clearChat", "()V");
|
||||
|
||||
|
||||
// Initialize Android Storage
|
||||
Common::FS::Android::RegisterCallbacks(env, s_native_library_class);
|
||||
|
||||
// Initialize applets
|
||||
Common::Android::SoftwareKeyboard::InitJNI(env);
|
||||
Common::Android::WebBrowser::InitJNI(env);
|
||||
|
||||
return JNI_VERSION;
|
||||
}
|
||||
|
||||
void JNI_OnUnload(JavaVM *vm, void *reserved) {
|
||||
JNIEnv *env;
|
||||
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION) != JNI_OK) {
|
||||
@@ -645,4 +462,183 @@ namespace Common::Android {
|
||||
}
|
||||
#endif
|
||||
|
||||
void Initialize(JavaVM* vm, JNIEnv *env) {
|
||||
s_java_vm = vm;
|
||||
InitFFmpegOnLoad(vm);
|
||||
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionClear();
|
||||
}
|
||||
|
||||
// Initialize Java classes
|
||||
const jclass native_library_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary");
|
||||
s_native_library_class = reinterpret_cast<jclass>(env->NewGlobalRef(native_library_class));
|
||||
s_disk_cache_progress_class = reinterpret_cast<jclass>(env->NewGlobalRef(
|
||||
env->FindClass("org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress")));
|
||||
s_load_callback_stage_class = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass(
|
||||
"org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress$LoadCallbackStage")));
|
||||
|
||||
const jclass game_dir_class = env->FindClass("org/yuzu/yuzu_emu/model/GameDir");
|
||||
s_game_dir_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_dir_class));
|
||||
s_game_dir_constructor = env->GetMethodID(game_dir_class, "<init>",
|
||||
"(Ljava/lang/String;Z)V");
|
||||
env->DeleteLocalRef(game_dir_class);
|
||||
|
||||
// Initialize methods
|
||||
s_exit_emulation_activity =
|
||||
env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V");
|
||||
s_disk_cache_load_progress =
|
||||
env->GetStaticMethodID(s_disk_cache_progress_class, "loadProgress", "(III)V");
|
||||
s_copy_to_storage = env->GetStaticMethodID(s_native_library_class, "copyFileToStorage",
|
||||
"(Ljava/lang/String;Ljava/lang/String;)Z");
|
||||
s_file_exists = env->GetStaticMethodID(s_native_library_class, "exists",
|
||||
"(Ljava/lang/String;)Z");
|
||||
s_file_extension = env->GetStaticMethodID(s_native_library_class, "getFileExtension",
|
||||
"(Ljava/lang/String;)Ljava/lang/String;");
|
||||
s_on_emulation_started =
|
||||
env->GetStaticMethodID(s_native_library_class, "onEmulationStarted", "()V");
|
||||
s_on_emulation_stopped =
|
||||
env->GetStaticMethodID(s_native_library_class, "onEmulationStopped", "(I)V");
|
||||
s_on_program_changed =
|
||||
env->GetStaticMethodID(s_native_library_class, "onProgramChanged", "(I)V");
|
||||
|
||||
const jclass game_class = env->FindClass("org/yuzu/yuzu_emu/model/Game");
|
||||
s_game_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_class));
|
||||
s_game_constructor = env->GetMethodID(game_class, "<init>",
|
||||
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
|
||||
"String;Ljava/lang/String;Ljava/lang/String;Z)V");
|
||||
s_game_title_field = env->GetFieldID(game_class, "title", "Ljava/lang/String;");
|
||||
s_game_path_field = env->GetFieldID(game_class, "path", "Ljava/lang/String;");
|
||||
s_game_program_id_field = env->GetFieldID(game_class, "programId", "Ljava/lang/String;");
|
||||
s_game_developer_field = env->GetFieldID(game_class, "developer", "Ljava/lang/String;");
|
||||
s_game_version_field = env->GetFieldID(game_class, "version", "Ljava/lang/String;");
|
||||
s_game_is_homebrew_field = env->GetFieldID(game_class, "isHomebrew", "Z");
|
||||
env->DeleteLocalRef(game_class);
|
||||
|
||||
const jclass string_class = env->FindClass("java/lang/String");
|
||||
s_string_class = reinterpret_cast<jclass>(env->NewGlobalRef(string_class));
|
||||
env->DeleteLocalRef(string_class);
|
||||
|
||||
const jclass pair_class = env->FindClass("kotlin/Pair");
|
||||
s_pair_class = reinterpret_cast<jclass>(env->NewGlobalRef(pair_class));
|
||||
s_pair_constructor =
|
||||
env->GetMethodID(pair_class, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V");
|
||||
s_pair_first_field = env->GetFieldID(pair_class, "first", "Ljava/lang/Object;");
|
||||
s_pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;");
|
||||
env->DeleteLocalRef(pair_class);
|
||||
|
||||
const jclass overlay_control_data_class =
|
||||
env->FindClass("org/yuzu/yuzu_emu/overlay/model/OverlayControlData");
|
||||
s_overlay_control_data_class =
|
||||
reinterpret_cast<jclass>(env->NewGlobalRef(overlay_control_data_class));
|
||||
s_overlay_control_data_constructor =
|
||||
env->GetMethodID(overlay_control_data_class, "<init>",
|
||||
"(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;F)V");
|
||||
s_overlay_control_data_id_field =
|
||||
env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;");
|
||||
s_overlay_control_data_enabled_field =
|
||||
env->GetFieldID(overlay_control_data_class, "enabled", "Z");
|
||||
s_overlay_control_data_landscape_position_field =
|
||||
env->GetFieldID(overlay_control_data_class, "landscapePosition", "Lkotlin/Pair;");
|
||||
s_overlay_control_data_portrait_position_field =
|
||||
env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;");
|
||||
s_overlay_control_data_foldable_position_field =
|
||||
env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;");
|
||||
s_overlay_control_data_individual_scale_field =
|
||||
env->GetFieldID(overlay_control_data_class, "individualScale", "F");
|
||||
env->DeleteLocalRef(overlay_control_data_class);
|
||||
|
||||
const jclass patch_class = env->FindClass("org/yuzu/yuzu_emu/model/Patch");
|
||||
s_patch_class = reinterpret_cast<jclass>(env->NewGlobalRef(patch_class));
|
||||
s_patch_constructor = env->GetMethodID(
|
||||
patch_class, "<init>",
|
||||
"(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JI)V");
|
||||
s_patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z");
|
||||
s_patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;");
|
||||
s_patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;");
|
||||
s_patch_type_field = env->GetFieldID(patch_class, "type", "I");
|
||||
s_patch_program_id_field = env->GetFieldID(patch_class, "programId", "Ljava/lang/String;");
|
||||
s_patch_title_id_field = env->GetFieldID(patch_class, "titleId", "Ljava/lang/String;");
|
||||
env->DeleteLocalRef(patch_class);
|
||||
|
||||
const jclass double_class = env->FindClass("java/lang/Double");
|
||||
s_double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class));
|
||||
s_double_constructor = env->GetMethodID(double_class, "<init>", "(D)V");
|
||||
s_double_value_method = env->GetMethodID(double_class, "doubleValue", "()D");
|
||||
env->DeleteLocalRef(double_class);
|
||||
|
||||
const jclass int_class = env->FindClass("java/lang/Integer");
|
||||
s_integer_class = reinterpret_cast<jclass>(env->NewGlobalRef(int_class));
|
||||
s_integer_constructor = env->GetMethodID(int_class, "<init>", "(I)V");
|
||||
s_integer_value_method = env->GetMethodID(int_class, "intValue", "()I");
|
||||
env->DeleteLocalRef(int_class);
|
||||
|
||||
const jclass boolean_class = env->FindClass("java/lang/Boolean");
|
||||
s_boolean_class = reinterpret_cast<jclass>(env->NewGlobalRef(boolean_class));
|
||||
s_boolean_constructor = env->GetMethodID(boolean_class, "<init>", "(Z)V");
|
||||
s_boolean_value_method = env->GetMethodID(boolean_class, "booleanValue", "()Z");
|
||||
env->DeleteLocalRef(boolean_class);
|
||||
|
||||
const jclass player_input_class =
|
||||
env->FindClass("org/yuzu/yuzu_emu/features/input/model/PlayerInput");
|
||||
s_player_input_class = reinterpret_cast<jclass>(env->NewGlobalRef(player_input_class));
|
||||
s_player_input_constructor = env->GetMethodID(
|
||||
player_input_class, "<init>",
|
||||
"(Z[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZIJJJJLjava/lang/String;Z)V");
|
||||
s_player_input_connected_field = env->GetFieldID(player_input_class, "connected", "Z");
|
||||
s_player_input_buttons_field =
|
||||
env->GetFieldID(player_input_class, "buttons", "[Ljava/lang/String;");
|
||||
s_player_input_analogs_field =
|
||||
env->GetFieldID(player_input_class, "analogs", "[Ljava/lang/String;");
|
||||
s_player_input_motions_field =
|
||||
env->GetFieldID(player_input_class, "motions", "[Ljava/lang/String;");
|
||||
s_player_input_vibration_enabled_field =
|
||||
env->GetFieldID(player_input_class, "vibrationEnabled", "Z");
|
||||
s_player_input_vibration_strength_field =
|
||||
env->GetFieldID(player_input_class, "vibrationStrength", "I");
|
||||
s_player_input_body_color_left_field =
|
||||
env->GetFieldID(player_input_class, "bodyColorLeft", "J");
|
||||
s_player_input_body_color_right_field =
|
||||
env->GetFieldID(player_input_class, "bodyColorRight", "J");
|
||||
s_player_input_button_color_left_field =
|
||||
env->GetFieldID(player_input_class, "buttonColorLeft", "J");
|
||||
s_player_input_button_color_right_field =
|
||||
env->GetFieldID(player_input_class, "buttonColorRight", "J");
|
||||
s_player_input_profile_name_field =
|
||||
env->GetFieldID(player_input_class, "profileName", "Ljava/lang/String;");
|
||||
s_player_input_use_system_vibrator_field =
|
||||
env->GetFieldID(player_input_class, "useSystemVibrator", "Z");
|
||||
env->DeleteLocalRef(player_input_class);
|
||||
|
||||
const jclass yuzu_input_device_interface =
|
||||
env->FindClass("org/yuzu/yuzu_emu/features/input/YuzuInputDevice");
|
||||
s_yuzu_input_device_interface =
|
||||
reinterpret_cast<jclass>(env->NewGlobalRef(yuzu_input_device_interface));
|
||||
s_yuzu_input_device_get_name =
|
||||
env->GetMethodID(yuzu_input_device_interface, "getName", "()Ljava/lang/String;");
|
||||
s_yuzu_input_device_get_guid =
|
||||
env->GetMethodID(yuzu_input_device_interface, "getGUID", "()Ljava/lang/String;");
|
||||
s_yuzu_input_device_get_port = env->GetMethodID(yuzu_input_device_interface, "getPort",
|
||||
"()I");
|
||||
s_yuzu_input_device_get_supports_vibration =
|
||||
env->GetMethodID(yuzu_input_device_interface, "getSupportsVibration", "()Z");
|
||||
s_yuzu_input_device_vibrate = env->GetMethodID(yuzu_input_device_interface, "vibrate",
|
||||
"(F)V");
|
||||
s_yuzu_input_device_get_axes =
|
||||
env->GetMethodID(yuzu_input_device_interface, "getAxes", "()[Ljava/lang/Integer;");
|
||||
s_yuzu_input_device_has_keys =
|
||||
env->GetMethodID(yuzu_input_device_interface, "hasKeys", "([I)[Z");
|
||||
env->DeleteLocalRef(yuzu_input_device_interface);
|
||||
s_add_netplay_message = env->GetStaticMethodID(s_native_library_class, "addNetPlayMessage",
|
||||
"(ILjava/lang/String;)V");
|
||||
s_clear_chat = env->GetStaticMethodID(s_native_library_class, "clearChat", "()V");
|
||||
|
||||
// Initialize Android Storage
|
||||
Common::FS::Android::RegisterCallbacks(env, s_native_library_class);
|
||||
|
||||
// Initialize applets
|
||||
Common::Android::SoftwareKeyboard::InitJNI(env);
|
||||
Common::Android::WebBrowser::InitJNI(env);
|
||||
}
|
||||
|
||||
} // namespace Common::Android
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace Common::Android {
|
||||
|
||||
void Initialize(JavaVM* vm, JNIEnv *env);
|
||||
JNIEnv* GetEnvForThread();
|
||||
|
||||
/**
|
||||
@@ -80,15 +81,15 @@ jfieldID GetPatchTitleIdField();
|
||||
|
||||
jclass GetDoubleClass();
|
||||
jmethodID GetDoubleConstructor();
|
||||
jfieldID GetDoubleValueField();
|
||||
jmethodID GetDoubleValueMethod();
|
||||
|
||||
jclass GetIntegerClass();
|
||||
jmethodID GetIntegerConstructor();
|
||||
jfieldID GetIntegerValueField();
|
||||
jmethodID GetIntegerValueMethod();
|
||||
|
||||
jclass GetBooleanClass();
|
||||
jmethodID GetBooleanConstructor();
|
||||
jfieldID GetBooleanValueField();
|
||||
jmethodID GetBooleanValueMethod();
|
||||
|
||||
jclass GetPlayerInputClass();
|
||||
jmethodID GetPlayerInputConstructor();
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
#include <string_view>
|
||||
#ifdef _WIN32
|
||||
#include <llvm/Demangle/Demangle.h>
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <cstring>
|
||||
|
||||
#include "common/make_unique_for_overwrite.h"
|
||||
|
||||
@@ -61,7 +65,7 @@ public:
|
||||
void resize(size_type size) {
|
||||
if (size > buffer_capacity) {
|
||||
auto new_buffer = Common::make_unique_for_overwrite<T[]>(size);
|
||||
std::move(buffer.get(), buffer.get() + buffer_capacity, new_buffer.get());
|
||||
std::memcpy(new_buffer.get(), buffer.get(), buffer_capacity * sizeof(T));
|
||||
buffer = std::move(new_buffer);
|
||||
buffer_capacity = size;
|
||||
}
|
||||
|
||||
@@ -92,14 +92,14 @@ struct EnumMetadata {
|
||||
// AudioEngine must be specified discretely due to having existing but slightly different
|
||||
// canonicalizations
|
||||
// TODO (lat9nq): Remove explicit definition of AudioEngine/sink_id
|
||||
enum class AudioEngine : u32 { Auto, Cubeb, Sdl3, Null, Oboe, };
|
||||
enum class AudioEngine : u32 { Auto, Cubeb, Sdl3, Null, };
|
||||
template<>
|
||||
inline std::vector<std::pair<std::string_view, AudioEngine>> EnumMetadata<AudioEngine>::Canonicalizations() {
|
||||
return {
|
||||
{"auto", AudioEngine::Auto},
|
||||
{"cubeb", AudioEngine::Cubeb},
|
||||
{"sdl3", AudioEngine::Sdl3},
|
||||
{"null", AudioEngine::Null}, {"oboe", AudioEngine::Oboe},
|
||||
{"null", AudioEngine::Null},
|
||||
};
|
||||
}
|
||||
/// @brief This is just a sufficiently large number that is more than the number of other enums declared here
|
||||
@@ -113,7 +113,7 @@ inline AudioEngine EnumMetadata<AudioEngine>::GetFirst() {
|
||||
}
|
||||
template<>
|
||||
inline AudioEngine EnumMetadata<AudioEngine>::GetLast() {
|
||||
return AudioEngine::Oboe;
|
||||
return AudioEngine::Null;
|
||||
}
|
||||
|
||||
ENUM(AudioMode, Mono, Stereo, Surround);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <functional>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
|
||||
@@ -160,26 +160,16 @@ bool ArmNce::HandleGuestAlignmentFault(GuestContext* guest_ctx, void* raw_info,
|
||||
bool ArmNce::HandleGuestAccessFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) {
|
||||
auto* info = static_cast<siginfo_t*>(raw_info);
|
||||
|
||||
auto& memory = guest_ctx->parent->m_running_thread->GetOwnerProcess()->GetMemory();
|
||||
|
||||
// Try to handle an invalid access.
|
||||
auto const acc_size = 16; // Max architectural access size
|
||||
// Please note accesses can be wider than 16-bytes
|
||||
// This should handle **most** of the fragant issues with cases like 128-bit vector
|
||||
// ld/st or GPU writes.
|
||||
// This computes the addr for the (first) page corresponding to the access (if not crossing)
|
||||
auto const addr_c1 = Common::ProcessAddress(u64(info->si_addr) & ~Memory::YUZU_PAGEMASK);
|
||||
if (!(acc_size > 1 && (addr_c1 & Memory::YUZU_PAGEMASK) + acc_size > Memory::YUZU_PAGESIZE)) {
|
||||
if (memory.InvalidateNCE(addr_c1, Memory::YUZU_PAGESIZE))
|
||||
return true;
|
||||
} else {
|
||||
// Corresponds to the 2nd page, this means the access is split between two pages
|
||||
auto const addr_c2 = (addr_c1 & ~Memory::YUZU_PAGEMASK) + Memory::YUZU_PAGESIZE;
|
||||
// Always invalidate 2nd page, but only account if 1st page was invalidated properly
|
||||
memory.InvalidateNCE(addr_c2, Memory::YUZU_PAGESIZE);
|
||||
if (memory.InvalidateNCE(addr_c1, Memory::YUZU_PAGESIZE))
|
||||
return true;
|
||||
// TODO: handle accesses which split a page?
|
||||
const Common::ProcessAddress addr =
|
||||
(reinterpret_cast<u64>(info->si_addr) & ~Memory::YUZU_PAGEMASK);
|
||||
auto& memory = guest_ctx->parent->m_running_thread->GetOwnerProcess()->GetMemory();
|
||||
if (memory.InvalidateNCE(addr, Memory::YUZU_PAGESIZE)) {
|
||||
// We handled the access successfully and are returning to guest code.
|
||||
return true;
|
||||
}
|
||||
|
||||
// We couldn't handle the access.
|
||||
return HandleFailedGuestFault(guest_ctx, raw_info, raw_context);
|
||||
}
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/version.hpp>
|
||||
|
||||
#if BOOST_VERSION > 108400 && (!defined(_WINDOWS) && !defined(__ANDROID__)) || defined(YUZU_BOOST_v1)
|
||||
#define USE_BOOST_v1
|
||||
#endif
|
||||
|
||||
#ifdef USE_BOOST_v1
|
||||
#include <boost/process/v1/async_pipe.hpp>
|
||||
#else
|
||||
@@ -358,7 +358,7 @@ private:
|
||||
|
||||
ConnectionState(boost::asio::ip::tcp::socket&& client_socket_, async_pipe signal_pipe_, Kernel::KernelCore& kernel)
|
||||
: client_socket{std::move(client_socket_)}
|
||||
, signal_pipe{signal_pipe_}
|
||||
, signal_pipe{std::move(signal_pipe_)}
|
||||
, active_thread{kernel, nullptr}
|
||||
{}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include "common/common_funcs.h"
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
|
||||
#include "common/literals.h"
|
||||
#include "core/file_sys/fssystem/fs_i_storage.h"
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <type_traits>
|
||||
#include "core/file_sys/errors.h"
|
||||
#include "core/file_sys/fssystem/fssystem_bucket_tree.h"
|
||||
#include "core/file_sys/fssystem/fssystem_bucket_tree_utils.h"
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <type_traits>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/common_funcs.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include "core/file_sys/errors.h"
|
||||
#include "core/file_sys/fssystem/fssystem_bucket_tree.h"
|
||||
#include "core/file_sys/fssystem/fssystem_bucket_tree_utils.h"
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <cstddef>
|
||||
#include "common/literals.h"
|
||||
|
||||
#include "core/file_sys/errors.h"
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include "common/alignment.h"
|
||||
#include "core/file_sys/fssystem/fs_i_storage.h"
|
||||
#include "core/file_sys/fssystem/fs_types.h"
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include "core/file_sys/errors.h"
|
||||
#include "core/file_sys/fssystem/fs_i_storage.h"
|
||||
#include "core/file_sys/fssystem/fssystem_bucket_tree.h"
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
|
||||
#include "core/file_sys/fssystem/fs_i_storage.h"
|
||||
#include "core/file_sys/fssystem/fs_types.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <cstddef>
|
||||
#include "core/file_sys/fssystem/fssystem_compression_common.h"
|
||||
#include "core/file_sys/fssystem/fssystem_nca_header.h"
|
||||
#include "core/file_sys/vfs/vfs.h"
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/literals.h"
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/page_table.h"
|
||||
|
||||
@@ -1021,6 +1021,9 @@ Result KProcess::Run(KernelCore& kernel, s32 priority, size_t stack_size) {
|
||||
|
||||
// Suspend for debug, if we should.
|
||||
if (kernel.System().DebuggerEnabled()) {
|
||||
LOG_INFO(Debug_GDBStub,
|
||||
"GDB stub enabled; suspending guest process until a debugger continues execution on port {}",
|
||||
Settings::values.gdbstub_port.GetValue());
|
||||
main_thread->RequestSuspend(kernel, SuspendType::Debug);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include "common/assert.h"
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_funcs.h"
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <type_traits>
|
||||
#include <functional>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
|
||||
@@ -175,19 +175,10 @@ Result AlbumManager::LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& ou
|
||||
return ResultIsNotMounted;
|
||||
}
|
||||
|
||||
out_image_output = {
|
||||
.width = 1280,
|
||||
.height = 720,
|
||||
.attribute =
|
||||
{
|
||||
.unknown_0{},
|
||||
.orientation = AlbumImageOrientation::None,
|
||||
.unknown_1{},
|
||||
.unknown_2{},
|
||||
.pad163{},
|
||||
},
|
||||
.pad179{},
|
||||
};
|
||||
out_image_output = {};
|
||||
out_image_output.width = 1280;
|
||||
out_image_output.height = 720;
|
||||
out_image_output.attribute.orientation = AlbumImageOrientation::None;
|
||||
|
||||
std::filesystem::path path;
|
||||
const auto result = GetFile(path, file_id);
|
||||
@@ -211,19 +202,10 @@ Result AlbumManager::LoadAlbumScreenShotThumbnail(
|
||||
return ResultIsNotMounted;
|
||||
}
|
||||
|
||||
out_image_output = {
|
||||
.width = 320,
|
||||
.height = 180,
|
||||
.attribute =
|
||||
{
|
||||
.unknown_0{},
|
||||
.orientation = AlbumImageOrientation::None,
|
||||
.unknown_1{},
|
||||
.unknown_2{},
|
||||
.pad163{},
|
||||
},
|
||||
.pad179{},
|
||||
};
|
||||
out_image_output = {};
|
||||
out_image_output.width = 320;
|
||||
out_image_output.height = 180;
|
||||
out_image_output.attribute.orientation = AlbumImageOrientation::None;
|
||||
|
||||
std::filesystem::path path;
|
||||
const auto result = GetFile(path, file_id);
|
||||
|
||||
@@ -73,13 +73,8 @@ void IScreenShotApplicationService::CaptureAndSaveScreenshot(AlbumReportOption r
|
||||
Layout::FramebufferLayout layout =
|
||||
Layout::DefaultFrameLayout(screenshot_width, screenshot_height);
|
||||
|
||||
const Capture::ScreenShotAttribute attribute{
|
||||
.unknown_0{},
|
||||
.orientation = Capture::AlbumImageOrientation::None,
|
||||
.unknown_1{},
|
||||
.unknown_2{},
|
||||
.pad163{},
|
||||
};
|
||||
Capture::ScreenShotAttribute attribute{};
|
||||
attribute.orientation = Capture::AlbumImageOrientation::None;
|
||||
|
||||
renderer.RequestScreenshot(
|
||||
image_data.data(),
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <fmt/ranges.h>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <type_traits>
|
||||
#include <fmt/ranges.h>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <type_traits>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <type_traits>
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_funcs.h"
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <array>
|
||||
#include <type_traits>
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
@@ -114,7 +114,7 @@ std::set<s32> Android::GetDeviceAxes(JNIEnv* env, jobject& j_device) const {
|
||||
std::set<s32> axes;
|
||||
for (int i = 0; i < env->GetArrayLength(j_axes); ++i) {
|
||||
jobject axis = env->GetObjectArrayElement(j_axes, i);
|
||||
axes.insert(env->GetIntField(axis, Common::Android::GetIntegerValueField()));
|
||||
axes.insert(env->CallIntMethod(axis, Common::Android::GetIntegerValueMethod()));
|
||||
}
|
||||
return axes;
|
||||
}
|
||||
|
||||
@@ -6,55 +6,6 @@
|
||||
|
||||
add_library(shader_recompiler STATIC
|
||||
backend/bindings.h
|
||||
backend/glasm/emit_glasm.cpp
|
||||
backend/glasm/emit_glasm.h
|
||||
backend/glasm/emit_glasm_barriers.cpp
|
||||
backend/glasm/emit_glasm_bitwise_conversion.cpp
|
||||
backend/glasm/emit_glasm_composite.cpp
|
||||
backend/glasm/emit_glasm_context_get_set.cpp
|
||||
backend/glasm/emit_glasm_control_flow.cpp
|
||||
backend/glasm/emit_glasm_convert.cpp
|
||||
backend/glasm/emit_glasm_floating_point.cpp
|
||||
backend/glasm/emit_glasm_image.cpp
|
||||
backend/glasm/emit_glasm_instructions.h
|
||||
backend/glasm/emit_glasm_integer.cpp
|
||||
backend/glasm/emit_glasm_logical.cpp
|
||||
backend/glasm/emit_glasm_memory.cpp
|
||||
backend/glasm/emit_glasm_not_implemented.cpp
|
||||
backend/glasm/emit_glasm_select.cpp
|
||||
backend/glasm/emit_glasm_shared_memory.cpp
|
||||
backend/glasm/emit_glasm_special.cpp
|
||||
backend/glasm/emit_glasm_undefined.cpp
|
||||
backend/glasm/emit_glasm_warp.cpp
|
||||
backend/glasm/glasm_emit_context.cpp
|
||||
backend/glasm/glasm_emit_context.h
|
||||
backend/glasm/reg_alloc.cpp
|
||||
backend/glasm/reg_alloc.h
|
||||
backend/glsl/emit_glsl.cpp
|
||||
backend/glsl/emit_glsl.h
|
||||
backend/glsl/emit_glsl_atomic.cpp
|
||||
backend/glsl/emit_glsl_barriers.cpp
|
||||
backend/glsl/emit_glsl_bitwise_conversion.cpp
|
||||
backend/glsl/emit_glsl_composite.cpp
|
||||
backend/glsl/emit_glsl_context_get_set.cpp
|
||||
backend/glsl/emit_glsl_control_flow.cpp
|
||||
backend/glsl/emit_glsl_convert.cpp
|
||||
backend/glsl/emit_glsl_floating_point.cpp
|
||||
backend/glsl/emit_glsl_image.cpp
|
||||
backend/glsl/emit_glsl_instructions.h
|
||||
backend/glsl/emit_glsl_integer.cpp
|
||||
backend/glsl/emit_glsl_logical.cpp
|
||||
backend/glsl/emit_glsl_memory.cpp
|
||||
backend/glsl/emit_glsl_not_implemented.cpp
|
||||
backend/glsl/emit_glsl_select.cpp
|
||||
backend/glsl/emit_glsl_shared_memory.cpp
|
||||
backend/glsl/emit_glsl_special.cpp
|
||||
backend/glsl/emit_glsl_undefined.cpp
|
||||
backend/glsl/emit_glsl_warp.cpp
|
||||
backend/glsl/glsl_emit_context.cpp
|
||||
backend/glsl/glsl_emit_context.h
|
||||
backend/glsl/var_alloc.cpp
|
||||
backend/glsl/var_alloc.h
|
||||
backend/spirv/emit_spirv.cpp
|
||||
backend/spirv/emit_spirv.h
|
||||
backend/spirv/emit_spirv_atomic.cpp
|
||||
@@ -239,9 +190,60 @@ add_library(shader_recompiler STATIC
|
||||
program_header.h
|
||||
runtime_info.h
|
||||
shader_info.h
|
||||
varying_state.h
|
||||
varying_state.h)
|
||||
|
||||
)
|
||||
if (ENABLE_OPENGL)
|
||||
target_sources(shader_recompiler PRIVATE
|
||||
backend/glasm/emit_glasm.cpp
|
||||
backend/glasm/emit_glasm.h
|
||||
backend/glasm/emit_glasm_barriers.cpp
|
||||
backend/glasm/emit_glasm_bitwise_conversion.cpp
|
||||
backend/glasm/emit_glasm_composite.cpp
|
||||
backend/glasm/emit_glasm_context_get_set.cpp
|
||||
backend/glasm/emit_glasm_control_flow.cpp
|
||||
backend/glasm/emit_glasm_convert.cpp
|
||||
backend/glasm/emit_glasm_floating_point.cpp
|
||||
backend/glasm/emit_glasm_image.cpp
|
||||
backend/glasm/emit_glasm_instructions.h
|
||||
backend/glasm/emit_glasm_integer.cpp
|
||||
backend/glasm/emit_glasm_logical.cpp
|
||||
backend/glasm/emit_glasm_memory.cpp
|
||||
backend/glasm/emit_glasm_not_implemented.cpp
|
||||
backend/glasm/emit_glasm_select.cpp
|
||||
backend/glasm/emit_glasm_shared_memory.cpp
|
||||
backend/glasm/emit_glasm_special.cpp
|
||||
backend/glasm/emit_glasm_undefined.cpp
|
||||
backend/glasm/emit_glasm_warp.cpp
|
||||
backend/glasm/glasm_emit_context.cpp
|
||||
backend/glasm/glasm_emit_context.h
|
||||
backend/glasm/reg_alloc.cpp
|
||||
backend/glasm/reg_alloc.h
|
||||
backend/glsl/emit_glsl.cpp
|
||||
backend/glsl/emit_glsl.h
|
||||
backend/glsl/emit_glsl_atomic.cpp
|
||||
backend/glsl/emit_glsl_barriers.cpp
|
||||
backend/glsl/emit_glsl_bitwise_conversion.cpp
|
||||
backend/glsl/emit_glsl_composite.cpp
|
||||
backend/glsl/emit_glsl_context_get_set.cpp
|
||||
backend/glsl/emit_glsl_control_flow.cpp
|
||||
backend/glsl/emit_glsl_convert.cpp
|
||||
backend/glsl/emit_glsl_floating_point.cpp
|
||||
backend/glsl/emit_glsl_image.cpp
|
||||
backend/glsl/emit_glsl_instructions.h
|
||||
backend/glsl/emit_glsl_integer.cpp
|
||||
backend/glsl/emit_glsl_logical.cpp
|
||||
backend/glsl/emit_glsl_memory.cpp
|
||||
backend/glsl/emit_glsl_not_implemented.cpp
|
||||
backend/glsl/emit_glsl_select.cpp
|
||||
backend/glsl/emit_glsl_shared_memory.cpp
|
||||
backend/glsl/emit_glsl_special.cpp
|
||||
backend/glsl/emit_glsl_undefined.cpp
|
||||
backend/glsl/emit_glsl_warp.cpp
|
||||
backend/glsl/glsl_emit_context.cpp
|
||||
backend/glsl/glsl_emit_context.h
|
||||
backend/glsl/var_alloc.cpp
|
||||
backend/glsl/var_alloc.h)
|
||||
endif()
|
||||
|
||||
target_link_libraries(shader_recompiler PUBLIC common fmt::fmt sirit::sirit)
|
||||
|
||||
|
||||
@@ -553,17 +553,6 @@ void GlobalMemoryToStorageBufferPass(IR::Program& program, const HostTranslateIn
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Descriptors, typename Descriptor, typename Func>
|
||||
static u32 Add(Descriptors& descriptors, const Descriptor& desc, Func&& pred) {
|
||||
// TODO: Handle arrays
|
||||
const auto it{std::ranges::find_if(descriptors, pred)};
|
||||
if (it != descriptors.end()) {
|
||||
return static_cast<u32>(std::distance(descriptors.begin(), it));
|
||||
}
|
||||
descriptors.push_back(desc);
|
||||
return static_cast<u32>(descriptors.size()) - 1;
|
||||
}
|
||||
|
||||
void JoinStorageInfo(Info& base, Info& source) {
|
||||
auto& descriptors = base.storage_buffers_descriptors;
|
||||
for (auto& desc : source.storage_buffers_descriptors) {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_funcs.h"
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/scratch_buffer.h"
|
||||
|
||||
@@ -338,7 +338,7 @@ void PresentManager::PresentThread(std::stop_token token) {
|
||||
// By exchanging the lock ownership we take the swapchain lock
|
||||
// before the queue lock goes out of scope. This way the swapchain
|
||||
// lock in WaitPresent is guaranteed to occur after here.
|
||||
std::exchange(lock, std::unique_lock{swapchain_mutex});
|
||||
void(std::exchange(lock, std::unique_lock{swapchain_mutex}));
|
||||
CopyToSwapchain(frame);
|
||||
|
||||
// Free the frame for reuse
|
||||
|
||||
@@ -300,7 +300,7 @@ void Scheduler::WorkerThread(std::stop_token stop_token) {
|
||||
// Exchange lock ownership so that we take the execution lock before
|
||||
// the queue lock goes out of scope. This allows us to force execution
|
||||
// to complete in the next step.
|
||||
std::exchange(lk, std::unique_lock{execution_mutex});
|
||||
void(std::exchange(lk, std::unique_lock{execution_mutex}));
|
||||
|
||||
// Perform the work, tracking whether the chunk was a submission
|
||||
// before executing.
|
||||
|
||||
@@ -26,350 +26,329 @@
|
||||
#include "common/settings.h"
|
||||
|
||||
namespace Vulkan {
|
||||
namespace {
|
||||
namespace {
|
||||
|
||||
// Helpers translating MemoryUsage to flags/usage
|
||||
|
||||
[[maybe_unused]] VkMemoryPropertyFlags MemoryUsagePropertyFlags(MemoryUsage usage) {
|
||||
switch (usage) {
|
||||
case MemoryUsage::DeviceLocal:
|
||||
return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
case MemoryUsage::Upload:
|
||||
return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
case MemoryUsage::Download:
|
||||
return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
|
||||
case MemoryUsage::Stream:
|
||||
return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
}
|
||||
ASSERT_MSG(false, "Invalid memory usage={}", usage);
|
||||
return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
[[maybe_unused]] VkMemoryPropertyFlags MemoryUsagePropertyFlags(MemoryUsage usage) {
|
||||
switch (usage) {
|
||||
case MemoryUsage::DeviceLocal:
|
||||
return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
case MemoryUsage::Upload:
|
||||
return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
case MemoryUsage::Download:
|
||||
return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
|
||||
case MemoryUsage::Stream:
|
||||
return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
}
|
||||
ASSERT_MSG(false, "Invalid memory usage={}", usage);
|
||||
return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
}
|
||||
|
||||
[[nodiscard]] VkMemoryPropertyFlags MemoryUsagePreferredVmaFlags(MemoryUsage usage) {
|
||||
if (usage == MemoryUsage::Download) {
|
||||
return VK_MEMORY_PROPERTY_HOST_CACHED_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
}
|
||||
return usage != MemoryUsage::DeviceLocal ? VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
||||
: VkMemoryPropertyFlagBits{};
|
||||
[[nodiscard]] VkMemoryPropertyFlags MemoryUsagePreferredVmaFlags(MemoryUsage usage) {
|
||||
if (usage == MemoryUsage::Download) {
|
||||
return VK_MEMORY_PROPERTY_HOST_CACHED_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
}
|
||||
return usage != MemoryUsage::DeviceLocal ? VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
||||
: VkMemoryPropertyFlagBits{};
|
||||
}
|
||||
|
||||
[[nodiscard]] VmaAllocationCreateFlags MemoryUsageVmaFlags(MemoryUsage usage) {
|
||||
switch (usage) {
|
||||
case MemoryUsage::Upload:
|
||||
case MemoryUsage::Stream:
|
||||
return VMA_ALLOCATION_CREATE_MAPPED_BIT |
|
||||
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
||||
case MemoryUsage::Download:
|
||||
return VMA_ALLOCATION_CREATE_MAPPED_BIT |
|
||||
VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
|
||||
case MemoryUsage::DeviceLocal:
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
[[nodiscard]] VmaAllocationCreateFlags MemoryUsageVmaFlags(MemoryUsage usage) {
|
||||
switch (usage) {
|
||||
case MemoryUsage::Upload:
|
||||
case MemoryUsage::Stream:
|
||||
return VMA_ALLOCATION_CREATE_MAPPED_BIT |
|
||||
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
||||
case MemoryUsage::Download:
|
||||
return VMA_ALLOCATION_CREATE_MAPPED_BIT |
|
||||
VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
|
||||
case MemoryUsage::DeviceLocal:
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] VmaMemoryUsage MemoryUsageVma(MemoryUsage usage) {
|
||||
switch (usage) {
|
||||
case MemoryUsage::DeviceLocal:
|
||||
case MemoryUsage::Stream:
|
||||
return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
|
||||
case MemoryUsage::Upload:
|
||||
case MemoryUsage::Download:
|
||||
return VMA_MEMORY_USAGE_AUTO_PREFER_HOST;
|
||||
}
|
||||
return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
|
||||
[[nodiscard]] VmaMemoryUsage MemoryUsageVma(MemoryUsage usage) {
|
||||
switch (usage) {
|
||||
case MemoryUsage::DeviceLocal:
|
||||
case MemoryUsage::Stream:
|
||||
return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
|
||||
case MemoryUsage::Upload:
|
||||
case MemoryUsage::Download:
|
||||
return VMA_MEMORY_USAGE_AUTO_PREFER_HOST;
|
||||
}
|
||||
|
||||
|
||||
// This avoids calling vkGetBufferMemoryRequirements* directly.
|
||||
template<typename T>
|
||||
static VkBuffer GetVkHandleFromBuffer(const T &buf) {
|
||||
if constexpr (requires { static_cast<VkBuffer>(buf); }) {
|
||||
return static_cast<VkBuffer>(buf);
|
||||
} else if constexpr (requires {{ buf.GetHandle() } -> std::convertible_to<VkBuffer>; }) {
|
||||
return buf.GetHandle();
|
||||
} else if constexpr (requires {{ buf.Handle() } -> std::convertible_to<VkBuffer>; }) {
|
||||
return buf.Handle();
|
||||
} else if constexpr (requires {{ buf.vk_handle() } -> std::convertible_to<VkBuffer>; }) {
|
||||
return buf.vk_handle();
|
||||
} else {
|
||||
static_assert(sizeof(T) == 0, "Cannot extract VkBuffer handle from vk::Buffer");
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
//MemoryCommit is now VMA-backed
|
||||
MemoryCommit::MemoryCommit(VmaAllocator alloc, VmaAllocation a,
|
||||
const VmaAllocationInfo &info) noexcept
|
||||
: allocator{alloc}, allocation{a}, memory{info.deviceMemory},
|
||||
offset{info.offset}, size{info.size}, mapped_ptr{info.pMappedData} {
|
||||
// Log GPU memory allocation
|
||||
MemoryCommit::MemoryCommit(VmaAllocator alloc, VmaAllocation a,
|
||||
const VmaAllocationInfo &info) noexcept
|
||||
: allocator{alloc}, allocation{a}, memory{info.deviceMemory},
|
||||
offset{info.offset}, size{info.size}, mapped_ptr{info.pMappedData} {
|
||||
// Log GPU memory allocation
|
||||
if (GPU::Logging::IsActive() &&
|
||||
Settings::values.gpu_log_memory_tracking.GetValue()) {
|
||||
GPU::Logging::GPULogger::GetInstance().LogMemoryAllocation(
|
||||
reinterpret_cast<uintptr_t>(memory),
|
||||
static_cast<u64>(size),
|
||||
0 // Memory property flags (not easily available from VMA)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MemoryCommit::~MemoryCommit() { Release(); }
|
||||
|
||||
MemoryCommit::MemoryCommit(MemoryCommit &&rhs) noexcept
|
||||
: allocator{std::exchange(rhs.allocator, nullptr)},
|
||||
allocation{std::exchange(rhs.allocation, nullptr)},
|
||||
memory{std::exchange(rhs.memory, VK_NULL_HANDLE)},
|
||||
offset{std::exchange(rhs.offset, 0)},
|
||||
size{std::exchange(rhs.size, 0)},
|
||||
mapped_ptr{std::exchange(rhs.mapped_ptr, nullptr)} {}
|
||||
|
||||
MemoryCommit &MemoryCommit::operator=(MemoryCommit &&rhs) noexcept {
|
||||
if (this != &rhs) {
|
||||
Release();
|
||||
allocator = std::exchange(rhs.allocator, nullptr);
|
||||
allocation = std::exchange(rhs.allocation, nullptr);
|
||||
memory = std::exchange(rhs.memory, VK_NULL_HANDLE);
|
||||
offset = std::exchange(rhs.offset, 0);
|
||||
size = std::exchange(rhs.size, 0);
|
||||
mapped_ptr = std::exchange(rhs.mapped_ptr, nullptr);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::span<u8> MemoryCommit::Map()
|
||||
{
|
||||
if (!allocation) return {};
|
||||
if (!mapped_ptr) {
|
||||
if (vmaMapMemory(allocator, allocation, &mapped_ptr) != VK_SUCCESS) return {};
|
||||
}
|
||||
const size_t n = static_cast<size_t>(std::min<VkDeviceSize>(size,
|
||||
(std::numeric_limits<size_t>::max)()));
|
||||
return std::span<u8>{static_cast<u8 *>(mapped_ptr), n};
|
||||
}
|
||||
|
||||
std::span<const u8> MemoryCommit::Map() const
|
||||
{
|
||||
if (!allocation) return {};
|
||||
if (!mapped_ptr) {
|
||||
void *p = nullptr;
|
||||
if (vmaMapMemory(allocator, allocation, &p) != VK_SUCCESS) return {};
|
||||
const_cast<MemoryCommit *>(this)->mapped_ptr = p;
|
||||
}
|
||||
const size_t n = static_cast<size_t>(std::min<VkDeviceSize>(size,
|
||||
(std::numeric_limits<size_t>::max)()));
|
||||
return std::span<const u8>{static_cast<const u8 *>(mapped_ptr), n};
|
||||
}
|
||||
|
||||
void MemoryCommit::Unmap()
|
||||
{
|
||||
if (allocation && mapped_ptr) {
|
||||
vmaUnmapMemory(allocator, allocation);
|
||||
mapped_ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryCommit::Release() {
|
||||
if (allocation && allocator) {
|
||||
// Log GPU memory deallocation
|
||||
if (GPU::Logging::IsActive() &&
|
||||
Settings::values.gpu_log_memory_tracking.GetValue()) {
|
||||
GPU::Logging::GPULogger::GetInstance().LogMemoryAllocation(
|
||||
reinterpret_cast<uintptr_t>(memory),
|
||||
static_cast<u64>(size),
|
||||
0 // Memory property flags (not easily available from VMA)
|
||||
Settings::values.gpu_log_memory_tracking.GetValue() &&
|
||||
memory != VK_NULL_HANDLE) {
|
||||
GPU::Logging::GPULogger::GetInstance().LogMemoryDeallocation(
|
||||
reinterpret_cast<uintptr_t>(memory)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MemoryCommit::~MemoryCommit() { Release(); }
|
||||
|
||||
MemoryCommit::MemoryCommit(MemoryCommit &&rhs) noexcept
|
||||
: allocator{std::exchange(rhs.allocator, nullptr)},
|
||||
allocation{std::exchange(rhs.allocation, nullptr)},
|
||||
memory{std::exchange(rhs.memory, VK_NULL_HANDLE)},
|
||||
offset{std::exchange(rhs.offset, 0)},
|
||||
size{std::exchange(rhs.size, 0)},
|
||||
mapped_ptr{std::exchange(rhs.mapped_ptr, nullptr)} {}
|
||||
|
||||
MemoryCommit &MemoryCommit::operator=(MemoryCommit &&rhs) noexcept {
|
||||
if (this != &rhs) {
|
||||
Release();
|
||||
allocator = std::exchange(rhs.allocator, nullptr);
|
||||
allocation = std::exchange(rhs.allocation, nullptr);
|
||||
memory = std::exchange(rhs.memory, VK_NULL_HANDLE);
|
||||
offset = std::exchange(rhs.offset, 0);
|
||||
size = std::exchange(rhs.size, 0);
|
||||
mapped_ptr = std::exchange(rhs.mapped_ptr, nullptr);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::span<u8> MemoryCommit::Map()
|
||||
{
|
||||
if (!allocation) return {};
|
||||
if (!mapped_ptr) {
|
||||
if (vmaMapMemory(allocator, allocation, &mapped_ptr) != VK_SUCCESS) return {};
|
||||
}
|
||||
const size_t n = static_cast<size_t>(std::min<VkDeviceSize>(size,
|
||||
(std::numeric_limits<size_t>::max)()));
|
||||
return std::span<u8>{static_cast<u8 *>(mapped_ptr), n};
|
||||
}
|
||||
|
||||
std::span<const u8> MemoryCommit::Map() const
|
||||
{
|
||||
if (!allocation) return {};
|
||||
if (!mapped_ptr) {
|
||||
void *p = nullptr;
|
||||
if (vmaMapMemory(allocator, allocation, &p) != VK_SUCCESS) return {};
|
||||
const_cast<MemoryCommit *>(this)->mapped_ptr = p;
|
||||
}
|
||||
const size_t n = static_cast<size_t>(std::min<VkDeviceSize>(size,
|
||||
(std::numeric_limits<size_t>::max)()));
|
||||
return std::span<const u8>{static_cast<const u8 *>(mapped_ptr), n};
|
||||
}
|
||||
|
||||
void MemoryCommit::Unmap()
|
||||
{
|
||||
if (allocation && mapped_ptr) {
|
||||
if (mapped_ptr) {
|
||||
vmaUnmapMemory(allocator, allocation);
|
||||
mapped_ptr = nullptr;
|
||||
}
|
||||
vmaFreeMemory(allocator, allocation);
|
||||
}
|
||||
allocation = nullptr;
|
||||
allocator = nullptr;
|
||||
memory = VK_NULL_HANDLE;
|
||||
offset = 0;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
void MemoryCommit::Release() {
|
||||
if (allocation && allocator) {
|
||||
// Log GPU memory deallocation
|
||||
if (GPU::Logging::IsActive() &&
|
||||
Settings::values.gpu_log_memory_tracking.GetValue() &&
|
||||
memory != VK_NULL_HANDLE) {
|
||||
GPU::Logging::GPULogger::GetInstance().LogMemoryDeallocation(
|
||||
reinterpret_cast<uintptr_t>(memory)
|
||||
);
|
||||
}
|
||||
MemoryAllocator::MemoryAllocator(const Device &device_)
|
||||
: device{device_}, allocator{device.GetAllocator()},
|
||||
properties{device_.GetPhysical().GetMemoryProperties().memoryProperties},
|
||||
buffer_image_granularity{
|
||||
device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {
|
||||
|
||||
if (mapped_ptr) {
|
||||
vmaUnmapMemory(allocator, allocation);
|
||||
mapped_ptr = nullptr;
|
||||
}
|
||||
vmaFreeMemory(allocator, allocation);
|
||||
}
|
||||
allocation = nullptr;
|
||||
allocator = nullptr;
|
||||
memory = VK_NULL_HANDLE;
|
||||
offset = 0;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
MemoryAllocator::MemoryAllocator(const Device &device_)
|
||||
: device{device_}, allocator{device.GetAllocator()},
|
||||
properties{device_.GetPhysical().GetMemoryProperties().memoryProperties},
|
||||
buffer_image_granularity{
|
||||
device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {
|
||||
|
||||
// Preserve the previous "RenderDoc small heap" trimming behavior that we had in original vma minus the heap bug
|
||||
if (device.HasDebuggingToolAttached())
|
||||
{
|
||||
using namespace Common::Literals;
|
||||
ForEachDeviceLocalHostVisibleHeap(device, [this](size_t heap_idx, VkMemoryHeap &heap) {
|
||||
if (heap.size <= 256_MiB) {
|
||||
for (u32 t = 0; t < properties.memoryTypeCount; ++t) {
|
||||
if (properties.memoryTypes[t].heapIndex == heap_idx) {
|
||||
valid_memory_types &= ~(1u << t);
|
||||
}
|
||||
// Preserve the previous "RenderDoc small heap" trimming behavior that we had in original vma minus the heap bug
|
||||
if (device.HasDebuggingToolAttached())
|
||||
{
|
||||
using namespace Common::Literals;
|
||||
ForEachDeviceLocalHostVisibleHeap(device, [this](size_t heap_idx, VkMemoryHeap &heap) {
|
||||
if (heap.size <= 256_MiB) {
|
||||
for (u32 t = 0; t < properties.memoryTypeCount; ++t) {
|
||||
if (properties.memoryTypes[t].heapIndex == heap_idx) {
|
||||
valid_memory_types &= ~(1u << t);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
MemoryAllocator::~MemoryAllocator() = default;
|
||||
MemoryAllocator::~MemoryAllocator() = default;
|
||||
|
||||
vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo &ci) const
|
||||
{
|
||||
const VmaAllocationCreateInfo alloc_ci = {
|
||||
.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT,
|
||||
.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
|
||||
.requiredFlags = 0,
|
||||
.preferredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
.memoryTypeBits = 0,
|
||||
.pool = VK_NULL_HANDLE,
|
||||
.pUserData = nullptr,
|
||||
.priority = 0.f,
|
||||
};
|
||||
|
||||
VkImage handle{};
|
||||
VmaAllocation allocation{};
|
||||
VmaAllocationInfo alloc_info{};
|
||||
vk::Check(vmaCreateImage(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info));
|
||||
|
||||
// Log GPU memory allocation for images
|
||||
if (GPU::Logging::IsActive() &&
|
||||
Settings::values.gpu_log_memory_tracking.GetValue()) {
|
||||
GPU::Logging::GPULogger::GetInstance().LogMemoryAllocation(
|
||||
reinterpret_cast<uintptr_t>(alloc_info.deviceMemory),
|
||||
static_cast<u64>(alloc_info.size),
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
||||
);
|
||||
}
|
||||
|
||||
return vk::Image(handle, ci.usage, *device.GetLogical(), allocator, allocation,
|
||||
device.GetDispatchLoader());
|
||||
}
|
||||
|
||||
vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo &ci, MemoryUsage usage) const {
|
||||
// MESA will do memcpy() if not marked as host cached, so just force mark it for most buffers
|
||||
auto const anv_flags = (usage == MemoryUsage::Stream
|
||||
&& device.GetDriverID() == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA)
|
||||
? VK_MEMORY_PROPERTY_HOST_CACHED_BIT : 0;
|
||||
const VmaAllocationCreateInfo alloc_ci = {
|
||||
.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | MemoryUsageVmaFlags(usage),
|
||||
.usage = MemoryUsageVma(usage),
|
||||
vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo &ci) const
|
||||
{
|
||||
const VmaAllocationCreateInfo alloc_ci = {
|
||||
.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT,
|
||||
.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
|
||||
.requiredFlags = 0,
|
||||
.preferredFlags = MemoryUsagePreferredVmaFlags(usage) | anv_flags,
|
||||
.memoryTypeBits = usage == MemoryUsage::Stream ? 0u : valid_memory_types,
|
||||
.preferredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
.memoryTypeBits = 0,
|
||||
.pool = VK_NULL_HANDLE,
|
||||
.pUserData = nullptr,
|
||||
.priority = 0.f,
|
||||
};
|
||||
};
|
||||
|
||||
VkBuffer handle{};
|
||||
VmaAllocationInfo alloc_info{};
|
||||
VmaAllocation allocation{};
|
||||
VkMemoryPropertyFlags property_flags{};
|
||||
VkImage handle{};
|
||||
VmaAllocation allocation{};
|
||||
VmaAllocationInfo alloc_info{};
|
||||
vk::Check(vmaCreateImage(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info));
|
||||
|
||||
vk::Check(vmaCreateBuffer(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info));
|
||||
vmaGetAllocationMemoryProperties(allocator, allocation, &property_flags);
|
||||
|
||||
// Log GPU memory allocation for buffers
|
||||
if (GPU::Logging::IsActive() &&
|
||||
Settings::values.gpu_log_memory_tracking.GetValue()) {
|
||||
GPU::Logging::GPULogger::GetInstance().LogMemoryAllocation(
|
||||
reinterpret_cast<uintptr_t>(alloc_info.deviceMemory),
|
||||
static_cast<u64>(alloc_info.size),
|
||||
property_flags
|
||||
);
|
||||
}
|
||||
|
||||
u8 *data = reinterpret_cast<u8 *>(alloc_info.pMappedData);
|
||||
const std::span<u8> mapped_data = data ? std::span<u8>{data, ci.size} : std::span<u8>{};
|
||||
const bool is_coherent = (property_flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0;
|
||||
|
||||
return vk::Buffer(handle, *device.GetLogical(), allocator, allocation, mapped_data,
|
||||
is_coherent,
|
||||
device.GetDispatchLoader());
|
||||
// Log GPU memory allocation for images
|
||||
if (GPU::Logging::IsActive() &&
|
||||
Settings::values.gpu_log_memory_tracking.GetValue()) {
|
||||
GPU::Logging::GPULogger::GetInstance().LogMemoryAllocation(
|
||||
reinterpret_cast<uintptr_t>(alloc_info.deviceMemory),
|
||||
static_cast<u64>(alloc_info.size),
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
||||
);
|
||||
}
|
||||
|
||||
MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements &reqs, MemoryUsage usage)
|
||||
{
|
||||
const auto vma_usage = MemoryUsageVma(usage);
|
||||
VmaAllocationCreateInfo ci{};
|
||||
ci.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | MemoryUsageVmaFlags(usage);
|
||||
ci.usage = vma_usage;
|
||||
ci.memoryTypeBits = reqs.memoryTypeBits & valid_memory_types;
|
||||
ci.requiredFlags = 0;
|
||||
ci.preferredFlags = MemoryUsagePreferredVmaFlags(usage);
|
||||
return vk::Image(handle, ci.usage, *device.GetLogical(), allocator, allocation,
|
||||
device.GetDispatchLoader());
|
||||
}
|
||||
|
||||
VmaAllocation a{};
|
||||
VmaAllocationInfo info{};
|
||||
vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo &ci, MemoryUsage usage) const {
|
||||
// MESA will do memcpy() if not marked as host cached, so just force mark it for most buffers
|
||||
auto const anv_flags = (usage == MemoryUsage::Stream
|
||||
&& device.GetDriverID() == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA)
|
||||
? VK_MEMORY_PROPERTY_HOST_CACHED_BIT : 0;
|
||||
const VmaAllocationCreateInfo alloc_ci = {
|
||||
.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | MemoryUsageVmaFlags(usage),
|
||||
.usage = MemoryUsageVma(usage),
|
||||
.requiredFlags = 0,
|
||||
.preferredFlags = MemoryUsagePreferredVmaFlags(usage) | anv_flags,
|
||||
.memoryTypeBits = usage == MemoryUsage::Stream ? 0u : valid_memory_types,
|
||||
.pool = VK_NULL_HANDLE,
|
||||
.pUserData = nullptr,
|
||||
.priority = 0.f,
|
||||
};
|
||||
|
||||
VkResult res = vmaAllocateMemory(allocator, &reqs, &ci, &a, &info);
|
||||
VkBuffer handle{};
|
||||
VmaAllocationInfo alloc_info{};
|
||||
VmaAllocation allocation{};
|
||||
VkMemoryPropertyFlags property_flags{};
|
||||
|
||||
if (res != VK_SUCCESS) {
|
||||
// Relax 1: drop budget constraint
|
||||
auto ci2 = ci;
|
||||
ci2.flags &= ~VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT;
|
||||
res = vmaAllocateMemory(allocator, &reqs, &ci2, &a, &info);
|
||||
vk::Check(vmaCreateBuffer(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info));
|
||||
vmaGetAllocationMemoryProperties(allocator, allocation, &property_flags);
|
||||
|
||||
// Relax 2: if we preferred DEVICE_LOCAL, drop that preference
|
||||
if (res != VK_SUCCESS && (ci.preferredFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
|
||||
auto ci3 = ci2;
|
||||
ci3.preferredFlags &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
res = vmaAllocateMemory(allocator, &reqs, &ci3, &a, &info);
|
||||
}
|
||||
}
|
||||
|
||||
vk::Check(res);
|
||||
return MemoryCommit(allocator, a, info);
|
||||
// Log GPU memory allocation for buffers
|
||||
if (GPU::Logging::IsActive() &&
|
||||
Settings::values.gpu_log_memory_tracking.GetValue()) {
|
||||
GPU::Logging::GPULogger::GetInstance().LogMemoryAllocation(
|
||||
reinterpret_cast<uintptr_t>(alloc_info.deviceMemory),
|
||||
static_cast<u64>(alloc_info.size),
|
||||
property_flags
|
||||
);
|
||||
}
|
||||
|
||||
MemoryCommit MemoryAllocator::Commit(const vk::Buffer &buffer, MemoryUsage usage) {
|
||||
// Allocate memory appropriate for this buffer automatically
|
||||
const auto vma_usage = MemoryUsageVma(usage);
|
||||
u8 *data = reinterpret_cast<u8 *>(alloc_info.pMappedData);
|
||||
const std::span<u8> mapped_data = data ? std::span<u8>{data, ci.size} : std::span<u8>{};
|
||||
const bool is_coherent = (property_flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0;
|
||||
|
||||
VmaAllocationCreateInfo ci{};
|
||||
ci.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | MemoryUsageVmaFlags(usage);
|
||||
ci.usage = vma_usage;
|
||||
ci.requiredFlags = 0;
|
||||
ci.preferredFlags = MemoryUsagePreferredVmaFlags(usage);
|
||||
ci.pool = VK_NULL_HANDLE;
|
||||
ci.pUserData = nullptr;
|
||||
ci.priority = 0.0f;
|
||||
return vk::Buffer(handle, *device.GetLogical(), allocator, allocation, mapped_data,
|
||||
is_coherent,
|
||||
device.GetDispatchLoader());
|
||||
}
|
||||
|
||||
const VkBuffer raw = *buffer;
|
||||
MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements &reqs, MemoryUsage usage)
|
||||
{
|
||||
const auto vma_usage = MemoryUsageVma(usage);
|
||||
VmaAllocationCreateInfo ci{};
|
||||
ci.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | MemoryUsageVmaFlags(usage);
|
||||
ci.usage = vma_usage;
|
||||
ci.memoryTypeBits = reqs.memoryTypeBits & valid_memory_types;
|
||||
ci.requiredFlags = 0;
|
||||
ci.preferredFlags = MemoryUsagePreferredVmaFlags(usage);
|
||||
|
||||
VmaAllocation a{};
|
||||
VmaAllocationInfo info{};
|
||||
VmaAllocation a{};
|
||||
VmaAllocationInfo info{};
|
||||
|
||||
// Let VMA infer memory requirements from the buffer
|
||||
VkResult res = vmaAllocateMemoryForBuffer(allocator, raw, &ci, &a, &info);
|
||||
VkResult res = vmaAllocateMemory(allocator, &reqs, &ci, &a, &info);
|
||||
|
||||
if (res != VK_SUCCESS) {
|
||||
auto ci2 = ci;
|
||||
ci2.flags &= ~VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT;
|
||||
res = vmaAllocateMemoryForBuffer(allocator, raw, &ci2, &a, &info);
|
||||
if (res != VK_SUCCESS) {
|
||||
// Relax 1: drop budget constraint
|
||||
auto ci2 = ci;
|
||||
ci2.flags &= ~VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT;
|
||||
res = vmaAllocateMemory(allocator, &reqs, &ci2, &a, &info);
|
||||
|
||||
if (res != VK_SUCCESS && (ci.preferredFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
|
||||
auto ci3 = ci2;
|
||||
ci3.preferredFlags &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
res = vmaAllocateMemoryForBuffer(allocator, raw, &ci3, &a, &info);
|
||||
}
|
||||
// Relax 2: if we preferred DEVICE_LOCAL, drop that preference
|
||||
if (res != VK_SUCCESS && (ci.preferredFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
|
||||
auto ci3 = ci2;
|
||||
ci3.preferredFlags &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
res = vmaAllocateMemory(allocator, &reqs, &ci3, &a, &info);
|
||||
}
|
||||
|
||||
vk::Check(res);
|
||||
vk::Check(vmaBindBufferMemory2(allocator, a, 0, raw, nullptr));
|
||||
return MemoryCommit(allocator, a, info);
|
||||
}
|
||||
|
||||
vk::Check(res);
|
||||
return MemoryCommit(allocator, a, info);
|
||||
}
|
||||
|
||||
MemoryCommit MemoryAllocator::Commit(const vk::Buffer &buffer, MemoryUsage usage) {
|
||||
// Allocate memory appropriate for this buffer automatically
|
||||
const auto vma_usage = MemoryUsageVma(usage);
|
||||
|
||||
VmaAllocationCreateInfo ci{};
|
||||
ci.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | MemoryUsageVmaFlags(usage);
|
||||
ci.usage = vma_usage;
|
||||
ci.requiredFlags = 0;
|
||||
ci.preferredFlags = MemoryUsagePreferredVmaFlags(usage);
|
||||
ci.pool = VK_NULL_HANDLE;
|
||||
ci.pUserData = nullptr;
|
||||
ci.priority = 0.0f;
|
||||
|
||||
const VkBuffer raw = *buffer;
|
||||
|
||||
VmaAllocation a{};
|
||||
VmaAllocationInfo info{};
|
||||
|
||||
// Let VMA infer memory requirements from the buffer
|
||||
VkResult res = vmaAllocateMemoryForBuffer(allocator, raw, &ci, &a, &info);
|
||||
|
||||
if (res != VK_SUCCESS) {
|
||||
auto ci2 = ci;
|
||||
ci2.flags &= ~VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT;
|
||||
res = vmaAllocateMemoryForBuffer(allocator, raw, &ci2, &a, &info);
|
||||
|
||||
if (res != VK_SUCCESS && (ci.preferredFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
|
||||
auto ci3 = ci2;
|
||||
ci3.preferredFlags &= ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
res = vmaAllocateMemoryForBuffer(allocator, raw, &ci3, &a, &info);
|
||||
}
|
||||
}
|
||||
|
||||
vk::Check(res);
|
||||
vk::Check(vmaBindBufferMemory2(allocator, a, 0, raw, nullptr));
|
||||
return MemoryCommit(allocator, a, info);
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
@@ -4796,6 +4796,6 @@ void VolumeButton::ResetMultiplier() {
|
||||
#endif
|
||||
|
||||
#if !defined(QT_STATICPLUGIN) || defined(__APPLE__)
|
||||
#define VMA_IMPLEMENTATION
|
||||
#define VMA_IMPLEMENTATION 1
|
||||
#include "video_core/vulkan_common/vma.h"
|
||||
#endif
|
||||
|
||||
@@ -65,7 +65,7 @@ else()
|
||||
endif()
|
||||
|
||||
# update cached cpmfile content
|
||||
string(JSON cpmfile SET "${cpmfile}" "${key}" "${new_object}")
|
||||
string(JSON cpmfile SET "${cpmfile}" "${KEY}" "${new_object}")
|
||||
|
||||
# write cached cpmfile
|
||||
get_cpmfile_path(file)
|
||||
|
||||
Reference in New Issue
Block a user