Merge tag 'for-11.0-pull-request' of https://gitlab.com/marcandre.lureau/qemu into staging Gather various audio/ui/dump patches for 11.0-rc # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCgAdFiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmm5jPYACgkQ2ujhCXWW # nOWsxQ/+LOVsrCjxSQTI7Iygo8ICXBKwjBXOHA9g4PHMSZDD5B+WbCXLXRPfSwkj # y+zjJpv13pqXXNFKw0MoEz6kIRKFWYq1XbHLgkXt538QIEJ5h5tff0V8YGtk9U0H # D2ZwUBOWH7OW4VDCFg2BCYNrnC4y2wxFG7lSm5tbeJzkAogsLRDNPf5thvHgdS+U # oYP2g8WdXx5ZgX8/f9tvDApTPXjfg1eATLy8veSZWkgqaCL8pO5E436sVT+cPRii # aFQpiTPms6vutOtQpWLHv6Kvffvkk0A1zrdlRrvlEhhWT3v5sBvF5hVH/iEt+LIL # ldChBtJnzc40ujsdKHSmUV+foCnKQYuWSwzgJaxSg2Rp81yrVZ+L8nz3f8W/raPp # 5dWr+i6e80+2nUvDL3LA6HOJGz2JtQyaRXc4BgiwePEMKT6RfFW9V4mWRp4ItlRv # 3mWhGFjPRLEU8kOefAcT77epe1gwLdlpUH3ZjCqECZYUWNu5FjNjPQUZ1kxD3o0K # 7TyxLrZ6OH9b3mGhum17GBF0tAI3rkErriOxzjQF3UqMsFB9+OZlzQNfQRL/NnYw # NjmV8JMXRe2+tjxS1bfqcUanmKpxYqiDJPJaoWG08VHuhuXBydfhiOhrG61H1u3N # yoq5kb8XZ4LiSin+smSl5a9gCa7qZ17ceAAxuuCbItCXuHZ4nsk= # =K+XO # -----END PGP SIGNATURE----- # gpg: Signature made Tue Mar 17 17:18:46 2026 GMT # gpg: using RSA key 87A9BD933F87C606D276F62DDAE8E10975969CE5 # gpg: Good signature from "Marc-André Lureau <marcandre.lureau@redhat.com>" [full] # gpg: aka "Marc-André Lureau <marcandre.lureau@gmail.com>" [full] # Primary key fingerprint: 87A9 BD93 3F87 C606 D276 F62D DAE8 E109 7596 9CE5 * tag 'for-11.0-pull-request' of https://gitlab.com/marcandre.lureau/qemu: coreaudio: Initialize the buffer for device change audio: Add functions to initialize buffers coreaudio: Commit the result of init in the end coreaudio: Improve naming ui/surface: Avoid including epoxy/gl.h in header files ui/console: Remove DisplaySurface::mem_obj ui/console: Unify pixman-OpenGL format mapping dump: enhance dump_state_prepare fd initialization ui/gtk-egl: Ensure EGL surface is available before drawing ui/dbus-listener: remove dbus_filter on connection close ui/dbus-listener: Fix FBO leak in dbus_cursor_dmabuf virtio-gpu: use computed rowstride instead of deriving it from hostmem virtio-gpu: fix overflow check when allocating 2d image ui/vdagent: add migration blocker when machine version < 10.1 rutabaga: improve error handling, fix potential crash during init audio/mixeng: drop some needless checks Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/audio/audio-mixeng-be.c b/audio/audio-mixeng-be.c index 5878b23..f7d73d8 100644 --- a/audio/audio-mixeng-be.c +++ b/audio/audio-mixeng-be.c
@@ -1187,14 +1187,20 @@ } } +void audio_generic_initialize_buffer_in(HWVoiceIn *hw) +{ + g_free(hw->buf_emul); + hw->size_emul = hw->samples * hw->info.bytes_per_frame; + hw->buf_emul = g_malloc(hw->size_emul); + hw->pos_emul = hw->pending_emul = 0; +} + void audio_generic_run_buffer_in(HWVoiceIn *hw) { AudioMixengBackendClass *k = AUDIO_MIXENG_BACKEND_GET_CLASS(hw->s); if (unlikely(!hw->buf_emul)) { - hw->size_emul = hw->samples * hw->info.bytes_per_frame; - hw->buf_emul = g_malloc(hw->size_emul); - hw->pos_emul = hw->pending_emul = 0; + audio_generic_initialize_buffer_in(hw); } while (hw->pending_emul < hw->size_emul) { @@ -1227,6 +1233,14 @@ hw->pending_emul -= size; } +void audio_generic_initialize_buffer_out(HWVoiceOut *hw) +{ + g_free(hw->buf_emul); + hw->size_emul = hw->samples * hw->info.bytes_per_frame; + hw->buf_emul = g_malloc(hw->size_emul); + hw->pos_emul = hw->pending_emul = 0; +} + size_t audio_generic_buffer_get_free(HWVoiceOut *hw) { if (hw->buf_emul) { @@ -1260,9 +1274,7 @@ void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size) { if (unlikely(!hw->buf_emul)) { - hw->size_emul = hw->samples * hw->info.bytes_per_frame; - hw->buf_emul = g_malloc(hw->size_emul); - hw->pos_emul = hw->pending_emul = 0; + audio_generic_initialize_buffer_out(hw); } *size = MIN(hw->size_emul - hw->pending_emul,
diff --git a/audio/audio_int.h b/audio/audio_int.h index 06f79ad..290cf37 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h
@@ -141,9 +141,11 @@ int wav_start_capture(AudioBackend *state, CaptureState *s, const char *path, int freq, int bits, int nchannels); +void audio_generic_initialize_buffer_in(HWVoiceIn *hw); void audio_generic_run_buffer_in(HWVoiceIn *hw); void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size); void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size); +void audio_generic_initialize_buffer_out(HWVoiceOut *hw); void audio_generic_run_buffer_out(HWVoiceOut *hw); size_t audio_generic_buffer_get_free(HWVoiceOut *hw); void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size);
diff --git a/audio/audio_template.h b/audio/audio_template.h index 228369c..fe769cd 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h
@@ -497,12 +497,6 @@ AudioMixengBackendClass *k; AudiodevPerDirectionOptions *pdo; - if (!be || !name || !callback_fn || !as) { - audio_bug("backend=%p name=%p callback_fn=%p as=%p", - be, name, callback_fn, as); - goto fail; - } - k = AUDIO_MIXENG_BACKEND_GET_CLASS(s); pdo = glue(audio_get_pdo_, TYPE)(s->dev);
diff --git a/audio/coreaudio.m b/audio/coreaudio.m index bc9ab74..e4ec1df 100644 --- a/audio/coreaudio.m +++ b/audio/coreaudio.m
@@ -43,34 +43,34 @@ typedef struct coreaudioVoiceOut { HWVoiceOut hw; pthread_mutex_t buf_mutex; - AudioDeviceID outputDeviceID; - int frameSizeSetting; - uint32_t bufferCount; - UInt32 audioDevicePropertyBufferFrameSize; + AudioDeviceID device_id; + int frame_size_setting; + uint32_t buffer_count; + UInt32 device_frame_size; AudioDeviceIOProcID ioprocid; bool enabled; -} coreaudioVoiceOut; +} CoreaudioVoiceOut; -static const AudioObjectPropertyAddress voice_addr = { +static const AudioObjectPropertyAddress voice_out_addr = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain }; -static OSStatus coreaudio_get_voice(AudioDeviceID *id) +static OSStatus coreaudio_get_voice_out(AudioDeviceID *id) { UInt32 size = sizeof(*id); return AudioObjectGetPropertyData(kAudioObjectSystemObject, - &voice_addr, + &voice_out_addr, 0, NULL, &size, id); } -static OSStatus coreaudio_get_framesizerange(AudioDeviceID id, - AudioValueRange *framerange) +static OSStatus coreaudio_get_out_framesizerange(AudioDeviceID id, + AudioValueRange *framerange) { UInt32 size = sizeof(*framerange); AudioObjectPropertyAddress addr = { @@ -87,7 +87,7 @@ framerange); } -static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize) +static OSStatus coreaudio_get_out_framesize(AudioDeviceID id, UInt32 *framesize) { UInt32 size = sizeof(*framesize); AudioObjectPropertyAddress addr = { @@ -104,7 +104,7 @@ framesize); } -static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize) +static OSStatus coreaudio_set_out_framesize(AudioDeviceID id, UInt32 *framesize) { UInt32 size = sizeof(*framesize); AudioObjectPropertyAddress addr = { @@ -121,8 +121,8 @@ framesize); } -static OSStatus coreaudio_set_streamformat(AudioDeviceID id, - AudioStreamBasicDescription *d) +static OSStatus coreaudio_set_out_streamformat(AudioDeviceID id, + AudioStreamBasicDescription *d) { UInt32 size = sizeof(*d); AudioObjectPropertyAddress addr = { @@ -139,7 +139,7 @@ d); } -static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result) +static OSStatus coreaudio_get_out_isrunning(AudioDeviceID id, UInt32 *result) { UInt32 size = sizeof(*result); AudioObjectPropertyAddress addr = { @@ -243,7 +243,8 @@ #define coreaudio_playback_logerr(status, ...) \ coreaudio_logerr2(status, "playback", __VA_ARGS__) -static int coreaudio_buf_lock(coreaudioVoiceOut *core, const char *fn_name) +static int coreaudio_voice_out_buf_lock(CoreaudioVoiceOut *core, + const char *fn_name) { int err; @@ -256,7 +257,8 @@ return 0; } -static int coreaudio_buf_unlock(coreaudioVoiceOut *core, const char *fn_name) +static int coreaudio_voice_out_buf_unlock(CoreaudioVoiceOut *core, + const char *fn_name) { int err; @@ -269,20 +271,20 @@ return 0; } -#define COREAUDIO_WRAPPER_FUNC(name, ret_type, args_decl, args) \ - static ret_type glue(coreaudio_, name)args_decl \ - { \ - coreaudioVoiceOut *core = (coreaudioVoiceOut *)hw; \ - ret_type ret; \ - \ - if (coreaudio_buf_lock(core, "coreaudio_" #name)) { \ - return 0; \ - } \ - \ - ret = glue(audio_generic_, name)args; \ - \ - coreaudio_buf_unlock(core, "coreaudio_" #name); \ - return ret; \ +#define COREAUDIO_WRAPPER_FUNC(name, ret_type, args_decl, args) \ + static ret_type glue(coreaudio_, name)args_decl \ + { \ + CoreaudioVoiceOut *core = (CoreaudioVoiceOut *)hw; \ + ret_type ret; \ + \ + if (coreaudio_voice_out_buf_lock(core, "coreaudio_" #name)) { \ + return 0; \ + } \ + \ + ret = glue(audio_generic_, name)args; \ + \ + coreaudio_voice_out_buf_unlock(core, "coreaudio_" #name); \ + return ret; \ } COREAUDIO_WRAPPER_FUNC(buffer_get_free, size_t, (HWVoiceOut *hw), (hw)) COREAUDIO_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size), @@ -298,7 +300,7 @@ * callback to feed audiooutput buffer. called without BQL. * allowed to lock "buf_mutex", but disallowed to have any other locks. */ -static OSStatus audioDeviceIOProc( +static OSStatus out_device_ioproc( AudioDeviceID inDevice, const AudioTimeStamp *inNow, const AudioBufferList *inInputData, @@ -307,33 +309,33 @@ const AudioTimeStamp *inOutputTime, void *hwptr) { - UInt32 frameCount, pending_frames; + UInt32 frame_size, pending_frames; void *out = outOutputData->mBuffers[0].mData; HWVoiceOut *hw = hwptr; - coreaudioVoiceOut *core = hwptr; + CoreaudioVoiceOut *core = hwptr; size_t len; - if (coreaudio_buf_lock(core, "audioDeviceIOProc")) { + if (coreaudio_voice_out_buf_lock(core, "out_device_ioproc")) { inInputTime = 0; return 0; } - if (inDevice != core->outputDeviceID) { - coreaudio_buf_unlock(core, "audioDeviceIOProc(old device)"); + if (inDevice != core->device_id) { + coreaudio_voice_out_buf_unlock(core, "out_device_ioproc(old device)"); return 0; } - frameCount = core->audioDevicePropertyBufferFrameSize; + frame_size = core->device_frame_size; pending_frames = hw->pending_emul / hw->info.bytes_per_frame; /* if there are not enough samples, set signal and return */ - if (pending_frames < frameCount) { + if (pending_frames < frame_size) { inInputTime = 0; - coreaudio_buf_unlock(core, "audioDeviceIOProc(empty)"); + coreaudio_voice_out_buf_unlock(core, "out_device_ioproc(empty)"); return 0; } - len = frameCount * hw->info.bytes_per_frame; + len = frame_size * hw->info.bytes_per_frame; while (len) { size_t write_len, start; @@ -349,16 +351,19 @@ out += write_len; } - coreaudio_buf_unlock(core, "audioDeviceIOProc"); + coreaudio_voice_out_buf_unlock(core, "out_device_ioproc"); return 0; } -static OSStatus init_out_device(coreaudioVoiceOut *core) +static OSStatus init_out_device(CoreaudioVoiceOut *core) { + AudioDeviceID device_id; + AudioDeviceIOProcID ioprocid; + AudioValueRange value_range; OSStatus status; - AudioValueRange frameRange; + UInt32 device_frame_size; - AudioStreamBasicDescription streamBasicDescription = { + AudioStreamBasicDescription stream_basic_description = { .mBitsPerChannel = audio_format_bits(core->hw.info.af), .mBytesPerFrame = core->hw.info.bytes_per_frame, .mBytesPerPacket = core->hw.info.bytes_per_frame, @@ -369,21 +374,20 @@ .mSampleRate = core->hw.info.freq }; - status = coreaudio_get_voice(&core->outputDeviceID); + status = coreaudio_get_voice_out(&device_id); if (status != kAudioHardwareNoError) { coreaudio_playback_logerr(status, "Could not get default output device"); return status; } - if (core->outputDeviceID == kAudioDeviceUnknown) { + if (device_id == kAudioDeviceUnknown) { error_report("coreaudio: Could not initialize playback: " "Unknown audio device"); return status; } /* get minimum and maximum buffer frame sizes */ - status = coreaudio_get_framesizerange(core->outputDeviceID, - &frameRange); + status = coreaudio_get_out_framesizerange(device_id, &value_range); if (status == kAudioHardwareBadObjectError) { return 0; } @@ -393,34 +397,32 @@ return status; } - if (frameRange.mMinimum > core->frameSizeSetting) { - core->audioDevicePropertyBufferFrameSize = frameRange.mMinimum; + if (value_range.mMinimum > core->frame_size_setting) { + device_frame_size = value_range.mMinimum; warn_report("coreaudio: Upsizing buffer frames to %f", - frameRange.mMinimum); - } else if (frameRange.mMaximum < core->frameSizeSetting) { - core->audioDevicePropertyBufferFrameSize = frameRange.mMaximum; + value_range.mMinimum); + } else if (value_range.mMaximum < core->frame_size_setting) { + device_frame_size = value_range.mMaximum; warn_report("coreaudio: Downsizing buffer frames to %f", - frameRange.mMaximum); + value_range.mMaximum); } else { - core->audioDevicePropertyBufferFrameSize = core->frameSizeSetting; + device_frame_size = core->frame_size_setting; } /* set Buffer Frame Size */ - status = coreaudio_set_framesize(core->outputDeviceID, - &core->audioDevicePropertyBufferFrameSize); + status = coreaudio_set_out_framesize(device_id, &device_frame_size); if (status == kAudioHardwareBadObjectError) { return 0; } if (status != kAudioHardwareNoError) { coreaudio_playback_logerr(status, "Could not set device buffer frame size %" PRIu32, - (uint32_t)core->audioDevicePropertyBufferFrameSize); + (uint32_t)device_frame_size); return status; } /* get Buffer Frame Size */ - status = coreaudio_get_framesize(core->outputDeviceID, - &core->audioDevicePropertyBufferFrameSize); + status = coreaudio_get_out_framesize(device_id, &device_frame_size); if (status == kAudioHardwareBadObjectError) { return 0; } @@ -429,19 +431,17 @@ "Could not get device buffer frame size"); return status; } - core->hw.samples = core->bufferCount * core->audioDevicePropertyBufferFrameSize; /* set Samplerate */ - status = coreaudio_set_streamformat(core->outputDeviceID, - &streamBasicDescription); + status = coreaudio_set_out_streamformat(device_id, + &stream_basic_description); if (status == kAudioHardwareBadObjectError) { return 0; } if (status != kAudioHardwareNoError) { coreaudio_playback_logerr(status, "Could not set samplerate %lf", - streamBasicDescription.mSampleRate); - core->outputDeviceID = kAudioDeviceUnknown; + stream_basic_description.mSampleRate); return status; } @@ -455,30 +455,35 @@ * Therefore, the specified callback must be designed to avoid a deadlock * with the callers of AudioObjectGetPropertyData. */ - core->ioprocid = NULL; - status = AudioDeviceCreateIOProcID(core->outputDeviceID, - audioDeviceIOProc, + ioprocid = NULL; + status = AudioDeviceCreateIOProcID(device_id, + out_device_ioproc, &core->hw, - &core->ioprocid); + &ioprocid); if (status == kAudioHardwareBadDeviceError) { return 0; } - if (status != kAudioHardwareNoError || core->ioprocid == NULL) { + if (status != kAudioHardwareNoError || ioprocid == NULL) { coreaudio_playback_logerr(status, "Could not set IOProc"); - core->outputDeviceID = kAudioDeviceUnknown; return status; } + core->device_id = device_id; + core->device_frame_size = device_frame_size; + core->hw.samples = core->buffer_count * core->device_frame_size; + audio_generic_initialize_buffer_out(&core->hw); + core->ioprocid = ioprocid; + return 0; } -static void fini_out_device(coreaudioVoiceOut *core) +static void fini_out_device(CoreaudioVoiceOut *core) { OSStatus status; UInt32 isrunning; /* stop playback */ - status = coreaudio_get_isrunning(core->outputDeviceID, &isrunning); + status = coreaudio_get_out_isrunning(core->device_id, &isrunning); if (status != kAudioHardwareBadObjectError) { if (status != kAudioHardwareNoError) { coreaudio_logerr(status, @@ -486,7 +491,7 @@ } if (isrunning) { - status = AudioDeviceStop(core->outputDeviceID, core->ioprocid); + status = AudioDeviceStop(core->device_id, core->ioprocid); if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) { coreaudio_logerr(status, "Could not stop playback"); } @@ -494,20 +499,20 @@ } /* remove callback */ - status = AudioDeviceDestroyIOProcID(core->outputDeviceID, + status = AudioDeviceDestroyIOProcID(core->device_id, core->ioprocid); if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) { coreaudio_logerr(status, "Could not remove IOProc"); } - core->outputDeviceID = kAudioDeviceUnknown; + core->device_id = kAudioDeviceUnknown; } -static void update_device_playback_state(coreaudioVoiceOut *core) +static void update_out_device_playback_state(CoreaudioVoiceOut *core) { OSStatus status; UInt32 isrunning; - status = coreaudio_get_isrunning(core->outputDeviceID, &isrunning); + status = coreaudio_get_out_isrunning(core->device_id, &isrunning); if (status != kAudioHardwareNoError) { if (status != kAudioHardwareBadObjectError) { coreaudio_logerr(status, @@ -520,7 +525,7 @@ if (core->enabled) { /* start playback */ if (!isrunning) { - status = AudioDeviceStart(core->outputDeviceID, core->ioprocid); + status = AudioDeviceStart(core->device_id, core->ioprocid); if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) { coreaudio_logerr(status, "Could not resume playback"); } @@ -528,7 +533,7 @@ } else { /* stop playback */ if (isrunning) { - status = AudioDeviceStop(core->outputDeviceID, + status = AudioDeviceStop(core->device_id, core->ioprocid); if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) { coreaudio_logerr(status, "Could not pause playback"); @@ -538,22 +543,24 @@ } /* called without BQL. */ -static OSStatus handle_voice_change( +static OSStatus handle_voice_out_change( AudioObjectID in_object_id, UInt32 in_number_addresses, const AudioObjectPropertyAddress *in_addresses, void *in_client_data) { - coreaudioVoiceOut *core = in_client_data; + CoreaudioVoiceOut *core = in_client_data; bql_lock(); - if (core->outputDeviceID) { + if (core->device_id) { fini_out_device(core); } - if (!init_out_device(core)) { - update_device_playback_state(core); + init_out_device(core); + + if (core->device_id) { + update_out_device_playback_state(core); } bql_unlock(); @@ -563,7 +570,7 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as) { OSStatus status; - coreaudioVoiceOut *core = (coreaudioVoiceOut *)hw; + CoreaudioVoiceOut *core = (CoreaudioVoiceOut *)hw; int err; Audiodev *dev = hw->s->dev; AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out; @@ -581,13 +588,14 @@ as->fmt = AUDIO_FORMAT_F32; audio_pcm_init_info(&hw->info, as); - core->frameSizeSetting = audio_buffer_frames( + core->frame_size_setting = audio_buffer_frames( qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo), as, 11610); - core->bufferCount = cpdo->has_buffer_count ? cpdo->buffer_count : 4; + core->buffer_count = cpdo->has_buffer_count ? cpdo->buffer_count : 4; status = AudioObjectAddPropertyListener(kAudioObjectSystemObject, - &voice_addr, handle_voice_change, + &voice_out_addr, + handle_voice_out_change, core); if (status != kAudioHardwareNoError) { coreaudio_playback_logerr(status, @@ -597,8 +605,8 @@ if (init_out_device(core)) { status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, - &voice_addr, - handle_voice_change, + &voice_out_addr, + handle_voice_out_change, core); if (status != kAudioHardwareNoError) { coreaudio_playback_logerr(status, @@ -615,11 +623,11 @@ { OSStatus status; int err; - coreaudioVoiceOut *core = (coreaudioVoiceOut *)hw; + CoreaudioVoiceOut *core = (CoreaudioVoiceOut *)hw; status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, - &voice_addr, - handle_voice_change, + &voice_out_addr, + handle_voice_out_change, core); if (status != kAudioHardwareNoError) { coreaudio_logerr(status, "Could not remove voice property change listener"); @@ -636,10 +644,10 @@ static void coreaudio_enable_out(HWVoiceOut *hw, bool enable) { - coreaudioVoiceOut *core = (coreaudioVoiceOut *)hw; + CoreaudioVoiceOut *core = (CoreaudioVoiceOut *)hw; core->enabled = enable; - update_device_playback_state(core); + update_out_device_playback_state(core); } static void audio_coreaudio_class_init(ObjectClass *klass, const void *data) @@ -648,7 +656,7 @@ k->max_voices_out = 1; k->max_voices_in = 0; - k->voice_size_out = sizeof(coreaudioVoiceOut); + k->voice_size_out = sizeof(CoreaudioVoiceOut); k->voice_size_in = 0; k->init_out = coreaudio_init_out;
diff --git a/dump/dump.c b/dump/dump.c index 80ed6c8..1f216e7 100644 --- a/dump/dump.c +++ b/dump/dump.c
@@ -104,7 +104,10 @@ guest_phys_blocks_free(&s->guest_phys_blocks); memory_mapping_list_free(&s->list); - close(s->fd); + if (s->fd != -1) { + close(s->fd); + } + s->fd = -1; g_free(s->guest_note); g_clear_pointer(&s->string_table_buf, g_array_unref); s->guest_note = NULL; @@ -1709,8 +1712,8 @@ static void dump_state_prepare(DumpState *s) { - /* zero the struct, setting status to active */ - *s = (DumpState) { .status = DUMP_STATUS_ACTIVE }; + /* zero the struct, setting status to active and fd to -1 */ + *s = (DumpState) { .fd = -1, .status = DUMP_STATUS_ACTIVE }; } bool qemu_system_dump_in_progress(void)
diff --git a/hw/core/machine.c b/hw/core/machine.c index a14ad05..6cf0e2f 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c
@@ -57,6 +57,7 @@ { "vfio-pci", "x-migration-load-config-after-iter", "off" }, { "ramfb", "use-legacy-x86-rom", "true"}, { "vfio-pci-nohotplug", "use-legacy-x86-rom", "true" }, + { "chardev-qemu-vdagent", "x-migration-blocked", "true" }, }; const size_t hw_compat_10_0_len = G_N_ELEMENTS(hw_compat_10_0);
diff --git a/hw/display/virtio-gpu-rutabaga.c b/hw/display/virtio-gpu-rutabaga.c index ed5ae52..ebb6c78 100644 --- a/hw/display/virtio-gpu-rutabaga.c +++ b/hw/display/virtio-gpu-rutabaga.c
@@ -1032,19 +1032,19 @@ return true; } -static int virtio_gpu_rutabaga_get_num_capsets(VirtIOGPU *g) +static bool +virtio_gpu_rutabaga_get_num_capsets(VirtIOGPU *g, uint32_t *num_capsets, Error **errp) { int result; - uint32_t num_capsets; VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g); - result = rutabaga_get_num_capsets(vr->rutabaga, &num_capsets); + result = rutabaga_get_num_capsets(vr->rutabaga, num_capsets); if (result) { - error_report("Failed to get capsets"); - return 0; + error_setg_errno(errp, -result, "Failed to get num_capsets"); + return false; } - vr->num_capsets = num_capsets; - return num_capsets; + vr->num_capsets = *num_capsets; + return true; } static void virtio_gpu_rutabaga_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) @@ -1070,7 +1070,7 @@ static void virtio_gpu_rutabaga_realize(DeviceState *qdev, Error **errp) { - int num_capsets; + uint32_t num_capsets; VirtIOGPUBase *bdev = VIRTIO_GPU_BASE(qdev); VirtIOGPU *gpudev = VIRTIO_GPU(qdev); @@ -1083,8 +1083,7 @@ return; } - num_capsets = virtio_gpu_rutabaga_get_num_capsets(gpudev); - if (!num_capsets) { + if (!virtio_gpu_rutabaga_get_num_capsets(gpudev, &num_capsets, errp)) { return; }
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index de7a86a..b998ce8 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c
@@ -227,16 +227,21 @@ virtio_gpu_ctrl_response(g, cmd, &edid.hdr, sizeof(edid)); } -static uint32_t calc_image_hostmem(pixman_format_code_t pformat, - uint32_t width, uint32_t height) +static bool calc_image_hostmem(pixman_format_code_t pformat, + uint32_t width, uint32_t height, + uint32_t *hostmem, uint32_t *rowstride_bytes) { - /* Copied from pixman/pixman-bits-image.c, skip integer overflow check. - * pixman_image_create_bits will fail in case it overflow. - */ + uint64_t bpp = PIXMAN_FORMAT_BPP(pformat); + uint64_t stride = (((uint64_t)width * bpp + 0x1f) >> 5) * sizeof(uint32_t); + uint64_t size = (uint64_t)height * stride; - int bpp = PIXMAN_FORMAT_BPP(pformat); - int stride = ((width * bpp + 0x1f) >> 5) * sizeof(uint32_t); - return height * stride; + if (size > UINT32_MAX) { + return false; + } + + *hostmem = size; + *rowstride_bytes = stride; + return true; } static void virtio_gpu_resource_create_2d(VirtIOGPU *g, @@ -246,6 +251,7 @@ pixman_format_code_t pformat; struct virtio_gpu_simple_resource *res; struct virtio_gpu_resource_create_2d c2d; + uint32_t hostmem, rowstride_bytes; VIRTIO_GPU_FILL_CMD(c2d); virtio_gpu_bswap_32(&c2d, sizeof(c2d)); @@ -284,7 +290,13 @@ return; } - res->hostmem = calc_image_hostmem(pformat, c2d.width, c2d.height); + if (!calc_image_hostmem(pformat, c2d.width, c2d.height, + &hostmem, &rowstride_bytes)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: image dimensions overflow\n", + __func__); + goto end; + } + res->hostmem = hostmem; if (res->hostmem + g->hostmem < g->conf_max_hostmem) { if (!qemu_pixman_image_new_shareable( &res->image, @@ -293,7 +305,7 @@ pformat, c2d.width, c2d.height, - c2d.height ? res->hostmem / c2d.height : 0, + rowstride_bytes, &err)) { warn_report_err(err); goto end; @@ -1292,7 +1304,7 @@ VirtIOGPU *g = opaque; Error *err = NULL; struct virtio_gpu_simple_resource *res; - uint32_t resource_id, pformat; + uint32_t resource_id, pformat, hostmem, rowstride_bytes; int i, ret; g->hostmem = 0; @@ -1318,14 +1330,19 @@ return -EINVAL; } - res->hostmem = calc_image_hostmem(pformat, res->width, res->height); + if (!calc_image_hostmem(pformat, res->width, res->height, + &hostmem, &rowstride_bytes)) { + g_free(res); + return -EINVAL; + } + res->hostmem = hostmem; if (!qemu_pixman_image_new_shareable(&res->image, &res->share_handle, "virtio-gpu res", pformat, res->width, res->height, - res->height ? res->hostmem / res->height : 0, + rowstride_bytes, &err)) { warn_report_err(err); g_free(res);
diff --git a/include/ui/console.h b/include/ui/console.h index 3677a9d..0808238 100644 --- a/include/ui/console.h +++ b/include/ui/console.h
@@ -423,8 +423,8 @@ void surface_gl_create_texture(QemuGLShader *gls, DisplaySurface *surface); bool surface_gl_create_texture_from_fd(DisplaySurface *surface, - int fd, GLuint *texture, - GLuint *mem_obj); + int fd, uint32_t *texture, + uint32_t *mem_obj); void surface_gl_update_texture(QemuGLShader *gls, DisplaySurface *surface, int x, int y, int w, int h);
diff --git a/include/ui/shader.h b/include/ui/shader.h index 4c5acb2..e822132 100644 --- a/include/ui/shader.h +++ b/include/ui/shader.h
@@ -1,8 +1,6 @@ #ifndef QEMU_SHADER_H #define QEMU_SHADER_H -#include <epoxy/gl.h> - typedef struct QemuGLShader QemuGLShader; void qemu_gl_run_texture_blit(QemuGLShader *gls, bool flip);
diff --git a/include/ui/spice-display.h b/include/ui/spice-display.h index 690ece7..a382553 100644 --- a/include/ui/spice-display.h +++ b/include/ui/spice-display.h
@@ -121,6 +121,7 @@ QEMUBH *gl_unblock_bh; QEMUTimer *gl_unblock_timer; QemuGLShader *gls; + GLuint gl_surface_mem_obj; int gl_updates; bool have_scanout; bool have_surface;
diff --git a/include/ui/surface.h b/include/ui/surface.h index 006b198..d2542d3 100644 --- a/include/ui/surface.h +++ b/include/ui/surface.h
@@ -8,7 +8,6 @@ #include "ui/qemu-pixman.h" #ifdef CONFIG_OPENGL -# include <epoxy/gl.h> # include "ui/shader.h" #endif @@ -19,10 +18,7 @@ pixman_image_t *image; uint8_t flags; #ifdef CONFIG_OPENGL - GLenum glformat; - GLenum gltype; - GLuint texture; - GLuint mem_obj; + uint32_t texture; #endif qemu_pixman_shareable share_handle; uint32_t share_handle_offset;
diff --git a/ui/console-gl.c b/ui/console-gl.c index 403fc36..d4b9017 100644 --- a/ui/console-gl.c +++ b/ui/console-gl.c
@@ -25,28 +25,51 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" +#include <epoxy/gl.h> #include "qemu/error-report.h" #include "ui/console.h" #include "ui/shader.h" /* ---------------------------------------------------------------------- */ -bool console_gl_check_format(DisplayChangeListener *dcl, - pixman_format_code_t format) +static bool map_format(pixman_format_code_t format, + GLenum *glformat, GLenum *gltype) { switch (format) { case PIXMAN_BE_b8g8r8x8: case PIXMAN_BE_b8g8r8a8: + *glformat = GL_BGRA_EXT; + *gltype = GL_UNSIGNED_BYTE; + return true; + case PIXMAN_BE_x8r8g8b8: + case PIXMAN_BE_a8r8g8b8: + *glformat = GL_RGBA; + *gltype = GL_UNSIGNED_BYTE; + return true; case PIXMAN_r5g6b5: + *glformat = GL_RGB; + *gltype = GL_UNSIGNED_SHORT_5_6_5; return true; default: return false; } } +bool console_gl_check_format(DisplayChangeListener *dcl, + pixman_format_code_t format) +{ + GLenum glformat; + GLenum gltype; + + return map_format(format, &glformat, &gltype); +} + void surface_gl_create_texture(QemuGLShader *gls, DisplaySurface *surface) { + GLenum glformat; + GLenum gltype; + assert(gls); assert(QEMU_IS_ALIGNED(surface_stride(surface), surface_bytes_per_pixel(surface))); @@ -54,25 +77,7 @@ return; } - switch (surface_format(surface)) { - case PIXMAN_BE_b8g8r8x8: - case PIXMAN_BE_b8g8r8a8: - surface->glformat = GL_BGRA_EXT; - surface->gltype = GL_UNSIGNED_BYTE; - break; - case PIXMAN_BE_x8r8g8b8: - case PIXMAN_BE_a8r8g8b8: - surface->glformat = GL_RGBA; - surface->gltype = GL_UNSIGNED_BYTE; - break; - case PIXMAN_r5g6b5: - surface->glformat = GL_RGB; - surface->gltype = GL_UNSIGNED_SHORT_5_6_5; - break; - default: - g_assert_not_reached(); - } - + assert(map_format(surface_format(surface), &glformat, &gltype)); glGenTextures(1, &surface->texture); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, surface->texture); @@ -80,16 +85,12 @@ surface_stride(surface) / surface_bytes_per_pixel(surface)); if (epoxy_is_desktop_gl()) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, - surface_width(surface), - surface_height(surface), - 0, surface->glformat, surface->gltype, - surface_data(surface)); + surface_width(surface), surface_height(surface), 0, + glformat, gltype, surface_data(surface)); } else { - glTexImage2D(GL_TEXTURE_2D, 0, surface->glformat, - surface_width(surface), - surface_height(surface), - 0, surface->glformat, surface->gltype, - surface_data(surface)); + glTexImage2D(GL_TEXTURE_2D, 0, glformat, + surface_width(surface), surface_height(surface), 0, + glformat, gltype, surface_data(surface)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE); } @@ -149,17 +150,18 @@ int x, int y, int w, int h) { uint8_t *data = (void *)surface_data(surface); + GLenum glformat; + GLenum gltype; assert(gls); + assert(map_format(surface_format(surface), &glformat, &gltype)); if (surface->texture) { glBindTexture(GL_TEXTURE_2D, surface->texture); glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, surface_stride(surface) / surface_bytes_per_pixel(surface)); - glTexSubImage2D(GL_TEXTURE_2D, 0, - x, y, w, h, - surface->glformat, surface->gltype, + glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, glformat, gltype, data + surface_stride(surface) * y + surface_bytes_per_pixel(surface) * x); } @@ -184,12 +186,6 @@ } glDeleteTextures(1, &surface->texture); surface->texture = 0; -#ifdef GL_EXT_memory_object_fd - if (surface->mem_obj) { - glDeleteMemoryObjectsEXT(1, &surface->mem_obj); - surface->mem_obj = 0; - } -#endif } void surface_gl_setup_viewport(QemuGLShader *gls,
diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c index 3e2b4ad..3794523 100644 --- a/ui/dbus-listener.c +++ b/ui/dbus-listener.c
@@ -660,6 +660,7 @@ egl_fb_setup_for_tex(&cursor_fb, width, height, texture, false); ds = qemu_create_displaysurface(width, height); egl_fb_read(ds, &cursor_fb); + egl_fb_destroy(&cursor_fb); v_data = g_variant_new_from_data( G_VARIANT_TYPE("ay"), @@ -1180,6 +1181,20 @@ #endif } +static void +dbus_conn_closed(GDBusConnection *conn, + gboolean remote_peer_vanished, + GError *error, + gpointer user_data) +{ + DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(user_data); + + if (ddl->dbus_filter) { + g_dbus_connection_remove_filter(ddl->conn, ddl->dbus_filter); + ddl->dbus_filter = 0; + } +} + static GDBusMessage * dbus_filter(GDBusConnection *connection, GDBusMessage *message, @@ -1261,6 +1276,7 @@ } ddl->dbus_filter = g_dbus_connection_add_filter(conn, dbus_filter, g_object_ref(ddl), g_object_unref); + g_signal_connect(conn, "closed", G_CALLBACK(dbus_conn_closed), ddl); ddl->bus_name = g_strdup(bus_name); ddl->conn = conn; ddl->console = console;
diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c index 1b5c1d4..fa8fe89 100644 --- a/ui/gtk-egl.c +++ b/ui/gtk-egl.c
@@ -152,12 +152,6 @@ gd_update_monitor_refresh_rate( vc, vc->window ? vc->window : vc->gfx.drawing_area); - if (vc->gfx.guest_fb.dmabuf && - qemu_dmabuf_get_draw_submitted(vc->gfx.guest_fb.dmabuf)) { - gd_egl_draw(vc); - return; - } - if (!vc->gfx.esurface) { gd_egl_init(vc); if (!vc->gfx.esurface) { @@ -176,6 +170,12 @@ #endif } + if (vc->gfx.guest_fb.dmabuf && + qemu_dmabuf_get_draw_submitted(vc->gfx.guest_fb.dmabuf)) { + gd_egl_draw(vc); + return; + } + graphic_hw_update(dcl->con); if (vc->gfx.glupdates) {
diff --git a/ui/shader.c b/ui/shader.c index ab448c4..76ee4c3 100644 --- a/ui/shader.c +++ b/ui/shader.c
@@ -25,6 +25,7 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" +#include <epoxy/gl.h> #include "ui/shader.h" #include "ui/shader/texture-blit-vert.h"
diff --git a/ui/spice-display.c b/ui/spice-display.c index 5052f37..87cc193 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c
@@ -950,7 +950,14 @@ } else { surface_gl_destroy_texture(ssd->gls, ssd->ds); ssd->ds->texture = texture; - ssd->ds->mem_obj = mem_obj; + +#ifdef GL_EXT_memory_object_fd + if (ssd->gl_surface_mem_obj) { + glDeleteMemoryObjectsEXT(1, &ssd->gl_surface_mem_obj); + } + + ssd->gl_surface_mem_obj = mem_obj; +#endif } return ret; }
diff --git a/ui/vdagent.c b/ui/vdagent.c index 5a5e4bf..bb0c4aa 100644 --- a/ui/vdagent.c +++ b/ui/vdagent.c
@@ -6,6 +6,8 @@ #include "qemu/option.h" #include "qemu/units.h" #include "hw/core/qdev.h" +#include "hw/core/qdev-properties.h" +#include "migration/blocker.h" #include "ui/clipboard.h" #include "ui/console.h" #include "ui/input.h" @@ -24,6 +26,10 @@ struct VDAgentChardev { Chardev parent; + /* needed for machine versions < 10.1 when migration was not supported */ + Error *migration_blocker; + bool migration_blocked; + /* config */ bool mouse; bool clipboard; @@ -657,6 +663,12 @@ return false; #endif + if (vd->migration_blocked) { + if (migrate_add_blocker(&vd->migration_blocker, errp) != 0) { + return false; + } + } + vd->mouse = VDAGENT_MOUSE_DEFAULT; if (cfg->has_mouse) { vd->mouse = cfg->mouse; @@ -901,6 +913,19 @@ /* ------------------------------------------------------------------ */ +static bool get_migration_blocked(Object *o, Error **errp) +{ + VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(o); + return vd->migration_blocked; +} + +static void set_migration_blocked(Object *o, bool migration_blocked, + Error **errp) +{ + VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(o); + vd->migration_blocked = migration_blocked; +} + static void vdagent_chr_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); @@ -910,6 +935,10 @@ cc->chr_write = vdagent_chr_write; cc->chr_set_fe_open = vdagent_chr_set_fe_open; cc->chr_accept_input = vdagent_chr_accept_input; + + object_class_property_add_bool(oc, "x-migration-blocked", + get_migration_blocked, + set_migration_blocked); } static int post_load(void *opaque, int version_id) @@ -1064,10 +1093,26 @@ vmstate_register_any(NULL, &vmstate_vdagent, vd); } +static void vdagent_post_init(Object *obj) +{ + VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(obj); + + object_apply_compat_props(obj); + + if (vd->migration_blocked) { + error_setg(&vd->migration_blocker, + "The vdagent chardev doesn't support migration with machine" + " version less than 10.1"); + } +} + static void vdagent_chr_fini(Object *obj) { VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(obj); + if (vd->migration_blocked) { + migrate_del_blocker(&vd->migration_blocker); + } vdagent_disconnect(vd); if (vd->mouse_hs) { qemu_input_handler_unregister(vd->mouse_hs); @@ -1080,6 +1125,7 @@ .parent = TYPE_CHARDEV, .instance_size = sizeof(VDAgentChardev), .instance_init = vdagent_chr_instance_init, + .instance_post_init = vdagent_post_init, .instance_finalize = vdagent_chr_fini, .class_init = vdagent_chr_class_init, };