mirror of
https://github.com/mauiaaron/apple2.git
synced 2025-04-27 19:39:59 +00:00
Refactor glvideo to be the root glnode, begin to privatize video_backend APIs
This commit is contained in:
parent
51fb905260
commit
edaae0bc89
@ -191,15 +191,16 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnCreate(JNIEnv *env, jclas
|
||||
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);
|
||||
video_reshape(width, height);
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2View_nativeGraphicsInitialized(JNIEnv *env, jclass cls, jint width, jint height) {
|
||||
// WARNING : this needs to happen on the GL thread only
|
||||
LOG("width:%d height:%d", width, height);
|
||||
_video_setRenderThread(pthread_self()); // Assume Android knows what it's doing ;-P
|
||||
video_shutdown();
|
||||
video_backend->reshape(width, height);
|
||||
video_backend->init((void *)0);
|
||||
video_reshape(width, height);
|
||||
video_init();
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeEmulationResume(JNIEnv *env, jclass cls) {
|
||||
@ -271,7 +272,7 @@ void Java_org_deadc0de_apple2ix_Apple2View_nativeRender(JNIEnv *env, jclass cls)
|
||||
}
|
||||
#endif
|
||||
|
||||
video_backend->render();
|
||||
video_render();
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeReboot(JNIEnv *env, jclass cls) {
|
||||
|
@ -26,6 +26,7 @@ static uint8_t vga_mem_page_1[SCANWIDTH*SCANHEIGHT] = { 0 };
|
||||
|
||||
A2Color_s colormap[256] = { { 0 } };
|
||||
video_backend_s *video_backend = NULL;
|
||||
static pthread_t render_thread_id = 0;
|
||||
|
||||
static uint8_t video__wider_font[0x8000] = { 0 };
|
||||
static uint8_t video__font[0x4000] = { 0 };
|
||||
@ -1147,6 +1148,10 @@ GLUE_C_WRITE(video__write_2e_odd1_mixed)
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void video_init(void) {
|
||||
assert(pthread_self() != cpu_thread_id);
|
||||
LOG("(re)setting render_thread_id : %ld -> %ld", render_thread_id, pthread_self());
|
||||
render_thread_id = pthread_self();
|
||||
|
||||
video__fb1 = vga_mem_page_0;
|
||||
video__fb2 = vga_mem_page_1;
|
||||
|
||||
@ -1154,13 +1159,32 @@ void video_init(void) {
|
||||
memset(video__fb1,0,SCANWIDTH*SCANHEIGHT);
|
||||
memset(video__fb2,0,SCANWIDTH*SCANHEIGHT);
|
||||
|
||||
#if !defined(__APPLE__) && !defined(ANDROID)
|
||||
video_backend->init((void*)0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void _video_setRenderThread(pthread_t id) {
|
||||
render_thread_id = id;
|
||||
}
|
||||
|
||||
void video_shutdown(void) {
|
||||
|
||||
#if MOBILE_DEVICE
|
||||
// WARNING : shutdown should occur on the render thread. Platform code (iOS, Android) should ensure this is called
|
||||
// from within a render pass...
|
||||
assert(pthread_self() == render_thread_id);
|
||||
#endif
|
||||
|
||||
video_backend->shutdown();
|
||||
render_thread_id = 0;
|
||||
}
|
||||
|
||||
void video_reshape(int w, int h) {
|
||||
video_backend->reshape(w, h);
|
||||
}
|
||||
|
||||
void video_render(void) {
|
||||
assert(pthread_self() == render_thread_id);
|
||||
video_backend->render();
|
||||
}
|
||||
|
||||
void video_main_loop(void) {
|
||||
|
@ -230,7 +230,10 @@ void emulator_start(void) {
|
||||
load_settings(); // user prefs
|
||||
c_keys_set_key(kF8); // show credits before emulation start
|
||||
#endif
|
||||
|
||||
#if !defined(__APPLE__) && !defined(ANDROID)
|
||||
video_init();
|
||||
#endif
|
||||
timing_startCPU();
|
||||
video_main_loop();
|
||||
}
|
||||
|
@ -9,8 +9,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "video/glvideo.h"
|
||||
#include "video/glhudmodel.h"
|
||||
#include "video/glnode.h"
|
||||
|
||||
@ -204,7 +202,7 @@ static void alert_reshape(int w, int h) {
|
||||
|
||||
#if INTERFACE_TOUCH
|
||||
static int64_t alert_onTouchEvent(interface_touch_event_t action, int pointer_count, int pointer_idx, float *x_coords, float *y_coords) {
|
||||
return false; // non-interactive element ...
|
||||
return 0x0; // non-interactive element ...
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
#include "glhudmodel.h"
|
||||
#include "glvideo.h"
|
||||
#include "glnode.h"
|
||||
|
||||
// . . .
|
||||
// . x .
|
||||
|
@ -9,11 +9,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "video/glnode.h"
|
||||
#include "video/glvideo.h"
|
||||
#include "video/glinput.h"
|
||||
|
||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
bool safe_to_do_opengl_logging = false;
|
||||
|
||||
// WARNING : linked list designed for convenience and not performance =P ... if the amount of GLNode objects grows
|
||||
// wildly, should rethink this ...
|
||||
@ -27,9 +26,17 @@ typedef struct glnode_array_node_s {
|
||||
static glnode_array_node_s *head = NULL;
|
||||
static glnode_array_node_s *tail = NULL;
|
||||
|
||||
static video_backend_s glnode_backend = { 0 };
|
||||
|
||||
#if USE_GLUT
|
||||
static bool glut_in_main_loop = false;
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void glnode_registerNode(glnode_render_order_t order, GLNode node) {
|
||||
|
||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
glnode_array_node_s *arrayNode = MALLOC(sizeof(glnode_array_node_s));
|
||||
@ -46,7 +53,7 @@ void glnode_registerNode(glnode_render_order_t order, GLNode node) {
|
||||
} else {
|
||||
glnode_array_node_s *p0 = NULL;
|
||||
glnode_array_node_s *p = head;
|
||||
while (p && (order < p->order)) {
|
||||
while (p && (order > p->order)) {
|
||||
p0 = p;
|
||||
p = p->next;
|
||||
}
|
||||
@ -67,34 +74,121 @@ void glnode_registerNode(glnode_render_order_t order, GLNode node) {
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
void glnode_setupNodes(void) {
|
||||
LOG("glnode_setupNodes ...");
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#if USE_GLUT
|
||||
static void _glnode_updateGLUT(int unused) {
|
||||
#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("%u", idleCount-prevCount);
|
||||
prevCount = idleCount;
|
||||
prev = now;
|
||||
}
|
||||
#endif
|
||||
|
||||
c_keys_handle_input(-1, 0, 0);
|
||||
glutPostRedisplay();
|
||||
glutTimerFunc(17, _glnode_updateGLUT, 0);
|
||||
}
|
||||
|
||||
static void _glnode_initGLUTPre(void) {
|
||||
glutInit(&argc, argv);
|
||||
glutInitDisplayMode(/*GLUT_DOUBLE|*/GLUT_RGBA);
|
||||
glutInitWindowSize(SCANWIDTH*1.5, SCANHEIGHT*1.5);
|
||||
//glutInitContextVersion(4, 0); -- Is this needed?
|
||||
glutInitContextProfile(GLUT_CORE_PROFILE);
|
||||
/*glutWindow = */glutCreateWindow(PACKAGE_NAME);
|
||||
GL_ERRQUIT("GLUT initialization");
|
||||
|
||||
if (glewInit()) {
|
||||
ERRQUIT("Unable to initialize GLEW");
|
||||
}
|
||||
}
|
||||
|
||||
static void _glnode_reshapeGLUT(int w, int h) {
|
||||
video_reshape(w, h);
|
||||
}
|
||||
|
||||
static void _glnode_initGLUTPost(void) {
|
||||
glutTimerFunc(16, _glnode_updateGLUT, 0);
|
||||
glutDisplayFunc(video_render);
|
||||
glutReshapeFunc(_glnode_reshapeGLUT);
|
||||
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS);
|
||||
|
||||
#if !TESTING
|
||||
glutKeyboardFunc(gldriver_on_key_down);
|
||||
glutKeyboardUpFunc(gldriver_on_key_up);
|
||||
glutSpecialFunc(gldriver_on_key_special_down);
|
||||
glutSpecialUpFunc(gldriver_on_key_special_up);
|
||||
//glutMouseFunc(gldriver_mouse);
|
||||
//glutMotionFunc(gldriver_mouse_drag);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static void glnode_setupNodes(void *ctx) {
|
||||
LOG("BEGIN glnode_setupNodes ...");
|
||||
|
||||
#if USE_GLUT
|
||||
_glnode_initGLUTPre();
|
||||
#endif
|
||||
|
||||
safe_to_do_opengl_logging = true;
|
||||
glnode_array_node_s *p = head;
|
||||
while (p) {
|
||||
p->node.setup();
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
#if USE_GLUT
|
||||
_glnode_initGLUTPost();
|
||||
#endif
|
||||
|
||||
LOG("END glnode_setupNodes ...");
|
||||
}
|
||||
|
||||
void glnode_shutdownNodes(void) {
|
||||
LOG("glnode_shutdownNodes ...");
|
||||
glnode_array_node_s *p = head;
|
||||
while (p) {
|
||||
p->node.shutdown();
|
||||
p = p->next;
|
||||
static void glnode_shutdownNodes(void) {
|
||||
LOG("BEGIN glnode_shutdownNodes ...");
|
||||
|
||||
#if USE_GLUT
|
||||
LOG("Waiting for GLUT mainloop to finish ...");
|
||||
glutLeaveMainLoop();
|
||||
while (glut_in_main_loop) {
|
||||
usleep(40);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void glnode_renderNodes(void) {
|
||||
SCOPE_TRACE_VIDEO("glnode render");
|
||||
glnode_array_node_s *p = tail;
|
||||
while (p) {
|
||||
p->node.render();
|
||||
p->node.shutdown();
|
||||
p = p->last;
|
||||
}
|
||||
LOG("END glnode_shutdownNodes ...");
|
||||
}
|
||||
|
||||
void glnode_reshapeNodes(int w, int h) {
|
||||
static void glnode_renderNodes(void) {
|
||||
SCOPE_TRACE_VIDEO("glnode render");
|
||||
glnode_array_node_s *p = head;
|
||||
while (p) {
|
||||
p->node.render();
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
#if USE_GLUT
|
||||
glutSwapBuffers();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void glnode_reshapeNodes(int w, int h) {
|
||||
glnode_array_node_s *p = head;
|
||||
while (p) {
|
||||
p->node.reshape(w, h);
|
||||
@ -103,21 +197,33 @@ void glnode_reshapeNodes(int w, int h) {
|
||||
}
|
||||
|
||||
#if INTERFACE_TOUCH
|
||||
int64_t glnode_onTouchEvent(interface_touch_event_t action, int pointer_count, int pointer_idx, float *x_coords, float *y_coords) {
|
||||
static int64_t glnode_onTouchEvent(interface_touch_event_t action, int pointer_count, int pointer_idx, float *x_coords, float *y_coords) {
|
||||
SCOPE_TRACE_TOUCH("glnode onTouchEvent");
|
||||
glnode_array_node_s *p = head;
|
||||
glnode_array_node_s *p = tail;
|
||||
int64_t flags = 0x0;
|
||||
while (p) {
|
||||
flags = p->node.onTouchEvent(action, pointer_count, pointer_idx, x_coords, y_coords);
|
||||
if (flags & TOUCH_FLAGS_HANDLED) {
|
||||
break;
|
||||
}
|
||||
p = p->next;
|
||||
p = p->last;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void glnode_mainLoop(void) {
|
||||
#if USE_GLUT
|
||||
LOG("BEGIN GLUT main loop...");
|
||||
glut_in_main_loop = true;
|
||||
glutMainLoop();
|
||||
glut_in_main_loop = false;
|
||||
LOG("END GLUT main loop...");
|
||||
#endif
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
__attribute__((destructor(255)))
|
||||
static void _destroy_glnodes(void) {
|
||||
LOG("...");
|
||||
@ -137,6 +243,14 @@ __attribute__((constructor(CTOR_PRIORITY_LATE)))
|
||||
static void _init_glnode_manager(void) {
|
||||
LOG("Initializing GLNode manager subsystem");
|
||||
|
||||
assert((video_backend == NULL) && "there can only be one!");
|
||||
glnode_backend.init = &glnode_setupNodes;
|
||||
glnode_backend.main_loop = &glnode_mainLoop;
|
||||
glnode_backend.reshape = &glnode_reshapeNodes;
|
||||
glnode_backend.render = &glnode_renderNodes;
|
||||
glnode_backend.shutdown = &glnode_shutdownNodes;
|
||||
video_backend = &glnode_backend;
|
||||
|
||||
#if INTERFACE_TOUCH
|
||||
interface_onTouchEvent = &glnode_onTouchEvent;
|
||||
#endif
|
||||
|
@ -9,14 +9,80 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifndef _GLNODE_H_
|
||||
#define _GLNODE_H_
|
||||
|
||||
#include "common.h"
|
||||
#include "video_util/modelUtil.h"
|
||||
#include "video_util/matrixUtil.h"
|
||||
#include "video_util/sourceUtil.h"
|
||||
|
||||
#define TRACKING_NONE (-1)
|
||||
// TODO: implement 3D CRT object, possibly with perspective drawing?
|
||||
#define PERSPECTIVE 0
|
||||
|
||||
enum {
|
||||
TEXTURE_ID_FRAMEBUFFER=0,
|
||||
TEXTURE_ID_MESSAGE,
|
||||
#if INTERFACE_TOUCH
|
||||
TEXTURE_ID_TOUCHJOY_AXIS,
|
||||
TEXTURE_ID_TOUCHJOY_BUTTON,
|
||||
TEXTURE_ID_TOUCHKBD,
|
||||
TEXTURE_ID_TOUCHMENU,
|
||||
#endif
|
||||
TEXTURE_ID_MAX,
|
||||
};
|
||||
|
||||
enum {
|
||||
TEXTURE_ACTIVE_FRAMEBUFFER = GL_TEXTURE0,
|
||||
TEXTURE_ACTIVE_MESSAGE = GL_TEXTURE1,
|
||||
#if INTERFACE_TOUCH
|
||||
TEXTURE_ACTIVE_TOUCHJOY_AXIS = GL_TEXTURE2,
|
||||
TEXTURE_ACTIVE_TOUCHJOY_BUTTON = GL_TEXTURE3,
|
||||
TEXTURE_ACTIVE_TOUCHKBD = GL_TEXTURE4,
|
||||
TEXTURE_ACTIVE_TOUCHMENU = GL_TEXTURE5,
|
||||
#endif
|
||||
TEXTURE_ACTIVE_MAX,
|
||||
};
|
||||
|
||||
// Important common shader values
|
||||
extern GLint texSamplerLoc;
|
||||
extern GLint alphaValue;
|
||||
extern GLuint mainShaderProgram;
|
||||
extern GLfloat mvpIdentity[16]; // Common Model View Projection matrix
|
||||
|
||||
// http://stackoverflow.com/questions/13676070/how-to-properly-mix-drawing-calls-and-changes-of-a-sampler-value-with-a-single-s
|
||||
// https://developer.qualcomm.com/forum/qdevnet-forums/mobile-gaming-graphics-optimization-adreno/8896
|
||||
extern bool hackAroundBrokenAdreno200;
|
||||
extern bool hackAroundBrokenAdreno205;
|
||||
#define _HACKAROUND_GLDRAW_PRE() \
|
||||
({ \
|
||||
if (hackAroundBrokenAdreno200) { \
|
||||
glUseProgram(0); \
|
||||
glUseProgram(mainShaderProgram); \
|
||||
} \
|
||||
})
|
||||
|
||||
#define _HACKAROUND_GLTEXIMAGE2D_PRE(ACTIVE, NAME) \
|
||||
({ \
|
||||
if (hackAroundBrokenAdreno205) { \
|
||||
/* Adreno 205 driver (HTC Desire) is even more broken than the 200! It appears that we must delete and recreate textures every time we upload new pixels! */ \
|
||||
glBindTexture(GL_TEXTURE_2D, 0); \
|
||||
glDeleteTextures(1, &(NAME)); \
|
||||
glGenTextures(1, &(NAME)); \
|
||||
glActiveTexture((ACTIVE)); \
|
||||
glBindTexture(GL_TEXTURE_2D, (NAME)); \
|
||||
/* HACK NOTE : these should match what is (currently hardcoded) in modelUtil.c */ \
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); \
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); \
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); \
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); \
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); \
|
||||
} \
|
||||
})
|
||||
|
||||
#if INTERFACE_TOUCH
|
||||
# define TRACKING_NONE (-1)
|
||||
#endif
|
||||
|
||||
typedef enum glnode_render_order_t {
|
||||
RENDER_BOTTOM=0, // e.g., the //e framebuffer node itself
|
||||
@ -39,22 +105,5 @@ typedef struct GLNode {
|
||||
// registers a node with manager
|
||||
void glnode_registerNode(glnode_render_order_t order, GLNode node);
|
||||
|
||||
// setup nodes (occurs when OpenGL context created)
|
||||
void glnode_setupNodes(void);
|
||||
|
||||
// shutdown nodes (occurs when OpenGL context about to be lost)
|
||||
void glnode_shutdownNodes(void);
|
||||
|
||||
// render pass over all nodes in their requested render order
|
||||
void glnode_renderNodes(void);
|
||||
|
||||
// distribute viewport dimension changes
|
||||
void glnode_reshapeNodes(int w, int h);
|
||||
|
||||
#if INTERFACE_TOUCH
|
||||
// distribute touch event to node which can handle it (in render order)
|
||||
int64_t glnode_onTouchEvent(interface_touch_event_t action, int pointer_count, int pointer_idx, float *x_coords, float *y_coords);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif // whole file
|
||||
|
||||
|
@ -12,8 +12,6 @@
|
||||
#ifndef _GLTOUCHJOY_H_
|
||||
#define _GLTOUCHJOY_H_
|
||||
|
||||
#include "common.h"
|
||||
#include "video/glvideo.h"
|
||||
#include "video/glhudmodel.h"
|
||||
#include "video/glnode.h"
|
||||
|
||||
|
@ -9,8 +9,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "video/glvideo.h"
|
||||
#include "video/glhudmodel.h"
|
||||
#include "video/glnode.h"
|
||||
#include "json_parse.h"
|
||||
|
@ -9,8 +9,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "video/glvideo.h"
|
||||
#include "video/glhudmodel.h"
|
||||
#include "video/glnode.h"
|
||||
|
||||
|
@ -9,16 +9,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "video/glvideo.h"
|
||||
#include "video/glinput.h"
|
||||
#include "video/glnode.h"
|
||||
|
||||
#include <regex.h>
|
||||
|
||||
bool safe_to_do_opengl_logging = false;
|
||||
bool renderer_shutting_down = false;
|
||||
|
||||
volatile unsigned long _backend_vid_dirty = 0;
|
||||
|
||||
static int viewportX = 0;
|
||||
@ -40,19 +34,9 @@ static GLModel *crtModel = NULL;
|
||||
static GLuint vertexShader = UNINITIALIZED_GL;
|
||||
static GLuint fragShader = UNINITIALIZED_GL;
|
||||
|
||||
static video_backend_s glvideo_backend = { 0 };
|
||||
|
||||
#if USE_GLUT
|
||||
static int windowWidth = SCANWIDTH*1.5;
|
||||
static int windowHeight = SCANHEIGHT*1.5;
|
||||
static int glutWindow = -1;
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
static void gldriver_render(void);
|
||||
|
||||
static void _gldriver_setup_hackarounds(void) {
|
||||
static void _glvideo_setup_hackarounds(void) {
|
||||
|
||||
const char *vendor = (const char *)glGetString(GL_VENDOR);
|
||||
const char *renderer = (const char *)glGetString(GL_RENDERER);
|
||||
@ -142,9 +126,9 @@ static void _gldriver_setup_hackarounds(void) {
|
||||
} while (0);
|
||||
}
|
||||
|
||||
static void gldriver_init_common(void) {
|
||||
static void glvideo_init(void) {
|
||||
|
||||
_gldriver_setup_hackarounds();
|
||||
_glvideo_setup_hackarounds();
|
||||
|
||||
#if !PERSPECTIVE
|
||||
mtxLoadIdentity(mvpIdentity);
|
||||
@ -154,8 +138,6 @@ static void gldriver_init_common(void) {
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
|
||||
LOG("GL_MAX_TEXTURE_SIZE:%d", value);
|
||||
|
||||
renderer_shutting_down = false;
|
||||
|
||||
if (!viewportWidth) {
|
||||
viewportWidth = 400;
|
||||
}
|
||||
@ -248,7 +230,7 @@ static void gldriver_init_common(void) {
|
||||
// This is done in order to pre-warm OpenGL
|
||||
// We don't need to present the buffer since we don't actually want the
|
||||
// user to see this, we're only drawing as a pre-warm stage
|
||||
gldriver_render();
|
||||
video_render();
|
||||
|
||||
// Check for errors to make sure all of our setup went ok
|
||||
GL_ERRLOG("finished initialization");
|
||||
@ -259,8 +241,8 @@ static void gldriver_init_common(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static void _gldriver_shutdown(void) {
|
||||
LOG("Beginning GLDriver shutdown ...");
|
||||
static void glvideo_shutdown(void) {
|
||||
LOG("BEGIN ...");
|
||||
|
||||
// Cleanup all OpenGL objects
|
||||
|
||||
@ -283,51 +265,10 @@ static void _gldriver_shutdown(void) {
|
||||
mainShaderProgram = UNINITIALIZED_GL;
|
||||
}
|
||||
|
||||
glnode_shutdownNodes();
|
||||
LOG("Completed GLDriver shutdown ...");
|
||||
LOG("END ...");
|
||||
}
|
||||
|
||||
static void gldriver_shutdown(void) {
|
||||
if (renderer_shutting_down) {
|
||||
return;
|
||||
}
|
||||
#if USE_GLUT
|
||||
glutLeaveMainLoop();
|
||||
#endif
|
||||
renderer_shutting_down = true;
|
||||
_gldriver_shutdown();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// update, render, reshape
|
||||
//
|
||||
#if USE_GLUT
|
||||
static void gldriver_update(int unused) {
|
||||
#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("gldriver_update() : %u", idleCount-prevCount);
|
||||
prevCount = idleCount;
|
||||
prev = now;
|
||||
}
|
||||
#endif
|
||||
|
||||
c_keys_handle_input(-1, 0, 0);
|
||||
glutPostRedisplay();
|
||||
glutTimerFunc(17, gldriver_update, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void gldriver_render(void) {
|
||||
static void glvideo_render(void) {
|
||||
SCOPE_TRACE_VIDEO("glvideo render");
|
||||
|
||||
const uint8_t * const fb = video_current_framebuffer();
|
||||
@ -335,10 +276,6 @@ static void gldriver_render(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (UNLIKELY(renderer_shutting_down)) {
|
||||
return;
|
||||
}
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
#if MOBILE_DEVICE
|
||||
glViewport(viewportX, viewportY, viewportWidth, viewportHeight);
|
||||
@ -439,22 +376,11 @@ static void gldriver_render(void) {
|
||||
_HACKAROUND_GLDRAW_PRE();
|
||||
glDrawElements(GL_TRIANGLES, crtModel->numElements, crtModel->elementType, 0);
|
||||
|
||||
// Render HUD nodes
|
||||
glnode_renderNodes();
|
||||
|
||||
#if USE_GLUT
|
||||
glutSwapBuffers();
|
||||
#endif
|
||||
|
||||
GL_ERRLOG("gldriver_render");
|
||||
GL_ERRLOG("glvideo_render");
|
||||
}
|
||||
|
||||
static void gldriver_reshape(int w, int h) {
|
||||
static void glvideo_reshape(int w, int h) {
|
||||
//LOG("reshape to w:%d h:%d", w, h);
|
||||
#if USE_GLUT
|
||||
windowWidth = w;
|
||||
windowHeight = h;
|
||||
#endif
|
||||
|
||||
int w2 = ((float)h * (SCANWIDTH/(float)SCANHEIGHT));
|
||||
int h2 = ((float)w / (SCANWIDTH/(float)SCANHEIGHT));
|
||||
@ -481,78 +407,29 @@ static void gldriver_reshape(int w, int h) {
|
||||
}
|
||||
|
||||
glViewport(viewportX, viewportY, viewportWidth, viewportHeight);
|
||||
|
||||
// Reshape HUD nodes
|
||||
glnode_reshapeNodes(w, h);
|
||||
}
|
||||
|
||||
#if USE_GLUT
|
||||
static void gldriver_init_glut(void) {
|
||||
glutInit(&argc, argv);
|
||||
glutInitDisplayMode(/*GLUT_DOUBLE|*/GLUT_RGBA);
|
||||
glutInitWindowSize(windowWidth, windowHeight);
|
||||
//glutInitContextVersion(4, 0); -- Is this needed?
|
||||
glutInitContextProfile(GLUT_CORE_PROFILE);
|
||||
glutWindow = glutCreateWindow(PACKAGE_NAME);
|
||||
GL_ERRQUIT("GLUT initialization");
|
||||
|
||||
if (glewInit()) {
|
||||
ERRQUIT("Unable to initialize GLEW");
|
||||
}
|
||||
|
||||
gldriver_init_common();
|
||||
|
||||
glutTimerFunc(16, gldriver_update, 0);
|
||||
glutDisplayFunc(gldriver_render);
|
||||
glutReshapeFunc(gldriver_reshape);
|
||||
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS);
|
||||
|
||||
#if !TESTING
|
||||
glutKeyboardFunc(gldriver_on_key_down);
|
||||
glutKeyboardUpFunc(gldriver_on_key_up);
|
||||
glutSpecialFunc(gldriver_on_key_special_down);
|
||||
glutSpecialUpFunc(gldriver_on_key_special_up);
|
||||
//glutMouseFunc(gldriver_mouse);
|
||||
//glutMotionFunc(gldriver_mouse_drag);
|
||||
#endif
|
||||
#if INTERFACE_TOUCH
|
||||
static int64_t glvideo_onTouchEvent(interface_touch_event_t action, int pointer_count, int pointer_idx, float *x_coords, float *y_coords) {
|
||||
// no-op
|
||||
return 0x0;
|
||||
}
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// backend renderer API
|
||||
|
||||
static void gldriver_init(void *unused) {
|
||||
safe_to_do_opengl_logging = true;
|
||||
#if defined(__APPLE__) || defined(ANDROID)
|
||||
gldriver_init_common();
|
||||
#elif USE_GLUT
|
||||
gldriver_init_glut();
|
||||
#else
|
||||
#error no working codepaths
|
||||
#endif
|
||||
glnode_setupNodes();
|
||||
}
|
||||
|
||||
static void gldriver_main_loop(void) {
|
||||
#if USE_GLUT
|
||||
glutMainLoop();
|
||||
LOG("GLUT main loop finished...");
|
||||
#endif
|
||||
// fall through if not GLUT
|
||||
}
|
||||
|
||||
__attribute__((constructor(CTOR_PRIORITY_EARLY)))
|
||||
static void _init_glvideo(void) {
|
||||
LOG("Initializing OpenGL renderer");
|
||||
|
||||
assert((video_backend == NULL) && "there can only be one!");
|
||||
|
||||
glvideo_backend.init = &gldriver_init;
|
||||
glvideo_backend.main_loop = &gldriver_main_loop;
|
||||
glvideo_backend.reshape = &gldriver_reshape;
|
||||
glvideo_backend.render = &gldriver_render;
|
||||
glvideo_backend.shutdown = &gldriver_shutdown;
|
||||
|
||||
video_backend = &glvideo_backend;
|
||||
glnode_registerNode(RENDER_BOTTOM, (GLNode){
|
||||
.setup = &glvideo_init,
|
||||
.shutdown = &glvideo_shutdown,
|
||||
.render = &glvideo_render,
|
||||
.reshape = &glvideo_reshape,
|
||||
#if INTERFACE_TOUCH
|
||||
.onTouchEvent = &glvideo_onTouchEvent,
|
||||
#endif
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2013-2015 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _GLVIDEO_H_
|
||||
#define _GLVIDEO_H_
|
||||
|
||||
// TODO: implement 3D CRT object, possibly with perspective drawing?
|
||||
#define PERSPECTIVE 0
|
||||
|
||||
#include "video_util/modelUtil.h"
|
||||
#include "video_util/matrixUtil.h"
|
||||
#include "video_util/sourceUtil.h"
|
||||
|
||||
enum {
|
||||
TEXTURE_ID_FRAMEBUFFER=0,
|
||||
TEXTURE_ID_MESSAGE,
|
||||
#if INTERFACE_TOUCH
|
||||
TEXTURE_ID_TOUCHJOY_AXIS,
|
||||
TEXTURE_ID_TOUCHJOY_BUTTON,
|
||||
TEXTURE_ID_TOUCHKBD,
|
||||
TEXTURE_ID_TOUCHMENU,
|
||||
#endif
|
||||
TEXTURE_ID_MAX,
|
||||
};
|
||||
|
||||
enum {
|
||||
TEXTURE_ACTIVE_FRAMEBUFFER = GL_TEXTURE0,
|
||||
TEXTURE_ACTIVE_MESSAGE = GL_TEXTURE1,
|
||||
#if INTERFACE_TOUCH
|
||||
TEXTURE_ACTIVE_TOUCHJOY_AXIS = GL_TEXTURE2,
|
||||
TEXTURE_ACTIVE_TOUCHJOY_BUTTON = GL_TEXTURE3,
|
||||
TEXTURE_ACTIVE_TOUCHKBD = GL_TEXTURE4,
|
||||
TEXTURE_ACTIVE_TOUCHMENU = GL_TEXTURE5,
|
||||
#endif
|
||||
TEXTURE_ACTIVE_MAX,
|
||||
};
|
||||
|
||||
extern GLint texSamplerLoc;
|
||||
extern GLint alphaValue;
|
||||
extern GLuint mainShaderProgram;
|
||||
extern GLfloat mvpIdentity[16]; // Common Model View Projection matrix
|
||||
|
||||
// http://stackoverflow.com/questions/13676070/how-to-properly-mix-drawing-calls-and-changes-of-a-sampler-value-with-a-single-s
|
||||
// https://developer.qualcomm.com/forum/qdevnet-forums/mobile-gaming-graphics-optimization-adreno/8896
|
||||
extern bool hackAroundBrokenAdreno200;
|
||||
extern bool hackAroundBrokenAdreno205;
|
||||
#define _HACKAROUND_GLDRAW_PRE() \
|
||||
({ \
|
||||
if (hackAroundBrokenAdreno200) { \
|
||||
glUseProgram(0); \
|
||||
glUseProgram(mainShaderProgram); \
|
||||
} \
|
||||
})
|
||||
|
||||
#define _HACKAROUND_GLTEXIMAGE2D_PRE(ACTIVE, NAME) \
|
||||
({ \
|
||||
if (hackAroundBrokenAdreno205) { \
|
||||
/* Adreno 205 driver (HTC Desire) is even more broken than the 200! It appears that we must delete and recreate textures every time we upload new pixels! */ \
|
||||
glBindTexture(GL_TEXTURE_2D, 0); \
|
||||
glDeleteTextures(1, &(NAME)); \
|
||||
glGenTextures(1, &(NAME)); \
|
||||
glActiveTexture((ACTIVE)); \
|
||||
glBindTexture(GL_TEXTURE_2D, (NAME)); \
|
||||
/* HACK NOTE : these should match what is (currently hardcoded) in modelUtil.c */ \
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); \
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); \
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); \
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); \
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); \
|
||||
} \
|
||||
})
|
||||
|
||||
#endif
|
||||
|
@ -70,16 +70,32 @@ extern A2Color_s colormap[];
|
||||
void video_init(void);
|
||||
|
||||
/*
|
||||
* Enters main video loop (returns on emulator shutdown request).
|
||||
* Enters emulator-managed main video loop--if backend rendering system requires it. Currently only used by desktop X11
|
||||
* and desktop OpenGL/GLUT.
|
||||
*/
|
||||
void video_main_loop(void);
|
||||
|
||||
/*
|
||||
* Begins video subsystem shutdown. Because this process is multithreaded, this really just gives notice that a
|
||||
* shutdown has been requested, and so various threads should begin their own shutdown process.
|
||||
* Shutdown video system. Should only be called on the render thread (unless render thread is in emulator-managed main
|
||||
* video loop).
|
||||
*/
|
||||
void video_shutdown(void);
|
||||
|
||||
/*
|
||||
* Begin a render pass (only for non-emulator-managed main video). This should only be called on the render thread.
|
||||
*/
|
||||
void video_render(void);
|
||||
|
||||
/*
|
||||
* Set the render thread ID. Use with caution.
|
||||
*/
|
||||
void _video_setRenderThread(pthread_t id);
|
||||
|
||||
/*
|
||||
* Reshape the display to particular dimensions.
|
||||
*/
|
||||
void video_reshape(int w, int h);
|
||||
|
||||
/*
|
||||
* Setup the display. This may be called multiple times in a run, and is
|
||||
* used when graphics parameters may have changed.
|
||||
|
Loading…
x
Reference in New Issue
Block a user