1
0
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:
Florian Walpen 2024-03-31 20:14:16 +01:00 committed by Ruslan Bukin
parent fefb7c399b
commit ee36e7face
2 changed files with 38 additions and 9 deletions

View File

@ -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;

View File

@ -184,6 +184,7 @@ struct sc_chinfo {
/* Buffer */
uint32_t *data;
uint32_t size;
uint32_t position;
/* Flags */
uint32_t run;