apple2ix/src/video/video.c
Aaron Culliney f8b4602fca Beginning to refactor display and backend video
- Futher disentangle display, interface, and video backends
    - Backend video owns the staging/intermediate framebuffer for now
    - Add the beginnings of display update callbacks
2017-08-06 12:12:12 -10:00

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