Merging
This commit is contained in:
commit
d5129d9347
14 changed files with 380 additions and 494 deletions
|
@ -3,4 +3,4 @@
|
|||
|
||||
[codespell]
|
||||
skip = ./.git,./build,./dist,./Doxyfile,./externals,./LICENSES
|
||||
ignore-words-list = aci,allright,ba,deques,froms,hda,inout,lod,masia,nam,nax,nd,pullrequests,pullrequest,te,transfered,unstall,uscaled,zink
|
||||
ignore-words-list = aci,allright,ba,deques,froms,hda,inout,lod,masia,nam,nax,nd,optin,pullrequests,pullrequest,te,transfered,unstall,uscaled,zink
|
||||
|
|
|
@ -223,6 +223,8 @@ object NativeLibrary {
|
|||
|
||||
external fun getCompany(filename: String): String
|
||||
|
||||
external fun isHomebrew(filename: String): Boolean
|
||||
|
||||
external fun setAppDirectory(directory: String)
|
||||
|
||||
external fun initializeGpuDriver(
|
||||
|
|
|
@ -6,15 +6,12 @@ package org.yuzu.yuzu_emu.activities
|
|||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Rect
|
||||
import android.hardware.Sensor
|
||||
import android.hardware.SensorEvent
|
||||
import android.hardware.SensorEventListener
|
||||
import android.hardware.SensorManager
|
||||
import android.hardware.display.DisplayManager
|
||||
import android.os.Bundle
|
||||
import android.view.Display
|
||||
import android.view.InputDevice
|
||||
import android.view.KeyEvent
|
||||
import android.view.MotionEvent
|
||||
|
@ -23,7 +20,6 @@ import android.view.View
|
|||
import android.view.inputmethod.InputMethodManager
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
|
@ -39,7 +35,6 @@ import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel
|
|||
import org.yuzu.yuzu_emu.fragments.EmulationFragment
|
||||
import org.yuzu.yuzu_emu.model.Game
|
||||
import org.yuzu.yuzu_emu.utils.ControllerMappingHelper
|
||||
import org.yuzu.yuzu_emu.utils.EmulationMenuSettings
|
||||
import org.yuzu.yuzu_emu.utils.ForegroundService
|
||||
import org.yuzu.yuzu_emu.utils.InputHandler
|
||||
import org.yuzu.yuzu_emu.utils.NfcReader
|
||||
|
@ -148,11 +143,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
|||
super.onResume()
|
||||
nfcReader.startScanning()
|
||||
startMotionSensorListener()
|
||||
|
||||
NativeLibrary.notifyOrientationChange(
|
||||
EmulationMenuSettings.landscapeScreenLayout,
|
||||
getAdjustedRotation()
|
||||
)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
|
@ -258,24 +248,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
|||
|
||||
override fun onAccuracyChanged(sensor: Sensor, i: Int) {}
|
||||
|
||||
private fun getAdjustedRotation():Int {
|
||||
val rotation = getSystemService<DisplayManager>()!!.getDisplay(Display.DEFAULT_DISPLAY).rotation
|
||||
val config: Configuration = resources.configuration
|
||||
|
||||
if ((config.screenLayout and Configuration.SCREENLAYOUT_LONG_YES) != 0 ||
|
||||
(config.screenLayout and Configuration.SCREENLAYOUT_LONG_NO) == 0 ||
|
||||
(config.screenLayout and Configuration.SCREENLAYOUT_SIZE_SMALL) != 0) {
|
||||
return rotation
|
||||
}
|
||||
when (rotation) {
|
||||
Surface.ROTATION_0 -> return Surface.ROTATION_90
|
||||
Surface.ROTATION_90 -> return Surface.ROTATION_0
|
||||
Surface.ROTATION_180 -> return Surface.ROTATION_270
|
||||
Surface.ROTATION_270 -> return Surface.ROTATION_180
|
||||
}
|
||||
return rotation
|
||||
}
|
||||
|
||||
private fun restoreState(savedInstanceState: Bundle) {
|
||||
game = savedInstanceState.parcelable(EXTRA_SELECTED_GAME)!!
|
||||
}
|
||||
|
|
|
@ -127,13 +127,7 @@ class SearchFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
R.id.chip_homebrew -> {
|
||||
baseList.filter {
|
||||
Log.error("Guh - ${it.path}")
|
||||
FileUtil.hasExtension(it.path, "nro")
|
||||
|| FileUtil.hasExtension(it.path, "nso")
|
||||
}
|
||||
}
|
||||
R.id.chip_homebrew -> baseList.filter { it.isHomebrew }
|
||||
|
||||
R.id.chip_retail -> baseList.filter {
|
||||
FileUtil.hasExtension(it.path, "xci")
|
||||
|
|
|
@ -16,7 +16,8 @@ class Game(
|
|||
val regions: String,
|
||||
val path: String,
|
||||
val gameId: String,
|
||||
val company: String
|
||||
val company: String,
|
||||
val isHomebrew: Boolean
|
||||
) : Parcelable {
|
||||
val keyAddedToLibraryTime get() = "${gameId}_AddedToLibraryTime"
|
||||
val keyLastPlayedTime get() = "${gameId}_LastPlayed"
|
||||
|
@ -31,6 +32,7 @@ class Game(
|
|||
&& path == other.path
|
||||
&& gameId == other.gameId
|
||||
&& company == other.company
|
||||
&& isHomebrew == other.isHomebrew
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -13,6 +13,8 @@ import androidx.preference.PreferenceManager
|
|||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.MissingFieldException
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
|
@ -20,6 +22,7 @@ import org.yuzu.yuzu_emu.YuzuApplication
|
|||
import org.yuzu.yuzu_emu.utils.GameHelper
|
||||
import java.util.Locale
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
class GamesViewModel : ViewModel() {
|
||||
private val _games = MutableLiveData<List<Game>>(emptyList())
|
||||
val games: LiveData<List<Game>> get() = _games
|
||||
|
@ -49,7 +52,13 @@ class GamesViewModel : ViewModel() {
|
|||
if (storedGames!!.isNotEmpty()) {
|
||||
val deserializedGames = mutableSetOf<Game>()
|
||||
storedGames.forEach {
|
||||
val game: Game = Json.decodeFromString(it)
|
||||
val game: Game
|
||||
try {
|
||||
game = Json.decodeFromString(it)
|
||||
} catch (e: MissingFieldException) {
|
||||
return@forEach
|
||||
}
|
||||
|
||||
val gameExists =
|
||||
DocumentFile.fromSingleUri(YuzuApplication.appContext, Uri.parse(game.path))
|
||||
?.exists()
|
||||
|
|
|
@ -765,18 +765,20 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
|
|||
// If we have API access, calculate the safe area to draw the overlay
|
||||
var cutoutLeft = 0
|
||||
var cutoutBottom = 0
|
||||
val insets = context.windowManager.currentWindowMetrics.windowInsets.displayCutout
|
||||
if (insets != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
if (insets.boundingRectTop.bottom != 0 && insets.boundingRectTop.bottom > maxY / 2)
|
||||
insets.boundingRectTop.bottom.toFloat() else maxY
|
||||
if (insets.boundingRectRight.left != 0 && insets.boundingRectRight.left > maxX / 2)
|
||||
insets.boundingRectRight.left.toFloat() else maxX
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
val insets = context.windowManager.currentWindowMetrics.windowInsets.displayCutout
|
||||
if (insets != null) {
|
||||
if (insets.boundingRectTop.bottom != 0 && insets.boundingRectTop.bottom > maxY / 2)
|
||||
insets.boundingRectTop.bottom.toFloat() else maxY
|
||||
if (insets.boundingRectRight.left != 0 && insets.boundingRectRight.left > maxX / 2)
|
||||
insets.boundingRectRight.left.toFloat() else maxX
|
||||
|
||||
minX = insets.boundingRectLeft.right - insets.boundingRectLeft.left
|
||||
minY = insets.boundingRectBottom.top - insets.boundingRectBottom.bottom
|
||||
minX = insets.boundingRectLeft.right - insets.boundingRectLeft.left
|
||||
minY = insets.boundingRectBottom.top - insets.boundingRectBottom.bottom
|
||||
|
||||
cutoutLeft = insets.boundingRectRight.right - insets.boundingRectRight.left
|
||||
cutoutBottom = insets.boundingRectTop.top - insets.boundingRectTop.bottom
|
||||
cutoutLeft = insets.boundingRectRight.right - insets.boundingRectRight.left
|
||||
cutoutBottom = insets.boundingRectTop.top - insets.boundingRectTop.bottom
|
||||
}
|
||||
}
|
||||
|
||||
// This makes sure that if we have an inset on one side of the screen, we mirror it on
|
||||
|
|
|
@ -6,7 +6,6 @@ package org.yuzu.yuzu_emu.utils
|
|||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
import androidx.preference.PreferenceManager
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
|
@ -83,7 +82,8 @@ object GameHelper {
|
|||
NativeLibrary.getRegions(filePath),
|
||||
filePath,
|
||||
gameId,
|
||||
NativeLibrary.getCompany(filePath)
|
||||
NativeLibrary.getCompany(filePath),
|
||||
NativeLibrary.isHomebrew(filePath)
|
||||
)
|
||||
|
||||
val addedTime = preferences.getLong(newGame.keyAddedToLibraryTime, 0L)
|
||||
|
|
|
@ -13,8 +13,7 @@
|
|||
|
||||
#include <android/api-level.h>
|
||||
#include <android/native_window_jni.h>
|
||||
#include <network/room_member.h>
|
||||
#include <network/network.h>
|
||||
#include <core/loader/nro.h>
|
||||
|
||||
#include "common/detached_tasks.h"
|
||||
#include "common/dynamic_library.h"
|
||||
|
@ -59,390 +58,365 @@
|
|||
|
||||
namespace {
|
||||
|
||||
class EmulationSession final {
|
||||
public:
|
||||
EmulationSession() {
|
||||
m_vfs = std::make_shared<FileSys::RealVfsFilesystem>();
|
||||
}
|
||||
class EmulationSession final {
|
||||
public:
|
||||
EmulationSession() {
|
||||
m_vfs = std::make_shared<FileSys::RealVfsFilesystem>();
|
||||
}
|
||||
|
||||
~EmulationSession() = default;
|
||||
~EmulationSession() = default;
|
||||
|
||||
static EmulationSession& GetInstance() {
|
||||
return s_instance;
|
||||
}
|
||||
static EmulationSession& GetInstance() {
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
const Core::System& System() const {
|
||||
return m_system;
|
||||
}
|
||||
const Core::System& System() const {
|
||||
return m_system;
|
||||
}
|
||||
|
||||
Core::System& System() {
|
||||
return m_system;
|
||||
}
|
||||
Core::System& System() {
|
||||
return m_system;
|
||||
}
|
||||
|
||||
const EmuWindow_Android& Window() const {
|
||||
return *m_window;
|
||||
}
|
||||
const EmuWindow_Android& Window() const {
|
||||
return *m_window;
|
||||
}
|
||||
|
||||
EmuWindow_Android& Window() {
|
||||
return *m_window;
|
||||
}
|
||||
EmuWindow_Android& Window() {
|
||||
return *m_window;
|
||||
}
|
||||
|
||||
ANativeWindow* NativeWindow() const {
|
||||
return m_native_window;
|
||||
}
|
||||
ANativeWindow* NativeWindow() const {
|
||||
return m_native_window;
|
||||
}
|
||||
|
||||
void SetNativeWindow(ANativeWindow* native_window) {
|
||||
m_native_window = native_window;
|
||||
}
|
||||
void SetNativeWindow(ANativeWindow* native_window) {
|
||||
m_native_window = native_window;
|
||||
}
|
||||
|
||||
u32 ScreenRotation() const {
|
||||
return m_screen_rotation;
|
||||
}
|
||||
|
||||
void SetScreenRotation(u32 screen_rotation) {
|
||||
m_screen_rotation = screen_rotation;
|
||||
}
|
||||
|
||||
void InitializeGpuDriver(const std::string& hook_lib_dir, const std::string& custom_driver_dir,
|
||||
const std::string& custom_driver_name,
|
||||
const std::string& file_redirect_dir) {
|
||||
void InitializeGpuDriver(const std::string& hook_lib_dir, const std::string& custom_driver_dir,
|
||||
const std::string& custom_driver_name,
|
||||
const std::string& file_redirect_dir) {
|
||||
#ifdef ARCHITECTURE_arm64
|
||||
void* handle{};
|
||||
const char* file_redirect_dir_{};
|
||||
int featureFlags{};
|
||||
void* handle{};
|
||||
const char* file_redirect_dir_{};
|
||||
int featureFlags{};
|
||||
|
||||
// Enable driver file redirection when renderer debugging is enabled.
|
||||
if (Settings::values.renderer_debug && file_redirect_dir.size()) {
|
||||
featureFlags |= ADRENOTOOLS_DRIVER_FILE_REDIRECT;
|
||||
file_redirect_dir_ = file_redirect_dir.c_str();
|
||||
}
|
||||
// Enable driver file redirection when renderer debugging is enabled.
|
||||
if (Settings::values.renderer_debug && file_redirect_dir.size()) {
|
||||
featureFlags |= ADRENOTOOLS_DRIVER_FILE_REDIRECT;
|
||||
file_redirect_dir_ = file_redirect_dir.c_str();
|
||||
}
|
||||
|
||||
// Try to load a custom driver.
|
||||
if (custom_driver_name.size()) {
|
||||
handle = adrenotools_open_libvulkan(
|
||||
RTLD_NOW, featureFlags | ADRENOTOOLS_DRIVER_CUSTOM, nullptr, hook_lib_dir.c_str(),
|
||||
custom_driver_dir.c_str(), custom_driver_name.c_str(), file_redirect_dir_, nullptr);
|
||||
}
|
||||
// Try to load a custom driver.
|
||||
if (custom_driver_name.size()) {
|
||||
handle = adrenotools_open_libvulkan(
|
||||
RTLD_NOW, featureFlags | ADRENOTOOLS_DRIVER_CUSTOM, nullptr, hook_lib_dir.c_str(),
|
||||
custom_driver_dir.c_str(), custom_driver_name.c_str(), file_redirect_dir_, nullptr);
|
||||
}
|
||||
|
||||
// Try to load the system driver.
|
||||
if (!handle) {
|
||||
handle =
|
||||
adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(),
|
||||
nullptr, nullptr, file_redirect_dir_, nullptr);
|
||||
}
|
||||
// Try to load the system driver.
|
||||
if (!handle) {
|
||||
handle =
|
||||
adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(),
|
||||
nullptr, nullptr, file_redirect_dir_, nullptr);
|
||||
}
|
||||
|
||||
m_vulkan_library = std::make_shared<Common::DynamicLibrary>(handle);
|
||||
m_vulkan_library = std::make_shared<Common::DynamicLibrary>(handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IsRunning() const {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
return m_is_running;
|
||||
}
|
||||
|
||||
const Core::PerfStatsResults& PerfStats() const {
|
||||
std::scoped_lock m_perf_stats_lock(m_perf_stats_mutex);
|
||||
return m_perf_stats;
|
||||
}
|
||||
|
||||
void SurfaceChanged() {
|
||||
if (!IsRunning()) {
|
||||
return;
|
||||
}
|
||||
m_window->OnSurfaceChanged(m_native_window);
|
||||
m_system.Renderer().NotifySurfaceChanged();
|
||||
}
|
||||
|
||||
Core::SystemResultStatus InitializeEmulation(const std::string& filepath) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
|
||||
// Loads the configuration.
|
||||
Config{};
|
||||
|
||||
// Create the render window.
|
||||
m_window = std::make_unique<EmuWindow_Android>(&m_input_subsystem, m_native_window,
|
||||
m_vulkan_library);
|
||||
|
||||
// Initialize system.
|
||||
auto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>();
|
||||
m_software_keyboard = android_keyboard.get();
|
||||
m_system.SetShuttingDown(false);
|
||||
m_system.ApplySettings();
|
||||
m_system.HIDCore().ReloadInputDevices();
|
||||
m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
|
||||
m_system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
|
||||
m_system.SetAppletFrontendSet({
|
||||
nullptr, // Amiibo Settings
|
||||
nullptr, // Controller Selector
|
||||
nullptr, // Error Display
|
||||
nullptr, // Mii Editor
|
||||
nullptr, // Parental Controls
|
||||
nullptr, // Photo Viewer
|
||||
nullptr, // Profile Selector
|
||||
std::move(android_keyboard), // Software Keyboard
|
||||
nullptr, // Web Browser
|
||||
});
|
||||
m_system.GetFileSystemController().CreateFactories(*m_system.GetFilesystem());
|
||||
|
||||
// Initialize account manager
|
||||
m_profile_manager = std::make_unique<Service::Account::ProfileManager>();
|
||||
|
||||
// Load the ROM.
|
||||
m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath);
|
||||
if (m_load_result != Core::SystemResultStatus::Success) {
|
||||
return m_load_result;
|
||||
}
|
||||
|
||||
// Complete initialization.
|
||||
m_system.GPU().Start();
|
||||
m_system.GetCpuManager().OnGpuReady();
|
||||
m_system.RegisterExitCallback([&] { HaltEmulation(); });
|
||||
|
||||
return Core::SystemResultStatus::Success;
|
||||
}
|
||||
|
||||
void ShutdownEmulation() {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
|
||||
m_is_running = false;
|
||||
|
||||
// Unload user input.
|
||||
m_system.HIDCore().UnloadInputDevices();
|
||||
|
||||
// Shutdown the main emulated process
|
||||
if (m_load_result == Core::SystemResultStatus::Success) {
|
||||
m_system.DetachDebugger();
|
||||
m_system.ShutdownMainProcess();
|
||||
m_detached_tasks.WaitForAllTasks();
|
||||
m_load_result = Core::SystemResultStatus::ErrorNotInitialized;
|
||||
}
|
||||
|
||||
// Tear down the render window.
|
||||
m_window.reset();
|
||||
}
|
||||
|
||||
void PauseEmulation() {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
m_system.Pause();
|
||||
}
|
||||
|
||||
void UnPauseEmulation() {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
m_system.Run();
|
||||
}
|
||||
|
||||
void HaltEmulation() {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
m_is_running = false;
|
||||
m_cv.notify_one();
|
||||
}
|
||||
|
||||
void RunEmulation() {
|
||||
{
|
||||
bool IsRunning() const {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
m_is_running = true;
|
||||
return m_is_running;
|
||||
}
|
||||
|
||||
// Load the disk shader cache.
|
||||
if (Settings::values.use_disk_shader_cache.GetValue()) {
|
||||
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
|
||||
m_system.Renderer().ReadRasterizer()->LoadDiskResources(
|
||||
m_system.GetApplicationProcessProgramID(), std::stop_token{},
|
||||
LoadDiskCacheProgress);
|
||||
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
|
||||
const Core::PerfStatsResults& PerfStats() const {
|
||||
std::scoped_lock m_perf_stats_lock(m_perf_stats_mutex);
|
||||
return m_perf_stats;
|
||||
}
|
||||
|
||||
void(m_system.Run());
|
||||
|
||||
if (m_system.DebuggerEnabled()) {
|
||||
m_system.InitializeDebugger();
|
||||
void SurfaceChanged() {
|
||||
if (!IsRunning()) {
|
||||
return;
|
||||
}
|
||||
m_window->OnSurfaceChanged(m_native_window);
|
||||
m_system.Renderer().NotifySurfaceChanged();
|
||||
}
|
||||
|
||||
while (true) {
|
||||
Core::SystemResultStatus InitializeEmulation(const std::string& filepath) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
|
||||
// Loads the configuration.
|
||||
Config{};
|
||||
|
||||
// Create the render window.
|
||||
m_window = std::make_unique<EmuWindow_Android>(&m_input_subsystem, m_native_window,
|
||||
m_vulkan_library);
|
||||
|
||||
// Initialize system.
|
||||
auto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>();
|
||||
m_software_keyboard = android_keyboard.get();
|
||||
m_system.SetShuttingDown(false);
|
||||
m_system.ApplySettings();
|
||||
m_system.HIDCore().ReloadInputDevices();
|
||||
m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
|
||||
m_system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
|
||||
m_system.SetAppletFrontendSet({
|
||||
nullptr, // Amiibo Settings
|
||||
nullptr, // Controller Selector
|
||||
nullptr, // Error Display
|
||||
nullptr, // Mii Editor
|
||||
nullptr, // Parental Controls
|
||||
nullptr, // Photo Viewer
|
||||
nullptr, // Profile Selector
|
||||
std::move(android_keyboard), // Software Keyboard
|
||||
nullptr, // Web Browser
|
||||
});
|
||||
m_system.GetFileSystemController().CreateFactories(*m_system.GetFilesystem());
|
||||
|
||||
// Initialize account manager
|
||||
m_profile_manager = std::make_unique<Service::Account::ProfileManager>();
|
||||
|
||||
// Load the ROM.
|
||||
m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath);
|
||||
if (m_load_result != Core::SystemResultStatus::Success) {
|
||||
return m_load_result;
|
||||
}
|
||||
|
||||
// Complete initialization.
|
||||
m_system.GPU().Start();
|
||||
m_system.GetCpuManager().OnGpuReady();
|
||||
m_system.RegisterExitCallback([&] { HaltEmulation(); });
|
||||
|
||||
return Core::SystemResultStatus::Success;
|
||||
}
|
||||
|
||||
void ShutdownEmulation() {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
|
||||
m_is_running = false;
|
||||
|
||||
// Unload user input.
|
||||
m_system.HIDCore().UnloadInputDevices();
|
||||
|
||||
// Shutdown the main emulated process
|
||||
if (m_load_result == Core::SystemResultStatus::Success) {
|
||||
m_system.DetachDebugger();
|
||||
m_system.ShutdownMainProcess();
|
||||
m_detached_tasks.WaitForAllTasks();
|
||||
m_load_result = Core::SystemResultStatus::ErrorNotInitialized;
|
||||
}
|
||||
|
||||
// Tear down the render window.
|
||||
m_window.reset();
|
||||
}
|
||||
|
||||
void PauseEmulation() {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
m_system.Pause();
|
||||
}
|
||||
|
||||
void UnPauseEmulation() {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
m_system.Run();
|
||||
}
|
||||
|
||||
void HaltEmulation() {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
m_is_running = false;
|
||||
m_cv.notify_one();
|
||||
}
|
||||
|
||||
void RunEmulation() {
|
||||
{
|
||||
std::unique_lock lock(m_mutex);
|
||||
if (m_cv.wait_for(lock, std::chrono::milliseconds(800),
|
||||
[&]() { return !m_is_running; })) {
|
||||
// Emulation halted.
|
||||
break;
|
||||
std::scoped_lock lock(m_mutex);
|
||||
m_is_running = true;
|
||||
}
|
||||
|
||||
// Load the disk shader cache.
|
||||
if (Settings::values.use_disk_shader_cache.GetValue()) {
|
||||
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
|
||||
m_system.Renderer().ReadRasterizer()->LoadDiskResources(
|
||||
m_system.GetApplicationProcessProgramID(), std::stop_token{},
|
||||
LoadDiskCacheProgress);
|
||||
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
|
||||
}
|
||||
|
||||
void(m_system.Run());
|
||||
|
||||
if (m_system.DebuggerEnabled()) {
|
||||
m_system.InitializeDebugger();
|
||||
}
|
||||
|
||||
while (true) {
|
||||
{
|
||||
std::unique_lock lock(m_mutex);
|
||||
if (m_cv.wait_for(lock, std::chrono::milliseconds(800),
|
||||
[&]() { return !m_is_running; })) {
|
||||
// Emulation halted.
|
||||
break;
|
||||
}
|
||||
}
|
||||
{
|
||||
// Refresh performance stats.
|
||||
std::scoped_lock m_perf_stats_lock(m_perf_stats_mutex);
|
||||
m_perf_stats = m_system.GetAndResetPerfStats();
|
||||
}
|
||||
}
|
||||
{
|
||||
// Refresh performance stats.
|
||||
std::scoped_lock m_perf_stats_lock(m_perf_stats_mutex);
|
||||
m_perf_stats = m_system.GetAndResetPerfStats();
|
||||
}
|
||||
|
||||
std::string GetRomTitle(const std::string& path) {
|
||||
return GetRomMetadata(path).title;
|
||||
}
|
||||
|
||||
std::vector<u8> GetRomIcon(const std::string& path) {
|
||||
return GetRomMetadata(path).icon;
|
||||
}
|
||||
|
||||
bool GetIsHomebrew(const std::string& path) {
|
||||
return GetRomMetadata(path).isHomebrew;
|
||||
}
|
||||
|
||||
void ResetRomMetadata() {
|
||||
m_rom_metadata_cache.clear();
|
||||
}
|
||||
|
||||
bool IsHandheldOnly() {
|
||||
const auto npad_style_set = m_system.HIDCore().GetSupportedStyleTag();
|
||||
|
||||
if (npad_style_set.fullkey == 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetRomTitle(const std::string& path) {
|
||||
return GetRomMetadata(path).title;
|
||||
}
|
||||
if (npad_style_set.handheld == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<u8> GetRomIcon(const std::string& path) {
|
||||
return GetRomMetadata(path).icon;
|
||||
}
|
||||
|
||||
void ResetRomMetadata() {
|
||||
m_rom_metadata_cache.clear();
|
||||
}
|
||||
|
||||
bool IsHandheldOnly() {
|
||||
const auto npad_style_set = m_system.HIDCore().GetSupportedStyleTag();
|
||||
|
||||
if (npad_style_set.fullkey == 1) {
|
||||
return false;
|
||||
return !Settings::values.use_docked_mode.GetValue();
|
||||
}
|
||||
|
||||
if (npad_style_set.handheld == 0) {
|
||||
return false;
|
||||
void SetDeviceType(int index, int type) {
|
||||
auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
|
||||
controller->SetNpadStyleIndex(static_cast<Core::HID::NpadStyleIndex>(type));
|
||||
}
|
||||
|
||||
return !Settings::values.use_docked_mode.GetValue();
|
||||
}
|
||||
void OnGamepadConnectEvent(int index) {
|
||||
auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
|
||||
|
||||
void SetDeviceType(int index, int type) {
|
||||
auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
|
||||
controller->SetNpadStyleIndex(static_cast<Core::HID::NpadStyleIndex>(type));
|
||||
}
|
||||
// Ensure that player1 is configured correctly and handheld disconnected
|
||||
if (controller->GetNpadIdType() == Core::HID::NpadIdType::Player1) {
|
||||
auto handheld =
|
||||
m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
|
||||
|
||||
void OnGamepadConnectEvent(int index) {
|
||||
auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
|
||||
if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) {
|
||||
handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
|
||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
|
||||
handheld->Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that player1 is configured correctly and handheld disconnected
|
||||
if (controller->GetNpadIdType() == Core::HID::NpadIdType::Player1) {
|
||||
auto handheld =
|
||||
m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
|
||||
// Ensure that handheld is configured correctly and player 1 disconnected
|
||||
if (controller->GetNpadIdType() == Core::HID::NpadIdType::Handheld) {
|
||||
auto player1 = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
|
||||
|
||||
if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) {
|
||||
handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
|
||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
|
||||
handheld->Disconnect();
|
||||
if (controller->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::Handheld) {
|
||||
player1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
|
||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
|
||||
player1->Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
if (!controller->IsConnected()) {
|
||||
controller->Connect();
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that handheld is configured correctly and player 1 disconnected
|
||||
if (controller->GetNpadIdType() == Core::HID::NpadIdType::Handheld) {
|
||||
auto player1 = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
|
||||
void OnGamepadDisconnectEvent(int index) {
|
||||
auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
|
||||
controller->Disconnect();
|
||||
}
|
||||
|
||||
if (controller->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::Handheld) {
|
||||
player1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
|
||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
|
||||
player1->Disconnect();
|
||||
SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard() {
|
||||
return m_software_keyboard;
|
||||
}
|
||||
|
||||
private:
|
||||
struct RomMetadata {
|
||||
std::string title;
|
||||
std::vector<u8> icon;
|
||||
bool isHomebrew;
|
||||
};
|
||||
|
||||
RomMetadata GetRomMetadata(const std::string& path) {
|
||||
if (auto search = m_rom_metadata_cache.find(path); search != m_rom_metadata_cache.end()) {
|
||||
return search->second;
|
||||
}
|
||||
|
||||
return CacheRomMetadata(path);
|
||||
}
|
||||
|
||||
if (!controller->IsConnected()) {
|
||||
controller->Connect();
|
||||
}
|
||||
}
|
||||
RomMetadata CacheRomMetadata(const std::string& path) {
|
||||
const auto file = Core::GetGameFileFromPath(m_vfs, path);
|
||||
auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0);
|
||||
|
||||
void OnGamepadDisconnectEvent(int index) {
|
||||
auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
|
||||
controller->Disconnect();
|
||||
}
|
||||
|
||||
SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard() {
|
||||
return m_software_keyboard;
|
||||
}
|
||||
|
||||
void DirectConnectToRoom(const std::string& nickname, const char* server_addr = "127.0.0.1",
|
||||
u16 server_port = Network::DefaultRoomPort,
|
||||
const std::string& password = "") {
|
||||
auto room_network = m_system.GetRoomNetwork();
|
||||
|
||||
if (const auto member = room_network.GetRoomMember().lock()) {
|
||||
// Prevent the user from trying to join a room while they are already joining.
|
||||
if (member->GetState() == Network::RoomMember::State::Joining || member->IsConnected()) {
|
||||
return;
|
||||
RomMetadata entry;
|
||||
loader->ReadTitle(entry.title);
|
||||
loader->ReadIcon(entry.icon);
|
||||
if (loader->GetFileType() == Loader::FileType::NRO) {
|
||||
auto loader_nro = dynamic_cast<Loader::AppLoader_NRO*>(loader.get());
|
||||
entry.isHomebrew = loader_nro->IsHomebrew();
|
||||
} else {
|
||||
member->Join(nickname, server_addr, server_port);
|
||||
entry.isHomebrew = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Network::RoomMember::State GetRoomMemberState() {
|
||||
if (const auto member = m_system.GetRoomNetwork().GetRoomMember().lock()) {
|
||||
return member->GetState();
|
||||
} else {
|
||||
return Network::RoomMember::State::Idle;
|
||||
}
|
||||
}
|
||||
m_rom_metadata_cache[path] = entry;
|
||||
|
||||
private:
|
||||
struct RomMetadata {
|
||||
std::string title;
|
||||
std::vector<u8> icon;
|
||||
return entry;
|
||||
}
|
||||
|
||||
private:
|
||||
static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max) {
|
||||
JNIEnv* env = IDCache::GetEnvForThread();
|
||||
env->CallStaticVoidMethod(IDCache::GetDiskCacheProgressClass(),
|
||||
IDCache::GetDiskCacheLoadProgress(), static_cast<jint>(stage),
|
||||
static_cast<jint>(progress), static_cast<jint>(max));
|
||||
}
|
||||
|
||||
private:
|
||||
static EmulationSession s_instance;
|
||||
|
||||
// Frontend management
|
||||
std::unordered_map<std::string, RomMetadata> m_rom_metadata_cache;
|
||||
|
||||
// Window management
|
||||
std::unique_ptr<EmuWindow_Android> m_window;
|
||||
ANativeWindow* m_native_window{};
|
||||
|
||||
// Core emulation
|
||||
Core::System m_system;
|
||||
InputCommon::InputSubsystem m_input_subsystem;
|
||||
Common::DetachedTasks m_detached_tasks;
|
||||
Core::PerfStatsResults m_perf_stats{};
|
||||
std::shared_ptr<FileSys::RealVfsFilesystem> m_vfs;
|
||||
Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized};
|
||||
bool m_is_running{};
|
||||
SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
|
||||
std::unique_ptr<Service::Account::ProfileManager> m_profile_manager;
|
||||
|
||||
// GPU driver parameters
|
||||
std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;
|
||||
|
||||
// Synchronization
|
||||
std::condition_variable_any m_cv;
|
||||
mutable std::mutex m_perf_stats_mutex;
|
||||
mutable std::mutex m_mutex;
|
||||
};
|
||||
|
||||
RomMetadata GetRomMetadata(const std::string& path) {
|
||||
if (auto search = m_rom_metadata_cache.find(path); search != m_rom_metadata_cache.end()) {
|
||||
return search->second;
|
||||
}
|
||||
|
||||
return CacheRomMetadata(path);
|
||||
}
|
||||
|
||||
RomMetadata CacheRomMetadata(const std::string& path) {
|
||||
const auto file = Core::GetGameFileFromPath(m_vfs, path);
|
||||
const auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0);
|
||||
|
||||
RomMetadata entry;
|
||||
loader->ReadTitle(entry.title);
|
||||
loader->ReadIcon(entry.icon);
|
||||
|
||||
m_rom_metadata_cache[path] = entry;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
private:
|
||||
static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max) {
|
||||
JNIEnv* env = IDCache::GetEnvForThread();
|
||||
env->CallStaticVoidMethod(IDCache::GetDiskCacheProgressClass(),
|
||||
IDCache::GetDiskCacheLoadProgress(), static_cast<jint>(stage),
|
||||
static_cast<jint>(progress), static_cast<jint>(max));
|
||||
}
|
||||
|
||||
private:
|
||||
static EmulationSession s_instance;
|
||||
|
||||
// Frontend management
|
||||
std::unordered_map<std::string, RomMetadata> m_rom_metadata_cache;
|
||||
|
||||
// Window management
|
||||
std::unique_ptr<EmuWindow_Android> m_window;
|
||||
ANativeWindow* m_native_window{};
|
||||
u32 m_screen_rotation{};
|
||||
|
||||
// Core emulation
|
||||
Core::System m_system;
|
||||
InputCommon::InputSubsystem m_input_subsystem;
|
||||
Common::DetachedTasks m_detached_tasks;
|
||||
Core::PerfStatsResults m_perf_stats{};
|
||||
std::shared_ptr<FileSys::RealVfsFilesystem> m_vfs;
|
||||
Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized};
|
||||
bool m_is_running{};
|
||||
SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
|
||||
std::unique_ptr<Service::Account::ProfileManager> m_profile_manager;
|
||||
|
||||
// GPU driver parameters
|
||||
std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;
|
||||
|
||||
// Synchronization
|
||||
std::condition_variable_any m_cv;
|
||||
mutable std::mutex m_perf_stats_mutex;
|
||||
mutable std::mutex m_mutex;
|
||||
};
|
||||
|
||||
/*static*/ EmulationSession EmulationSession::s_instance;
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
u32 GetAndroidScreenRotation() {
|
||||
return EmulationSession::GetInstance().ScreenRotation();
|
||||
}
|
||||
|
||||
static Core::SystemResultStatus RunEmulation(const std::string& filepath) {
|
||||
Common::Log::Initialize();
|
||||
Common::Log::SetColorConsoleBackendEnabled(true);
|
||||
|
@ -486,13 +460,6 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env,
|
|||
EmulationSession::GetInstance().SurfaceChanged();
|
||||
}
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_notifyOrientationChange(JNIEnv* env,
|
||||
[[maybe_unused]] jclass clazz,
|
||||
jint layout_option,
|
||||
jint rotation) {
|
||||
return EmulationSession::GetInstance().SetScreenRotation(static_cast<u32>(rotation));
|
||||
}
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env,
|
||||
[[maybe_unused]] jclass clazz,
|
||||
jstring j_directory) {
|
||||
|
@ -500,11 +467,11 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env,
|
|||
}
|
||||
|
||||
void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver(
|
||||
JNIEnv* env, [[maybe_unused]] jclass clazz, jstring hook_lib_dir, jstring custom_driver_dir,
|
||||
jstring custom_driver_name, jstring file_redirect_dir) {
|
||||
JNIEnv* env, [[maybe_unused]] jclass clazz, jstring hook_lib_dir, jstring custom_driver_dir,
|
||||
jstring custom_driver_name, jstring file_redirect_dir) {
|
||||
EmulationSession::GetInstance().InitializeGpuDriver(
|
||||
GetJString(env, hook_lib_dir), GetJString(env, custom_driver_dir),
|
||||
GetJString(env, custom_driver_name), GetJString(env, file_redirect_dir));
|
||||
GetJString(env, hook_lib_dir), GetJString(env, custom_driver_dir),
|
||||
GetJString(env, custom_driver_name), GetJString(env, file_redirect_dir));
|
||||
}
|
||||
|
||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadKeys(JNIEnv* env,
|
||||
|
@ -562,7 +529,7 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadConnectEvent([[maybe_unu
|
|||
}
|
||||
|
||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadDisconnectEvent(
|
||||
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint j_device) {
|
||||
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint j_device) {
|
||||
if (EmulationSession::GetInstance().IsRunning()) {
|
||||
EmulationSession::GetInstance().OnGamepadDisconnectEvent(j_device);
|
||||
}
|
||||
|
@ -592,12 +559,12 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadJoystickEvent([[maybe_un
|
|||
}
|
||||
|
||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMotionEvent(
|
||||
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint j_device,
|
||||
jlong delta_timestamp, jfloat gyro_x, jfloat gyro_y, jfloat gyro_z, jfloat accel_x,
|
||||
jfloat accel_y, jfloat accel_z) {
|
||||
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint j_device,
|
||||
jlong delta_timestamp, jfloat gyro_x, jfloat gyro_y, jfloat gyro_z, jfloat accel_x,
|
||||
jfloat accel_y, jfloat accel_z) {
|
||||
if (EmulationSession::GetInstance().IsRunning()) {
|
||||
EmulationSession::GetInstance().Window().OnGamepadMotionEvent(
|
||||
j_device, delta_timestamp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z);
|
||||
j_device, delta_timestamp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z);
|
||||
}
|
||||
return static_cast<jboolean>(true);
|
||||
}
|
||||
|
@ -687,8 +654,14 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCompany([[maybe_unused]] JNIEnv
|
|||
return env->NewStringUTF("");
|
||||
}
|
||||
|
||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHomebrew([[maybe_unused]] JNIEnv* env,
|
||||
[[maybe_unused]] jclass clazz,
|
||||
[[maybe_unused]] jstring j_filename) {
|
||||
return EmulationSession::GetInstance().GetIsHomebrew(GetJString(env, j_filename));
|
||||
}
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation
|
||||
[[maybe_unused]] (JNIEnv* env, [[maybe_unused]] jclass clazz) {
|
||||
[[maybe_unused]] (JNIEnv* env, [[maybe_unused]] jclass clazz) {
|
||||
// Create the default config.ini.
|
||||
Config{};
|
||||
// Initialize the emulated system.
|
||||
|
@ -701,8 +674,8 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore([[maybe_unused]] JNIEn
|
|||
}
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2Ljava_lang_String_2Z(
|
||||
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, [[maybe_unused]] jstring j_file,
|
||||
[[maybe_unused]] jstring j_savestate, [[maybe_unused]] jboolean j_delete_savestate) {}
|
||||
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, [[maybe_unused]] jstring j_file,
|
||||
[[maybe_unused]] jstring j_savestate, [[maybe_unused]] jboolean j_delete_savestate) {}
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings([[maybe_unused]] JNIEnv* env,
|
||||
[[maybe_unused]] jclass clazz) {
|
||||
|
@ -765,7 +738,7 @@ jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats([[maybe_unused]]
|
|||
}
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_utils_DirectoryInitialization_setSysDirectory(
|
||||
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jstring j_path) {}
|
||||
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jstring j_path) {}
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2([[maybe_unused]] JNIEnv* env,
|
||||
[[maybe_unused]] jclass clazz,
|
||||
|
@ -796,45 +769,4 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_submitInlineKeyboardInput(JNIEnv* env
|
|||
EmulationSession::GetInstance().SoftwareKeyboard()->SubmitInlineKeyboardInput(j_key_code);
|
||||
}
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_connectToRoom(JNIEnv* env, jclass clazz,
|
||||
jstring nickname,
|
||||
jstring server_addr,
|
||||
jint server_port,
|
||||
jstring password) {
|
||||
EmulationSession::GetInstance().DirectConnectToRoom(
|
||||
GetJString(env, nickname),
|
||||
GetJString(env, server_addr).c_str(),
|
||||
server_port,
|
||||
GetJString(env, password)
|
||||
);
|
||||
}
|
||||
|
||||
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getRoomMemberState(JNIEnv* env, jclass clazz) {
|
||||
auto state = EmulationSession::GetInstance().GetRoomMemberState();
|
||||
|
||||
std::string state_str{};
|
||||
|
||||
switch(state) {
|
||||
using State = Network::RoomMember::State;
|
||||
|
||||
case State::Uninitialized:
|
||||
state_str = "Uninitialized";
|
||||
break;
|
||||
case State::Idle:
|
||||
state_str = "Idle";
|
||||
break;
|
||||
case State::Joining:
|
||||
state_str = "Joining";
|
||||
break;
|
||||
case State::Joined:
|
||||
state_str = "Joined";
|
||||
break;
|
||||
case State::Moderator:
|
||||
state_str = "Moderator";
|
||||
break;
|
||||
}
|
||||
|
||||
return env->NewStringUTF(state_str.c_str());
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
} // extern "C"
|
|
@ -33,7 +33,8 @@ static_assert(sizeof(NroSegmentHeader) == 0x8, "NroSegmentHeader has incorrect s
|
|||
struct NroHeader {
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
u32_le module_header_offset;
|
||||
INSERT_PADDING_BYTES(0x8);
|
||||
u32 magic_ext1;
|
||||
u32 magic_ext2;
|
||||
u32_le magic;
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
u32_le file_size;
|
||||
|
@ -124,6 +125,16 @@ FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& nro_file) {
|
|||
return FileType::Error;
|
||||
}
|
||||
|
||||
bool AppLoader_NRO::IsHomebrew() {
|
||||
// Read NSO header
|
||||
NroHeader nro_header{};
|
||||
if (sizeof(NroHeader) != file->ReadObject(&nro_header)) {
|
||||
return false;
|
||||
}
|
||||
return nro_header.magic_ext1 == Common::MakeMagic('H', 'O', 'M', 'E') &&
|
||||
nro_header.magic_ext2 == Common::MakeMagic('B', 'R', 'E', 'W');
|
||||
}
|
||||
|
||||
static constexpr u32 PageAlignSize(u32 size) {
|
||||
return static_cast<u32>((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK);
|
||||
}
|
||||
|
|
|
@ -38,6 +38,8 @@ public:
|
|||
*/
|
||||
static FileType IdentifyType(const FileSys::VirtualFile& nro_file);
|
||||
|
||||
bool IsHomebrew();
|
||||
|
||||
FileType GetFileType() const override {
|
||||
return IdentifyType(file);
|
||||
}
|
||||
|
|
|
@ -37,10 +37,6 @@
|
|||
#include "video_core/vulkan_common/vulkan_memory_allocator.h"
|
||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
extern u32 GetAndroidScreenRotation();
|
||||
#endif
|
||||
|
||||
namespace Vulkan {
|
||||
|
||||
namespace {
|
||||
|
@ -78,47 +74,6 @@ struct ScreenRectVertex {
|
|||
}
|
||||
};
|
||||
|
||||
#ifdef ANDROID
|
||||
|
||||
std::array<f32, 4 * 4> MakeOrthographicMatrix(f32 width, f32 height) {
|
||||
constexpr u32 ROTATION_0 = 0;
|
||||
constexpr u32 ROTATION_90 = 1;
|
||||
constexpr u32 ROTATION_180 = 2;
|
||||
constexpr u32 ROTATION_270 = 3;
|
||||
|
||||
// clang-format off
|
||||
switch (GetAndroidScreenRotation()) {
|
||||
case ROTATION_0:
|
||||
// Desktop
|
||||
return { 2.f / width, 0.f, 0.f, 0.f,
|
||||
0.f, 2.f / height, 0.f, 0.f,
|
||||
0.f, 0.f, 1.f, 0.f,
|
||||
-1.f, -1.f, 0.f, 1.f};
|
||||
case ROTATION_180:
|
||||
// Reverse desktop
|
||||
return {-2.f / width, 0.f, 0.f, 0.f,
|
||||
0.f, -2.f / height, 0.f, 0.f,
|
||||
0.f, 0.f, 1.f, 0.f,
|
||||
1.f, 1.f, 0.f, 1.f};
|
||||
case ROTATION_270:
|
||||
// Reverse landscape
|
||||
return { 0.f, -2.f / width, 0.f, 0.f,
|
||||
2.f / height, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 1.f, 0.f,
|
||||
-1.f, 1.f, 0.f, 1.f};
|
||||
case ROTATION_90:
|
||||
default:
|
||||
// Landscape
|
||||
return { 0.f, 2.f / width, 0.f, 0.f,
|
||||
-2.f / height, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 1.f, 0.f,
|
||||
1.f, -1.f, 0.f, 1.f};
|
||||
}
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
std::array<f32, 4 * 4> MakeOrthographicMatrix(f32 width, f32 height) {
|
||||
// clang-format off
|
||||
return { 2.f / width, 0.f, 0.f, 0.f,
|
||||
|
@ -128,8 +83,6 @@ std::array<f32, 4 * 4> MakeOrthographicMatrix(f32 width, f32 height) {
|
|||
// clang-format on
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
u32 GetBytesPerPixel(const Tegra::FramebufferConfig& framebuffer) {
|
||||
using namespace VideoCore::Surface;
|
||||
return BytesPerBlock(PixelFormatFromGPUPixelFormat(framebuffer.pixel_format));
|
||||
|
@ -1159,7 +1112,7 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
|
|||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.imageType = VK_IMAGE_TYPE_2D,
|
||||
.format = GetFormat(framebuffer),
|
||||
.format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : GetFormat(framebuffer),
|
||||
.extent =
|
||||
{
|
||||
.width = (up_scale * framebuffer.width) >> down_shift,
|
||||
|
@ -1180,14 +1133,14 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
|
|||
const auto create_commit = [&](vk::Image& image) {
|
||||
return memory_allocator.Commit(image, MemoryUsage::DeviceLocal);
|
||||
};
|
||||
const auto create_image_view = [&](vk::Image& image) {
|
||||
const auto create_image_view = [&](vk::Image& image, bool used_on_framebuffer = false) {
|
||||
return device.GetLogical().CreateImageView(VkImageViewCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.image = *image,
|
||||
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
||||
.format = GetFormat(framebuffer),
|
||||
.format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : GetFormat(framebuffer),
|
||||
.components =
|
||||
{
|
||||
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
|
@ -1217,7 +1170,7 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
|
|||
const u32 down_shift = Settings::values.resolution_info.down_shift;
|
||||
aa_image = create_image(true, up_scale, down_shift);
|
||||
aa_commit = create_commit(aa_image);
|
||||
aa_image_view = create_image_view(aa_image);
|
||||
aa_image_view = create_image_view(aa_image, true);
|
||||
VkExtent2D size{
|
||||
.width = (up_scale * framebuffer.width) >> down_shift,
|
||||
.height = (up_scale * framebuffer.height) >> down_shift,
|
||||
|
|
|
@ -231,7 +231,12 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bo
|
|||
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.queueFamilyIndexCount = 0,
|
||||
.pQueueFamilyIndices = nullptr,
|
||||
#ifdef ANDROID
|
||||
// On Android, do not allow surface rotation to deviate from the frontend.
|
||||
.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
|
||||
#else
|
||||
.preTransform = capabilities.currentTransform,
|
||||
#endif
|
||||
.compositeAlpha = alpha_flags,
|
||||
.presentMode = present_mode,
|
||||
.clipped = VK_FALSE,
|
||||
|
|
|
@ -760,6 +760,7 @@ void Config::ReadRendererValues() {
|
|||
ReadGlobalSetting(Settings::values.use_fast_gpu_time);
|
||||
ReadGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache);
|
||||
ReadGlobalSetting(Settings::values.enable_compute_pipelines);
|
||||
ReadGlobalSetting(Settings::values.use_video_framerate);
|
||||
ReadGlobalSetting(Settings::values.bg_red);
|
||||
ReadGlobalSetting(Settings::values.bg_green);
|
||||
ReadGlobalSetting(Settings::values.bg_blue);
|
||||
|
@ -1415,6 +1416,7 @@ void Config::SaveRendererValues() {
|
|||
WriteGlobalSetting(Settings::values.use_fast_gpu_time);
|
||||
WriteGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache);
|
||||
WriteGlobalSetting(Settings::values.enable_compute_pipelines);
|
||||
WriteGlobalSetting(Settings::values.use_video_framerate);
|
||||
WriteGlobalSetting(Settings::values.bg_red);
|
||||
WriteGlobalSetting(Settings::values.bg_green);
|
||||
WriteGlobalSetting(Settings::values.bg_blue);
|
||||
|
|
Loading…
Add table
Reference in a new issue