openGL is working!

This commit is contained in:
David Griswold 2025-03-11 16:24:32 -03:00
parent c22ac3367e
commit 3929d44815
8 changed files with 264 additions and 168 deletions

View File

@ -126,8 +126,9 @@ object NativeLibrary {
external fun doFrame()
//Second window
external fun enableSecondWindow(secondary_surface: Surface)
external fun disableSecondWindow()
external fun secondarySurfaceChanged(secondary_surface: Surface)
external fun secondarySurfaceDestroyed()
external fun disableSecondaryScreen()
/**
* Unpauses emulation from a paused state.
*/

View File

@ -67,6 +67,9 @@ class EmulationActivity : AppCompatActivity() {
private fun updatePresentation() {
displayManager = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
val display = getCustomerDisplay();
if (secondScreenPresentation != null && (IntSetting.SECONDARY_SCREEN_LAYOUT.int == SecondaryScreenLayout.NONE.int || display == null)) {
releasePresentation();
}
if (secondScreenPresentation == null || secondScreenPresentation?.display != display) {
secondScreenPresentation?.dismiss()
if (display != null && IntSetting.SECONDARY_SCREEN_LAYOUT.int != SecondaryScreenLayout.NONE.int) {
@ -76,9 +79,12 @@ class EmulationActivity : AppCompatActivity() {
}
}
private fun releasePresentation() {
if (secondScreenPresentation != null) {
NativeLibrary.disableSecondaryScreen()
secondScreenPresentation?.dismiss();
secondScreenPresentation = null;
}
}
private fun getCustomerDisplay(): Display? {
return displayManager?.displays?.firstOrNull { it.isValid && it.displayId != Display.DEFAULT_DISPLAY }

View File

@ -6,6 +6,8 @@ import android.view.SurfaceHolder
import android.view.SurfaceView
import org.citra.citra_emu.NativeLibrary
class SecondScreenPresentation(
context: Context,
display: Display,
@ -19,7 +21,7 @@ class SecondScreenPresentation(
surfaceView = SurfaceView(context)
surfaceView.holder.addCallback(object : SurfaceHolder.Callback {
override fun surfaceCreated(holder: SurfaceHolder) {
NativeLibrary.enableSecondWindow(holder.surface)
}
override fun surfaceChanged(
@ -28,11 +30,11 @@ class SecondScreenPresentation(
width: Int,
height: Int
) {
NativeLibrary.enableSecondWindow(holder.surface)
NativeLibrary.secondarySurfaceChanged(holder.surface)
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
NativeLibrary.disableSecondWindow();
NativeLibrary.secondarySurfaceDestroyed()
}
})

View File

@ -16,11 +16,15 @@
#include <core/hle/service/cfg/cfg.h>
#include "audio_core/dsp_interface.h"
#include "common/arch.h"
#if CITRA_ARCH(arm64)
#include "common/aarch64/cpu_detect.h"
#elif CITRA_ARCH(x86_64)
#include "common/x64/cpu_detect.h"
#endif
#include "common/common_paths.h"
#include "common/dynamic_library/dynamic_library.h"
#include "common/file_util.h"
@ -44,12 +48,18 @@
#include "jni/camera/ndk_camera.h"
#include "jni/camera/still_image_camera.h"
#include "jni/config.h"
#ifdef ENABLE_OPENGL
#include "jni/emu_window/emu_window_gl.h"
#endif
#ifdef ENABLE_VULKAN
#include "jni/emu_window/emu_window_vk.h"
#endif
#include "jni/id_cache.h"
#include "jni/input_manager.h"
#include "jni/ndk_motion.h"
@ -59,7 +69,9 @@
#include "video_core/renderer_base.h"
#if defined(ENABLE_VULKAN) && CITRA_ARCH(arm64)
#include <adrenotools/driver.h>
#endif
namespace {
@ -156,14 +168,18 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
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);
second_window = std::make_unique<EmuWindow_Android_OpenGL>(system,
s_secondary_surface,
true, c);
}
break;
#endif
#ifdef ENABLE_VULKAN
case Settings::GraphicsAPI::Vulkan:
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);
if (secondary_enabled)
second_window = std::make_unique<EmuWindow_Android_Vulkan>(s_secondary_surface,
vulkan_library, true);
break;
#endif
default:
@ -174,7 +190,9 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
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);
second_window = std::make_unique<EmuWindow_Android_OpenGL>(system,
s_secondary_surface,
true, c);
}
#elif ENABLE_VULKAN
window = std::make_unique<EmuWindow_Android_Vulkan>(s_surf, vulkan_library);
@ -217,8 +235,8 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
InputManager::Init();
window->MakeCurrent();
//if (second_window) second_window->MakeCurrent();
const Core::System::ResultStatus load_result{system.Load(*window, filepath,second_window.get())};
const Core::System::ResultStatus load_result{
system.Load(*window, filepath, second_window.get())};
if (load_result != Core::System::ResultStatus::Success) {
return load_result;
}
@ -323,15 +341,39 @@ void Java_org_citra_citra_1emu_NativeLibrary_surfaceChanged(JNIEnv* env,
LOG_INFO(Frontend, "Surface changed");
}
void Java_org_citra_citra_1emu_NativeLibrary_enableSecondWindow(JNIEnv* env,
[[maybe_unused]] jobject obj,jobject surf) {
void Java_org_citra_citra_1emu_NativeLibrary_secondarySurfaceChanged(JNIEnv *env,
[[maybe_unused]] jobject obj,
jobject surf) {
auto &system = Core::System::GetInstance();
s_secondary_surface = ANativeWindow_fromSurface(env, surf);
secondary_enabled = true;
bool notify = false;
if (second_window) {
notify = second_window->OnSurfaceChanged(s_secondary_surface);
if (!s_secondary_surface) {
// did not create the surface, so disable second screen
secondary_enabled = false;
if (system.IsPoweredOn()) {
system.GPU().Renderer().setSecondaryWindow(nullptr);
}
auto& system = Core::System::GetInstance();
return;
}
if (second_window) {
//second window already created, so update it
notify = second_window->OnSurfaceChanged(s_secondary_surface);
} else if (system.IsPoweredOn() && window) {
// emulation running, window is new
// create a new window and set it
const auto graphics_api = Settings::values.graphics_api.GetValue();
if (graphics_api == Settings::GraphicsAPI::OpenGL) {
EGLContext *c = window->GetEGLContext();
second_window = std::make_unique<EmuWindow_Android_OpenGL>(system,
s_secondary_surface,true, c);
}else{
second_window = std::make_unique<EmuWindow_Android_Vulkan>(s_secondary_surface,
vulkan_library, true);
}
system.GPU().Renderer().setSecondaryWindow(second_window.get());
}
if (notify && system.IsPoweredOn()) {
system.GPU().Renderer().NotifySurfaceChanged(true);
}
@ -340,22 +382,36 @@ void Java_org_citra_citra_1emu_NativeLibrary_enableSecondWindow(JNIEnv* env,
}
void Java_org_citra_citra_1emu_NativeLibrary_disableSecondWindow(JNIEnv* env,
void Java_org_citra_citra_1emu_NativeLibrary_secondarySurfaceDestroyed(JNIEnv *env,
[[maybe_unused]] jobject obj) {
//auto &system = Core::System::GetInstance();
secondary_enabled = false;
if (s_secondary_surface != nullptr) {
ANativeWindow_release(s_secondary_surface);
s_secondary_surface = nullptr;
}
LOG_INFO(Frontend, "Secondary Surface Destroyed");
}
void Java_org_citra_citra_1emu_NativeLibrary_disableSecondaryScreen(JNIEnv *env,
[[maybe_unused]] jobject obj) {
auto &system = Core::System::GetInstance();
secondary_enabled = false;
if (s_secondary_surface != nullptr) {
ANativeWindow_release(s_secondary_surface);
s_secondary_surface = nullptr;
}
if (system.IsPoweredOn()) {
system.GPU().Renderer().setSecondaryWindow(nullptr);
}
if (second_window) {
second_window->OnSurfaceChanged(s_secondary_surface);
}
second_window.release();
second_window = nullptr;
}
LOG_INFO(Frontend, "Secondary Window Disabled");
LOG_INFO(Frontend, "Secondary Surface Disabled");
}
void Java_org_citra_citra_1emu_NativeLibrary_surfaceDestroyed([[maybe_unused]] JNIEnv *env,
[[maybe_unused]] jobject obj) {
if (s_surf != nullptr) {
@ -442,7 +498,8 @@ jobjectArray Java_org_citra_citra_1emu_NativeLibrary_getInstalledGamePaths(
JNIEnv *env, [[maybe_unused]] jclass clazz) {
std::vector<std::string> games;
const FileUtil::DirectoryEntryCallable ScanDir =
[&games, &ScanDir](u64*, const std::string& directory, const std::string& virtual_name) {
[&games, &ScanDir](u64 *, const std::string &directory,
const std::string &virtual_name) {
std::string path = directory + virtual_name;
if (FileUtil::IsDirectory(path)) {
path += '/';
@ -565,7 +622,8 @@ jboolean Java_org_citra_citra_1emu_NativeLibrary_onGamePadEvent([[maybe_unused]]
}
jboolean Java_org_citra_citra_1emu_NativeLibrary_onGamePadMoveEvent(
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj, [[maybe_unused]] jstring j_device,
[[maybe_unused]] JNIEnv *env, [[maybe_unused]] jobject obj,
[[maybe_unused]] jstring j_device,
jint axis, jfloat x, jfloat y) {
// Clamp joystick movement to supported minimum and maximum
// Citra uses an inverted y axis sent by the frontend
@ -584,7 +642,8 @@ jboolean Java_org_citra_citra_1emu_NativeLibrary_onGamePadMoveEvent(
}
jboolean Java_org_citra_citra_1emu_NativeLibrary_onGamePadAxisEvent(
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj, [[maybe_unused]] jstring j_device,
[[maybe_unused]] JNIEnv *env, [[maybe_unused]] jobject obj,
[[maybe_unused]] jstring j_device,
jint axis_id, jfloat axis_val) {
return static_cast<jboolean>(
InputManager::ButtonHandler()->AnalogButtonEvent(axis_id, axis_val));
@ -740,7 +799,8 @@ JNIEXPORT jobject JNICALL Java_org_citra_citra_1emu_utils_CiaInstallWorker_insta
Service::AM::InstallStatus res = Service::AM::InstallCIA(
path, [env, jobj](std::size_t total_bytes_read, std::size_t file_size) {
env->CallVoidMethod(jobj, IDCache::GetCiaInstallHelperSetProgress(),
static_cast<jint>(file_size), static_cast<jint>(total_bytes_read));
static_cast<jint>(file_size),
static_cast<jint>(total_bytes_read));
});
return IDCache::GetJavaCiaInstallStatus(res);
@ -767,7 +827,8 @@ jobjectArray Java_org_citra_citra_1emu_NativeLibrary_getSavestateInfo(
const auto savestates = Core::ListSaveStates(title_id, system.Movie().GetCurrentMovieID());
const jobjectArray array =
env->NewObjectArray(static_cast<jsize>(savestates.size()), savestate_info_class, nullptr);
env->NewObjectArray(static_cast<jsize>(savestates.size()), savestate_info_class,
nullptr);
for (std::size_t i = 0; i < savestates.size(); ++i) {
const jobject object = env->AllocObject(savestate_info_class);
env->SetIntField(object, slot_field, static_cast<jint>(savestates[i].slot));

View File

@ -67,4 +67,13 @@ void RendererBase::RequestScreenshot(void* data, std::function<void(bool)> callb
settings.screenshot_requested = true;
}
Frontend::EmuWindow *RendererBase::getSecondaryWindow() const {
return secondary_window;
}
void RendererBase::setSecondaryWindow(Frontend::EmuWindow *secondaryWindow) {
secondary_window = secondaryWindow;
if (secondary_window) secondary_window->PollEvents();
}
} // namespace VideoCore

View File

@ -111,7 +111,14 @@ protected:
Core::System& system;
RendererSettings settings;
Frontend::EmuWindow& render_window; ///< Reference to the render window handle.
Frontend::EmuWindow* secondary_window; ///< Reference to the secondary render window handle.
Frontend::EmuWindow* secondary_window;
public:
Frontend::EmuWindow *getSecondaryWindow() const;
virtual void setSecondaryWindow(Frontend::EmuWindow *secondaryWindow);
protected:
///< Reference to the secondary render window handle.
f32 current_fps = 0.0f; ///< Current framerate, should be set by the renderer
s32 current_frame = 0; ///< Current frame, should be set by the renderer
};

View File

@ -87,6 +87,15 @@ RendererOpenGL::RendererOpenGL(Core::System& system, Pica::PicaCore& pica_,
}
RendererOpenGL::~RendererOpenGL() = default;
void RendererOpenGL::setSecondaryWindow(Frontend::EmuWindow *secondaryWindow) {
if (secondaryWindow) {
secondary_window = secondaryWindow;
secondary_window->mailbox = std::make_unique<OGLTextureMailbox>(driver.HasDebugTool());
}else {
secondary_window = nullptr;
// should I release something here? The mailbox??
}
}
void RendererOpenGL::SwapBuffers() {
// Maintain the rasterizer's state as a priority

View File

@ -54,6 +54,7 @@ public:
void PrepareVideoDumping() override;
void CleanupVideoDumping() override;
void Sync() override;
void setSecondaryWindow(Frontend::EmuWindow *secondaryWindow) override;
private:
void InitOpenGLObjects();