Android: Support GLES3 and hardware renderers
This commit is contained in:
parent
299ee05cd9
commit
adc3a2fac1
|
@ -28,7 +28,6 @@ android {
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
arguments "-DCMAKE_BUILD_TYPE=RelWithDebInfo"
|
arguments "-DCMAKE_BUILD_TYPE=RelWithDebInfo"
|
||||||
abiFilters "x86"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@ set(SRCS
|
||||||
android_audio_stream.h
|
android_audio_stream.h
|
||||||
android_host_interface.cpp
|
android_host_interface.cpp
|
||||||
android_host_interface.h
|
android_host_interface.h
|
||||||
android_gles2_host_display.cpp
|
android_gles_host_display.cpp
|
||||||
android_gles2_host_display.h
|
android_gles_host_display.h
|
||||||
main.cpp
|
main.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
#include "android_gles2_host_display.h"
|
#include "android_gles_host_display.h"
|
||||||
#include "YBaseLib/Log.h"
|
#include "YBaseLib/Log.h"
|
||||||
#include <EGL/eglext.h>
|
#include <EGL/eglext.h>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <imgui_impl_opengl3.h>
|
#include <imgui_impl_opengl3.h>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
Log_SetChannel(AndroidGLES2HostDisplay);
|
Log_SetChannel(AndroidGLESHostDisplay);
|
||||||
|
|
||||||
class AndroidGLES2HostDisplayTexture : public HostDisplayTexture
|
class AndroidGLESHostDisplayTexture : public HostDisplayTexture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AndroidGLES2HostDisplayTexture(GLuint id, u32 width, u32 height) : m_id(id), m_width(width), m_height(height) {}
|
AndroidGLESHostDisplayTexture(GLuint id, u32 width, u32 height) : m_id(id), m_width(width), m_height(height) {}
|
||||||
~AndroidGLES2HostDisplayTexture() override { glDeleteTextures(1, &m_id); }
|
~AndroidGLESHostDisplayTexture() override { glDeleteTextures(1, &m_id); }
|
||||||
|
|
||||||
void* GetHandle() const override { return reinterpret_cast<void*>(static_cast<uintptr_t>(m_id)); }
|
void* GetHandle() const override { return reinterpret_cast<void*>(static_cast<uintptr_t>(m_id)); }
|
||||||
u32 GetWidth() const override { return m_width; }
|
u32 GetWidth() const override { return m_width; }
|
||||||
|
@ -19,7 +19,7 @@ public:
|
||||||
|
|
||||||
GLuint GetGLID() const { return m_id; }
|
GLuint GetGLID() const { return m_id; }
|
||||||
|
|
||||||
static std::unique_ptr<AndroidGLES2HostDisplayTexture> Create(u32 width, u32 height, const void* initial_data,
|
static std::unique_ptr<AndroidGLESHostDisplayTexture> Create(u32 width, u32 height, const void* initial_data,
|
||||||
u32 initial_data_stride)
|
u32 initial_data_stride)
|
||||||
{
|
{
|
||||||
GLuint id;
|
GLuint id;
|
||||||
|
@ -38,7 +38,7 @@ public:
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, id);
|
glBindTexture(GL_TEXTURE_2D, id);
|
||||||
return std::make_unique<AndroidGLES2HostDisplayTexture>(id, width, height);
|
return std::make_unique<AndroidGLESHostDisplayTexture>(id, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -47,12 +47,12 @@ private:
|
||||||
u32 m_height;
|
u32 m_height;
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidGLES2HostDisplay::AndroidGLES2HostDisplay(ANativeWindow* window)
|
AndroidGLESHostDisplay::AndroidGLESHostDisplay(ANativeWindow* window)
|
||||||
: m_window(window), m_window_width(ANativeWindow_getWidth(window)), m_window_height(ANativeWindow_getHeight(window))
|
: m_window(window), m_window_width(ANativeWindow_getWidth(window)), m_window_height(ANativeWindow_getHeight(window))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
AndroidGLES2HostDisplay::~AndroidGLES2HostDisplay()
|
AndroidGLESHostDisplay::~AndroidGLESHostDisplay()
|
||||||
{
|
{
|
||||||
if (m_egl_context != EGL_NO_CONTEXT)
|
if (m_egl_context != EGL_NO_CONTEXT)
|
||||||
{
|
{
|
||||||
|
@ -66,27 +66,27 @@ AndroidGLES2HostDisplay::~AndroidGLES2HostDisplay()
|
||||||
eglDestroySurface(m_egl_display, m_egl_surface);
|
eglDestroySurface(m_egl_display, m_egl_surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
HostDisplay::RenderAPI AndroidGLES2HostDisplay::GetRenderAPI() const
|
HostDisplay::RenderAPI AndroidGLESHostDisplay::GetRenderAPI() const
|
||||||
{
|
{
|
||||||
return HostDisplay::RenderAPI::OpenGLES;
|
return HostDisplay::RenderAPI::OpenGLES;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* AndroidGLES2HostDisplay::GetRenderDevice() const
|
void* AndroidGLESHostDisplay::GetRenderDevice() const
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* AndroidGLES2HostDisplay::GetRenderContext() const
|
void* AndroidGLESHostDisplay::GetRenderContext() const
|
||||||
{
|
{
|
||||||
return m_egl_context;
|
return m_egl_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* AndroidGLES2HostDisplay::GetRenderWindow() const
|
void* AndroidGLESHostDisplay::GetRenderWindow() const
|
||||||
{
|
{
|
||||||
return m_window;
|
return m_window;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidGLES2HostDisplay::ChangeRenderWindow(void* new_window)
|
void AndroidGLESHostDisplay::ChangeRenderWindow(void* new_window)
|
||||||
{
|
{
|
||||||
eglMakeCurrent(m_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
eglMakeCurrent(m_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||||
|
|
||||||
|
@ -101,16 +101,16 @@ void AndroidGLES2HostDisplay::ChangeRenderWindow(void* new_window)
|
||||||
Panic("Failed to make context current after window change");
|
Panic("Failed to make context current after window change");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<HostDisplayTexture> AndroidGLES2HostDisplay::CreateTexture(u32 width, u32 height, const void* data,
|
std::unique_ptr<HostDisplayTexture> AndroidGLESHostDisplay::CreateTexture(u32 width, u32 height, const void* data,
|
||||||
u32 data_stride, bool dynamic)
|
u32 data_stride, bool dynamic)
|
||||||
{
|
{
|
||||||
return AndroidGLES2HostDisplayTexture::Create(width, height, data, data_stride);
|
return AndroidGLESHostDisplayTexture::Create(width, height, data, data_stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidGLES2HostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
|
void AndroidGLESHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
|
||||||
const void* data, u32 data_stride)
|
const void* data, u32 data_stride)
|
||||||
{
|
{
|
||||||
AndroidGLES2HostDisplayTexture* tex = static_cast<AndroidGLES2HostDisplayTexture*>(texture);
|
AndroidGLESHostDisplayTexture* tex = static_cast<AndroidGLESHostDisplayTexture*>(texture);
|
||||||
Assert(data_stride == (width * sizeof(u32)));
|
Assert(data_stride == (width * sizeof(u32)));
|
||||||
|
|
||||||
GLint old_texture_binding = 0;
|
GLint old_texture_binding = 0;
|
||||||
|
@ -122,7 +122,7 @@ void AndroidGLES2HostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x,
|
||||||
glBindTexture(GL_TEXTURE_2D, old_texture_binding);
|
glBindTexture(GL_TEXTURE_2D, old_texture_binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidGLES2HostDisplay::SetDisplayTexture(void* texture, s32 offset_x, s32 offset_y, s32 width, s32 height,
|
void AndroidGLESHostDisplay::SetDisplayTexture(void* texture, s32 offset_x, s32 offset_y, s32 width, s32 height,
|
||||||
u32 texture_width, u32 texture_height, float aspect_ratio)
|
u32 texture_width, u32 texture_height, float aspect_ratio)
|
||||||
{
|
{
|
||||||
m_display_texture_id = static_cast<GLuint>(reinterpret_cast<uintptr_t>(texture));
|
m_display_texture_id = static_cast<GLuint>(reinterpret_cast<uintptr_t>(texture));
|
||||||
|
@ -136,39 +136,41 @@ void AndroidGLES2HostDisplay::SetDisplayTexture(void* texture, s32 offset_x, s32
|
||||||
m_display_texture_changed = true;
|
m_display_texture_changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidGLES2HostDisplay::SetDisplayLinearFiltering(bool enabled)
|
void AndroidGLESHostDisplay::SetDisplayLinearFiltering(bool enabled)
|
||||||
{
|
{
|
||||||
m_display_linear_filtering = enabled;
|
m_display_linear_filtering = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidGLES2HostDisplay::SetDisplayTopMargin(int height)
|
void AndroidGLESHostDisplay::SetDisplayTopMargin(int height)
|
||||||
{
|
{
|
||||||
m_display_top_margin = height;
|
m_display_top_margin = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidGLES2HostDisplay::SetVSync(bool enabled)
|
void AndroidGLESHostDisplay::SetVSync(bool enabled)
|
||||||
{
|
{
|
||||||
eglSwapInterval(m_egl_display, enabled ? 1 : 0);
|
eglSwapInterval(m_egl_display, enabled ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<u32, u32> AndroidGLES2HostDisplay::GetWindowSize() const
|
std::tuple<u32, u32> AndroidGLESHostDisplay::GetWindowSize() const
|
||||||
{
|
{
|
||||||
return std::make_tuple(static_cast<u32>(m_window_width), static_cast<u32>(m_window_height));
|
return std::make_tuple(static_cast<u32>(m_window_width), static_cast<u32>(m_window_height));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidGLES2HostDisplay::WindowResized()
|
void AndroidGLESHostDisplay::WindowResized()
|
||||||
{
|
{
|
||||||
m_window_width = ANativeWindow_getWidth(m_window);
|
m_window_width = ANativeWindow_getWidth(m_window);
|
||||||
m_window_height = ANativeWindow_getHeight(m_window);
|
m_window_height = ANativeWindow_getHeight(m_window);
|
||||||
|
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_width);
|
||||||
|
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_height);
|
||||||
Log_InfoPrintf("WindowResized %dx%d", m_window_width, m_window_height);
|
Log_InfoPrintf("WindowResized %dx%d", m_window_width, m_window_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* AndroidGLES2HostDisplay::GetGLSLVersionString() const
|
const char* AndroidGLESHostDisplay::GetGLSLVersionString() const
|
||||||
{
|
{
|
||||||
return "#version 100";
|
return "#version 100";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AndroidGLES2HostDisplay::GetGLSLVersionHeader() const
|
std::string AndroidGLESHostDisplay::GetGLSLVersionHeader() const
|
||||||
{
|
{
|
||||||
return R"(
|
return R"(
|
||||||
#version 100
|
#version 100
|
||||||
|
@ -178,7 +180,7 @@ precision highp int;
|
||||||
)";
|
)";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AndroidGLES2HostDisplay::CreateGLContext()
|
bool AndroidGLESHostDisplay::CreateGLContext()
|
||||||
{
|
{
|
||||||
m_egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
m_egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||||
if (!m_egl_display)
|
if (!m_egl_display)
|
||||||
|
@ -209,8 +211,15 @@ bool AndroidGLES2HostDisplay::CreateGLContext()
|
||||||
|
|
||||||
eglBindAPI(EGL_OPENGL_ES_API);
|
eglBindAPI(EGL_OPENGL_ES_API);
|
||||||
|
|
||||||
static constexpr std::array<int, 3> egl_context_attribs = {{EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}};
|
// Try GLES 3, then fall back to GLES 2.
|
||||||
m_egl_context = eglCreateContext(m_egl_display, m_egl_config, EGL_NO_CONTEXT, egl_context_attribs.data());
|
for (int major_version : {3, 2}) {
|
||||||
|
std::array<int, 3> egl_context_attribs = {{EGL_CONTEXT_CLIENT_VERSION, major_version, EGL_NONE}};
|
||||||
|
m_egl_context = eglCreateContext(m_egl_display, m_egl_config, EGL_NO_CONTEXT,
|
||||||
|
egl_context_attribs.data());
|
||||||
|
if (m_egl_context)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_egl_context)
|
if (!m_egl_context)
|
||||||
{
|
{
|
||||||
Log_ErrorPrint("eglCreateContext() failed");
|
Log_ErrorPrint("eglCreateContext() failed");
|
||||||
|
@ -233,10 +242,12 @@ bool AndroidGLES2HostDisplay::CreateGLContext()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log_InfoPrintf("GLES Version: %s", glGetString(GL_VERSION));
|
||||||
|
Log_InfoPrintf("GLES Renderer: %s", glGetString(GL_RENDERER));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AndroidGLES2HostDisplay::CreateSurface()
|
bool AndroidGLESHostDisplay::CreateSurface()
|
||||||
{
|
{
|
||||||
EGLint native_visual;
|
EGLint native_visual;
|
||||||
eglGetConfigAttrib(m_egl_display, m_egl_config, EGL_NATIVE_VISUAL_ID, &native_visual);
|
eglGetConfigAttrib(m_egl_display, m_egl_config, EGL_NATIVE_VISUAL_ID, &native_visual);
|
||||||
|
@ -255,13 +266,13 @@ bool AndroidGLES2HostDisplay::CreateSurface()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidGLES2HostDisplay::DestroySurface()
|
void AndroidGLESHostDisplay::DestroySurface()
|
||||||
{
|
{
|
||||||
eglDestroySurface(m_egl_display, m_egl_surface);
|
eglDestroySurface(m_egl_display, m_egl_surface);
|
||||||
m_egl_surface = EGL_NO_SURFACE;
|
m_egl_surface = EGL_NO_SURFACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AndroidGLES2HostDisplay::CreateImGuiContext()
|
bool AndroidGLESHostDisplay::CreateImGuiContext()
|
||||||
{
|
{
|
||||||
if (!ImGui_ImplOpenGL3_Init(GetGLSLVersionString()))
|
if (!ImGui_ImplOpenGL3_Init(GetGLSLVersionString()))
|
||||||
return false;
|
return false;
|
||||||
|
@ -272,7 +283,7 @@ bool AndroidGLES2HostDisplay::CreateImGuiContext()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AndroidGLES2HostDisplay::CreateGLResources()
|
bool AndroidGLESHostDisplay::CreateGLResources()
|
||||||
{
|
{
|
||||||
static constexpr char fullscreen_quad_vertex_shader[] = R"(
|
static constexpr char fullscreen_quad_vertex_shader[] = R"(
|
||||||
attribute vec2 a_pos;
|
attribute vec2 a_pos;
|
||||||
|
@ -321,9 +332,9 @@ void main()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<HostDisplay> AndroidGLES2HostDisplay::Create(ANativeWindow* window)
|
std::unique_ptr<HostDisplay> AndroidGLESHostDisplay::Create(ANativeWindow* window)
|
||||||
{
|
{
|
||||||
std::unique_ptr<AndroidGLES2HostDisplay> display = std::make_unique<AndroidGLES2HostDisplay>(window);
|
std::unique_ptr<AndroidGLESHostDisplay> display = std::make_unique<AndroidGLESHostDisplay>(window);
|
||||||
if (!display->CreateGLContext() || !display->CreateImGuiContext() || !display->CreateGLResources())
|
if (!display->CreateGLContext() || !display->CreateImGuiContext() || !display->CreateGLResources())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
@ -331,7 +342,7 @@ std::unique_ptr<HostDisplay> AndroidGLES2HostDisplay::Create(ANativeWindow* wind
|
||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidGLES2HostDisplay::Render()
|
void AndroidGLESHostDisplay::Render()
|
||||||
{
|
{
|
||||||
glDisable(GL_SCISSOR_TEST);
|
glDisable(GL_SCISSOR_TEST);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
@ -349,7 +360,7 @@ void AndroidGLES2HostDisplay::Render()
|
||||||
GL::Program::ResetLastProgram();
|
GL::Program::ResetLastProgram();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidGLES2HostDisplay::RenderDisplay()
|
void AndroidGLESHostDisplay::RenderDisplay()
|
||||||
{
|
{
|
||||||
if (!m_display_texture_id)
|
if (!m_display_texture_id)
|
||||||
return;
|
return;
|
||||||
|
@ -378,6 +389,7 @@ void AndroidGLES2HostDisplay::RenderDisplay()
|
||||||
{{1.0f, 1.0f, tex_right, tex_top}}, // top-right
|
{{1.0f, 1.0f, tex_right, tex_top}}, // top-right
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(vertices[0]), &vertices[0][0]);
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(vertices[0]), &vertices[0][0]);
|
||||||
glEnableVertexAttribArray(0);
|
glEnableVertexAttribArray(0);
|
||||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertices[0]), &vertices[0][2]);
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertices[0]), &vertices[0][2]);
|
|
@ -8,11 +8,11 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class AndroidGLES2HostDisplay final : public HostDisplay
|
class AndroidGLESHostDisplay final : public HostDisplay
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AndroidGLES2HostDisplay(ANativeWindow* window);
|
AndroidGLESHostDisplay(ANativeWindow* window);
|
||||||
~AndroidGLES2HostDisplay();
|
~AndroidGLESHostDisplay();
|
||||||
|
|
||||||
static std::unique_ptr<HostDisplay> Create(ANativeWindow* window);
|
static std::unique_ptr<HostDisplay> Create(ANativeWindow* window);
|
||||||
|
|
|
@ -3,11 +3,12 @@
|
||||||
#include "YBaseLib/Log.h"
|
#include "YBaseLib/Log.h"
|
||||||
#include "YBaseLib/String.h"
|
#include "YBaseLib/String.h"
|
||||||
#include "android_audio_stream.h"
|
#include "android_audio_stream.h"
|
||||||
#include "android_gles2_host_display.h"
|
#include "android_gles_host_display.h"
|
||||||
#include "core/gpu.h"
|
#include "core/gpu.h"
|
||||||
#include "core/host_display.h"
|
#include "core/host_display.h"
|
||||||
#include "core/system.h"
|
#include "core/system.h"
|
||||||
#include <android/native_window_jni.h>
|
#include <android/native_window_jni.h>
|
||||||
|
#include <cmath>
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
Log_SetChannel(AndroidHostInterface);
|
Log_SetChannel(AndroidHostInterface);
|
||||||
|
|
||||||
|
@ -52,10 +53,12 @@ AndroidHostInterface::AndroidHostInterface(jobject java_object) : m_java_object(
|
||||||
m_settings.SetDefaults();
|
m_settings.SetDefaults();
|
||||||
m_settings.bios_path = "/sdcard/PSX/BIOS/scph1001.bin";
|
m_settings.bios_path = "/sdcard/PSX/BIOS/scph1001.bin";
|
||||||
m_settings.memory_card_a_path = "/sdcard/PSX/memory_card_a.mcd";
|
m_settings.memory_card_a_path = "/sdcard/PSX/memory_card_a.mcd";
|
||||||
m_settings.gpu_renderer = GPURenderer::Software;
|
m_settings.cpu_execution_mode = CPUExecutionMode::CachedInterpreter;
|
||||||
m_settings.video_sync_enabled = true;
|
//m_settings.gpu_renderer = GPURenderer::Software;
|
||||||
|
m_settings.speed_limiter_enabled = false;
|
||||||
|
m_settings.video_sync_enabled = false;
|
||||||
m_settings.audio_sync_enabled = false;
|
m_settings.audio_sync_enabled = false;
|
||||||
// m_settings.debugging.show_vram = true;
|
//m_settings.debugging.show_vram = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AndroidHostInterface::~AndroidHostInterface()
|
AndroidHostInterface::~AndroidHostInterface()
|
||||||
|
@ -136,7 +139,7 @@ void AndroidHostInterface::EmulationThreadEntryPoint(ANativeWindow* initial_surf
|
||||||
CreateImGuiContext();
|
CreateImGuiContext();
|
||||||
|
|
||||||
// Create display.
|
// Create display.
|
||||||
m_display = AndroidGLES2HostDisplay::Create(initial_surface);
|
m_display = AndroidGLESHostDisplay::Create(initial_surface);
|
||||||
if (!m_display)
|
if (!m_display)
|
||||||
{
|
{
|
||||||
Log_ErrorPrint("Failed to create display on emulation thread.");
|
Log_ErrorPrint("Failed to create display on emulation thread.");
|
||||||
|
@ -219,6 +222,8 @@ void AndroidHostInterface::EmulationThreadEntryPoint(ANativeWindow* initial_surf
|
||||||
if (m_speed_limiter_enabled)
|
if (m_speed_limiter_enabled)
|
||||||
Throttle();
|
Throttle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdatePerformanceCounters();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,61 +248,69 @@ void AndroidHostInterface::DestroyImGuiContext()
|
||||||
|
|
||||||
void AndroidHostInterface::DrawImGui()
|
void AndroidHostInterface::DrawImGui()
|
||||||
{
|
{
|
||||||
|
DrawFPSWindow();
|
||||||
DrawOSDMessages();
|
DrawOSDMessages();
|
||||||
|
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidHostInterface::AddOSDMessage(const char* message, float duration)
|
void AndroidHostInterface::DrawFPSWindow()
|
||||||
{
|
{
|
||||||
OSDMessage msg;
|
const bool show_fps = true;
|
||||||
msg.text = message;
|
const bool show_vps = true;
|
||||||
msg.duration = duration;
|
const bool show_speed = true;
|
||||||
|
|
||||||
std::unique_lock<std::mutex> lock(m_osd_messages_lock);
|
ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x - 175.0f, 0.0f), ImGuiCond_Always);
|
||||||
m_osd_messages.push_back(std::move(msg));
|
ImGui::SetNextWindowSize(ImVec2(175.0f, 16.0f));
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidHostInterface::DrawOSDMessages()
|
if (!ImGui::Begin("FPSWindow", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse |
|
||||||
{
|
ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoResize |
|
||||||
constexpr ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs |
|
ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoBringToFrontOnFocus))
|
||||||
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings |
|
|
||||||
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav |
|
|
||||||
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing;
|
|
||||||
|
|
||||||
std::unique_lock<std::mutex> lock(m_osd_messages_lock);
|
|
||||||
const float scale = ImGui::GetIO().DisplayFramebufferScale.x;
|
|
||||||
|
|
||||||
auto iter = m_osd_messages.begin();
|
|
||||||
float position_x = 10.0f * scale;
|
|
||||||
float position_y = (10.0f + (m_settings.display_fullscreen ? 0.0f : 20.0f)) * scale;
|
|
||||||
u32 index = 0;
|
|
||||||
while (iter != m_osd_messages.end())
|
|
||||||
{
|
{
|
||||||
const OSDMessage& msg = *iter;
|
|
||||||
const double time = msg.time.GetTimeSeconds();
|
|
||||||
const float time_remaining = static_cast<float>(msg.duration - time);
|
|
||||||
if (time_remaining <= 0.0f)
|
|
||||||
{
|
|
||||||
iter = m_osd_messages.erase(iter);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float opacity = std::min(time_remaining, 1.0f);
|
|
||||||
ImGui::SetNextWindowPos(ImVec2(position_x, position_y));
|
|
||||||
ImGui::SetNextWindowSize(ImVec2(0.0f, 0.0f));
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, opacity);
|
|
||||||
|
|
||||||
if (ImGui::Begin(SmallString::FromFormat("osd_%u", index++), nullptr, window_flags))
|
|
||||||
{
|
|
||||||
ImGui::TextUnformatted(msg.text.c_str());
|
|
||||||
position_y += ImGui::GetWindowSize().y + (4.0f * scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
ImGui::PopStyleVar();
|
return;
|
||||||
++iter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool first = true;
|
||||||
|
if (show_fps)
|
||||||
|
{
|
||||||
|
ImGui::Text("%.2f", m_fps);
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
if (show_vps)
|
||||||
|
{
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text("/");
|
||||||
|
ImGui::SameLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Text("%.2f", m_vps);
|
||||||
|
}
|
||||||
|
if (show_speed)
|
||||||
|
{
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text("/");
|
||||||
|
ImGui::SameLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
const u32 rounded_speed = static_cast<u32>(std::round(m_speed));
|
||||||
|
if (m_speed < 90.0f)
|
||||||
|
ImGui::TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), "%u%%", rounded_speed);
|
||||||
|
else if (m_speed < 110.0f)
|
||||||
|
ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 1.0f), "%u%%", rounded_speed);
|
||||||
|
else
|
||||||
|
ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), "%u%%", rounded_speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidHostInterface::SurfaceChanged(ANativeWindow* window, int format, int width, int height)
|
void AndroidHostInterface::SurfaceChanged(ANativeWindow* window, int format, int width, int height)
|
||||||
|
|
|
@ -3,10 +3,8 @@
|
||||||
#include "YBaseLib/Timer.h"
|
#include "YBaseLib/Timer.h"
|
||||||
#include "core/host_interface.h"
|
#include "core/host_interface.h"
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <deque>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <mutex>
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
struct ANativeWindow;
|
struct ANativeWindow;
|
||||||
|
@ -19,7 +17,6 @@ public:
|
||||||
|
|
||||||
void ReportError(const char* message) override;
|
void ReportError(const char* message) override;
|
||||||
void ReportMessage(const char* message) override;
|
void ReportMessage(const char* message) override;
|
||||||
void AddOSDMessage(const char* message, float duration = 2.0f) override;
|
|
||||||
|
|
||||||
bool IsEmulationThreadRunning() const { return m_emulation_thread.joinable(); }
|
bool IsEmulationThreadRunning() const { return m_emulation_thread.joinable(); }
|
||||||
bool StartEmulationThread(ANativeWindow* initial_surface, std::string initial_filename,
|
bool StartEmulationThread(ANativeWindow* initial_surface, std::string initial_filename,
|
||||||
|
@ -30,26 +27,17 @@ public:
|
||||||
void SurfaceChanged(ANativeWindow* window, int format, int width, int height);
|
void SurfaceChanged(ANativeWindow* window, int format, int width, int height);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct OSDMessage
|
|
||||||
{
|
|
||||||
std::string text;
|
|
||||||
Timer time;
|
|
||||||
float duration;
|
|
||||||
};
|
|
||||||
|
|
||||||
void EmulationThreadEntryPoint(ANativeWindow* initial_surface, std::string initial_filename,
|
void EmulationThreadEntryPoint(ANativeWindow* initial_surface, std::string initial_filename,
|
||||||
std::string initial_state_filename);
|
std::string initial_state_filename);
|
||||||
|
|
||||||
void CreateImGuiContext();
|
void CreateImGuiContext();
|
||||||
void DestroyImGuiContext();
|
void DestroyImGuiContext();
|
||||||
void DrawImGui();
|
void DrawImGui();
|
||||||
void DrawOSDMessages();
|
|
||||||
|
void DrawFPSWindow();
|
||||||
|
|
||||||
jobject m_java_object = {};
|
jobject m_java_object = {};
|
||||||
|
|
||||||
std::deque<OSDMessage> m_osd_messages;
|
|
||||||
std::mutex m_osd_messages_lock;
|
|
||||||
|
|
||||||
std::mutex m_callback_mutex;
|
std::mutex m_callback_mutex;
|
||||||
std::deque<std::function<void()>> m_callback_queue;
|
std::deque<std::function<void()>> m_callback_queue;
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#if defined(Y_CPU_X64)
|
#if defined(Y_CPU_X64)
|
||||||
#if defined(Y_PLATFORM_WINDOWS)
|
#if defined(Y_PLATFORM_WINDOWS)
|
||||||
#define ABI_WIN64 1
|
#define ABI_WIN64 1
|
||||||
#elif defined(Y_PLATFORM_LINUX) || defined(Y_PLATFORM_OSX)
|
#elif defined(Y_PLATFORM_LINUX) || defined(Y_PLATFORM_OSX) || defined(Y_PLATFORM_ANDROID)
|
||||||
#define ABI_SYSV 1
|
#define ABI_SYSV 1
|
||||||
#else
|
#else
|
||||||
#error Unknown ABI.
|
#error Unknown ABI.
|
||||||
|
|
|
@ -22,38 +22,43 @@ static void DefineMacro(std::stringstream& ss, const char* name, bool enabled)
|
||||||
ss << "#define " << name << " " << BoolToUInt32(enabled) << "\n";
|
ss << "#define " << name << " " << BoolToUInt32(enabled) << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU_HW_ShaderGen::SetGLSLVersionString()
|
void GPU_HW_ShaderGen::SetGLSLVersionString() {
|
||||||
{
|
const char *glsl_version = reinterpret_cast<const char *>(glGetString(
|
||||||
const char* glsl_version = reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION));
|
GL_SHADING_LANGUAGE_VERSION));
|
||||||
Assert(glsl_version != nullptr);
|
Assert(glsl_version != nullptr);
|
||||||
|
|
||||||
|
// Skip any strings in front of the version code.
|
||||||
|
const char *glsl_version_start = glsl_version;
|
||||||
|
while (*glsl_version_start != '\0' && (*glsl_version_start < '0' || *glsl_version_start > '9'))
|
||||||
|
glsl_version_start++;
|
||||||
|
|
||||||
int major_version = 0, minor_version = 0;
|
int major_version = 0, minor_version = 0;
|
||||||
if (std::sscanf(glsl_version, "%d.%d", &major_version, &minor_version) != 2)
|
if (std::sscanf(glsl_version_start, "%d.%d", &major_version, &minor_version) == 2)
|
||||||
{
|
{
|
||||||
Log_ErrorPrintf("Invalid GLSL version string: '%s'", glsl_version);
|
// Cap at GLSL 3.3, we're not using anything newer for now.
|
||||||
|
if (!m_glsl_es && major_version >= 4) {
|
||||||
|
major_version = 3;
|
||||||
|
minor_version = 30;
|
||||||
|
} else if (m_glsl_es && (major_version > 3 || minor_version > 20)) {
|
||||||
|
major_version = 3;
|
||||||
|
minor_version = 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Invalid GLSL version string: '%s' ('%s')", glsl_version, glsl_version_start);
|
||||||
|
if (m_glsl_es) {
|
||||||
|
major_version = 3;
|
||||||
|
minor_version = 0;
|
||||||
|
}
|
||||||
m_glsl_version_string = m_glsl_es ? "300" : "130";
|
m_glsl_version_string = m_glsl_es ? "300" : "130";
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cap at GLSL 3.3, we're not using anything newer for now.
|
|
||||||
if (!m_glsl_es && major_version >= 4)
|
|
||||||
{
|
|
||||||
major_version = 3;
|
|
||||||
minor_version = 30;
|
|
||||||
}
|
|
||||||
else if (m_glsl_es && (major_version > 3 || minor_version > 20))
|
|
||||||
{
|
|
||||||
major_version = 3;
|
|
||||||
minor_version = 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_glsl_version_string = "#version ";
|
char buf[128];
|
||||||
m_glsl_version_string += std::to_string(major_version);
|
std::snprintf(buf, sizeof(buf), "#version %d%02d %s", major_version, minor_version,
|
||||||
m_glsl_version_string += std::to_string(minor_version);
|
(!m_glsl_es && major_version >= 3 && minor_version >= 3) ? "core" : (m_glsl_es ? "es" : ""));
|
||||||
if (!m_glsl_es && major_version >= 3 && minor_version >= 3)
|
m_glsl_version_string = buf;
|
||||||
m_glsl_version_string += " core";
|
|
||||||
else if (m_glsl_es)
|
|
||||||
m_glsl_version_string += " es";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU_HW_ShaderGen::WriteHeader(std::stringstream& ss)
|
void GPU_HW_ShaderGen::WriteHeader(std::stringstream& ss)
|
||||||
|
@ -61,14 +66,12 @@ void GPU_HW_ShaderGen::WriteHeader(std::stringstream& ss)
|
||||||
if (m_render_api == HostDisplay::RenderAPI::OpenGL || m_render_api == HostDisplay::RenderAPI::OpenGLES)
|
if (m_render_api == HostDisplay::RenderAPI::OpenGL || m_render_api == HostDisplay::RenderAPI::OpenGLES)
|
||||||
ss << m_glsl_version_string << "\n\n";
|
ss << m_glsl_version_string << "\n\n";
|
||||||
|
|
||||||
if (m_render_api == HostDisplay::RenderAPI::OpenGL)
|
DefineMacro(ss, "API_OPENGL", m_render_api == HostDisplay::RenderAPI::OpenGL);
|
||||||
{
|
DefineMacro(ss, "API_OPENGL_ES", m_render_api == HostDisplay::RenderAPI::OpenGLES);
|
||||||
ss << "#define API_OPENGL 1\n";
|
DefineMacro(ss, "API_D3D11", m_render_api == HostDisplay::RenderAPI::D3D11);
|
||||||
}
|
|
||||||
else if (m_render_api == HostDisplay::RenderAPI::OpenGLES)
|
|
||||||
{
|
|
||||||
ss << "#define API_OPENGL_ES 1\n";
|
|
||||||
|
|
||||||
|
if (m_render_api == HostDisplay::RenderAPI::OpenGLES)
|
||||||
|
{
|
||||||
ss << "precision highp float;\n";
|
ss << "precision highp float;\n";
|
||||||
ss << "precision highp int;\n";
|
ss << "precision highp int;\n";
|
||||||
ss << "precision highp sampler2D;\n";
|
ss << "precision highp sampler2D;\n";
|
||||||
|
@ -78,10 +81,6 @@ void GPU_HW_ShaderGen::WriteHeader(std::stringstream& ss)
|
||||||
|
|
||||||
ss << "\n";
|
ss << "\n";
|
||||||
}
|
}
|
||||||
else if (m_render_api == HostDisplay::RenderAPI::D3D11)
|
|
||||||
{
|
|
||||||
ss << "#define API_D3D11 1\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_glsl)
|
if (m_glsl)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue