From: "Rémi Bernon" Subject: [PATCH v4 5/5] winegstreamer: Use an atomic queue for wg_transform input buffers. Message-Id: Date: Thu, 30 Jun 2022 08:04:30 +0000 In-Reply-To: References: From: Rémi Bernon And push them one by one until an output buffer is generated, to avoid generating multiple output buffers without a backing wg_sample. This makes zero-copy more efficient for games which queue multiple input buffers before checking output, such as Yakuza 4. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 Signed-off-by: Rémi Bernon --- dlls/winegstreamer/wg_transform.c | 55 +++++++++++++++---------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 73c3c6d42b0..3ddeaeb44b3 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -51,10 +51,10 @@ struct wg_transform GstPad *my_src, *my_sink; GstPad *their_sink, *their_src; GstSegment segment; - GstBufferList *input; guint input_max_length; guint output_plane_align; struct wg_sample *output_wg_sample; + GstAtomicQueue *input_queue; GstAtomicQueue *output_queue; GstSample *output_sample; bool output_caps_changed; @@ -215,9 +215,11 @@ NTSTATUS wg_transform_destroy(void *args) { struct wg_transform *transform = args; GstSample *sample; + GstBuffer *buffer; - if (transform->input) - gst_buffer_list_unref(transform->input); + while ((buffer = gst_atomic_queue_pop(transform->input_queue))) + gst_buffer_unref(buffer); + gst_atomic_queue_unref(transform->input_queue); gst_element_set_state(transform->container, GST_STATE_NULL); @@ -327,7 +329,7 @@ NTSTATUS wg_transform_create(void *args) return STATUS_NO_MEMORY; if (!(transform->container = gst_bin_new("wg_transform"))) goto out; - if (!(transform->input = gst_buffer_list_new())) + if (!(transform->input_queue = gst_atomic_queue_new(8))) goto out; if (!(transform->output_queue = gst_atomic_queue_new(8))) goto out; @@ -494,8 +496,8 @@ out: wg_allocator_destroy(transform->allocator); if (transform->output_queue) gst_atomic_queue_unref(transform->output_queue); - if (transform->input) - gst_buffer_list_unref(transform->input); + if (transform->input_queue) + gst_atomic_queue_unref(transform->input_queue); if (transform->container) { gst_element_set_state(transform->container, GST_STATE_NULL); @@ -521,7 +523,7 @@ NTSTATUS wg_transform_push_data(void *args) GstBuffer *buffer; guint length; - length = gst_buffer_list_length(transform->input); + length = gst_atomic_queue_length(transform->input_queue); if (length >= transform->input_max_length) { GST_INFO("Refusing %u bytes, %u buffers already queued", sample->size, length); @@ -547,7 +549,7 @@ NTSTATUS wg_transform_push_data(void *args) GST_BUFFER_DURATION(buffer) = sample->duration * 100; if (!(sample->flags & WG_SAMPLE_FLAG_SYNC_POINT)) GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT); - gst_buffer_list_insert(transform->input, -1, buffer); + gst_atomic_queue_push(transform->input_queue, buffer); params->result = S_OK; return STATUS_SUCCESS; @@ -702,9 +704,7 @@ NTSTATUS wg_transform_read_data(void *args) struct wg_transform *transform = params->transform; struct wg_sample *sample = params->sample; struct wg_format *format = params->format; - GstFlowReturn ret = GST_FLOW_OK; GstBuffer *output_buffer; - GstBufferList *input; GstCaps *output_caps; bool discard_data; NTSTATUS status; @@ -712,30 +712,29 @@ NTSTATUS wg_transform_read_data(void *args) /* Provide the sample for transform_request_sample to pick it up */ wg_allocator_set_next_sample(transform->allocator, sample); - if (!gst_buffer_list_length(transform->input)) - GST_DEBUG("Not input buffer queued"); - else if ((input = gst_buffer_list_new())) - { - ret = gst_pad_push_list(transform->my_src, transform->input); - transform->input = input; - } - else + while (!transform->output_sample) { - GST_ERROR("Failed to allocate new input queue"); - ret = GST_FLOW_ERROR; + GstFlowReturn ret = GST_FLOW_OK; + GstBuffer *input_buffer; + + if ((input_buffer = gst_atomic_queue_pop(transform->input_queue)) + && (ret = gst_pad_push(transform->my_src, input_buffer))) + { + GST_ERROR("Failed to push transform input, error %d", ret); + wg_allocator_set_next_sample(transform->allocator, NULL); + wg_allocator_release_sample(transform->allocator, sample, false); + return STATUS_UNSUCCESSFUL; + } + + transform->output_sample = gst_atomic_queue_pop(transform->output_queue); + if (!input_buffer) + break; } /* Remove the sample so transform_request_sample cannot use it */ wg_allocator_set_next_sample(transform->allocator, NULL); - if (ret) - { - GST_ERROR("Failed to push transform input, error %d", ret); - wg_allocator_release_sample(transform->allocator, sample, false); - return STATUS_UNSUCCESSFUL; - } - - if (!transform->output_sample && !(transform->output_sample = gst_atomic_queue_pop(transform->output_queue))) + if (!transform->output_sample) { sample->size = 0; params->result = MF_E_TRANSFORM_NEED_MORE_INPUT; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/302