mirror of
https://github.com/PabloMK7/citra
synced 2024-11-14 20:58:23 +00:00
renderer_vulkan: Address vulkan surface recreation issues (#198)
This commit is contained in:
parent
55748d7d1a
commit
959a66d839
9 changed files with 24 additions and 34 deletions
|
@ -29,7 +29,7 @@ android {
|
||||||
namespace = "org.citra.citra_emu"
|
namespace = "org.citra.citra_emu"
|
||||||
|
|
||||||
compileSdkVersion = "android-34"
|
compileSdkVersion = "android-34"
|
||||||
ndkVersion = "26.1.10909125"
|
ndkVersion = "26.3.11579264"
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
|
|
@ -38,7 +38,6 @@ import org.citra.citra_emu.features.settings.model.view.InputBindingSetting
|
||||||
import org.citra.citra_emu.fragments.MessageDialogFragment
|
import org.citra.citra_emu.fragments.MessageDialogFragment
|
||||||
import org.citra.citra_emu.utils.ControllerMappingHelper
|
import org.citra.citra_emu.utils.ControllerMappingHelper
|
||||||
import org.citra.citra_emu.utils.FileBrowserHelper
|
import org.citra.citra_emu.utils.FileBrowserHelper
|
||||||
import org.citra.citra_emu.utils.ForegroundService
|
|
||||||
import org.citra.citra_emu.utils.EmulationLifecycleUtil
|
import org.citra.citra_emu.utils.EmulationLifecycleUtil
|
||||||
import org.citra.citra_emu.utils.EmulationMenuSettings
|
import org.citra.citra_emu.utils.EmulationMenuSettings
|
||||||
import org.citra.citra_emu.utils.ThemeUtil
|
import org.citra.citra_emu.utils.ThemeUtil
|
||||||
|
@ -47,7 +46,6 @@ import org.citra.citra_emu.viewmodel.EmulationViewModel
|
||||||
class EmulationActivity : AppCompatActivity() {
|
class EmulationActivity : AppCompatActivity() {
|
||||||
private val preferences: SharedPreferences
|
private val preferences: SharedPreferences
|
||||||
get() = PreferenceManager.getDefaultSharedPreferences(CitraApplication.appContext)
|
get() = PreferenceManager.getDefaultSharedPreferences(CitraApplication.appContext)
|
||||||
private var foregroundService: Intent? = null
|
|
||||||
var isActivityRecreated = false
|
var isActivityRecreated = false
|
||||||
|
|
||||||
private val settingsViewModel: SettingsViewModel by viewModels()
|
private val settingsViewModel: SettingsViewModel by viewModels()
|
||||||
|
@ -85,10 +83,6 @@ class EmulationActivity : AppCompatActivity() {
|
||||||
windowManager.defaultDisplay.rotation
|
windowManager.defaultDisplay.rotation
|
||||||
)
|
)
|
||||||
|
|
||||||
// Start a foreground service to prevent the app from getting killed in the background
|
|
||||||
foregroundService = Intent(this, ForegroundService::class.java)
|
|
||||||
startForegroundService(foregroundService)
|
|
||||||
|
|
||||||
EmulationLifecycleUtil.addShutdownHook(hook = { this.finish() })
|
EmulationLifecycleUtil.addShutdownHook(hook = { this.finish() })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +106,6 @@ class EmulationActivity : AppCompatActivity() {
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
EmulationLifecycleUtil.clear()
|
EmulationLifecycleUtil.clear()
|
||||||
stopForegroundService(this)
|
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,12 +445,4 @@ class EmulationActivity : AppCompatActivity() {
|
||||||
|
|
||||||
OnFilePickerResult(result.toString())
|
OnFilePickerResult(result.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun stopForegroundService(activity: Activity) {
|
|
||||||
val startIntent = Intent(activity, ForegroundService::class.java)
|
|
||||||
startIntent.action = ForegroundService.ACTION_STOP
|
|
||||||
activity.startForegroundService(startIntent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,9 +156,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dismiss previous notifications (should not happen unless a crash occurred)
|
|
||||||
EmulationActivity.stopForegroundService(this)
|
|
||||||
|
|
||||||
setInsets()
|
setInsets()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +167,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
EmulationActivity.stopForegroundService(this)
|
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,14 +27,18 @@ static void UpdateLandscapeScreenLayout() {
|
||||||
IDCache::GetNativeLibraryClass(), IDCache::GetLandscapeScreenLayout()));
|
IDCache::GetNativeLibraryClass(), IDCache::GetLandscapeScreenLayout()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
|
bool EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
|
||||||
render_window = surface;
|
if (render_window == surface) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
render_window = surface;
|
||||||
window_info.type = Frontend::WindowSystemType::Android;
|
window_info.type = Frontend::WindowSystemType::Android;
|
||||||
window_info.render_surface = surface;
|
window_info.render_surface = surface;
|
||||||
|
|
||||||
StopPresenting();
|
StopPresenting();
|
||||||
OnFramebufferSizeChanged();
|
OnFramebufferSizeChanged();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EmuWindow_Android::OnTouchEvent(int x, int y, bool pressed) {
|
bool EmuWindow_Android::OnTouchEvent(int x, int y, bool pressed) {
|
||||||
|
|
|
@ -17,7 +17,7 @@ public:
|
||||||
~EmuWindow_Android();
|
~EmuWindow_Android();
|
||||||
|
|
||||||
/// Called by the onSurfaceChanges() method to change the surface
|
/// Called by the onSurfaceChanges() method to change the surface
|
||||||
void OnSurfaceChanged(ANativeWindow* surface);
|
bool OnSurfaceChanged(ANativeWindow* surface);
|
||||||
|
|
||||||
/// Handles touch event that occur.(Touched or released)
|
/// Handles touch event that occur.(Touched or released)
|
||||||
bool OnTouchEvent(int x, int y, bool pressed);
|
bool OnTouchEvent(int x, int y, bool pressed);
|
||||||
|
|
|
@ -294,12 +294,13 @@ void Java_org_citra_citra_1emu_NativeLibrary_surfaceChanged(JNIEnv* env,
|
||||||
jobject surf) {
|
jobject surf) {
|
||||||
s_surf = ANativeWindow_fromSurface(env, surf);
|
s_surf = ANativeWindow_fromSurface(env, surf);
|
||||||
|
|
||||||
|
bool notify = false;
|
||||||
if (window) {
|
if (window) {
|
||||||
window->OnSurfaceChanged(s_surf);
|
notify = window->OnSurfaceChanged(s_surf);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& system = Core::System::GetInstance();
|
auto& system = Core::System::GetInstance();
|
||||||
if (system.IsPoweredOn()) {
|
if (notify && system.IsPoweredOn()) {
|
||||||
system.GPU().Renderer().NotifySurfaceChanged();
|
system.GPU().Renderer().NotifySurfaceChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||||
|
|
|
@ -473,7 +473,7 @@ void PresentWindow::CopyToSwapchain(Frame* frame) {
|
||||||
.pSignalSemaphores = &present_ready,
|
.pSignalSemaphores = &present_ready,
|
||||||
};
|
};
|
||||||
|
|
||||||
std::scoped_lock submit_lock{scheduler.submit_mutex};
|
std::scoped_lock submit_lock{scheduler.submit_mutex, recreate_surface_mutex};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
graphics_queue.submit(submit_info, frame->present_done);
|
graphics_queue.submit(submit_info, frame->present_done);
|
||||||
|
|
|
@ -78,9 +78,13 @@ void Swapchain::Create(u32 width_, u32 height_, vk::SurfaceKHR surface_) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Swapchain::AcquireNextImage() {
|
bool Swapchain::AcquireNextImage() {
|
||||||
|
if (needs_recreation) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
MICROPROFILE_SCOPE(Vulkan_Acquire);
|
MICROPROFILE_SCOPE(Vulkan_Acquire);
|
||||||
vk::Device device = instance.GetDevice();
|
const vk::Device device = instance.GetDevice();
|
||||||
vk::Result result =
|
const vk::Result result =
|
||||||
device.acquireNextImageKHR(swapchain, std::numeric_limits<u64>::max(),
|
device.acquireNextImageKHR(swapchain, std::numeric_limits<u64>::max(),
|
||||||
image_acquired[frame_index], VK_NULL_HANDLE, &image_index);
|
image_acquired[frame_index], VK_NULL_HANDLE, &image_index);
|
||||||
|
|
||||||
|
@ -102,10 +106,6 @@ bool Swapchain::AcquireNextImage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Swapchain::Present() {
|
void Swapchain::Present() {
|
||||||
if (needs_recreation) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const vk::PresentInfoKHR present_info = {
|
const vk::PresentInfoKHR present_info = {
|
||||||
.waitSemaphoreCount = 1,
|
.waitSemaphoreCount = 1,
|
||||||
.pWaitSemaphores = &present_ready[image_index],
|
.pWaitSemaphores = &present_ready[image_index],
|
||||||
|
@ -119,6 +119,10 @@ void Swapchain::Present() {
|
||||||
[[maybe_unused]] vk::Result result = instance.GetPresentQueue().presentKHR(present_info);
|
[[maybe_unused]] vk::Result result = instance.GetPresentQueue().presentKHR(present_info);
|
||||||
} catch (vk::OutOfDateKHRError&) {
|
} catch (vk::OutOfDateKHRError&) {
|
||||||
needs_recreation = true;
|
needs_recreation = true;
|
||||||
|
return;
|
||||||
|
} catch (vk::SurfaceLostKHRError&) {
|
||||||
|
needs_recreation = true;
|
||||||
|
return;
|
||||||
} catch (const vk::SystemError& err) {
|
} catch (const vk::SystemError& err) {
|
||||||
LOG_CRITICAL(Render_Vulkan, "Swapchain presentation failed {}", err.what());
|
LOG_CRITICAL(Render_Vulkan, "Swapchain presentation failed {}", err.what());
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
|
@ -268,4 +272,4 @@ void Swapchain::SetupImages() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
Loading…
Reference in a new issue