Move queued buffer code from gaudio into gqueue

ugfx_release_2.6
inmarket 2014-03-20 23:33:32 +10:00
parent e4d6884bca
commit 8b9d31ef90
16 changed files with 234 additions and 158 deletions

View File

@ -96,7 +96,7 @@ GHandle gwinGScopeCreate(GDisplay *g, GScopeObject *gs, GWindowInit *pInit, uint
void gwinScopeWaitForTrace(GHandle gh) { void gwinScopeWaitForTrace(GHandle gh) {
#define gs ((GScopeObject *)(gh)) #define gs ((GScopeObject *)(gh))
GAudioData *paud; GDataBuffer *paud;
int i; int i;
coord_t x, y; coord_t x, y;
coord_t yoffset; coord_t yoffset;
@ -216,6 +216,6 @@ void gwinScopeWaitForTrace(GHandle gh) {
gs->scopemin = scopemin; gs->scopemin = scopemin;
#endif #endif
gaudioReleaseBuffer(paud); gfxBufferRelease(paud);
#undef gs #undef gs
} }

View File

@ -58,7 +58,7 @@ int main(void) {
// Allocate audio buffers - 4 x 128 byte buffers. // Allocate audio buffers - 4 x 128 byte buffers.
// You may need to increase this for slower cpu's. // You may need to increase this for slower cpu's.
// You may be able to decrease this for low latency operating systems. // You may be able to decrease this for low latency operating systems.
gaudioAllocBuffers(4, 128); gfxBufferAlloc(4, 128);
/* Get the screen dimensions */ /* Get the screen dimensions */
swidth = gdispGetWidth(); swidth = gdispGetWidth();

View File

@ -64,7 +64,7 @@ int main(void) {
// Allocate audio buffers - 4 x 512 byte buffers. // Allocate audio buffers - 4 x 512 byte buffers.
// You may need to increase this for slower cpu's. // You may need to increase this for slower cpu's.
// You may be able to decrease this for low latency operating systems. // You may be able to decrease this for low latency operating systems.
if (!gaudioAllocBuffers(4, 512)) { if (!gfxBufferAlloc(4, 512)) {
errmsg = "Err: No Memory"; errmsg = "Err: No Memory";
goto theend; goto theend;
} }
@ -164,7 +164,7 @@ int main(void) {
gdispDrawString(0, gdispGetHeight()/2, "Playing...", font, Yellow); gdispDrawString(0, gdispGetHeight()/2, "Playing...", font, Yellow);
while(toplay) { while(toplay) {
// Get a buffer to put the data into // Get a buffer to put the data into
paud = gaudioGetBuffer(TIME_INFINITE); // This should never fail as we are waiting forever paud = gfxBufferGet(TIME_INFINITE); // This should never fail as we are waiting forever
// How much data can we put in // How much data can we put in
len = toplay > paud->size ? paud->size : toplay; len = toplay > paud->size ? paud->size : toplay;

View File

@ -47,7 +47,7 @@ static DWORD threadID;
*************************************************************************/ *************************************************************************/
static bool_t senddata(WAVEHDR *pwh) { static bool_t senddata(WAVEHDR *pwh) {
GAudioData *paud; GDataBuffer *paud;
// Get the next data block to send // Get the next data block to send
gfxSystemLock(); gfxSystemLock();
@ -94,7 +94,7 @@ static DWORD WINAPI waveProc(LPVOID arg) {
// Give the buffer back to the Audio Free List // Give the buffer back to the Audio Free List
gfxSystemLock(); gfxSystemLock();
gaudioPlayReleaseDataBlockI((GAudioData *)pwh->dwUser); gaudioPlayReleaseDataBlockI((GDataBuffer *)pwh->dwUser);
gfxSystemUnlock(); gfxSystemUnlock();
pwh->lpData = 0; pwh->lpData = 0;
nQueuedBuffers--; nQueuedBuffers--;

View File

@ -47,7 +47,7 @@ static DWORD threadID;
*************************************************************************/ *************************************************************************/
static bool_t getbuffer(WAVEHDR *pwh) { static bool_t getbuffer(WAVEHDR *pwh) {
GAudioData *paud; GDataBuffer *paud;
// Get the next data block to send // Get the next data block to send
gfxSystemLock(); gfxSystemLock();
@ -81,7 +81,7 @@ static bool_t getbuffer(WAVEHDR *pwh) {
static DWORD WINAPI waveProc(LPVOID arg) { static DWORD WINAPI waveProc(LPVOID arg) {
MSG msg; MSG msg;
WAVEHDR *pwh; WAVEHDR *pwh;
GAudioData *paud; GDataBuffer *paud;
(void) arg; (void) arg;
while (GetMessage(&msg, 0, 0, 0)) { while (GetMessage(&msg, 0, 0, 0)) {
@ -93,7 +93,7 @@ static DWORD WINAPI waveProc(LPVOID arg) {
waveInUnprepareHeader(ah, pwh, sizeof(WAVEHDR)); waveInUnprepareHeader(ah, pwh, sizeof(WAVEHDR));
// Save the buffer in the audio record list // Save the buffer in the audio record list
paud = (GAudioData *)pwh->dwUser; paud = (GDataBuffer *)pwh->dwUser;
paud->len = pwh->dwBytesRecorded; paud->len = pwh->dwBytesRecorded;
gfxSystemLock(); gfxSystemLock();
gaudioRecordSaveDataBlockI(paud); gaudioRecordSaveDataBlockI(paud);

View File

@ -175,7 +175,7 @@
#define GQUEUE_NEED_ASYNC FALSE #define GQUEUE_NEED_ASYNC FALSE
#define GQUEUE_NEED_GSYNC FALSE #define GQUEUE_NEED_GSYNC FALSE
#define GQUEUE_NEED_FSYNC FALSE #define GQUEUE_NEED_FSYNC FALSE
#define GQUEUE_NEED_BUFFERS FALSE
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// GINPUT // // GINPUT //

View File

@ -42,19 +42,19 @@ extern "C" {
* @iclass * @iclass
* @notapi * @notapi
*/ */
GAudioData *gaudioPlayGetDataBlockI(void); GDataBuffer *gaudioPlayGetDataBlockI(void);
/** /**
* @brief Release a block of audio data to the free list * @brief Release a block of audio data to the free list
* *
* @param[in] paud The GAudioData block to be released. * @param[in] paud The GDataBuffer block to be released.
* *
* @note Defined in the high level GAUDIO code for use by the GAUDIO play drivers. * @note Defined in the high level GAUDIO code for use by the GAUDIO play drivers.
* *
* @iclass * @iclass
* @notapi * @notapi
*/ */
void gaudioPlayReleaseDataBlockI(GAudioData *paud); void gaudioPlayReleaseDataBlockI(GDataBuffer *paud);
/** /**
* @brief Signal that all playing has now stopped * @brief Signal that all playing has now stopped

View File

@ -34,19 +34,19 @@
* @iclass * @iclass
* @notapi * @notapi
*/ */
GAudioData *gaudioRecordGetFreeBlockI(void); #define gaudioRecordGetFreeBlockI() gfxBufferGetI()
/** /**
* @brief Save a block of recorded audio data ready for the application * @brief Save a block of recorded audio data ready for the application
* *
* @param[in] paud The GAudioData block with data. * @param[in] paud The GDataBuffer block with data.
* *
* @note Defined in the high level GAUDIO code for use by the GAUDIO record drivers. * @note Defined in the high level GAUDIO code for use by the GAUDIO record drivers.
* *
* @iclass * @iclass
* @notapi * @notapi
*/ */
void gaudioRecordSaveDataBlockI(GAudioData *paud); void gaudioRecordSaveDataBlockI(GDataBuffer *paud);
/** /**
* @brief Signal that all recording has now stopped * @brief Signal that all recording has now stopped

View File

@ -16,8 +16,6 @@
#if GFX_USE_GAUDIO #if GFX_USE_GAUDIO
static gfxQueueGSync freeList;
#if GAUDIO_NEED_PLAY #if GAUDIO_NEED_PLAY
#include "src/gaudio/driver_play.h" #include "src/gaudio/driver_play.h"
@ -51,7 +49,6 @@ static gfxQueueGSync freeList;
void _gaudioInit(void) void _gaudioInit(void)
{ {
gfxQueueGSyncInit(&freeList);
#if GAUDIO_NEED_PLAY #if GAUDIO_NEED_PLAY
gfxQueueASyncInit(&playList); gfxQueueASyncInit(&playList);
#if GFX_USE_GEVENT #if GFX_USE_GEVENT
@ -70,48 +67,20 @@ void _gaudioInit(void)
void _gaudioDeinit(void) void _gaudioDeinit(void)
{ {
#if GAUDIO_NEED_PLAY #if GAUDIO_NEED_PLAY
gfxQueueASyncDeinit(&playList);
#if GFX_USE_GEVENT #if GFX_USE_GEVENT
gtimerDeinit(&playTimer); gtimerDeinit(&playTimer);
#endif #endif
gfxSemDestroy(&playComplete); gfxSemDestroy(&playComplete);
#endif #endif
#if GAUDIO_NEED_RECORD #if GAUDIO_NEED_RECORD
gfxQueueGSyncDeinit(&recordList);
#if GFX_USE_GEVENT #if GFX_USE_GEVENT
gtimerDeinit(&recordTimer); gtimerDeinit(&recordTimer);
#endif #endif
#endif #endif
} }
bool_t gaudioAllocBuffers(unsigned num, size_t size) {
GAudioData *paud;
if (num < 1)
return FALSE;
// Round up to a multiple of 4 to prevent problems with structure alignment
size = (size + 3) & ~0x03;
// Allocate the memory
if (!(paud = gfxAlloc((size+sizeof(GAudioData)) * num)))
return FALSE;
// Add each of them to our free list
for(;num--; paud = (GAudioData *)((char *)(paud+1)+size)) {
paud->size = size;
gfxQueueGSyncPut(&freeList, (gfxQueueGSyncItem *)paud);
}
return TRUE;
}
void gaudioReleaseBuffer(GAudioData *paud) {
gfxQueueGSyncPut(&freeList, (gfxQueueGSyncItem *)paud);
}
GAudioData *gaudioGetBuffer(delaytime_t ms) {
return (GAudioData *)gfxQueueGSyncGet(&freeList, ms);
}
#if GAUDIO_NEED_PLAY #if GAUDIO_NEED_PLAY
bool_t gaudioPlayInit(uint16_t channel, uint32_t frequency, ArrayDataFormat format) { bool_t gaudioPlayInit(uint16_t channel, uint32_t frequency, ArrayDataFormat format) {
@ -123,11 +92,11 @@ GAudioData *gaudioGetBuffer(delaytime_t ms) {
return TRUE; return TRUE;
} }
void gaudioPlay(GAudioData *paud) { void gaudioPlay(GDataBuffer *pd) {
if (!(playFlags & PLAYFLG_ISINIT)) { if (!(playFlags & PLAYFLG_ISINIT)) {
// Oops - init failed - return it directly to the free-list // Oops - init failed - return it directly to the free-list
if (paud) { if (pd) {
gfxQueueGSyncPut(&freeList, (gfxQueueGSyncItem *)paud); gfxBufferRelease(pd);
gfxYield(); // Make sure we get no endless cpu hogging loops gfxYield(); // Make sure we get no endless cpu hogging loops
} }
return; return;
@ -145,12 +114,12 @@ GAudioData *gaudioGetBuffer(delaytime_t ms) {
} }
void gaudioPlayStop(void) { void gaudioPlayStop(void) {
GAudioData *paud; GDataBuffer *pd;
if (playFlags & PLAYFLG_PLAYING) if (playFlags & PLAYFLG_PLAYING)
gaudio_play_lld_stop(); gaudio_play_lld_stop();
while((paud = (GAudioData *)gfxQueueASyncGet(&playList))) while((pd = (GDataBuffer *)gfxQueueASyncGet(&playList)))
gfxQueueGSyncPut(&freeList, (gfxQueueGSyncItem *)paud); gfxBufferRelease(pd);
} }
bool_t gaudioPlaySetVolume(uint8_t vol) { bool_t gaudioPlaySetVolume(uint8_t vol) {
@ -182,7 +151,7 @@ GAudioData *gaudioGetBuffer(delaytime_t ms) {
psl->srcflags = 0; psl->srcflags = 0;
if ((playFlags & PLAYFLG_PLAYING)) if ((playFlags & PLAYFLG_PLAYING))
pe->flags |= GAUDIO_PLAY_PLAYING; pe->flags |= GAUDIO_PLAY_PLAYING;
if (!gfxQueueGSyncIsEmpty(&freeList)) if (gfxBufferIsAvailable())
pe->flags |= GAUDIO_PLAY_FREEBLOCK; pe->flags |= GAUDIO_PLAY_FREEBLOCK;
geventSendEvent(psl); geventSendEvent(psl);
} }
@ -200,12 +169,12 @@ GAudioData *gaudioGetBuffer(delaytime_t ms) {
* Routines provided for use by drivers. * Routines provided for use by drivers.
*/ */
GAudioData *gaudioPlayGetDataBlockI(void) { GDataBuffer *gaudioPlayGetDataBlockI(void) {
return (GAudioData *)gfxQueueASyncGetI(&playList); return (GDataBuffer *)gfxQueueASyncGetI(&playList);
} }
void gaudioPlayReleaseDataBlockI(GAudioData *paud) { void gaudioPlayReleaseDataBlockI(GDataBuffer *pd) {
gfxQueueGSyncPutI(&freeList, (gfxQueueGSyncItem *)paud); gfxBufferReleaseI(pd);
#if GFX_USE_GEVENT #if GFX_USE_GEVENT
if (playFlags & PLAYFLG_USEEVENTS) if (playFlags & PLAYFLG_USEEVENTS)
gtimerJabI(&playTimer); gtimerJabI(&playTimer);
@ -242,17 +211,17 @@ GAudioData *gaudioGetBuffer(delaytime_t ms) {
} }
void gaudioRecordStop(void) { void gaudioRecordStop(void) {
GAudioData *paud; GDataBuffer *pd;
if ((recordFlags & (RECORDFLG_RECORDING|RECORDFLG_STALLED)) == RECORDFLG_RECORDING) if ((recordFlags & (RECORDFLG_RECORDING|RECORDFLG_STALLED)) == RECORDFLG_RECORDING)
gaudio_record_lld_stop(); gaudio_record_lld_stop();
recordFlags &= ~(RECORDFLG_RECORDING|RECORDFLG_STALLED); recordFlags &= ~(RECORDFLG_RECORDING|RECORDFLG_STALLED);
while((paud = (GAudioData *)gfxQueueGSyncGet(&recordList, TIME_IMMEDIATE))) while((pd = (GDataBuffer *)gfxQueueGSyncGet(&recordList, TIME_IMMEDIATE)))
gfxQueueGSyncPut(&freeList, (gfxQueueGSyncItem *)paud); gfxBufferRelease(pd);
} }
GAudioData *gaudioRecordGetData(delaytime_t ms) { GDataBuffer *gaudioRecordGetData(delaytime_t ms) {
return (GAudioData *)gfxQueueGSyncGet(&recordList, ms); return (GDataBuffer *)gfxQueueGSyncGet(&recordList, ms);
} }
#if GFX_USE_GEVENT #if GFX_USE_GEVENT
@ -276,7 +245,7 @@ GAudioData *gaudioGetBuffer(delaytime_t ms) {
if ((recordFlags & RECORDFLG_STALLED)) if ((recordFlags & RECORDFLG_STALLED))
pe->flags |= GAUDIO_RECORD_STALL; pe->flags |= GAUDIO_RECORD_STALL;
if (!gfxQueueGSyncIsEmpty(&recordList)) if (!gfxQueueGSyncIsEmpty(&recordList))
pe->flags |= GAUDIO_RECORD_GOTBLOCK; pe->flags |= GAUDIO_RECORD_GOTBUFFER;
geventSendEvent(psl); geventSendEvent(psl);
} }
} }
@ -293,11 +262,7 @@ GAudioData *gaudioGetBuffer(delaytime_t ms) {
* Routines provided for use by drivers. * Routines provided for use by drivers.
*/ */
GAudioData *gaudioRecordGetFreeBlockI(void) { void gaudioRecordSaveDataBlockI(GDataBuffer *paud) {
return (GAudioData *)gfxQueueGSyncGetI(&freeList);
}
void gaudioRecordSaveDataBlockI(GAudioData *paud) {
gfxQueueGSyncPutI(&recordList, (gfxQueueGSyncItem *)paud); gfxQueueGSyncPutI(&recordList, (gfxQueueGSyncItem *)paud);
#if GFX_USE_GEVENT #if GFX_USE_GEVENT
if (recordFlags & RECORDFLG_USEEVENTS) if (recordFlags & RECORDFLG_USEEVENTS)

View File

@ -34,19 +34,6 @@
/* Type definitions */ /* Type definitions */
/*===========================================================================*/ /*===========================================================================*/
/**
* @brief Contains Audio Data Samples
* @note This structure is followed immediately by the sample data itself.
* When allocating the buffers for the sample data put this structure
* at the beginning of the buffer.
*/
typedef struct GAudioData {
gfxQueueASyncItem next; // @< Used for queuing the buffers
size_t size; // @< The size of the buffer area following this structure (in bytes)
size_t len; // @< The length of the data in the buffer area (in bytes)
} GAudioData;
// Event types for GAUDIO // Event types for GAUDIO
#define GEVENT_AUDIO_PLAY (GEVENT_GAUDIO_FIRST+0) #define GEVENT_AUDIO_PLAY (GEVENT_GAUDIO_FIRST+0)
#define GEVENT_AUDIO_RECORD (GEVENT_GAUDIO_FIRST+1) #define GEVENT_AUDIO_RECORD (GEVENT_GAUDIO_FIRST+1)
@ -95,7 +82,7 @@ typedef struct GAudioData {
*/ */
#define GAUDIO_RECORD_LOSTEVENT 0x0001 /**< @brief The last GEVENT_AUDIO_IN event was lost */ #define GAUDIO_RECORD_LOSTEVENT 0x0001 /**< @brief The last GEVENT_AUDIO_IN event was lost */
#define GAUDIO_RECORD_RECORDING 0x0002 /**< @brief The audio recording system is currently recording */ #define GAUDIO_RECORD_RECORDING 0x0002 /**< @brief The audio recording system is currently recording */
#define GAUDIO_RECORD_GOTBLOCK 0x0004 /**< @brief An audio buffer is ready for processing */ #define GAUDIO_RECORD_GOTBUFFER 0x0004 /**< @brief An audio buffer is ready for processing */
#define GAUDIO_RECORD_STALL 0x0008 /**< @brief The recording process has stalled due to no free buffers */ #define GAUDIO_RECORD_STALL 0x0008 /**< @brief The recording process has stalled due to no free buffers */
/** @} */ /** @} */
} GEventAudioRecord; } GEventAudioRecord;
@ -110,41 +97,6 @@ typedef struct GAudioData {
extern "C" { extern "C" {
#endif #endif
/**
* @brief Allocate some audio buffers and put them on the free list
* @return TRUE is it succeeded. FALSE on allocation failure.
*
* @param[in] num The number of buffers to allocate
* @param[in] size The size (in bytes) of each buffer
*
* @api
*/
bool_t gaudioAllocBuffers(unsigned num, size_t size);
/**
* @brief Get an audio buffer from the free list
* @return A GAudioData pointer or NULL if the timeout is exceeded
*
* @params[in] ms The maximum amount of time in milliseconds to wait for a buffer if one is not available.
*
* @api
*/
GAudioData *gaudioGetBuffer(delaytime_t ms);
/**
* @brief Release a buffer back to the free list
*
* @param[in] paud The buffer to put (back) on the free-list.
*
* @note This call should be used to return any buffers that were taken from
* the free-list once they have been finished with. It can also be used
* to put new buffers onto the free-list. Just make sure the "size" field
* of the GAudioData structure has been filled in first.
*
* @api
*/
void gaudioReleaseBuffer(GAudioData *paud);
#if GAUDIO_NEED_PLAY || defined(__DOXYGEN__) #if GAUDIO_NEED_PLAY || defined(__DOXYGEN__)
/** /**
* @brief Set the audio device to play on the specified channel and with the specified * @brief Set the audio device to play on the specified channel and with the specified
@ -172,7 +124,7 @@ void gaudioReleaseBuffer(GAudioData *paud);
* @param[in] paud The audio sample buffer to play. It can be NULL (used to restart paused audio) * @param[in] paud The audio sample buffer to play. It can be NULL (used to restart paused audio)
* *
* @note Calling this will cancel any pause. * @note Calling this will cancel any pause.
* @note Before calling this function the len field of the GAudioData structure must be * @note Before calling this function the len field of the GDataBuffer structure must be
* specified (in bytes). * specified (in bytes).
* @note For stereo channels the sample data is interleaved in the buffer. * @note For stereo channels the sample data is interleaved in the buffer.
* @note This call returns before the data has completed playing. Subject to available buffers (which * @note This call returns before the data has completed playing. Subject to available buffers (which
@ -182,7 +134,7 @@ void gaudioReleaseBuffer(GAudioData *paud);
* *
* @api * @api
*/ */
void gaudioPlay(GAudioData *paud); void gaudioPlay(GDataBuffer *paud);
/** /**
* @brief Pause any currently playing sounds. * @brief Pause any currently playing sounds.
@ -298,16 +250,20 @@ void gaudioReleaseBuffer(GAudioData *paud);
/** /**
* @brief Get a filled audio buffer from the recording list * @brief Get a filled audio buffer from the recording list
* @return A GAudioData pointer or NULL if the timeout is exceeded * @return A GDataBuffer pointer or NULL if the timeout is exceeded
* *
* @params[in] ms The maximum amount of time in milliseconds to wait for data if some is not currently available. * @params[in] ms The maximum amount of time in milliseconds to wait for data if some is not currently available.
* *
* @note After processing the audio data, your application must return the buffer to the free-list so that * @note After processing the audio data, your application must return the buffer to the free-list so that
* it can be used to record more audio into. This can be done via the play list using @p gaudioPlay() or * it can be used to record more audio into. This can be done via the play list using @p gaudioPlay() or
* directly using @p gaudioReleaseBuffer(). * directly using @p gfxBufferRelease().
* @note A buffer may be returned to the free-list before you have finished processing it provided you finish
* processing it before GADC re-uses it. This is useful when RAM usage is critical to reduce the number
* of buffers required. It works before the free list is a FIFO queue and therefore buffers are kept
* in the queue as long as possible before they are re-used.
* @api * @api
*/ */
GAudioData *gaudioRecordGetData(delaytime_t ms); GDataBuffer *gaudioRecordGetData(delaytime_t ms);
#if GFX_USE_GEVENT || defined(__DOXYGEN__) #if GFX_USE_GEVENT || defined(__DOXYGEN__)
/** /**

View File

@ -27,17 +27,19 @@
#undef GFX_USE_GQUEUE #undef GFX_USE_GQUEUE
#define GFX_USE_GQUEUE TRUE #define GFX_USE_GQUEUE TRUE
#endif #endif
#if !GQUEUE_NEED_ASYNC #if GAUDIO_NEED_PLAY && !GQUEUE_NEED_ASYNC
#if GFX_DISPLAY_RULE_WARNINGS #if GFX_DISPLAY_RULE_WARNINGS
#warning "GAUDIO: GQUEUE_NEED_ASYNC is required if GFX_USE_GAUDIO is TRUE. It has been turned on for you." #warning "GAUDIO: GQUEUE_NEED_ASYNC is required if GAUDIO_NEED_PLAY is TRUE. It has been turned on for you."
#endif #endif
#undef GQUEUE_NEED_ASYNC #undef GQUEUE_NEED_ASYNC
#define GQUEUE_NEED_ASYNC TRUE #define GQUEUE_NEED_ASYNC TRUE
#endif #endif
#if !GQUEUE_NEED_GSYNC #if !GQUEUE_NEED_GSYNC || !GQUEUE_NEED_BUFFERS
#if GFX_DISPLAY_RULE_WARNINGS #if GFX_DISPLAY_RULE_WARNINGS
#warning "GAUDIO: GQUEUE_NEED_GSYNC is required if GFX_USE_GAUDIO is TRUE. It has been turned on for you." #warning "GAUDIO: GQUEUE_NEED_BUFFERS and GQUEUE_NEED_GSYNC are required if GFX_USE_GAUDIO is TRUE. They have been turned on for you."
#endif #endif
#undef GQUEUE_NEED_BUFFERS
#define GQUEUE_NEED_BUFFERS TRUE
#undef GQUEUE_NEED_GSYNC #undef GQUEUE_NEED_GSYNC
#define GQUEUE_NEED_GSYNC TRUE #define GQUEUE_NEED_GSYNC TRUE
#endif #endif

View File

@ -48,6 +48,10 @@ extern void _gosDeinit(void);
extern void _gaudioInit(void); extern void _gaudioInit(void);
extern void _gaudioDeinit(void); extern void _gaudioDeinit(void);
#endif #endif
#if GFX_USE_GQUEUE
extern void _gqueueInit(void);
extern void _gqueueDeinit(void);
#endif
#if GFX_USE_GMISC #if GFX_USE_GMISC
extern void _gmiscInit(void); extern void _gmiscInit(void);
extern void _gmiscDeinit(void); extern void _gmiscDeinit(void);
@ -63,6 +67,9 @@ void gfxInit(void)
// These must be initialised in the order of their dependancies // These must be initialised in the order of their dependancies
_gosInit(); _gosInit();
#if GFX_USE_GQUEUE
_gqueueInit();
#endif
#if GFX_USE_GMISC #if GFX_USE_GMISC
_gmiscInit(); _gmiscInit();
#endif #endif
@ -118,7 +125,10 @@ void gfxDeinit(void)
_geventDeinit(); _geventDeinit();
#endif #endif
#if GFX_USE_GMISC #if GFX_USE_GMISC
_gmiscInit(); _gmiscDeinit();
#endif
#if GFX_USE_GQUEUE
_gqueueDeinit();
#endif #endif
_gosDeinit(); _gosDeinit();
} }

View File

@ -14,6 +14,21 @@
#if GFX_USE_GQUEUE #if GFX_USE_GQUEUE
#if GQUEUE_NEED_BUFFERS
static gfxQueueGSync bufferFreeList;
#endif
void _gqueueInit(void)
{
#if GQUEUE_NEED_BUFFERS
gfxQueueGSyncInit(&bufferFreeList);
#endif
}
void _gqueueDeinit(void)
{
}
#if GQUEUE_NEED_ASYNC #if GQUEUE_NEED_ASYNC
void gfxQueueASyncInit(gfxQueueASync *pqueue) { void gfxQueueASyncInit(gfxQueueASync *pqueue) {
pqueue->head = pqueue->tail = 0; pqueue->head = pqueue->tail = 0;
@ -123,6 +138,10 @@
pqueue->head = pqueue->tail = 0; pqueue->head = pqueue->tail = 0;
gfxSemInit(&pqueue->sem, 0, MAX_SEMAPHORE_COUNT); gfxSemInit(&pqueue->sem, 0, MAX_SEMAPHORE_COUNT);
} }
void gfxQueueGSyncDeinit(gfxQueueGSync *pqueue) {
pqueue->head = pqueue->tail = 0;
gfxSemDestroy(&pqueue->sem);
}
gfxQueueGSyncItem *gfxQueueGSyncGet(gfxQueueGSync *pqueue, delaytime_t ms) { gfxQueueGSyncItem *gfxQueueGSyncGet(gfxQueueGSync *pqueue, delaytime_t ms) {
gfxQueueGSyncItem *pi; gfxQueueGSyncItem *pi;
@ -232,6 +251,11 @@
pqueue->head = pqueue->tail = 0; pqueue->head = pqueue->tail = 0;
gfxSemInit(&pqueue->sem, 0, MAX_SEMAPHORE_COUNT); gfxSemInit(&pqueue->sem, 0, MAX_SEMAPHORE_COUNT);
} }
void gfxQueueFSyncDeinit(gfxQueueGSync *pqueue) {
while(gfxQueueFSyncGet(pqueue, TIME_IMMEDIATE));
pqueue->head = pqueue->tail = 0;
gfxSemDestroy(&pqueue->sem);
}
gfxQueueFSyncItem *gfxQueueFSyncGet(gfxQueueFSync *pqueue, delaytime_t ms) { gfxQueueFSyncItem *gfxQueueFSyncGet(gfxQueueFSync *pqueue, delaytime_t ms) {
gfxQueueFSyncItem *pi; gfxQueueFSyncItem *pi;
@ -333,4 +357,36 @@
} }
#endif #endif
#if GQUEUE_NEED_BUFFERS
bool_t gfxBufferAlloc(unsigned num, size_t size) {
GDataBuffer *pd;
if (num < 1)
return FALSE;
// Round up to a multiple of 4 to prevent problems with structure alignment
size = (size + 3) & ~0x03;
// Allocate the memory
if (!(pd = gfxAlloc((size+sizeof(GDataBuffer)) * num)))
return FALSE;
// Add each of them to our free list
for(;num--; pd = (GDataBuffer *)((char *)(pd+1)+size)) {
pd->size = size;
gfxBufferRelease(pd);
}
return TRUE;
}
void gfxBufferRelease(GDataBuffer *pd) { gfxQueueGSyncPut(&bufferFreeList, (gfxQueueGSyncItem *)pd); }
void gfxBufferReleaseI(GDataBuffer *pd) { gfxQueueGSyncPutI(&bufferFreeList, (gfxQueueGSyncItem *)pd); }
GDataBuffer *gfxBufferGet(delaytime_t ms) { return (GDataBuffer *)gfxQueueGSyncGet(&bufferFreeList, ms); }
GDataBuffer *gfxBufferGetI(void) { return (GDataBuffer *)gfxQueueGSyncGetI(&bufferFreeList); }
bool_t gfxBufferIsAvailable(void) { return bufferFreeList.head != 0; }
#endif
#endif /* GFX_USE_GQUEUE */ #endif /* GFX_USE_GQUEUE */

View File

@ -23,6 +23,8 @@
* operations because fully synchronous queues have the highest storage requirements. The other queue types are * operations because fully synchronous queues have the highest storage requirements. The other queue types are
* optimizations. Efficiency IS important to use (particularly RAM efficiency). * optimizations. Efficiency IS important to use (particularly RAM efficiency).
* In practice we only implement ASync, GSync and FSync queues as PSync queues are of dubious value. * In practice we only implement ASync, GSync and FSync queues as PSync queues are of dubious value.
* <br>
* We also define GDataBuffer which is a data buffer that supports being queued.
* @{ * @{
*/ */
@ -31,39 +33,13 @@
#if GFX_USE_GQUEUE || defined(__DOXYGEN__) #if GFX_USE_GQUEUE || defined(__DOXYGEN__)
/**
* @brief A queue
* @{
*/
typedef struct gfxQueueASync {
struct gfxQueueASyncItem *head;
struct gfxQueueASyncItem *tail;
} gfxQueueASync;
typedef struct gfxQueueGSync {
struct gfxQueueGSyncItem *head;
struct gfxQueueGSyncItem *tail;
gfxSem sem;
} gfxQueueGSync;
typedef struct gfxQueueFSync {
struct gfxQueueFSyncItem *head;
struct gfxQueueFSyncItem *tail;
gfxSem sem;
} gfxQueueFSync;
/* @} */
/** /**
* @brief A queue item * @brief A queue item
* @{ * @{
*/ */
typedef struct gfxQueueASyncItem { typedef struct gfxQueueASyncItem {
struct gfxQueueASyncItem *next; struct gfxQueueASyncItem *next;
} gfxQueueASyncItem; } gfxQueueASyncItem, gfxQueueGSyncItem;
typedef struct gfxQueueGSyncItem {
struct gfxQueueGSyncItem *next;
} gfxQueueGSyncItem;
typedef struct gfxQueueFSyncItem { typedef struct gfxQueueFSyncItem {
struct gfxQueueFSyncItem *next; struct gfxQueueFSyncItem *next;
@ -71,6 +47,39 @@ typedef struct gfxQueueFSyncItem {
} gfxQueueFSyncItem; } gfxQueueFSyncItem;
/* @} */ /* @} */
/**
* @brief A queue
* @{
*/
typedef struct gfxQueueASync {
gfxQueueASyncItem *head;
gfxQueueASyncItem *tail;
} gfxQueueASync;
typedef struct gfxQueueGSync {
gfxQueueGSyncItem *head;
gfxQueueGSyncItem *tail;
gfxSem sem;
} gfxQueueGSync;
typedef struct gfxQueueFSync {
gfxQueueFSyncItem *head;
gfxQueueFSyncItem *tail;
gfxSem sem;
} gfxQueueFSync;
/* @} */
/**
* @brief A Data Buffer Queue
* @note This structure is followed immediately by the data itself.
* When allocating the buffers for the data put this structure
* at the beginning of the buffer.
*/
typedef struct GDataBuffer {
gfxQueueGSyncItem next; // @< Used for queueing the buffers
size_t size; // @< The size of the buffer area following this structure (in bytes)
size_t len; // @< The length of the data in the buffer area (in bytes)
} GDataBuffer;
/*===========================================================================*/ /*===========================================================================*/
/* Function declarations. */ /* Function declarations. */
@ -97,6 +106,19 @@ void gfxQueueGSyncInit(gfxQueueGSync *pqueue);
void gfxQueueFSyncInit(gfxQueueFSync *pqueue); void gfxQueueFSyncInit(gfxQueueFSync *pqueue);
/* @} */ /* @} */
/**
* @brief De-Initialise a queue.
*
* @param[in] pqueue A pointer to the queue
*
* @api
* @{
*/
#define gfxQueueASyncDeinit(pqueue)
void gfxQueueGSyncDeinit(gfxQueueGSync *pqueue);
void gfxQueueFSyncDeinit(gfxQueueFSync *pqueue);
/* @} */
/** /**
* @brief Get an item from the head of the queue (and remove it from the queue). * @brief Get an item from the head of the queue (and remove it from the queue).
* @return NULL if the timeout expires before an item is available * @return NULL if the timeout expires before an item is available
@ -286,6 +308,58 @@ bool_t gfxQueueFSyncIsInI(gfxQueueFSync *pqueue, const gfxQueueFSyncItem *pitem)
#define gfxQueueFSyncNextI(pitem) ((const gfxQueueFSyncItem *)((pitem)->next)) #define gfxQueueFSyncNextI(pitem) ((const gfxQueueFSyncItem *)((pitem)->next))
/* @} */ /* @} */
/**
* @brief Allocate some buffers and put them on the free list
* @return TRUE is it succeeded. FALSE on allocation failure.
*
* @param[in] num The number of buffers to allocate
* @param[in] size The size (in bytes) of each buffer
*
* @api
*/
bool_t gfxBufferAlloc(unsigned num, size_t size);
/**
* @brief Is there one or more buffers currently available on the free list
* @return TRUE if there are buffers in the free list
*
* @api
* @{
*/
bool_t gfxBufferIsAvailable(void);
/* @} */
/**
* @brief Get a buffer from the free list
* @return A GDataBuffer pointer or NULL if the timeout is exceeded
*
* @params[in] ms The maximum amount of time in milliseconds to wait for a buffer if one is not available.
*
* @api
* @{
*/
GDataBuffer *gfxBufferGet(delaytime_t ms);
GDataBuffer *gfxBufferGetI(void);
/* @} */
/**
* @brief Release a buffer back to the free list
*
* @param[in] pd The buffer to put (back) on the free-list.
*
* @note This call should be used to return any buffers that were taken from
* the free-list once they have been finished with. It can also be used
* to put new buffers onto the free-list. Just make sure the "size" field
* of the GDataBuffer structure has been filled in first.
*
* @api
* @{
*/
void gfxBufferRelease(GDataBuffer *pd);
void gfxBufferReleaseI(GDataBuffer *pd);
/* @} */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -41,6 +41,12 @@
#ifndef GQUEUE_NEED_FSYNC #ifndef GQUEUE_NEED_FSYNC
#define GQUEUE_NEED_FSYNC FALSE #define GQUEUE_NEED_FSYNC FALSE
#endif #endif
/**
* @brief Enable Queue-able Data Buffers
*/
#ifndef GQUEUE_NEED_BUFFERS
#define GQUEUE_NEED_BUFFERS FALSE
#endif
/** /**
* @} * @}
* *

View File

@ -17,6 +17,13 @@
#define _GQUEUE_RULES_H #define _GQUEUE_RULES_H
#if GFX_USE_GQUEUE #if GFX_USE_GQUEUE
#if GQUEUE_NEED_BUFFERS && !GQUEUE_NEED_GSYNC
#if GFX_DISPLAY_RULE_WARNINGS
#warning "GQUEUE: GQUEUE_NEED_GSYNC is required if GQUEUE_NEED_BUFFERS is TRUE. It has been turned on for you."
#endif
#undef GQUEUE_NEED_GSYNC
#define GQUEUE_NEED_GSYNC TRUE
#endif
#endif #endif
#endif /* _GQUEUE_RULES_H */ #endif /* _GQUEUE_RULES_H */