mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-01 08:27:59 +00:00
snd_hdspe(4): Only buffer_copy() audio data once.
Instead of blindly copying two periods of audio data to and from DMA buffers, keep track of the writing position and derive the actual part of audio data that needs to be copied. This approximately halves the number of samples copied in total. Differential Revision: https://reviews.freebsd.org/D44084
This commit is contained in:
parent
fefb7c399b
commit
ee36e7face
@ -540,7 +540,8 @@ buffer_copy(struct sc_chinfo *ch)
|
||||
struct sc_pcminfo *scp;
|
||||
struct sc_info *sc;
|
||||
uint32_t row, ports;
|
||||
unsigned int pos;
|
||||
uint32_t dma_pos;
|
||||
unsigned int pos, length, offset;
|
||||
unsigned int n;
|
||||
unsigned int adat_width, pcm_width;
|
||||
|
||||
@ -558,13 +559,35 @@ buffer_copy(struct sc_chinfo *ch)
|
||||
else
|
||||
pcm_width = 8;
|
||||
|
||||
if (ch->dir == PCMDIR_PLAY)
|
||||
pos = sndbuf_getreadyptr(ch->buffer);
|
||||
else
|
||||
pos = sndbuf_getfreeptr(ch->buffer);
|
||||
/* Derive buffer position and length to be copied. */
|
||||
if (ch->dir == PCMDIR_PLAY) {
|
||||
/* Position per channel is n times smaller than PCM. */
|
||||
pos = sndbuf_getreadyptr(ch->buffer) / n;
|
||||
length = sndbuf_getready(ch->buffer) / n;
|
||||
/* Copy no more than 2 periods in advance. */
|
||||
if (length > (sc->period * 4 * 2))
|
||||
length = (sc->period * 4 * 2);
|
||||
/* Skip what was already copied last time. */
|
||||
offset = (ch->position + HDSPE_CHANBUF_SIZE) - pos;
|
||||
offset %= HDSPE_CHANBUF_SIZE;
|
||||
if (offset <= length) {
|
||||
pos = (pos + offset) % HDSPE_CHANBUF_SIZE;
|
||||
length -= offset;
|
||||
}
|
||||
} else {
|
||||
/* Position per channel is n times smaller than PCM. */
|
||||
pos = sndbuf_getfreeptr(ch->buffer) / n;
|
||||
/* Get DMA buffer write position. */
|
||||
dma_pos = hdspe_read_2(sc, HDSPE_STATUS_REG);
|
||||
dma_pos &= HDSPE_BUF_POSITION_MASK;
|
||||
/* Copy what is newly available. */
|
||||
length = (dma_pos + HDSPE_CHANBUF_SIZE) - pos;
|
||||
length %= HDSPE_CHANBUF_SIZE;
|
||||
}
|
||||
|
||||
pos /= 4; /* Bytes per sample. */
|
||||
pos /= n; /* Destination buffer n-times smaller. */
|
||||
/* Position and length in samples (4 bytes). */
|
||||
pos /= 4;
|
||||
length /= 4;
|
||||
|
||||
/* Iterate through rows of ports with contiguous slots. */
|
||||
ports = ch->ports;
|
||||
@ -576,10 +599,10 @@ buffer_copy(struct sc_chinfo *ch)
|
||||
while (row != 0) {
|
||||
if (ch->dir == PCMDIR_PLAY)
|
||||
buffer_mux_port(sc->pbuf, ch->data, row, ch->ports, pos,
|
||||
sc->period * 2, adat_width, pcm_width);
|
||||
length, adat_width, pcm_width);
|
||||
else
|
||||
buffer_demux_port(sc->rbuf, ch->data, row, ch->ports,
|
||||
pos, sc->period * 2, adat_width, pcm_width);
|
||||
pos, length, adat_width, pcm_width);
|
||||
|
||||
ports &= ~row;
|
||||
if (pcm_width == adat_width)
|
||||
@ -587,6 +610,8 @@ buffer_copy(struct sc_chinfo *ch)
|
||||
else
|
||||
row = hdspe_port_first(ports);
|
||||
}
|
||||
|
||||
ch->position = ((pos + length) * 4) % HDSPE_CHANBUF_SIZE;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -620,6 +645,8 @@ clean(struct sc_chinfo *ch)
|
||||
row = hdspe_port_first_row(ports);
|
||||
}
|
||||
|
||||
ch->position = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -664,6 +691,7 @@ hdspechan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
|
||||
/* Allocate maximum buffer size. */
|
||||
ch->size = HDSPE_CHANBUF_SIZE * hdspe_channel_count(ch->ports, 8);
|
||||
ch->data = malloc(ch->size, M_HDSPE, M_NOWAIT);
|
||||
ch->position = 0;
|
||||
|
||||
ch->buffer = b;
|
||||
ch->channel = c;
|
||||
|
@ -184,6 +184,7 @@ struct sc_chinfo {
|
||||
/* Buffer */
|
||||
uint32_t *data;
|
||||
uint32_t size;
|
||||
uint32_t position;
|
||||
|
||||
/* Flags */
|
||||
uint32_t run;
|
||||
|
Loading…
Reference in New Issue
Block a user