mirror of
https://github.com/mauiaaron/apple2.git
synced 2024-09-28 16:54:51 +00:00
175 lines
4.1 KiB
C
175 lines
4.1 KiB
C
|
/*
|
||
|
* 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 2017 Aaron Culliney
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include "common.h"
|
||
|
|
||
|
typedef struct backend_node_s {
|
||
|
struct backend_node_s *next;
|
||
|
long order;
|
||
|
video_backend_s *backend;
|
||
|
} backend_node_s;
|
||
|
|
||
|
static bool video_initialized = false;
|
||
|
static bool null_backend_running = true;
|
||
|
static backend_node_s *head = NULL;
|
||
|
static video_backend_s *currentBackend = NULL;
|
||
|
static pthread_t render_thread_id = 0;
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
void video_init(void) {
|
||
|
video_initialized = true;
|
||
|
|
||
|
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_clear();
|
||
|
|
||
|
currentBackend->init((void*)0);
|
||
|
}
|
||
|
|
||
|
void _video_setRenderThread(pthread_t id) {
|
||
|
LOG("setting render_thread_id : %ld -> %ld", render_thread_id, id);
|
||
|
render_thread_id = id;
|
||
|
}
|
||
|
|
||
|
bool video_isRenderThread(void) {
|
||
|
return (pthread_self() == render_thread_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(!render_thread_id || pthread_self() == render_thread_id);
|
||
|
#endif
|
||
|
|
||
|
currentBackend->shutdown();
|
||
|
}
|
||
|
|
||
|
void video_render(void) {
|
||
|
assert(pthread_self() == render_thread_id);
|
||
|
currentBackend->render();
|
||
|
}
|
||
|
|
||
|
void video_main_loop(void) {
|
||
|
currentBackend->main_loop();
|
||
|
}
|
||
|
|
||
|
void video_clear(void) {
|
||
|
video_setDirty(A2_DIRTY_FLAG);
|
||
|
}
|
||
|
|
||
|
bool video_saveState(StateHelper_s *helper) {
|
||
|
bool saved = false;
|
||
|
int fd = helper->fd;
|
||
|
|
||
|
do {
|
||
|
uint8_t state = 0x0;
|
||
|
if (!helper->save(fd, &state, 1)) {
|
||
|
break;
|
||
|
}
|
||
|
LOG("SAVE (no-op) video__current_page = %02x", state);
|
||
|
|
||
|
saved = true;
|
||
|
} while (0);
|
||
|
|
||
|
return saved;
|
||
|
}
|
||
|
|
||
|
bool video_loadState(StateHelper_s *helper) {
|
||
|
bool loaded = false;
|
||
|
int fd = helper->fd;
|
||
|
|
||
|
do {
|
||
|
uint8_t state = 0x0;
|
||
|
|
||
|
if (!helper->load(fd, &state, 1)) {
|
||
|
break;
|
||
|
}
|
||
|
LOG("LOAD (no-op) video__current_page = %02x", state);
|
||
|
|
||
|
loaded = true;
|
||
|
} while (0);
|
||
|
|
||
|
return loaded;
|
||
|
}
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// Video backend registration and selection
|
||
|
|
||
|
void video_registerBackend(video_backend_s *backend, long order) {
|
||
|
assert(!video_initialized); // backends cannot be registered after we've picked one to use
|
||
|
|
||
|
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||
|
pthread_mutex_lock(&mutex);
|
||
|
|
||
|
backend_node_s *node = MALLOC(sizeof(backend_node_s));
|
||
|
assert(node);
|
||
|
node->next = NULL;
|
||
|
node->order = order;
|
||
|
node->backend = backend;
|
||
|
|
||
|
backend_node_s *p0 = NULL;
|
||
|
backend_node_s *p = head;
|
||
|
while (p && (order > p->order)) {
|
||
|
p0 = p;
|
||
|
p = p->next;
|
||
|
}
|
||
|
if (p0) {
|
||
|
p0->next = node;
|
||
|
} else {
|
||
|
head = node;
|
||
|
}
|
||
|
node->next = p;
|
||
|
|
||
|
currentBackend = head->backend;
|
||
|
|
||
|
pthread_mutex_unlock(&mutex);
|
||
|
}
|
||
|
|
||
|
video_animation_s *video_getAnimationDriver(void) {
|
||
|
return currentBackend->anim;
|
||
|
}
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// NULL video backend ...
|
||
|
|
||
|
static void _null_backend_init(void *context) {
|
||
|
}
|
||
|
|
||
|
static void _null_backend_main_loop(void) {
|
||
|
while (null_backend_running) {
|
||
|
sleep(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void _null_backend_render(void) {
|
||
|
}
|
||
|
|
||
|
static void _null_backend_shutdown(void) {
|
||
|
null_backend_running = false;
|
||
|
}
|
||
|
|
||
|
static __attribute__((constructor)) void _init_video(void) {
|
||
|
static video_backend_s null_backend = { 0 };
|
||
|
null_backend.init = &_null_backend_init;
|
||
|
null_backend.main_loop = &_null_backend_main_loop;
|
||
|
null_backend.render = &_null_backend_render;
|
||
|
null_backend.shutdown = &_null_backend_shutdown;
|
||
|
static video_animation_s _null_animations = { 0 };
|
||
|
null_backend.anim = &_null_animations;
|
||
|
video_registerBackend(&null_backend, VID_PRIO_NULL);
|
||
|
}
|
||
|
|