diff --git a/configure.ac b/configure.ac index d4ef971a..8bb09c60 100644 --- a/configure.ac +++ b/configure.ac @@ -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 -#include + 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 +#include ]) ], [ - 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 ... diff --git a/src/audio/mockingboard.c b/src/audio/mockingboard.c index 60e3e3bf..a59fd20a 100644 --- a/src/audio/mockingboard.c +++ b/src/audio/mockingboard.c @@ -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 ... } diff --git a/src/audio/soundcore-openal.c b/src/audio/soundcore-openal.c index eb0d31e8..d8b8fc9b 100644 --- a/src/audio/soundcore-openal.c +++ b/src/audio/soundcore-openal.c @@ -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) { diff --git a/src/audio/soundcore-opensles.c b/src/audio/soundcore-opensles.c index b51b957c..434f4d7d 100644 --- a/src/audio/soundcore-opensles.c +++ b/src/audio/soundcore-opensles.c @@ -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) { diff --git a/src/audio/soundcore.c b/src/audio/soundcore.c index 8e242957..fed3549a 100644 --- a/src/audio/soundcore.c +++ b/src/audio/soundcore.c @@ -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); +} + diff --git a/src/audio/soundcore.h b/src/audio/soundcore.h index 60ab6aa0..e27b96f1 100644 --- a/src/audio/soundcore.h +++ b/src/audio/soundcore.h @@ -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 */ diff --git a/src/audio/speaker.c b/src/audio/speaker.c index a8ae4cc1..59959d98 100644 --- a/src/audio/speaker.c +++ b/src/audio/speaker.c @@ -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) { diff --git a/src/disk.c b/src/disk.c index be78a04d..afbd0f3f 100644 --- a/src/disk.c +++ b/src/disk.c @@ -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); } diff --git a/src/display.c b/src/display.c index 1208f18e..c8d5569d 100644 --- a/src/display.c +++ b/src/display.c @@ -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) { diff --git a/src/display.h b/src/display.h index 8040d727..5b75dc83 100644 --- a/src/display.h +++ b/src/display.h @@ -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 diff --git a/src/interface.c b/src/interface.c index 167a73be..e351ef1b 100644 --- a/src/interface.c +++ b/src/interface.c @@ -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); } } diff --git a/src/keys.c b/src/keys.c index 6935fab1..e19e3dda 100644 --- a/src/keys.c +++ b/src/keys.c @@ -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(); diff --git a/src/video/glalert.c b/src/video/glalert.c index c9a194d2..f0fd2173 100644 --- a/src/video/glalert.c +++ b/src/video/glalert.c @@ -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, diff --git a/src/video/glnode.c b/src/video/glnode.c index eebb9dbf..cd12f3bf 100644 --- a/src/video/glnode.c +++ b/src/video/glnode.c @@ -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) { diff --git a/src/video/glnode.h b/src/video/glnode.h index 3d1da832..b9cdec8c 100644 --- a/src/video/glnode.h +++ b/src/video/glnode.h @@ -118,5 +118,8 @@ static void inline swizzleDimensions(int *w, int *h, bool landscape) { } } +// animations +extern video_animation_s glnode_animations; + #endif // whole file diff --git a/src/video/gltouchjoy.c b/src/video/gltouchjoy.c index 30e9c6f0..816d8c08 100644 --- a/src/video/gltouchjoy.c +++ b/src/video/gltouchjoy.c @@ -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, diff --git a/src/video/gltouchkbd.c b/src/video/gltouchkbd.c index 34ba36f6..1f2c298a 100644 --- a/src/video/gltouchkbd.c +++ b/src/video/gltouchkbd.c @@ -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; diff --git a/src/video/gltouchmenu.c b/src/video/gltouchmenu.c index 2a7bd09d..c5cae5ab 100644 --- a/src/video/gltouchmenu.c +++ b/src/video/gltouchmenu.c @@ -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; diff --git a/src/video/video.h b/src/video/video.h index 33959bee..1f6bdea4 100644 --- a/src/video/video.h +++ b/src/video/video.h @@ -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 */ diff --git a/src/video/xvideo.c b/src/video/xvideo.c index 4de83ac5..20e2fd82 100644 --- a/src/video/xvideo.c +++ b/src/video/xvideo.c @@ -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) {