[PATCH] Abstract DMA sound buffer locking

Add SNDDMA_LockBuffer() and SNDDMA_UnlockBuffer() functions to the generic
sound interface, to allow drivers to implement appropriate locking on their
DMA buffers if required. Move the #ifdef'd Windows specific code to do this
from the shared snd_mix.c and snd_dma.c files to the windows sound driver.

Thanks to O.Sezer <sezero@users.sourceforge.net> for the idea and for
providing the orginal patch which was the basis for this one.

Signed-off-by: Tyrann <tyrann@disenchant.net>
This commit is contained in:
Tyrann 2007-12-30 22:43:00 +10:30
parent e56a126544
commit 33b5b4fcbe
5 changed files with 88 additions and 119 deletions

View File

@ -547,50 +547,21 @@ S_StopAllSoundsC(void)
void
S_ClearBuffer(void)
{
int err;
int clear;
#ifdef _WIN32
if (!sound_started || !shm || (!shm->buffer && !pDSBuf))
#else
if (!sound_started || !shm || !shm->buffer)
#endif
if (!sound_started || !shm)
return;
if (shm->samplebits == 8)
clear = 0x80;
else
clear = 0;
#ifdef _WIN32
if (pDSBuf) {
int reps;
void *pData;
DWORD dwSize;
HRESULT hresult;
reps = 0;
while ((hresult =
pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pData, &dwSize,
NULL, NULL, 0)) != DS_OK) {
if (hresult != DSERR_BUFFERLOST) {
Con_Printf("%s: DS::Lock Sound Buffer Failed\n", __func__);
S_Shutdown();
return;
}
if (++reps > 10000) {
Con_Printf("%s: DS: couldn't restore buffer\n", __func__);
S_Shutdown();
return;
}
}
memset(pData, clear, shm->samples * shm->samplebits / 8);
pDSBuf->lpVtbl->Unlock(pDSBuf, pData, dwSize, NULL, 0);
} else
#endif
{
memset(shm->buffer, clear, shm->samples * shm->samplebits / 8);
err = SNDDMA_LockBuffer();
if (err) {
S_Shutdown();
return;
}
clear = (shm->samplebits == 8) ? 0x80 : 0;
memset(shm->buffer, clear, shm->samples * shm->samplebits / 8);
SNDDMA_UnlockBuffer();
}

View File

@ -235,6 +235,17 @@ SNDDMA_Init(void)
return 1;
}
int
SNDDMA_LockBuffer(void)
{
return 0;
}
void
SNDDMA_UnlockBuffer(void)
{
}
int
SNDDMA_GetDMAPos(void)
{

View File

@ -68,69 +68,34 @@ S_TransferStereo16(int endtime)
{
int lpos;
int lpaintedtime;
void *pbuf;
#ifdef _WIN32
int reps;
DWORD dwSize;
HRESULT hresult;
#endif
int err;
snd_vol = volume.value * 256;
snd_p = (int *)paintbuffer;
lpaintedtime = paintedtime;
#ifdef _WIN32
if (pDSBuf) {
reps = 0;
while ((hresult =
pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize,
NULL, NULL, 0)) != DS_OK) {
if (hresult != DSERR_BUFFERLOST) {
Con_Printf("%s: DS::Lock Sound Buffer Failed\n", __func__);
S_Shutdown();
S_Startup();
return;
}
if (++reps > 10000) {
Con_Printf("%s: DS: couldn't restore buffer\n", __func__);
S_Shutdown();
S_Startup();
return;
}
}
} else
#endif
{
pbuf = shm->buffer;
err = SNDDMA_LockBuffer();
if (err) {
S_Shutdown();
S_Startup();
return;
}
while (lpaintedtime < endtime) {
// handle recirculating buffer issues
lpos = lpaintedtime & ((shm->samples >> 1) - 1);
snd_out = (short *)pbuf + (lpos << 1);
snd_out = (short *)shm->buffer + (lpos << 1);
snd_linear_count = (shm->samples >> 1) - lpos;
if (lpaintedtime + snd_linear_count > endtime)
snd_linear_count = endtime - lpaintedtime;
snd_linear_count <<= 1;
// write a linear blast of samples
Snd_WriteLinearBlastStereo16();
snd_p += snd_linear_count;
lpaintedtime += (snd_linear_count >> 1);
}
#ifdef _WIN32
if (pDSBuf)
pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0);
#endif
SNDDMA_UnlockBuffer();
}
void
@ -143,13 +108,7 @@ S_TransferPaintBuffer(int endtime)
int step;
int val;
int snd_vol;
void *pbuf;
#ifdef _WIN32
int reps;
DWORD dwSize;
HRESULT hresult;
#endif
int err;
if (shm->samplebits == 16 && shm->channels == 2) {
S_TransferStereo16(endtime);
@ -163,36 +122,15 @@ S_TransferPaintBuffer(int endtime)
step = 3 - shm->channels;
snd_vol = volume.value * 256;
#ifdef _WIN32
if (pDSBuf) {
reps = 0;
while ((hresult =
pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize,
NULL, NULL, 0)) != DS_OK) {
if (hresult != DSERR_BUFFERLOST) {
Con_Printf("%s: DS::Lock Sound Buffer Failed\n", __func__);
S_Shutdown();
S_Startup();
return;
}
if (++reps > 10000) {
Con_Printf("%s: DS: couldn't restore buffer\n", __func__);
S_Shutdown();
S_Startup();
return;
}
}
} else
#endif
{
pbuf = shm->buffer;
err = SNDDMA_LockBuffer();
if (err) {
S_Shutdown();
S_Startup();
return;
}
if (shm->samplebits == 16) {
short *out = (short *)pbuf;
short *out = (short *)shm->buffer;
while (count--) {
val = (*p * snd_vol) >> 8;
p += step;
@ -204,8 +142,7 @@ S_TransferPaintBuffer(int endtime)
out_idx = (out_idx + 1) & out_mask;
}
} else if (shm->samplebits == 8) {
unsigned char *out = (unsigned char *)pbuf;
unsigned char *out = (unsigned char *)shm->buffer;
while (count--) {
val = (*p * snd_vol) >> 8;
p += step;
@ -217,6 +154,7 @@ S_TransferPaintBuffer(int endtime)
out_idx = (out_idx + 1) & out_mask;
}
}
SNDDMA_UnlockBuffer();
#ifdef _WIN32
if (pDSBuf) {
DWORD dwNewpos, dwWrite;
@ -224,7 +162,6 @@ S_TransferPaintBuffer(int endtime)
int ir = endtime - paintedtime;
ir += il;
pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0);
pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &dwNewpos, &dwWrite);
}
#endif

View File

@ -169,6 +169,52 @@ FreeSound(void)
wav_init = false;
}
static DWORD dsLockSize;
static qboolean dsIsLocked = false;
int
SNDDMA_LockBuffer(void)
{
int reps;
void *pData;
HRESULT hresult;
if (dsIsLocked)
Sys_Error("%s: Recursive locking detected!", __func__);
if (pDSBuf) {
reps = 0;
while ((hresult =
pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pData,
&dsLockSize, NULL, NULL, 0)) != DS_OK) {
if (hresult != DSERR_BUFFERLOST) {
Con_Printf("%s: DS::Lock Sound Buffer Failed\n", __func__);
return 1;
}
if (++reps > 10000) {
Con_Printf("%s: DS: couldn't restore buffer\n", __func__);
return 1;
}
}
shm->buffer = pData;
}
dsIsLocked = true;
return 0;
}
void
SNDDMA_UnlockBuffer()
{
if (!dsIsLocked)
Sys_Error("%s: Detected unlock without lock", __func__);
if (pDSBuf) {
pDSBuf->lpVtbl->Unlock(pDSBuf, shm->buffer, dsLockSize, NULL, 0);
shm->buffer = NULL;
}
dsIsLocked = false;
}
/*
==================

View File

@ -121,6 +121,10 @@ qboolean SNDDMA_Init(void);
// gets the current DMA position
int SNDDMA_GetDMAPos(void);
/* Lock and unlock the DMA sound buffer */
int SNDDMA_LockBuffer(void);
void SNDDMA_UnlockBuffer(void);
// shutdown the DMA xfer.
void SNDDMA_Shutdown(void);