diff --git a/src/conf/cards/HdmiLpeAudio.conf b/src/conf/cards/HdmiLpeAudio.conf index f5836c05..61bdfeae 100644 --- a/src/conf/cards/HdmiLpeAudio.conf +++ b/src/conf/cards/HdmiLpeAudio.conf @@ -20,6 +20,9 @@ HdmiLpeAudio.pcm.front.0 { } } +# uncached memory reads have a high penalty +HdmiLpeAudio.dmix.direct_memory_access false + # default with dmix+softvol HdmiLpeAudio.pcm.default { @args [ CARD ] diff --git a/src/conf/pcm/dmix.conf b/src/conf/pcm/dmix.conf index 7d0aa015..2d3b329e 100644 --- a/src/conf/pcm/dmix.conf +++ b/src/conf/pcm/dmix.conf @@ -49,6 +49,21 @@ pcm.!dmix { @func refer name defaults.pcm.ipc_perm } + direct_memory_access { + @func refer + name { + @func concat + strings [ + "cards." + { + @func card_driver + card $CARD + } + ".dmix.direct_memory_access" + ] + } + default true + } slave { pcm { type hw diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c index e4bef786..364191b2 100644 --- a/src/pcm/pcm_direct.c +++ b/src/pcm/pcm_direct.c @@ -1861,6 +1861,7 @@ int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf, rec->slowptr = 1; rec->max_periods = 0; rec->var_periodsize = 1; + rec->direct_memory_access = 1; /* read defaults */ if (snd_config_search(root, "defaults.pcm.dmix_max_periods", &n) >= 0) { @@ -1974,6 +1975,13 @@ int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf, rec->var_periodsize = err; continue; } + if (strcmp(id, "direct_memory_access") == 0) { + err = snd_config_get_bool(n); + if (err < 0) + return err; + rec->direct_memory_access = err; + continue; + } SNDERR("Unknown field %s", id); return -EINVAL; } diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h index 66107ec0..fba55fdc 100644 --- a/src/pcm/pcm_direct.h +++ b/src/pcm/pcm_direct.h @@ -159,6 +159,7 @@ struct snd_pcm_direct { unsigned int channels; /* client's channels */ unsigned int *bindings; unsigned int recoveries; /* mirror of executed recoveries on slave */ + int direct_memory_access; /* use arch-optimized buffer RW */ union { struct { int shmid_sum; /* IPC global sum ring buffer memory identification */ @@ -340,6 +341,7 @@ struct snd_pcm_direct_open_conf { int slowptr; int max_periods; int var_periodsize; + int direct_memory_access; snd_config_t *slave; snd_config_t *bindings; }; diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c index 2ef61599..dd0356e9 100644 --- a/src/pcm/pcm_dmix.c +++ b/src/pcm/pcm_dmix.c @@ -1065,6 +1065,7 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, dmix->max_periods = opts->max_periods; dmix->var_periodsize = opts->var_periodsize; dmix->sync_ptr = snd_pcm_dmix_sync_ptr; + dmix->direct_memory_access = opts->direct_memory_access; retry: if (first_instance) { diff --git a/src/pcm/pcm_dmix_i386.c b/src/pcm/pcm_dmix_i386.c index dcc6b9a4..1ab983a8 100644 --- a/src/pcm/pcm_dmix_i386.c +++ b/src/pcm/pcm_dmix_i386.c @@ -87,6 +87,11 @@ static void mix_select_callbacks(snd_pcm_direct_t *dmix) { static int smp = 0, mmx = 0, cmov = 0; + if (!dmix->direct_memory_access) { + generic_mix_select_callbacks(dmix); + return; + } + if (!((1ULL<< dmix->shmptr->s.format) & i386_dmix_supported_format)) { generic_mix_select_callbacks(dmix); return; diff --git a/src/pcm/pcm_dmix_x86_64.c b/src/pcm/pcm_dmix_x86_64.c index 831046d9..34c40d4e 100644 --- a/src/pcm/pcm_dmix_x86_64.c +++ b/src/pcm/pcm_dmix_x86_64.c @@ -70,6 +70,11 @@ static void mix_select_callbacks(snd_pcm_direct_t *dmix) { static int smp = 0; + if (!dmix->direct_memory_access) { + generic_mix_select_callbacks(dmix); + return; + } + if (!((1ULL<< dmix->shmptr->s.format) & x86_64_dmix_supported_format)) { generic_mix_select_callbacks(dmix); return;