Refactor glvideo to be the root glnode, begin to privatize video_backend APIs

This commit is contained in:
Aaron Culliney 2016-02-06 13:13:31 -08:00
parent 51fb905260
commit edaae0bc89
13 changed files with 282 additions and 288 deletions

View File

@ -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) {

View File

@ -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) {

View File

@ -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();
}

View File

@ -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

View File

@ -10,7 +10,7 @@
*/
#include "glhudmodel.h"
#include "glvideo.h"
#include "glnode.h"
// . . .
// . x .

View File

@ -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

View File

@ -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

View 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"

View File

@ -9,8 +9,6 @@
*
*/
#include "common.h"
#include "video/glvideo.h"
#include "video/glhudmodel.h"
#include "video/glnode.h"
#include "json_parse.h"

View File

@ -9,8 +9,6 @@
*
*/
#include "common.h"
#include "video/glvideo.h"
#include "video/glhudmodel.h"
#include "video/glnode.h"

View File

@ -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
});
}

View File

@ -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

View File

@ -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.