This commit is contained in:
Timotej Leginus 2023-06-11 20:20:17 +02:00
commit d5129d9347
14 changed files with 380 additions and 494 deletions

View file

@ -3,4 +3,4 @@
[codespell] [codespell]
skip = ./.git,./build,./dist,./Doxyfile,./externals,./LICENSES 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

View file

@ -223,6 +223,8 @@ object NativeLibrary {
external fun getCompany(filename: String): String external fun getCompany(filename: String): String
external fun isHomebrew(filename: String): Boolean
external fun setAppDirectory(directory: String) external fun setAppDirectory(directory: String)
external fun initializeGpuDriver( external fun initializeGpuDriver(

View file

@ -6,15 +6,12 @@ package org.yuzu.yuzu_emu.activities
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.res.Configuration
import android.graphics.Rect import android.graphics.Rect
import android.hardware.Sensor import android.hardware.Sensor
import android.hardware.SensorEvent import android.hardware.SensorEvent
import android.hardware.SensorEventListener import android.hardware.SensorEventListener
import android.hardware.SensorManager import android.hardware.SensorManager
import android.hardware.display.DisplayManager
import android.os.Bundle import android.os.Bundle
import android.view.Display
import android.view.InputDevice import android.view.InputDevice
import android.view.KeyEvent import android.view.KeyEvent
import android.view.MotionEvent import android.view.MotionEvent
@ -23,7 +20,6 @@ import android.view.View
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.getSystemService
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat 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.fragments.EmulationFragment
import org.yuzu.yuzu_emu.model.Game import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.utils.ControllerMappingHelper 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.ForegroundService
import org.yuzu.yuzu_emu.utils.InputHandler import org.yuzu.yuzu_emu.utils.InputHandler
import org.yuzu.yuzu_emu.utils.NfcReader import org.yuzu.yuzu_emu.utils.NfcReader
@ -148,11 +143,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
super.onResume() super.onResume()
nfcReader.startScanning() nfcReader.startScanning()
startMotionSensorListener() startMotionSensorListener()
NativeLibrary.notifyOrientationChange(
EmulationMenuSettings.landscapeScreenLayout,
getAdjustedRotation()
)
} }
override fun onPause() { override fun onPause() {
@ -258,24 +248,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
override fun onAccuracyChanged(sensor: Sensor, i: Int) {} 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) { private fun restoreState(savedInstanceState: Bundle) {
game = savedInstanceState.parcelable(EXTRA_SELECTED_GAME)!! game = savedInstanceState.parcelable(EXTRA_SELECTED_GAME)!!
} }

View file

@ -127,13 +127,7 @@ class SearchFragment : Fragment() {
} }
} }
R.id.chip_homebrew -> { R.id.chip_homebrew -> baseList.filter { it.isHomebrew }
baseList.filter {
Log.error("Guh - ${it.path}")
FileUtil.hasExtension(it.path, "nro")
|| FileUtil.hasExtension(it.path, "nso")
}
}
R.id.chip_retail -> baseList.filter { R.id.chip_retail -> baseList.filter {
FileUtil.hasExtension(it.path, "xci") FileUtil.hasExtension(it.path, "xci")

View file

@ -16,7 +16,8 @@ class Game(
val regions: String, val regions: String,
val path: String, val path: String,
val gameId: String, val gameId: String,
val company: String val company: String,
val isHomebrew: Boolean
) : Parcelable { ) : Parcelable {
val keyAddedToLibraryTime get() = "${gameId}_AddedToLibraryTime" val keyAddedToLibraryTime get() = "${gameId}_AddedToLibraryTime"
val keyLastPlayedTime get() = "${gameId}_LastPlayed" val keyLastPlayedTime get() = "${gameId}_LastPlayed"
@ -31,6 +32,7 @@ class Game(
&& path == other.path && path == other.path
&& gameId == other.gameId && gameId == other.gameId
&& company == other.company && company == other.company
&& isHomebrew == other.isHomebrew
} }
companion object { companion object {

View file

@ -13,6 +13,8 @@ import androidx.preference.PreferenceManager
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.MissingFieldException
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
@ -20,6 +22,7 @@ import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.utils.GameHelper import org.yuzu.yuzu_emu.utils.GameHelper
import java.util.Locale import java.util.Locale
@OptIn(ExperimentalSerializationApi::class)
class GamesViewModel : ViewModel() { class GamesViewModel : ViewModel() {
private val _games = MutableLiveData<List<Game>>(emptyList()) private val _games = MutableLiveData<List<Game>>(emptyList())
val games: LiveData<List<Game>> get() = _games val games: LiveData<List<Game>> get() = _games
@ -49,7 +52,13 @@ class GamesViewModel : ViewModel() {
if (storedGames!!.isNotEmpty()) { if (storedGames!!.isNotEmpty()) {
val deserializedGames = mutableSetOf<Game>() val deserializedGames = mutableSetOf<Game>()
storedGames.forEach { storedGames.forEach {
val game: Game = Json.decodeFromString(it) val game: Game
try {
game = Json.decodeFromString(it)
} catch (e: MissingFieldException) {
return@forEach
}
val gameExists = val gameExists =
DocumentFile.fromSingleUri(YuzuApplication.appContext, Uri.parse(game.path)) DocumentFile.fromSingleUri(YuzuApplication.appContext, Uri.parse(game.path))
?.exists() ?.exists()

View file

@ -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 // If we have API access, calculate the safe area to draw the overlay
var cutoutLeft = 0 var cutoutLeft = 0
var cutoutBottom = 0 var cutoutBottom = 0
val insets = context.windowManager.currentWindowMetrics.windowInsets.displayCutout if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (insets != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { val insets = context.windowManager.currentWindowMetrics.windowInsets.displayCutout
if (insets.boundingRectTop.bottom != 0 && insets.boundingRectTop.bottom > maxY / 2) if (insets != null) {
insets.boundingRectTop.bottom.toFloat() else maxY if (insets.boundingRectTop.bottom != 0 && insets.boundingRectTop.bottom > maxY / 2)
if (insets.boundingRectRight.left != 0 && insets.boundingRectRight.left > maxX / 2) insets.boundingRectTop.bottom.toFloat() else maxY
insets.boundingRectRight.left.toFloat() else maxX if (insets.boundingRectRight.left != 0 && insets.boundingRectRight.left > maxX / 2)
insets.boundingRectRight.left.toFloat() else maxX
minX = insets.boundingRectLeft.right - insets.boundingRectLeft.left minX = insets.boundingRectLeft.right - insets.boundingRectLeft.left
minY = insets.boundingRectBottom.top - insets.boundingRectBottom.bottom minY = insets.boundingRectBottom.top - insets.boundingRectBottom.bottom
cutoutLeft = insets.boundingRectRight.right - insets.boundingRectRight.left cutoutLeft = insets.boundingRectRight.right - insets.boundingRectRight.left
cutoutBottom = insets.boundingRectTop.top - insets.boundingRectTop.bottom 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 // This makes sure that if we have an inset on one side of the screen, we mirror it on

View file

@ -6,7 +6,6 @@ package org.yuzu.yuzu_emu.utils
import android.content.SharedPreferences import android.content.SharedPreferences
import android.net.Uri import android.net.Uri
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
@ -83,7 +82,8 @@ object GameHelper {
NativeLibrary.getRegions(filePath), NativeLibrary.getRegions(filePath),
filePath, filePath,
gameId, gameId,
NativeLibrary.getCompany(filePath) NativeLibrary.getCompany(filePath),
NativeLibrary.isHomebrew(filePath)
) )
val addedTime = preferences.getLong(newGame.keyAddedToLibraryTime, 0L) val addedTime = preferences.getLong(newGame.keyAddedToLibraryTime, 0L)

View file

@ -13,8 +13,7 @@
#include <android/api-level.h> #include <android/api-level.h>
#include <android/native_window_jni.h> #include <android/native_window_jni.h>
#include <network/room_member.h> #include <core/loader/nro.h>
#include <network/network.h>
#include "common/detached_tasks.h" #include "common/detached_tasks.h"
#include "common/dynamic_library.h" #include "common/dynamic_library.h"
@ -59,390 +58,365 @@
namespace { namespace {
class EmulationSession final { class EmulationSession final {
public: public:
EmulationSession() { EmulationSession() {
m_vfs = std::make_shared<FileSys::RealVfsFilesystem>(); m_vfs = std::make_shared<FileSys::RealVfsFilesystem>();
} }
~EmulationSession() = default; ~EmulationSession() = default;
static EmulationSession& GetInstance() { static EmulationSession& GetInstance() {
return s_instance; return s_instance;
} }
const Core::System& System() const { const Core::System& System() const {
return m_system; return m_system;
} }
Core::System& System() { Core::System& System() {
return m_system; return m_system;
} }
const EmuWindow_Android& Window() const { const EmuWindow_Android& Window() const {
return *m_window; return *m_window;
} }
EmuWindow_Android& Window() { EmuWindow_Android& Window() {
return *m_window; return *m_window;
} }
ANativeWindow* NativeWindow() const { ANativeWindow* NativeWindow() const {
return m_native_window; return m_native_window;
} }
void SetNativeWindow(ANativeWindow* native_window) { void SetNativeWindow(ANativeWindow* native_window) {
m_native_window = native_window; m_native_window = native_window;
} }
u32 ScreenRotation() const { void InitializeGpuDriver(const std::string& hook_lib_dir, const std::string& custom_driver_dir,
return m_screen_rotation; const std::string& custom_driver_name,
} const std::string& file_redirect_dir) {
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) {
#ifdef ARCHITECTURE_arm64 #ifdef ARCHITECTURE_arm64
void* handle{}; void* handle{};
const char* file_redirect_dir_{}; const char* file_redirect_dir_{};
int featureFlags{}; int featureFlags{};
// Enable driver file redirection when renderer debugging is enabled. // Enable driver file redirection when renderer debugging is enabled.
if (Settings::values.renderer_debug && file_redirect_dir.size()) { if (Settings::values.renderer_debug && file_redirect_dir.size()) {
featureFlags |= ADRENOTOOLS_DRIVER_FILE_REDIRECT; featureFlags |= ADRENOTOOLS_DRIVER_FILE_REDIRECT;
file_redirect_dir_ = file_redirect_dir.c_str(); file_redirect_dir_ = file_redirect_dir.c_str();
} }
// Try to load a custom driver. // Try to load a custom driver.
if (custom_driver_name.size()) { if (custom_driver_name.size()) {
handle = adrenotools_open_libvulkan( handle = adrenotools_open_libvulkan(
RTLD_NOW, featureFlags | ADRENOTOOLS_DRIVER_CUSTOM, nullptr, hook_lib_dir.c_str(), 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); custom_driver_dir.c_str(), custom_driver_name.c_str(), file_redirect_dir_, nullptr);
} }
// Try to load the system driver. // Try to load the system driver.
if (!handle) { if (!handle) {
handle = handle =
adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(), adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(),
nullptr, nullptr, file_redirect_dir_, nullptr); 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 #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. bool IsRunning() const {
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::scoped_lock lock(m_mutex); std::scoped_lock lock(m_mutex);
m_is_running = true; return m_is_running;
} }
// Load the disk shader cache. const Core::PerfStatsResults& PerfStats() const {
if (Settings::values.use_disk_shader_cache.GetValue()) { std::scoped_lock m_perf_stats_lock(m_perf_stats_mutex);
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); return m_perf_stats;
m_system.Renderer().ReadRasterizer()->LoadDiskResources(
m_system.GetApplicationProcessProgramID(), std::stop_token{},
LoadDiskCacheProgress);
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
} }
void(m_system.Run()); void SurfaceChanged() {
if (!IsRunning()) {
if (m_system.DebuggerEnabled()) { return;
m_system.InitializeDebugger(); }
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); std::scoped_lock lock(m_mutex);
if (m_cv.wait_for(lock, std::chrono::milliseconds(800), m_is_running = true;
[&]() { return !m_is_running; })) { }
// Emulation halted.
break; // 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); std::string GetRomTitle(const std::string& path) {
m_perf_stats = m_system.GetAndResetPerfStats(); 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) { if (npad_style_set.handheld == 0) {
return GetRomMetadata(path).title; return false;
} }
std::vector<u8> GetRomIcon(const std::string& path) { return !Settings::values.use_docked_mode.GetValue();
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;
} }
if (npad_style_set.handheld == 0) { void SetDeviceType(int index, int type) {
return false; 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) { // Ensure that player1 is configured correctly and handheld disconnected
auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); if (controller->GetNpadIdType() == Core::HID::NpadIdType::Player1) {
controller->SetNpadStyleIndex(static_cast<Core::HID::NpadStyleIndex>(type)); auto handheld =
} m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
void OnGamepadConnectEvent(int index) { if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) {
auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
handheld->Disconnect();
}
}
// Ensure that player1 is configured correctly and handheld disconnected // Ensure that handheld is configured correctly and player 1 disconnected
if (controller->GetNpadIdType() == Core::HID::NpadIdType::Player1) { if (controller->GetNpadIdType() == Core::HID::NpadIdType::Handheld) {
auto handheld = auto player1 = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) { if (controller->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::Handheld) {
handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); player1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
handheld->Disconnect(); player1->Disconnect();
}
}
if (!controller->IsConnected()) {
controller->Connect();
} }
} }
// Ensure that handheld is configured correctly and player 1 disconnected void OnGamepadDisconnectEvent(int index) {
if (controller->GetNpadIdType() == Core::HID::NpadIdType::Handheld) { auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
auto player1 = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); controller->Disconnect();
}
if (controller->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::Handheld) { SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard() {
player1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); return m_software_keyboard;
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); }
player1->Disconnect();
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()) { RomMetadata CacheRomMetadata(const std::string& path) {
controller->Connect(); const auto file = Core::GetGameFileFromPath(m_vfs, path);
} auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0);
}
void OnGamepadDisconnectEvent(int index) { RomMetadata entry;
auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); loader->ReadTitle(entry.title);
controller->Disconnect(); loader->ReadIcon(entry.icon);
} if (loader->GetFileType() == Loader::FileType::NRO) {
auto loader_nro = dynamic_cast<Loader::AppLoader_NRO*>(loader.get());
SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard() { entry.isHomebrew = loader_nro->IsHomebrew();
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;
} else { } else {
member->Join(nickname, server_addr, server_port); entry.isHomebrew = false;
} }
}
}
Network::RoomMember::State GetRoomMemberState() { m_rom_metadata_cache[path] = entry;
if (const auto member = m_system.GetRoomNetwork().GetRoomMember().lock()) {
return member->GetState();
} else {
return Network::RoomMember::State::Idle;
}
}
private: return entry;
struct RomMetadata { }
std::string title;
std::vector<u8> icon; 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; /*static*/ EmulationSession EmulationSession::s_instance;
} // Anonymous namespace } // Anonymous namespace
u32 GetAndroidScreenRotation() {
return EmulationSession::GetInstance().ScreenRotation();
}
static Core::SystemResultStatus RunEmulation(const std::string& filepath) { static Core::SystemResultStatus RunEmulation(const std::string& filepath) {
Common::Log::Initialize(); Common::Log::Initialize();
Common::Log::SetColorConsoleBackendEnabled(true); Common::Log::SetColorConsoleBackendEnabled(true);
@ -486,13 +460,6 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env,
EmulationSession::GetInstance().SurfaceChanged(); 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, void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env,
[[maybe_unused]] jclass clazz, [[maybe_unused]] jclass clazz,
jstring j_directory) { 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( void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver(
JNIEnv* env, [[maybe_unused]] jclass clazz, jstring hook_lib_dir, jstring custom_driver_dir, JNIEnv* env, [[maybe_unused]] jclass clazz, jstring hook_lib_dir, jstring custom_driver_dir,
jstring custom_driver_name, jstring file_redirect_dir) { jstring custom_driver_name, jstring file_redirect_dir) {
EmulationSession::GetInstance().InitializeGpuDriver( EmulationSession::GetInstance().InitializeGpuDriver(
GetJString(env, hook_lib_dir), GetJString(env, custom_driver_dir), GetJString(env, hook_lib_dir), GetJString(env, custom_driver_dir),
GetJString(env, custom_driver_name), GetJString(env, file_redirect_dir)); GetJString(env, custom_driver_name), GetJString(env, file_redirect_dir));
} }
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadKeys(JNIEnv* env, 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( 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()) { if (EmulationSession::GetInstance().IsRunning()) {
EmulationSession::GetInstance().OnGamepadDisconnectEvent(j_device); 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( jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMotionEvent(
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint j_device, [[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, jlong delta_timestamp, jfloat gyro_x, jfloat gyro_y, jfloat gyro_z, jfloat accel_x,
jfloat accel_y, jfloat accel_z) { jfloat accel_y, jfloat accel_z) {
if (EmulationSession::GetInstance().IsRunning()) { if (EmulationSession::GetInstance().IsRunning()) {
EmulationSession::GetInstance().Window().OnGamepadMotionEvent( 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); return static_cast<jboolean>(true);
} }
@ -687,8 +654,14 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCompany([[maybe_unused]] JNIEnv
return env->NewStringUTF(""); 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 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. // Create the default config.ini.
Config{}; Config{};
// Initialize the emulated system. // 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( 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]] JNIEnv* env, [[maybe_unused]] jclass clazz, [[maybe_unused]] jstring j_file,
[[maybe_unused]] jstring j_savestate, [[maybe_unused]] jboolean j_delete_savestate) {} [[maybe_unused]] jstring j_savestate, [[maybe_unused]] jboolean j_delete_savestate) {}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings([[maybe_unused]] JNIEnv* env, void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings([[maybe_unused]] JNIEnv* env,
[[maybe_unused]] jclass clazz) { [[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( 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, void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2([[maybe_unused]] JNIEnv* env,
[[maybe_unused]] jclass clazz, [[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); EmulationSession::GetInstance().SoftwareKeyboard()->SubmitInlineKeyboardInput(j_key_code);
} }
void Java_org_yuzu_yuzu_1emu_NativeLibrary_connectToRoom(JNIEnv* env, jclass clazz, } // extern "C"
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"

View file

@ -33,7 +33,8 @@ static_assert(sizeof(NroSegmentHeader) == 0x8, "NroSegmentHeader has incorrect s
struct NroHeader { struct NroHeader {
INSERT_PADDING_BYTES(0x4); INSERT_PADDING_BYTES(0x4);
u32_le module_header_offset; u32_le module_header_offset;
INSERT_PADDING_BYTES(0x8); u32 magic_ext1;
u32 magic_ext2;
u32_le magic; u32_le magic;
INSERT_PADDING_BYTES(0x4); INSERT_PADDING_BYTES(0x4);
u32_le file_size; u32_le file_size;
@ -124,6 +125,16 @@ FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& nro_file) {
return FileType::Error; 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) { static constexpr u32 PageAlignSize(u32 size) {
return static_cast<u32>((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK); return static_cast<u32>((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK);
} }

View file

@ -38,6 +38,8 @@ public:
*/ */
static FileType IdentifyType(const FileSys::VirtualFile& nro_file); static FileType IdentifyType(const FileSys::VirtualFile& nro_file);
bool IsHomebrew();
FileType GetFileType() const override { FileType GetFileType() const override {
return IdentifyType(file); return IdentifyType(file);
} }

View file

@ -37,10 +37,6 @@
#include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_memory_allocator.h"
#include "video_core/vulkan_common/vulkan_wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
#ifdef ANDROID
extern u32 GetAndroidScreenRotation();
#endif
namespace Vulkan { namespace Vulkan {
namespace { 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) { std::array<f32, 4 * 4> MakeOrthographicMatrix(f32 width, f32 height) {
// clang-format off // clang-format off
return { 2.f / width, 0.f, 0.f, 0.f, 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 // clang-format on
} }
#endif
u32 GetBytesPerPixel(const Tegra::FramebufferConfig& framebuffer) { u32 GetBytesPerPixel(const Tegra::FramebufferConfig& framebuffer) {
using namespace VideoCore::Surface; using namespace VideoCore::Surface;
return BytesPerBlock(PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)); return BytesPerBlock(PixelFormatFromGPUPixelFormat(framebuffer.pixel_format));
@ -1159,7 +1112,7 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
.pNext = nullptr, .pNext = nullptr,
.flags = 0, .flags = 0,
.imageType = VK_IMAGE_TYPE_2D, .imageType = VK_IMAGE_TYPE_2D,
.format = GetFormat(framebuffer), .format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : GetFormat(framebuffer),
.extent = .extent =
{ {
.width = (up_scale * framebuffer.width) >> down_shift, .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) { const auto create_commit = [&](vk::Image& image) {
return memory_allocator.Commit(image, MemoryUsage::DeviceLocal); 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{ return device.GetLogical().CreateImageView(VkImageViewCreateInfo{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.pNext = nullptr, .pNext = nullptr,
.flags = 0, .flags = 0,
.image = *image, .image = *image,
.viewType = VK_IMAGE_VIEW_TYPE_2D, .viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = GetFormat(framebuffer), .format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : GetFormat(framebuffer),
.components = .components =
{ {
.r = VK_COMPONENT_SWIZZLE_IDENTITY, .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; const u32 down_shift = Settings::values.resolution_info.down_shift;
aa_image = create_image(true, up_scale, down_shift); aa_image = create_image(true, up_scale, down_shift);
aa_commit = create_commit(aa_image); 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{ VkExtent2D size{
.width = (up_scale * framebuffer.width) >> down_shift, .width = (up_scale * framebuffer.width) >> down_shift,
.height = (up_scale * framebuffer.height) >> down_shift, .height = (up_scale * framebuffer.height) >> down_shift,

View file

@ -231,7 +231,12 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bo
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0, .queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr, .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, .preTransform = capabilities.currentTransform,
#endif
.compositeAlpha = alpha_flags, .compositeAlpha = alpha_flags,
.presentMode = present_mode, .presentMode = present_mode,
.clipped = VK_FALSE, .clipped = VK_FALSE,

View file

@ -760,6 +760,7 @@ void Config::ReadRendererValues() {
ReadGlobalSetting(Settings::values.use_fast_gpu_time); ReadGlobalSetting(Settings::values.use_fast_gpu_time);
ReadGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache); ReadGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache);
ReadGlobalSetting(Settings::values.enable_compute_pipelines); ReadGlobalSetting(Settings::values.enable_compute_pipelines);
ReadGlobalSetting(Settings::values.use_video_framerate);
ReadGlobalSetting(Settings::values.bg_red); ReadGlobalSetting(Settings::values.bg_red);
ReadGlobalSetting(Settings::values.bg_green); ReadGlobalSetting(Settings::values.bg_green);
ReadGlobalSetting(Settings::values.bg_blue); ReadGlobalSetting(Settings::values.bg_blue);
@ -1415,6 +1416,7 @@ void Config::SaveRendererValues() {
WriteGlobalSetting(Settings::values.use_fast_gpu_time); WriteGlobalSetting(Settings::values.use_fast_gpu_time);
WriteGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache); WriteGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache);
WriteGlobalSetting(Settings::values.enable_compute_pipelines); WriteGlobalSetting(Settings::values.enable_compute_pipelines);
WriteGlobalSetting(Settings::values.use_video_framerate);
WriteGlobalSetting(Settings::values.bg_red); WriteGlobalSetting(Settings::values.bg_red);
WriteGlobalSetting(Settings::values.bg_green); WriteGlobalSetting(Settings::values.bg_green);
WriteGlobalSetting(Settings::values.bg_blue); WriteGlobalSetting(Settings::values.bg_blue);