Refactor to enable loading multiple AV backends

- Includes default 'null' backends with lowest priority
This commit is contained in:
Aaron Culliney 2017-07-15 13:25:00 -10:00
parent 97a98f0c86
commit 3c1dcd4a69
20 changed files with 324 additions and 173 deletions

View File

@ -1,6 +1,6 @@
dnl ---------------------------------------------------------------------------
AC_DEFINE(PACKAGE_URL, "https://github.com/mauiaaron/apple2", [apple2ix project URL])
AC_DEFINE(PACKAGE_URL, "https://deadc0de.org/apple2ix", [apple2ix project URL])
AC_PREREQ([2.69])
AC_INIT([apple2ix], [0.8])
@ -169,17 +169,17 @@ dnl Video ...
AC_PATH_XTRA
opengl_selected='yes'
AC_ARG_ENABLE([opengl], AS_HELP_STRING([--disable-opengl], [Disable OpenGL video driver (uses regular X11)]), [
opengl_selected='no'
], [
AC_CHECK_HEADER(GL/glew.h, [
AC_CHECK_HEADER(GL/freeglut.h, [
AC_SEARCH_LIBS(glCreateProgram, [GL], [
AC_SEARCH_LIBS(glutMainLoop, [glut freeglut], [
AC_SEARCH_LIBS(glewInit, [GLEW glew], [
opengl_supported='yes'
AC_DEFINE(VIDEO_OPENGL, 1, [Use OpenGL])
AC_ARG_ENABLE([opengl], AS_HELP_STRING([--enable-opengl], [Enable OpenGL graphics output (autodetected)]))
AC_CHECK_HEADER(GL/glew.h, [
AC_CHECK_HEADER(GL/freeglut.h, [
AC_SEARCH_LIBS(glCreateProgram, [GL], [
AC_SEARCH_LIBS(glutMainLoop, [glut freeglut], [
AC_SEARCH_LIBS(glewInit, [GLEW glew], [
AS_IF([test "x$enable_opengl" != "xno"], [
AC_DEFINE(VIDEO_OPENGL, 1, [Building with OpenGL support])
AC_DEFINE(USE_GLUT, 1, [Use GLUT library])
VIDEO_O="src/video/glvideo.o src/video/glnode.o src/video/glalert.o src/video/glhudmodel.o src/video/glutinput.o src/video_util/matrixUtil.o src/video_util/modelUtil.o src/video_util/sourceUtil.o src/video_util/vectorUtil.o"
dnl HACK there's gotta be a better way ... without this verbosity, CFLAGS are not correct (lacking -DTESTING=1 , etc) if we don't specify specific obj files for test binaries
@ -191,54 +191,66 @@ AC_ARG_ENABLE([opengl], AS_HELP_STRING([--disable-opengl], [Disable OpenGL video
testui_VIDEO_O="src/video/testui-glvideo.o src/video/testui-glnode.o src/video/testui-glalert.o src/video/testui-glhudmodel.o src/video/testui-glutinput.o src/video_util/testui-matrixUtil.o src/video_util/testui-modelUtil.o src/video_util/testui-sourceUtil.o src/video_util/testui-vectorUtil.o"
testvm_VIDEO_O="src/video/testvm-glvideo.o src/video/testvm-glnode.o src/video/testvm-glalert.o src/video/testvm-glhudmodel.o src/video/testvm-glutinput.o src/video_util/testvm-matrixUtil.o src/video_util/testvm-modelUtil.o src/video_util/testvm-sourceUtil.o src/video_util/testvm-vectorUtil.o"
AC_MSG_RESULT([Building emulator with OpenGL support, w00t!])
], [
AC_MSG_WARN([Did not find OpenGL GLEW library...])
], [-lGL -lGLEW -lglut])
])
], [
AC_MSG_WARN([Did not find glut library...])
AS_IF([test "x$enable_opengl" != "xno"], [
AC_MSG_WARN([Did not find OpenGL GLEW library, OpenGL support is disabled ...])
])
], [-lGL -lGLEW -lglut])
], [
AC_MSG_WARN([Did not find OpenGL library...])
], [-lGL])
AS_IF([test "x$enable_opengl" != "xno"], [
AC_MSG_WARN([Did not find glut library, OpenGL support is disabled ...])
])
], [-lGL -lGLEW -lglut])
], [
AC_MSG_WARN([Did not find GL/freeglut.h header ...])
])
AS_IF([test "x$enable_opengl" != "xno"], [
AC_MSG_WARN([Did not find OpenGL library, OpenGL support is disabled ...])
])
], [-lGL])
], [
AC_MSG_WARN([Did not find GL/glew.h header ...])
AS_IF([test "x$enable_opengl" != "xno"], [
AC_MSG_WARN([Did not find GL/freeglut.h header, OpenGL support is disabled ...])
])
])
], [
AS_IF([test "x$enable_opengl" != "xno"], [
AC_MSG_WARN([Did not find GL/glew.h header, OpenGL support is disabled ...])
])
])
AS_IF([test "x$opengl_supported" = "xyes"], [
], [
dnl OpenGL not supported
AS_IF([test "x$opengl_selected" = "xyes"], [
AC_MSG_WARN([!!! DID NOT FIND OPENGL LIBRARIES !!! will attempt to build legacy X11 variant (this is OKAY but LIMITED) ...])
], [])
AC_CHECK_HEADER(X11/XKBlib.h, [
AC_SEARCH_LIBS(XPutImage, [X11], [
AC_ARG_ENABLE([x11], AS_HELP_STRING([--enable-x11], [Enable X11 graphics output (autodetected)]))
AC_CHECK_HEADER(X11/XKBlib.h, [
AC_SEARCH_LIBS(XPutImage, [X11], [
AS_IF([test "x$enable_x11" != "xno"], [
AC_SEARCH_LIBS(XShmAttach, Xext, [
AC_DEFINE(HAVE_X11_SHM, 1, [Enable X11 MIT SHM extension])
], [
AC_MSG_WARN([Building emulator without support of X11 MITSHM extension...])
], [-lX11])
VIDEO_O="src/video/xvideo.o"
VIDEO_O="$VIDEO_O src/video/xvideo.o"
dnl HACK there's gotta be a better way ... without this verbosity, CFLAGS are not correct (lacking -DTESTING=1 , etc) if we don't specify specific obj files for test binaries
testcpu_VIDEO_O="src/video/testcpu-xvideo.o"
testdisk_VIDEO_O="src/video/testdisk-xvideo.o"
testdisplay_VIDEO_O="src/video/testdisplay-xvideo.o"
testprefs_VIDEO_O="src/video/testprefs-xvideo.o"
testtrace_VIDEO_O="src/video/testtrace-xvideo.o"
testui_VIDEO_O="src/video/testui-xvideo.o"
testvm_VIDEO_O="src/video/testvm-xvideo.o"
], [
AC_MSG_ERROR([Did not find OpenGL nor X11 libraries...])
], [-LX11])
testcpu_VIDEO_O="$testcpu_VIDEO_O src/video/testcpu-xvideo.o"
testdisk_VIDEO_O="$testdisk_VIDEO_O src/video/testdisk-xvideo.o"
testdisplay_VIDEO_O="$testdisplay_VIDEO_O src/video/testdisplay-xvideo.o"
testprefs_VIDEO_O="$testprefs_VIDEO_O src/video/testprefs-xvideo.o"
testtrace_VIDEO_O="$testtrace_VIDEO_O src/video/testtrace-xvideo.o"
testui_VIDEO_O="$testui_VIDEO_O src/video/testui-xvideo.o"
testvm_VIDEO_O="$testvm_VIDEO_O src/video/testvm-xvideo.o"
AC_MSG_RESULT([Building emulator with X11 support])
])
], [
AC_MSG_ERROR([Did not find OpenGL nor X11 headers...])
AS_IF([test "x$enable_x11" != "xno"], [
AC_MSG_WARN([Did not find X11 libraries, X11 support is disabled ...])
])
], [-LX11])
], [
AS_IF([test "x$enable_x11" != "xno"], [
AC_MSG_WARN([Did not find X11 headers, X11 support is disabled ...])
])
])
AC_SUBST(VIDEO_O)
AC_SUBST(testcpu_VIDEO_O)
AC_SUBST(testdisk_VIDEO_O)
@ -248,45 +260,62 @@ AC_SUBST(testtrace_VIDEO_O)
AC_SUBST(testui_VIDEO_O)
AC_SUBST(testvm_VIDEO_O)
dnl ---------------------------------------------------------------------------
dnl Sound ...
openal_selected='yes'
AC_ARG_ENABLE([audio], AS_HELP_STRING([--disable-audio], [Disable emulator audio output]), [
openal_selected='no'
], [
AC_CHECK_HEADER(AL/al.h, [
AC_CHECK_HEADER(AL/alc.h, [
AC_CHECK_HEADER(AL/alext.h, [
AC_SEARCH_LIBS(alcOpenDevice, openal, [
AUDIO_GLUE_C="src/audio/speaker.c src/audio/mockingboard.c"
AUDIO_O="src/audio/soundcore.o src/audio/speaker.o src/audio/mockingboard.o src/audio/AY8910.o"
testcpu_AUDIO_O="src/audio/testcpu-soundcore.o src/audio/testcpu-speaker.o src/audio/testcpu-mockingboard.o src/audio/testcpu-AY8910.o"
testdisk_AUDIO_O="src/audio/testdisk-soundcore.o src/audio/testdisk-speaker.o src/audio/testdisk-mockingboard.o src/audio/testdisk-AY8910.o"
testdisplay_AUDIO_O="src/audio/testdisplay-soundcore.o src/audio/testdisplay-speaker.o src/audio/testdisplay-mockingboard.o src/audio/testdisplay-AY8910.o"
testprefs_AUDIO_O="src/audio/testprefs-soundcore.o src/audio/testprefs-speaker.o src/audio/testprefs-mockingboard.o src/audio/testprefs-AY8910.o"
testtrace_AUDIO_O="src/audio/testtrace-soundcore.o src/audio/testtrace-speaker.o src/audio/testtrace-mockingboard.o src/audio/testtrace-AY8910.o"
testui_AUDIO_O="src/audio/testui-soundcore.o src/audio/testui-speaker.o src/audio/testui-mockingboard.o src/audio/testui-AY8910.o"
testvm_AUDIO_O="src/audio/testvm-soundcore.o src/audio/testvm-speaker.o src/audio/testvm-mockingboard.o src/audio/testvm-AY8910.o"
AC_ARG_ENABLE([openal], AS_HELP_STRING([--enable-openal], [Enable OpenAL audio output (autodetected)]))
AC_CHECK_HEADER(AL/al.h, [
AC_CHECK_HEADER(AL/alc.h, [
AC_CHECK_HEADER(AL/alext.h, [
AC_SEARCH_LIBS(alcOpenDevice, openal, [
AS_IF([test "x$enable_openal" != "xno"], [
dnl found OpenAL ...
openal_supported='yes'
AUDIO_GLUE_C="src/audio/speaker.c src/audio/mockingboard.c"
AUDIO_O="src/audio/soundcore.o src/audio/soundcore-openal.o src/audio/speaker.o src/audio/playqueue.o src/audio/alhelpers.o src/audio/mockingboard.o src/audio/AY8910.o"
AUDIO_O="$AUDIO_O src/audio/soundcore-openal.o src/audio/playqueue.o src/audio/alhelpers.o"
dnl HACK there's gotta be a better way ... without this verbosity, CFLAGS are not correct (lacking -DTESTING=1 , etc) if we don't specify specific obj files for test binaries
testcpu_AUDIO_O="src/audio/testcpu-soundcore.o src/audio/testcpu-soundcore-openal.o src/audio/testcpu-speaker.o src/audio/testcpu-playqueue.o src/audio/testcpu-alhelpers.o src/audio/testcpu-mockingboard.o src/audio/testcpu-AY8910.o"
testdisk_AUDIO_O="src/audio/testdisk-soundcore.o src/audio/testdisk-soundcore-openal.o src/audio/testdisk-speaker.o src/audio/testdisk-playqueue.o src/audio/testdisk-alhelpers.o src/audio/testdisk-mockingboard.o src/audio/testdisk-AY8910.o"
testdisplay_AUDIO_O="src/audio/testdisplay-soundcore.o src/audio/testdisplay-soundcore-openal.o src/audio/testdisplay-speaker.o src/audio/testdisplay-playqueue.o src/audio/testdisplay-alhelpers.o src/audio/testdisplay-mockingboard.o src/audio/testdisplay-AY8910.o"
testprefs_AUDIO_O="src/audio/testprefs-soundcore.o src/audio/testprefs-soundcore-openal.o src/audio/testprefs-speaker.o src/audio/testprefs-playqueue.o src/audio/testprefs-alhelpers.o src/audio/testprefs-mockingboard.o src/audio/testprefs-AY8910.o"
testtrace_AUDIO_O="src/audio/testtrace-soundcore.o src/audio/testtrace-soundcore-openal.o src/audio/testtrace-speaker.o src/audio/testtrace-playqueue.o src/audio/testtrace-alhelpers.o src/audio/testtrace-mockingboard.o src/audio/testtrace-AY8910.o"
testui_AUDIO_O="src/audio/testui-soundcore.o src/audio/testui-soundcore-openal.o src/audio/testui-speaker.o src/audio/testui-playqueue.o src/audio/testui-alhelpers.o src/audio/testui-mockingboard.o src/audio/testui-AY8910.o"
testvm_AUDIO_O="src/audio/testvm-soundcore.o src/audio/testvm-soundcore-openal.o src/audio/testvm-speaker.o src/audio/testvm-playqueue.o src/audio/testvm-alhelpers.o src/audio/testvm-mockingboard.o src/audio/testvm-AY8910.o"
], [
AC_MSG_ERROR([Could not find OpenAL libraries ... todo fixme ... implement a null sound backend])
], [])
testcpu_AUDIO_O="$testcpu_AUDIO_O src/audio/testcpu-soundcore-openal.o src/audio/testcpu-playqueue.o src/audio/testcpu-alhelpers.o"
testdisk_AUDIO_O="$testdisk_AUDIO_O src/audio/testdisk-soundcore-openal.o src/audio/testdisk-playqueue.o src/audio/testdisk-alhelpers.o"
testdisplay_AUDIO_O="$testdisplay_AUDIO_O src/audio/testdisplay-soundcore-openal.o src/audio/testdisplay-playqueue.o src/audio/testdisplay-alhelpers.o"
testprefs_AUDIO_O="$testprefs_AUDIO_O src/audio/testprefs-soundcore-openal.o src/audio/testprefs-playqueue.o src/audio/testprefs-alhelpers.o"
testtrace_AUDIO_O="$testtrace_AUDIO_O src/audio/testtrace-soundcore-openal.o src/audio/testtrace-playqueue.o src/audio/testtrace-alhelpers.o"
testui_AUDIO_O="$testui_AUDIO_O src/audio/testui-soundcore-openal.o src/audio/testui-playqueue.o src/audio/testui-alhelpers.o"
testvm_AUDIO_O="$testvm_AUDIO_O src/audio/testvm-soundcore-openal.o src/audio/testvm-playqueue.o src/audio/testvm-alhelpers.o"
])
], [
AC_MSG_ERROR([Could not find OpenAL headers ... todo fixme ... implement a null sound backend])
], [
#include <AL/al.h>
#include <AL/alc.h>
AS_IF([test "x$enable_openal" != "xno"], [
AC_MSG_WARN([Did not find OpenAL libraries, OpenAL sound output is disabled ...])
])
], [])
], [
AS_IF([test "x$enable_openal" != "xno"], [
AC_MSG_WARN([Could not find OpenAL headers, OpenAL sound output is disabled ...])
])
], [
AC_MSG_ERROR([Could not find OpenAL headers ... todo fixme ... implement a null sound backend])
#include <AL/al.h>
#include <AL/alc.h>
])
], [
AC_MSG_ERROR([Could not find OpenAL headers ... todo fixme ... implement a null sound backend])
AS_IF([test "x$enable_openal" != "xno"], [
AC_MSG_WARN([Could not find OpenAL headers, OpenAL sound output is disabled ...])
])
])
], [
AS_IF([test "x$enable_openal" != "xno"], [
AC_MSG_WARN([Could not find OpenAL headers, OpenAL sound output is disabled ...])
])
])
AC_SUBST(AUDIO_GLUE_C)
AC_SUBST(AUDIO_O)
AC_SUBST(testcpu_AUDIO_O)
@ -297,14 +326,6 @@ AC_SUBST(testtrace_AUDIO_O)
AC_SUBST(testui_AUDIO_O)
AC_SUBST(testvm_AUDIO_O)
AS_IF([test "x$openal_supported" = "xyes"], [
], [
dnl OpenAL not supported
AS_IF([test "x$openal_selected" = "xyes"], [
AC_MSG_WARN([!!! DID NOT FIND OPENAL LIBRARIES !!! audio will be disabled (this is OKAY but LIMITED) ...])
], [])
])
dnl ---------------------------------------------------------------------------
dnl Debugger & classic interface ...

View File

@ -1282,7 +1282,7 @@ static DWORD WINAPI SSI263Thread(LPVOID lpParameter)
#else
static void* SSI263Thread(void *lpParameter)
{
const unsigned long nsecWait = NANOSECONDS_PER_SECOND / audio_backend->systemSettings.sampleRateHz;
const unsigned long nsecWait = NANOSECONDS_PER_SECOND / audio_getCurrentBackend()->systemSettings.sampleRateHz;
const struct timespec wait = { .tv_sec=0, .tv_nsec=nsecWait };
while(1)
@ -1518,13 +1518,13 @@ static bool MB_DSInit()
}
#if 1 // APPLE2IX
SAMPLE_RATE = audio_backend->systemSettings.sampleRateHz;
SAMPLE_RATE = audio_getCurrentBackend()->systemSettings.sampleRateHz;
#if MB_TRACING
// force determinism
SAMPLE_RATE = 44100;
#endif
g_dwDSBufferSize = audio_backend->systemSettings.stereoBufferSizeSamples * audio_backend->systemSettings.bytesPerSample * g_nMB_NumChannels;
g_nMixBuffer = MALLOC(g_dwDSBufferSize / audio_backend->systemSettings.bytesPerSample);
g_dwDSBufferSize = audio_getCurrentBackend()->systemSettings.stereoBufferSizeSamples * audio_getCurrentBackend()->systemSettings.bytesPerSample * g_nMB_NumChannels;
g_nMixBuffer = MALLOC(g_dwDSBufferSize / audio_getCurrentBackend()->systemSettings.bytesPerSample);
#else
bool bRes = DSZeroVoiceBuffer(&MockingboardVoice, "MB", g_dwDSBufferSize);
@ -1611,13 +1611,13 @@ static bool MB_DSInit()
bPause = false;
}
unsigned int nPhonemeByteLength = g_nPhonemeInfo[nPhoneme].nLength * audio_backend->systemSettings.bytesPerSample;
unsigned int nPhonemeByteLength = g_nPhonemeInfo[nPhoneme].nLength * audio_getCurrentBackend()->systemSettings.bytesPerSample;
#if 0 // !APPLE2IX
// NB. DSBCAPS_LOCSOFTWARE required for Phoneme+2==0x28 - sample too short (see KB327698)
hr = DSGetSoundBuffer(&SSI263Voice[i], DSBCAPS_CTRLVOLUME+DSBCAPS_CTRLPOSITIONNOTIFY+DSBCAPS_LOCSOFTWARE, nPhonemeByteLength, 22050, 1);
LogFileOutput("MB_DSInit: (%02d) DSGetSoundBuffer(), hr=0x%08X\n", i, hr);
#else
if (nPhonemeByteLength > audio_backend->systemSettings.monoBufferSizeSamples) {
if (nPhonemeByteLength > audio_getCurrentBackend()->systemSettings.monoBufferSizeSamples) {
RELEASE_ERRLOG("!!!!!!!!!!!!!!!!!!!!! phoneme length > buffer size !!!!!!!!!!!!!!!!!!!!!");
#warning ^^^^^^^^^^ require vigilence here around this change ... we used to be able to specify the exact buffer size ...
}

View File

@ -625,15 +625,11 @@ static long openal_systemResume(AudioContext_s *audio_context) {
static void _init_openal(void) {
LOG("Initializing OpenAL sound system");
assert((audio_backend == NULL) && "there can only be one!");
openal_audio_backend.setup = &openal_systemSetup;
openal_audio_backend.shutdown = &openal_systemShutdown;
openal_audio_backend.pause = &openal_systemPause;
openal_audio_backend.resume = &openal_systemResume;
audio_backend = &openal_audio_backend;
audio_registerBackend(&openal_audio_backend, AUD_PRIO_OPENAL);
}
static __attribute__((constructor)) void __init_openal(void) {

View File

@ -760,15 +760,11 @@ static long opensles_systemResume(AudioContext_s *audio_context) {
static void _init_opensl(void) {
LOG("Initializing OpenSLES sound system");
assert(audio_backend == NULL && "there can only be one!");
opensles_audio_backend.setup = &opensles_systemSetup;
opensles_audio_backend.shutdown = &opensles_systemShutdown;
opensles_audio_backend.pause = &opensles_systemPause;
opensles_audio_backend.resume = &opensles_systemResume;
audio_backend = &opensles_audio_backend;
audio_registerBackend(&opensles_audio_backend, AUD_PRIO_OPENSLES);
}
static __attribute__((constructor)) void __init_opensl(void) {

View File

@ -24,7 +24,15 @@ static AudioContext_s *audioContext = NULL;
bool audio_isAvailable = false;
float audio_latencySecs = 0.25f;
AudioBackend_s *audio_backend = NULL;
typedef struct backend_node_s {
struct backend_node_s *next;
long order;
AudioBackend_s *backend;
} backend_node_s;
static backend_node_s *head = NULL;
//-----------------------------------------------------------------------------
@ -73,16 +81,11 @@ bool audio_init(void) {
}
do {
if (!audio_backend) {
LOG("No backend audio available, cannot initialize soundcore");
break;
}
if (audioContext) {
audio_backend->shutdown(&audioContext);
audio_getCurrentBackend()->shutdown(&audioContext);
}
long err = audio_backend->setup((AudioContext_s**)&audioContext);
long err = audio_getCurrentBackend()->setup((AudioContext_s**)&audioContext);
if (err) {
LOG("Failed to create an audio context!");
break;
@ -100,7 +103,7 @@ void audio_shutdown(void) {
if (!audio_isAvailable) {
return;
}
audio_backend->shutdown(&audioContext);
audio_getCurrentBackend()->shutdown(&audioContext);
audio_isAvailable = false;
}
@ -115,7 +118,7 @@ void audio_pause(void) {
if (!audio_isAvailable) {
return;
}
audio_backend->pause(audioContext);
audio_getCurrentBackend()->pause(audioContext);
}
void audio_resume(void) {
@ -124,7 +127,7 @@ void audio_resume(void) {
if (!audio_isAvailable) {
return;
}
audio_backend->resume(audioContext);
audio_getCurrentBackend()->resume(audioContext);
}
void audio_setLatency(float latencySecs) {
@ -135,3 +138,67 @@ float audio_getLatency(void) {
return audio_latencySecs;
}
//-----------------------------------------------------------------------------
void audio_registerBackend(AudioBackend_s *backend, long order) {
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;
pthread_mutex_unlock(&mutex);
}
AudioBackend_s *audio_getCurrentBackend(void) {
return head->backend;
}
static long _null_backend_setup(INOUT AudioContext_s **audio_context) {
*audio_context = NULL;
return -1;
}
static long _null_backend_shutdown(INOUT AudioContext_s **audio_context) {
*audio_context = NULL;
return -1;
}
static long _null_backend_pause(AudioContext_s *audio_context) {
return -1;
}
static long _null_backend_resume(AudioContext_s *audio_context) {
return -1;
}
static void _init_soundcore(void) {
LOG("Initializing audio subsystem");
static AudioBackend_s null_backend = { { 0 } };
null_backend.setup = &_null_backend_setup;
null_backend.shutdown = &_null_backend_shutdown;
null_backend.pause = &_null_backend_pause;
null_backend.resume = &_null_backend_resume;
audio_registerBackend(&null_backend, AUD_PRIO_NULL);
}
static __attribute__((constructor)) void __init_soundcore(void) {
emulator_registerStartupCallback(CTOR_PRIORITY_LATE, &_init_soundcore);
}

View File

@ -146,7 +146,15 @@ typedef struct AudioBackend_s {
} AudioBackend_s;
// Audio backend registered at CTOR time
extern AudioBackend_s *audio_backend;
enum {
AUD_PRIO_ALSA = 10,
AUD_PRIO_OPENAL = 20,
AUD_PRIO_OPENSLES = 30,
AUD_PRIO_NULL = 100,
};
void audio_registerBackend(AudioBackend_s *backend, long prio);
AudioBackend_s *audio_getCurrentBackend(void);
#endif /* whole file */

View File

@ -102,7 +102,7 @@ static void _speaker_init_timing(void) {
// 46.28 //e cycles for 22.05kHz sample rate
// AppleWin NOTE : use integer value: Better for MJ Mahon's RT.SYNTH.DSK (integer multiples of 1.023MHz Clk)
cycles_per_sample = (unsigned int)(cycles_persec_target / (double)audio_backend->systemSettings.sampleRateHz);
cycles_per_sample = (unsigned int)(cycles_persec_target / (double)audio_getCurrentBackend()->systemSettings.sampleRateHz);
unsigned int last_remainder_buffer_size = remainder_buffer_size;
remainder_buffer_size = (unsigned int)cycles_per_sample;
@ -122,7 +122,7 @@ static void _speaker_init_timing(void) {
cycles_last_update = 0;
}
LOG("Speaker initialize timing ... cycles_persec_target:%f cycles_per_sample:%f speaker sampleRateHz:%lu", cycles_persec_target, cycles_per_sample, audio_backend->systemSettings.sampleRateHz);
LOG("Speaker initialize timing ... cycles_persec_target:%f cycles_per_sample:%f speaker sampleRateHz:%lu", cycles_persec_target, cycles_per_sample, audio_getCurrentBackend()->systemSettings.sampleRateHz);
if (is_fullspeed) {
remainder_buffer_idx = 0;
@ -387,20 +387,20 @@ void speaker_init(void) {
break;
}
assert(audio_backend->systemSettings.bytesPerSample == sizeof(int16_t));
assert(audio_getCurrentBackend()->systemSettings.bytesPerSample == sizeof(int16_t));
assert(NUM_CHANNELS == 2 || NUM_CHANNELS == 1);
if (NUM_CHANNELS == 2) {
bufferTotalSize = audio_backend->systemSettings.stereoBufferSizeSamples * audio_backend->systemSettings.bytesPerSample * NUM_CHANNELS;
bufferTotalSize = audio_getCurrentBackend()->systemSettings.stereoBufferSizeSamples * audio_getCurrentBackend()->systemSettings.bytesPerSample * NUM_CHANNELS;
} else {
bufferTotalSize = audio_backend->systemSettings.monoBufferSizeSamples * audio_backend->systemSettings.bytesPerSample;
bufferTotalSize = audio_getCurrentBackend()->systemSettings.monoBufferSizeSamples * audio_getCurrentBackend()->systemSettings.bytesPerSample;
}
bufferSizeIdealMin = bufferTotalSize/4;
bufferSizeIdealMax = bufferTotalSize/2;
channelsSampleRateHz = audio_backend->systemSettings.sampleRateHz * NUM_CHANNELS;
LOG("Speaker initializing with %lu buffer size (bytes), sample rate of %lu", bufferTotalSize, audio_backend->systemSettings.sampleRateHz);
channelsSampleRateHz = audio_getCurrentBackend()->systemSettings.sampleRateHz * NUM_CHANNELS;
LOG("Speaker initializing with %lu buffer size (bytes), sample rate of %lu", bufferTotalSize, audio_getCurrentBackend()->systemSettings.sampleRateHz);
remainder_buffer_size_max = ((CLK_6502_INT*(unsigned long)CPU_SCALE_FASTEST)/audio_backend->systemSettings.sampleRateHz)+1;
remainder_buffer_size_max = ((CLK_6502_INT*(unsigned long)CPU_SCALE_FASTEST)/audio_getCurrentBackend()->systemSettings.sampleRateHz)+1;
samples_buffer = CALLOC(1, channelsSampleRateHz * sizeof(int16_t));
if (!samples_buffer) {

View File

@ -473,7 +473,7 @@ static void save_track_data(int drive) {
}
static inline void animate_disk_track_sector(void) {
if (video_animations && video_animations->animation_showTrackSector) {
if (video_getAnimationDriver()->animation_showTrackSector) {
static int previous_sect = 0;
int sect_width = disk6.disk[disk6.drive].track_width>>4; // div-by-16
do {
@ -483,7 +483,7 @@ static inline void animate_disk_track_sector(void) {
int sect = disk6.disk[disk6.drive].run_byte/sect_width;
if (sect != previous_sect) {
previous_sect = sect;
video_animations->animation_showTrackSector(disk6.drive, disk6.disk[disk6.drive].phase>>1, sect);
video_getAnimationDriver()->animation_showTrackSector(disk6.drive, disk6.disk[disk6.drive].phase>>1, sect);
}
} while (0);
}

View File

@ -26,12 +26,18 @@ typedef enum drawpage_mode_t {
DRAWPAGE_HIRES,
} drawpage_mode_t;
typedef struct backend_node_s {
struct backend_node_s *next;
long order;
video_backend_s *backend;
} backend_node_s;
static backend_node_s *head = NULL;
// framebuffers
static uint8_t *video__fb = NULL;
A2Color_s colormap[256] = { { 0 } };
video_animation_s *video_animations = NULL;
video_backend_s *video_backend = NULL;
static pthread_t render_thread_id = 0;
static pthread_mutex_t video_scan_mutex = PTHREAD_MUTEX_INITIALIZER;
@ -1204,7 +1210,7 @@ void video_init(void) {
video__fb = MALLOC(SCANWIDTH*SCANHEIGHT*sizeof(uint8_t));
video_clear();
video_backend->init((void*)0);
video_getCurrentBackend()->init((void*)0);
}
void _video_setRenderThread(pthread_t id) {
@ -1224,7 +1230,7 @@ void video_shutdown(void) {
assert(!render_thread_id || pthread_self() == render_thread_id);
#endif
video_backend->shutdown();
video_getCurrentBackend()->shutdown();
if (pthread_self() == render_thread_id) {
FREE(video__fb);
@ -1233,11 +1239,11 @@ void video_shutdown(void) {
void video_render(void) {
assert(pthread_self() == render_thread_id);
video_backend->render();
video_getCurrentBackend()->render();
}
void video_main_loop(void) {
video_backend->main_loop();
video_getCurrentBackend()->main_loop();
}
void video_clear(void) {
@ -1549,6 +1555,54 @@ uint8_t floating_bus_hibit(const bool hibit) {
return (b & ~0x80) | (hibit ? 0x80 : 0);
}
// ----------------------------------------------------------------------------
void video_registerBackend(video_backend_s *backend, long order) {
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;
pthread_mutex_unlock(&mutex);
}
video_backend_s *video_getCurrentBackend(void) {
return head->backend;
}
video_animation_s *video_getAnimationDriver(void) {
return video_getCurrentBackend()->anim;
}
static void _null_backend_init(void *context) {
}
static void _null_backend_main_loop(void) {
}
static void _null_backend_render(void) {
}
static void _null_backend_shutdown(void) {
}
static void _init_interface(void) {
LOG("Initializing display subsystem");
_initialize_interface_fonts();
@ -1558,6 +1612,15 @@ static void _init_interface(void) {
_initialize_color();
prefs_registerListener(PREF_DOMAIN_VIDEO, &video_prefsChanged);
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);
}
static __attribute__((constructor)) void __init_interface(void) {

View File

@ -43,9 +43,9 @@ typedef struct video_animation_s {
} video_animation_s;
/*
* The registered video animations.
* Get current animation driver
*/
extern video_animation_s *video_animations;
video_animation_s *video_getAnimationDriver(void);
/*
* Prepare the video system, converting console to graphics mode, or

View File

@ -589,8 +589,8 @@ void c_interface_select_diskette( int drive )
}
else
{
if (video_animations->animation_showDiskChosen) {
video_animations->animation_showDiskChosen(drive);
if (video_getAnimationDriver()->animation_showDiskChosen) {
video_getAnimationDriver()->animation_showDiskChosen(drive);
}
}
@ -664,8 +664,8 @@ void c_interface_select_diskette( int drive )
}
else
{
if (video_animations->animation_showDiskChosen) {
video_animations->animation_showDiskChosen(drive);
if (video_getAnimationDriver()->animation_showDiskChosen) {
video_getAnimationDriver()->animation_showDiskChosen(drive);
}
}

View File

@ -252,8 +252,8 @@ void c_keys_handle_input(int scancode, int pressed, int is_cooked)
cpu_pause();
timing_toggleCPUSpeed();
cpu_resume();
if (video_animations->animation_showCPUSpeed) {
video_animations->animation_showCPUSpeed();
if (video_getAnimationDriver()->animation_showCPUSpeed) {
video_getAnimationDriver()->animation_showCPUSpeed();
}
break;
}
@ -283,8 +283,8 @@ void c_keys_handle_input(int scancode, int pressed, int is_cooked)
cpu_scale_factor = scale;
}
if (video_animations->animation_showCPUSpeed) {
video_animations->animation_showCPUSpeed();
if (video_getAnimationDriver()->animation_showCPUSpeed) {
video_getAnimationDriver()->animation_showCPUSpeed();
}
cpu_pause();
@ -313,8 +313,8 @@ void c_keys_handle_input(int scancode, int pressed, int is_cooked)
cpu_scale_factor = scale;
}
if (video_animations->animation_showCPUSpeed) {
video_animations->animation_showCPUSpeed();
if (video_getAnimationDriver()->animation_showCPUSpeed) {
video_getAnimationDriver()->animation_showCPUSpeed();
}
cpu_pause();

View File

@ -380,9 +380,9 @@ static void alert_applyPrefs(void) {
bool bVal = false;
bool enabled = prefs_parseBoolValue(PREF_DOMAIN_INTERFACE, PREF_DISK_ANIMATIONS_ENABLED, &bVal) ? bVal : true;
if (enabled) {
video_animations->animation_showTrackSector = &_animation_showTrackSector;
glnode_animations->animation_showTrackSector = &_animation_showTrackSector;
} else {
video_animations->animation_showTrackSector = NULL;
glnode_animations->animation_showTrackSector = NULL;
}
long lVal = 0;
@ -400,11 +400,11 @@ static void alert_prefsChanged(const char *domain) {
static void _init_glalert(void) {
LOG("Initializing message animation subsystem");
video_animations->animation_showMessage = &_animation_showMessage;
video_animations->animation_showPaused = &_animation_showPaused;
video_animations->animation_showCPUSpeed = &_animation_showCPUSpeed;
video_animations->animation_showDiskChosen = &_animation_showDiskChosen;
video_animations->animation_showTrackSector = &_animation_showTrackSector;
glnode_animations->animation_showMessage = &_animation_showMessage;
glnode_animations->animation_showPaused = &_animation_showPaused;
glnode_animations->animation_showCPUSpeed = &_animation_showCPUSpeed;
glnode_animations->animation_showDiskChosen = &_animation_showDiskChosen;
glnode_animations->animation_showTrackSector = &_animation_showTrackSector;
glnode_registerNode(RENDER_MIDDLE, (GLNode){
.setup = &alert_init,

View File

@ -27,7 +27,7 @@ static glnode_array_node_s *head = NULL;
static glnode_array_node_s *tail = NULL;
static video_backend_s glnode_backend = { 0 };
static video_animation_s glnode_animations = { 0 };
video_animation_s glnode_animations = { 0 };
#if USE_GLUT
static bool glut_in_main_loop = false;
@ -238,16 +238,11 @@ static void glnode_mainLoop(void) {
static void _init_glnode_manager(void) {
LOG("Initializing GLNode manager subsystem");
assert((video_backend == NULL) && "there can only be one!");
assert((video_animations == NULL) && "there can only be one!");
glnode_backend.init = &glnode_setupNodes;
glnode_backend.main_loop = &glnode_mainLoop;
glnode_backend.render = &glnode_renderNodes;
glnode_backend.shutdown = &glnode_shutdownNodes;
video_backend = &glnode_backend;
video_animations = &glnode_animations;
glnode_backend.anim = &glnode_animations;
#if INTERFACE_TOUCH
interface_onTouchEvent = &glnode_onTouchEvent;
@ -256,6 +251,8 @@ static void _init_glnode_manager(void) {
#if USE_GLUT && !TEST_CPU
joydriver_resetJoystick = &_glutJoystickReset;
#endif
video_registerBackend(&glnode_backend, VID_PRIO_GRAPHICS_GL);
}
static __attribute__((constructor)) void __init_glnode_manager(void) {

View File

@ -118,5 +118,8 @@ static void inline swizzleDimensions(int *w, int *h, bool landscape) {
}
}
// animations
extern video_animation_s glnode_animations;
#endif // whole file

View File

@ -468,7 +468,7 @@ static void gltouchjoy_setup(void) {
joyglobals.isAvailable = true;
if (joyglobals.ownsScreen) {
video_animations->animation_showTouchJoystick();
video_getAnimationDriver()->animation_showTouchJoystick();
}
}
@ -911,8 +911,8 @@ static void _init_gltouchjoy(void) {
joyglobals.prefsChanged = true; // force reload preferences/defaults
video_animations->animation_showTouchJoystick = &_animation_showTouchJoystick;
video_animations->animation_hideTouchJoystick = &_animation_hideTouchJoystick;
video_getAnimationDriver()->animation_showTouchJoystick = &_animation_showTouchJoystick;
video_getAnimationDriver()->animation_hideTouchJoystick = &_animation_hideTouchJoystick;
glnode_registerNode(RENDER_LOW, (GLNode){
.type = TOUCH_DEVICE_JOYSTICK,

View File

@ -571,7 +571,7 @@ static void gltouchkbd_setup(void) {
isAvailable = true;
if (ownsScreen) {
video_animations->animation_showTouchKeyboard();
video_getAnimationDriver()->animation_showTouchKeyboard();
}
}
@ -1054,8 +1054,8 @@ static void _init_gltouchkbd(void) {
_initialize_keyboard_templates();
video_animations->animation_showTouchKeyboard = &_animation_showTouchKeyboard;
video_animations->animation_hideTouchKeyboard = &_animation_hideTouchKeyboard;
video_getAnimationDriver()->animation_showTouchKeyboard = &_animation_showTouchKeyboard;
video_getAnimationDriver()->animation_hideTouchKeyboard = &_animation_hideTouchKeyboard;
kbd.prefsChanged = true;
kbd.selectedCol = -1;

View File

@ -259,8 +259,8 @@ static inline void _step_cpu_speed(int delta) {
prefs_setFloatValue(PREF_DOMAIN_VM, PREF_CPU_SCALE, scale);
prefs_sync(PREF_DOMAIN_VM);
if (video_animations->animation_showCPUSpeed) {
video_animations->animation_showCPUSpeed();
if (video_getAnimationDriver()->animation_showCPUSpeed) {
video_getAnimationDriver()->animation_showCPUSpeed();
}
timing_initialize();
@ -623,8 +623,8 @@ static void gltouchmenu_prefsChanged(const char *domain) {
static void _init_gltouchmenu(void) {
LOG("Registering OpenGL software touch menu");
video_animations->animation_showTouchMenu = &_animation_showTouchMenu;
video_animations->animation_hideTouchMenu = &_animation_hideTouchMenu;
video_getAnimationDriver()->animation_showTouchMenu = &_animation_showTouchMenu;
video_getAnimationDriver()->animation_hideTouchMenu = &_animation_hideTouchMenu;
menu.prefsChanged = true;

View File

@ -19,16 +19,11 @@
typedef struct video_backend_s {
void (*init)(void *context);
void (*main_loop)(void);
void (*reshape)(int width, int height, bool landscape);
void (*render)(void);
void (*shutdown)(void);
video_animation_s *anim;
} video_backend_s;
/*
* The registered video backend (renderer).
*/
extern video_backend_s *video_backend;
/*
* Color structure
*/
@ -55,5 +50,16 @@ typedef enum a2_video_mode_t {
extern a2_video_mode_t a2_video_mode;
#endif
enum {
VID_PRIO_GRAPHICS_GL = 10,
VID_PRIO_GRAPHICS_X = 20,
VID_PRIO_TERMINAL = 30,
VID_PRIO_NULL = 100,
};
void video_registerBackend(video_backend_s *backend, long prio);
video_backend_s *video_getCurrentBackend(void);
#endif /* !A2_VIDEO_H */

View File

@ -60,7 +60,6 @@ static int xshmeventtype;
// pad pixels to uint32_t boundaries
static int bitmap_pad = sizeof(uint32_t);
static video_backend_s xvideo_backend = { 0 };
static bool request_set_mode = false;
static a2_video_mode_t request_mode = VIDEO_2X;
@ -860,10 +859,6 @@ static void xdriver_shutdown(bool emulatorShuttingDown) {
_destroy_image();
}
static void xdriver_reshape(int width, int height) {
// no-op
}
static void xdriver_render(void) {
// no-op
}
@ -871,15 +866,14 @@ static void xdriver_render(void) {
static void _init_xvideo(void) {
LOG("Initializing X11 renderer");
assert((video_backend == NULL) && "there can only be one!");
static video_backend_s xvideo_backend = { 0 };
static video_animation_s xdriver_animations = { 0 };
xvideo_backend.init = &xdriver_init;
xvideo_backend.main_loop = &xdriver_main_loop;
xvideo_backend.reshape = &xdriver_reshape;
xvideo_backend.render = &xdriver_render;
xvideo_backend.shutdown = &xdriver_shutdown;
video_backend = &xvideo_backend;
xvideo_backend.anim = &xdriver_animations;
video_registerBackend(&xvideo_backend, VID_PRIO_GRAPHICS_X);
}
static __attribute__((constructor)) void __init_xvideo(void) {