testdisk appears to work and is rendering on Android

This commit is contained in:
Aaron Culliney 2015-02-24 16:03:21 -08:00
parent 1c7e707af9
commit bf1e15b6c9
9 changed files with 409 additions and 33 deletions

View File

@ -4,16 +4,17 @@
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="10"/>
<uses-feature android:glEsVersion="0x00020000"/>
<supports-screens android:resizeable="true" android:normalScreens="true" android:largeScreens="true" android:smallScreens="false"/>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.INTERNET" /> <!-- DEBUGGING ONLY -->
<application
android:debuggable="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
<activity
android:name=".Apple2Activity"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:screenOrientation="landscape"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation"
android:windowSoftInputMode="adjustPan">
<intent-filter>

1
Android/assets/disks Symbolic link
View File

@ -0,0 +1 @@
../../disks

View File

@ -0,0 +1 @@
../../../src/video/Basic.fsh

View File

@ -0,0 +1 @@
../../../src/video/Basic.vsh

View File

@ -11,29 +11,20 @@
#include <jni.h>
#include "common.h"
#define LAUNCH_WITHOUT_JAVA 0
#if LAUNCH_WITHOUT_JAVA
int main(int argc, char **argv) {
for (unsigned int i=0; i<10; i++) {
LOG("counter : %u", i);
sleep(1);
}
LOG("%s", "finished...");
}
#else
#include "video/renderer.h"
void Java_org_deadc0de_apple2_Apple2Activity_nativeOnCreate(JNIEnv *env, jobject obj, jstring j_dataDir) {
const char *dataDir = (*env)->GetStringUTFChars(env, j_dataDir, 0);
data_dir = strdup(dataDir);
(*env)->ReleaseStringUTFChars(env, j_dataDir, dataDir);
LOG("nativeOnCreate(%s)...", data_dir);
}
void Java_org_deadc0de_apple2_Apple2Activity_nativeGraphicsInitialized(JNIEnv *env, jobject obj, jint width, jint height) {
LOG("%s", "native graphicsInitialized...");
video_driver_reshape(width, height);
#if !TESTING
#warning FIXME TODO ...
// TODO ...
#else
char *local_argv[] = {
@ -44,24 +35,21 @@ void Java_org_deadc0de_apple2_Apple2Activity_nativeOnCreate(JNIEnv *env, jobject
for (char **p = &local_argv[0]; *p != NULL; p++) {
++local_argc;
}
#if defined(TEST_CPU)
# if defined(TEST_CPU)
extern int test_cpu(int, char *[]);
test_cpu(local_argc, local_argv);
#elif defined(TEST_VM)
# elif defined(TEST_VM)
extern int test_vm(int, char *[]);
test_vm(local_argc, local_argv);
#elif defined(TEST_DISPLAY)
# elif defined(TEST_DISPLAY)
extern int test_display(int, char *[]);
test_display(local_argc, local_argv);
#elif defined(TEST_DISK)
# elif defined(TEST_DISK)
extern int test_disk(int, char *[]);
test_disk(local_argc, local_argv);
#else
# error "OOPS, no tests specified"
#endif
exit(0);
# else
# error "OOPS, no tests specified"
# endif
#endif
}
@ -73,4 +61,29 @@ void Java_org_deadc0de_apple2_Apple2Activity_nativeOnPause(JNIEnv *env, jobject
LOG("%s", "native onPause...");
}
#endif // LAUNCH_WITHOUT_JAVA
void Java_org_deadc0de_apple2_Apple2Activity_nativeRender(JNIEnv *env, jobject obj) {
c_keys_handle_input(-1, 0, 0);
#define FPS_LOG 1
#if FPS_LOG
static uint32_t prevCount = 0;
static uint32_t idleCount = 0;
idleCount++;
static struct timespec prev = { 0 };
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
if (now.tv_sec != prev.tv_sec) {
LOG("native render() : %u", idleCount-prevCount);
prevCount = idleCount;
prev = now;
}
#endif
if (_vid_dirty) {
video_driver_render();
}
}

1
Android/jni/testdisk Symbolic link
View File

@ -0,0 +1 @@
build.sh

32
Android/jni/testdisk.mk Normal file
View File

@ -0,0 +1,32 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
PACKAGE_IDENTIFIER := "org.deadc0de.apple2"
PACKAGE_NAME := "apple2ix"
COMMON_SOURCES_MK := $(LOCAL_PATH)/sources.mk
include $(COMMON_SOURCES_MK)
# -----------------------------------------------------------------------------
# Android build config
LOCAL_MODULE := libapple2ix
LOCAL_SRC_FILES := jnihooks.c $(APPLE2_SRC_PATH)/test/testcommon.c $(APPLE2_SRC_PATH)/test/testdisk.c
LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) -DTEST_DISK -DTESTING=1 -DCPU_TRACING=1 -DDISK_TRACING=1 -DVM_TRACING=1
LOCAL_LDLIBS := -llog -landroid -lGLESv2 -lz
# Add assembly files first ... mostly for the benefit of the ARM assembler ...
ifeq ($(TARGET_ARCH_ABI),x86)
LOCAL_SRC_FILES += $(APPLE2_X86_SRC)
else
LOCAL_SRC_FILES += $(APPLE2_ARM_SRC)
endif
LOCAL_SRC_FILES += $(APPLE2_MAIN_SRC) $(APPLE2_META_SRC) $(APPLE2_VIDEO_SRC)
# Build a shared library and let Java/Dalvik drive
include $(BUILD_SHARED_LIBRARY)
# --OR-- Build an executable so native can drive this show
#include $(BUILD_EXECUTABLE)

View File

@ -19,7 +19,6 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import java.io.File;
import java.io.InputStream;
@ -34,6 +33,8 @@ public class Apple2Activity extends Activity {
private final static String PREFS_CONFIGURED = "prefs_configured";
private Apple2View mView = null;
static {
System.loadLibrary("apple2ix");
}
@ -41,6 +42,8 @@ public class Apple2Activity extends Activity {
private native void nativeOnCreate(String dataDir);
private native void nativeOnResume();
private native void nativeOnPause();
public native void nativeGraphicsInitialized(int width, int height);
public native void nativeRender();
// HACK NOTE 2015/02/22 : Apparently native code cannot easily access stuff in the APK ... so copy various resources
// out of the APK and into the /data/data/... for ease of access. Because this is FOSS software we don't care about
@ -129,20 +132,21 @@ public class Apple2Activity extends Activity {
String dataDir = firstTimeInitialization();
nativeOnCreate(dataDir);
TextView tv = new TextView(this);
tv.setText("Hello Apple2!");
setContentView(tv);
mView = new Apple2View(this);
setContentView(mView);
}
@Override
protected void onResume() {
super.onResume();
mView.onResume();
nativeOnResume();
}
@Override
protected void onPause() {
super.onPause();
mView.onPause();
nativeOnPause();
}
}

View File

@ -0,0 +1,322 @@
/*
* Apple // emulator for *nix
*
* This software package is subject to the GNU General Public License
* version 2 or later (your choice) as published by the Free Software
* Foundation.
*
* THERE ARE NO WARRANTIES WHATSOEVER.
*
*/
/*
* Sourced from AOSP "GL2JNI" sample code.
*/
package org.deadc0de.apple2;
import android.content.Context;
import android.graphics.PixelFormat;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.opengles.GL10;
/**
* A simple GLSurfaceView sub-class that demonstrate how to perform
* OpenGL ES 2.0 rendering into a GL Surface. Note the following important
* details:
*
* - The class must use a custom context factory to enable 2.0 rendering.
* See ContextFactory class definition below.
*
* - The class must use a custom EGLConfigChooser to be able to select
* an EGLConfig that supports 2.0. This is done by providing a config
* specification to eglChooseConfig() that has the attribute
* EGL10.ELG_RENDERABLE_TYPE containing the EGL_OPENGL_ES2_BIT flag
* set. See ConfigChooser class definition below.
*
* - The class must select the surface's format, then choose an EGLConfig
* that matches it exactly (with regards to red/green/blue/alpha channels
* bit depths). Failure to do so would result in an EGL_BAD_MATCH error.
*/
class Apple2View extends GLSurfaceView {
private final static String TAG = "Apple2View";
private final static boolean DEBUG = true;
private Apple2Activity mActivity = null;
private boolean inefficient8888 = true; // HACK FIXME TODO : rewrite GL code to accommodate 565 rendering ...
public Apple2View(Apple2Activity activity) {
super(activity.getApplication());
mActivity = activity;
init(inefficient8888, 0, 0);
}
public Apple2View(Apple2Activity activity, boolean translucent, int depth, int stencil) {
super(activity.getApplication());
mActivity = activity;
init(translucent, depth, stencil);
}
private void init(boolean translucent, 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
* format here, using PixelFormat.TRANSLUCENT for GL Surfaces
* is interpreted as any 32-bit surface with alpha by SurfaceFlinger.
*/
if (translucent) {
this.getHolder().setFormat(PixelFormat.TRANSLUCENT);
}
/* Setup the context factory for 2.0 rendering.
* See ContextFactory class definition below
*/
setEGLContextFactory(new ContextFactory());
/* We need to choose an EGLConfig that matches the format of
* our surface exactly. This is going to be done in our
* custom config chooser. See ConfigChooser class definition
* below.
*/
setEGLConfigChooser( translucent ?
new ConfigChooser(8, 8, 8, 8, depth, stencil) :
new ConfigChooser(5, 6, 5, 0, depth, stencil) );
/* Set the renderer responsible for frame rendering */
setRenderer(new Renderer());
}
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);
int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
checkEglError("After eglCreateContext", egl);
return context;
}
public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
egl.eglDestroyContext(display, context);
}
}
private static void checkEglError(String prompt, EGL10 egl) {
int error;
while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) {
Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error));
}
}
private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser {
public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) {
mRedSize = r;
mGreenSize = g;
mBlueSize = b;
mAlphaSize = a;
mDepthSize = depth;
mStencilSize = stencil;
}
/* This EGL config specification is used to specify 2.0 rendering.
* We use a minimum size of 4 bits for red/green/blue, but will
* perform actual matching in chooseConfig() below.
*/
private static int EGL_OPENGL_ES2_BIT = 4;
private static int[] s_configAttribs2 = {
EGL10.EGL_RED_SIZE, 4,
EGL10.EGL_GREEN_SIZE, 4,
EGL10.EGL_BLUE_SIZE, 4,
EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL10.EGL_NONE
};
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
// Get the number of minimally matching EGL configurations
int[] num_config = new int[1];
egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config);
int numConfigs = num_config[0];
if (numConfigs <= 0) {
throw new IllegalArgumentException("No configs match configSpec");
}
// Allocate then read the array of minimally matching EGL configs
EGLConfig[] configs = new EGLConfig[numConfigs];
egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config);
if (DEBUG) {
printConfigs(egl, display, configs);
}
// Now return the "best" one
EGLConfig best = chooseConfig(egl, display, configs);
if (DEBUG) {
Log.w(TAG, "BEST CONFIG : ");
printConfig(egl, display, best);
}
return best;
}
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {
for (EGLConfig config : configs) {
int d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0);
int s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0);
// We need at least mDepthSize and mStencilSize bits
if (d < mDepthSize || s < mStencilSize) {
continue;
}
// We want an *exact* match for red/green/blue/alpha
int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0);
int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0);
int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0);
int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0);
if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize) {
return config;
}
}
return null;
}
private int findConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config, int attribute, int defaultValue) {
if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
return mValue[0];
}
return defaultValue;
}
private void printConfigs(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {
int numConfigs = configs.length;
Log.w(TAG, String.format("%d configurations", numConfigs));
for (int i = 0; i < numConfigs; i++) {
Log.w(TAG, String.format("Configuration %d:\n", i));
printConfig(egl, display, configs[i]);
}
}
private void printConfig(EGL10 egl, EGLDisplay display, EGLConfig config) {
int[] attributes = {
EGL10.EGL_BUFFER_SIZE,
EGL10.EGL_ALPHA_SIZE,
EGL10.EGL_BLUE_SIZE,
EGL10.EGL_GREEN_SIZE,
EGL10.EGL_RED_SIZE,
EGL10.EGL_DEPTH_SIZE,
EGL10.EGL_STENCIL_SIZE,
EGL10.EGL_CONFIG_CAVEAT,
EGL10.EGL_CONFIG_ID,
EGL10.EGL_LEVEL,
EGL10.EGL_MAX_PBUFFER_HEIGHT,
EGL10.EGL_MAX_PBUFFER_PIXELS,
EGL10.EGL_MAX_PBUFFER_WIDTH,
EGL10.EGL_NATIVE_RENDERABLE,
EGL10.EGL_NATIVE_VISUAL_ID,
EGL10.EGL_NATIVE_VISUAL_TYPE,
0x3030, // EGL10.EGL_PRESERVED_RESOURCES,
EGL10.EGL_SAMPLES,
EGL10.EGL_SAMPLE_BUFFERS,
EGL10.EGL_SURFACE_TYPE,
EGL10.EGL_TRANSPARENT_TYPE,
EGL10.EGL_TRANSPARENT_RED_VALUE,
EGL10.EGL_TRANSPARENT_GREEN_VALUE,
EGL10.EGL_TRANSPARENT_BLUE_VALUE,
0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB,
0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA,
0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL,
0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL,
EGL10.EGL_LUMINANCE_SIZE,
EGL10.EGL_ALPHA_MASK_SIZE,
EGL10.EGL_COLOR_BUFFER_TYPE,
EGL10.EGL_RENDERABLE_TYPE,
0x3042 // EGL10.EGL_CONFORMANT
};
String[] names = {
"EGL_BUFFER_SIZE",
"EGL_ALPHA_SIZE",
"EGL_BLUE_SIZE",
"EGL_GREEN_SIZE",
"EGL_RED_SIZE",
"EGL_DEPTH_SIZE",
"EGL_STENCIL_SIZE",
"EGL_CONFIG_CAVEAT",
"EGL_CONFIG_ID",
"EGL_LEVEL",
"EGL_MAX_PBUFFER_HEIGHT",
"EGL_MAX_PBUFFER_PIXELS",
"EGL_MAX_PBUFFER_WIDTH",
"EGL_NATIVE_RENDERABLE",
"EGL_NATIVE_VISUAL_ID",
"EGL_NATIVE_VISUAL_TYPE",
"EGL_PRESERVED_RESOURCES",
"EGL_SAMPLES",
"EGL_SAMPLE_BUFFERS",
"EGL_SURFACE_TYPE",
"EGL_TRANSPARENT_TYPE",
"EGL_TRANSPARENT_RED_VALUE",
"EGL_TRANSPARENT_GREEN_VALUE",
"EGL_TRANSPARENT_BLUE_VALUE",
"EGL_BIND_TO_TEXTURE_RGB",
"EGL_BIND_TO_TEXTURE_RGBA",
"EGL_MIN_SWAP_INTERVAL",
"EGL_MAX_SWAP_INTERVAL",
"EGL_LUMINANCE_SIZE",
"EGL_ALPHA_MASK_SIZE",
"EGL_COLOR_BUFFER_TYPE",
"EGL_RENDERABLE_TYPE",
"EGL_CONFORMANT"
};
int[] value = new int[1];
for (int i = 0; i < attributes.length; i++) {
int attribute = attributes[i];
String name = names[i];
if ( egl.eglGetConfigAttrib(display, config, attribute, value)) {
Log.w(TAG, String.format(" %s: %d\n", name, value[0]));
} else {
// Log.w(TAG, String.format(" %s: failed\n", name));
while (egl.eglGetError() != EGL10.EGL_SUCCESS);
}
}
}
// Subclasses can adjust these values:
protected int mRedSize;
protected int mGreenSize;
protected int mBlueSize;
protected int mAlphaSize;
protected int mDepthSize;
protected int mStencilSize;
private int[] mValue = new int[1];
}
private class Renderer implements GLSurfaceView.Renderer {
public void onDrawFrame(GL10 gl) {
Apple2View.this.mActivity.nativeRender();
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
Apple2View.this.mActivity.nativeGraphicsInitialized(width, height);
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// Do nothing.
}
}
}