pci: cleanup virtio ids.

audio: bugfixes and latency improvements.
 misc fixes for hw/display and ui
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEoDKM/7k6F6eZAf59TLbY7tPocTgFAmNHtYsACgkQTLbY7tPo
 cTjHhg//RDkHbqVSExe+Odw5ISuLu/EXZSHAVjo3KOCUvaj7O2cXi8N7DVfEy5a5
 T3+WSv0v4X6TYSV0PoMb36a11rCuOKzeLZrtEOQeYfG3D1WCVc9gIWMt6omzBC7A
 YQ59P+u19qHD7xD2PP3WRtdcqmsceg1RG+47adX2EnsRZmmu/yJxD72w/Q1kXMuB
 jIzuJU2ZVorYX9y11hnIU3M5pvoX/vjFA+Ib2UGZZdlE3KlUKtJeAtLiZkHfoyd1
 5janU+PtSU6Z1yVirE7RVz3+IBbfqqEFTkDtMXJucJW/Eod0NHCyo4Q6D64HoiZe
 +JZKkHmuvn8ZUgXMtIOZdH+aOHlaIJzA5SoA2IFxCBVuxn7p4NtPbCRoHHg7gkDh
 BDsq+p/wsdOY06u1txFw9dYy+4tKvWS7+Dxhyme7GT2YUQHrEEG3pzGFmk3PE0Vi
 tEAhmfNRxWzUgIcynQiN/3SnShAI8lANq0SEiiTvqcX7h1TK+cjEYjOTMsjK43nL
 2W/pgQxJpEPcSs3jgFLnBLk9rUHRNRC+GtMBlwN+Wdc1y17leZHiIinqhHjXuts3
 cJTdv4veeGuJENPIl2rk5JOdvpVtzduDkz+Rzx0mGb+LnAYdK2lBUV5LY9FfdwaK
 2Bgg02ZYNBz7K2zzFeeV+7b7K/LYOuWkGdzGvKbpqjbefopZmTM=
 =6d/F
 -----END PGP SIGNATURE-----

Merge tag 'kraxel-20221013-pull-request' of https://gitlab.com/kraxel/qemu into staging

pci: cleanup virtio ids.
audio: bugfixes and latency improvements.
misc fixes for hw/display and ui

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCgAdFiEEoDKM/7k6F6eZAf59TLbY7tPocTgFAmNHtYsACgkQTLbY7tPo
# cTjHhg//RDkHbqVSExe+Odw5ISuLu/EXZSHAVjo3KOCUvaj7O2cXi8N7DVfEy5a5
# T3+WSv0v4X6TYSV0PoMb36a11rCuOKzeLZrtEOQeYfG3D1WCVc9gIWMt6omzBC7A
# YQ59P+u19qHD7xD2PP3WRtdcqmsceg1RG+47adX2EnsRZmmu/yJxD72w/Q1kXMuB
# jIzuJU2ZVorYX9y11hnIU3M5pvoX/vjFA+Ib2UGZZdlE3KlUKtJeAtLiZkHfoyd1
# 5janU+PtSU6Z1yVirE7RVz3+IBbfqqEFTkDtMXJucJW/Eod0NHCyo4Q6D64HoiZe
# +JZKkHmuvn8ZUgXMtIOZdH+aOHlaIJzA5SoA2IFxCBVuxn7p4NtPbCRoHHg7gkDh
# BDsq+p/wsdOY06u1txFw9dYy+4tKvWS7+Dxhyme7GT2YUQHrEEG3pzGFmk3PE0Vi
# tEAhmfNRxWzUgIcynQiN/3SnShAI8lANq0SEiiTvqcX7h1TK+cjEYjOTMsjK43nL
# 2W/pgQxJpEPcSs3jgFLnBLk9rUHRNRC+GtMBlwN+Wdc1y17leZHiIinqhHjXuts3
# cJTdv4veeGuJENPIl2rk5JOdvpVtzduDkz+Rzx0mGb+LnAYdK2lBUV5LY9FfdwaK
# 2Bgg02ZYNBz7K2zzFeeV+7b7K/LYOuWkGdzGvKbpqjbefopZmTM=
# =6d/F
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 13 Oct 2022 02:51:55 EDT
# gpg:                using RSA key A0328CFFB93A17A79901FE7D4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full]
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>" [full]
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full]
# Primary key fingerprint: A032 8CFF B93A 17A7 9901  FE7D 4CB6 D8EE D3E8 7138

* tag 'kraxel-20221013-pull-request' of https://gitlab.com/kraxel/qemu: (26 commits)
  audio: improve out.voices test
  audio: fix in.voices test
  gtk: Add show_menubar=on|off command line option.
  qemu-edid: Restrict input parameter -d to avoid division by zero
  ui/gtk: Fix the implicit mouse ungrabbing logic
  pci-ids: document modern virtio-pci ids in pci.h too
  pci-ids: drop list of modern virtio devices
  pci-ids: drop PCI_DEVICE_ID_VIRTIO_PMEM
  pci-ids: drop PCI_DEVICE_ID_VIRTIO_MEM
  pci-ids: drop PCI_DEVICE_ID_VIRTIO_IOMMU
  docs: add firmware feature flags
  cirrus_vga: fix potential memory overflow
  ui/gtk-egl: egl context needs to be unbound in the end of gd_egl_switch
  ui/vnc-clipboard: fix integer underflow in vnc_client_cut_text_ext
  audio: prevent an integer overflow in resampling code
  audio: fix sw->buf size for audio recording
  audio: refactor audio_get_avail()
  audio: rename audio_sw_bytes_free()
  audio: swap audio_rate_get_bytes() function parameters
  spiceaudio: update comment
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2022-10-13 13:55:53 -04:00
commit 2ba341b369
23 changed files with 218 additions and 92 deletions

View File

@ -602,6 +602,42 @@ static int alsa_open(bool in, struct alsa_params_req *req,
return -1; return -1;
} }
static size_t alsa_buffer_get_free(HWVoiceOut *hw)
{
ALSAVoiceOut *alsa = (ALSAVoiceOut *)hw;
snd_pcm_sframes_t avail;
size_t alsa_free, generic_free, generic_in_use;
avail = snd_pcm_avail_update(alsa->handle);
if (avail < 0) {
if (avail == -EPIPE) {
if (!alsa_recover(alsa->handle)) {
avail = snd_pcm_avail_update(alsa->handle);
}
}
if (avail < 0) {
alsa_logerr(avail,
"Could not obtain number of available frames\n");
avail = 0;
}
}
alsa_free = avail * hw->info.bytes_per_frame;
generic_free = audio_generic_buffer_get_free(hw);
generic_in_use = hw->samples * hw->info.bytes_per_frame - generic_free;
if (generic_in_use) {
/*
* This code can only be reached in the unlikely case that
* snd_pcm_avail_update() returned a larger number of frames
* than snd_pcm_writei() could write. Make sure that all
* remaining bytes in the generic buffer can be written.
*/
alsa_free = alsa_free > generic_in_use ? alsa_free - generic_in_use : 0;
}
return alsa_free;
}
static size_t alsa_write(HWVoiceOut *hw, void *buf, size_t len) static size_t alsa_write(HWVoiceOut *hw, void *buf, size_t len)
{ {
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
@ -916,7 +952,7 @@ static struct audio_pcm_ops alsa_pcm_ops = {
.init_out = alsa_init_out, .init_out = alsa_init_out,
.fini_out = alsa_fini_out, .fini_out = alsa_fini_out,
.write = alsa_write, .write = alsa_write,
.buffer_get_free = audio_generic_buffer_get_free, .buffer_get_free = alsa_buffer_get_free,
.run_buffer_out = audio_generic_run_buffer_out, .run_buffer_out = audio_generic_run_buffer_out,
.enable_out = alsa_enable_out, .enable_out = alsa_enable_out,

View File

@ -986,6 +986,18 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
} }
} }
/**
* audio_frontend_frames_in() - returns the number of frames the resampling
* code generates from frames_in frames
*
* @sw: audio recording frontend
* @frames_in: number of frames
*/
static size_t audio_frontend_frames_in(SWVoiceIn *sw, size_t frames_in)
{
return (int64_t)frames_in * sw->ratio >> 32;
}
static size_t audio_get_avail (SWVoiceIn *sw) static size_t audio_get_avail (SWVoiceIn *sw)
{ {
size_t live; size_t live;
@ -1002,17 +1014,24 @@ static size_t audio_get_avail (SWVoiceIn *sw)
} }
ldebug ( ldebug (
"%s: get_avail live %zu ret %" PRId64 "\n", "%s: get_avail live %zu frontend frames %zu\n",
SW_NAME (sw), SW_NAME (sw),
live, (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame live, audio_frontend_frames_in(sw, live)
); );
return (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame; return live;
} }
static size_t audio_sw_bytes_free(SWVoiceOut *sw, size_t free) /**
* audio_frontend_frames_out() - returns the number of frames needed to
* get frames_out frames after resampling
*
* @sw: audio playback frontend
* @frames_out: number of frames
*/
static size_t audio_frontend_frames_out(SWVoiceOut *sw, size_t frames_out)
{ {
return (((int64_t)free << 32) / sw->ratio) * sw->info.bytes_per_frame; return ((int64_t)frames_out << 32) / sw->ratio;
} }
static size_t audio_get_free(SWVoiceOut *sw) static size_t audio_get_free(SWVoiceOut *sw)
@ -1034,8 +1053,8 @@ static size_t audio_get_free(SWVoiceOut *sw)
dead = sw->hw->mix_buf->size - live; dead = sw->hw->mix_buf->size - live;
#ifdef DEBUG_OUT #ifdef DEBUG_OUT
dolog("%s: get_free live %zu dead %zu sw_bytes %zu\n", dolog("%s: get_free live %zu dead %zu frontend frames %zu\n",
SW_NAME(sw), live, dead, audio_sw_bytes_free(sw, dead)); SW_NAME(sw), live, dead, audio_frontend_frames_out(sw, dead));
#endif #endif
return dead; return dead;
@ -1121,8 +1140,12 @@ static void audio_run_out (AudioState *s)
HWVoiceOut *hw = NULL; HWVoiceOut *hw = NULL;
SWVoiceOut *sw; SWVoiceOut *sw;
if (!audio_get_pdo_out(s->dev)->mixing_engine) { while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) {
while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) { size_t played, live, prev_rpos;
size_t hw_free = audio_pcm_hw_get_free(hw);
int nb_live;
if (!audio_get_pdo_out(s->dev)->mixing_engine) {
/* there is exactly 1 sw for each hw with no mixeng */ /* there is exactly 1 sw for each hw with no mixeng */
sw = hw->sw_head.lh_first; sw = hw->sw_head.lh_first;
@ -1135,16 +1158,16 @@ static void audio_run_out (AudioState *s)
} }
if (sw->active) { if (sw->active) {
sw->callback.fn(sw->callback.opaque, INT_MAX); sw->callback.fn(sw->callback.opaque,
hw_free * sw->info.bytes_per_frame);
} }
}
return;
}
while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) { if (hw->pcm_ops->run_buffer_out) {
size_t played, live, prev_rpos; hw->pcm_ops->run_buffer_out(hw);
size_t hw_free = audio_pcm_hw_get_free(hw); }
int nb_live;
continue;
}
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
if (sw->active) { if (sw->active) {
@ -1152,13 +1175,14 @@ static void audio_run_out (AudioState *s)
size_t free; size_t free;
if (hw_free > sw->total_hw_samples_mixed) { if (hw_free > sw->total_hw_samples_mixed) {
free = audio_sw_bytes_free(sw, free = audio_frontend_frames_out(sw,
MIN(sw_free, hw_free - sw->total_hw_samples_mixed)); MIN(sw_free, hw_free - sw->total_hw_samples_mixed));
} else { } else {
free = 0; free = 0;
} }
if (free > 0) { if (free > 0) {
sw->callback.fn(sw->callback.opaque, free); sw->callback.fn(sw->callback.opaque,
free * sw->info.bytes_per_frame);
} }
} }
} }
@ -1297,11 +1321,13 @@ static void audio_run_in (AudioState *s)
sw->total_hw_samples_acquired -= min; sw->total_hw_samples_acquired -= min;
if (sw->active) { if (sw->active) {
size_t sw_avail = audio_get_avail(sw);
size_t avail; size_t avail;
avail = audio_get_avail (sw); avail = audio_frontend_frames_in(sw, sw_avail);
if (avail > 0) { if (avail > 0) {
sw->callback.fn (sw->callback.opaque, avail); sw->callback.fn(sw->callback.opaque,
avail * sw->info.bytes_per_frame);
} }
} }
} }
@ -1501,10 +1527,6 @@ size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
} }
} }
if (hw->pcm_ops->run_buffer_out) {
hw->pcm_ops->run_buffer_out(hw);
}
return total; return total;
} }
@ -1750,13 +1772,13 @@ static AudioState *audio_init(Audiodev *dev, const char *name)
s->nb_hw_voices_out = audio_get_pdo_out(dev)->voices; s->nb_hw_voices_out = audio_get_pdo_out(dev)->voices;
s->nb_hw_voices_in = audio_get_pdo_in(dev)->voices; s->nb_hw_voices_in = audio_get_pdo_in(dev)->voices;
if (s->nb_hw_voices_out <= 0) { if (s->nb_hw_voices_out < 1) {
dolog ("Bogus number of playback voices %d, setting to 1\n", dolog ("Bogus number of playback voices %d, setting to 1\n",
s->nb_hw_voices_out); s->nb_hw_voices_out);
s->nb_hw_voices_out = 1; s->nb_hw_voices_out = 1;
} }
if (s->nb_hw_voices_in <= 0) { if (s->nb_hw_voices_in < 0) {
dolog ("Bogus number of capture voices %d, setting to 0\n", dolog ("Bogus number of capture voices %d, setting to 0\n",
s->nb_hw_voices_in); s->nb_hw_voices_in);
s->nb_hw_voices_in = 0; s->nb_hw_voices_in = 0;
@ -2251,26 +2273,39 @@ void audio_rate_start(RateCtl *rate)
rate->start_ticks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); rate->start_ticks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
} }
size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate, size_t audio_rate_peek_bytes(RateCtl *rate, struct audio_pcm_info *info)
size_t bytes_avail)
{ {
int64_t now; int64_t now;
int64_t ticks; int64_t ticks;
int64_t bytes; int64_t bytes;
int64_t samples; int64_t frames;
size_t ret;
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
ticks = now - rate->start_ticks; ticks = now - rate->start_ticks;
bytes = muldiv64(ticks, info->bytes_per_second, NANOSECONDS_PER_SECOND); bytes = muldiv64(ticks, info->bytes_per_second, NANOSECONDS_PER_SECOND);
samples = (bytes - rate->bytes_sent) / info->bytes_per_frame; frames = (bytes - rate->bytes_sent) / info->bytes_per_frame;
if (samples < 0 || samples > 65536) { if (frames < 0 || frames > 65536) {
AUD_log(NULL, "Resetting rate control (%" PRId64 " samples)\n", samples); AUD_log(NULL, "Resetting rate control (%" PRId64 " frames)\n", frames);
audio_rate_start(rate); audio_rate_start(rate);
samples = 0; frames = 0;
} }
ret = MIN(samples * info->bytes_per_frame, bytes_avail); return frames * info->bytes_per_frame;
rate->bytes_sent += ret; }
return ret;
void audio_rate_add_bytes(RateCtl *rate, size_t bytes_used)
{
rate->bytes_sent += bytes_used;
}
size_t audio_rate_get_bytes(RateCtl *rate, struct audio_pcm_info *info,
size_t bytes_avail)
{
size_t bytes;
bytes = audio_rate_peek_bytes(rate, info);
bytes = MIN(bytes, bytes_avail);
audio_rate_add_bytes(rate, bytes);
return bytes;
} }

View File

@ -263,7 +263,9 @@ typedef struct RateCtl {
} RateCtl; } RateCtl;
void audio_rate_start(RateCtl *rate); void audio_rate_start(RateCtl *rate);
size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate, size_t audio_rate_peek_bytes(RateCtl *rate, struct audio_pcm_info *info);
void audio_rate_add_bytes(RateCtl *rate, size_t bytes_used);
size_t audio_rate_get_bytes(RateCtl *rate, struct audio_pcm_info *info,
size_t bytes_avail); size_t bytes_avail);
static inline size_t audio_ring_dist(size_t dst, size_t src, size_t len) static inline size_t audio_ring_dist(size_t dst, size_t src, size_t len)

View File

@ -110,7 +110,11 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
return 0; return 0;
} }
#ifdef DAC
samples = ((int64_t) sw->HWBUF->size << 32) / sw->ratio; samples = ((int64_t) sw->HWBUF->size << 32) / sw->ratio;
#else
samples = (int64_t)sw->HWBUF->size * sw->ratio >> 32;
#endif
sw->buf = audio_calloc(__func__, samples, sizeof(struct st_sample)); sw->buf = audio_calloc(__func__, samples, sizeof(struct st_sample));
if (!sw->buf) { if (!sw->buf) {

View File

@ -82,7 +82,7 @@ static void *dbus_get_buffer_out(HWVoiceOut *hw, size_t *size)
} }
*size = MIN(vo->buf_size - vo->buf_pos, *size); *size = MIN(vo->buf_size - vo->buf_pos, *size);
*size = audio_rate_get_bytes(&hw->info, &vo->rate, *size); *size = audio_rate_get_bytes(&vo->rate, &hw->info, *size);
return vo->buf + vo->buf_pos; return vo->buf + vo->buf_pos;
@ -343,7 +343,7 @@ dbus_read(HWVoiceIn *hw, void *buf, size_t size)
trace_dbus_audio_read(size); trace_dbus_audio_read(size);
/* size = audio_rate_get_bytes(&hw->info, &vo->rate, size); */ /* size = audio_rate_get_bytes(&vo->rate, &hw->info, size); */
g_hash_table_iter_init(&iter, da->in_listeners); g_hash_table_iter_init(&iter, da->in_listeners);
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) { while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {

View File

@ -44,7 +44,7 @@ typedef struct NoVoiceIn {
static size_t no_write(HWVoiceOut *hw, void *buf, size_t len) static size_t no_write(HWVoiceOut *hw, void *buf, size_t len)
{ {
NoVoiceOut *no = (NoVoiceOut *) hw; NoVoiceOut *no = (NoVoiceOut *) hw;
return audio_rate_get_bytes(&hw->info, &no->rate, len); return audio_rate_get_bytes(&no->rate, &hw->info, len);
} }
static int no_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque) static int no_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
@ -89,7 +89,7 @@ static void no_fini_in (HWVoiceIn *hw)
static size_t no_read(HWVoiceIn *hw, void *buf, size_t size) static size_t no_read(HWVoiceIn *hw, void *buf, size_t size)
{ {
NoVoiceIn *no = (NoVoiceIn *) hw; NoVoiceIn *no = (NoVoiceIn *) hw;
int64_t bytes = audio_rate_get_bytes(&hw->info, &no->rate, size); int64_t bytes = audio_rate_get_bytes(&no->rate, &hw->info, size);
audio_pcm_info_clear_buf(&hw->info, buf, bytes / hw->info.bytes_per_frame); audio_pcm_info_clear_buf(&hw->info, buf, bytes / hw->info.bytes_per_frame);
return bytes; return bytes;

View File

@ -72,11 +72,6 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
ilast = *ibuf++; ilast = *ibuf++;
rate->ipos++; rate->ipos++;
/* if ipos overflow, there is a infinite loop */
if (rate->ipos == 0xffffffff) {
rate->ipos = 1;
rate->opos = rate->opos & 0xffffffff;
}
/* See if we finished the input buffer yet */ /* See if we finished the input buffer yet */
if (ibuf >= iend) { if (ibuf >= iend) {
goto the_end; goto the_end;
@ -85,6 +80,12 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
icur = *ibuf; icur = *ibuf;
/* wrap ipos and opos around long before they overflow */
if (rate->ipos >= 0x10001) {
rate->ipos = 1;
rate->opos &= 0xffffffff;
}
/* interpolate */ /* interpolate */
#ifdef FLOAT_MIXENG #ifdef FLOAT_MIXENG
#ifdef RECIPROCAL #ifdef RECIPROCAL

View File

@ -120,6 +120,13 @@ static void line_out_fini (HWVoiceOut *hw)
spice_server_remove_interface (&out->sin.base); spice_server_remove_interface (&out->sin.base);
} }
static size_t line_out_get_free(HWVoiceOut *hw)
{
SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
return audio_rate_peek_bytes(&out->rate, &hw->info);
}
static void *line_out_get_buffer(HWVoiceOut *hw, size_t *size) static void *line_out_get_buffer(HWVoiceOut *hw, size_t *size)
{ {
SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw); SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
@ -133,8 +140,6 @@ static void *line_out_get_buffer(HWVoiceOut *hw, size_t *size)
*size = MIN((out->fsize - out->fpos) << 2, *size); *size = MIN((out->fsize - out->fpos) << 2, *size);
} }
*size = audio_rate_get_bytes(&hw->info, &out->rate, *size);
return out->frame + out->fpos; return out->frame + out->fpos;
} }
@ -142,6 +147,8 @@ static size_t line_out_put_buffer(HWVoiceOut *hw, void *buf, size_t size)
{ {
SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw); SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
audio_rate_add_bytes(&out->rate, size);
if (buf) { if (buf) {
assert(buf == out->frame + out->fpos && out->fpos <= out->fsize); assert(buf == out->frame + out->fpos && out->fpos <= out->fsize);
out->fpos += size >> 2; out->fpos += size >> 2;
@ -232,10 +239,13 @@ static void line_in_fini (HWVoiceIn *hw)
static size_t line_in_read(HWVoiceIn *hw, void *buf, size_t len) static size_t line_in_read(HWVoiceIn *hw, void *buf, size_t len)
{ {
SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw); SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
uint64_t to_read = audio_rate_get_bytes(&hw->info, &in->rate, len) >> 2; uint64_t to_read = audio_rate_get_bytes(&in->rate, &hw->info, len) >> 2;
size_t ready = spice_server_record_get_samples(&in->sin, buf, to_read); size_t ready = spice_server_record_get_samples(&in->sin, buf, to_read);
/* XXX: do we need this? */ /*
* If the client didn't send new frames, it most likely disconnected.
* Generate silence in this case to avoid a stalled audio stream.
*/
if (ready == 0) { if (ready == 0) {
memset(buf, 0, to_read << 2); memset(buf, 0, to_read << 2);
ready = to_read; ready = to_read;
@ -282,6 +292,7 @@ static struct audio_pcm_ops audio_callbacks = {
.init_out = line_out_init, .init_out = line_out_init,
.fini_out = line_out_fini, .fini_out = line_out_fini,
.write = audio_generic_write, .write = audio_generic_write,
.buffer_get_free = line_out_get_free,
.get_buffer_out = line_out_get_buffer, .get_buffer_out = line_out_get_buffer,
.put_buffer_out = line_out_put_buffer, .put_buffer_out = line_out_put_buffer,
.enable_out = line_out_enable, .enable_out = line_out_enable,

View File

@ -42,7 +42,7 @@ typedef struct WAVVoiceOut {
static size_t wav_write_out(HWVoiceOut *hw, void *buf, size_t len) static size_t wav_write_out(HWVoiceOut *hw, void *buf, size_t len)
{ {
WAVVoiceOut *wav = (WAVVoiceOut *) hw; WAVVoiceOut *wav = (WAVVoiceOut *) hw;
int64_t bytes = audio_rate_get_bytes(&hw->info, &wav->rate, len); int64_t bytes = audio_rate_get_bytes(&wav->rate, &hw->info, len);
assert(bytes % hw->info.bytes_per_frame == 0); assert(bytes % hw->info.bytes_per_frame == 0);
if (bytes && fwrite(buf, bytes, 1, wav->f) != 1) { if (bytes && fwrite(buf, bytes, 1, wav->f) != 1) {

View File

@ -113,13 +113,22 @@
# Virtualization, as specified in the AMD64 Architecture # Virtualization, as specified in the AMD64 Architecture
# Programmer's Manual. QEMU command line options related to # Programmer's Manual. QEMU command line options related to
# this feature are documented in # this feature are documented in
# "docs/amd-memory-encryption.txt". # "docs/system/i386/amd-memory-encryption.rst".
# #
# @amd-sev-es: The firmware supports running under AMD Secure Encrypted # @amd-sev-es: The firmware supports running under AMD Secure Encrypted
# Virtualization - Encrypted State, as specified in the AMD64 # Virtualization - Encrypted State, as specified in the AMD64
# Architecture Programmer's Manual. QEMU command line options # Architecture Programmer's Manual. QEMU command line options
# related to this feature are documented in # related to this feature are documented in
# "docs/amd-memory-encryption.txt". # "docs/system/i386/amd-memory-encryption.rst".
#
# @amd-sev-snp: The firmware supports running under AMD Secure Encrypted
# Virtualization - Secure Nested Paging, as specified in the
# AMD64 Architecture Programmer's Manual. QEMU command line
# options related to this feature are documented in
# "docs/system/i386/amd-memory-encryption.rst".
#
# @intel-tdx: The firmware supports running under Intel Trust Domain
# Extensions (TDX).
# #
# @enrolled-keys: The variable store (NVRAM) template associated with # @enrolled-keys: The variable store (NVRAM) template associated with
# the firmware binary has the UEFI Secure Boot # the firmware binary has the UEFI Secure Boot
@ -185,9 +194,11 @@
# Since: 3.0 # Since: 3.0
## ##
{ 'enum' : 'FirmwareFeature', { 'enum' : 'FirmwareFeature',
'data' : [ 'acpi-s3', 'acpi-s4', 'amd-sev', 'amd-sev-es', 'enrolled-keys', 'data' : [ 'acpi-s3', 'acpi-s4',
'requires-smm', 'secure-boot', 'verbose-dynamic', 'amd-sev', 'amd-sev-es', 'amd-sev-snp',
'verbose-static' ] } 'intel-tdx',
'enrolled-keys', 'requires-smm', 'secure-boot',
'verbose-dynamic', 'verbose-static' ] }
## ##
# @FirmwareFlashFile: # @FirmwareFlashFile:

View File

@ -22,16 +22,14 @@ maintained as part of the virtio specification.
1af4:1004 SCSI host bus adapter device (legacy) 1af4:1004 SCSI host bus adapter device (legacy)
1af4:1005 entropy generator device (legacy) 1af4:1005 entropy generator device (legacy)
1af4:1009 9p filesystem device (legacy) 1af4:1009 9p filesystem device (legacy)
1af4:1012 vsock device (bug compatibility)
1af4:1041 network device (modern) 1af4:1040 Start of ID range for modern virtio devices. The PCI device
1af4:1042 block device (modern) to ID is calculated from the virtio device ID by adding the
1af4:1043 console device (modern) 1af4:10ef 0x1040 offset. The virtio IDs are defined in the virtio
1af4:1044 entropy generator device (modern) specification. The Linux kernel has a header file with
1af4:1045 balloon device (modern) defines for all virtio IDs (linux/virtio_ids.h), qemu has a
1af4:1048 SCSI host bus adapter device (modern) copy in include/standard-headers/.
1af4:1049 9p filesystem device (modern)
1af4:1050 virtio gpu device (modern)
1af4:1052 virtio input device (modern)
1af4:10f0 Available for experimental usage without registration. Must get 1af4:10f0 Available for experimental usage without registration. Must get
to official ID when the code leaves the test lab (i.e. when seeking to official ID when the code leaves the test lab (i.e. when seeking

View File

@ -834,7 +834,7 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s)
word alignment, so we keep them for the next line */ word alignment, so we keep them for the next line */
/* XXX: keep alignment to speed up transfer */ /* XXX: keep alignment to speed up transfer */
end_ptr = s->cirrus_bltbuf + s->cirrus_blt_srcpitch; end_ptr = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
copy_count = s->cirrus_srcptr_end - end_ptr; copy_count = MIN(s->cirrus_srcptr_end - end_ptr, CIRRUS_BLTBUFSIZE);
memmove(s->cirrus_bltbuf, end_ptr, copy_count); memmove(s->cirrus_bltbuf, end_ptr, copy_count);
s->cirrus_srcptr = s->cirrus_bltbuf + copy_count; s->cirrus_srcptr = s->cirrus_bltbuf + copy_count;
s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch; s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;

View File

@ -74,8 +74,6 @@ static void virtio_iommu_pci_class_init(ObjectClass *klass, void *data)
k->realize = virtio_iommu_pci_realize; k->realize = virtio_iommu_pci_realize;
set_bit(DEVICE_CATEGORY_MISC, dc->categories); set_bit(DEVICE_CATEGORY_MISC, dc->categories);
device_class_set_props(dc, virtio_iommu_pci_properties); device_class_set_props(dc, virtio_iommu_pci_properties);
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_IOMMU;
pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
pcidev_k->class_id = PCI_CLASS_OTHERS; pcidev_k->class_id = PCI_CLASS_OTHERS;
dc->hotpluggable = false; dc->hotpluggable = false;
@ -90,7 +88,7 @@ static void virtio_iommu_pci_instance_init(Object *obj)
} }
static const VirtioPCIDeviceTypeInfo virtio_iommu_pci_info = { static const VirtioPCIDeviceTypeInfo virtio_iommu_pci_info = {
.generic_name = TYPE_VIRTIO_IOMMU_PCI, .generic_name = TYPE_VIRTIO_IOMMU_PCI,
.instance_size = sizeof(VirtIOIOMMUPCI), .instance_size = sizeof(VirtIOIOMMUPCI),
.instance_init = virtio_iommu_pci_instance_init, .instance_init = virtio_iommu_pci_instance_init,
.class_init = virtio_iommu_pci_class_init, .class_init = virtio_iommu_pci_class_init,

View File

@ -104,8 +104,6 @@ static void virtio_mem_pci_class_init(ObjectClass *klass, void *data)
k->realize = virtio_mem_pci_realize; k->realize = virtio_mem_pci_realize;
set_bit(DEVICE_CATEGORY_MISC, dc->categories); set_bit(DEVICE_CATEGORY_MISC, dc->categories);
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_MEM;
pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
pcidev_k->class_id = PCI_CLASS_OTHERS; pcidev_k->class_id = PCI_CLASS_OTHERS;

View File

@ -1688,7 +1688,7 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
pci_set_word(config + PCI_VENDOR_ID, pci_set_word(config + PCI_VENDOR_ID,
PCI_VENDOR_ID_REDHAT_QUMRANET); PCI_VENDOR_ID_REDHAT_QUMRANET);
pci_set_word(config + PCI_DEVICE_ID, pci_set_word(config + PCI_DEVICE_ID,
0x1040 + virtio_bus_get_vdev_id(bus)); PCI_DEVICE_ID_VIRTIO_10_BASE + virtio_bus_get_vdev_id(bus));
pci_config_set_revision(config, 1); pci_config_set_revision(config, 1);
} }
config[PCI_INTERRUPT_PIN] = 1; config[PCI_INTERRUPT_PIN] = 1;

View File

@ -90,8 +90,6 @@ static void virtio_pmem_pci_class_init(ObjectClass *klass, void *data)
k->realize = virtio_pmem_pci_realize; k->realize = virtio_pmem_pci_realize;
set_bit(DEVICE_CATEGORY_MISC, dc->categories); set_bit(DEVICE_CATEGORY_MISC, dc->categories);
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_PMEM;
pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
pcidev_k->class_id = PCI_CLASS_OTHERS; pcidev_k->class_id = PCI_CLASS_OTHERS;

View File

@ -76,6 +76,7 @@ extern bool pci_available;
#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4 #define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4
#define PCI_SUBDEVICE_ID_QEMU 0x1100 #define PCI_SUBDEVICE_ID_QEMU 0x1100
/* legacy virtio-pci devices */
#define PCI_DEVICE_ID_VIRTIO_NET 0x1000 #define PCI_DEVICE_ID_VIRTIO_NET 0x1000
#define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001 #define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001
#define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002 #define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002
@ -84,9 +85,15 @@ extern bool pci_available;
#define PCI_DEVICE_ID_VIRTIO_RNG 0x1005 #define PCI_DEVICE_ID_VIRTIO_RNG 0x1005
#define PCI_DEVICE_ID_VIRTIO_9P 0x1009 #define PCI_DEVICE_ID_VIRTIO_9P 0x1009
#define PCI_DEVICE_ID_VIRTIO_VSOCK 0x1012 #define PCI_DEVICE_ID_VIRTIO_VSOCK 0x1012
#define PCI_DEVICE_ID_VIRTIO_PMEM 0x1013
#define PCI_DEVICE_ID_VIRTIO_IOMMU 0x1014 /*
#define PCI_DEVICE_ID_VIRTIO_MEM 0x1015 * modern virtio-pci devices get their id assigned automatically,
* there is no need to add #defines here. It gets calculated as
*
* PCI_DEVICE_ID = PCI_DEVICE_ID_VIRTIO_10_BASE +
* virtio_bus_get_vdev_id(bus)
*/
#define PCI_DEVICE_ID_VIRTIO_10_BASE 0x1040
#define PCI_VENDOR_ID_REDHAT 0x1b36 #define PCI_VENDOR_ID_REDHAT 0x1b36
#define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001 #define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001

View File

@ -1199,13 +1199,16 @@
# interfaces (e.g. VGA and virtual console character devices) # interfaces (e.g. VGA and virtual console character devices)
# by default. # by default.
# Since 7.1 # Since 7.1
# @show-menubar: Display the main window menubar. Defaults to "on".
# Since 8.0
# #
# Since: 2.12 # Since: 2.12
## ##
{ 'struct' : 'DisplayGTK', { 'struct' : 'DisplayGTK',
'data' : { '*grab-on-hover' : 'bool', 'data' : { '*grab-on-hover' : 'bool',
'*zoom-to-fit' : 'bool', '*zoom-to-fit' : 'bool',
'*show-tabs' : 'bool' } } '*show-tabs' : 'bool',
'*show-menubar' : 'bool' } }
## ##
# @DisplayEGLHeadless: # @DisplayEGLHeadless:

View File

@ -92,6 +92,10 @@ int main(int argc, char *argv[])
fprintf(stderr, "not a number: %s\n", optarg); fprintf(stderr, "not a number: %s\n", optarg);
exit(1); exit(1);
} }
if (dpi == 0) {
fprintf(stderr, "cannot be zero: %s\n", optarg);
exit(1);
}
break; break;
case 'v': case 'v':
info.vendor = optarg; info.vendor = optarg;

View File

@ -1980,6 +1980,7 @@ DEF("display", HAS_ARG, QEMU_OPTION_display,
#if defined(CONFIG_GTK) #if defined(CONFIG_GTK)
"-display gtk[,full-screen=on|off][,gl=on|off][,grab-on-hover=on|off]\n" "-display gtk[,full-screen=on|off][,gl=on|off][,grab-on-hover=on|off]\n"
" [,show-tabs=on|off][,show-cursor=on|off][,window-close=on|off]\n" " [,show-tabs=on|off][,show-cursor=on|off][,window-close=on|off]\n"
" [,show-menubar=on|off]\n"
#endif #endif
#if defined(CONFIG_VNC) #if defined(CONFIG_VNC)
"-display vnc=<display>[,<optargs>]\n" "-display vnc=<display>[,<optargs>]\n"
@ -2072,6 +2073,8 @@ SRST
``window-close=on|off`` : Allow to quit qemu with window close button ``window-close=on|off`` : Allow to quit qemu with window close button
``show-menubar=on|off`` : Display the main window menubar, defaults to "on"
``curses[,charset=<encoding>]`` ``curses[,charset=<encoding>]``
Display video output via curses. For graphics device models Display video output via curses. For graphics device models
which support a text mode, QEMU can display this output using a which support a text mode, QEMU can display this output using a

View File

@ -195,6 +195,9 @@ void gd_egl_switch(DisplayChangeListener *dcl,
if (resized) { if (resized) {
gd_update_windowsize(vc); gd_update_windowsize(vc);
} }
eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT);
} }
QEMUGLContext gd_egl_create_context(DisplayGLCtx *dgc, QEMUGLContext gd_egl_create_context(DisplayGLCtx *dgc,

View File

@ -681,9 +681,13 @@ static void gd_mouse_mode_change(Notifier *notify, void *data)
s = container_of(notify, GtkDisplayState, mouse_mode_notifier); s = container_of(notify, GtkDisplayState, mouse_mode_notifier);
/* release the grab at switching to absolute mode */ /* release the grab at switching to absolute mode */
if (qemu_input_is_absolute() && gd_is_grab_active(s)) { if (qemu_input_is_absolute() && s->ptr_owner) {
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), if (!s->ptr_owner->window) {
FALSE); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
FALSE);
} else {
gd_ungrab_pointer(s);
}
} }
for (i = 0; i < s->nb_vcs; i++) { for (i = 0; i < s->nb_vcs; i++) {
VirtualConsole *vc = &s->vc[i]; VirtualConsole *vc = &s->vc[i];
@ -2167,7 +2171,7 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
return group; return group;
} }
static GtkWidget *gd_create_menu_view(GtkDisplayState *s) static GtkWidget *gd_create_menu_view(GtkDisplayState *s, DisplayOptions *opts)
{ {
GSList *group = NULL; GSList *group = NULL;
GtkWidget *view_menu; GtkWidget *view_menu;
@ -2265,7 +2269,8 @@ static GtkWidget *gd_create_menu_view(GtkDisplayState *s)
s->show_menubar_item = gtk_check_menu_item_new_with_mnemonic( s->show_menubar_item = gtk_check_menu_item_new_with_mnemonic(
_("Show Menubar")); _("Show Menubar"));
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->show_menubar_item), gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->show_menubar_item),
TRUE); !opts->u.gtk.has_show_menubar ||
opts->u.gtk.show_menubar);
gtk_accel_group_connect(s->accel_group, GDK_KEY_m, HOTKEY_MODIFIERS, 0, gtk_accel_group_connect(s->accel_group, GDK_KEY_m, HOTKEY_MODIFIERS, 0,
g_cclosure_new_swap(G_CALLBACK(gd_accel_show_menubar), s, NULL)); g_cclosure_new_swap(G_CALLBACK(gd_accel_show_menubar), s, NULL));
gtk_accel_label_set_accel( gtk_accel_label_set_accel(
@ -2276,13 +2281,13 @@ static GtkWidget *gd_create_menu_view(GtkDisplayState *s)
return view_menu; return view_menu;
} }
static void gd_create_menus(GtkDisplayState *s) static void gd_create_menus(GtkDisplayState *s, DisplayOptions *opts)
{ {
GtkSettings *settings; GtkSettings *settings;
s->accel_group = gtk_accel_group_new(); s->accel_group = gtk_accel_group_new();
s->machine_menu = gd_create_menu_machine(s); s->machine_menu = gd_create_menu_machine(s);
s->view_menu = gd_create_menu_view(s); s->view_menu = gd_create_menu_view(s, opts);
s->machine_menu_item = gtk_menu_item_new_with_mnemonic(_("_Machine")); s->machine_menu_item = gtk_menu_item_new_with_mnemonic(_("_Machine"));
gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->machine_menu_item), gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->machine_menu_item),
@ -2359,7 +2364,7 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts)
gtk_window_set_icon_name(GTK_WINDOW(s->window), "qemu"); gtk_window_set_icon_name(GTK_WINDOW(s->window), "qemu");
gd_create_menus(s); gd_create_menus(s, opts);
gd_connect_signals(s); gd_connect_signals(s);
@ -2374,6 +2379,10 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts)
gtk_container_add(GTK_CONTAINER(s->window), s->vbox); gtk_container_add(GTK_CONTAINER(s->window), s->vbox);
gtk_widget_show_all(s->window); gtk_widget_show_all(s->window);
if (opts->u.gtk.has_show_menubar &&
!opts->u.gtk.show_menubar) {
gtk_widget_hide(s->menu_bar);
}
vc = gd_vc_find_current(s); vc = gd_vc_find_current(s);
gtk_widget_set_sensitive(s->view_menu, vc != NULL); gtk_widget_set_sensitive(s->view_menu, vc != NULL);

View File

@ -2442,8 +2442,8 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
if (len == 1) { if (len == 1) {
return 8; return 8;
} }
uint32_t dlen = abs(read_s32(data, 4));
if (len == 8) { if (len == 8) {
uint32_t dlen = abs(read_s32(data, 4));
if (dlen > (1 << 20)) { if (dlen > (1 << 20)) {
error_report("vnc: client_cut_text msg payload has %u bytes" error_report("vnc: client_cut_text msg payload has %u bytes"
" which exceeds our limit of 1MB.", dlen); " which exceeds our limit of 1MB.", dlen);
@ -2456,8 +2456,13 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
} }
if (read_s32(data, 4) < 0) { if (read_s32(data, 4) < 0) {
vnc_client_cut_text_ext(vs, abs(read_s32(data, 4)), if (dlen < 4) {
read_u32(data, 8), data + 12); error_report("vnc: malformed payload (header less than 4 bytes)"
" in extended clipboard pseudo-encoding.");
vnc_client_error(vs);
break;
}
vnc_client_cut_text_ext(vs, dlen, read_u32(data, 8), data + 12);
break; break;
} }
vnc_client_cut_text(vs, read_u32(data, 4), data + 8); vnc_client_cut_text(vs, read_u32(data, 4), data + 8);