mirror of
https://github.com/Lime3DS/Lime3DS.git
synced 2025-03-30 01:09:38 +01:00
Update everything to enable second screen on android under GL and Vulkan. Still some issues!
This commit is contained in:
parent
c4667b1cf0
commit
12afea9015
@ -125,6 +125,9 @@ object NativeLibrary {
|
|||||||
external fun surfaceDestroyed()
|
external fun surfaceDestroyed()
|
||||||
external fun doFrame()
|
external fun doFrame()
|
||||||
|
|
||||||
|
//Second window
|
||||||
|
external fun enableSecondWindow(secondary_surface: Surface)
|
||||||
|
external fun disableSecondWindow()
|
||||||
/**
|
/**
|
||||||
* Unpauses emulation from a paused state.
|
* Unpauses emulation from a paused state.
|
||||||
*/
|
*/
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import android.app.Presentation
|
import android.app.Presentation
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Color
|
|
||||||
import android.graphics.Paint
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.Display
|
import android.view.Display
|
||||||
import android.view.SurfaceHolder
|
import android.view.SurfaceHolder
|
||||||
import android.view.SurfaceView
|
import android.view.SurfaceView
|
||||||
|
import org.citra.citra_emu.NativeLibrary
|
||||||
|
|
||||||
class SecondScreenPresentation(
|
class SecondScreenPresentation(
|
||||||
context: Context,
|
context: Context,
|
||||||
@ -20,7 +19,7 @@ class SecondScreenPresentation(
|
|||||||
surfaceView = SurfaceView(context)
|
surfaceView = SurfaceView(context)
|
||||||
surfaceView.holder.addCallback(object : SurfaceHolder.Callback {
|
surfaceView.holder.addCallback(object : SurfaceHolder.Callback {
|
||||||
override fun surfaceCreated(holder: SurfaceHolder) {
|
override fun surfaceCreated(holder: SurfaceHolder) {
|
||||||
|
NativeLibrary.enableSecondWindow(holder.surface)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun surfaceChanged(
|
override fun surfaceChanged(
|
||||||
@ -29,9 +28,12 @@ class SecondScreenPresentation(
|
|||||||
width: Int,
|
width: Int,
|
||||||
height: Int
|
height: Int
|
||||||
) {
|
) {
|
||||||
|
NativeLibrary.enableSecondWindow(holder.surface)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun surfaceDestroyed(holder: SurfaceHolder) {}
|
override fun surfaceDestroyed(holder: SurfaceHolder) {
|
||||||
|
NativeLibrary.disableSecondWindow();
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
setContentView(surfaceView) // Set SurfaceView as content
|
setContentView(surfaceView) // Set SurfaceView as content
|
||||||
|
@ -1329,7 +1329,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun runWithValidSurface() {
|
private fun runWithValidSurface() {
|
||||||
NativeLibrary.surfaceChanged(surface!!, surface2!!)
|
NativeLibrary.surfaceChanged(surface!!)
|
||||||
when (state) {
|
when (state) {
|
||||||
State.STOPPED -> {
|
State.STOPPED -> {
|
||||||
Thread({
|
Thread({
|
||||||
|
@ -49,16 +49,17 @@ void EmuWindow_Android::OnFramebufferSizeChanged() {
|
|||||||
|
|
||||||
const int bigger{window_width > window_height ? window_width : window_height};
|
const int bigger{window_width > window_height ? window_width : window_height};
|
||||||
const int smaller{window_width < window_height ? window_width : window_height};
|
const int smaller{window_width < window_height ? window_width : window_height};
|
||||||
if (is_portrait_mode) {
|
if (is_portrait_mode && !is_secondary) {
|
||||||
UpdateCurrentFramebufferLayout(smaller, bigger, is_portrait_mode);
|
UpdateCurrentFramebufferLayout(smaller, bigger, is_portrait_mode);
|
||||||
} else {
|
} else {
|
||||||
UpdateCurrentFramebufferLayout(bigger, smaller, is_portrait_mode);
|
UpdateCurrentFramebufferLayout(bigger, smaller, is_portrait_mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface) : host_window{surface} {
|
EmuWindow_Android::EmuWindow_Android(ANativeWindow *surface, bool is_secondary) : EmuWindow{
|
||||||
|
is_secondary}, host_window(surface) {
|
||||||
LOG_DEBUG(Frontend, "Initializing EmuWindow_Android");
|
LOG_DEBUG(Frontend, "Initializing EmuWindow_Android");
|
||||||
|
if (is_secondary) LOG_DEBUG(Frontend, "Initializing secondary window Android");
|
||||||
if (!surface) {
|
if (!surface) {
|
||||||
LOG_CRITICAL(Frontend, "surface is nullptr");
|
LOG_CRITICAL(Frontend, "surface is nullptr");
|
||||||
return;
|
return;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <EGL/egl.h>
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
@ -13,7 +14,7 @@ class System;
|
|||||||
|
|
||||||
class EmuWindow_Android : public Frontend::EmuWindow {
|
class EmuWindow_Android : public Frontend::EmuWindow {
|
||||||
public:
|
public:
|
||||||
EmuWindow_Android(ANativeWindow* surface);
|
EmuWindow_Android(ANativeWindow* surface, bool is_secondary = false);
|
||||||
~EmuWindow_Android();
|
~EmuWindow_Android();
|
||||||
|
|
||||||
/// Called by the onSurfaceChanges() method to change the surface
|
/// Called by the onSurfaceChanges() method to change the surface
|
||||||
@ -30,7 +31,10 @@ public:
|
|||||||
void DoneCurrent() override;
|
void DoneCurrent() override;
|
||||||
|
|
||||||
virtual void TryPresenting() {}
|
virtual void TryPresenting() {}
|
||||||
|
// EGL Context must be shared
|
||||||
|
// could probably use the existing
|
||||||
|
// SharedContext for this instead, this is maybe temporary
|
||||||
|
virtual EGLContext* GetEGLContext() {return NULL;}
|
||||||
virtual void StopPresenting() {}
|
virtual void StopPresenting() {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -72,8 +72,8 @@ private:
|
|||||||
EGLContext egl_context{};
|
EGLContext egl_context{};
|
||||||
};
|
};
|
||||||
|
|
||||||
EmuWindow_Android_OpenGL::EmuWindow_Android_OpenGL(Core::System& system_, ANativeWindow* surface)
|
EmuWindow_Android_OpenGL::EmuWindow_Android_OpenGL(Core::System& system_, ANativeWindow* surface, bool is_secondary, EGLContext* sharedContext)
|
||||||
: EmuWindow_Android{surface}, system{system_} {
|
: EmuWindow_Android{surface,is_secondary}, system{system_} {
|
||||||
if (egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); egl_display == EGL_NO_DISPLAY) {
|
if (egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); egl_display == EGL_NO_DISPLAY) {
|
||||||
LOG_CRITICAL(Frontend, "eglGetDisplay() failed");
|
LOG_CRITICAL(Frontend, "eglGetDisplay() failed");
|
||||||
return;
|
return;
|
||||||
@ -96,8 +96,9 @@ EmuWindow_Android_OpenGL::EmuWindow_Android_OpenGL(Core::System& system_, ANativ
|
|||||||
if (eglQuerySurface(egl_display, egl_surface, EGL_HEIGHT, &window_height) != EGL_TRUE) {
|
if (eglQuerySurface(egl_display, egl_surface, EGL_HEIGHT, &window_height) != EGL_TRUE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (sharedContext) {
|
||||||
if (egl_context = eglCreateContext(egl_display, egl_config, 0, egl_context_attribs.data());
|
egl_context = *sharedContext;
|
||||||
|
}else if (egl_context = eglCreateContext(egl_display, egl_config, 0, egl_context_attribs.data());
|
||||||
egl_context == EGL_NO_CONTEXT) {
|
egl_context == EGL_NO_CONTEXT) {
|
||||||
LOG_CRITICAL(Frontend, "eglCreateContext() failed");
|
LOG_CRITICAL(Frontend, "eglCreateContext() failed");
|
||||||
return;
|
return;
|
||||||
@ -127,6 +128,10 @@ EmuWindow_Android_OpenGL::EmuWindow_Android_OpenGL(Core::System& system_, ANativ
|
|||||||
OnFramebufferSizeChanged();
|
OnFramebufferSizeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EGLContext* EmuWindow_Android_OpenGL::GetEGLContext() {
|
||||||
|
return &egl_context;
|
||||||
|
}
|
||||||
|
|
||||||
bool EmuWindow_Android_OpenGL::CreateWindowSurface() {
|
bool EmuWindow_Android_OpenGL::CreateWindowSurface() {
|
||||||
if (!host_window) {
|
if (!host_window) {
|
||||||
return true;
|
return true;
|
||||||
@ -204,14 +209,15 @@ void EmuWindow_Android_OpenGL::TryPresenting() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (presenting_state == PresentingState::Initial) [[unlikely]] {
|
if (presenting_state == PresentingState::Initial) [[unlikely]] {
|
||||||
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
|
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
||||||
presenting_state = PresentingState::Running;
|
presenting_state = PresentingState::Running;
|
||||||
}
|
}
|
||||||
if (presenting_state != PresentingState::Running) [[unlikely]] {
|
// if (presenting_state != PresentingState::Running) [[unlikely]] {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
eglSwapInterval(egl_display, Settings::values.use_vsync_new ? 1 : 0);
|
eglSwapInterval(egl_display, Settings::values.use_vsync_new ? 1 : 0);
|
||||||
system.GPU().Renderer().TryPresent(0);
|
system.GPU().Renderer().TryPresent(100,is_secondary);
|
||||||
eglSwapBuffers(egl_display, egl_surface);
|
eglSwapBuffers(egl_display, egl_surface);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -19,13 +19,13 @@ struct ANativeWindow;
|
|||||||
|
|
||||||
class EmuWindow_Android_OpenGL : public EmuWindow_Android {
|
class EmuWindow_Android_OpenGL : public EmuWindow_Android {
|
||||||
public:
|
public:
|
||||||
EmuWindow_Android_OpenGL(Core::System& system, ANativeWindow* surface);
|
EmuWindow_Android_OpenGL(Core::System& system, ANativeWindow* surface, bool is_secondary, EGLContext* sharedContext = NULL);
|
||||||
~EmuWindow_Android_OpenGL() override = default;
|
~EmuWindow_Android_OpenGL() override = default;
|
||||||
|
|
||||||
void TryPresenting() override;
|
void TryPresenting() override;
|
||||||
void StopPresenting() override;
|
void StopPresenting() override;
|
||||||
void PollEvents() override;
|
void PollEvents() override;
|
||||||
|
EGLContext* GetEGLContext() override;
|
||||||
std::unique_ptr<GraphicsContext> CreateSharedContext() const override;
|
std::unique_ptr<GraphicsContext> CreateSharedContext() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -24,8 +24,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
EmuWindow_Android_Vulkan::EmuWindow_Android_Vulkan(
|
EmuWindow_Android_Vulkan::EmuWindow_Android_Vulkan(
|
||||||
ANativeWindow* surface, std::shared_ptr<Common::DynamicLibrary> driver_library_)
|
ANativeWindow* surface, std::shared_ptr<Common::DynamicLibrary> driver_library_, bool is_secondary)
|
||||||
: EmuWindow_Android{surface}, driver_library{driver_library_} {
|
: EmuWindow_Android{surface,is_secondary}, driver_library{driver_library_} {
|
||||||
CreateWindowSurface();
|
CreateWindowSurface();
|
||||||
|
|
||||||
if (core_context = CreateSharedContext(); !core_context) {
|
if (core_context = CreateSharedContext(); !core_context) {
|
||||||
|
@ -11,7 +11,7 @@ struct ANativeWindow;
|
|||||||
class EmuWindow_Android_Vulkan : public EmuWindow_Android {
|
class EmuWindow_Android_Vulkan : public EmuWindow_Android {
|
||||||
public:
|
public:
|
||||||
EmuWindow_Android_Vulkan(ANativeWindow* surface,
|
EmuWindow_Android_Vulkan(ANativeWindow* surface,
|
||||||
std::shared_ptr<Common::DynamicLibrary> driver_library);
|
std::shared_ptr<Common::DynamicLibrary> driver_library, bool is_secondary);
|
||||||
~EmuWindow_Android_Vulkan() override = default;
|
~EmuWindow_Android_Vulkan() override = default;
|
||||||
|
|
||||||
void PollEvents() override {}
|
void PollEvents() override {}
|
||||||
|
@ -65,9 +65,12 @@
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
ANativeWindow* s_surf;
|
ANativeWindow* s_surf;
|
||||||
|
ANativeWindow* s_secondary_surface;
|
||||||
|
bool secondary_enabled = false;
|
||||||
|
|
||||||
std::shared_ptr<Common::DynamicLibrary> vulkan_library{};
|
std::shared_ptr<Common::DynamicLibrary> vulkan_library{};
|
||||||
std::unique_ptr<EmuWindow_Android> window;
|
std::unique_ptr<EmuWindow_Android> window;
|
||||||
|
std::unique_ptr<EmuWindow_Android> second_window;
|
||||||
|
|
||||||
std::atomic<bool> stop_run{true};
|
std::atomic<bool> stop_run{true};
|
||||||
std::atomic<bool> pause_emulation{false};
|
std::atomic<bool> pause_emulation{false};
|
||||||
@ -118,8 +121,10 @@ static void TryShutdown() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
window->DoneCurrent();
|
window->DoneCurrent();
|
||||||
|
if (second_window) second_window->DoneCurrent();
|
||||||
Core::System::GetInstance().Shutdown();
|
Core::System::GetInstance().Shutdown();
|
||||||
window.reset();
|
window.reset();
|
||||||
|
if (second_window) second_window.reset();
|
||||||
InputManager::Shutdown();
|
InputManager::Shutdown();
|
||||||
MicroProfileShutdown();
|
MicroProfileShutdown();
|
||||||
}
|
}
|
||||||
@ -148,12 +153,17 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
|
|||||||
switch (graphics_api) {
|
switch (graphics_api) {
|
||||||
#ifdef ENABLE_OPENGL
|
#ifdef ENABLE_OPENGL
|
||||||
case Settings::GraphicsAPI::OpenGL:
|
case Settings::GraphicsAPI::OpenGL:
|
||||||
window = std::make_unique<EmuWindow_Android_OpenGL>(system, s_surf);
|
window = std::make_unique<EmuWindow_Android_OpenGL>(system, s_surf,false);
|
||||||
|
if (secondary_enabled) {
|
||||||
|
EGLContext* c = window->GetEGLContext();
|
||||||
|
second_window = std::make_unique<EmuWindow_Android_OpenGL>(system,s_secondary_surface, true, c);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_VULKAN
|
#ifdef ENABLE_VULKAN
|
||||||
case Settings::GraphicsAPI::Vulkan:
|
case Settings::GraphicsAPI::Vulkan:
|
||||||
window = std::make_unique<EmuWindow_Android_Vulkan>(s_surf, vulkan_library);
|
window = std::make_unique<EmuWindow_Android_Vulkan>(s_surf, vulkan_library,false);
|
||||||
|
if (secondary_enabled) second_window = std::make_unique<EmuWindow_Android_Vulkan>(s_secondary_surface, vulkan_library, true);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
@ -161,9 +171,14 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
|
|||||||
"Unknown or unsupported graphics API {}, falling back to available default",
|
"Unknown or unsupported graphics API {}, falling back to available default",
|
||||||
graphics_api);
|
graphics_api);
|
||||||
#ifdef ENABLE_OPENGL
|
#ifdef ENABLE_OPENGL
|
||||||
window = std::make_unique<EmuWindow_Android_OpenGL>(system, s_surf);
|
window = std::make_unique<EmuWindow_Android_OpenGL>(system, s_surf, false);
|
||||||
|
if (secondary_enabled) {
|
||||||
|
EGLContext *c = window->GetEGLContext();
|
||||||
|
second_window = std::make_unique<EmuWindow_Android_OpenGL>(system, s_secondary_surface,true, c);
|
||||||
|
}
|
||||||
#elif ENABLE_VULKAN
|
#elif ENABLE_VULKAN
|
||||||
window = std::make_unique<EmuWindow_Android_Vulkan>(s_surf, vulkan_library);
|
window = std::make_unique<EmuWindow_Android_Vulkan>(s_surf, vulkan_library);
|
||||||
|
if (secondary_enabled) second_window = std::make_unique<EmuWindow_Android_Vulkan>(s_secondary_surface, vulkan_library, true);
|
||||||
#else
|
#else
|
||||||
// TODO: Add a null renderer backend for this, perhaps.
|
// TODO: Add a null renderer backend for this, perhaps.
|
||||||
#error "At least one renderer must be enabled."
|
#error "At least one renderer must be enabled."
|
||||||
@ -202,7 +217,8 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
|
|||||||
InputManager::Init();
|
InputManager::Init();
|
||||||
|
|
||||||
window->MakeCurrent();
|
window->MakeCurrent();
|
||||||
const Core::System::ResultStatus load_result{system.Load(*window, filepath)};
|
//if (second_window) second_window->MakeCurrent();
|
||||||
|
const Core::System::ResultStatus load_result{system.Load(*window, filepath,second_window.get())};
|
||||||
if (load_result != Core::System::ResultStatus::Success) {
|
if (load_result != Core::System::ResultStatus::Success) {
|
||||||
return load_result;
|
return load_result;
|
||||||
}
|
}
|
||||||
@ -249,6 +265,7 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
|
|||||||
std::unique_lock pause_lock{paused_mutex};
|
std::unique_lock pause_lock{paused_mutex};
|
||||||
running_cv.wait(pause_lock, [] { return !pause_emulation || stop_run; });
|
running_cv.wait(pause_lock, [] { return !pause_emulation || stop_run; });
|
||||||
window->PollEvents();
|
window->PollEvents();
|
||||||
|
//if (second_window) second_window->PollEvents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,6 +323,23 @@ void Java_org_citra_citra_1emu_NativeLibrary_surfaceChanged(JNIEnv* env,
|
|||||||
LOG_INFO(Frontend, "Surface changed");
|
LOG_INFO(Frontend, "Surface changed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Java_org_citra_citra_1emu_NativeLibrary_enableSecondWindow(JNIEnv* env,
|
||||||
|
[[maybe_unused]] jobject obj,jobject surf) {
|
||||||
|
s_secondary_surface = ANativeWindow_fromSurface(env, surf);
|
||||||
|
secondary_enabled = true;
|
||||||
|
|
||||||
|
LOG_INFO(Frontend, "Secondary Surface Enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Java_org_citra_citra_1emu_NativeLibrary_disableSecondWindow(JNIEnv* env,
|
||||||
|
[[maybe_unused]] jobject obj) {
|
||||||
|
|
||||||
|
secondary_enabled = false;
|
||||||
|
// how do I delete the window? TODO
|
||||||
|
|
||||||
|
LOG_INFO(Frontend, "Secondary Surface Disabled");
|
||||||
|
}
|
||||||
|
|
||||||
void Java_org_citra_citra_1emu_NativeLibrary_surfaceDestroyed([[maybe_unused]] JNIEnv* env,
|
void Java_org_citra_citra_1emu_NativeLibrary_surfaceDestroyed([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jobject obj) {
|
[[maybe_unused]] jobject obj) {
|
||||||
if (s_surf != nullptr) {
|
if (s_surf != nullptr) {
|
||||||
@ -325,6 +359,9 @@ void Java_org_citra_citra_1emu_NativeLibrary_doFrame([[maybe_unused]] JNIEnv* en
|
|||||||
if (window) {
|
if (window) {
|
||||||
window->TryPresenting();
|
window->TryPresenting();
|
||||||
}
|
}
|
||||||
|
if (second_window) {
|
||||||
|
second_window->TryPresenting();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JNICALL Java_org_citra_citra_1emu_NativeLibrary_initializeGpuDriver(
|
void JNICALL Java_org_citra_citra_1emu_NativeLibrary_initializeGpuDriver(
|
||||||
@ -481,6 +518,7 @@ void Java_org_citra_citra_1emu_NativeLibrary_stopEmulation([[maybe_unused]] JNIE
|
|||||||
stop_run = true;
|
stop_run = true;
|
||||||
pause_emulation = false;
|
pause_emulation = false;
|
||||||
window->StopPresenting();
|
window->StopPresenting();
|
||||||
|
if (second_window) second_window->StopPresenting();
|
||||||
running_cv.notify_all();
|
running_cv.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -745,4 +783,4 @@ void Java_org_citra_citra_1emu_NativeLibrary_logDeviceInfo([[maybe_unused]] JNIE
|
|||||||
LOG_INFO(Frontend, "Host OS: Android API level {}", android_get_device_api_level());
|
LOG_INFO(Frontend, "Host OS: Android API level {}", android_get_device_api_level());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // extern "C"
|
}
|
@ -251,6 +251,13 @@ void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height, bool is_po
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef ANDROID
|
||||||
|
// if is_secondary is set on android, MUST be a second window
|
||||||
|
if (is_secondary) {
|
||||||
|
layout = Layout::SeparateWindowsLayout(width, height, is_secondary,
|
||||||
|
Settings::values.upright_screen.GetValue());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
UpdateMinimumWindowSize(min_size);
|
UpdateMinimumWindowSize(min_size);
|
||||||
|
|
||||||
if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::CardboardVR) {
|
if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::CardboardVR) {
|
||||||
|
@ -35,7 +35,7 @@ void RendererBase::UpdateCurrentFramebufferLayout(bool is_portrait_mode) {
|
|||||||
window.UpdateCurrentFramebufferLayout(layout.width, layout.height, is_portrait_mode);
|
window.UpdateCurrentFramebufferLayout(layout.width, layout.height, is_portrait_mode);
|
||||||
};
|
};
|
||||||
update_layout(render_window);
|
update_layout(render_window);
|
||||||
if (secondary_window) {
|
if (secondary_window != nullptr) {
|
||||||
update_layout(*secondary_window);
|
update_layout(*secondary_window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ void RendererOpenGL::SwapBuffers() {
|
|||||||
PrepareRendertarget();
|
PrepareRendertarget();
|
||||||
RenderScreenshot();
|
RenderScreenshot();
|
||||||
|
|
||||||
const auto& main_layout = render_window.GetFramebufferLayout();
|
const auto &main_layout = render_window.GetFramebufferLayout();
|
||||||
RenderToMailbox(main_layout, render_window.mailbox, false);
|
RenderToMailbox(main_layout, render_window.mailbox, false);
|
||||||
|
|
||||||
#ifndef ANDROID
|
#ifndef ANDROID
|
||||||
@ -106,6 +106,15 @@ void RendererOpenGL::SwapBuffers() {
|
|||||||
RenderToMailbox(secondary_layout, secondary_window->mailbox, false);
|
RenderToMailbox(secondary_layout, secondary_window->mailbox, false);
|
||||||
secondary_window->PollEvents();
|
secondary_window->PollEvents();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ANDROID
|
||||||
|
// on android, if secondary_window is defined at all
|
||||||
|
// it means we have a second display
|
||||||
|
if (secondary_window) {
|
||||||
|
const auto &secondary_layout = secondary_window->GetFramebufferLayout();
|
||||||
|
RenderToMailbox(secondary_layout, secondary_window->mailbox, false);
|
||||||
|
secondary_window->PollEvents();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (frame_dumper.IsDumping()) {
|
if (frame_dumper.IsDumping()) {
|
||||||
try {
|
try {
|
||||||
@ -553,7 +562,7 @@ void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, fl
|
|||||||
state.texture_units[0].texture_2d = 0;
|
state.texture_units[0].texture_2d = 0;
|
||||||
state.texture_units[0].sampler = 0;
|
state.texture_units[0].sampler = 0;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD
|
* Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD
|
||||||
|
@ -829,6 +829,16 @@ void RendererVulkan::SwapBuffers() {
|
|||||||
RenderToWindow(*second_window, secondary_layout, false);
|
RenderToWindow(*second_window, secondary_layout, false);
|
||||||
secondary_window->PollEvents();
|
secondary_window->PollEvents();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ANDROID
|
||||||
|
if (secondary_window) {
|
||||||
|
const auto &secondary_layout = secondary_window->GetFramebufferLayout();
|
||||||
|
if (!second_window) {
|
||||||
|
second_window = std::make_unique<PresentWindow>(*secondary_window, instance, scheduler);
|
||||||
|
}
|
||||||
|
RenderToWindow(*second_window, secondary_layout, false);
|
||||||
|
secondary_window->PollEvents();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
rasterizer.TickFrame();
|
rasterizer.TickFrame();
|
||||||
EndFrame();
|
EndFrame();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user