mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 13:30:02 +00:00
Merge pull request #8642 from hrydgard/java-egl
Restore Java EGL support, while keeping the new stuff around as an option
This commit is contained in:
commit
eaeddc6c23
@ -411,7 +411,7 @@ static int DefaultAndroidHwScale() {
|
||||
int xres = System_GetPropertyInt(SYSPROP_DISPLAY_XRES);
|
||||
int yres = System_GetPropertyInt(SYSPROP_DISPLAY_YRES);
|
||||
|
||||
if (xres < 960) {
|
||||
if (xres <= 960) {
|
||||
// Smaller than the PSP*2, let's go native.
|
||||
return 0;
|
||||
} else if (xres <= 480 * 3) { // 720p xres
|
||||
|
@ -209,8 +209,8 @@ void TransformDrawEngine::DestroyDeviceObjects() {
|
||||
}
|
||||
}
|
||||
|
||||
void TransformDrawEngine::GLLost() {
|
||||
ILOG("TransformDrawEngine::GLLost()");
|
||||
void TransformDrawEngine::GLRestore() {
|
||||
ILOG("TransformDrawEngine::GLRestore()");
|
||||
// The objects have already been deleted.
|
||||
bufferNameCache_.clear();
|
||||
bufferNameInfo_.clear();
|
||||
|
@ -129,7 +129,7 @@ public:
|
||||
void RestoreVAO();
|
||||
void InitDeviceObjects();
|
||||
void DestroyDeviceObjects();
|
||||
void GLLost() override;
|
||||
void GLRestore() override;
|
||||
void Resized();
|
||||
|
||||
void DecimateTrackedVertexArrays();
|
||||
|
@ -193,6 +193,8 @@ void GameSettingsScreen::CreateViews() {
|
||||
#ifdef ANDROID
|
||||
static const char *deviceResolutions[] = { "Native device resolution", "Auto (same as Rendering)", "1x PSP", "2x PSP", "3x PSP", "4x PSP", "5x PSP" };
|
||||
int max_res_temp = std::max(System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES)) / 480 + 2;
|
||||
if (max_res_temp == 3)
|
||||
max_res_temp = 4; // At least allow 2x
|
||||
int max_res = std::min(max_res_temp, (int)ARRAY_SIZE(deviceResolutions));
|
||||
UI::PopupMultiChoice *hwscale = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iAndroidHwScale, gr->T("Display Resolution (HW scaler)"), deviceResolutions, 0, max_res, gr->GetName(), screenManager()));
|
||||
hwscale->OnChoice.Handle(this, &GameSettingsScreen::OnHwScaleChange); // To refresh the display mode
|
||||
@ -647,14 +649,18 @@ UI::EventReturn GameSettingsScreen::OnHardwareTransform(UI::EventParams &e) {
|
||||
|
||||
UI::EventReturn GameSettingsScreen::OnScreenRotation(UI::EventParams &e) {
|
||||
ILOG("New display rotation: %d", g_Config.iScreenRotation);
|
||||
ILOG("Sending rotate");
|
||||
System_SendMessage("rotate", "");
|
||||
ILOG("Got back from rotate");
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
static void RecreateActivity() {
|
||||
const int SYSTEM_JELLYBEAN = 16;
|
||||
if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= SYSTEM_JELLYBEAN) {
|
||||
ILOG("Sending recreate");
|
||||
System_SendMessage("recreate", "");
|
||||
ILOG("Got back from recreate");
|
||||
} else {
|
||||
I18NCategory *gr = GetI18NCategory("Graphics");
|
||||
System_SendMessage("toast", gr->T("Must Restart", "You must restart PPSSPP for this change to take effect"));
|
||||
|
@ -766,12 +766,13 @@ void NativeUpdate(InputState &input) {
|
||||
screenManager->update(input);
|
||||
}
|
||||
|
||||
void NativeDeviceLost() {
|
||||
// g_gameInfoCache.Clear();
|
||||
void NativeDeviceRestore() {
|
||||
if (g_gameInfoCache)
|
||||
g_gameInfoCache->Clear();
|
||||
screenManager->deviceLost();
|
||||
|
||||
if (GetGPUBackend() == GPUBackend::OPENGL) {
|
||||
gl_lost();
|
||||
gl_restore();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,6 +121,21 @@ void AndroidEGLGraphicsContext::SwapBuffers() {
|
||||
gl->Swap();
|
||||
}
|
||||
|
||||
// Doesn't do much. Just to fit in.
|
||||
class AndroidJavaEGLGraphicsContext : public GraphicsContext {
|
||||
public:
|
||||
AndroidJavaEGLGraphicsContext() {}
|
||||
bool Init(ANativeWindow *wnd, int desiredBackbufferSizeX, int desiredBackbufferSizeY, int backbufferFormat, int androidVersion) { return true; }
|
||||
void Shutdown() override {}
|
||||
void SwapBuffers() override {}
|
||||
void SwapInterval(int interval) override {}
|
||||
void Resize() {}
|
||||
Thin3DContext *CreateThin3DContext() {
|
||||
CheckGLExtensions();
|
||||
return T3DCreateGLContext();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static recursive_mutex frameCommandLock;
|
||||
static std::queue<FrameCommand> frameCommands;
|
||||
@ -165,10 +180,14 @@ InputState input_state;
|
||||
|
||||
static bool renderer_inited = false;
|
||||
static bool first_lost = true;
|
||||
static bool javaGL = true;
|
||||
|
||||
static std::string library_path;
|
||||
static std::map<SystemPermission, PermissionStatus> permissions;
|
||||
|
||||
AndroidEGLGraphicsContext *graphicsContext;
|
||||
GraphicsContext *graphicsContext;
|
||||
|
||||
static void ProcessFrameCommands(JNIEnv *env);
|
||||
|
||||
void PushCommand(std::string cmd, std::string param) {
|
||||
lock_guard guard(frameCommandLock);
|
||||
@ -295,9 +314,9 @@ 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, jstring jlangRegion, jstring japkpath,
|
||||
jstring jdataDir, jstring jexternalDir, jstring jlibraryDir, jstring jcacheDir, jstring jshortcutParam,
|
||||
jint jAndroidVersion) {
|
||||
jint jAndroidVersion, jboolean jjavaGL) {
|
||||
jniEnvUI = env;
|
||||
|
||||
javaGL = jjavaGL;
|
||||
setCurrentThreadName("androidInit");
|
||||
|
||||
ILOG("NativeApp.init() -- begin");
|
||||
@ -402,8 +421,110 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_shutdown(JNIEnv *, jclass) {
|
||||
ILOG("NativeApp.shutdown() -- end");
|
||||
}
|
||||
|
||||
extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayShutdown(JNIEnv *env, jobject obj) {
|
||||
// JavaEGL
|
||||
extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env, jobject obj) {
|
||||
ILOG("NativeApp.displayInit()");
|
||||
if (javaGL && !graphicsContext) {
|
||||
graphicsContext = new AndroidJavaEGLGraphicsContext();
|
||||
}
|
||||
|
||||
if (!renderer_inited) {
|
||||
NativeInitGraphics(graphicsContext);
|
||||
renderer_inited = true;
|
||||
} else {
|
||||
NativeDeviceRestore(); // ???
|
||||
ILOG("displayInit: NativeDeviceRestore completed.");
|
||||
}
|
||||
}
|
||||
|
||||
// JavaEGL
|
||||
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;
|
||||
|
||||
pixel_xres = w;
|
||||
pixel_yres = h;
|
||||
// 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;
|
||||
|
||||
NativeResized();
|
||||
}
|
||||
|
||||
// JavaEGL
|
||||
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(graphicsContext);
|
||||
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;
|
||||
}
|
||||
|
||||
ProcessFrameCommands(env);
|
||||
}
|
||||
|
||||
extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayShutdown(JNIEnv *env, jobject obj) {
|
||||
ILOG("NativeApp.displayShutdown()");
|
||||
if (renderer_inited) {
|
||||
NativeShutdownGraphics();
|
||||
renderer_inited = false;
|
||||
NativeMessageReceived("recreateviews", "");
|
||||
}
|
||||
@ -427,6 +548,7 @@ PermissionStatus System_GetPermissionStatus(SystemPermission permission) {
|
||||
|
||||
extern "C" jboolean JNICALL Java_org_ppsspp_ppsspp_NativeApp_touch
|
||||
(JNIEnv *, jclass, float x, float y, int code, int pointerId) {
|
||||
|
||||
float scaledX = x * dp_xscale;
|
||||
float scaledY = y * dp_yscale;
|
||||
|
||||
@ -679,7 +801,7 @@ extern "C" jint JNICALL Java_org_ppsspp_ppsspp_NativeApp_getDesiredBackbufferHei
|
||||
return desiredBackbufferSizeY;
|
||||
}
|
||||
|
||||
void ProcessFrameCommands(JNIEnv *env) {
|
||||
static void ProcessFrameCommands(JNIEnv *env) {
|
||||
lock_guard guard(frameCommandLock);
|
||||
while (!frameCommands.empty()) {
|
||||
FrameCommand frameCmd;
|
||||
@ -757,9 +879,6 @@ extern "C" bool JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runEGLRenderLoop(J
|
||||
ILOG("After render loop.");
|
||||
g_gameInfoCache->WorkQueue()->Flush();
|
||||
|
||||
NativeDeviceLost();
|
||||
ILOG("NativeDeviceLost completed.");
|
||||
|
||||
NativeShutdownGraphics();
|
||||
renderer_inited = false;
|
||||
|
||||
|
@ -9,6 +9,7 @@ import android.Manifest;
|
||||
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,9 +17,11 @@ 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;
|
||||
@ -38,6 +41,7 @@ import android.view.HapticFeedbackConstants;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.view.View.OnSystemUiVisibilityChangeListener;
|
||||
import android.view.Window;
|
||||
@ -56,11 +60,18 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
// Allows us to skip a lot of initialization on secondary calls to onCreate.
|
||||
private static boolean initialized = false;
|
||||
|
||||
// Graphics and audio interfaces
|
||||
// Change this to false to switch to C++ EGL.
|
||||
private static boolean javaGL = true;
|
||||
|
||||
// Graphics and audio interfaces for EGL (javaGL = false)
|
||||
private NativeSurfaceView mSurfaceView;
|
||||
private Surface mSurface;
|
||||
private Thread mRenderLoopThread = null;
|
||||
|
||||
// Graphics and audio interfaces for Java EGL (javaGL = true)
|
||||
private NativeGLView mGLSurfaceView;
|
||||
protected NativeRenderer nativeRenderer;
|
||||
|
||||
private String shortcutParam = "";
|
||||
|
||||
public static String runCommand;
|
||||
@ -95,6 +106,10 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
return true;
|
||||
}
|
||||
|
||||
NativeRenderer getRenderer() {
|
||||
return nativeRenderer;
|
||||
}
|
||||
|
||||
@TargetApi(17)
|
||||
private void detectOptimalAudioSettings() {
|
||||
try {
|
||||
@ -207,8 +222,13 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
detectOptimalAudioSettings();
|
||||
}
|
||||
|
||||
// Get system information
|
||||
// isLandscape is used to trigger GetAppInfo currently, we
|
||||
boolean landscape = NativeApp.isLandscape();
|
||||
Log.d(TAG, "Landscape: " + landscape);
|
||||
|
||||
// Get system information
|
||||
ApplicationInfo appInfo = null;
|
||||
|
||||
PackageManager packMgmr = getPackageManager();
|
||||
String packageName = getPackageName();
|
||||
try {
|
||||
@ -246,10 +266,28 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
String languageRegion = Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry();
|
||||
|
||||
NativeApp.audioConfig(optimalFramesPerBuffer, optimalSampleRate);
|
||||
NativeApp.init(model, deviceType, languageRegion, apkFilePath, dataDir, externalStorageDir, libraryDir, cacheDir, shortcutParam, Build.VERSION.SDK_INT);
|
||||
NativeApp.init(model, deviceType, languageRegion, apkFilePath, dataDir, externalStorageDir, libraryDir, cacheDir, shortcutParam, Build.VERSION.SDK_INT, javaGL);
|
||||
|
||||
sendInitialGrants();
|
||||
|
||||
// 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();
|
||||
@ -352,6 +390,13 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
NativeApp.setDisplayParameters(outSize.x, outSize.y, metrics.densityDpi, refreshRate);
|
||||
}
|
||||
|
||||
public void getDesiredBackbufferSize(Point sz) {
|
||||
NativeApp.computeDesiredBackbufferDimensions();
|
||||
sz.x = NativeApp.getDesiredBackbufferWidth();
|
||||
sz.y = NativeApp.getDesiredBackbufferHeight();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@ -376,37 +421,78 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
gainAudioFocus(this.audioManager, this.audioFocusChangeListener);
|
||||
NativeApp.audioInit();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
updateSystemUiVisibility();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
setupSystemUiCallback();
|
||||
}
|
||||
}
|
||||
updateDisplayMetrics(null);
|
||||
if (javaGL) {
|
||||
mGLSurfaceView = new NativeGLView(this);
|
||||
nativeRenderer = new NativeRenderer(this);
|
||||
|
||||
NativeApp.computeDesiredBackbufferDimensions();
|
||||
int bbW = NativeApp.getDesiredBackbufferWidth();
|
||||
int bbH = NativeApp.getDesiredBackbufferHeight();
|
||||
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);
|
||||
|
||||
mSurfaceView = new NativeSurfaceView(NativeActivity.this, bbW, bbH);
|
||||
mSurfaceView.getHolder().addCallback(NativeActivity.this);
|
||||
Log.i(TAG, "setcontentview before");
|
||||
setContentView(mSurfaceView);
|
||||
Log.i(TAG, "setcontentview after");
|
||||
// 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.
|
||||
|
||||
ensureRenderLoop();
|
||||
// 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());
|
||||
}
|
||||
// Tried to mess around with config choosers here but fail completely on Xperia Play.
|
||||
|
||||
mGLSurfaceView.setRenderer(nativeRenderer);
|
||||
setContentView(mGLSurfaceView);
|
||||
} else {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
updateSystemUiVisibility();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
setupSystemUiCallback();
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
ensureRenderLoop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder)
|
||||
{
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
Log.d(TAG, "Surface created.");
|
||||
}
|
||||
|
||||
//
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
|
||||
{
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
if (javaGL) {
|
||||
Log.e(TAG, "JavaGL - should not get into surfaceChanged.");
|
||||
return;
|
||||
}
|
||||
|
||||
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...
|
||||
@ -425,6 +511,10 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
|
||||
// Invariants: After this, mRenderLoopThread will be set, and the thread will be running.
|
||||
protected synchronized void ensureRenderLoop() {
|
||||
if (javaGL) {
|
||||
Log.e(TAG, "JavaGL - should not get into ensureRenderLoop.");
|
||||
return;
|
||||
}
|
||||
if (mSurface == null) {
|
||||
Log.w(TAG, "ensureRenderLoop - not starting thread, needs surface");
|
||||
return;
|
||||
@ -439,6 +529,11 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
|
||||
// Invariants: After this, mRenderLoopThread will be null, and the thread has exited.
|
||||
private synchronized void joinRenderLoopThread() {
|
||||
if (javaGL) {
|
||||
Log.e(TAG, "JavaGL - should not get into joinRenderLoopThread.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mRenderLoopThread != null) {
|
||||
// This will wait until the thread has exited.
|
||||
Log.i(TAG, "exitEGLRenderLoop");
|
||||
@ -457,12 +552,16 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
if (javaGL) {
|
||||
Log.e(TAG, "JavaGL - should not get into surfaceDestroyed.");
|
||||
return;
|
||||
}
|
||||
|
||||
mSurface = null;
|
||||
Log.w(TAG, "Surface destroyed.");
|
||||
joinRenderLoopThread();
|
||||
}
|
||||
|
||||
|
||||
@TargetApi(19)
|
||||
void setupSystemUiCallback() {
|
||||
getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() {
|
||||
@ -484,15 +583,17 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
Log.i(TAG, "onDestroy");
|
||||
mSurfaceView.onDestroy();
|
||||
NativeApp.audioShutdown();
|
||||
// Probably vain attempt to help the garbage collector...
|
||||
mSurfaceView = null;
|
||||
audioFocusChangeListener = null;
|
||||
audioManager = null;
|
||||
unregisterCallbacks();
|
||||
|
||||
if (javaGL) {
|
||||
Log.i(TAG, "onDestroy");
|
||||
mGLSurfaceView.onDestroy();
|
||||
nativeRenderer.onDestroyed();
|
||||
NativeApp.audioShutdown();
|
||||
// Probably vain attempt to help the garbage collector...
|
||||
mGLSurfaceView = null;
|
||||
audioFocusChangeListener = null;
|
||||
audioManager = null;
|
||||
unregisterCallbacks();
|
||||
}
|
||||
if (shuttingDown) {
|
||||
NativeApp.shutdown();
|
||||
}
|
||||
@ -503,14 +604,35 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
super.onPause();
|
||||
Log.i(TAG, "onPause");
|
||||
loseAudioFocus(this.audioManager, this.audioFocusChangeListener);
|
||||
Log.i(TAG, "Pausing surface view");
|
||||
NativeApp.pause();
|
||||
mSurfaceView.onPause();
|
||||
Log.i(TAG, "Joining render thread");
|
||||
joinRenderLoopThread();
|
||||
if (!javaGL) {
|
||||
Log.i(TAG, "Pausing surface view");
|
||||
mSurfaceView.onPause();
|
||||
Log.i(TAG, "Joining render thread");
|
||||
joinRenderLoopThread();
|
||||
} else {
|
||||
if (mGLSurfaceView != null) {
|
||||
mGLSurfaceView.onPause();
|
||||
} else {
|
||||
Log.e(TAG, "mGLSurfaceView really shouldn't be null in onPause");
|
||||
}
|
||||
}
|
||||
Log.i(TAG, "onPause completed");
|
||||
}
|
||||
|
||||
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
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
@ -518,20 +640,26 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
updateSystemUiVisibility();
|
||||
}
|
||||
// OK, config should be initialized, we can query for screen rotation.
|
||||
updateScreenRotation();
|
||||
if (javaGL || Build.VERSION.SDK_INT >= 9) {
|
||||
updateScreenRotation();
|
||||
}
|
||||
|
||||
Log.i(TAG, "onResume");
|
||||
if (mSurfaceView != null) {
|
||||
mSurfaceView.onResume();
|
||||
} else {
|
||||
Log.e(TAG, "mGLSurfaceView really shouldn't be null in onResume");
|
||||
if (javaGL) {
|
||||
if (mGLSurfaceView != null) {
|
||||
mGLSurfaceView.onResume();
|
||||
} else {
|
||||
Log.e(TAG, "mGLSurfaceView really shouldn't be null in onResume");
|
||||
}
|
||||
}
|
||||
|
||||
gainAudioFocus(this.audioManager, this.audioFocusChangeListener);
|
||||
NativeApp.resume();
|
||||
|
||||
// Restart the render loop.
|
||||
ensureRenderLoop();
|
||||
if (!javaGL) {
|
||||
// Restart the render loop.
|
||||
ensureRenderLoop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -542,6 +670,13 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
updateSystemUiVisibility();
|
||||
}
|
||||
updateDisplayMetrics(null);
|
||||
if (javaGL) {
|
||||
Point sz = new Point();
|
||||
getDesiredBackbufferSize(sz);
|
||||
if (sz.x > 0) {
|
||||
mGLSurfaceView.getHolder().setFixedSize(sz.x/2, sz.y/2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//keep this static so we can call this even if we don't
|
||||
@ -775,7 +910,6 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@TargetApi(11)
|
||||
@SuppressWarnings("deprecation")
|
||||
private AlertDialog.Builder createDialogBuilderWithTheme() {
|
||||
@ -823,14 +957,14 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
.setTitle(title)
|
||||
.setPositiveButton(defaultAction, new DialogInterface.OnClickListener(){
|
||||
@Override
|
||||
public void onClick(DialogInterface d, int which) {
|
||||
NativeApp.sendMessage("inputbox_completed", title + ":" + input.getText().toString());
|
||||
public void onClick(DialogInterface d, int which) {
|
||||
NativeApp.sendMessage("inputbox_completed", input.getText().toString());
|
||||
d.dismiss();
|
||||
}
|
||||
})
|
||||
.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
|
||||
@Override
|
||||
public void onClick(DialogInterface d, int which) {
|
||||
public void onClick(DialogInterface d, int which) {
|
||||
NativeApp.sendMessage("inputbox_failed", "");
|
||||
d.cancel();
|
||||
}
|
||||
@ -841,6 +975,7 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
}
|
||||
|
||||
public boolean processCommand(String command, String params) {
|
||||
SurfaceView surfView = javaGL ? mGLSurfaceView : mSurfaceView;
|
||||
if (command.equals("launchBrowser")) {
|
||||
try {
|
||||
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(params));
|
||||
@ -916,18 +1051,18 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
toast.show();
|
||||
Log.i(TAG, params);
|
||||
return true;
|
||||
} else if (command.equals("showKeyboard") && mSurfaceView != null) {
|
||||
} else if (command.equals("showKeyboard") && surfView != 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(
|
||||
mSurfaceView.getApplicationWindowToken(),
|
||||
surfView.getApplicationWindowToken(),
|
||||
InputMethodManager.SHOW_FORCED, 0);
|
||||
return true;
|
||||
} else if (command.equals("hideKeyboard") && mSurfaceView != null) {
|
||||
} else if (command.equals("hideKeyboard") && surfView != null) {
|
||||
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
inputMethodManager.toggleSoftInputFromWindow(
|
||||
mSurfaceView.getApplicationWindowToken(),
|
||||
surfView.getApplicationWindowToken(),
|
||||
InputMethodManager.SHOW_FORCED, 0);
|
||||
return true;
|
||||
} else if (command.equals("inputbox")) {
|
||||
@ -941,7 +1076,7 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
Log.i(TAG, "Launching inputbox: " + title + " " + defString);
|
||||
inputBox(title, defString, "OK");
|
||||
return true;
|
||||
} else if (command.equals("vibrate") && mSurfaceView != null) {
|
||||
} else if (command.equals("vibrate") && surfView != null) {
|
||||
int milliseconds = -1;
|
||||
if (params != "") {
|
||||
try {
|
||||
@ -958,13 +1093,13 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
// permission.
|
||||
switch (milliseconds) {
|
||||
case -1:
|
||||
mSurfaceView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
|
||||
surfView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
|
||||
break;
|
||||
case -2:
|
||||
mSurfaceView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
|
||||
surfView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
|
||||
break;
|
||||
case -3:
|
||||
mSurfaceView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||
surfView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||
break;
|
||||
default:
|
||||
if (vibrator != null) {
|
||||
@ -978,16 +1113,21 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
|
||||
shuttingDown = true;
|
||||
finish();
|
||||
} else if (command.equals("rotate")) {
|
||||
updateScreenRotation();
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
Log.i(TAG, "Must recreate activity on rotation");
|
||||
}
|
||||
if (javaGL) {
|
||||
updateScreenRotation();
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
Log.i(TAG, "Must recreate activity on rotation");
|
||||
}
|
||||
} else {
|
||||
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();
|
||||
} else if (command.equals("ask_permission") && params.equals("storage")) {
|
||||
askForStoragePermission();
|
||||
|
@ -13,8 +13,7 @@ public class NativeApp {
|
||||
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, String languageRegion, String apkPath, String dataDir, String externalDir, String libraryDir, String cacheDir, String shortcutParam, int androidVersion);
|
||||
|
||||
public static native void init(String model, int deviceType, String languageRegion, String apkPath, String dataDir, String externalDir, String libraryDir, String cacheDir, String shortcutParam, int androidVersion, boolean javaGL);
|
||||
public static native void audioInit();
|
||||
public static native void audioShutdown();
|
||||
public static native void audioConfig(int optimalFramesPerBuffer, int optimalSampleRate);
|
||||
@ -57,3 +56,4 @@ public class NativeApp {
|
||||
|
||||
public static native String queryConfig(String queryName);
|
||||
}
|
||||
|
||||
|
213
android/src/org/ppsspp/ppsspp/NativeEGLConfigChooser.java
Normal file
213
android/src/org/ppsspp/ppsspp/NativeEGLConfigChooser.java
Normal file
@ -0,0 +1,213 @@
|
||||
package org.ppsspp.ppsspp;
|
||||
|
||||
import javax.microedition.khronos.egl.EGL10;
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.egl.EGLDisplay;
|
||||
|
||||
import android.graphics.PixelFormat;
|
||||
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;
|
||||
|
||||
NativeEGLConfigChooser() {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
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_TRANSPARENT_TYPE, EGL10.EGL_NONE
|
||||
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.
|
||||
// Though, that may be possible to fix by using EGL10.EGL_TRANSPARENT_TYPE, EGL10.EGL_NONE.
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
}
|
243
android/src/org/ppsspp/ppsspp/NativeGLView.java
Normal file
243
android/src/org/ppsspp/ppsspp/NativeGLView.java
Normal file
@ -0,0 +1,243 @@
|
||||
package org.ppsspp.ppsspp;
|
||||
|
||||
// Touch- and sensor-enabled GLSurfaceView.
|
||||
// Used when javaGL = true.
|
||||
//
|
||||
// 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.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.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import com.bda.controller.*;
|
||||
|
||||
public class NativeGLView extends GLSurfaceView implements SensorEventListener, ControllerListener {
|
||||
private static String TAG = "NativeGLView";
|
||||
private SensorManager mSensorManager;
|
||||
private Sensor mAccelerometer;
|
||||
|
||||
// Moga controller
|
||||
private Controller mController = null;
|
||||
private boolean isMogaPro = false;
|
||||
|
||||
NativeActivity mActivity;
|
||||
|
||||
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();
|
||||
}
|
||||
}*/
|
||||
|
||||
mSensorManager = (SensorManager)activity.getSystemService(Activity.SENSOR_SERVICE);
|
||||
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||
|
||||
mController = Controller.getInstance(activity);
|
||||
try {
|
||||
MogaHack.init(mController, activity);
|
||||
Log.i(TAG, "MOGA initialized");
|
||||
mController.setListener(this, new Handler());
|
||||
} catch (Exception e) {
|
||||
Log.i(TAG, "Moga failed to initialize");
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
|
||||
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;
|
||||
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:
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
if (ev.getActionIndex() == i)
|
||||
code = 2;
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
if (ev.getActionIndex() == i)
|
||||
code = 4;
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
code = 1;
|
||||
break;
|
||||
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(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;
|
||||
}
|
||||
// Can also look at event.timestamp for accuracy magic
|
||||
NativeApp.accelerometer(event.values[0], event.values[1], event.values[2]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
Log.i(TAG, "onPause");
|
||||
super.onPause();
|
||||
mSensorManager.unregisterListener(this);
|
||||
if (mController != null) {
|
||||
mController.onPause();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
Log.i(TAG, "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() {
|
||||
Log.i(TAG, "onDestroy");
|
||||
if (mController != null) {
|
||||
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:
|
||||
case KeyEvent.KEYCODE_DPAD_UP:
|
||||
case KeyEvent.KEYCODE_DPAD_LEFT:
|
||||
case KeyEvent.KEYCODE_DPAD_RIGHT:
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
boolean repeat = false; // Moga has no repeats?
|
||||
switch (event.getAction()) {
|
||||
case KeyEvent.ACTION_DOWN:
|
||||
NativeApp.keyDown(NativeApp.DEVICE_ID_PAD_0, event.getKeyCode(), repeat);
|
||||
break;
|
||||
case KeyEvent.ACTION_UP:
|
||||
NativeApp.keyUp(NativeApp.DEVICE_ID_PAD_0, event.getKeyCode());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// MOGA Controller - from ControllerListener
|
||||
@Override
|
||||
public void onMotionEvent(com.bda.controller.MotionEvent event) {
|
||||
NativeApp.joystickAxis(NativeApp.DEVICE_ID_PAD_0, com.bda.controller.MotionEvent.AXIS_X, event.getAxisValue(com.bda.controller.MotionEvent.AXIS_X));
|
||||
NativeApp.joystickAxis(NativeApp.DEVICE_ID_PAD_0, com.bda.controller.MotionEvent.AXIS_Y, event.getAxisValue(com.bda.controller.MotionEvent.AXIS_Y));
|
||||
NativeApp.joystickAxis(NativeApp.DEVICE_ID_PAD_0, com.bda.controller.MotionEvent.AXIS_Z, event.getAxisValue(com.bda.controller.MotionEvent.AXIS_Z));
|
||||
NativeApp.joystickAxis(NativeApp.DEVICE_ID_PAD_0, com.bda.controller.MotionEvent.AXIS_RZ, event.getAxisValue(com.bda.controller.MotionEvent.AXIS_RZ));
|
||||
NativeApp.joystickAxis(NativeApp.DEVICE_ID_PAD_0, com.bda.controller.MotionEvent.AXIS_LTRIGGER, event.getAxisValue(com.bda.controller.MotionEvent.AXIS_LTRIGGER));
|
||||
NativeApp.joystickAxis(NativeApp.DEVICE_ID_PAD_0, com.bda.controller.MotionEvent.AXIS_RTRIGGER, event.getAxisValue(com.bda.controller.MotionEvent.AXIS_RTRIGGER));
|
||||
}
|
||||
|
||||
// MOGA Controller - from ControllerListener
|
||||
@Override
|
||||
public void onStateEvent(StateEvent state) {
|
||||
switch (state.getState()) {
|
||||
case StateEvent.STATE_CONNECTION:
|
||||
switch (state.getAction()) {
|
||||
case StateEvent.ACTION_CONNECTED:
|
||||
Log.i(TAG, "Moga Connected");
|
||||
if (mController.getState(Controller.STATE_CURRENT_PRODUCT_VERSION) == Controller.ACTION_VERSION_MOGA) {
|
||||
NativeApp.sendMessage("moga", "Moga");
|
||||
} else {
|
||||
Log.i(TAG, "MOGA Pro detected");
|
||||
isMogaPro = true;
|
||||
NativeApp.sendMessage("moga", "MogaPro");
|
||||
}
|
||||
break;
|
||||
case StateEvent.ACTION_CONNECTING:
|
||||
Log.i(TAG, "Moga Connecting...");
|
||||
break;
|
||||
case StateEvent.ACTION_DISCONNECTED:
|
||||
Log.i(TAG, "Moga Disconnected (or simply Not connected)");
|
||||
NativeApp.sendMessage("moga", "");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case StateEvent.STATE_POWER_LOW:
|
||||
switch (state.getAction()) {
|
||||
case StateEvent.ACTION_TRUE:
|
||||
Log.i(TAG, "Moga Power Low");
|
||||
break;
|
||||
case StateEvent.ACTION_FALSE:
|
||||
Log.i(TAG, "Moga Power OK");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
94
android/src/org/ppsspp/ppsspp/NativeRenderer.java
Normal file
94
android/src/org/ppsspp/ppsspp/NativeRenderer.java
Normal file
@ -0,0 +1,94 @@
|
||||
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();
|
||||
}
|
@ -13,6 +13,8 @@ import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
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;
|
||||
@ -68,6 +70,8 @@ public class NativeSurfaceView extends SurfaceView implements SensorEventListene
|
||||
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;
|
||||
|
@ -2,6 +2,7 @@ package org.ppsspp.ppsspp;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Point;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Looper;
|
||||
@ -72,11 +73,11 @@ public class PpssppActivity extends NativeActivity {
|
||||
// (from app drawer or file explorer).
|
||||
Intent intent = getIntent();
|
||||
String action = intent.getAction();
|
||||
if(intent.ACTION_VIEW.equals(action))
|
||||
{
|
||||
if(Intent.ACTION_VIEW.equals(action))
|
||||
{
|
||||
String path = intent.getData().getPath();
|
||||
super.setShortcutParam(path);
|
||||
Toast.makeText(getApplicationContext(), path, Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(getApplicationContext(), path, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
else super.setShortcutParam(getIntent().getStringExtra(SHORTCUT_EXTRA_KEY));
|
||||
|
||||
@ -95,4 +96,4 @@ public class PpssppActivity extends NativeActivity {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,10 +52,13 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
|
||||
// Should not initialize anything screen-size-dependent - do that in NativeResized.
|
||||
void NativeInitGraphics(GraphicsContext *graphicsContext);
|
||||
|
||||
// Signals that you need to destroy and recreate all buffered OpenGL resources,
|
||||
// Signals that you need to forget all buffered OpenGL resources,
|
||||
// like textures, vbo etc.
|
||||
void NativeDeviceLost();
|
||||
|
||||
// Signals that it's time to recreate buffered OpenGL resources
|
||||
void NativeDeviceRestore();
|
||||
|
||||
// If you want to change DPI stuff (such as modifying dp_xres and dp_yres), this is the
|
||||
// place to do it. You should only read g_dpi_scale and pixel_xres and pixel_yres in this,
|
||||
// and only write dp_xres and dp_yres.
|
||||
|
@ -7,10 +7,11 @@
|
||||
std::vector<GfxResourceHolder *> *holders;
|
||||
|
||||
static bool inLost;
|
||||
static bool inRestore;
|
||||
|
||||
void register_gl_resource_holder(GfxResourceHolder *holder) {
|
||||
if (inLost) {
|
||||
FLOG("BAD: Should not call register_gl_resource_holder from lost path");
|
||||
if (inLost || inRestore) {
|
||||
FLOG("BAD: Should not call register_gl_resource_holder from lost/restore path");
|
||||
return;
|
||||
}
|
||||
if (holders) {
|
||||
@ -21,8 +22,8 @@ void register_gl_resource_holder(GfxResourceHolder *holder) {
|
||||
}
|
||||
|
||||
void unregister_gl_resource_holder(GfxResourceHolder *holder) {
|
||||
if (inLost) {
|
||||
FLOG("BAD: Should not call unregister_gl_resource_holder from lost path");
|
||||
if (inLost || inRestore) {
|
||||
FLOG("BAD: Should not call unregister_gl_resource_holder from lost/restore path");
|
||||
return;
|
||||
}
|
||||
if (holders) {
|
||||
@ -38,22 +39,22 @@ void unregister_gl_resource_holder(GfxResourceHolder *holder) {
|
||||
}
|
||||
}
|
||||
|
||||
void gl_lost() {
|
||||
inLost = true;
|
||||
void gl_restore() {
|
||||
inRestore = true;
|
||||
if (!holders) {
|
||||
WLOG("GL resource holder not initialized, cannot process lost request");
|
||||
inLost = false;
|
||||
WLOG("GL resource holder not initialized, cannot process restore request");
|
||||
inRestore = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: We should really do this when we get the context back, not during gl_lost...
|
||||
ILOG("gl_lost() restoring %i items:", (int)holders->size());
|
||||
ILOG("gl_restore() restoring %i items:", (int)holders->size());
|
||||
for (size_t i = 0; i < holders->size(); i++) {
|
||||
ILOG("GLLost(%i / %i, %p, %08x)", (int)(i + 1), (int) holders->size(), (*holders)[i], *((uint32_t *)((*holders)[i])));
|
||||
(*holders)[i]->GLLost();
|
||||
ILOG("gl_restore(%i / %i, %p, %08x)", (int)(i + 1), (int)holders->size(), (*holders)[i], *((uint32_t *)((*holders)[i])));
|
||||
(*holders)[i]->GLRestore();
|
||||
}
|
||||
ILOG("gl_lost() completed on %i items:", (int)holders->size());
|
||||
inLost = false;
|
||||
ILOG("gl_restore() completed on %i items:", (int)holders->size());
|
||||
inRestore = false;
|
||||
}
|
||||
|
||||
void gl_lost_manager_init() {
|
||||
|
@ -6,7 +6,7 @@
|
||||
class GfxResourceHolder {
|
||||
public:
|
||||
virtual ~GfxResourceHolder() {}
|
||||
virtual void GLLost() = 0;
|
||||
virtual void GLRestore() = 0;
|
||||
};
|
||||
|
||||
void gl_lost_manager_init();
|
||||
@ -15,5 +15,5 @@ void gl_lost_manager_shutdown();
|
||||
void register_gl_resource_holder(GfxResourceHolder *holder);
|
||||
void unregister_gl_resource_holder(GfxResourceHolder *holder);
|
||||
|
||||
// Notifies all objects about the loss.
|
||||
void gl_lost();
|
||||
// Notifies all objects that it's time to be restored.
|
||||
void gl_restore();
|
||||
|
@ -220,7 +220,7 @@ bool glsl_recompile(GLSLProgram *program, std::string *error_message) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLSLProgram::GLLost() {
|
||||
void GLSLProgram::GLRestore() {
|
||||
// Quoth http://developer.android.com/reference/android/opengl/GLSurfaceView.Renderer.html;
|
||||
// "Note that when the EGL context is lost, all OpenGL resources associated with that context will be automatically deleted.
|
||||
// You do not need to call the corresponding "glDelete" methods such as glDeleteTextures to manually delete these lost resources."
|
||||
@ -228,17 +228,16 @@ void GLSLProgram::GLLost() {
|
||||
// glDeleteShader(this->vsh_);
|
||||
// glDeleteShader(this->fsh_);
|
||||
// glDeleteProgram(this->program_);
|
||||
ILOG("Restoring GLSL program %s/%s",
|
||||
strlen(this->vshader_filename) > 0 ? this->vshader_filename : "(mem)",
|
||||
strlen(this->fshader_filename) > 0 ? this->fshader_filename : "(mem)");
|
||||
this->program_ = 0;
|
||||
this->vsh_ = 0;
|
||||
this->fsh_ = 0;
|
||||
ILOG("Restoring GLSL program %s/%s",
|
||||
strlen(this->vshader_filename) > 0 ? this->vshader_filename : "(mem)",
|
||||
strlen(this->fshader_filename) > 0 ? this->fshader_filename : "(mem)");
|
||||
glsl_recompile(this);
|
||||
// Note that uniforms are still lost, hopefully the client sets them every frame at a minimum...
|
||||
// Note that any shader uniforms are still lost, hopefully the client sets them every frame at a minimum...
|
||||
}
|
||||
|
||||
|
||||
int glsl_attrib_loc(const GLSLProgram *program, const char *name) {
|
||||
return glGetAttribLocation(program->program_, name);
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ struct GLSLProgram : public GfxResourceHolder {
|
||||
GLuint fsh_;
|
||||
GLuint program_;
|
||||
|
||||
void GLLost();
|
||||
void GLRestore() override;
|
||||
};
|
||||
|
||||
// C API, old skool. Not much point either...
|
||||
|
@ -164,7 +164,7 @@ public:
|
||||
glBindBuffer(target_, buffer_);
|
||||
}
|
||||
|
||||
void GLLost() override {
|
||||
void GLRestore() override {
|
||||
ILOG("Recreating vertex buffer after glLost");
|
||||
knownSize_ = 0; // Will cause a new glBufferData call. Should genBuffers again though?
|
||||
glGenBuffers(1, &buffer_);
|
||||
@ -239,7 +239,7 @@ public:
|
||||
void Apply(const void *base = nullptr);
|
||||
void Unapply();
|
||||
void Compile();
|
||||
void GLLost() override;
|
||||
void GLRestore() override;
|
||||
bool RequiresBuffer() override {
|
||||
return id_ != 0;
|
||||
}
|
||||
@ -280,7 +280,7 @@ public:
|
||||
void SetVector(const char *name, float *value, int n) override;
|
||||
void SetMatrix4x4(const char *name, const Matrix4x4 &value) override;
|
||||
|
||||
void GLLost() override {
|
||||
void GLRestore() override {
|
||||
vshader->Compile(vshader->GetSource().c_str());
|
||||
fshader->Compile(fshader->GetSource().c_str());
|
||||
Link();
|
||||
@ -466,13 +466,22 @@ public:
|
||||
glBindTexture(target_, tex_);
|
||||
}
|
||||
|
||||
void GLLost() override {
|
||||
// We lost our GL context - zero out the tex_.
|
||||
void GLRestore() override {
|
||||
// We can assume that the texture is gone.
|
||||
tex_ = 0;
|
||||
generatedMips_ = false;
|
||||
// Don't try to restore stuff, that's not what this is for. Lost just means
|
||||
// that all our textures and buffers are invalid.
|
||||
if (!filename_.empty()) {
|
||||
if (LoadFromFile(filename_.c_str())) {
|
||||
ILOG("Reloaded lost texture %s", filename_.c_str());
|
||||
} else {
|
||||
ELOG("Failed to reload lost texture %s", filename_.c_str());
|
||||
}
|
||||
} else {
|
||||
WLOG("Texture %p cannot be restored - has no filename", this);
|
||||
tex_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Finalize(int zim_flags) override;
|
||||
|
||||
private:
|
||||
@ -573,7 +582,7 @@ void Thin3DGLVertexFormat::Compile() {
|
||||
lastBase_ = -1;
|
||||
}
|
||||
|
||||
void Thin3DGLVertexFormat::GLLost() {
|
||||
void Thin3DGLVertexFormat::GLRestore() {
|
||||
Compile();
|
||||
}
|
||||
|
||||
|
@ -120,7 +120,7 @@ void UIContext::SetFontStyle(const UI::FontStyle &fontStyle) {
|
||||
*fontStyle_ = fontStyle;
|
||||
if (textDrawer_) {
|
||||
textDrawer_->SetFontScale(fontScaleX_, fontScaleY_);
|
||||
Text()->SetFont(fontStyle.fontName.c_str(), fontStyle.sizePts, fontStyle.flags);
|
||||
textDrawer_->SetFont(fontStyle.fontName.c_str(), fontStyle.sizePts, fontStyle.flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user