diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj
index 6f0ab6e6e2..d93b8d8667 100644
--- a/Common/Common.vcxproj
+++ b/Common/Common.vcxproj
@@ -72,7 +72,7 @@
USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_32=1;_M_IX86=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions)
stdafx.h
MultiThreadedDebug
- ../ext/native
+ ../ext/native;..
StreamingSIMDExtensions2
Fast
true
@@ -99,7 +99,7 @@
stdafx.h
MultiThreadedDebug
USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_64=1;_M_X64=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions)
- ../ext/native
+ ../ext/native;..
NotSet
Fast
false
@@ -132,7 +132,7 @@
false
StreamingSIMDExtensions2
Fast
- ../ext/native
+ ../ext/native;..
Speed
true
false
@@ -161,7 +161,7 @@
true
USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_64=1;_M_X64=1;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions)
stdafx.h
- ../ext/native
+ ../ext/native;..
false
NotSet
Fast
@@ -209,6 +209,19 @@
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
@@ -258,6 +271,24 @@
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters
index 2bce532528..5b2bb42345 100644
--- a/Common/Common.vcxproj.filters
+++ b/Common/Common.vcxproj.filters
@@ -48,6 +48,15 @@
+
+ GL\GLInterface
+
+
+ GL\GLInterface
+
+
+ GL
+
@@ -84,6 +93,15 @@
+
+ GL\GLInterface
+
+
+ GL\GLInterface
+
+
+ GL\GLInterface
+
@@ -92,5 +110,11 @@
{1b593f03-7b28-4707-9228-4981796f5589}
+
+ {2f2ca112-9e26-499e-9cb9-38a78b4ac09d}
+
+
+ {2c723cf4-75b6-406a-90c0-ebb7a13ba476}
+
\ No newline at end of file
diff --git a/Common/GL/GLInterface/EGL.cpp b/Common/GL/GLInterface/EGL.cpp
new file mode 100644
index 0000000000..dee999b160
--- /dev/null
+++ b/Common/GL/GLInterface/EGL.cpp
@@ -0,0 +1,324 @@
+// Copyright 2012 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include
+#include
+
+#include "Common/GL/GLInterface/EGL.h"
+#include "Common/Log.h"
+
+// Show the current FPS
+void cInterfaceEGL::Swap()
+{
+ eglSwapBuffers(egl_dpy, egl_surf);
+}
+void cInterfaceEGL::SwapInterval(int Interval)
+{
+ eglSwapInterval(egl_dpy, Interval);
+}
+
+void* cInterfaceEGL::GetFuncAddress(const std::string& name)
+{
+ return (void*)eglGetProcAddress(name.c_str());
+}
+
+void cInterfaceEGL::DetectMode()
+{
+ EGLint num_configs;
+ bool supportsGL = false, supportsGLES2 = false, supportsGLES3 = false;
+ std::array renderable_types = {
+ EGL_OPENGL_BIT,
+ (1 << 6), /* EGL_OPENGL_ES3_BIT_KHR */
+ EGL_OPENGL_ES2_BIT,
+ };
+
+ for (auto renderable_type : renderable_types)
+ {
+ // attributes for a visual in RGBA format with at least
+ // 8 bits per color
+ int attribs[] = {
+ EGL_RENDERABLE_TYPE, renderable_type,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_DEPTH_SIZE, 16,
+ EGL_STENCIL_SIZE, 8,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_TRANSPARENT_TYPE, EGL_NONE,
+ EGL_SAMPLES, 0,
+ EGL_NONE
+ };
+
+ // Get how many configs there are
+ if (!eglChooseConfig( egl_dpy, attribs, nullptr, 0, &num_configs))
+ {
+ INFO_LOG(G3D, "Error: couldn't get an EGL visual config\n");
+ continue;
+ }
+
+ EGLConfig* config = new EGLConfig[num_configs];
+
+ // Get all the configurations
+ if (!eglChooseConfig(egl_dpy, attribs, config, num_configs, &num_configs))
+ {
+ INFO_LOG(G3D, "Error: couldn't get an EGL visual config\n");
+ delete[] config;
+ continue;
+ }
+
+ for (int i = 0; i < num_configs; ++i)
+ {
+ EGLint attribVal;
+ bool ret;
+ ret = eglGetConfigAttrib(egl_dpy, config[i], EGL_RENDERABLE_TYPE, &attribVal);
+ if (ret)
+ {
+ if ((attribVal & EGL_OPENGL_BIT) && s_opengl_mode != GLInterfaceMode::MODE_DETECT_ES)
+ supportsGL = true;
+ if (attribVal & (1 << 6)) /* EGL_OPENGL_ES3_BIT_KHR */
+ supportsGLES3 = true;
+ if (attribVal & EGL_OPENGL_ES2_BIT)
+ supportsGLES2 = true;
+ }
+ }
+ delete[] config;
+ }
+
+ if (supportsGL)
+ s_opengl_mode = GLInterfaceMode::MODE_OPENGL;
+ else if (supportsGLES3)
+ s_opengl_mode = GLInterfaceMode::MODE_OPENGLES3;
+ else if (supportsGLES2)
+ s_opengl_mode = GLInterfaceMode::MODE_OPENGLES2;
+
+ if (s_opengl_mode == GLInterfaceMode::MODE_DETECT) // Errored before we found a mode
+ s_opengl_mode = GLInterfaceMode::MODE_OPENGL; // Fall back to OpenGL
+}
+
+static void LogEGLConfig(EGLDisplay egl_dpy, EGLConfig config) {
+ EGLint red = 0, green = 0, blue = 0, alpha = 0, depth = 0, stencil = 0, format = -1, type;
+
+ struct {
+ EGLint value;
+ const char *name;
+ } vals[] = {
+ { EGL_RED_SIZE, "EGL_RED_SIZE" },
+ { EGL_GREEN_SIZE, "EGL_GREEN_SIZE" },
+ { EGL_BLUE_SIZE, "EGL_BLUE_SIZE" },
+ { EGL_ALPHA_SIZE, "EGL_ALPHA_SIZE" },
+ { EGL_DEPTH_SIZE, "EGL_DEPTH_SIZE" },
+ { EGL_STENCIL_SIZE, "EGL_STENCIL_SIZE" },
+ { EGL_NATIVE_VISUAL_ID, "EGL_NATIVE_VISUAL_ID" },
+ { EGL_NATIVE_VISUAL_TYPE, "EGL_NATIVE_VISUAL_TYPE" },
+ { EGL_MAX_SWAP_INTERVAL, "EGL_MAX_SWAP_INTERVAL" },
+ { EGL_MIN_SWAP_INTERVAL, "EGL_MIN_SWAP_INTERVAL" },
+ { EGL_MIN_SWAP_INTERVAL, "EGL_MIN_SWAP_INTERVAL" },
+ { EGL_NATIVE_RENDERABLE, "EGL_NATIVE_RENDERABLE" },
+ { EGL_COLOR_BUFFER_TYPE, "EGL_COLOR_BUFFER_TYPE" },
+ { EGL_BUFFER_SIZE, "EGL_BUFFER_SIZE" },
+ { EGL_CONFIG_ID, "EGL_CONFIG_ID" },
+ { EGL_SAMPLES, "EGL_SAMPLES" },
+ };
+
+ for (int i = 0; i < (int)(sizeof(vals)/sizeof(vals[0])); i++) {
+ EGLint value;
+ eglGetConfigAttrib(egl_dpy, config, vals[i].value, &value);
+ INFO_LOG(G3D, " %s = %d", vals[i].name, value);
+ }
+}
+
+const char *cInterfaceEGL::EGLGetErrorString(EGLint error) {
+ switch (error) {
+ case EGL_SUCCESS: return "EGL_SUCCESS";
+ case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
+ case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
+ case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
+ case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
+ case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
+ case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
+ case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
+ case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
+ case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
+ case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
+ case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
+ case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
+ case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
+ case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
+ default:
+ return "(UNKNOWN)";
+ }
+}
+
+// Create rendering window.
+bool cInterfaceEGL::Create(void *window_handle, bool core, bool use16bit)
+{
+ const char *s;
+ EGLint egl_major, egl_minor;
+
+ egl_dpy = OpenDisplay();
+
+ if (!egl_dpy)
+ {
+ INFO_LOG(G3D, "Error: eglGetDisplay() failed\n");
+ return false;
+ }
+
+ if (!eglInitialize(egl_dpy, &egl_major, &egl_minor))
+ {
+ INFO_LOG(G3D, "Error: eglInitialize() failed\n");
+ return false;
+ }
+ INFO_LOG(G3D, "eglInitialize() succeeded\n");
+
+ if (s_opengl_mode == MODE_DETECT || s_opengl_mode == MODE_DETECT_ES)
+ DetectMode();
+
+ int attribs32[] = {
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, // Keep this first!
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_DEPTH_SIZE, 16,
+ EGL_STENCIL_SIZE, 8,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_TRANSPARENT_TYPE, EGL_NONE,
+ EGL_SAMPLES, 0,
+ EGL_NONE, 0
+ };
+ int attribs16[] = {
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, // Keep this first!
+ EGL_RED_SIZE, 5,
+ EGL_GREEN_SIZE, 6,
+ EGL_BLUE_SIZE, 5,
+ EGL_ALPHA_SIZE, 0,
+ EGL_DEPTH_SIZE, 16,
+ EGL_STENCIL_SIZE, 8,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_TRANSPARENT_TYPE, EGL_NONE,
+ EGL_SAMPLES, 0,
+ EGL_NONE, 0
+ };
+ int *attribs = attribs32;
+ if (use16bit) {
+ attribs = attribs16;
+ }
+
+ EGLint ctx_attribs[] = {
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE, 0
+ };
+
+ switch (s_opengl_mode) {
+ case MODE_OPENGL:
+ attribs[1] = EGL_OPENGL_BIT;
+ ctx_attribs[0] = EGL_NONE;
+ break;
+ case MODE_OPENGLES2:
+ attribs[1] = EGL_OPENGL_ES2_BIT;
+ ctx_attribs[1] = 2;
+ break;
+ case MODE_OPENGLES3:
+ attribs[1] = (1 << 6); /* EGL_OPENGL_ES3_BIT_KHR */
+ ctx_attribs[1] = 3;
+ break;
+ default:
+ ERROR_LOG(G3D, "Unknown OpenGL mode set\n");
+ return false;
+ break;
+ }
+
+ EGLConfig *configs;
+ EGLint num_configs;
+ if (!eglChooseConfig(egl_dpy, attribs, NULL, 0, &num_configs) || num_configs == 0) {
+ INFO_LOG(G3D, "Error: couldn't get a number of configs\n");
+ eglTerminate(egl_dpy);
+ return false;
+ }
+
+ configs = new EGLConfig[num_configs];
+
+ if (!eglChooseConfig(egl_dpy, attribs, configs, num_configs, &num_configs)) {
+ INFO_LOG(G3D, "Error: couldn't get an EGL visual config\n");
+ eglTerminate(egl_dpy);
+ return false;
+ }
+
+ INFO_LOG(G3D, "eglChooseConfig successful: num_configs=%d, choosing config 0", num_configs);
+ for (int i = 0; i < num_configs; i++) {
+ INFO_LOG(G3D, "Config %d:", i);
+ LogEGLConfig(egl_dpy, configs[i]);
+ }
+
+ if (s_opengl_mode == MODE_OPENGL)
+ eglBindAPI(EGL_OPENGL_API);
+ else
+ eglBindAPI(EGL_OPENGL_ES_API);
+
+ EGLNativeWindowType host_window = (EGLNativeWindowType) window_handle;
+ EGLNativeWindowType native_window = InitializePlatform(host_window, configs[0]);
+
+ s = eglQueryString(egl_dpy, EGL_VERSION);
+ INFO_LOG(G3D, "EGL_VERSION = %s\n", s);
+
+ s = eglQueryString(egl_dpy, EGL_VENDOR);
+ INFO_LOG(G3D, "EGL_VENDOR = %s\n", s);
+
+ s = eglQueryString(egl_dpy, EGL_EXTENSIONS);
+ INFO_LOG(G3D, "EGL_EXTENSIONS = %s\n", s);
+
+ s = eglQueryString(egl_dpy, EGL_CLIENT_APIS);
+ INFO_LOG(G3D, "EGL_CLIENT_APIS = %s\n", s);
+
+ egl_ctx = eglCreateContext(egl_dpy, configs[0], EGL_NO_CONTEXT, ctx_attribs);
+ if (!egl_ctx) {
+ INFO_LOG(G3D, "Error: eglCreateContext failed: %s\n", EGLGetErrorString(eglGetError()));
+ eglTerminate(egl_dpy);
+ delete[] configs;
+ return false;
+ }
+
+ egl_surf = eglCreateWindowSurface(egl_dpy, configs[0], native_window, nullptr);
+ if (!egl_surf) {
+ INFO_LOG(G3D, "Error: eglCreateWindowSurface failed: native_window=%p error=%s ctx_attribs[1]==%d\n", native_window, EGLGetErrorString(eglGetError()), ctx_attribs[1]);
+
+ eglDestroyContext(egl_dpy, egl_ctx);
+ eglTerminate(egl_dpy);
+ delete[] configs;
+ return false;
+ }
+
+ delete[] configs;
+ return true;
+}
+
+bool cInterfaceEGL::MakeCurrent()
+{
+ return eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx);
+}
+
+bool cInterfaceEGL::ClearCurrent()
+{
+ return eglMakeCurrent(egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+}
+
+void cInterfaceEGL::Shutdown()
+{
+ ShutdownPlatform();
+ if (egl_ctx && !eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx))
+ NOTICE_LOG(G3D, "Could not release drawing context.");
+ if (egl_ctx)
+ {
+ eglMakeCurrent(egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ if (!eglDestroyContext(egl_dpy, egl_ctx))
+ NOTICE_LOG(G3D, "Could not destroy drawing context.");
+ if (!eglDestroySurface(egl_dpy, egl_surf))
+ NOTICE_LOG(G3D, "Could not destroy window surface.");
+ if (!eglTerminate(egl_dpy))
+ NOTICE_LOG(G3D, "Could not destroy display connection.");
+ egl_ctx = nullptr;
+ egl_dpy = nullptr;
+ }
+}
diff --git a/Common/GL/GLInterface/EGL.h b/Common/GL/GLInterface/EGL.h
new file mode 100644
index 0000000000..cf8ed1db61
--- /dev/null
+++ b/Common/GL/GLInterface/EGL.h
@@ -0,0 +1,35 @@
+// Copyright 2008 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include
+#include
+
+#include "Common/GL/GLInterfaceBase.h"
+
+class cInterfaceEGL : public cInterfaceBase
+{
+protected:
+ void DetectMode();
+ EGLSurface egl_surf;
+ EGLContext egl_ctx;
+ EGLDisplay egl_dpy;
+
+ virtual EGLDisplay OpenDisplay() = 0;
+ virtual EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window, EGLConfig config) = 0;
+ virtual void ShutdownPlatform() = 0;
+ virtual void SetInternalResolution(int internalWidth, int internalHeight) {}
+ const char *EGLGetErrorString(EGLint error);
+
+public:
+ void SwapInterval(int Interval);
+ void Swap();
+ void SetMode(u32 mode) { s_opengl_mode = mode; }
+ void* GetFuncAddress(const std::string& name);
+ bool Create(void *window_handle, bool core, bool use16bit) override;
+ bool MakeCurrent();
+ bool ClearCurrent();
+ void Shutdown();
+};
diff --git a/Common/GL/GLInterface/EGLAndroid.cpp b/Common/GL/GLInterface/EGLAndroid.cpp
new file mode 100644
index 0000000000..0d4a0e2339
--- /dev/null
+++ b/Common/GL/GLInterface/EGLAndroid.cpp
@@ -0,0 +1,29 @@
+// Copyright 2014 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "Common/Log.h"
+#include "Common/GL/GLInterface/EGLAndroid.h"
+
+EGLDisplay cInterfaceEGLAndroid::OpenDisplay() {
+ return eglGetDisplay(EGL_DEFAULT_DISPLAY);
+}
+
+EGLNativeWindowType cInterfaceEGLAndroid::InitializePlatform(EGLNativeWindowType host_window, EGLConfig config) {
+ EGLint format;
+ if (EGL_FALSE == eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &format)) {
+ ERROR_LOG(G3D, "Failed getting EGL_NATIVE_VISUAL_ID: error %s", EGLGetErrorString(eglGetError()));
+ return NULL;
+ }
+
+ ANativeWindow_setBuffersGeometry(host_window, internalWidth_, internalHeight_, format);
+
+ const int width = ANativeWindow_getWidth(host_window);
+ const int height = ANativeWindow_getHeight(host_window);
+ SetBackBufferDimensions(width, height);
+
+ return host_window;
+}
+
+void cInterfaceEGLAndroid::ShutdownPlatform() {
+}
diff --git a/Common/GL/GLInterface/EGLAndroid.h b/Common/GL/GLInterface/EGLAndroid.h
new file mode 100644
index 0000000000..811485d91b
--- /dev/null
+++ b/Common/GL/GLInterface/EGLAndroid.h
@@ -0,0 +1,24 @@
+// Copyright 2014 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "Common/GL/GLInterface/EGL.h"
+
+class cInterfaceEGLAndroid : public cInterfaceEGL {
+public:
+ cInterfaceEGLAndroid() : internalWidth_(0), internalHeight_(0) {}
+protected:
+ EGLDisplay OpenDisplay() override;
+ EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window, EGLConfig config) override;
+ void ShutdownPlatform() override;
+ void OverrideBackbufferDimensions(int internalWidth, int internalHeight) override {
+ internalWidth_ = internalWidth;
+ internalHeight_ = internalHeight;
+ }
+
+private:
+ int internalWidth_;
+ int internalHeight_;
+};
diff --git a/Common/GL/GLInterface/GLInterface.cpp b/Common/GL/GLInterface/GLInterface.cpp
new file mode 100644
index 0000000000..bf8d729745
--- /dev/null
+++ b/Common/GL/GLInterface/GLInterface.cpp
@@ -0,0 +1,39 @@
+// Copyright 2014 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "Common/GL/GLInterfaceBase.h"
+
+#ifdef ANDROID
+#include "Common/GL/GLInterface/EGLAndroid.h"
+#elif defined(__APPLE__)
+#include "Common/GL/GLInterface/AGL.h"
+#elif defined(_WIN32)
+#include "Common/GL/GLInterface/WGL.h"
+#elif HAVE_X11
+#if defined(USE_EGL) && USE_EGL
+#include "Common/GL/GLInterface/EGLX11.h"
+#else
+#include "Common/GL/GLInterface/GLX.h"
+#endif
+#else
+#error Platform doesnt have a GLInterface
+#endif
+
+cInterfaceBase* HostGL_CreateGLInterface(){
+ #ifdef ANDROID
+ return new cInterfaceEGLAndroid;
+ #elif defined(__APPLE__)
+ return new cInterfaceAGL;
+ #elif defined(_WIN32)
+ return new cInterfaceWGL;
+ #elif defined(HAVE_X11) && HAVE_X11
+ #if defined(USE_EGL) && USE_EGL
+ return new cInterfaceEGLX11;
+ #else
+ return new cInterfaceGLX;
+ #endif
+ #else
+ return nullptr;
+ #endif
+}
diff --git a/Common/GL/GLInterfaceBase.h b/Common/GL/GLInterfaceBase.h
new file mode 100644
index 0000000000..250f0f35e9
--- /dev/null
+++ b/Common/GL/GLInterfaceBase.h
@@ -0,0 +1,50 @@
+// Copyright 2008 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include
+
+#include "Common/CommonTypes.h"
+
+enum GLInterfaceMode {
+ MODE_DETECT = 0,
+ MODE_DETECT_ES,
+ MODE_OPENGL,
+ MODE_OPENGLES2,
+ MODE_OPENGLES3,
+};
+
+class cInterfaceBase {
+protected:
+ // Window dimensions.
+ u32 s_backbuffer_width;
+ u32 s_backbuffer_height;
+
+ u32 s_opengl_mode;
+public:
+ cInterfaceBase() : s_backbuffer_width(0), s_backbuffer_height(0), s_opengl_mode(MODE_DETECT) {}
+ virtual ~cInterfaceBase() {}
+ virtual void Swap() {}
+ virtual void SetMode(u32 mode) { s_opengl_mode = GLInterfaceMode::MODE_OPENGL; }
+ virtual u32 GetMode() { return s_opengl_mode; }
+ virtual void* GetFuncAddress(const std::string& name) { return nullptr; }
+ virtual bool Create(void *window_handle, bool core = true, bool use16bit = false) = 0;
+ virtual bool MakeCurrent() { return true; }
+ virtual bool ClearCurrent() { return true; }
+ virtual void Shutdown() {}
+
+ virtual void SwapInterval(int Interval) { }
+ virtual u32 GetBackBufferWidth() { return s_backbuffer_width; }
+ virtual u32 GetBackBufferHeight() { return s_backbuffer_height; }
+
+ virtual void OverrideBackbufferDimensions(int w, int h) = 0;
+
+ virtual void SetBackBufferDimensions(u32 W, u32 H) {s_backbuffer_width = W; s_backbuffer_height = H; }
+ virtual void Update() { }
+ virtual bool PeekMessages() { return false; }
+};
+
+
+cInterfaceBase* HostGL_CreateGLInterface();
diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp
index 90d2534dae..56c135d6fb 100644
--- a/UI/GameSettingsScreen.cpp
+++ b/UI/GameSettingsScreen.cpp
@@ -637,6 +637,7 @@ UI::EventReturn GameSettingsScreen::OnHardwareTransform(UI::EventParams &e) {
}
UI::EventReturn GameSettingsScreen::OnScreenRotation(UI::EventParams &e) {
+ ILOG("New display rotation: %d", g_Config.iScreenRotation);
System_SendMessage("rotate", "");
return UI::EVENT_DONE;
}
diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp
index bacead8251..ecc639e3b6 100644
--- a/UI/NativeApp.cpp
+++ b/UI/NativeApp.cpp
@@ -210,7 +210,8 @@ void QtHost::ShutdownSound() { }
std::string NativeQueryConfig(std::string query) {
char temp[128];
if (query == "screenRotation") {
- sprintf(temp, "%i", g_Config.iScreenRotation);
+ ILOG("g_Config.screenRotation = %d", g_Config.iScreenRotation);
+ snprintf(temp, sizeof(temp), "%d", g_Config.iScreenRotation);
return std::string(temp);
} else if (query == "immersiveMode") {
return std::string(g_Config.bImmersiveMode ? "1" : "0");
@@ -224,7 +225,7 @@ std::string NativeQueryConfig(std::string query) {
}
int max_res = std::max(System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES)) / 480 + 1;
- sprintf(temp, "%i", std::min(scale, max_res));
+ snprintf(temp, sizeof(temp), "%d", std::min(scale, max_res));
return std::string(temp);
} else if (query == "force44khz") {
return std::string("0");
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index 6ff5076007..b61f43730c 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -99,8 +99,14 @@ ARCH_FILES := \
ArmEmitterTest.cpp
endif
+EGL_FILES := \
+ $(SRC)/Common/GL/GLInterface/EGL.cpp \
+ $(SRC)/Common/GL/GLInterface/EGLAndroid.cpp \
+ $(SRC)/Common/GL/GLInterface/GLInterface.cpp
+
EXEC_AND_LIB_FILES := \
$(ARCH_FILES) \
+ $(EGL_FILES) \
TestRunner.cpp \
$(SRC)/Core/MIPS/MIPS.cpp.arm \
$(SRC)/Core/MIPS/MIPSAnalyst.cpp \
diff --git a/android/jni/Locals.mk b/android/jni/Locals.mk
index 377a6a5f7b..1e566d3298 100644
--- a/android/jni/Locals.mk
+++ b/android/jni/Locals.mk
@@ -15,7 +15,7 @@ LOCAL_C_INCLUDES := \
$(LOCAL_PATH)
LOCAL_STATIC_LIBRARIES := native libzip
-LOCAL_LDLIBS := -lz -lGLESv2 -lOpenSLES -lEGL -ldl -llog
+LOCAL_LDLIBS := -lz -landroid -lGLESv2 -lOpenSLES -lEGL -ldl -llog
# ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
ifeq ($(findstring armeabi-v7a,$(TARGET_ARCH_ABI)),armeabi-v7a)
diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp
index c41ba41c90..c812c25771 100644
--- a/android/jni/app-android.cpp
+++ b/android/jni/app-android.cpp
@@ -6,6 +6,7 @@
#include
#include
+#include
#include
#include
#include
@@ -27,6 +28,8 @@
#include "android/jni/native_audio.h"
#include "gfx/gl_common.h"
+#include "Common/GL/GLInterfaceBase.h"
+
#include "app-android.h"
static JNIEnv *jniEnvUI;
@@ -61,11 +64,29 @@ static int androidVersion;
static int deviceType;
// Should only be used for display detection during startup (for config defaults etc)
+// This is the ACTUAL display size, not the hardware scaled display size.
+static int display_dpi;
static int display_xres;
static int display_yres;
+static int backbuffer_format; // Android PixelFormat enum
+
+static int desiredBackbufferSizeX;
+static int desiredBackbufferSizeY;
static jmethodID postCommand;
static jobject nativeActivity;
+static volatile bool exitRenderLoop;
+bool renderLoopRunning;
+
+float dp_xscale = 1.0f;
+float dp_yscale = 1.0f;
+
+InputState input_state;
+
+static bool renderer_inited = false;
+static bool first_lost = true;
+static std::string library_path;
+
// Android implementation of callbacks to the Java part of the app
void SystemToast(const char *text) {
@@ -143,18 +164,6 @@ int System_GetPropertyInt(SystemProperty prop) {
}
}
-// Remember that all of these need initialization on init! The process
-// may be reused when restarting the game. Globals are DANGEROUS.
-
-float dp_xscale = 1.0f;
-float dp_yscale = 1.0f;
-
-InputState input_state;
-
-static bool renderer_inited = false;
-static bool first_lost = true;
-static std::string library_path;
-
std::string GetJavaString(JNIEnv *env, jstring jstr) {
const char *str = env->GetStringUTFChars(jstr, 0);
std::string cpp_string = std::string(str);
@@ -202,7 +211,7 @@ extern "C" jstring Java_org_ppsspp_ppsspp_NativeApp_queryConfig
}
extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init
- (JNIEnv *env, jclass, jstring jmodel, jint jdeviceType, jint jxres, jint jyres, jstring jlangRegion, jstring japkpath,
+ (JNIEnv *env, jclass, jstring jmodel, jint jdeviceType, jstring jlangRegion, jstring japkpath,
jstring jdataDir, jstring jexternalDir, jstring jlibraryDir, jstring jshortcutParam,
jstring jinstallID, jint jAndroidVersion) {
jniEnvUI = env;
@@ -226,8 +235,6 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init
right_joystick_y_async = 0;
hat_joystick_x_async = 0;
hat_joystick_y_async = 0;
- display_xres = jxres;
- display_yres = jyres;
std::string apkPath = GetJavaString(env, japkpath);
VFSRegister("", new ZipAssetReader(apkPath.c_str(), "assets/"));
@@ -313,97 +320,8 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_shutdown(JNIEnv *, jclass) {
ILOG("NativeApp.shutdown() -- end");
}
-extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env, jobject obj) {
- ILOG("NativeApp.displayInit()");
- if (!renderer_inited) {
- NativeInitGraphics();
- renderer_inited = true;
- } else {
- NativeDeviceLost(); // ???
- ILOG("displayInit: NativeDeviceLost completed.");
- }
-}
-
-extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayResize(JNIEnv *, jobject clazz, jint w, jint h, jint dpi, jfloat refreshRate) {
- ILOG("NativeApp.displayResize(%i x %i, dpi=%i, refresh=%0.2f)", w, h, dpi, refreshRate);
-
- g_dpi = dpi;
- g_dpi_scale = 240.0f / (float)g_dpi;
-
- pixel_xres = w;
- pixel_yres = h;
- dp_xres = pixel_xres * g_dpi_scale;
- dp_yres = pixel_yres * g_dpi_scale;
- dp_xscale = (float)dp_xres / pixel_xres;
- dp_yscale = (float)dp_yres / pixel_yres;
- display_hz = refreshRate;
-
- NativeResized();
-}
-
-extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayRender(JNIEnv *env, jobject obj) {
- static bool hasSetThreadName = false;
- if (!hasSetThreadName) {
- hasSetThreadName = true;
- setCurrentThreadName("AndroidRender");
- }
-
- if (renderer_inited) {
- // TODO: Look into if these locks are a perf loss
- {
- lock_guard guard(input_state.lock);
-
- input_state.pad_lstick_x = left_joystick_x_async;
- input_state.pad_lstick_y = left_joystick_y_async;
- input_state.pad_rstick_x = right_joystick_x_async;
- input_state.pad_rstick_y = right_joystick_y_async;
-
- UpdateInputState(&input_state);
- }
- NativeUpdate(input_state);
-
- {
- lock_guard guard(input_state.lock);
- EndInputState(&input_state);
- }
-
- NativeRender();
- time_update();
- } else {
- ELOG("BAD: Ended up in nativeRender even though app has quit.%s", "");
- // Shouldn't really get here. Let's draw magenta.
- glDepthMask(GL_TRUE);
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- glClearColor(1.0, 0.0, 1.0f, 1.0f);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
- }
-
- lock_guard guard(frameCommandLock);
- if (!nativeActivity) {
- while (!frameCommands.empty())
- frameCommands.pop();
- return;
- }
- while (!frameCommands.empty()) {
- FrameCommand frameCmd;
- frameCmd = frameCommands.front();
- frameCommands.pop();
-
- DLOG("frameCommand %s %s", frameCmd.command.c_str(), frameCmd.params.c_str());
-
- jstring cmd = env->NewStringUTF(frameCmd.command.c_str());
- jstring param = env->NewStringUTF(frameCmd.params.c_str());
- env->CallVoidMethod(nativeActivity, postCommand, cmd, param);
- env->DeleteLocalRef(cmd);
- env->DeleteLocalRef(param);
- }
-}
-
extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayShutdown(JNIEnv *env, jobject obj) {
if (renderer_inited) {
- NativeDeviceLost();
- ILOG("NativeDeviceLost completed.");
- NativeShutdownGraphics();
renderer_inited = false;
NativeMessageReceived("recreateviews", "");
}
@@ -538,7 +456,7 @@ extern "C" jboolean JNICALL Java_org_ppsspp_ppsspp_NativeApp_accelerometer(JNIEn
return retvalX || retvalY || retvalZ;
}
-extern "C" void Java_org_ppsspp_ppsspp_NativeApp_sendMessage(JNIEnv *env, jclass, jstring message, jstring param) {
+extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_sendMessage(JNIEnv *env, jclass, jstring message, jstring param) {
std::string msg = GetJavaString(env, message);
std::string prm = GetJavaString(env, param);
@@ -547,3 +465,211 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_sendMessage(JNIEnv *env, jclass
}
NativeMessageReceived(msg.c_str(), prm.c_str());
}
+
+extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeActivity_exitEGLRenderLoop(JNIEnv *env, jobject obj) {
+ if (!renderLoopRunning) {
+ ELOG("Render loop already exited");
+ return;
+ }
+ exitRenderLoop = true;
+ while (renderLoopRunning) {
+ sleep_ms(10);
+ }
+}
+
+void correctRatio(int &sz_x, int &sz_y, float scale) {
+ float x = (float)sz_x;
+ float y = (float)sz_y;
+ float ratio = x / y;
+ ILOG("CorrectRatio: Considering size: %0.2f/%0.2f=%0.2f for scale %f", x, y, ratio, scale);
+ float targetRatio;
+
+ // Try to get the longest dimension to match scale*PSP resolution.
+ if (x >= y) {
+ targetRatio = 480.0f / 272.0f;
+ x = 480.f * scale;
+ y = 272.f * scale;
+ } else {
+ targetRatio = 272.0f / 480.0f;
+ x = 272.0f * scale;
+ y = 480.0f * scale;
+ }
+
+ float correction = targetRatio / ratio;
+ ILOG("Target ratio: %0.2f ratio: %0.2f correction: %0.2f", targetRatio, ratio, correction);
+ if (ratio < targetRatio) {
+ y *= correction;
+ } else {
+ x /= correction;
+ }
+
+ sz_x = x;
+ sz_y = y;
+ ILOG("Corrected ratio: %dx%d", sz_x, sz_y);
+}
+
+void getDesiredBackbufferSize(int &sz_x, int &sz_y) {
+ sz_x = display_xres;
+ sz_y = display_yres;
+ std::string config = NativeQueryConfig("hwScale");
+ int scale;
+ if (1 == sscanf(config.c_str(), "%d", &scale) && scale > 0) {
+ correctRatio(sz_x, sz_y, scale);
+ } else {
+ sz_x = 0;
+ sz_y = 0;
+ }
+}
+
+extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_setDisplayParameters(JNIEnv *, jclass, jint xres, jint yres, jint dpi, jfloat refreshRate) {
+ ILOG("NativeApp.setDisplayParameters(%d x %d, dpi=%d, refresh=%0.2f)", xres, yres, dpi, refreshRate);
+ display_xres = xres;
+ display_yres = yres;
+ display_dpi = dpi;
+ display_hz = refreshRate;
+}
+
+extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_backbufferResize(JNIEnv *, jclass, jint bufw, jint bufh, jint format) {
+ ILOG("NativeApp.backbufferResize(%d x %d)", bufw, bufh);
+
+ // pixel_*res is the backbuffer resolution.
+ pixel_xres = bufw;
+ pixel_yres = bufh;
+ backbuffer_format = format;
+
+ g_dpi = (int)display_dpi;
+ g_dpi_scale = 240.0f / (float)g_dpi;
+
+ dp_xres = display_xres * g_dpi_scale;
+ dp_yres = display_yres * g_dpi_scale;
+
+ // Touch scaling is from display pixels to dp pixels.
+ dp_xscale = (float)dp_xres / (float)display_xres;
+ dp_yscale = (float)dp_yres / (float)display_yres;
+
+ pixel_in_dps = (float)pixel_xres / dp_xres;
+
+ ILOG("dp_xscale=%f dp_yscale=%f", dp_xscale, dp_yscale);
+ ILOG("dp_xres=%d dp_yres=%d", dp_xres, dp_yres);
+ ILOG("pixel_xres=%d pixel_yres=%d", pixel_xres, pixel_yres);
+ ILOG("g_dpi=%d g_dpi_scale=%f", g_dpi, g_dpi_scale);
+
+ NativeResized();
+}
+
+extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_computeDesiredBackbufferDimensions() {
+ getDesiredBackbufferSize(desiredBackbufferSizeX, desiredBackbufferSizeY);
+}
+
+extern "C" jint JNICALL Java_org_ppsspp_ppsspp_NativeApp_getDesiredBackbufferWidth(JNIEnv *, jclass) {
+ return desiredBackbufferSizeX;
+}
+
+extern "C" jint JNICALL Java_org_ppsspp_ppsspp_NativeApp_getDesiredBackbufferHeight(JNIEnv *, jclass) {
+ return desiredBackbufferSizeY;
+}
+
+extern "C" bool JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runEGLRenderLoop(JNIEnv *env, jobject obj, jobject _surf) {
+ ANativeWindow *wnd = ANativeWindow_fromSurface(env, _surf);
+
+ WLOG("runEGLRenderLoop. display_xres=%d display_yres=%d", display_xres, display_yres);
+
+ if (wnd == nullptr) {
+ ELOG("Error: Surface is null.");
+ return false;
+ }
+
+ cInterfaceBase *gl = HostGL_CreateGLInterface();
+ if (!gl) {
+ ELOG("ERROR: Failed to create GL interface");
+ return false;
+ }
+ ILOG("EGL interface created. Desired backbuffer size: %dx%d", desiredBackbufferSizeX, desiredBackbufferSizeY);
+
+ // Apparently we still have to set this through Java through setFixedSize on the bufferHolder for it to take effect...
+ gl->SetBackBufferDimensions(desiredBackbufferSizeX, desiredBackbufferSizeY);
+ gl->SetMode(MODE_DETECT_ES);
+
+ bool use565 = false;
+ switch (backbuffer_format) {
+ case 4: // PixelFormat.RGB_565
+ use565 = true;
+ break;
+ }
+
+ if (!gl->Create(wnd, false, use565)) {
+ ELOG("EGL creation failed");
+ // TODO: What do we do now?
+ return false;
+ }
+ gl->MakeCurrent();
+
+ if (!renderer_inited) {
+ NativeInitGraphics();
+ renderer_inited = true;
+ }
+
+ exitRenderLoop = false;
+ renderLoopRunning = true;
+
+ while (!exitRenderLoop) {
+ static bool hasSetThreadName = false;
+ if (!hasSetThreadName) {
+ hasSetThreadName = true;
+ setCurrentThreadName("AndroidRender");
+ }
+
+ // TODO: Look into if these locks are a perf loss
+ {
+ lock_guard guard(input_state.lock);
+
+ input_state.pad_lstick_x = left_joystick_x_async;
+ input_state.pad_lstick_y = left_joystick_y_async;
+ input_state.pad_rstick_x = right_joystick_x_async;
+ input_state.pad_rstick_y = right_joystick_y_async;
+
+ UpdateInputState(&input_state);
+ }
+ NativeUpdate(input_state);
+
+ {
+ lock_guard guard(input_state.lock);
+ EndInputState(&input_state);
+ }
+
+ NativeRender();
+ time_update();
+
+ gl->Swap();
+
+ lock_guard guard(frameCommandLock);
+ while (!frameCommands.empty()) {
+ FrameCommand frameCmd;
+ frameCmd = frameCommands.front();
+ frameCommands.pop();
+
+ WLOG("frameCommand! '%s' '%s'", frameCmd.command.c_str(), frameCmd.params.c_str());
+
+ jstring cmd = env->NewStringUTF(frameCmd.command.c_str());
+ jstring param = env->NewStringUTF(frameCmd.params.c_str());
+ env->CallVoidMethod(nativeActivity, postCommand, cmd, param);
+ env->DeleteLocalRef(cmd);
+ env->DeleteLocalRef(param);
+ }
+ }
+
+ // Restore lost device objects. TODO: This feels like the wrong place for this.
+ NativeDeviceLost();
+ ILOG("NativeDeviceLost completed.");
+
+ NativeShutdownGraphics();
+ renderer_inited = false;
+
+ gl->ClearCurrent();
+ delete gl;
+
+ ANativeWindow_release(wnd);
+ renderLoopRunning = false;
+ WLOG("Render loop exited;");
+ return true;
+}
diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java
index f9017ba0cb..5e91e96ea9 100644
--- a/android/src/org/ppsspp/ppsspp/NativeActivity.java
+++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java
@@ -8,7 +8,6 @@ import java.util.Locale;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
-import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.UiModeManager;
import android.content.Context;
@@ -16,11 +15,9 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.pm.ConfigurationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
-import android.graphics.PixelFormat;
import android.graphics.Point;
import android.media.AudioManager;
import android.net.Uri;
@@ -29,6 +26,7 @@ import android.os.Bundle;
import android.os.Environment;
import android.os.Vibrator;
import android.text.InputType;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.Gravity;
@@ -37,6 +35,8 @@ import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.SurfaceHolder;
import android.view.View;
import android.view.View.OnSystemUiVisibilityChangeListener;
import android.view.Window;
@@ -46,57 +46,54 @@ import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.Toast;
-public class NativeActivity extends Activity {
+public class NativeActivity extends Activity implements SurfaceHolder.Callback {
// Remember to loadLibrary your JNI .so in a static {} block
// Adjust these as necessary
private static String TAG = "NativeActivity";
-
+
// Allows us to skip a lot of initialization on secondary calls to onCreate.
private static boolean initialized = false;
-
+
// Graphics and audio interfaces
- private NativeGLView mGLSurfaceView;
- protected NativeRenderer nativeRenderer;
-
+ private NativeSurfaceView mSurfaceView;
+ private Surface mSurface;
+ private Thread mRenderLoopThread;
+
private String shortcutParam = "";
-
+
public static String runCommand;
public static String commandParameter;
public static String installID;
-
+
// Remember settings for best audio latency
private int optimalFramesPerBuffer;
private int optimalSampleRate;
-
+
// audioFocusChangeListener to listen to changes in audio state
private AudioFocusChangeListener audioFocusChangeListener;
private AudioManager audioManager;
-
+
private Vibrator vibrator;
private boolean isXperiaPlay;
-
+
// Allow for multiple connected gamepads but just consider them the same for now.
// Actually this is not entirely true, see the code.
InputDeviceState inputPlayerA;
InputDeviceState inputPlayerB;
InputDeviceState inputPlayerC;
String inputPlayerADesc;
-
+
// Functions for the app activity to override to change behaviour.
-
+
public native void registerCallbacks();
public native void unregisterCallbacks();
public boolean useLowProfileButtons() {
return true;
}
-
- NativeRenderer getRenderer() {
- return nativeRenderer;
- }
-
+
@TargetApi(17)
private void detectOptimalAudioSettings() {
try {
@@ -110,8 +107,8 @@ public class NativeActivity extends Activity {
// Ignore, if we can't parse it it's bogus and zero is a fine value (means we couldn't detect it).
}
}
-
- String getApplicationLibraryDir(ApplicationInfo application) {
+
+ String getApplicationLibraryDir(ApplicationInfo application) {
String libdir = null;
try {
// Starting from Android 2.3, nativeLibraryDir is available:
@@ -159,33 +156,29 @@ public class NativeActivity extends Activity {
size.y = d.getHeight();
}
}
-
+
public void setShortcutParam(String shortcutParam) {
this.shortcutParam = ((shortcutParam == null) ? "" : shortcutParam);
}
-
+
public void Initialize() {
// Initialize audio classes. Do this here since detectOptimalAudioSettings()
// needs audioManager
this.audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
this.audioFocusChangeListener = new AudioFocusChangeListener();
-
+
if (Build.VERSION.SDK_INT >= 17) {
// Get the optimal buffer sz
detectOptimalAudioSettings();
}
- // isLandscape is used to trigger GetAppInfo currently, we
- boolean landscape = NativeApp.isLandscape();
- Log.d(TAG, "Landscape: " + landscape);
-
// Get system information
- ApplicationInfo appInfo = null;
+ ApplicationInfo appInfo = null;
PackageManager packMgmr = getPackageManager();
String packageName = getPackageName();
try {
appInfo = packMgmr.getApplicationInfo(packageName, 0);
- } catch (NameNotFoundException e) {
+ } catch (NameNotFoundException e) {
e.printStackTrace();
throw new RuntimeException("Unable to locate assets, aborting...");
}
@@ -205,42 +198,22 @@ public class NativeActivity extends Activity {
}
isXperiaPlay = IsXperiaPlay();
-
+
String libraryDir = getApplicationLibraryDir(appInfo);
File sdcard = Environment.getExternalStorageDirectory();
- String externalStorageDir = sdcard.getAbsolutePath();
+ String externalStorageDir = sdcard.getAbsolutePath();
String dataDir = this.getFilesDir().getAbsolutePath();
- String apkFilePath = appInfo.sourceDir;
+ String apkFilePath = appInfo.sourceDir;
String model = Build.MANUFACTURER + ":" + Build.MODEL;
- String languageRegion = Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry();
+ String languageRegion = Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry();
- Point displaySize = new Point();
- GetScreenSize(displaySize);
NativeApp.audioConfig(optimalFramesPerBuffer, optimalSampleRate);
- NativeApp.init(model, deviceType, displaySize.x, displaySize.y, languageRegion, apkFilePath, dataDir, externalStorageDir, libraryDir, shortcutParam, installID, Build.VERSION.SDK_INT);
+ NativeApp.init(model, deviceType, languageRegion, apkFilePath, dataDir, externalStorageDir, libraryDir, shortcutParam, installID, Build.VERSION.SDK_INT);
NativeApp.sendMessage("cacheDir", getCacheDir().getAbsolutePath());
- // OK, config should be initialized, we can query for screen rotation.
- if (Build.VERSION.SDK_INT >= 9) {
- updateScreenRotation();
- }
-
- // Detect OpenGL support.
- // We don't currently use this detection for anything but good to have in the log.
- if (!detectOpenGLES20()) {
- Log.i(TAG, "OpenGL ES 2.0 NOT detected. Things will likely go badly.");
- } else {
- if (detectOpenGLES30()) {
- Log.i(TAG, "OpenGL ES 3.0 detected.");
- }
- else {
- Log.i(TAG, "OpenGL ES 2.0 detected.");
- }
- }
-
vibrator = (Vibrator)getSystemService(VIBRATOR_SERVICE);
if (Build.VERSION.SDK_INT >= 11) {
checkForVibrator();
@@ -258,6 +231,8 @@ public class NativeActivity extends Activity {
Log.e(TAG, "Invalid rotation: " + rotString);
return;
}
+ Log.i(TAG, "Setting requested rotation: " + rot + " ('" + rotString + "')");
+
switch (rot) {
case 0:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
@@ -276,10 +251,12 @@ public class NativeActivity extends Activity {
break;
}
}
-
+
private boolean useImmersive() {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
+ return false;
String immersive = NativeApp.queryConfig("immersiveMode");
- return immersive.equals("1") && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
+ return immersive.equals("1");
}
@SuppressLint("InlinedApi")
@@ -298,7 +275,7 @@ public class NativeActivity extends Activity {
Log.e(TAG, "updateSystemUiVisibility: decor view not yet created, ignoring");
}
}
-
+
// Need API 11 to check for existence of a vibrator? Zany.
@TargetApi(11)
public void checkForVibrator() {
@@ -309,71 +286,67 @@ public class NativeActivity extends Activity {
}
}
- // Override this to scale the backbuffer (use the Android hardware scaler)
- public void getDesiredBackbufferSize(Point sz) {
- sz.x = 0;
- sz.y = 0;
+ private Runnable mEmulationRunner = new Runnable() {
+ @Override
+ public void run() {
+ // Bit of a hack - loop until onSurfaceCreated succeeds.
+ try {
+ while (mSurface == null)
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ Log.i(TAG, "Starting the render loop: " + mSurface);
+ // Start emulation using the provided Surface.
+ if (!runEGLRenderLoop(mSurface)) {
+ // TODO: Add an alert dialog or something
+ Log.e(TAG, "Failed to start up OpenGL");
+ }
+ Log.i(TAG, "Left the render loop: " + mSurface);
+ }
+ };
+
+ public native boolean runEGLRenderLoop(Surface surface);
+ // Tells the render loop thread to exit, so we can restart it.
+ public native void exitEGLRenderLoop();
+
+ void updateDisplayMetrics(Point outSize) {
+ DisplayMetrics metrics = new DisplayMetrics();
+ Display display = getWindowManager().getDefaultDisplay();
+ display.getMetrics(metrics);
+
+ float refreshRate = display.getRefreshRate();
+ if (outSize == null) {
+ outSize = new Point();
+ }
+ GetScreenSize(outSize);
+ NativeApp.setDisplayParameters(outSize.x, outSize.y, metrics.densityDpi, refreshRate);
}
- @Override
+ @Override
public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ super.onCreate(savedInstanceState);
registerCallbacks();
installID = Installation.id(this);
+ updateDisplayMetrics(null);
+
if (!initialized) {
Initialize();
initialized = true;
}
+
+ // OK, config should be initialized, we can query for screen rotation.
+ updateScreenRotation();
+
// Keep the screen bright - very annoying if it goes dark when tilting away
Window window = this.getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
-
+
gainAudioFocus(this.audioManager, this.audioFocusChangeListener);
NativeApp.audioInit();
-
- mGLSurfaceView = new NativeGLView(this);
- nativeRenderer = new NativeRenderer(this);
-
- Point sz = new Point();
- getDesiredBackbufferSize(sz);
- if (sz.x > 0) {
- Log.i(TAG, "Requesting fixed size buffer: " + sz.x + "x" + sz.y);
- // Auto-calculates new DPI and forwards to the correct call on mGLSurfaceView.getHolder()
- nativeRenderer.setFixedSize(sz.x, sz.y, mGLSurfaceView);
- }
- mGLSurfaceView.setEGLContextClientVersion(2);
-
- // Setup the GLSurface and ask android for the correct
- // Number of bits for r, g, b, a, depth and stencil components
- // The PSP only has 16-bit Z so that should be enough.
- // Might want to change this for other apps (24-bit might be useful).
- // Actually, we might be able to do without both stencil and depth in
- // the back buffer, but that would kill non-buffered rendering.
-
- // It appears some gingerbread devices blow up if you use a config chooser at all ???? (Xperia Play)
- //if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
-
- // On some (especially older devices), things blow up later (EGL_BAD_MATCH) if we don't set the format here,
- // if we specify that we want destination alpha in the config chooser, which we do.
- // http://grokbase.com/t/gg/android-developers/11bj40jm4w/fall-back
-
-
- // Needed to avoid banding on Ouya?
- if (Build.MANUFACTURER == "OUYA") {
- mGLSurfaceView.getHolder().setFormat(PixelFormat.RGBX_8888);
- mGLSurfaceView.setEGLConfigChooser(new NativeEGLConfigChooser());
- } else {
- // Many devices require that we set a config chooser, despite the documentation
- // explicitly stating: "If no setEGLConfigChooser method is called, then by default the view will choose an RGB_888 surface with a depth buffer depth of at least 16 bits."
- // On these devices, I get these crashes: http://stackoverflow.com/questions/14167319/android-opengl-demo-no-config-chosen
- // So let's try it...
- mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 8);
- }
-
- mGLSurfaceView.setRenderer(nativeRenderer);
- setContentView(mGLSurfaceView);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
updateSystemUiVisibility();
@@ -381,8 +354,62 @@ public class NativeActivity extends Activity {
setupSystemUiCallback();
}
}
+ updateDisplayMetrics(null);
+
+ NativeApp.computeDesiredBackbufferDimensions();
+ int bbW = NativeApp.getDesiredBackbufferWidth();
+ int bbH = NativeApp.getDesiredBackbufferHeight();
+
+ mSurfaceView = new NativeSurfaceView(NativeActivity.this, bbW, bbH);
+ mSurfaceView.getHolder().addCallback(NativeActivity.this);
+ Log.i(TAG, "setcontentview before");
+ setContentView(mSurfaceView);
+ Log.i(TAG, "setcontentview after");
+
+ mRenderLoopThread = new Thread(mEmulationRunner);
+ mRenderLoopThread.start();
}
+ @Override
+ public void surfaceCreated(SurfaceHolder holder)
+ {
+ Log.d(TAG, "Surface created.");
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
+ {
+ Log.w(TAG, "Surface changed. Resolution: " + width + "x" + height + " Format: " + format);
+ // Make sure we have fresh display metrics so the computations go right.
+ // This is needed on some very old devices, I guess event order is different or something...
+ Point sz = new Point();
+ updateDisplayMetrics(sz);
+ NativeApp.backbufferResize(width, height, format);
+ mSurface = holder.getSurface();
+ if (mRenderLoopThread == null || !mRenderLoopThread.isAlive()) {
+ mRenderLoopThread = new Thread(mEmulationRunner);
+ mRenderLoopThread.start();
+ }
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder)
+ {
+ mSurface = null;
+ Log.w(TAG, "Surface destroyed.");
+ if (mRenderLoopThread != null && mRenderLoopThread.isAlive()) {
+ // This will wait until the thread has exited.
+ exitEGLRenderLoop();
+ try {
+ mRenderLoopThread.join();
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
+
@TargetApi(19)
void setupSystemUiCallback() {
getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() {
@@ -394,48 +421,36 @@ public class NativeActivity extends Activity {
}
});
}
-
+
@Override
protected void onStop() {
- super.onStop();
+ exitEGLRenderLoop();
+ super.onStop();
Log.i(TAG, "onStop - do nothing special");
- }
+ }
@Override
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy");
- mGLSurfaceView.onDestroy();
- nativeRenderer.onDestroyed();
+ mSurfaceView.onDestroy();
NativeApp.audioShutdown();
// Probably vain attempt to help the garbage collector...
- mGLSurfaceView = null;
+ mSurfaceView = null;
audioFocusChangeListener = null;
audioManager = null;
unregisterCallbacks();
- }
-
- private boolean detectOpenGLES20() {
- ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
- ConfigurationInfo info = am.getDeviceConfigurationInfo();
- return info.reqGlEsVersion >= 0x20000;
- }
+ }
- private boolean detectOpenGLES30() {
- ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
- ConfigurationInfo info = am.getDeviceConfigurationInfo();
- return info.reqGlEsVersion >= 0x30000;
- }
-
- @Override
+ @Override
protected void onPause() {
super.onPause();
Log.i(TAG, "onPause");
loseAudioFocus(this.audioManager, this.audioFocusChangeListener);
NativeApp.pause();
- mGLSurfaceView.onPause();
+ mSurfaceView.onPause();
}
-
+
@Override
protected void onResume() {
super.onResume();
@@ -443,33 +458,27 @@ public class NativeActivity extends Activity {
updateSystemUiVisibility();
}
// OK, config should be initialized, we can query for screen rotation.
- if (Build.VERSION.SDK_INT >= 9) {
- updateScreenRotation();
- }
+ updateScreenRotation();
Log.i(TAG, "onResume");
- if (mGLSurfaceView != null) {
- mGLSurfaceView.onResume();
+ if (mSurfaceView != null) {
+ mSurfaceView.onResume();
} else {
Log.e(TAG, "mGLSurfaceView really shouldn't be null in onResume");
}
-
+
gainAudioFocus(this.audioManager, this.audioFocusChangeListener);
NativeApp.resume();
}
-
+
@Override
public void onConfigurationChanged(Configuration newConfig) {
+ Log.i(TAG, "onConfigurationChanged");
super.onConfigurationChanged(newConfig);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
updateSystemUiVisibility();
}
-
- Point sz = new Point();
- getDesiredBackbufferSize(sz);
- if (sz.x > 0) {
- mGLSurfaceView.getHolder().setFixedSize(sz.x/2, sz.y/2);
- }
+ updateDisplayMetrics(null);
}
//keep this static so we can call this even if we don't
@@ -480,7 +489,7 @@ public class NativeActivity extends Activity {
AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
}
}
-
+
//keep this static so we can call this even if we don't
//instantiate NativeAudioPlayer
public static void loseAudioFocus(AudioManager audioManager,AudioFocusChangeListener focusChangeListener){
@@ -488,7 +497,7 @@ public class NativeActivity extends Activity {
audioManager.abandonAudioFocus(focusChangeListener);
}
}
-
+
// We simply grab the first input device to produce an event and ignore all others that are connected.
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
private InputDeviceState getInputDeviceState(InputEvent event) {
@@ -579,11 +588,11 @@ public class NativeActivity extends Activity {
}
}
}
-
+
// Let's go through the old path (onKeyUp, onKeyDown).
return super.dispatchKeyEvent(event);
- }
-
+ }
+
@TargetApi(16)
static public String getInputDesc(InputDevice input) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
@@ -648,7 +657,7 @@ public class NativeActivity extends Activity {
case KeyEvent.KEYCODE_SEARCH:
NativeApp.keyDown(0, keyCode, repeat);
return true;
-
+
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_DPAD_LEFT:
@@ -703,12 +712,12 @@ public class NativeActivity extends Activity {
}
}
-
+
@TargetApi(11)
private AlertDialog.Builder createDialogBuilderWithTheme() {
return new AlertDialog.Builder(this, AlertDialog.THEME_HOLO_DARK);
}
-
+
// The return value is sent elsewhere. TODO in java, in SendMessage in C++.
public void inputBox(String title, String defaultText, String defaultAction) {
final FrameLayout fl = new FrameLayout(this);
@@ -722,7 +731,7 @@ public class NativeActivity extends Activity {
input.setInputType(InputType.TYPE_CLASS_TEXT);
input.setText(defaultText);
input.selectAll();
-
+
AlertDialog.Builder bld = null;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB)
bld = new AlertDialog.Builder(this);
@@ -733,22 +742,24 @@ public class NativeActivity extends Activity {
.setView(fl)
.setTitle(title)
.setPositiveButton(defaultAction, new DialogInterface.OnClickListener(){
- public void onClick(DialogInterface d, int which) {
+ @Override
+ public void onClick(DialogInterface d, int which) {
NativeApp.sendMessage("inputbox_completed", input.getText().toString());
d.dismiss();
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
- public void onClick(DialogInterface d, int which) {
+ @Override
+ public void onClick(DialogInterface d, int which) {
NativeApp.sendMessage("inputbox_failed", "");
d.cancel();
}
}).create();
-
+
dlg.setCancelable(true);
dlg.show();
}
-
+
public boolean processCommand(String command, String params) {
if (command.equals("launchBrowser")) {
try {
@@ -825,18 +836,18 @@ public class NativeActivity extends Activity {
toast.show();
Log.i(TAG, params);
return true;
- } else if (command.equals("showKeyboard") && mGLSurfaceView != null) {
+ } else if (command.equals("showKeyboard") && mSurfaceView != null) {
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
// No idea what the point of the ApplicationWindowToken is or if it
// matters where we get it from...
inputMethodManager.toggleSoftInputFromWindow(
- mGLSurfaceView.getApplicationWindowToken(),
+ mSurfaceView.getApplicationWindowToken(),
InputMethodManager.SHOW_FORCED, 0);
return true;
- } else if (command.equals("hideKeyboard") && mGLSurfaceView != null) {
+ } else if (command.equals("hideKeyboard") && mSurfaceView != null) {
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.toggleSoftInputFromWindow(
- mGLSurfaceView.getApplicationWindowToken(),
+ mSurfaceView.getApplicationWindowToken(),
InputMethodManager.SHOW_FORCED, 0);
return true;
} else if (command.equals("inputbox")) {
@@ -850,7 +861,7 @@ public class NativeActivity extends Activity {
Log.i(TAG, "Launching inputbox: " + title + " " + defString);
inputBox(title, defString, "OK");
return true;
- } else if (command.equals("vibrate") && mGLSurfaceView != null) {
+ } else if (command.equals("vibrate") && mSurfaceView != null) {
int milliseconds = -1;
if (params != "") {
try {
@@ -867,13 +878,13 @@ public class NativeActivity extends Activity {
// permission.
switch (milliseconds) {
case -1:
- mGLSurfaceView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
+ mSurfaceView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
break;
case -2:
- mGLSurfaceView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
+ mSurfaceView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
break;
case -3:
- mGLSurfaceView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ mSurfaceView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
break;
default:
if (vibrator != null) {
@@ -885,14 +896,16 @@ public class NativeActivity extends Activity {
} else if (command.equals("finish")) {
finish();
} else if (command.equals("rotate")) {
- if (Build.VERSION.SDK_INT >= 9) {
- updateScreenRotation();
- }
+ updateScreenRotation();
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ Log.i(TAG, "Must recreate activity on rotation");
+ }
} else if (command.equals("immersive")) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
updateSystemUiVisibility();
}
} else if (command.equals("recreate")) {
+ exitEGLRenderLoop();
recreate();
}
return false;
diff --git a/android/src/org/ppsspp/ppsspp/NativeApp.java b/android/src/org/ppsspp/ppsspp/NativeApp.java
index 9265f6a47c..e15252191a 100644
--- a/android/src/org/ppsspp/ppsspp/NativeApp.java
+++ b/android/src/org/ppsspp/ppsspp/NativeApp.java
@@ -1,24 +1,31 @@
package org.ppsspp.ppsspp;
-// Note that the display* methods are in NativeRenderer.java
+// Note that the display* methods are in NativeRenderer.java
public class NativeApp {
- public final static int DEVICE_ID_DEFAULT = 0;
- public final static int DEVICE_ID_KEYBOARD = 1;
- public final static int DEVICE_ID_MOUSE = 2;
- public final static int DEVICE_ID_PAD_0 = 10;
-
+ public final static int DEVICE_ID_DEFAULT = 0;
+ public final static int DEVICE_ID_KEYBOARD = 1;
+ public final static int DEVICE_ID_MOUSE = 2;
+ public final static int DEVICE_ID_PAD_0 = 10;
+
public final static int DEVICE_TYPE_MOBILE = 0;
public final static int DEVICE_TYPE_TV = 1;
public final static int DEVICE_TYPE_DESKTOP = 2;
- public static native void init(String model, int deviceType, int xres, int yres, String languageRegion, String apkPath, String dataDir, String externalDir, String libraryDir, String shortcutParam, String installID, int androidVersion);
-
+ public static native void init(String model, int deviceType, String languageRegion, String apkPath, String dataDir, String externalDir, String libraryDir, String shortcutParam, String installID, int androidVersion);
+
public static native void audioInit();
public static native void audioShutdown();
public static native void audioConfig(int optimalFramesPerBuffer, int optimalSampleRate);
-
+
+ public static native void computeDesiredBackbufferDimensions();
+ public static native int getDesiredBackbufferWidth();
+ public static native int getDesiredBackbufferHeight();
+
+ public static native void setDisplayParameters(int display_xres, int display_yres, int dpi, float refreshRate);
+ public static native void backbufferResize(int bufferWidth, int bufferHeight, int format);
+
public static native boolean isLandscape();
public static native boolean isAtTopLevel();
@@ -35,7 +42,7 @@ public class NativeApp {
public static native void beginJoystickEvent();
public static native void joystickAxis(int deviceId, int axis, float value);
public static native void endJoystickEvent();
-
+
public static native boolean mouseWheelEvent(float x, float y);
// will only be called between init() and shutdown()
@@ -47,7 +54,6 @@ public class NativeApp {
public static native boolean accelerometer(float x, float y, float z);
public static native void sendMessage(String msg, String arg);
-
+
public static native String queryConfig(String queryName);
}
-
\ No newline at end of file
diff --git a/android/src/org/ppsspp/ppsspp/NativeEGLConfigChooser.java b/android/src/org/ppsspp/ppsspp/NativeEGLConfigChooser.java
deleted file mode 100644
index fe4d09fe0d..0000000000
--- a/android/src/org/ppsspp/ppsspp/NativeEGLConfigChooser.java
+++ /dev/null
@@ -1,205 +0,0 @@
-package org.ppsspp.ppsspp;
-
-import javax.microedition.khronos.egl.EGL10;
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.egl.EGLDisplay;
-
-import android.opengl.GLSurfaceView.EGLConfigChooser;
-import android.util.Log;
-
-public class NativeEGLConfigChooser implements EGLConfigChooser {
- private static final String TAG = "NativeEGLConfigChooser";
-
- private static final int EGL_OPENGL_ES2_BIT = 4;
-
- private class ConfigAttribs {
- EGLConfig config;
- public int red;
- public int green;
- public int blue;
- public int alpha;
- public int stencil;
- public int depth;
- public int samples;
- public void Log() {
- Log.i(TAG, "EGLConfig: red=" + red + " green=" + green + " blue=" + blue + " alpha=" + alpha + " depth=" + depth + " stencil=" + stencil + " samples=" + samples);
- }
- }
-
- int getEglConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config, int attr) {
- int[] value = new int[1];
- try {
- if (egl.eglGetConfigAttrib(display, config, attr, value))
- return value[0];
- else
- return -1;
- } catch (IllegalArgumentException e) {
- if (config == null) {
- Log.e(TAG, "Called getEglConfigAttrib with null config. Bad developer.");
- } else {
- Log.e(TAG, "Illegal argument to getEglConfigAttrib: attr=" + attr);
- }
- return -1;
- }
- }
-
- ConfigAttribs[] getConfigAttribs(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {
- ConfigAttribs[] attr = new ConfigAttribs[configs.length];
- for (int i = 0; i < configs.length; i++) {
- ConfigAttribs cfg = new ConfigAttribs();
- cfg.config = configs[i];
- cfg.red = getEglConfigAttrib(egl, display, configs[i], EGL10.EGL_RED_SIZE);
- cfg.green = getEglConfigAttrib(egl, display, configs[i], EGL10.EGL_GREEN_SIZE);
- cfg.blue = getEglConfigAttrib(egl, display, configs[i], EGL10.EGL_BLUE_SIZE);
- cfg.alpha = getEglConfigAttrib(egl, display, configs[i], EGL10.EGL_ALPHA_SIZE);
- cfg.depth = getEglConfigAttrib(egl, display, configs[i], EGL10.EGL_DEPTH_SIZE);
- cfg.stencil = getEglConfigAttrib(egl, display, configs[i], EGL10.EGL_STENCIL_SIZE);
- cfg.samples = getEglConfigAttrib(egl, display, configs[i], EGL10.EGL_SAMPLES);
- attr[i] = cfg;
- }
- return attr;
- }
-
- public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
- // The absolute minimum. We will do our best to choose a better config though.
- int[] configSpec = {
- EGL10.EGL_RED_SIZE, 5,
- EGL10.EGL_GREEN_SIZE, 6,
- EGL10.EGL_BLUE_SIZE, 5,
- EGL10.EGL_DEPTH_SIZE, 16,
- EGL10.EGL_STENCIL_SIZE, 0,
- EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
- EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
- EGL10.EGL_NONE
- };
-
- int[] num_config = new int[1];
- if (!egl.eglChooseConfig(display, configSpec, null, 0, num_config)) {
- throw new IllegalArgumentException("eglChooseConfig failed when counting");
- }
-
- int numConfigs = num_config[0];
- Log.i(TAG, "There are " + numConfigs + " egl configs");
- if (numConfigs <= 0) {
- throw new IllegalArgumentException("No configs match configSpec");
- }
-
- EGLConfig[] eglConfigs = new EGLConfig[numConfigs];
- if (!egl.eglChooseConfig(display, configSpec, eglConfigs, numConfigs, num_config)) {
- throw new IllegalArgumentException("eglChooseConfig failed when retrieving");
- }
-
- ConfigAttribs [] configs = getConfigAttribs(egl, display, eglConfigs);
-
- ConfigAttribs chosen = null;
-
- // Log them all.
- for (int i = 0; i < configs.length; i++) {
- configs[i].Log();
- }
-
- // We now ignore destination alpha as a workaround for the Mali issue
- // where we get badly composited if we use it.
-
- // First, find our ideal configuration. Prefer depth.
- for (int i = 0; i < configs.length; i++) {
- ConfigAttribs c = configs[i];
- if (c.red == 8 && c.green == 8 && c.blue == 8 && c.alpha == 0 && c.stencil >= 8 && c.depth >= 24) {
- chosen = c;
- break;
- }
- }
-
- if (chosen == null) {
- // Then, prefer one with 20-bit depth (Tegra 3)
- for (int i = 0; i < configs.length; i++) {
- ConfigAttribs c = configs[i];
- if (c.red == 8 && c.green == 8 && c.blue == 8 && c.alpha == 0 && c.stencil >= 8 && c.depth >= 20) {
- chosen = c;
- break;
- }
- }
- }
-
- if (chosen == null) {
- // Second, accept one with 16-bit depth.
- for (int i = 0; i < configs.length; i++) {
- ConfigAttribs c = configs[i];
- if (c.red == 8 && c.green == 8 && c.blue == 8 && c.alpha == 0 && c.stencil >= 8 && c.depth >= 16) {
- chosen = c;
- break;
- }
- }
- }
-
- if (chosen == null) {
- // Third, accept one with no stencil.
- for (int i = 0; i < configs.length; i++) {
- ConfigAttribs c = configs[i];
- if (c.red == 8 && c.green == 8 && c.blue == 8 && c.alpha == 0 && c.depth >= 16) {
- chosen = c;
- break;
- }
- }
- }
-
- if (chosen == null) {
- // Third, accept one with alpha but with stencil, 24-bit depth.
- for (int i = 0; i < configs.length; i++) {
- ConfigAttribs c = configs[i];
- if (c.red == 8 && c.green == 8 && c.blue == 8 && c.alpha == 8 && c.stencil >= 8 && c.depth >= 24) {
- chosen = c;
- break;
- }
- }
- }
-
- if (chosen == null) {
- // Third, accept one with alpha but with stencil, 16-bit depth.
- for (int i = 0; i < configs.length; i++) {
- ConfigAttribs c = configs[i];
- if (c.red == 8 && c.green == 8 && c.blue == 8 && c.alpha == 8 && c.stencil >= 8 && c.depth >= 16) {
- chosen = c;
- break;
- }
- }
- }
-
- if (chosen == null) {
- // Fourth, accept one with 16-bit color but depth and stencil required.
- for (int i = 0; i < configs.length; i++) {
- ConfigAttribs c = configs[i];
- if (c.red >= 5 && c.green >= 6 && c.blue >= 5 && c.depth >= 16 && c.stencil >= 8) {
- chosen = c;
- break;
- }
- }
- }
-
- if (chosen == null) {
- // Fifth, accept one with 16-bit color but depth required.
- for (int i = 0; i < configs.length; i++) {
- ConfigAttribs c = configs[i];
- if (c.red >= 5 && c.green >= 6 && c.blue >= 5 && c.depth >= 16) {
- chosen = c;
- break;
- }
- }
- }
-
- if (chosen == null) {
- // Final, accept the first one in the list.
- if (configs.length > 0)
- chosen = configs[0];
- }
-
- if (chosen == null) {
- throw new IllegalArgumentException("Failed to find a valid EGL config");
- }
-
- Log.i(TAG, "Final chosen config: ");
- chosen.Log();
- return chosen.config;
- }
-
-}
diff --git a/android/src/org/ppsspp/ppsspp/NativeRenderer.java b/android/src/org/ppsspp/ppsspp/NativeRenderer.java
deleted file mode 100644
index ea2a021958..0000000000
--- a/android/src/org/ppsspp/ppsspp/NativeRenderer.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package org.ppsspp.ppsspp;
-
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.opengles.GL10;
-
-import android.graphics.Point;
-import android.opengl.GLES20;
-import android.opengl.GLSurfaceView;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.Display;
-
-public class NativeRenderer implements GLSurfaceView.Renderer {
- private static String TAG = "NativeRenderer";
- private NativeActivity mActivity;
- private boolean isDark = false;
- private int dpi;
- private float refreshRate;
-
- private double dpi_scale_x;
- private double dpi_scale_y;
-
- int last_width, last_height;
-
- NativeRenderer(NativeActivity act) {
- mActivity = act;
- DisplayMetrics metrics = new DisplayMetrics();
- Display display = act.getWindowManager().getDefaultDisplay();
- display.getMetrics(metrics);
- dpi = metrics.densityDpi;
-
- refreshRate = display.getRefreshRate();
- }
-
- double getDpiScaleX() {
- return dpi_scale_x;
- }
- double getDpiScaleY() {
- return dpi_scale_y;
- }
-
- public void setDark(boolean d) {
- isDark = d;
- }
-
- public void setFixedSize(int xres, int yres, GLSurfaceView surfaceView) {
- Log.i(TAG, "Setting surface to fixed size " + xres + "x" + yres);
- surfaceView.getHolder().setFixedSize(xres, yres);
- }
-
- public void onDrawFrame(GL10 unused /*use GLES20*/) {
- if (isDark) {
- GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
- GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_STENCIL_BUFFER_BIT);
- } else {
- displayRender();
- }
- }
-
- public void onSurfaceCreated(GL10 unused, EGLConfig config) {
- // Log.i(TAG, "onSurfaceCreated - EGL context is new or was lost");
- // Actually, it seems that it is here we should recreate lost GL objects.
- displayInit();
- }
-
- public void onSurfaceChanged(GL10 unused, int width, int height) {
- Point sz = new Point();
- mActivity.GetScreenSize(sz);
- double actualW = sz.x;
- double actualH = sz.y;
- dpi_scale_x = ((double)width / (double)actualW);
- dpi_scale_y = ((double)height / (double)actualH);
- Log.i(TAG, "onSurfaceChanged: " + dpi_scale_x + "x" + dpi_scale_y + " (width=" + width + ", actualW=" + actualW);
- int scaled_dpi = (int)((double)dpi * dpi_scale_x);
- displayResize(width, height, scaled_dpi, refreshRate);
- last_width = width;
- last_height = height;
- }
-
- // Not override, it's custom.
- public void onDestroyed() {
- displayShutdown();
- }
-
- // NATIVE METHODS
-
- // Note: This also means "device lost" and you should reload
- // all buffered objects.
- public native void displayInit();
- public native void displayResize(int w, int h, int dpi, float refreshRate);
- public native void displayRender();
- public native void displayShutdown();
-}
\ No newline at end of file
diff --git a/android/src/org/ppsspp/ppsspp/NativeGLView.java b/android/src/org/ppsspp/ppsspp/NativeSurfaceView.java
similarity index 81%
rename from android/src/org/ppsspp/ppsspp/NativeGLView.java
rename to android/src/org/ppsspp/ppsspp/NativeSurfaceView.java
index 603569fbfb..f0eb2369e3 100644
--- a/android/src/org/ppsspp/ppsspp/NativeGLView.java
+++ b/android/src/org/ppsspp/ppsspp/NativeSurfaceView.java
@@ -1,59 +1,54 @@
package org.ppsspp.ppsspp;
-// Touch- and sensor-enabled GLSurfaceView.
+// Touch- and sensor-enabled SurfaceView.
// Supports simple multitouch and pressure.
+// DPI scaling is handled by the native code.
+import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
+import android.graphics.PixelFormat;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
-import android.opengl.GLSurfaceView;
import android.os.Build;
import android.os.Handler;
-// import android.os.Build;
-// import android.util.Log;
import android.util.Log;
import android.view.MotionEvent;
+import android.view.SurfaceView;
+
import com.bda.controller.*;
-public class NativeGLView extends GLSurfaceView implements SensorEventListener, ControllerListener {
- private static String TAG = "NativeGLView";
+public class NativeSurfaceView extends SurfaceView implements SensorEventListener, ControllerListener {
+ private static String TAG = "NativeSurfaceView";
private SensorManager mSensorManager;
private Sensor mAccelerometer;
- private NativeActivity mActivity;
-
+
// Moga controller
private Controller mController = null;
private boolean isMogaPro = false;
-
- public NativeGLView(NativeActivity activity) {
- super(activity);
- mActivity = activity;
- /*// TODO: This would be nice.
- if (Build.VERSION.SDK_INT >= 11) {
- try {
- Method method_setPreserveEGLContextOnPause = GLSurfaceView.class.getMethod(
- "setPreserveEGLContextOnPause", new Class[] { Boolean.class });
- Log.i(TAG, "Invoking setPreserveEGLContextOnPause");
- method_setPreserveEGLContextOnPause.invoke(this, true);
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }
- }*/
-
+ public NativeSurfaceView(NativeActivity activity, int fixedW, int fixedH) {
+ super(activity);
+
+ Log.i(TAG, "NativeSurfaceView");
+
mSensorManager = (SensorManager)activity.getSystemService(Activity.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
-
+
mController = Controller.getInstance(activity);
+
+ // Maybe we need to use this?
+ if (fixedW != 0 && fixedH != 0) {
+ Log.i(TAG, "Setting surface holder to use a fixed size of " + fixedW + "x" + fixedH + " pixels");
+ this.getHolder().setFixedSize(fixedW, fixedH);
+ } else {
+ Log.i(TAG, "Using default backbuffer size.");
+ }
+
+ // this.getHolder().setFormat(PixelFormat.RGBA_8888);
+
try {
MogaHack.init(mController, activity);
Log.i(TAG, "MOGA initialized");
@@ -67,19 +62,19 @@ public class NativeGLView extends GLSurfaceView implements SensorEventListener,
private int getToolType(final MotionEvent ev, int pointer) {
return ev.getToolType(pointer);
}
-
+
+ @SuppressLint("ClickableViewAccessibility")
+ @Override
public boolean onTouchEvent(final MotionEvent ev) {
boolean canReadToolType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
int numTouchesHandled = 0;
- float scaleX = (float)mActivity.getRenderer().getDpiScaleX();
- float scaleY = (float)mActivity.getRenderer().getDpiScaleY();
for (int i = 0; i < ev.getPointerCount(); i++) {
int pid = ev.getPointerId(i);
int code = 0;
-
+
final int action = ev.getActionMasked();
-
+
// These code bits are now the same as the constants in input_state.h.
switch (action) {
case MotionEvent.ACTION_DOWN:
@@ -98,23 +93,25 @@ public class NativeGLView extends GLSurfaceView implements SensorEventListener,
default:
break;
}
-
+
if (code != 0) {
if (canReadToolType) {
int tool = getToolType(ev, i);
code |= tool << 10; // We use the Android tool type codes
}
// Can't use || due to short circuit evaluation
- numTouchesHandled += NativeApp.touch(scaleX * ev.getX(i), scaleY * ev.getY(i), code, pid) ? 1 : 0;
+ numTouchesHandled += NativeApp.touch(ev.getX(i), ev.getY(i), code, pid) ? 1 : 0;
}
}
return numTouchesHandled > 0;
}
// Sensor management
+ @Override
public void onAccuracyChanged(Sensor sensor, int arg1) {
}
+ @Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER) {
return;
@@ -122,41 +119,37 @@ public class NativeGLView extends GLSurfaceView implements SensorEventListener,
// Can also look at event.timestamp for accuracy magic
NativeApp.accelerometer(event.values[0], event.values[1], event.values[2]);
}
-
- @Override
+
public void onPause() {
- super.onPause();
mSensorManager.unregisterListener(this);
if (mController != null) {
mController.onPause();
}
}
-
- @Override
+
public void onResume() {
- super.onResume();
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
if (mController != null) {
mController.onResume();
-
+
// According to the docs, the Moga's state can be inconsistent here.
// We should do a one time poll. TODO
}
}
-
+
public void onDestroy() {
if (mController != null) {
- mController.exit();
+ mController.exit();
}
}
-
+
// MOGA Controller - from ControllerListener
@Override
public void onKeyEvent(KeyEvent event) {
// The Moga left stick doubles as a D-pad. This creates mapping conflicts so let's turn it off.
// Unfortunately this breaks menu navigation in PPSSPP currently but meh.
// This is different on Moga Pro though.
-
+
if (!isMogaPro) {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_DPAD_DOWN:
@@ -216,7 +209,7 @@ public class NativeGLView extends GLSurfaceView implements SensorEventListener,
break;
}
break;
-
+
case StateEvent.STATE_POWER_LOW:
switch (state.getAction()) {
case StateEvent.ACTION_TRUE:
diff --git a/android/src/org/ppsspp/ppsspp/PpssppActivity.java b/android/src/org/ppsspp/ppsspp/PpssppActivity.java
index f66d1b963d..bb61d9007d 100644
--- a/android/src/org/ppsspp/ppsspp/PpssppActivity.java
+++ b/android/src/org/ppsspp/ppsspp/PpssppActivity.java
@@ -1,7 +1,6 @@
package org.ppsspp.ppsspp;
import android.app.AlertDialog;
-import android.graphics.Point;
import android.os.Build;
import android.os.Bundle;
import android.os.Looper;
@@ -11,11 +10,12 @@ public class PpssppActivity extends NativeActivity {
private static final String TAG = "PpssppActivity";
// Key used by shortcut.
public static final String SHORTCUT_EXTRA_KEY = "org.ppsspp.ppsspp.Shortcuts";
-
+
private static boolean m_hasUnsupportedABI = false;
private static boolean m_hasNoNativeBinary = false;
- static {
+ @SuppressWarnings("deprecation")
+ static void CheckABIAndLoadLibrary() {
if (Build.CPU_ABI.equals("armeabi")) {
m_hasUnsupportedABI = true;
} else {
@@ -28,6 +28,10 @@ public class PpssppActivity extends NativeActivity {
}
}
+ static {
+ CheckABIAndLoadLibrary();
+ }
+
public PpssppActivity() {
super();
}
@@ -36,6 +40,7 @@ public class PpssppActivity extends NativeActivity {
public void onCreate(Bundle savedInstanceState) {
if (m_hasUnsupportedABI || m_hasNoNativeBinary) {
new Thread() {
+ @SuppressWarnings("deprecation")
@Override
public void run() {
Looper.prepare();
@@ -47,15 +52,15 @@ public class PpssppActivity extends NativeActivity {
}
Looper.loop();
}
-
+
}.start();
-
+
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
-
+
System.exit(-1);
return;
}
@@ -68,61 +73,13 @@ public class PpssppActivity extends NativeActivity {
super.onCreate(savedInstanceState);
}
-
- private void correctRatio(Point sz, float scale) {
- float x = sz.x;
- float y = sz.y;
- float ratio = x / y;
- // Log.i(TAG, "Considering size: " + sz.x + "x" + sz.y + "=" + ratio);
- float targetRatio;
- if (x >= y) {
- targetRatio = 480.0f / 272.0f;
- x = 480.f * scale;
- y = 272.f * scale;
- } else {
- targetRatio = 272.0f / 480.0f;
- x = 272.0f * scale;
- y = 480.0f * scale;
- }
- float correction = targetRatio / ratio;
- // Log.i(TAG, "Target ratio: " + targetRatio + " ratio: " + ratio + " correction: " + correction);
- if (ratio < targetRatio) {
- y *= correction;
- } else {
- x /= correction;
- }
- sz.x = (int)x;
- sz.y = (int)y;
- // Log.i(TAG, "Corrected ratio: " + sz.x + "x" + sz.y);
- }
-
- @Override
- public void getDesiredBackbufferSize(Point sz) {
- GetScreenSize(sz);
- String config = NativeApp.queryConfig("hwScale");
- int scale;
- try {
- scale = Integer.parseInt(config);
- if (scale == 0) {
- sz.x = 0;
- sz.y = 0;
- return;
- }
- }
- catch (NumberFormatException e) {
- sz.x = 0;
- sz.y = 0;
- return;
- }
- correctRatio(sz, (float)scale);
- }
-
// called by the C++ code through JNI. Dispatch anything we can't directly handle
// on the gfx thread to the UI thread.
public void postCommand(String command, String parameter) {
final String cmd = command;
final String param = parameter;
runOnUiThread(new Runnable() {
+ @Override
public void run() {
processCommand(cmd, param);
}
diff --git a/ext/native/ui/ui_context.cpp b/ext/native/ui/ui_context.cpp
index 56039e1809..d5b3bc3972 100644
--- a/ext/native/ui/ui_context.cpp
+++ b/ext/native/ui/ui_context.cpp
@@ -97,7 +97,7 @@ Bounds UIContext::GetScissorBounds() {
void UIContext::ActivateTopScissor() {
if (scissorStack_.size()) {
const Bounds &bounds = scissorStack_.back();
- float scale = 1.0f / g_dpi_scale;
+ float scale = pixel_in_dps;
int x = scale * bounds.x;
int y = scale * bounds.y;
int w = scale * bounds.w;