24 Commits

Author SHA1 Message Date
Aaron Culliney
ce974177b2 Correct link 2015-11-01 21:00:05 -08:00
Aaron Culliney
b524b5a068 Point to curated public domain images repo 2015-11-01 20:48:46 -08:00
Aaron Culliney
646d64cd92 Don't forget to clean up crash spam ;-) 2015-11-01 19:33:39 -08:00
Aaron Culliney
6de1cae478 Move nativeOnCreate back to proper position as first native call
- This runs discovery of CPU family
    - This sets up native crash handling
2015-11-01 19:26:34 -08:00
Aaron Culliney
4999471ade Work around black screen if someone went to joystick calibration from splash screen 2015-11-01 14:19:40 -08:00
Aaron Culliney
933e99c927 Bugfix Gingerbread GLSurfaceView lifecycle 2015-11-01 14:17:10 -08:00
Aaron Culliney
9a2044f75e Apparently not possible to query this early on Gingerbread devices 2015-11-01 13:43:09 -08:00
Aaron Culliney
3d634004cf Avoid reinitializing preferences every resume of GLView 2015-11-01 13:42:05 -08:00
Aaron Culliney
bf54615198 Refactor menu ownership and dismissal
- Fix incorrect iteration in dismissAll() that could lead to restarting CPU too early
    - Semi-lazy-loaded Apple2MainMenu (which depends on GLSurfaceView/Apple2View as main content) no longer owns
      Apple2SettingsMenu and Apple2DisksMenu
2015-11-01 12:44:31 -08:00
Aaron Culliney
521d1daccf Refactor app startup
- Make sure crash checking is performed as early as possible
    - Minimize calling complex native functions until after splash screen is dimissed
    - Do not attempt to setup/resume OpenGL until after splash screen is dimissed
2015-11-01 10:14:40 -08:00
Aaron Culliney
cbe8a734d0 Move CPU feature discovery into CTOR 2015-10-31 23:00:45 -07:00
Aaron Culliney
6c959a030c Remove unused public methods 2015-10-31 14:03:53 -07:00
Aaron Culliney
acdc8da64f Refactor pause/resume functions to be strictly CPU thread pause/resume 2015-10-31 14:01:47 -07:00
Aaron Culliney
e52f753bf3 Remove commented code 2015-10-31 10:35:24 -07:00
Aaron Culliney
d4adabda93 SNEAKY BUGFIX race condition between UI thread and CPU thread on disk insertion
- Previously we would start the CPU thread and then insert, which has been a long standing race condition, but
      possibly better exposed since the recent disk.c rephactor to use mmap I/O
    - This directly manifested on a Kindle Fire 1st Gen as a crash, and, anecdotally on other devices as a "stalled"
      disk read requiring a reboot of the virtual machine.  Yay for crappy devices helping to expose crappy code! (git
      blame me). =P
2015-10-30 23:19:33 -07:00
Aaron Culliney
20f79dc5eb Avoid buffer overflow
- Appears to fix a crash on Kindle Fire 1st Gen
2015-10-30 23:14:20 -07:00
Aaron Culliney
84fe0dd479 Fix crash on Nexus 10 device due to regfree()ing something not regcomp()ed 2015-10-30 23:12:12 -07:00
Aaron Culliney
5c4ab06612 Hopefully improve crash reporting on older devices by sending a crash summary (possibly in addition to the attachment) 2015-10-30 00:13:14 -07:00
Aaron Culliney
dcd77a4650 Allow and gracefully handle case when external files directory is null 2015-10-28 23:52:54 -07:00
Aaron Culliney
916a54fb4b Update README.md 2015-10-28 00:04:03 -07:00
Aaron Culliney
616428a03f Slightly improved DHIRES colors 2015-10-26 23:11:29 -07:00
Aaron Culliney
38dce3e212 Check if parent view exists as proxy for isShowing 2015-10-25 22:03:44 -07:00
Aaron Culliney
844d8b815b Losing trust with implementation(s) of Apple2MenuView.isShowing()
- This changes the behavior to rely on non-null status as proxy for showing
    - TODO : investigate why isShowing() appears to be a race/bogus
2015-10-25 21:00:16 -07:00
Aaron Culliney
997461318f Bump Android version code 2015-10-25 20:56:51 -07:00
19 changed files with 372 additions and 324 deletions

View File

@@ -27,8 +27,8 @@ android {
applicationId "org.deadc0de.apple2ix.basic"
minSdkVersion 10
targetSdkVersion 23
versionCode 3
versionName "1.0.0"
versionCode 4
versionName "1.0.1"
ndk {
moduleName "apple2ix"
}

View File

@@ -43,7 +43,7 @@ public abstract class Apple2AbstractMenu implements Apple2MenuView {
setup();
}
public synchronized void show() {
public void show() {
if (isShowing()) {
return;
}
@@ -59,7 +59,7 @@ public abstract class Apple2AbstractMenu implements Apple2MenuView {
}
public boolean isShowing() {
return mSettingsView.isShown();
return mSettingsView.getParent() != null;
}
public View getView() {

View File

@@ -15,7 +15,6 @@ import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Rect;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
@@ -25,12 +24,12 @@ import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.Toast;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.StringTokenizer;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -46,14 +45,14 @@ public class Apple2Activity extends Activity {
private Apple2View mView = null;
private Apple2SplashScreen mSplashScreen = null;
private Apple2MainMenu mMainMenu = null;
private Apple2SettingsMenu mSettingsMenu = null;
private Apple2DisksMenu mDisksMenu = null;
private ArrayList<Apple2MenuView> mMenuStack = new ArrayList<Apple2MenuView>();
private ArrayList<AlertDialog> mAlertDialogs = new ArrayList<AlertDialog>();
private AtomicBoolean mPausing = new AtomicBoolean(false);
private int mWidth = 0;
private int mHeight = 0;
private float[] mXCoords = new float[MAX_FINGERS];
private float[] mYCoords = new float[MAX_FINGERS];
@@ -90,17 +89,13 @@ public class Apple2Activity extends Activity {
private native void nativeOnCreate(String dataDir, int sampleRate, int monoBufferSize, int stereoBufferSize);
private native void nativeGraphicsInitialized(int width, int height);
private native void nativeGraphicsChanged(int width, int height);
private native void nativeOnKeyDown(int keyCode, int metaState);
private native void nativeOnKeyUp(int keyCode, int metaState);
private native void nativeOnResume(boolean isSystemResume);
public native void nativeEmulationResume();
public native void nativeOnPause(boolean isSystemPause);
public native void nativeEmulationPause();
public native void nativeOnQuit();
@@ -108,8 +103,6 @@ public class Apple2Activity extends Activity {
public native void nativeReboot();
public native void nativeRender();
public native void nativeChooseDisk(String path, boolean driveA, boolean readOnly);
public native void nativeEjectDisk(boolean driveA);
@@ -135,22 +128,17 @@ public class Apple2Activity extends Activity {
Log.e(TAG, "onCreate()");
// placeholder view on initial launch
if (mView == null) {
setContentView(new View(this));
}
Apple2CrashHandler.getInstance().initializeAndSetCustomExceptionHandler(this);
if (sNativeBarfed) {
Log.e(TAG, "NATIVE BARFED...", sNativeBarfedThrowable);
View view = new View(this);
setContentView(view);
return;
}
// run first-time initializations
if (!Apple2Preferences.FIRST_TIME_CONFIGURED.booleanValue(this)) {
Apple2DisksMenu.firstTime(this);
Apple2Preferences.KeypadPreset.IJKM_SPACE.apply(this);
}
Apple2Preferences.FIRST_TIME_CONFIGURED.saveBoolean(this, true);
// get device audio parameters for native OpenSLES
int sampleRate = DevicePropertyCalculator.getRecommendedSampleRate(this);
int monoBufferSize = DevicePropertyCalculator.getRecommendedBufferSize(this, /*isStereo:*/false);
int stereoBufferSize = DevicePropertyCalculator.getRecommendedBufferSize(this, /*isStereo:*/true);
@@ -159,31 +147,28 @@ public class Apple2Activity extends Activity {
String dataDir = Apple2DisksMenu.getDataDir(this);
nativeOnCreate(dataDir, sampleRate, monoBufferSize, stereoBufferSize);
// NOTE: load preferences after nativeOnCreate ... native CPU thread should still be paused
Apple2Preferences.loadPreferences(this);
showSplashScreen();
Apple2CrashHandler.getInstance().checkForCrashes(Apple2Activity.this);
mView = new Apple2View(this);
setContentView(mView);
// first-time initializations #1
if (!Apple2Preferences.FIRST_TIME_CONFIGURED.booleanValue(this)) {
Apple2DisksMenu.firstTime(this);
}
// Another Android Annoyance ...
// Even though we no longer use the system soft keyboard (which would definitely trigger width/height changes to our OpenGL canvas),
// we still need to listen to dimension changes, because it seems on some janky devices you have an incorrect width/height set when
// the initial OpenGL onSurfaceChanged() callback occurs. For now, include this defensive coding...
mView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
Rect rect = new Rect();
mView.getWindowVisibleDisplayFrame(rect);
int h = rect.height();
int w = rect.width();
if (w < h) {
// assure landscape dimensions
final int w_ = w;
w = h;
h = w_;
}
nativeGraphicsChanged(w, h);
mSettingsMenu = new Apple2SettingsMenu(this);
mDisksMenu = new Apple2DisksMenu(this);
Intent intent = getIntent();
String path = null;
if (intent != null) {
Uri data = intent.getData();
if (data != null) {
path = data.getPath();
}
});
}
if (path != null && Apple2DisksMenu.hasDiskExtension(path)) {
handleInsertDiskIntent(path);
}
}
@Override
@@ -195,8 +180,8 @@ public class Apple2Activity extends Activity {
}
Log.d(TAG, "onResume()");
mView.onResume();
nativeOnResume(/*isSystemResume:*/true);
showSplashScreen();
Apple2CrashHandler.getInstance().checkForCrashes(Apple2Activity.this); // NOTE : needs to be called again to clean-up
}
@Override
@@ -212,13 +197,15 @@ public class Apple2Activity extends Activity {
}
Log.d(TAG, "onPause()");
mView.onPause();
if (mView != null) {
mView.onPause();
}
// Apparently not good to leave popup/dialog windows showing when backgrounding.
// Dismiss these popups to avoid android.view.WindowLeaked issues
synchronized (this) {
dismissAllMenus();
nativeOnPause(true);
nativeEmulationPause();
}
mPausing.set(false);
@@ -260,45 +247,6 @@ public class Apple2Activity extends Activity {
}
}
/*
private String actionToString(int action) {
switch (action) {
case MotionEvent.ACTION_CANCEL:
return "CANCEL:" + action;
case MotionEvent.ACTION_DOWN:
return "DOWN:" + action;
case MotionEvent.ACTION_MOVE:
return "MOVE:" + action;
case MotionEvent.ACTION_UP:
return "UP:" + action;
case MotionEvent.ACTION_POINTER_DOWN:
return "PDOWN:" + action;
case MotionEvent.ACTION_POINTER_UP:
return "PUP:" + action;
default:
return "UNK:" + action;
}
}
private void printSamples(MotionEvent ev) {
final int historySize = ev.getHistorySize();
final int pointerCount = ev.getPointerCount();
for (int h = 0; h < historySize; h++) {
Log.d(TAG, "Event "+ev.getAction().toString()+" at historical time "+ev.getHistoricalEventTime(h)+" :");
for (int p = 0; p < pointerCount; p++) {
Log.d(TAG, " pointer "+ev.getPointerId(p)+": ("+ev.getHistoricalX(p, h)+","+ev.getHistoricalY(p, h)+")");
}
}
int pointerIndex = ev.getActionIndex();
Log.d(TAG, "Event " + actionToString(ev.getActionMasked()) + " for " + pointerIndex + " at time " + ev.getEventTime() + " :");
for (int p = 0; p < pointerCount; p++) {
Log.d(TAG, " pointer " + ev.getPointerId(p) + ": (" + ev.getX(p) + "," + ev.getY(p) + ")");
}
}
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
do {
@@ -394,44 +342,9 @@ public class Apple2Activity extends Activity {
return super.onTouchEvent(event);
}
void graphicsInitialized(int w, int h) {
if (mMainMenu == null) {
mMainMenu = new Apple2MainMenu(this, mView);
}
if (w < h) {
// assure landscape dimensions
final int w_ = w;
w = h;
h = w_;
}
mWidth = w;
mHeight = h;
// tell native about this...
nativeGraphicsInitialized(w, h);
showSplashScreen();
Intent intent = getIntent();
String path = null;
if (intent != null) {
Uri data = intent.getData();
if (data != null) {
path = data.getPath();
}
}
if (path != null && Apple2DisksMenu.hasDiskExtension(path)) {
handleInsertDiskIntent(path);
}
}
public void showMainMenu() {
if (mMainMenu != null) {
Apple2SettingsMenu settingsMenu = mMainMenu.getSettingsMenu();
Apple2DisksMenu disksMenu = mMainMenu.getDisksMenu();
if (!(settingsMenu.isShowing() || disksMenu.isShowing())) {
if (!(mSettingsMenu.isShowing() || mDisksMenu.isShowing())) {
mMainMenu.show();
}
}
@@ -441,6 +354,14 @@ public class Apple2Activity extends Activity {
return mMainMenu;
}
public synchronized Apple2DisksMenu getDisksMenu() {
return mDisksMenu;
}
public synchronized Apple2SettingsMenu getSettingsMenu() {
return mSettingsMenu;
}
private void handleInsertDiskIntent(final String path) {
runOnUiThread(new Runnable() {
@Override
@@ -464,15 +385,17 @@ public class Apple2Activity extends Activity {
}
Apple2Preferences.CURRENT_DISK_A.saveString(Apple2Activity.this, diskPath);
Apple2DisksMenu disksMenu = mMainMenu.getDisksMenu();
while (disksMenu.popPathStack() != null) {
while (mDisksMenu.popPathStack() != null) {
/* ... */
}
String storageDir = Apple2DisksMenu.getExternalStorageDirectory().getAbsolutePath();
if (diskPath.contains(storageDir)) {
diskPath = diskPath.replace(storageDir + File.separator, "");
disksMenu.pushPathStack(storageDir);
File storageDir = Apple2DisksMenu.getExternalStorageDirectory();
if (storageDir != null) {
String storagePath = storageDir.getAbsolutePath();
if (diskPath.contains(storagePath)) {
diskPath = diskPath.replace(storagePath + File.separator, "");
mDisksMenu.pushPathStack(storagePath);
}
}
StringTokenizer tokenizer = new StringTokenizer(diskPath, File.separator);
while (tokenizer.hasMoreTokens()) {
@@ -483,7 +406,7 @@ public class Apple2Activity extends Activity {
if (Apple2DisksMenu.hasDiskExtension(token)) {
continue;
}
disksMenu.pushPathStack(token);
mDisksMenu.pushPathStack(token);
}
Toast.makeText(Apple2Activity.this, Apple2Activity.this.getString(R.string.disk_insert_toast), Toast.LENGTH_SHORT).show();
@@ -493,21 +416,28 @@ public class Apple2Activity extends Activity {
}
private void showSplashScreen() {
runOnUiThread(new Runnable() {
@Override
public void run() {
synchronized (Apple2Activity.this) {
if (mSplashScreen == null) {
mSplashScreen = new Apple2SplashScreen(Apple2Activity.this);
}
if (mSplashScreen.isShowing()) {
return;
}
mSplashScreen.show();
Apple2CrashHandler.getInstance().checkForCrashes(Apple2Activity.this);
}
}
});
if (mSplashScreen != null) {
return;
}
mSplashScreen = new Apple2SplashScreen(Apple2Activity.this);
mSplashScreen.show();
}
private void setupGLView() {
boolean glViewFirstTime = false;
if (mView == null) {
glViewFirstTime = true;
mView = new Apple2View(this);
mMainMenu = new Apple2MainMenu(this, mView);
}
if (glViewFirstTime) {
// HACK NOTE : do not blanket setContentView() ... it appears to wedge Gingerbread
setContentView(mView);
} else {
mView.onResume();
}
}
public void registerAndShowDialog(AlertDialog dialog) {
@@ -518,8 +448,8 @@ public class Apple2Activity extends Activity {
public synchronized void pushApple2View(Apple2MenuView apple2MenuView) {
mMenuStack.add(apple2MenuView);
View menuView = apple2MenuView.getView();
nativeOnPause(false);
addContentView(menuView, new FrameLayout.LayoutParams(getWidth(), getHeight()));
nativeEmulationPause();
addContentView(menuView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
}
public synchronized Apple2MenuView popApple2View() {
@@ -566,13 +496,11 @@ public class Apple2Activity extends Activity {
mAlertDialogs.clear();
// Get rid of the menu hierarchy
Apple2MenuView apple2MenuView;
do {
apple2MenuView = popApple2View();
if (apple2MenuView != null) {
apple2MenuView.dismissAll();
}
} while (apple2MenuView != null);
ArrayList<Apple2MenuView> menuHierarchy = new ArrayList<Apple2MenuView>(mMenuStack);
Collections.reverse(menuHierarchy);
for (Apple2MenuView view : menuHierarchy) {
view.dismissAll();
}
}
public synchronized Apple2MenuView popApple2View(Apple2MenuView apple2MenuView) {
@@ -583,43 +511,42 @@ public class Apple2Activity extends Activity {
private void _disposeApple2View(Apple2MenuView apple2MenuView) {
boolean dismissedSplashScreen = false;
// Actually remove View from view hierarchy
{
View menuView = apple2MenuView.getView();
if (menuView.isShown()) {
((ViewGroup) menuView.getParent()).removeView(menuView);
ViewGroup viewGroup = (ViewGroup) menuView.getParent();
if (viewGroup != null) {
viewGroup.removeView(menuView);
}
if (apple2MenuView instanceof Apple2SplashScreen) { // 20151101 HACK NOTE : use instanceof to avoid edge case where joystick calibration occurred (and thus the splash was already dismissed without proper mView initialization)
mSplashScreen = null;
dismissedSplashScreen = true;
}
}
// if no more views on menu stack, resume emulation
if (mMenuStack.size() == 0) {
dismissAllMenus();
dismissAllMenus(); // NOTE : at this point, this should not be re-entrant into mMenuStack, it should just dismiss lingering popups
if (!mPausing.get()) {
if (dismissedSplashScreen) {
setupGLView();
} else {
nativeEmulationResume();
}
}
}
}
public void maybeResumeCPU() {
if (mMenuStack.size() == 0 && !mPausing.get()) {
nativeOnResume(/*isSystemResume:*/false);
nativeEmulationResume();
}
}
void _mainMenuDismissed() {
if (mMenuStack.size() == 0 && !mPausing.get()) {
nativeOnResume(/*isSystemResume:*/false);
}
}
public Apple2View getView() {
return mView;
}
public int getWidth() {
return mWidth;
}
public int getHeight() {
return mHeight;
}
public void maybeQuitApp() {
nativeOnPause(false);
nativeEmulationPause();
AlertDialog quitDialog = new AlertDialog.Builder(this).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.quit_really).setMessage(R.string.quit_warning).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
@@ -642,7 +569,7 @@ public class Apple2Activity extends Activity {
}
public void maybeReboot() {
nativeOnPause(false);
nativeEmulationPause();
AlertDialog rebootDialog = new AlertDialog.Builder(this).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.reboot_really).setMessage(R.string.reboot_warning).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {

View File

@@ -204,19 +204,22 @@ public class Apple2CrashHandler {
final int monoBufferSize = DevicePropertyCalculator.getRecommendedBufferSize(activity, /*isStereo:*/false);
final int stereoBufferSize = DevicePropertyCalculator.getRecommendedBufferSize(activity, /*isStereo:*/true);
StringBuilder summary = new StringBuilder();
StringBuilder allCrashData = new StringBuilder();
// prepend information about this device
allCrashData.append("BRAND: ").append(Build.BRAND).append("\n");
allCrashData.append("MODEL: ").append(Build.MODEL).append("\n");
allCrashData.append("MANUFACTURER: ").append(Build.MANUFACTURER).append("\n");
allCrashData.append("DEVICE: ").append(Build.DEVICE).append("\n");
allCrashData.append("SAMPLE RATE: ").append(sampleRate).append("\n");
allCrashData.append("MONO BUFSIZE: ").append(monoBufferSize).append("\n");
allCrashData.append("STEREO BUFSIZE: ").append(stereoBufferSize).append("\n");
allCrashData.append("GPU VENDOR: ").append(Apple2Preferences.GL_VENDOR.stringValue(activity)).append("\n");
allCrashData.append("GPU RENDERER: ").append(Apple2Preferences.GL_RENDERER.stringValue(activity)).append("\n");
allCrashData.append("GPU VERSION: ").append(Apple2Preferences.GL_VERSION.stringValue(activity)).append("\n");
summary.append("BRAND: ").append(Build.BRAND).append("\n");
summary.append("MODEL: ").append(Build.MODEL).append("\n");
summary.append("MANUFACTURER: ").append(Build.MANUFACTURER).append("\n");
summary.append("DEVICE: ").append(Build.DEVICE).append("\n");
summary.append("SAMPLE RATE: ").append(sampleRate).append("\n");
summary.append("MONO BUFSIZE: ").append(monoBufferSize).append("\n");
summary.append("STEREO BUFSIZE: ").append(stereoBufferSize).append("\n");
summary.append("GPU VENDOR: ").append(Apple2Preferences.GL_VENDOR.stringValue(activity)).append("\n");
summary.append("GPU RENDERER: ").append(Apple2Preferences.GL_RENDERER.stringValue(activity)).append("\n");
summary.append("GPU VERSION: ").append(Apple2Preferences.GL_VERSION.stringValue(activity)).append("\n");
allCrashData.append(summary);
File[] nativeCrashes = _nativeCrashFiles(activity);
if (nativeCrashes == null) {
@@ -247,6 +250,8 @@ public class Apple2CrashHandler {
}
});
boolean summarizedHeader = false;
// iteratively process native crashes
for (File crash : nativeCrashes) {
@@ -266,6 +271,48 @@ public class Apple2CrashHandler {
}
allCrashData.append(">>>>>>> NATIVE CRASH [").append(crashPath).append("]\n");
allCrashData.append(crashData);
summary.append("NATIVE CRASH:\n");
// append succinct information about crashing thread
String[] lines = crashData.toString().split("[\\n\\r][\\n\\r]*");
for (int i = 0, j = 0; i < lines.length; i++) {
// 2 lines of minidump summary
if (i < 2) {
if (!summarizedHeader) {
summary.append(lines[i]);
summary.append("\n");
}
continue;
}
// 1 line of crashing thread and reason
if (i == 2) {
summarizedHeader = true;
summary.append(lines[i]);
summary.append("\n");
continue;
}
// whole lotta modules
if (lines[i].startsWith("Module")) {
continue;
}
// one apparently empty line
if (lines[i].matches("^[ \\t]*$")) {
continue;
}
// append crashing thread backtrace
summary.append(lines[i]);
summary.append("\n");
final int maxSummaryBacktrace = 8;
if (j++ >= maxSummaryBacktrace) {
break;
}
}
activity.runOnUiThread(new Runnable() {
@Override
@@ -288,6 +335,10 @@ public class Apple2CrashHandler {
allCrashData.append(">>>>>>> JAVA CRASH DATA\n");
allCrashData.append(javaCrashData);
summary.append("JAVA CRASH:\n");
summary.append(javaCrashData);
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
@@ -313,7 +364,7 @@ public class Apple2CrashHandler {
});
// send report with all the data
_sendEmailToDeveloperWithCrashData(activity, allCrashData);
_sendEmailToDeveloperWithCrashData(activity, summary, allCrashData);
}
}).start();
}
@@ -481,19 +532,25 @@ public class Apple2CrashHandler {
return allCrashFile;
}
private void _sendEmailToDeveloperWithCrashData(Apple2Activity activity, StringBuilder allCrashData) {
private void _sendEmailToDeveloperWithCrashData(Apple2Activity activity, StringBuilder summary, StringBuilder allCrashData) {
mAlreadySentReport.set(true);
// <sigh> ... the disaster that is early Android ... there does not appear to be a reliable way to start an
// email Intent to send both text and an attachment, but we make a valiant (if futile) effort to do so here.
// And the reason to send an attachment is that you trigger an android.os.TransactionTooLargeException with too
// much text data in the EXTRA_TEXT ... </sigh>
Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", "apple2ix_crash@deadcode.org"/*non-zero variant is correct endpoint at the moment*/, null));
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Crasher");
File allCrashFile = _writeTempLogFile(activity, allCrashData);
// Putting all the text data into the EXTRA_TEXT appears to trigger android.os.TransactionTooLargeException ...
//emailIntent.putExtra(Intent.EXTRA_TEXT, allCrashData.toString());
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(allCrashFile));
final int maxCharsEmail = 4096;
int len = summary.length();
len = len < maxCharsEmail ? len : maxCharsEmail;
String summaryData = summary.substring(0, len);
emailIntent.putExtra(Intent.EXTRA_TEXT, "The app crashed, please help!\n\n"+summaryData);
// But we can put some text data
emailIntent.putExtra(Intent.EXTRA_TEXT, "Greeting Apple2ix developers! The app crashed, please help!");
File allCrashFile = _writeTempLogFile(activity, allCrashData);
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(allCrashFile));
Log.d(TAG, "STARTING CHOOSER FOR EMAIL ...");
activity.startActivity(Intent.createChooser(emailIntent, "Send email"));

View File

@@ -78,24 +78,36 @@ public class Apple2DisksMenu implements Apple2MenuView {
}
public static File getExternalStorageDirectory() {
if (sExternalFilesDir == null) {
do {
if (sExternalFilesDir != null) {
break;
}
String storageState = Environment.getExternalStorageState();
File externalDir = new File(Environment.getExternalStorageDirectory(), "apple2ix"); // /sdcard/apple2ix
sExternalFilesDir = null;
boolean externalStorageAvailable = storageState.equals(Environment.MEDIA_MOUNTED);
if (externalStorageAvailable) {
sExternalFilesDir = externalDir;
boolean made = sExternalFilesDir.mkdirs();
if (!storageState.equals(Environment.MEDIA_MOUNTED)) {
// 2015/10/28 : do not expose sExternalFilesDir/sDownloadFilesDir unless they are writable
break;
}
File externalStorageDir = Environment.getExternalStorageDirectory();
if (externalStorageDir == null) {
break;
}
File externalDir = new File(externalStorageDir, "apple2ix"); // /sdcard/apple2ix
if (!externalDir.exists()) {
boolean made = externalDir.mkdirs();
if (!made) {
Log.d(TAG, "WARNING: could not make directory : " + sExternalFilesDir);
break;
}
} else {
sExternalFilesDir = externalDir;
}
}
if (sDownloadFilesDir == null) {
sExternalFilesDir = externalDir;
sDownloadFilesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
}
} while (false);
return sExternalFilesDir;
}
@@ -134,7 +146,9 @@ public class Apple2DisksMenu implements Apple2MenuView {
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"shaders", /*to location:*/new File(sDataDir, "shaders").getAbsolutePath());
// expose keyboards to modding
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"keyboards", /*to location:*/sExternalFilesDir.getAbsolutePath());
if (sExternalFilesDir != null) {
recursivelyCopyAPKAssets(activity, /*from APK directory:*/"keyboards", /*to location:*/sExternalFilesDir.getAbsolutePath());
}
}
public static void exposeSymbols(Apple2Activity activity) {
@@ -184,7 +198,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
}
public boolean isShowing() {
return mDisksView.isShown();
return mDisksView.getParent() != null;
}
public View getView() {
@@ -437,7 +451,7 @@ public class Apple2DisksMenu implements Apple2MenuView {
int idx = 0;
if (includeExternalStoragePath) {
fileNames[idx] = sExternalFilesDir.getPath();
fileNames[idx] = sExternalFilesDir.getAbsolutePath();
isDirectory[idx] = true;
++idx;
}
@@ -601,8 +615,6 @@ public class Apple2DisksMenu implements Apple2MenuView {
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
mActivity.dismissAllMenus();
boolean isDriveA = diskA.isChecked();
boolean diskReadOnly = readOnly.isChecked();
if (isDriveA) {
@@ -612,6 +624,8 @@ public class Apple2DisksMenu implements Apple2MenuView {
Apple2Preferences.CURRENT_DISK_B_RO.saveBoolean(mActivity, diskReadOnly);
Apple2Preferences.CURRENT_DISK_B.saveString(mActivity, imageName);
}
dialog.dismiss();
mActivity.dismissAllMenus();
}
});

View File

@@ -114,7 +114,7 @@ public class Apple2JoystickCalibration implements Apple2MenuView {
}
public boolean isShowing() {
return mSettingsView.isShown();
return mSettingsView.getParent() != null;
}
public View getView() {

View File

@@ -249,7 +249,10 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu {
}
};
File[] files = extKeyboardDir.listFiles(kbdJsonFilter);
File[] files = null;
if (extKeyboardDir != null) {
files = extKeyboardDir.listFiles(kbdJsonFilter);
}
if (files == null) {
// read keyboard data from /data/data/...
File keyboardDir = new File(Apple2DisksMenu.getDataDir(activity) + File.separator + "keyboards");
@@ -270,7 +273,7 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu {
++idx;
}
final String keyboardDirName = extKeyboardDir.getPath();
final String keyboardDirName = extKeyboardDir == null ? "Keyboards" : extKeyboardDir.getPath();
_alertDialogHandleSelection(activity, keyboardDirName, titles, new IPreferenceLoadSave() {
@Override

View File

@@ -119,7 +119,7 @@ public class Apple2KeypadChooser implements Apple2MenuView {
}
public boolean isShowing() {
return mSettingsView.isShown();
return mSettingsView.getParent() != null;
}
public View getView() {

View File

@@ -36,8 +36,6 @@ public class Apple2MainMenu {
private Apple2Activity mActivity = null;
private Apple2View mParentView = null;
private PopupWindow mMainMenuPopup = null;
private Apple2SettingsMenu mSettingsMenu = null;
private Apple2DisksMenu mDisksMenu = null;
public Apple2MainMenu(Apple2Activity activity, Apple2View parent) {
mActivity = activity;
@@ -164,46 +162,29 @@ public class Apple2MainMenu {
mMainMenuPopup.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
boolean otherMenusShowing = (getSettingsMenu().isShowing() || getDisksMenu().isShowing());
if (!otherMenusShowing) {
Apple2MainMenu.this.mActivity._mainMenuDismissed();
}
Apple2MainMenu.this.mActivity.maybeResumeCPU();
}
});
}
public void showDisksMenu() {
Apple2DisksMenu disksMenu = getDisksMenu();
Apple2DisksMenu disksMenu = mActivity.getDisksMenu();
disksMenu.show();
mMainMenuPopup.dismiss();
}
public void showSettings() {
Apple2SettingsMenu settings = getSettingsMenu();
Apple2SettingsMenu settings = mActivity.getSettingsMenu();
settings.show();
mMainMenuPopup.dismiss();
}
public synchronized Apple2DisksMenu getDisksMenu() {
if (mDisksMenu == null) {
mDisksMenu = new Apple2DisksMenu(mActivity);
}
return mDisksMenu;
}
public synchronized Apple2SettingsMenu getSettingsMenu() {
if (mSettingsMenu == null) {
mSettingsMenu = new Apple2SettingsMenu(mActivity);
}
return mSettingsMenu;
}
public void show() {
if (mMainMenuPopup.isShowing()) {
return;
}
mActivity.nativeOnPause(false);
mActivity.nativeEmulationPause();
mMainMenuPopup.showAtLocation(mParentView, Gravity.CENTER, 0, 0);
}

View File

@@ -35,10 +35,7 @@ public enum Apple2Preferences {
CURRENT_DISK_PATH {
@Override
public void load(final Apple2Activity activity) {
Apple2MainMenu mainMenu = activity.getMainMenu();
if (mainMenu != null) {
mainMenu.getDisksMenu().setPathStackJSON(stringValue(activity));
}
activity.getDisksMenu().setPathStackJSON(stringValue(activity));
}
@Override

View File

@@ -46,9 +46,8 @@ public class Apple2SplashScreen implements Apple2MenuView {
prefsButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Apple2SettingsMenu settingsMenu = mActivity.getMainMenu().getSettingsMenu();
Apple2SettingsMenu settingsMenu = mActivity.getSettingsMenu();
settingsMenu.show();
Apple2SplashScreen.this.dismiss();
}
});
@@ -56,9 +55,8 @@ public class Apple2SplashScreen implements Apple2MenuView {
disksButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Apple2DisksMenu disksMenu = mActivity.getMainMenu().getDisksMenu();
Apple2DisksMenu disksMenu = mActivity.getDisksMenu();
disksMenu.show();
Apple2SplashScreen.this.dismiss();
}
});
}
@@ -71,7 +69,7 @@ public class Apple2SplashScreen implements Apple2MenuView {
/* ... */
}
public synchronized void show() {
public void show() {
if (isShowing()) {
return;
}
@@ -87,7 +85,7 @@ public class Apple2SplashScreen implements Apple2MenuView {
}
public boolean isShowing() {
return mSettingsView.isShown();
return mSettingsView.getParent() != null;
}
public View getView() {

View File

@@ -16,9 +16,13 @@
package org.deadc0de.apple2ix;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.util.Log;
import android.view.ViewTreeObserver;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
@@ -49,14 +53,17 @@ class Apple2View extends GLSurfaceView {
private final static boolean DEBUG = false;
private Apple2Activity mActivity = null;
private AtomicBoolean mInitialLaunch = new AtomicBoolean(true);
private static native void nativeGraphicsInitialized(int width, int height);
private static native void nativeGraphicsChanged(int width, int height);
private static native void nativeRender();
public Apple2View(Apple2Activity activity) {
super(activity.getApplication());
mActivity = activity;
setup(0, 0);
}
private void setup(int depth, int stencil) {
/* By default, GLSurfaceView() creates a RGB_565 opaque surface.
* If we want a translucent one, we should change the surface's
@@ -75,14 +82,36 @@ class Apple2View extends GLSurfaceView {
* custom config chooser. See ConfigChooser class definition
* below.
*/
setEGLConfigChooser(new ConfigChooser(8, 8, 8, 8, depth, stencil));
setEGLConfigChooser(new ConfigChooser(8, 8, 8, 8, /*depth:*/0, /*stencil:*/0));
/* Set the renderer responsible for frame rendering */
setRenderer(new Renderer());
// Another Android Annoyance ...
// Even though we no longer use the system soft keyboard (which would definitely trigger width/height changes to our OpenGL canvas),
// we still need to listen to dimension changes, because it seems on some janky devices you have an incorrect width/height set when
// the initial OpenGL onSurfaceChanged() callback occurs. For now, include this defensive coding...
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
Rect rect = new Rect();
Apple2View.this.getWindowVisibleDisplayFrame(rect);
int h = rect.height();
int w = rect.width();
if (w < h) {
// assure landscape dimensions
final int w_ = w;
w = h;
h = w_;
}
nativeGraphicsChanged(w, h);
}
});
}
private static class ContextFactory implements GLSurfaceView.EGLContextFactory {
private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
Log.w(TAG, "creating OpenGL ES 2.0 context");
checkEglError("Before eglCreateContext", egl);
@@ -295,17 +324,45 @@ class Apple2View extends GLSurfaceView {
}
private class Renderer implements GLSurfaceView.Renderer {
@Override
public void onDrawFrame(GL10 gl) {
Apple2View.this.mActivity.nativeRender();
nativeRender();
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
Apple2Preferences.GL_VENDOR.saveString(mActivity, GLES20.glGetString(GLES20.GL_VENDOR));
Apple2Preferences.GL_RENDERER.saveString(mActivity, GLES20.glGetString(GLES20.GL_RENDERER));
Apple2Preferences.GL_VERSION.saveString(mActivity, GLES20.glGetString(GLES20.GL_VERSION));
Apple2View.this.mActivity.graphicsInitialized(width, height);
Log.v(TAG, "graphicsInitialized(" + width + ", " + height + ")");
if (width < height) {
// assure landscape dimensions
final int w_ = width;
width = height;
height = w_;
}
nativeGraphicsInitialized(width, height);
// first-time initializations #2
if (!Apple2Preferences.FIRST_TIME_CONFIGURED.booleanValue(Apple2View.this.mActivity)) {
Apple2Preferences.KeypadPreset.IJKM_SPACE.apply(Apple2View.this.mActivity);
Apple2Preferences.FIRST_TIME_CONFIGURED.saveBoolean(Apple2View.this.mActivity, true);
}
// load preferences on each new process creation
if (mInitialLaunch.get()) {
mInitialLaunch.set(false);
Apple2Preferences.loadPreferences(Apple2View.this.mActivity);
}
Apple2View.this.mActivity.maybeResumeCPU();
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// Do nothing.
}

View File

@@ -1 +1 @@
../../disks
../../../apple2-images-pub/disks

View File

@@ -96,30 +96,8 @@ static inline int _androidTouchEvent2InterfaceEvent(jint action) {
}
}
// ----------------------------------------------------------------------------
// JNI functions
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnCreate(JNIEnv *env, jobject obj, jstring j_dataDir, jint sampleRate, jint monoBufferSize, jint stereoBufferSize) {
const char *dataDir = (*env)->GetStringUTFChars(env, j_dataDir, 0);
// Android lifecycle can call onCreate() multiple times...
if (data_dir) {
LOG("IGNORING multiple calls to nativeOnCreate ...");
return;
}
// Do not remove this deadc0de ... it forces a runtime load-library/link error on Gingerbread devices if we have
// incorrectly compiled the app against a later version of the NDK!!!
int pagesize = getpagesize();
LOG("PAGESIZE IS : %d", pagesize);
data_dir = strdup(dataDir);
if (crashHandler && crashHandler->init) {
crashHandler->init(data_dir);
}
(*env)->ReleaseStringUTFChars(env, j_dataDir, dataDir);
LOG("data_dir : %s", data_dir);
static void discover_cpu_family(void) {
LOG("Discovering CPU family...");
AndroidCpuFamily family = android_getCpuFamily();
uint64_t features = android_getCpuFeatures();
@@ -158,6 +136,34 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnCreate(JNIEnv *env, jobje
//android_arm64Arch = true;
android_armArchV7A = true;
}
}
// ----------------------------------------------------------------------------
// JNI functions
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnCreate(JNIEnv *env, jobject obj, jstring j_dataDir, jint sampleRate, jint monoBufferSize, jint stereoBufferSize) {
const char *dataDir = (*env)->GetStringUTFChars(env, j_dataDir, 0);
// Android lifecycle can call onCreate() multiple times...
if (data_dir) {
LOG("IGNORING multiple calls to nativeOnCreate ...");
return;
}
discover_cpu_family();
// Do not remove this deadc0de ... it forces a runtime load-library/link error on Gingerbread devices if we have
// incorrectly compiled the app against a later version of the NDK!!!
int pagesize = getpagesize();
LOG("PAGESIZE IS : %d", pagesize);
data_dir = strdup(dataDir);
if (crashHandler && crashHandler->init) {
crashHandler->init(data_dir);
}
(*env)->ReleaseStringUTFChars(env, j_dataDir, dataDir);
LOG("data_dir : %s", data_dir);
android_deviceSampleRateHz = (unsigned long)sampleRate;
android_monoBufferSubmitSizeSamples = (unsigned long)monoBufferSize;
@@ -173,34 +179,33 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnCreate(JNIEnv *env, jobje
#endif
}
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeGraphicsChanged(JNIEnv *env, jobject obj, jint width, jint height) {
void Java_org_deadc0de_apple2ix_Apple2View_nativeGraphicsChanged(JNIEnv *env, jclass cls, jint width, jint height) {
// WARNING : this can happen on non-GL thread
LOG("...");
video_backend->reshape(width, height);
}
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeGraphicsInitialized(JNIEnv *env, jobject obj, jint width, jint height) {
void Java_org_deadc0de_apple2ix_Apple2View_nativeGraphicsInitialized(JNIEnv *env, jclass cls, jint width, jint height) {
// WANRING : this needs to happen on the GL thread only
LOG("width:%d height:%d", width, height);
video_shutdown();
video_backend->reshape(width, height);
video_backend->init((void *)0);
}
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnResume(JNIEnv *env, jobject obj, jboolean isSystemResume) {
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeEmulationResume(JNIEnv *env, jobject obj) {
if (!cpu_isPaused()) {
return;
}
LOG("...");
if (!isSystemResume) {
#if TESTING
// test driver thread is managing CPU
// test driver thread is managing CPU
#else
cpu_resume();
cpu_resume();
#endif
}
}
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnPause(JNIEnv *env, jobject obj, jboolean isSystemPause) {
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeEmulationPause(JNIEnv *env, jobject obj) {
if (appState != APP_RUNNING) {
return;
}
@@ -216,7 +221,7 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnPause(JNIEnv *env, jobjec
#endif
}
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeRender(JNIEnv *env, jobject obj) {
void Java_org_deadc0de_apple2ix_Apple2View_nativeRender(JNIEnv *env, jclass cls) {
SCOPE_TRACE_VIDEO("nativeRender");
if (UNLIKELY(appState != APP_RUNNING)) {
@@ -311,6 +316,8 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeChooseDisk(JNIEnv *env, job
int drive = driveA ? 0 : 1;
int ro = readOnly ? 1 : 0;
assert(cpu_isPaused() && "considered dangerous to insert disk image when CPU thread is running");
LOG(": (%s, %s, %s)", path, driveA ? "drive A" : "drive B", readOnly ? "read only" : "read/write");
if (disk6_insert(drive, path, ro)) {
char *gzPath = NULL;

View File

@@ -23,7 +23,7 @@ Project Goals
Android
-------
Currently pre-alpha testing the Google Play Store version...PM me if you would like to be on the Android VIP testers invite =D
[Available on Google Play](https://play.google.com/store/apps/details?id=org.deadc0de.apple2ix.basic).
Running at 30FPS on Gingerbread (Android 2.3.3):
![Apple2ix on Samsung Galaxy Y running Gingerbread](https://raw.github.com/mauiaaron/apple2/develop/docs/android-galaxyY.png "Apple //ix")

View File

@@ -417,7 +417,7 @@ static long opensl_createSoundBuffer(const AudioContext_s *audio_context, INOUT
unsigned long bufferSize = opensles_audio_backend.systemSettings.stereoBufferSizeSamples * opensles_audio_backend.systemSettings.bytesPerSample * NUM_CHANNELS;
if (ctx->recycledVoices) {
LOG("Recycling previously SLVoice ...");
LOG("Recycling previous SLVoice ...");
voice = ctx->recycledVoices;
ctx->recycledVoices = voice->next;
uint8_t *prevBuffer = voice->ringBuffer;

View File

@@ -307,6 +307,13 @@ static unsigned int _submit_samples_buffer(const unsigned long num_channel_sampl
break;
}
unsigned long maxSpeakerBytes = channelsSampleRateHz * sizeof(int16_t);
if (system_buffer_size > maxSpeakerBytes) {
RELEASE_LOG("AVOIDING BUFOVER...");
system_buffer_size = maxSpeakerBytes;
}
memcpy(system_samples_buffer, &samples_buffer[samples_idx], system_buffer_size);
err = speakerBuffer->Unlock(speakerBuffer, system_buffer_size);

View File

@@ -72,24 +72,24 @@ unsigned short video__line_offset[TEXT_ROWS] = {
uint8_t video__dhires1[256] = {
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,
0x0,0x1,0x3,0x3,0x5,0x5,0x7,0x7,0x9,0x9,0xb,0xb,0xd,0xd,0xf,0xf,
0x0,0x1,0x2,0x3,0x6,0x5,0x6,0x7,0xa,0x9,0xa,0xb,0xe,0xd,0xe,0xf,
0x0,0x1,0x3,0x3,0x7,0x5,0x7,0x7,0xb,0x9,0xb,0xb,0xf,0xd,0xf,0xf,
0x0,0x1,0x2,0x3,0x4,0x4,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,
0x0,0x1,0x3,0x3,0x5,0x5,0x7,0x7,0xd,0x9,0xb,0xb,0xd,0xd,0xf,0xf,
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0xe,0x9,0xa,0xb,0xe,0xd,0xe,0xf,
0x0,0x1,0x7,0x3,0x7,0x5,0x7,0x7,0xf,0x9,0xb,0xb,0xf,0xd,0xf,0xf,
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,
};
uint8_t video__dhires2[256] = {
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x8,0x0,0xb,0x8,0xd,0x0,0x0,
0x1,0x1,0x1,0x1,0x0,0x5,0x1,0x1,0x0,0x9,0xb,0xb,0x0,0xd,0xf,0xf,
0x0,0x1,0x2,0x2,0x2,0x5,0x2,0x2,0x0,0xa,0xa,0xa,0xe,0xd,0x2,0x2,
0x3,0x3,0x3,0x3,0x7,0x5,0x7,0x7,0x0,0xb,0xb,0xb,0xf,0xd,0xf,0xf,
0x0,0x0,0x4,0x0,0x4,0x4,0x4,0x4,0xc,0x8,0x4,0x8,0xc,0xd,0x4,0x4,
0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0xd,0x4,0x4,0x4,0xd,0xd,0x4,0x4,
0x6,0x6,0x6,0x2,0xe,0x6,0x6,0x6,0xe,0xe,0xa,0xa,0xe,0x6,0xe,0x6,
0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0xf,0xf,0xb,0xb,0xf,0xf,0xf,0xf,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,
0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x9,0x9,0x9,0x9,0x9,0x9,0x9,0x9,
0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,
0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,
0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,
0x6,0x6,0x6,0x6,0x6,0x6,0x6,0x6,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,
0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,
};

View File

@@ -506,43 +506,45 @@ static void _gldriver_setup_hackarounds(void) {
return;
}
regex_t qualcommRegex = { 0 };
regex_t adrenoRegex = { 0 };
regex_t twoHundredRegex = { 0 };
regex_t twoHundredFiveRegex = { 0 };
do {
// As if we didn't have enough problems with Android ... Bionic's POSIX Regex support for android-10 appears
// very basic ... we can't match the word-boundary atomics \> \< \b ... sigh ... hopefully by the time there is
// an Adreno 2000 we can remove these hackarounds ;-)
regex_t qualcommRegex = { 0 };
int err = regcomp(&qualcommRegex, "qualcomm", REG_ICASE|REG_NOSUB|REG_EXTENDED);
if (err) {
LOG("Cannot compile regex : %d", err);
break;
}
int nomatch = regexec(&qualcommRegex, vendor, /*nmatch:*/0, /*pmatch:*/NULL, /*eflags:*/0);
regfree(&qualcommRegex);
if (nomatch) {
LOG("NO MATCH QUALCOMM >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
break;
}
regex_t adrenoRegex = { 0 };
err = regcomp(&adrenoRegex, "adreno", REG_ICASE|REG_NOSUB|REG_EXTENDED);
if (err) {
LOG("Cannot compile regex : %d", err);
break;
}
nomatch = regexec(&adrenoRegex, renderer, /*nmatch:*/0, /*pmatch:*/NULL, /*eflags:*/0);
regfree(&adrenoRegex);
if (nomatch) {
LOG("NO MATCH ADRENO >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
break;
}
regex_t twoHundredRegex = { 0 };
err = regcomp(&twoHundredRegex, "200", REG_ICASE|REG_NOSUB|REG_EXTENDED);
if (err) {
LOG("Cannot compile regex : %d", err);
break;
}
regex_t twoHundredFiveRegex = { 0 };
err = regcomp(&twoHundredFiveRegex, "205", REG_ICASE|REG_NOSUB|REG_EXTENDED);
if (err) {
LOG("Cannot compile regex : %d", err);
@@ -551,6 +553,9 @@ static void _gldriver_setup_hackarounds(void) {
int found200 = !regexec(&twoHundredRegex, renderer, /*nmatch:*/0, /*pmatch:*/NULL, /*eflags:*/0);
int found205 = !regexec(&twoHundredFiveRegex, renderer, /*nmatch:*/0, /*pmatch:*/NULL, /*eflags:*/0);
regfree(&twoHundredRegex);
regfree(&twoHundredFiveRegex);
if (found200) {
LOG("HACKING AROUND BROKEN ADRENO 200");
hackAroundBrokenAdreno200 = true;
@@ -563,11 +568,6 @@ static void _gldriver_setup_hackarounds(void) {
break;
}
} while (0);
regfree(&qualcommRegex);
regfree(&adrenoRegex);
regfree(&twoHundredRegex);
regfree(&twoHundredFiveRegex);
}
static void gldriver_init_common(void) {