mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-26 23:10:38 +00:00
Use EGL from native code to initialize and run OpenGL on Android.
Should be more robust, allows initializing desktop GL if available, and lets us take control of the render loop.
This commit is contained in:
parent
c2eb6a2fcb
commit
04f8bffa29
@ -44,6 +44,9 @@ void cInterfaceEGL::DetectMode()
|
||||
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_RENDERABLE_TYPE, renderable_type,
|
||||
EGL_NONE
|
||||
};
|
||||
@ -95,7 +98,6 @@ void cInterfaceEGL::DetectMode()
|
||||
}
|
||||
|
||||
// Create rendering window.
|
||||
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
|
||||
bool cInterfaceEGL::Create(void *window_handle, bool core)
|
||||
{
|
||||
const char *s;
|
||||
@ -128,6 +130,9 @@ bool cInterfaceEGL::Create(void *window_handle, bool core)
|
||||
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_NONE };
|
||||
|
||||
EGLint ctx_attribs[] = {
|
||||
@ -154,8 +159,7 @@ bool cInterfaceEGL::Create(void *window_handle, bool core)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!eglChooseConfig( egl_dpy, attribs, &config, 1, &num_configs))
|
||||
{
|
||||
if (!eglChooseConfig( egl_dpy, attribs, &config, 1, &num_configs)) {
|
||||
INFO_LOG(G3D, "Error: couldn't get an EGL visual config\n");
|
||||
exit(1);
|
||||
}
|
||||
@ -181,15 +185,13 @@ bool cInterfaceEGL::Create(void *window_handle, bool core)
|
||||
INFO_LOG(G3D, "EGL_CLIENT_APIS = %s\n", s);
|
||||
|
||||
egl_ctx = eglCreateContext(egl_dpy, config, EGL_NO_CONTEXT, ctx_attribs );
|
||||
if (!egl_ctx)
|
||||
{
|
||||
if (!egl_ctx) {
|
||||
INFO_LOG(G3D, "Error: eglCreateContext failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
egl_surf = eglCreateWindowSurface(egl_dpy, config, native_window, nullptr);
|
||||
if (!egl_surf)
|
||||
{
|
||||
if (!egl_surf) {
|
||||
INFO_LOG(G3D, "Error: eglCreateWindowSurface failed\n");
|
||||
exit(1);
|
||||
}
|
||||
@ -207,7 +209,6 @@ bool cInterfaceEGL::ClearCurrent()
|
||||
return eglMakeCurrent(egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
}
|
||||
|
||||
// Close backend
|
||||
void cInterfaceEGL::Shutdown()
|
||||
{
|
||||
ShutdownPlatform();
|
||||
|
@ -20,6 +20,8 @@ protected:
|
||||
virtual EGLDisplay OpenDisplay() = 0;
|
||||
virtual EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window, EGLConfig config) = 0;
|
||||
virtual void ShutdownPlatform() = 0;
|
||||
virtual void SetInternalResolution(int internalWidth, int internalHeight) {}
|
||||
|
||||
public:
|
||||
void SwapInterval(int Interval);
|
||||
void Swap();
|
||||
|
@ -11,9 +11,9 @@ EGLDisplay cInterfaceEGLAndroid::OpenDisplay()
|
||||
|
||||
EGLNativeWindowType cInterfaceEGLAndroid::InitializePlatform(EGLNativeWindowType host_window, EGLConfig config)
|
||||
{
|
||||
EGLint format;
|
||||
EGLint format = 0;
|
||||
eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &format);
|
||||
ANativeWindow_setBuffersGeometry(host_window, 0, 0, format);
|
||||
ANativeWindow_setBuffersGeometry(host_window, internalWidth_, internalHeight_, format);
|
||||
|
||||
const int width = ANativeWindow_getWidth(host_window);
|
||||
const int height = ANativeWindow_getHeight(host_window);
|
||||
|
@ -6,10 +6,19 @@
|
||||
|
||||
#include "Common/GL/GLInterface/EGL.h"
|
||||
|
||||
class cInterfaceEGLAndroid : public cInterfaceEGL
|
||||
{
|
||||
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 SetInternalResolution(int internalWidth, int internalHeight) override {
|
||||
internalWidth_ = internalWidth;
|
||||
internalHeight_ = internalHeight;
|
||||
}
|
||||
|
||||
private:
|
||||
int internalWidth_;
|
||||
int internalHeight_;
|
||||
};
|
||||
|
@ -43,8 +43,5 @@ public:
|
||||
virtual bool PeekMessages() { return false; }
|
||||
};
|
||||
|
||||
extern cInterfaceBase *GLInterface;
|
||||
|
||||
// This function has to be defined along the Host_ functions from Core/Host.h.
|
||||
// Current canonical implementation: DolphinWX/GLInterface/GLInterface.cpp.
|
||||
cInterfaceBase* HostGL_CreateGLInterface();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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 \
|
||||
|
@ -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)
|
||||
|
@ -6,10 +6,12 @@
|
||||
|
||||
#include <jni.h>
|
||||
#include <android/log.h>
|
||||
#include <android/native_window_jni.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <GLES2/gl2.h>
|
||||
#include <GLES2/gl2ext.h>
|
||||
#include <EGL/EGL.h>
|
||||
#include <queue>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
@ -27,6 +29,8 @@
|
||||
#include "android/jni/native_audio.h"
|
||||
#include "gfx/gl_common.h"
|
||||
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
|
||||
#include "app-android.h"
|
||||
|
||||
static JNIEnv *jniEnvUI;
|
||||
@ -66,6 +70,8 @@ static int display_yres;
|
||||
|
||||
static jmethodID postCommand;
|
||||
static jobject nativeActivity;
|
||||
static volatile bool exitRenderLoop;
|
||||
bool renderLoopRunning;
|
||||
|
||||
// Android implementation of callbacks to the Java part of the app
|
||||
void SystemToast(const char *text) {
|
||||
@ -313,18 +319,7 @@ 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) {
|
||||
extern "C" void Java_org_ppsspp_ppsspp_NativeApp_displayResize(JNIEnv *, jclass, 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;
|
||||
@ -341,69 +336,8 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayResize(JNIEnv *, jo
|
||||
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 +472,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 +481,99 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runEGLRenderLoop(JNIEnv *env, jobject obj, jobject _surf) {
|
||||
ANativeWindow *wnd = ANativeWindow_fromSurface(env, _surf);
|
||||
|
||||
WLOG("runEGLRenderLoop");
|
||||
|
||||
if (wnd == nullptr) {
|
||||
ELOG("Error: Surface is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
cInterfaceBase *gl = HostGL_CreateGLInterface();
|
||||
if (!gl) {
|
||||
ELOG("ERROR: Failed to create GL interface");
|
||||
return;
|
||||
}
|
||||
gl->SetMode(MODE_DETECT);
|
||||
gl->Create(wnd);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
NativeDeviceLost();
|
||||
ILOG("NativeDeviceLost completed.");
|
||||
NativeShutdownGraphics();
|
||||
renderer_inited = false;
|
||||
|
||||
delete gl;
|
||||
|
||||
ANativeWindow_release(wnd);
|
||||
renderLoopRunning = false;
|
||||
WLOG("Render loop exited;");
|
||||
}
|
||||
|
@ -37,6 +37,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 +48,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 +109,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,28 +158,28 @@ 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
|
||||
// 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 {
|
||||
@ -205,16 +204,16 @@ 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);
|
||||
@ -223,24 +222,6 @@ public class NativeActivity extends Activity {
|
||||
|
||||
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 +239,7 @@ public class NativeActivity extends Activity {
|
||||
Log.e(TAG, "Invalid rotation: " + rotString);
|
||||
return;
|
||||
}
|
||||
Log.i(TAG, "Requested rotation: " + rot + " ('" + rotString + "')");
|
||||
switch (rot) {
|
||||
case 0:
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
||||
@ -276,7 +258,7 @@ public class NativeActivity extends Activity {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean useImmersive() {
|
||||
String immersive = NativeApp.queryConfig("immersiveMode");
|
||||
return immersive.equals("1") && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
|
||||
@ -298,7 +280,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() {
|
||||
@ -315,9 +297,37 @@ public class NativeActivity extends Activity {
|
||||
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.
|
||||
runEGLRenderLoop(mSurface);
|
||||
|
||||
Log.i(TAG, "Left the render loop: " + mSurface);
|
||||
}
|
||||
};
|
||||
|
||||
public native void runEGLRenderLoop(Surface surface);
|
||||
// Tells the render loop thread to exit, so we can restart it.
|
||||
public native void exitEGLRenderLoop();
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
super.onCreate(savedInstanceState);
|
||||
registerCallbacks();
|
||||
installID = Installation.id(this);
|
||||
|
||||
@ -325,55 +335,32 @@ public class NativeActivity extends Activity {
|
||||
Initialize();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
// OK, config should be initialized, we can query for screen rotation.
|
||||
if (Build.VERSION.SDK_INT >= 9) {
|
||||
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);
|
||||
|
||||
mSurfaceView = new NativeSurfaceView(this);
|
||||
mSurfaceView.getHolder().addCallback(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);
|
||||
mSurfaceView.setFixedSize(sz.x, sz.y);
|
||||
}
|
||||
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);
|
||||
|
||||
setContentView(mSurfaceView);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
updateSystemUiVisibility();
|
||||
@ -381,8 +368,46 @@ public class NativeActivity extends Activity {
|
||||
setupSystemUiCallback();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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,27 +419,27 @@ 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();
|
||||
@ -426,16 +451,16 @@ public class NativeActivity extends Activity {
|
||||
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();
|
||||
@ -445,30 +470,30 @@ public class NativeActivity extends Activity {
|
||||
// OK, config should be initialized, we can query for screen rotation.
|
||||
if (Build.VERSION.SDK_INT >= 9) {
|
||||
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) {
|
||||
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);
|
||||
mSurfaceView.getHolder().setFixedSize(sz.x/2, sz.y/2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -480,7 +505,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 +513,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 +604,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 +673,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 +728,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 +747,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 +758,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 +852,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 +877,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 +894,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) {
|
||||
@ -887,12 +914,13 @@ public class NativeActivity extends Activity {
|
||||
} else if (command.equals("rotate")) {
|
||||
if (Build.VERSION.SDK_INT >= 9) {
|
||||
updateScreenRotation();
|
||||
}
|
||||
}
|
||||
} else if (command.equals("immersive")) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
updateSystemUiVisibility();
|
||||
}
|
||||
} else if (command.equals("recreate")) {
|
||||
exitEGLRenderLoop();
|
||||
recreate();
|
||||
}
|
||||
return false;
|
||||
|
@ -1,24 +1,25 @@
|
||||
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 audioInit();
|
||||
public static native void audioShutdown();
|
||||
public static native void audioConfig(int optimalFramesPerBuffer, int optimalSampleRate);
|
||||
|
||||
|
||||
public static native void displayResize(int width, int height, int scaled_dpi, float refreshRate);
|
||||
public static native boolean isLandscape();
|
||||
public static native boolean isAtTopLevel();
|
||||
|
||||
@ -35,7 +36,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 +48,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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
@ -5,6 +5,7 @@ package org.ppsspp.ppsspp;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.graphics.Point;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
@ -12,48 +13,55 @@ import android.hardware.SensorManager;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.util.DisplayMetrics;
|
||||
// import android.os.Build;
|
||||
// import android.util.Log;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.SurfaceView;
|
||||
|
||||
import com.bda.controller.*;
|
||||
|
||||
public class NativeGLView extends GLSurfaceView implements SensorEventListener, ControllerListener {
|
||||
public class NativeSurfaceView extends SurfaceView implements SensorEventListener, ControllerListener {
|
||||
private static String TAG = "NativeGLView";
|
||||
private SensorManager mSensorManager;
|
||||
private Sensor mAccelerometer;
|
||||
private NativeActivity mActivity;
|
||||
|
||||
|
||||
// Moga controller
|
||||
private Controller mController = null;
|
||||
private boolean isMogaPro = false;
|
||||
|
||||
public NativeGLView(NativeActivity activity) {
|
||||
private int dpi;
|
||||
private float refreshRate;
|
||||
|
||||
private double dpi_scale_x;
|
||||
private double dpi_scale_y;
|
||||
|
||||
int last_width, last_height;
|
||||
|
||||
public int fixedW = 0;
|
||||
public int fixedH = 0;
|
||||
|
||||
public NativeSurfaceView(NativeActivity activity) {
|
||||
super(activity);
|
||||
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
Display display = activity.getWindowManager().getDefaultDisplay();
|
||||
display.getMetrics(metrics);
|
||||
dpi = metrics.densityDpi;
|
||||
|
||||
refreshRate = display.getRefreshRate();
|
||||
|
||||
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();
|
||||
}
|
||||
}*/
|
||||
|
||||
mSensorManager = (SensorManager)activity.getSystemService(Activity.SENSOR_SERVICE);
|
||||
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||
|
||||
|
||||
mController = Controller.getInstance(activity);
|
||||
|
||||
onResize(display.getWidth(), display.getHeight());
|
||||
|
||||
try {
|
||||
MogaHack.init(mController, activity);
|
||||
Log.i(TAG, "MOGA initialized");
|
||||
@ -63,23 +71,43 @@ public class NativeGLView extends GLSurfaceView implements SensorEventListener,
|
||||
}
|
||||
}
|
||||
|
||||
void onResize(int width, int height) {
|
||||
Point sz = new Point();
|
||||
mActivity.GetScreenSize(sz);
|
||||
double actualW = sz.x;
|
||||
double actualH = sz.y;
|
||||
dpi_scale_x = (width / actualW);
|
||||
dpi_scale_y = (height / actualH);
|
||||
Log.i(TAG, "onSurfaceChanged: " + dpi_scale_x + "x" + dpi_scale_y + " (width=" + width + ", actualW=" + actualW);
|
||||
int scaled_dpi = (int)(dpi * dpi_scale_x);
|
||||
NativeApp.displayResize(width, height, scaled_dpi, refreshRate);
|
||||
last_width = width;
|
||||
last_height = height;
|
||||
}
|
||||
|
||||
void setFixedSize(int w, int h) {
|
||||
fixedW = w;
|
||||
fixedH = h;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
|
||||
private int getToolType(final MotionEvent ev, int pointer) {
|
||||
return ev.getToolType(pointer);
|
||||
}
|
||||
|
||||
|
||||
@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();
|
||||
float scaleX = (float)this.dpi_scale_x;
|
||||
float scaleY = (float)this.dpi_scale_y;
|
||||
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,7 +126,7 @@ public class NativeGLView extends GLSurfaceView implements SensorEventListener,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (code != 0) {
|
||||
if (canReadToolType) {
|
||||
int tool = getToolType(ev, i);
|
||||
@ -112,9 +140,11 @@ public class NativeGLView extends GLSurfaceView implements SensorEventListener,
|
||||
}
|
||||
|
||||
// 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 +152,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 +242,7 @@ public class NativeGLView extends GLSurfaceView implements SensorEventListener,
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case StateEvent.STATE_POWER_LOW:
|
||||
switch (state.getAction()) {
|
||||
case StateEvent.ACTION_TRUE:
|
@ -11,7 +11,7 @@ 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;
|
||||
|
||||
@ -47,15 +47,15 @@ public class PpssppActivity extends NativeActivity {
|
||||
}
|
||||
Looper.loop();
|
||||
}
|
||||
|
||||
|
||||
}.start();
|
||||
|
||||
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
System.exit(-1);
|
||||
return;
|
||||
}
|
||||
@ -114,7 +114,7 @@ public class PpssppActivity extends NativeActivity {
|
||||
sz.y = 0;
|
||||
return;
|
||||
}
|
||||
correctRatio(sz, (float)scale);
|
||||
correctRatio(sz, scale);
|
||||
}
|
||||
|
||||
// called by the C++ code through JNI. Dispatch anything we can't directly handle
|
||||
@ -123,6 +123,7 @@ public class PpssppActivity extends NativeActivity {
|
||||
final String cmd = command;
|
||||
final String param = parameter;
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
processCommand(cmd, param);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user