Wine-devel
Threads by month
- ----- 2026 -----
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
March 2022
- 80 participants
- 950 discussions
16 Mar '22
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/user32/message.c | 35 +----------------------------------
dlls/user32/user32.spec | 2 +-
dlls/win32u/message.c | 32 ++++++++++++++++++++++++++++++++
dlls/win32u/syscall.c | 1 +
dlls/win32u/win32u.spec | 2 +-
dlls/wow64win/syscall.h | 1 +
dlls/wow64win/user.c | 11 +++++++++++
include/ntuser.h | 1 +
8 files changed, 49 insertions(+), 36 deletions(-)
3
2
[PATCH 3/7] win32u: Move __wine_set_pixel_format implementation from user32.
by Jacek Caban 16 Mar '22
by Jacek Caban 16 Mar '22
16 Mar '22
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/user32/win.c | 39 +--------------------------------------
dlls/win32u/window.c | 18 ++++++++++++++++++
include/ntuser.h | 1 +
3 files changed, 20 insertions(+), 38 deletions(-)
2
1
16 Mar '22
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/user32/driver.c | 7 +-
dlls/user32/message.c | 2 -
dlls/user32/user32.spec | 2 +-
dlls/user32/win.c | 307 +--------------------------------
dlls/user32/win.h | 1 -
dlls/win32u/class.c | 11 ++
dlls/win32u/gdiobj.c | 3 +
dlls/win32u/message.c | 2 +
dlls/win32u/ntuser_private.h | 1 +
dlls/win32u/win32u.spec | 6 +-
dlls/win32u/win32u_private.h | 5 +
dlls/win32u/window.c | 317 +++++++++++++++++++++++++++++++++++
dlls/win32u/wrappers.c | 18 ++
include/ntuser.h | 3 +
14 files changed, 369 insertions(+), 316 deletions(-)
2
1
16 Mar '22
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/user32/message.c | 3 --
dlls/user32/win.c | 49 +++---------------------------
dlls/win32u/driver.c | 1 +
dlls/win32u/message.c | 3 ++
dlls/win32u/win32u_private.h | 1 +
dlls/win32u/window.c | 59 ++++++++++++++++++++++++++++++++++++
include/ntuser.h | 1 +
7 files changed, 69 insertions(+), 48 deletions(-)
2
1
[PATCH vkd3d 1/2] tests: Acknowledge buggy UAV clearing on NVIDIA.
by Giovanni Mascellani 16 Mar '22
by Giovanni Mascellani 16 Mar '22
16 Mar '22
The buggy test in test_clear_unordered_access_view_buffer() fails with
this log line:
d3d12:5036:Test 22: Test failed: Got 0xffff7fff, expected 0xffff8000 at (0, 0, 0).
It seems that NVIDIA drivers convert float 0.5 to unorm 0x7fff instead of
0x8000 when writing to the UAV.
Something similar happens for the test in
test_clear_unordered_access_view_image().
Signed-off-by: Giovanni Mascellani <gmascellani(a)codeweavers.com>
---
Actually, I am not completely sure of what's happening here (and therefore
the commit message might be wrong). My understanding is that in that test
the shader cs_uav_clear_buffer_float_code is used, where the buffer is declared
as "RWBuffer<float4> dst", while the underlying UAV is declared of format
DXGI_FORMAT_R16G16_UNORM. I suppose that is interpreted by D3D12 as a
conversion from float to a normalized uint16, and therefore the value 0.5
is converted to something in the middle of the range of uint16.
Whether 0x7fff or 0x8000 should be taken thus depends on the subtlety of
how the range of uint16 is defined. Should it be half of 0x10000 or of
0xffff? It seems that Linux Vulkan NVIDIA drivers choose the second
interpretation. Could somebody help me understanding if Vulkan specifications
mandate which of the two behavior should be considered correct?
---
tests/d3d12.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/tests/d3d12.c b/tests/d3d12.c
index 5067dd97..d32e4cba 100644
--- a/tests/d3d12.c
+++ b/tests/d3d12.c
@@ -4878,6 +4878,7 @@ static void test_clear_unordered_access_view_buffer(void)
unsigned int expected;
bool is_float;
bool is_todo;
+ bool bug_on_nvidia;
}
tests[] =
{
@@ -4930,7 +4931,7 @@ static void test_clear_unordered_access_view_buffer(void)
{DXGI_FORMAT_R16G16_UNORM, { 0, BUFFER_SIZE / sizeof(uint32_t), 0, 0, D3D12_BUFFER_UAV_FLAG_NONE},
{0x1234, 0xabcd, 0, 0}, 0xabcd1234},
{DXGI_FORMAT_R16G16_UNORM, { 0, BUFFER_SIZE / sizeof(uint32_t), 0, 0, D3D12_BUFFER_UAV_FLAG_NONE},
- {0x3f000000 /* 0.5f */, 0x3f800000 /* 1.0f */, 0, 0}, 0xffff8000, true},
+ {0x3f000000 /* 0.5f */, 0x3f800000 /* 1.0f */, 0, 0}, 0xffff8000, true, false, true},
{DXGI_FORMAT_R16G16_UNORM, { 0, BUFFER_SIZE / sizeof(uint32_t), 0, 0, D3D12_BUFFER_UAV_FLAG_NONE},
{0x40000000 /* 2.0f */, 0 /* 0.0f */, 0, 0}, 0x0000ffff, true},
{DXGI_FORMAT_R16G16_UNORM, { 0, BUFFER_SIZE / sizeof(uint32_t), 0, 0, D3D12_BUFFER_UAV_FLAG_NONE},
@@ -5032,6 +5033,7 @@ static void test_clear_unordered_access_view_buffer(void)
check_readback_data_uint(&rb, &box, clear_value[0], 0);
box.left = uav_desc.Buffer.FirstElement;
box.right = uav_desc.Buffer.FirstElement + uav_desc.Buffer.NumElements;
+ bug_if(tests[i].bug_on_nvidia && is_nvidia_device(device))
todo_if(tests[i].is_todo)
check_readback_data_uint(&rb, &box, tests[i].expected, tests[i].is_float ? 1 : 0);
box.left = uav_desc.Buffer.FirstElement + uav_desc.Buffer.NumElements;
@@ -5086,6 +5088,7 @@ static void test_clear_unordered_access_view_image(void)
unsigned int expected;
bool is_float;
bool is_todo;
+ bool bug_on_nvidia;
}
tests[] =
{
@@ -5124,7 +5127,7 @@ static void test_clear_unordered_access_view_image(void)
{DXGI_FORMAT_R11G11B10_FLOAT, 1, 1, 0, 0, 1, 0, {}, {1, 2, 3, 4}, 0x00c01001},
/* Test float clears with formats. */
{DXGI_FORMAT_R16G16_UNORM, 1, 1, 0, 0, 1, 0, {},
- {0x3f000000 /* 0.5f */, 0x3f800000 /* 1.0f */, 0, 0}, 0xffff8000, true},
+ {0x3f000000 /* 0.5f */, 0x3f800000 /* 1.0f */, 0, 0}, 0xffff8000, true, false, true},
{DXGI_FORMAT_R16G16_FLOAT, 1, 1, 0, 0, 1, 0, {},
{0x3f000000 /* 0.5f */, 0x3f800000 /* 1.0f */, 0, 0}, 0x3c003800, true},
{DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, 0, 0, 1, 0, {},
@@ -5308,6 +5311,7 @@ static void test_clear_unordered_access_view_image(void)
actual_colour = get_readback_uint(&rb, x, y, z);
success = compare_color(actual_colour, expected_colour, tests[i].is_float ? 1 : 0);
+ bug_if(tests[i].bug_on_nvidia && is_nvidia_device(device))
todo_if(tests[i].is_todo && expected_colour)
ok(success, "At layer %u, (%u,%u,%u), expected %#x, got %#x.\n",
layer, x, y, z, expected_colour, actual_colour);
--
2.35.1
1
1
[PATCH vkd3d v2 1/2] vkd3d: Use Vulkan timeline semaphores for D3D12 fences.
by Conor McCarthy 16 Mar '22
by Conor McCarthy 16 Mar '22
16 Mar '22
D3D12 supports signalling a fence to a lower value, while Vulkan timeline
semaphores do not. On the GPU side this is handled by simply submitting
the signal anyway, because working around this is impractical and it
currently works. For CPU signals the Vulkan semaphore is replaced with a
new one at the lower value only if no waits and/or signals are pending on
the GPU. Otherwise, a fixme is emitted.
Partly based on a vkd3d-proton patch by Hans-Kristian Arntzen (not
including the handling of lower fence values).
The old implementation is used if KHR_timeline_semaphore is not
available.
Signed-off-by: Conor McCarthy <cmccarthy(a)codeweavers.com>
---
libs/vkd3d/command.c | 562 ++++++++++++++++++++++++++++++++++---
libs/vkd3d/device.c | 14 +
libs/vkd3d/vkd3d_private.h | 25 ++
libs/vkd3d/vulkan_procs.h | 5 +
tests/d3d12.c | 11 +-
5 files changed, 576 insertions(+), 41 deletions(-)
diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c
index e7375fb8..cef6d022 100644
--- a/libs/vkd3d/command.c
+++ b/libs/vkd3d/command.c
@@ -22,11 +22,31 @@
static HRESULT d3d12_fence_signal(struct d3d12_fence *fence, uint64_t value, VkFence vk_fence);
+static VkResult vkd3d_create_timeline_semaphore(const struct d3d12_device *device, uint64_t initial_value,
+ VkSemaphore *timeline_semaphore)
+{
+ const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+ VkSemaphoreTypeCreateInfoKHR type_info;
+ VkSemaphoreCreateInfo info;
+
+ info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+ info.pNext = &type_info;
+ info.flags = 0;
+
+ type_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR;
+ type_info.pNext = NULL;
+ type_info.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE_KHR;
+ type_info.initialValue = initial_value;
+
+ return VK_CALL(vkCreateSemaphore(device->vk_device, &info, NULL, timeline_semaphore));
+}
+
HRESULT vkd3d_queue_create(struct d3d12_device *device,
uint32_t family_index, const VkQueueFamilyProperties *properties, struct vkd3d_queue **queue)
{
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
struct vkd3d_queue *object;
+ VkResult vr;
int rc;
if (!(object = vkd3d_malloc(sizeof(*object))))
@@ -46,6 +66,15 @@ HRESULT vkd3d_queue_create(struct d3d12_device *device,
object->vk_queue_flags = properties->queueFlags;
object->timestamp_bits = properties->timestampValidBits;
+ object->wait_completion_semaphore = VK_NULL_HANDLE;
+ object->pending_wait_completion_value = 0;
+ if (device->vk_info.KHR_timeline_semaphore && (vr = vkd3d_create_timeline_semaphore(device, 0,
+ &object->wait_completion_semaphore)) < 0)
+ {
+ WARN("Failed to create timeline semaphore, vr %d.\n", vr);
+ return hresult_from_vk_result(vr);
+ }
+
object->semaphores = NULL;
object->semaphores_size = 0;
object->semaphore_count = 0;
@@ -75,6 +104,8 @@ void vkd3d_queue_destroy(struct vkd3d_queue *queue, struct d3d12_device *device)
vkd3d_free(queue->semaphores);
+ VK_CALL(vkDestroySemaphore(device->vk_device, queue->wait_completion_semaphore, NULL));
+
for (i = 0; i < ARRAY_SIZE(queue->old_vk_semaphores); ++i)
{
if (queue->old_vk_semaphores[i])
@@ -268,6 +299,7 @@ static HRESULT vkd3d_enqueue_gpu_fence(struct vkd3d_fence_worker *worker,
}
worker->enqueued_fences[worker->enqueued_fence_count].vk_fence = vk_fence;
+ worker->enqueued_fences[worker->enqueued_fence_count].vk_semaphore = VK_NULL_HANDLE;
waiting_fence = &worker->enqueued_fences[worker->enqueued_fence_count].waiting_fence;
waiting_fence->fence = fence;
waiting_fence->value = value;
@@ -317,6 +349,7 @@ static void vkd3d_fence_worker_remove_fence(struct vkd3d_fence_worker *worker, s
static void vkd3d_fence_worker_move_enqueued_fences_locked(struct vkd3d_fence_worker *worker)
{
unsigned int i;
+ bool timeline;
size_t count;
bool ret;
@@ -325,8 +358,18 @@ static void vkd3d_fence_worker_move_enqueued_fences_locked(struct vkd3d_fence_wo
count = worker->fence_count + worker->enqueued_fence_count;
- ret = vkd3d_array_reserve((void **)&worker->vk_fences, &worker->vk_fences_size,
- count, sizeof(*worker->vk_fences));
+ if ((timeline = worker->device->vk_info.KHR_timeline_semaphore))
+ {
+ ret = vkd3d_array_reserve((void **) &worker->vk_semaphores, &worker->vk_semaphores_size,
+ count, sizeof(*worker->vk_semaphores));
+ ret &= vkd3d_array_reserve((void **) &worker->semaphore_wait_values, &worker->semaphore_wait_values_size,
+ count, sizeof(*worker->semaphore_wait_values));
+ }
+ else
+ {
+ ret = vkd3d_array_reserve((void **)&worker->vk_fences, &worker->vk_fences_size,
+ count, sizeof(*worker->vk_fences));
+ }
ret &= vkd3d_array_reserve((void **)&worker->fences, &worker->fences_size,
count, sizeof(*worker->fences));
if (!ret)
@@ -339,7 +382,16 @@ static void vkd3d_fence_worker_move_enqueued_fences_locked(struct vkd3d_fence_wo
{
struct vkd3d_enqueued_fence *current = &worker->enqueued_fences[i];
- worker->vk_fences[worker->fence_count] = current->vk_fence;
+ if (timeline)
+ {
+ worker->vk_semaphores[worker->fence_count] = current->vk_semaphore;
+ worker->semaphore_wait_values[worker->fence_count] = current->waiting_fence.value;
+ }
+ else
+ {
+ worker->vk_fences[worker->fence_count] = current->vk_fence;
+ }
+
worker->fences[worker->fence_count] = current->waiting_fence;
++worker->fence_count;
}
@@ -347,6 +399,66 @@ static void vkd3d_fence_worker_move_enqueued_fences_locked(struct vkd3d_fence_wo
worker->enqueued_fence_count = 0;
}
+static void vkd3d_wait_for_gpu_timeline_semaphores(struct vkd3d_fence_worker *worker)
+{
+ const struct d3d12_device *device = worker->device;
+ const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+ VkSemaphoreWaitInfoKHR wait_info;
+ VkSemaphore vk_semaphore;
+ uint64_t counter_value;
+ unsigned int i, j;
+ HRESULT hr;
+ int vr;
+
+ if (!worker->fence_count)
+ return;
+
+ wait_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO_KHR;
+ wait_info.pNext = NULL;
+ wait_info.flags = VK_SEMAPHORE_WAIT_ANY_BIT_KHR;
+ wait_info.pSemaphores = worker->vk_semaphores;
+ wait_info.semaphoreCount = worker->fence_count;
+ wait_info.pValues = worker->semaphore_wait_values;
+
+ vr = VK_CALL(vkWaitSemaphoresKHR(device->vk_device, &wait_info, ~(uint64_t)0));
+ if (vr == VK_TIMEOUT)
+ return;
+ if (vr != VK_SUCCESS)
+ {
+ ERR("Failed to wait for Vulkan timeline semaphores, vr %d.\n", vr);
+ return;
+ }
+
+ for (i = 0, j = 0; i < worker->fence_count; ++i)
+ {
+ struct vkd3d_waiting_fence *current = &worker->fences[i];
+
+ vk_semaphore = worker->vk_semaphores[i];
+ if ((vr = VK_CALL(vkGetSemaphoreCounterValueKHR(device->vk_device, vk_semaphore, &counter_value))) < 0)
+ {
+ ERR("Failed to get Vulkan semaphore value, vr %d.\n", vr);
+ }
+ else if (counter_value >= current->value)
+ {
+ TRACE("Signaling fence %p value %#"PRIx64".\n", current->fence, current->value);
+ if (FAILED(hr = d3d12_fence_signal(current->fence, counter_value, VK_NULL_HANDLE)))
+ ERR("Failed to signal D3D12 fence, hr %#x.\n", hr);
+
+ InterlockedDecrement(¤t->fence->pending_worker_operation_count);
+ continue;
+ }
+
+ if (i != j)
+ {
+ worker->vk_semaphores[j] = worker->vk_semaphores[i];
+ worker->semaphore_wait_values[j] = worker->semaphore_wait_values[i];
+ worker->fences[j] = worker->fences[i];
+ }
+ ++j;
+ }
+ worker->fence_count = j;
+}
+
static void vkd3d_wait_for_gpu_fences(struct vkd3d_fence_worker *worker)
{
struct d3d12_device *device = worker->device;
@@ -408,7 +520,7 @@ static void *vkd3d_fence_worker_main(void *arg)
for (;;)
{
- vkd3d_wait_for_gpu_fences(worker);
+ worker->wait_for_gpu_fences(worker);
if (!worker->fence_count || InterlockedAdd(&worker->enqueued_fence_count, 0))
{
@@ -473,6 +585,13 @@ HRESULT vkd3d_fence_worker_start(struct vkd3d_fence_worker *worker,
worker->vk_fences_size = 0;
worker->fences = NULL;
worker->fences_size = 0;
+ worker->vk_semaphores = NULL;
+ worker->vk_semaphores_size = 0;
+ worker->semaphore_wait_values = NULL;
+ worker->semaphore_wait_values_size = 0;
+
+ worker->wait_for_gpu_fences = device->vk_info.KHR_timeline_semaphore
+ ? vkd3d_wait_for_gpu_timeline_semaphores : vkd3d_wait_for_gpu_fences;
if ((rc = vkd3d_mutex_init(&worker->mutex)))
{
@@ -535,6 +654,8 @@ HRESULT vkd3d_fence_worker_stop(struct vkd3d_fence_worker *worker,
vkd3d_free(worker->enqueued_fences);
vkd3d_free(worker->vk_fences);
vkd3d_free(worker->fences);
+ vkd3d_free(worker->vk_semaphores);
+ vkd3d_free(worker->semaphore_wait_values);
return S_OK;
}
@@ -684,6 +805,7 @@ static void d3d12_fence_destroy_vk_objects(struct d3d12_fence *fence)
}
d3d12_fence_garbage_collect_vk_semaphores_locked(fence, true);
+ VK_CALL(vkDestroySemaphore(device->vk_device, fence->timeline_semaphore, NULL));
vkd3d_mutex_unlock(&fence->mutex);
}
@@ -802,31 +924,21 @@ static HRESULT d3d12_fence_add_vk_semaphore(struct d3d12_fence *fence,
return hr;
}
-static HRESULT d3d12_fence_signal(struct d3d12_fence *fence, uint64_t value, VkFence vk_fence)
+static bool d3d12_fence_signal_external_events_locked(struct d3d12_fence *fence)
{
struct d3d12_device *device = fence->device;
- struct vkd3d_signaled_semaphore *current;
bool signal_null_event_cond = false;
unsigned int i, j;
- int rc;
-
- if ((rc = vkd3d_mutex_lock(&fence->mutex)))
- {
- ERR("Failed to lock mutex, error %d.\n", rc);
- return hresult_from_errno(rc);
- }
-
- fence->value = value;
for (i = 0, j = 0; i < fence->event_count; ++i)
{
struct vkd3d_waiting_event *current = &fence->events[i];
- if (current->value <= value)
+ if (current->value <= fence->value)
{
if (current->event)
{
- fence->device->signal_event(current->event);
+ device->signal_event(current->event);
}
else
{
@@ -841,9 +953,28 @@ static HRESULT d3d12_fence_signal(struct d3d12_fence *fence, uint64_t value, VkF
++j;
}
}
+
fence->event_count = j;
- if (signal_null_event_cond)
+ return signal_null_event_cond;
+}
+
+static HRESULT d3d12_fence_signal(struct d3d12_fence *fence, uint64_t value, VkFence vk_fence)
+{
+ struct d3d12_device *device = fence->device;
+ struct vkd3d_signaled_semaphore *current;
+ unsigned int i;
+ int rc;
+
+ if ((rc = vkd3d_mutex_lock(&fence->mutex)))
+ {
+ ERR("Failed to lock mutex, error %d.\n", rc);
+ return hresult_from_errno(rc);
+ }
+
+ fence->value = value;
+
+ if (d3d12_fence_signal_external_events_locked(fence))
vkd3d_cond_broadcast(&fence->null_event_cond);
if (vk_fence)
@@ -1069,12 +1200,158 @@ static HRESULT STDMETHODCALLTYPE d3d12_fence_SetEventOnCompletion(ID3D12Fence *i
return S_OK;
}
+static inline bool d3d12_fence_gpu_wait_is_completed(const struct d3d12_fence *fence, unsigned int i)
+{
+ const struct d3d12_device *device = fence->device;
+ const struct vkd3d_vk_device_procs *vk_procs;
+ uint64_t value;
+ VkResult vr;
+
+ vk_procs = &device->vk_procs;
+
+ if ((vr = VK_CALL(vkGetSemaphoreCounterValueKHR(device->vk_device,
+ fence->gpu_waits[i].queue->wait_completion_semaphore, &value))) >= 0)
+ {
+ return value >= fence->gpu_waits[i].pending_value;
+ }
+
+ ERR("Failed to get Vulkan semaphore status, vr %d.\n", vr);
+ return true;
+}
+
+static inline bool d3d12_fence_has_pending_gpu_ops_locked(struct d3d12_fence *fence)
+{
+ const struct d3d12_device *device = fence->device;
+ const struct vkd3d_vk_device_procs *vk_procs;
+ uint64_t value;
+ unsigned int i;
+ VkResult vr;
+
+ for (i = 0; i < fence->gpu_wait_count; ++i)
+ {
+ if (d3d12_fence_gpu_wait_is_completed(fence, i) && i < --fence->gpu_wait_count)
+ fence->gpu_waits[i] = fence->gpu_waits[fence->gpu_wait_count];
+ }
+ if (fence->gpu_wait_count)
+ return true;
+
+ /* Check for pending signals too. */
+ if (fence->value >= fence->pending_timeline_value)
+ return false;
+
+ vk_procs = &device->vk_procs;
+
+ /* Check the actual semaphore value in case fence->value update is lagging. */
+ if ((vr = VK_CALL(vkGetSemaphoreCounterValueKHR(device->vk_device, fence->timeline_semaphore, &value))) < 0)
+ {
+ ERR("Failed to get Vulkan semaphore status, vr %d.\n", vr);
+ return false;
+ }
+
+ return value < fence->pending_timeline_value;
+}
+
+/* Replace the VkSemaphore with a new one to allow a lower value to be set. Ideally apps will
+ * only use this to reset the fence when no operations are pending on the queue. */
+static VkResult d3d12_fence_reinit_timeline_semaphore_locked(struct d3d12_fence *fence, uint64_t value)
+{
+ const struct d3d12_device *device = fence->device;
+ const struct vkd3d_vk_device_procs *vk_procs;
+ VkSemaphore timeline_semaphore;
+ VkResult vr;
+
+ if (d3d12_fence_has_pending_gpu_ops_locked(fence))
+ {
+ /* This situation is not very likely because it means a fence with pending waits and/or signals was
+ * signalled on the CPU to a lower value. For now, emit a fixme so it can be patched if necessary.
+ * A patch already exists for this but it's not pretty. */
+ FIXME("Unable to re-initialise timeline semaphore to a lower value due to pending GPU ops.\n");
+ return VK_ERROR_UNKNOWN;
+ }
+
+ if ((vr = vkd3d_create_timeline_semaphore(device, value, &timeline_semaphore)) < 0)
+ {
+ WARN("Failed to create timeline semaphore, vr %d.\n", vr);
+ return vr;
+ }
+
+ fence->value = value;
+ fence->pending_timeline_value = value;
+
+ WARN("Replacing timeline semaphore with a new object.\n");
+
+ vk_procs = &device->vk_procs;
+
+ VK_CALL(vkDestroySemaphore(device->vk_device, fence->timeline_semaphore, NULL));
+ fence->timeline_semaphore = timeline_semaphore;
+
+ return VK_SUCCESS;
+}
+
+static HRESULT d3d12_fence_signal_cpu_timeline_semaphore(struct d3d12_fence *fence, uint64_t value)
+{
+ const struct d3d12_device *device = fence->device;
+ VkSemaphoreSignalInfoKHR info;
+ VkResult vr = VK_SUCCESS;
+ int rc;
+
+ if ((rc = vkd3d_mutex_lock(&fence->mutex)))
+ {
+ ERR("Failed to lock mutex, error %d.\n", rc);
+ return hresult_from_errno(rc);
+ }
+
+ /* We must only signal a value which is greater than the current value.
+ * That value can be in the range of current known value (fence->value), or as large as pending_timeline_value.
+ * Pending timeline value signal might be blocked by another synchronization primitive, and thus statically
+ * cannot be that value, so the safest thing to do is to check the current value which is updated by the fence
+ * wait thread continuously. This check is technically racy since the value might be immediately out of date,
+ * but there is no way to avoid this. */
+ if (value > fence->value)
+ {
+ const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
+
+ /* Sanity check against the delta limit. */
+ if (value - fence->value > device->vk_info.timeline_semaphore_properties.maxTimelineSemaphoreValueDifference)
+ {
+ FIXME("Timeline semaphore delta is %"PRIu64", but implementation only supports a delta of %"PRIu64".\n",
+ value - fence->value, device->vk_info.timeline_semaphore_properties.maxTimelineSemaphoreValueDifference);
+ }
+
+ info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO_KHR;
+ info.pNext = NULL;
+ info.semaphore = fence->timeline_semaphore;
+ info.value = value;
+ if ((vr = VK_CALL(vkSignalSemaphoreKHR(device->vk_device, &info))) >= 0)
+ {
+ fence->value = value;
+ if (value > fence->pending_timeline_value)
+ fence->pending_timeline_value = value;
+ }
+ else
+ {
+ ERR("Failed to signal timeline semaphore, vr %d.\n", vr);
+ }
+ }
+ else if (value < fence->value)
+ {
+ vr = d3d12_fence_reinit_timeline_semaphore_locked(fence, value);
+ }
+
+ d3d12_fence_signal_external_events_locked(fence);
+
+ vkd3d_mutex_unlock(&fence->mutex);
+ return hresult_from_vk_result(vr);
+}
+
static HRESULT STDMETHODCALLTYPE d3d12_fence_Signal(ID3D12Fence *iface, UINT64 value)
{
struct d3d12_fence *fence = impl_from_ID3D12Fence(iface);
TRACE("iface %p, value %#"PRIx64".\n", iface, value);
+ if (fence->timeline_semaphore)
+ return d3d12_fence_signal_cpu_timeline_semaphore(fence, value);
return d3d12_fence_signal(fence, value, VK_NULL_HANDLE);
}
@@ -1108,6 +1385,7 @@ static struct d3d12_fence *unsafe_impl_from_ID3D12Fence(ID3D12Fence *iface)
static HRESULT d3d12_fence_init(struct d3d12_fence *fence, struct d3d12_device *device,
UINT64 initial_value, D3D12_FENCE_FLAGS flags)
{
+ VkResult vr;
HRESULT hr;
int rc;
@@ -1136,6 +1414,16 @@ static HRESULT d3d12_fence_init(struct d3d12_fence *fence, struct d3d12_device *
fence->events_size = 0;
fence->event_count = 0;
+ fence->timeline_semaphore = VK_NULL_HANDLE;
+ if (device->vk_info.KHR_timeline_semaphore && (vr = vkd3d_create_timeline_semaphore(device, initial_value,
+ &fence->timeline_semaphore)) < 0)
+ {
+ WARN("Failed to create timeline semaphore, vr %d.\n", vr);
+ return hresult_from_vk_result(vr);
+ }
+ fence->pending_timeline_value = initial_value;
+ fence->gpu_wait_count = 0;
+
list_init(&fence->semaphores);
fence->semaphore_count = 0;
@@ -5991,18 +6279,88 @@ static void STDMETHODCALLTYPE d3d12_command_queue_EndEvent(ID3D12CommandQueue *i
FIXME("iface %p stub!\n", iface);
}
+static HRESULT d3d12_fence_update_gpu_signal_timeline_semaphore(struct d3d12_fence *fence, uint64_t value)
+{
+ const struct d3d12_device *device = fence->device;
+ int rc;
+
+ if ((rc = vkd3d_mutex_lock(&fence->mutex)))
+ {
+ ERR("Failed to lock mutex, error %d.\n", rc);
+ return hresult_from_errno(rc);
+ }
+
+ /* If we're attempting to async signal a fence with a value which is not monotonically increasing the payload value,
+ * warn about this case. Do not treat this as an error since it works at least with RADV and Nvidia drivers and
+ * there's no workaround on the GPU side. */
+ if (value <= fence->pending_timeline_value)
+ {
+ WARN("Fence %p is being signalled non-monotonically. Old pending value %"PRIu64", new pending value %"PRIu64".\n",
+ fence, fence->pending_timeline_value, value);
+ }
+ /* Sanity check against the delta limit. Use the current fence value. */
+ else if (value - fence->value > device->vk_info.timeline_semaphore_properties.maxTimelineSemaphoreValueDifference)
+ {
+ FIXME("Timeline semaphore delta is %"PRIu64", but implementation only supports a delta of %"PRIu64".\n",
+ value - fence->value, device->vk_info.timeline_semaphore_properties.maxTimelineSemaphoreValueDifference);
+ }
+ fence->pending_timeline_value = value;
+
+ vkd3d_mutex_unlock(&fence->mutex);
+
+ return S_OK;
+}
+
+static HRESULT vkd3d_enqueue_timeline_semaphore(struct vkd3d_fence_worker *worker, VkSemaphore vk_semaphore,
+ struct d3d12_fence *fence, uint64_t value, struct vkd3d_queue *queue)
+{
+ struct vkd3d_waiting_fence *waiting_fence;
+ int rc;
+
+ TRACE("worker %p, fence %p, value %#"PRIx64".\n", worker, fence, value);
+
+ if ((rc = vkd3d_mutex_lock(&worker->mutex)))
+ {
+ ERR("Failed to lock mutex, error %d.\n", rc);
+ return hresult_from_errno(rc);
+ }
+
+ if (!vkd3d_array_reserve((void **)&worker->enqueued_fences, &worker->enqueued_fences_size,
+ worker->enqueued_fence_count + 1, sizeof(*worker->enqueued_fences)))
+ {
+ ERR("Failed to add GPU timeline semaphore.\n");
+ vkd3d_mutex_unlock(&worker->mutex);
+ return E_OUTOFMEMORY;
+ }
+
+ worker->enqueued_fences[worker->enqueued_fence_count].vk_semaphore = vk_semaphore;
+ waiting_fence = &worker->enqueued_fences[worker->enqueued_fence_count].waiting_fence;
+ waiting_fence->fence = fence;
+ waiting_fence->value = value;
+ waiting_fence->queue = queue;
+ ++worker->enqueued_fence_count;
+
+ InterlockedIncrement(&fence->pending_worker_operation_count);
+
+ vkd3d_cond_signal(&worker->cond);
+ vkd3d_mutex_unlock(&worker->mutex);
+
+ return S_OK;
+}
+
static HRESULT STDMETHODCALLTYPE d3d12_command_queue_Signal(ID3D12CommandQueue *iface,
ID3D12Fence *fence_iface, UINT64 value)
{
struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface);
+ VkTimelineSemaphoreSubmitInfoKHR timeline_submit_info;
const struct vkd3d_vk_device_procs *vk_procs;
VkSemaphore vk_semaphore = VK_NULL_HANDLE;
VkFence vk_fence = VK_NULL_HANDLE;
struct vkd3d_queue *vkd3d_queue;
+ uint64_t sequence_number = 0;
struct d3d12_device *device;
struct d3d12_fence *fence;
VkSubmitInfo submit_info;
- uint64_t sequence_number;
VkQueue vk_queue;
VkResult vr;
HRESULT hr;
@@ -6015,10 +6373,21 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_queue_Signal(ID3D12CommandQueue *
fence = unsafe_impl_from_ID3D12Fence(fence_iface);
- if ((vr = d3d12_fence_create_vk_fence(fence, &vk_fence)) < 0)
+ if (device->vk_info.KHR_timeline_semaphore)
{
- WARN("Failed to create Vulkan fence, vr %d.\n", vr);
- goto fail_vkresult;
+ if (FAILED(hr = d3d12_fence_update_gpu_signal_timeline_semaphore(fence, value)))
+ return hr;
+
+ vk_semaphore = fence->timeline_semaphore;
+ assert(vk_semaphore);
+ }
+ else
+ {
+ if ((vr = d3d12_fence_create_vk_fence(fence, &vk_fence)) < 0)
+ {
+ WARN("Failed to create Vulkan fence, vr %d.\n", vr);
+ goto fail_vkresult;
+ }
}
if (!(vk_queue = vkd3d_queue_acquire(vkd3d_queue)))
@@ -6028,7 +6397,8 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_queue_Signal(ID3D12CommandQueue *
goto fail;
}
- if ((vr = vkd3d_queue_create_vk_semaphore_locked(vkd3d_queue, device, &vk_semaphore)) < 0)
+ if (!device->vk_info.KHR_timeline_semaphore && (vr = vkd3d_queue_create_vk_semaphore_locked(vkd3d_queue,
+ device, &vk_semaphore)) < 0)
{
ERR("Failed to create Vulkan semaphore, vr %d.\n", vr);
vk_semaphore = VK_NULL_HANDLE;
@@ -6044,7 +6414,19 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_queue_Signal(ID3D12CommandQueue *
submit_info.signalSemaphoreCount = vk_semaphore ? 1 : 0;
submit_info.pSignalSemaphores = &vk_semaphore;
- if ((vr = VK_CALL(vkQueueSubmit(vk_queue, 1, &submit_info, vk_fence))) >= 0)
+ if (device->vk_info.KHR_timeline_semaphore)
+ {
+ timeline_submit_info.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR;
+ timeline_submit_info.pNext = NULL;
+ timeline_submit_info.pSignalSemaphoreValues = &value;
+ timeline_submit_info.signalSemaphoreValueCount = submit_info.signalSemaphoreCount;
+ timeline_submit_info.waitSemaphoreValueCount = 0;
+ timeline_submit_info.pWaitSemaphoreValues = NULL;
+ submit_info.pNext = &timeline_submit_info;
+ }
+
+ vr = VK_CALL(vkQueueSubmit(vk_queue, 1, &submit_info, vk_fence));
+ if (!device->vk_info.KHR_timeline_semaphore && vr >= 0)
{
sequence_number = ++vkd3d_queue->submitted_sequence_number;
@@ -6061,6 +6443,9 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_queue_Signal(ID3D12CommandQueue *
goto fail_vkresult;
}
+ if (device->vk_info.KHR_timeline_semaphore)
+ return vkd3d_enqueue_timeline_semaphore(&device->fence_worker, vk_semaphore, fence, value, vkd3d_queue);
+
if (vk_semaphore && SUCCEEDED(hr = d3d12_fence_add_vk_semaphore(fence, vk_semaphore, vk_fence, value)))
vk_semaphore = VK_NULL_HANDLE;
@@ -6096,32 +6481,27 @@ fail_vkresult:
hr = hresult_from_vk_result(vr);
fail:
VK_CALL(vkDestroyFence(device->vk_device, vk_fence, NULL));
- VK_CALL(vkDestroySemaphore(device->vk_device, vk_semaphore, NULL));
+ if (!device->vk_info.KHR_timeline_semaphore)
+ VK_CALL(vkDestroySemaphore(device->vk_device, vk_semaphore, NULL));
return hr;
}
-static HRESULT STDMETHODCALLTYPE d3d12_command_queue_Wait(ID3D12CommandQueue *iface,
- ID3D12Fence *fence_iface, UINT64 value)
+static HRESULT d3d12_command_queue_wait_binary_semaphore(struct d3d12_command_queue *command_queue,
+ struct d3d12_fence *fence, uint64_t value)
{
static const VkPipelineStageFlagBits wait_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
- struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface);
const struct vkd3d_vk_device_procs *vk_procs;
struct vkd3d_signaled_semaphore *semaphore;
uint64_t completed_value = 0;
struct vkd3d_queue *queue;
- struct d3d12_fence *fence;
VkSubmitInfo submit_info;
VkQueue vk_queue;
VkResult vr;
HRESULT hr;
- TRACE("iface %p, fence %p, value %#"PRIx64".\n", iface, fence_iface, value);
-
vk_procs = &command_queue->device->vk_procs;
queue = command_queue->vkd3d_queue;
- fence = unsafe_impl_from_ID3D12Fence(fence_iface);
-
semaphore = d3d12_fence_acquire_vk_semaphore(fence, value, &completed_value);
if (!semaphore && completed_value >= value)
{
@@ -6199,6 +6579,122 @@ fail:
return hr;
}
+static inline void d3d12_fence_update_gpu_wait(struct d3d12_fence *fence, const struct vkd3d_queue *queue)
+{
+ unsigned int i;
+ bool found;
+ int rc;
+
+ if ((rc = vkd3d_mutex_lock(&fence->mutex)))
+ {
+ ERR("Failed to lock mutex, error %d.\n", rc);
+ return;
+ }
+
+ for (i = 0, found = false; i < fence->gpu_wait_count; ++i)
+ {
+ if (fence->gpu_waits[i].queue == queue)
+ {
+ fence->gpu_waits[i].pending_value = queue->pending_wait_completion_value;
+ found = true;
+ }
+ else if (d3d12_fence_gpu_wait_is_completed(fence, i) && i < --fence->gpu_wait_count)
+ {
+ fence->gpu_waits[i] = fence->gpu_waits[fence->gpu_wait_count];
+ }
+ }
+
+ if (!found)
+ {
+ if (fence->gpu_wait_count < ARRAY_SIZE(fence->gpu_waits))
+ {
+ fence->gpu_waits[fence->gpu_wait_count].queue = queue;
+ fence->gpu_waits[fence->gpu_wait_count++].pending_value = queue->pending_wait_completion_value;
+ }
+ else
+ {
+ FIXME("Unable to track GPU fence wait.\n");
+ }
+ }
+
+ vkd3d_mutex_unlock(&fence->mutex);
+}
+
+static HRESULT d3d12_command_queue_wait_timeline_semaphore(struct d3d12_command_queue *command_queue,
+ struct d3d12_fence *fence, uint64_t value)
+{
+ static const VkPipelineStageFlagBits wait_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
+ VkTimelineSemaphoreSubmitInfoKHR timeline_submit_info;
+ const struct vkd3d_vk_device_procs *vk_procs;
+ struct vkd3d_queue *queue;
+ VkSubmitInfo submit_info;
+ VkQueue vk_queue;
+ VkResult vr;
+
+ vk_procs = &command_queue->device->vk_procs;
+ queue = command_queue->vkd3d_queue;
+
+ assert(fence->timeline_semaphore);
+ timeline_submit_info.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR;
+ timeline_submit_info.pNext = NULL;
+ timeline_submit_info.signalSemaphoreValueCount = 0;
+ timeline_submit_info.pSignalSemaphoreValues = NULL;
+ timeline_submit_info.waitSemaphoreValueCount = 1;
+ timeline_submit_info.pWaitSemaphoreValues = &value;
+
+ if (!(vk_queue = vkd3d_queue_acquire(queue)))
+ {
+ ERR("Failed to acquire queue %p.\n", queue);
+ return E_FAIL;
+ }
+
+ submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ submit_info.pNext = &timeline_submit_info;
+ submit_info.waitSemaphoreCount = 1;
+ submit_info.pWaitSemaphores = &fence->timeline_semaphore;
+ submit_info.pWaitDstStageMask = &wait_stage_mask;
+ submit_info.commandBufferCount = 0;
+ submit_info.pCommandBuffers = NULL;
+ submit_info.signalSemaphoreCount = 0;
+ submit_info.pSignalSemaphores = NULL;
+
+ ++queue->pending_wait_completion_value;
+
+ submit_info.signalSemaphoreCount = 1;
+ submit_info.pSignalSemaphores = &queue->wait_completion_semaphore;
+ timeline_submit_info.signalSemaphoreValueCount = 1;
+ timeline_submit_info.pSignalSemaphoreValues = &queue->pending_wait_completion_value;
+
+ d3d12_fence_update_gpu_wait(fence, queue);
+
+ vr = VK_CALL(vkQueueSubmit(vk_queue, 1, &submit_info, VK_NULL_HANDLE));
+
+ vkd3d_queue_release(queue);
+
+ if (vr < 0)
+ {
+ WARN("Failed to submit wait operation, vr %d.\n", vr);
+ return hresult_from_vk_result(vr);
+ }
+
+ return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE d3d12_command_queue_Wait(ID3D12CommandQueue *iface,
+ ID3D12Fence *fence_iface, UINT64 value)
+{
+ struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface);
+ struct d3d12_fence *fence = unsafe_impl_from_ID3D12Fence(fence_iface);
+
+ TRACE("iface %p, fence %p, value %#"PRIx64".\n", iface, fence_iface, value);
+
+ if (command_queue->device->vk_info.KHR_timeline_semaphore)
+ return d3d12_command_queue_wait_timeline_semaphore(command_queue, fence, value);
+
+ FIXME_ONCE("KHR_timeline_semaphore is not available. Some wait commands may be unsupported.\n");
+ return d3d12_command_queue_wait_binary_semaphore(command_queue, fence, value);
+}
+
static HRESULT STDMETHODCALLTYPE d3d12_command_queue_GetTimestampFrequency(ID3D12CommandQueue *iface,
UINT64 *frequency)
{
diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c
index 59fa9af9..0c5278c0 100644
--- a/libs/vkd3d/device.c
+++ b/libs/vkd3d/device.c
@@ -129,6 +129,7 @@ static const struct vkd3d_optional_extension_info optional_device_extensions[] =
VK_EXTENSION(KHR_MAINTENANCE3, KHR_maintenance3),
VK_EXTENSION(KHR_PUSH_DESCRIPTOR, KHR_push_descriptor),
VK_EXTENSION(KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE, KHR_sampler_mirror_clamp_to_edge),
+ VK_EXTENSION(KHR_TIMELINE_SEMAPHORE, KHR_timeline_semaphore),
/* EXT extensions */
VK_EXTENSION(EXT_CALIBRATED_TIMESTAMPS, EXT_calibrated_timestamps),
VK_EXTENSION(EXT_CONDITIONAL_RENDERING, EXT_conditional_rendering),
@@ -683,6 +684,7 @@ struct vkd3d_physical_device_info
VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT texel_buffer_alignment_properties;
VkPhysicalDeviceTransformFeedbackPropertiesEXT xfb_properties;
VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT vertex_divisor_properties;
+ VkPhysicalDeviceTimelineSemaphorePropertiesKHR timeline_semaphore_properties;
VkPhysicalDeviceProperties2KHR properties2;
@@ -694,6 +696,7 @@ struct vkd3d_physical_device_info
VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT texel_buffer_alignment_features;
VkPhysicalDeviceTransformFeedbackFeaturesEXT xfb_features;
VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT vertex_divisor_features;
+ VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline_semaphore_features;
VkPhysicalDeviceFeatures2 features2;
};
@@ -705,10 +708,12 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i
VkPhysicalDeviceDescriptorIndexingPropertiesEXT *descriptor_indexing_properties;
VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *vertex_divisor_properties;
VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT *buffer_alignment_properties;
+ VkPhysicalDeviceTimelineSemaphorePropertiesKHR *timeline_semaphore_properties;
VkPhysicalDeviceDescriptorIndexingFeaturesEXT *descriptor_indexing_features;
VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *vertex_divisor_features;
VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT *buffer_alignment_features;
VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT *demote_features;
+ VkPhysicalDeviceTimelineSemaphoreFeaturesKHR *timeline_semaphore_features;
VkPhysicalDeviceDepthClipEnableFeaturesEXT *depth_clip_features;
VkPhysicalDeviceMaintenance3Properties *maintenance3_properties;
VkPhysicalDeviceTransformFeedbackPropertiesEXT *xfb_properties;
@@ -727,6 +732,8 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i
buffer_alignment_properties = &info->texel_buffer_alignment_properties;
vertex_divisor_features = &info->vertex_divisor_features;
vertex_divisor_properties = &info->vertex_divisor_properties;
+ timeline_semaphore_features = &info->timeline_semaphore_features;
+ timeline_semaphore_properties = &info->timeline_semaphore_properties;
xfb_features = &info->xfb_features;
xfb_properties = &info->xfb_properties;
@@ -746,6 +753,8 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i
vk_prepend_struct(&info->features2, xfb_features);
vertex_divisor_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT;
vk_prepend_struct(&info->features2, vertex_divisor_features);
+ timeline_semaphore_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR;
+ vk_prepend_struct(&info->features2, timeline_semaphore_features);
if (vulkan_info->KHR_get_physical_device_properties2)
VK_CALL(vkGetPhysicalDeviceFeatures2KHR(physical_device, &info->features2));
@@ -764,6 +773,8 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i
vk_prepend_struct(&info->properties2, xfb_properties);
vertex_divisor_properties->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT;
vk_prepend_struct(&info->properties2, vertex_divisor_properties);
+ timeline_semaphore_properties->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES_KHR;
+ vk_prepend_struct(&info->properties2, timeline_semaphore_properties);
if (vulkan_info->KHR_get_physical_device_properties2)
VK_CALL(vkGetPhysicalDeviceProperties2KHR(physical_device, &info->properties2));
@@ -1322,6 +1333,7 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device,
vulkan_info->rasterization_stream = physical_device_info->xfb_properties.transformFeedbackRasterizationStreamSelect;
vulkan_info->transform_feedback_queries = physical_device_info->xfb_properties.transformFeedbackQueries;
vulkan_info->max_vertex_attrib_divisor = max(physical_device_info->vertex_divisor_properties.maxVertexAttribDivisor, 1);
+ vulkan_info->timeline_semaphore_properties = physical_device_info->timeline_semaphore_properties;
device->feature_options.DoublePrecisionFloatShaderOps = features->shaderFloat64;
device->feature_options.OutputMergerLogicOp = features->logicOp;
@@ -1444,6 +1456,8 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device,
vulkan_info->EXT_shader_demote_to_helper_invocation = false;
if (!physical_device_info->texel_buffer_alignment_features.texelBufferAlignment)
vulkan_info->EXT_texel_buffer_alignment = false;
+ if (!physical_device_info->timeline_semaphore_features.timelineSemaphore)
+ vulkan_info->KHR_timeline_semaphore = false;
vulkan_info->texel_buffer_alignment_properties = physical_device_info->texel_buffer_alignment_properties;
diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h
index ac0d5ce1..48777aac 100644
--- a/libs/vkd3d/vkd3d_private.h
+++ b/libs/vkd3d/vkd3d_private.h
@@ -59,6 +59,7 @@
#define VKD3D_MAX_SHADER_EXTENSIONS 3u
#define VKD3D_MAX_SHADER_STAGES 5u
#define VKD3D_MAX_VK_SYNC_OBJECTS 4u
+#define VKD3D_MAX_FENCE_WAITING_QUEUES 4u
#define VKD3D_MAX_DESCRIPTOR_SETS 64u
/* D3D12 binding tier 3 has a limit of 2048 samplers. */
#define VKD3D_MAX_DESCRIPTOR_SET_SAMPLERS 2048u
@@ -123,6 +124,7 @@ struct vkd3d_vulkan_info
bool KHR_maintenance3;
bool KHR_push_descriptor;
bool KHR_sampler_mirror_clamp_to_edge;
+ bool KHR_timeline_semaphore;
/* EXT device extensions */
bool EXT_calibrated_timestamps;
bool EXT_conditional_rendering;
@@ -147,6 +149,8 @@ struct vkd3d_vulkan_info
VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT texel_buffer_alignment_properties;
+ VkPhysicalDeviceTimelineSemaphorePropertiesKHR timeline_semaphore_properties;
+
unsigned int shader_extension_count;
enum vkd3d_shader_spirv_extension shader_extensions[VKD3D_MAX_SHADER_EXTENSIONS];
@@ -344,6 +348,7 @@ struct vkd3d_fence_worker
struct vkd3d_enqueued_fence
{
VkFence vk_fence;
+ VkSemaphore vk_semaphore;
struct vkd3d_waiting_fence waiting_fence;
} *enqueued_fences;
size_t enqueued_fences_size;
@@ -353,6 +358,12 @@ struct vkd3d_fence_worker
size_t vk_fences_size;
struct vkd3d_waiting_fence *fences;
size_t fences_size;
+ VkSemaphore *vk_semaphores;
+ size_t vk_semaphores_size;
+ uint64_t *semaphore_wait_values;
+ size_t semaphore_wait_values_size;
+
+ void (*wait_for_gpu_fences)(struct vkd3d_fence_worker *worker);
struct d3d12_device *device;
};
@@ -507,6 +518,12 @@ struct vkd3d_signaled_semaphore
bool is_acquired;
};
+struct vkd3d_pending_fence_wait
+{
+ const struct vkd3d_queue *queue;
+ uint64_t pending_value;
+};
+
/* ID3D12Fence */
struct d3d12_fence
{
@@ -526,6 +543,11 @@ struct d3d12_fence
size_t events_size;
size_t event_count;
+ VkSemaphore timeline_semaphore;
+ uint64_t pending_timeline_value;
+ struct vkd3d_pending_fence_wait gpu_waits[VKD3D_MAX_FENCE_WAITING_QUEUES];
+ unsigned int gpu_wait_count;
+
struct list semaphores;
unsigned int semaphore_count;
@@ -1200,6 +1222,9 @@ struct vkd3d_queue
VkQueueFlags vk_queue_flags;
uint32_t timestamp_bits;
+ VkSemaphore wait_completion_semaphore;
+ uint64_t pending_wait_completion_value;
+
struct
{
VkSemaphore vk_semaphore;
diff --git a/libs/vkd3d/vulkan_procs.h b/libs/vkd3d/vulkan_procs.h
index 60556735..34e0ab4b 100644
--- a/libs/vkd3d/vulkan_procs.h
+++ b/libs/vkd3d/vulkan_procs.h
@@ -195,6 +195,11 @@ VK_DEVICE_EXT_PFN(vkGetDescriptorSetLayoutSupportKHR)
/* VK_KHR_push_descriptor */
VK_DEVICE_EXT_PFN(vkCmdPushDescriptorSetKHR)
+/* VK_KHR_timeline_semaphore */
+VK_DEVICE_EXT_PFN(vkGetSemaphoreCounterValueKHR)
+VK_DEVICE_EXT_PFN(vkWaitSemaphoresKHR)
+VK_DEVICE_EXT_PFN(vkSignalSemaphoreKHR)
+
/* VK_EXT_calibrated_timestamps */
VK_DEVICE_EXT_PFN(vkGetCalibratedTimestampsEXT)
diff --git a/tests/d3d12.c b/tests/d3d12.c
index 5067dd97..ea64918f 100644
--- a/tests/d3d12.c
+++ b/tests/d3d12.c
@@ -33233,7 +33233,9 @@ static void test_queue_wait(void)
command_list = context.list;
queue = context.queue;
- queue2 = create_command_queue(device, D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL);
+ /* 'queue2' must not map to the same command queue as 'queue', or Wait() before GPU signal will fail.
+ * Using a compute queue fixes this on most hardware, but it may still fail on low spec hardware. */
+ queue2 = create_command_queue(device, D3D12_COMMAND_LIST_TYPE_COMPUTE, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL);
event = create_event();
ok(event, "Failed to create event.\n");
@@ -33298,12 +33300,6 @@ static void test_queue_wait(void)
check_readback_data_uint(&rb, NULL, 0xff00ff00, 0);
release_resource_readback(&rb);
- if (!vkd3d_test_platform_is_windows())
- {
- skip("Wait() is not implemented yet.\n"); /* FIXME */
- goto skip_tests;
- }
-
/* Wait() before CPU signal */
update_buffer_data(cb, 0, sizeof(blue), &blue);
queue_wait(queue, fence, 2);
@@ -33379,7 +33375,6 @@ static void test_queue_wait(void)
check_readback_data_uint(&rb, NULL, 0xff00ff00, 0);
release_resource_readback(&rb);
-skip_tests:
/* Signal() and Wait() in the same command queue */
update_buffer_data(cb, 0, sizeof(blue), &blue);
queue_signal(queue, fence, 7);
--
2.34.1
2
4
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/winealsa.drv/alsamidi.c | 57 ++++++++++++++++++++++++++++++++++++
dlls/winealsa.drv/midi.c | 47 -----------------------------
2 files changed, 57 insertions(+), 47 deletions(-)
diff --git a/dlls/winealsa.drv/alsamidi.c b/dlls/winealsa.drv/alsamidi.c
index a7a5a211484..a92c08793af 100644
--- a/dlls/winealsa.drv/alsamidi.c
+++ b/dlls/winealsa.drv/alsamidi.c
@@ -471,6 +471,60 @@ static UINT midi_out_open(WORD dev_id, MIDIOPENDESC *midi_desc, UINT flags, stru
return MMSYSERR_NOERROR;
}
+static UINT midi_out_close(WORD dev_id, struct notify_context *notify)
+{
+ struct midi_dest *dest;
+
+ TRACE("(%04X);\n", dev_id);
+
+ if (dev_id >= num_dests)
+ {
+ WARN("bad device ID : %d\n", dev_id);
+ return MMSYSERR_BADDEVICEID;
+ }
+
+ dest = dests + dev_id;
+
+ if (dest->midiDesc.hMidi == 0)
+ {
+ WARN("device not opened !\n");
+ return MMSYSERR_ERROR;
+ }
+
+ /* FIXME: should test that no pending buffer is still in the queue for
+ * playing */
+
+ if (dest->seq == NULL)
+ {
+ WARN("can't close !\n");
+ return MMSYSERR_ERROR;
+ }
+
+ switch (dest->caps.wTechnology)
+ {
+ case MOD_FMSYNTH:
+ case MOD_MIDIPORT:
+ case MOD_SYNTH:
+ seq_lock();
+ TRACE("Deleting port :%d, connected to %d:%d\n", dest->port_out, dest->addr.client, dest->addr.port);
+ snd_seq_delete_simple_port(dest->seq, dest->port_out);
+ dest->port_out = -1;
+ seq_unlock();
+ seq_close();
+ dest->seq = NULL;
+ break;
+ default:
+ WARN("Technology not supported (yet) %d !\n", dest->caps.wTechnology);
+ return MMSYSERR_NOTENABLED;
+ }
+
+ set_out_notify(notify, dest, dev_id, MOM_CLOSE, 0, 0);
+
+ dest->midiDesc.hMidi = 0;
+
+ return MMSYSERR_NOERROR;
+}
+
NTSTATUS midi_out_message(void *args)
{
struct midi_out_message_params *params = args;
@@ -488,6 +542,9 @@ NTSTATUS midi_out_message(void *args)
case MODM_OPEN:
*params->err = midi_out_open(params->dev_id, (MIDIOPENDESC *)params->param_1, params->param_2, params->notify);
break;
+ case MODM_CLOSE:
+ *params->err = midi_out_close(params->dev_id, params->notify);
+ break;
default:
TRACE("Unsupported message\n");
*params->err = MMSYSERR_NOTSUPPORTED;
diff --git a/dlls/winealsa.drv/midi.c b/dlls/winealsa.drv/midi.c
index c77d479162b..5f8d855c9fb 100644
--- a/dlls/winealsa.drv/midi.c
+++ b/dlls/winealsa.drv/midi.c
@@ -122,7 +122,6 @@ static void MIDI_NotifyClient(UINT wDevID, WORD wMsg,
wDevID, wMsg, dwParam1, dwParam2);
switch (wMsg) {
- case MOM_CLOSE:
case MOM_DONE:
case MOM_POSITIONCB:
if (wDevID > MODM_NumDevs) return;
@@ -631,50 +630,6 @@ static DWORD modGetDevCaps(WORD wDevID, LPMIDIOUTCAPSW lpCaps, DWORD dwSize)
return MMSYSERR_NOERROR;
}
-/**************************************************************************
- * modClose [internal]
- */
-static DWORD modClose(WORD wDevID)
-{
- int ret = MMSYSERR_NOERROR;
-
- TRACE("(%04X);\n", wDevID);
-
- if (MidiOutDev[wDevID].midiDesc.hMidi == 0) {
- WARN("device not opened !\n");
- return MMSYSERR_ERROR;
- }
- /* FIXME: should test that no pending buffer is still in the queue for
- * playing */
-
- if (MidiOutDev[wDevID].seq == NULL) {
- WARN("can't close !\n");
- return MMSYSERR_ERROR;
- }
-
- switch (MidiOutDev[wDevID].caps.wTechnology) {
- case MOD_FMSYNTH:
- case MOD_MIDIPORT:
- case MOD_SYNTH:
- seq_lock();
- TRACE("Deleting port :%d, connected to %d:%d\n", MidiOutDev[wDevID].port_out, MidiOutDev[wDevID].addr.client, MidiOutDev[wDevID].addr.port);
- snd_seq_delete_simple_port(MidiOutDev[wDevID].seq, MidiOutDev[wDevID].port_out);
- MidiOutDev[wDevID].port_out = -1;
- seq_unlock();
- midiCloseSeq();
- MidiOutDev[wDevID].seq = NULL;
- break;
- default:
- WARN("Technology not supported (yet) %d !\n",
- MidiOutDev[wDevID].caps.wTechnology);
- return MMSYSERR_NOTENABLED;
- }
-
- MIDI_NotifyClient(wDevID, MOM_CLOSE, 0L, 0L);
- MidiOutDev[wDevID].midiDesc.hMidi = 0;
- return ret;
-}
-
/**************************************************************************
* modData [internal]
*/
@@ -1051,8 +1006,6 @@ DWORD WINAPI ALSA_modMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
case DRVM_INIT:
ALSA_MidiInit();
return 0;
- case MODM_CLOSE:
- return modClose(wDevID);
case MODM_DATA:
return modData(wDevID, dwParam1);
case MODM_LONGDATA:
--
2.25.1
2
1
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/winealsa.drv/alsa.c | 1 +
dlls/winealsa.drv/alsamidi.c | 133 +++++++++++++++++++++++++++++++++++
dlls/winealsa.drv/midi.c | 127 +++++++--------------------------
dlls/winealsa.drv/unixlib.h | 26 +++++++
4 files changed, 186 insertions(+), 101 deletions(-)
diff --git a/dlls/winealsa.drv/alsa.c b/dlls/winealsa.drv/alsa.c
index 16c0c7c387d..6d307eb84bf 100644
--- a/dlls/winealsa.drv/alsa.c
+++ b/dlls/winealsa.drv/alsa.c
@@ -2445,6 +2445,7 @@ unixlib_entry_t __wine_unix_call_funcs[] =
is_started,
get_prop_value,
midi_init,
+ midi_out_message,
midi_seq_lock, /* temporary */
midi_seq_open,
diff --git a/dlls/winealsa.drv/alsamidi.c b/dlls/winealsa.drv/alsamidi.c
index e1fca85b3b4..a7a5a211484 100644
--- a/dlls/winealsa.drv/alsamidi.c
+++ b/dlls/winealsa.drv/alsamidi.c
@@ -362,3 +362,136 @@ NTSTATUS midi_init(void *args)
return STATUS_SUCCESS;
}
+
+static void set_out_notify(struct notify_context *notify, struct midi_dest *dest, WORD dev_id, WORD msg,
+ UINT_PTR param_1, UINT_PTR param_2)
+{
+ notify->send_notify = TRUE;
+ notify->dev_id = dev_id;
+ notify->msg = msg;
+ notify->param_1 = param_1;
+ notify->param_2 = param_2;
+ notify->callback = dest->midiDesc.dwCallback;
+ notify->flags = dest->wFlags;
+ notify->device = dest->midiDesc.hMidi;
+ notify->instance = dest->midiDesc.dwInstance;
+}
+
+static UINT midi_out_open(WORD dev_id, MIDIOPENDESC *midi_desc, UINT flags, struct notify_context *notify)
+{
+ int ret;
+ int port_out;
+ char port_out_name[32];
+ snd_seq_t *midi_seq;
+ struct midi_dest *dest;
+
+ TRACE("(%04X, %p, %08X);\n", dev_id, midi_desc, flags);
+
+ if (midi_desc == NULL)
+ {
+ WARN("Invalid Parameter !\n");
+ return MMSYSERR_INVALPARAM;
+ }
+ if (dev_id >= num_dests)
+ {
+ TRACE("MAX_MIDIOUTDRV reached !\n");
+ return MMSYSERR_BADDEVICEID;
+ }
+ dest = dests + dev_id;
+ if (dest->midiDesc.hMidi != 0)
+ {
+ WARN("device already open !\n");
+ return MMSYSERR_ALLOCATED;
+ }
+ if (!dest->bEnabled)
+ {
+ WARN("device disabled !\n");
+ return MIDIERR_NODEVICE;
+ }
+ if ((flags & ~CALLBACK_TYPEMASK) != 0)
+ {
+ WARN("bad dwFlags\n");
+ return MMSYSERR_INVALFLAG;
+ }
+
+ switch (dest->caps.wTechnology)
+ {
+ case MOD_FMSYNTH:
+ case MOD_MIDIPORT:
+ case MOD_SYNTH:
+ if (!(midi_seq = seq_open(NULL)))
+ return MMSYSERR_ALLOCATED;
+ break;
+ default:
+ WARN("Technology not supported (yet) %d !\n", dest->caps.wTechnology);
+ return MMSYSERR_NOTENABLED;
+ }
+
+ dest->wFlags = HIWORD(flags & CALLBACK_TYPEMASK);
+ dest->midiDesc = *midi_desc;
+ dest->seq = midi_seq;
+
+ seq_lock();
+ /* Create a port dedicated to a specific device */
+ /* Keep the old name without a number for the first port */
+ if (dev_id)
+ sprintf(port_out_name, "WINE ALSA Output #%d", dev_id);
+
+ port_out = snd_seq_create_simple_port(midi_seq, dev_id ? port_out_name : "WINE ALSA Output",
+ SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_SUBS_WRITE,
+ SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION);
+
+ if (port_out < 0)
+ {
+ TRACE("Unable to create output port\n");
+ dest->port_out = -1;
+ }
+ else
+ {
+ TRACE("Output port %d created successfully\n", port_out);
+ dest->port_out = port_out;
+
+ /* Connect our app port to the device port */
+ ret = snd_seq_connect_to(midi_seq, port_out, dest->addr.client, dest->addr.port);
+
+ /* usually will happen when the port is already connected */
+ /* other errors should not be fatal either */
+ if (ret < 0)
+ WARN("Could not connect port %d to %d:%d: %s\n", dev_id, dest->addr.client,
+ dest->addr.port, snd_strerror(ret));
+ }
+ seq_unlock();
+
+ if (port_out < 0)
+ return MMSYSERR_NOTENABLED;
+
+ TRACE("Output port :%d connected %d:%d\n", port_out, dest->addr.client, dest->addr.port);
+
+ set_out_notify(notify, dest, dev_id, MOM_OPEN, 0, 0);
+ return MMSYSERR_NOERROR;
+}
+
+NTSTATUS midi_out_message(void *args)
+{
+ struct midi_out_message_params *params = args;
+
+ params->notify->send_notify = FALSE;
+
+ switch (params->msg)
+ {
+ case DRVM_EXIT:
+ case DRVM_ENABLE:
+ case DRVM_DISABLE:
+ /* FIXME: Pretend this is supported */
+ *params->err = MMSYSERR_NOERROR;
+ break;
+ case MODM_OPEN:
+ *params->err = midi_out_open(params->dev_id, (MIDIOPENDESC *)params->param_1, params->param_2, params->notify);
+ break;
+ default:
+ TRACE("Unsupported message\n");
+ *params->err = MMSYSERR_NOTSUPPORTED;
+ }
+
+ return STATUS_SUCCESS;
+}
diff --git a/dlls/winealsa.drv/midi.c b/dlls/winealsa.drv/midi.c
index 535f3dbd348..c77d479162b 100644
--- a/dlls/winealsa.drv/midi.c
+++ b/dlls/winealsa.drv/midi.c
@@ -79,6 +79,14 @@ static void seq_unlock(void)
ALSA_CALL(midi_seq_lock, (void *)(UINT_PTR)0);
}
+static void notify_client(struct notify_context *notify)
+{
+ TRACE("dev_id = %d msg = %d param1 = %04lX param2 = %04lX\n", notify->dev_id, notify->msg, notify->param_1, notify->param_2);
+
+ DriverCallback(notify->callback, notify->flags, notify->device, notify->msg,
+ notify->instance, notify->param_1, notify->param_2);
+}
+
/*======================================================================*
* Low level MIDI implementation *
*======================================================================*/
@@ -114,7 +122,6 @@ static void MIDI_NotifyClient(UINT wDevID, WORD wMsg,
wDevID, wMsg, dwParam1, dwParam2);
switch (wMsg) {
- case MOM_OPEN:
case MOM_CLOSE:
case MOM_DONE:
case MOM_POSITIONCB:
@@ -624,96 +631,6 @@ static DWORD modGetDevCaps(WORD wDevID, LPMIDIOUTCAPSW lpCaps, DWORD dwSize)
return MMSYSERR_NOERROR;
}
-/**************************************************************************
- * modOpen [internal]
- */
-static DWORD modOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
-{
- int ret;
- int port_out;
- char port_out_name[32];
- snd_seq_t *midi_seq;
-
- TRACE("(%04X, %p, %08X);\n", wDevID, lpDesc, dwFlags);
- if (lpDesc == NULL) {
- WARN("Invalid Parameter !\n");
- return MMSYSERR_INVALPARAM;
- }
- if (wDevID >= MODM_NumDevs) {
- TRACE("MAX_MIDIOUTDRV reached !\n");
- return MMSYSERR_BADDEVICEID;
- }
- if (MidiOutDev[wDevID].midiDesc.hMidi != 0) {
- WARN("device already open !\n");
- return MMSYSERR_ALLOCATED;
- }
- if (!MidiOutDev[wDevID].bEnabled) {
- WARN("device disabled !\n");
- return MIDIERR_NODEVICE;
- }
- if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) {
- WARN("bad dwFlags\n");
- return MMSYSERR_INVALFLAG;
- }
-
- switch (MidiOutDev[wDevID].caps.wTechnology) {
- case MOD_FMSYNTH:
- case MOD_MIDIPORT:
- case MOD_SYNTH:
- if (!(midi_seq = midiOpenSeq(NULL))) {
- return MMSYSERR_ALLOCATED;
- }
- break;
- default:
- WARN("Technology not supported (yet) %d !\n",
- MidiOutDev[wDevID].caps.wTechnology);
- return MMSYSERR_NOTENABLED;
- }
-
- MidiOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
- MidiOutDev[wDevID].midiDesc = *lpDesc;
- MidiOutDev[wDevID].seq = midi_seq;
-
- seq_lock();
- /* Create a port dedicated to a specific device */
- /* Keep the old name without a number for the first port */
- if (wDevID)
- sprintf(port_out_name, "WINE ALSA Output #%d", wDevID);
-
- port_out = snd_seq_create_simple_port(midi_seq, wDevID?port_out_name:"WINE ALSA Output",
- SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ|SND_SEQ_PORT_CAP_SUBS_WRITE,
- SND_SEQ_PORT_TYPE_MIDI_GENERIC|SND_SEQ_PORT_TYPE_APPLICATION);
-
- if (port_out < 0) {
- TRACE("Unable to create output port\n");
- MidiOutDev[wDevID].port_out = -1;
- } else {
- TRACE("Output port %d created successfully\n", port_out);
- MidiOutDev[wDevID].port_out = port_out;
-
- /* Connect our app port to the device port */
- ret = snd_seq_connect_to(midi_seq, port_out, MidiOutDev[wDevID].addr.client,
- MidiOutDev[wDevID].addr.port);
-
- /* usually will happen when the port is already connected */
- /* other errors should not be fatal either */
- if (ret < 0)
- WARN("Could not connect port %d to %d:%d: %s\n",
- wDevID, MidiOutDev[wDevID].addr.client,
- MidiOutDev[wDevID].addr.port, snd_strerror(ret));
- }
- seq_unlock();
-
- if (port_out < 0)
- return MMSYSERR_NOTENABLED;
-
- TRACE("Output port :%d connected %d:%d\n",port_out,MidiOutDev[wDevID].addr.client,MidiOutDev[wDevID].addr.port);
-
- MIDI_NotifyClient(wDevID, MOM_OPEN, 0L, 0L);
- return MMSYSERR_NOERROR;
-}
-
-
/**************************************************************************
* modClose [internal]
*/
@@ -1123,6 +1040,10 @@ DWORD WINAPI ALSA_midMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
DWORD WINAPI ALSA_modMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
DWORD_PTR dwParam1, DWORD_PTR dwParam2)
{
+ struct midi_out_message_params params;
+ struct notify_context notify;
+ UINT err;
+
TRACE("(%04X, %04X, %08lX, %08lX, %08lX);\n",
wDevID, wMsg, dwUser, dwParam1, dwParam2);
@@ -1130,13 +1051,6 @@ DWORD WINAPI ALSA_modMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
case DRVM_INIT:
ALSA_MidiInit();
return 0;
- case DRVM_EXIT:
- case DRVM_ENABLE:
- case DRVM_DISABLE:
- /* FIXME: Pretend this is supported */
- return 0;
- case MODM_OPEN:
- return modOpen(wDevID, (LPMIDIOPENDESC)dwParam1, dwParam2);
case MODM_CLOSE:
return modClose(wDevID);
case MODM_DATA:
@@ -1157,10 +1071,21 @@ DWORD WINAPI ALSA_modMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
return 0;
case MODM_RESET:
return modReset(wDevID);
- default:
- TRACE("Unsupported message\n");
}
- return MMSYSERR_NOTSUPPORTED;
+
+ params.dev_id = wDevID;
+ params.msg = wMsg;
+ params.user = dwUser;
+ params.param_1 = dwParam1;
+ params.param_2 = dwParam2;
+ params.err = &err;
+ params.notify = ¬ify;
+
+ ALSA_CALL(midi_out_message, ¶ms);
+
+ if (!err && notify.send_notify) notify_client(¬ify);
+
+ return err;
}
/**************************************************************************
diff --git a/dlls/winealsa.drv/unixlib.h b/dlls/winealsa.drv/unixlib.h
index d69ab980f42..e3cd7123101 100644
--- a/dlls/winealsa.drv/unixlib.h
+++ b/dlls/winealsa.drv/unixlib.h
@@ -241,6 +241,30 @@ struct midi_init_params
void *dests, *srcs;
};
+struct notify_context
+{
+ BOOL send_notify;
+ WORD dev_id;
+ WORD msg;
+ UINT_PTR param_1;
+ UINT_PTR param_2;
+ UINT_PTR callback;
+ UINT flags;
+ HANDLE device;
+ UINT_PTR instance;
+};
+
+struct midi_out_message_params
+{
+ UINT dev_id;
+ UINT msg;
+ UINT_PTR user;
+ UINT_PTR param_1;
+ UINT_PTR param_2;
+ UINT *err;
+ struct notify_context *notify;
+};
+
struct midi_seq_open_params
{
int close;
@@ -274,12 +298,14 @@ enum alsa_funcs
alsa_is_started,
alsa_get_prop_value,
alsa_midi_init,
+ alsa_midi_out_message,
alsa_midi_seq_lock, /* temporary */
alsa_midi_seq_open,
};
NTSTATUS midi_init(void *args) DECLSPEC_HIDDEN;
+NTSTATUS midi_out_message(void *args) DECLSPEC_HIDDEN;
NTSTATUS midi_seq_lock(void *args) DECLSPEC_HIDDEN;
NTSTATUS midi_seq_open(void *args) DECLSPEC_HIDDEN;
--
2.25.1
2
1
[PATCH v2 3/5] winealsa: Add a temporary syscall to return the snd_seq handle.
by Huw Davies 16 Mar '22
by Huw Davies 16 Mar '22
16 Mar '22
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/winealsa.drv/alsa.c | 1 +
dlls/winealsa.drv/alsamidi.c | 51 ++++++++++++++++++++++++++++++------
dlls/winealsa.drv/midi.c | 49 ++++++++--------------------------
dlls/winealsa.drv/unixlib.h | 9 +++++++
4 files changed, 64 insertions(+), 46 deletions(-)
diff --git a/dlls/winealsa.drv/alsa.c b/dlls/winealsa.drv/alsa.c
index 76e4b98caaf..16c0c7c387d 100644
--- a/dlls/winealsa.drv/alsa.c
+++ b/dlls/winealsa.drv/alsa.c
@@ -2447,4 +2447,5 @@ unixlib_entry_t __wine_unix_call_funcs[] =
midi_init,
midi_seq_lock, /* temporary */
+ midi_seq_open,
};
diff --git a/dlls/winealsa.drv/alsamidi.c b/dlls/winealsa.drv/alsamidi.c
index 86e092bd977..e1fca85b3b4 100644
--- a/dlls/winealsa.drv/alsamidi.c
+++ b/dlls/winealsa.drv/alsamidi.c
@@ -55,6 +55,7 @@ static struct midi_dest dests[MAX_MIDIOUTDRV];
static struct midi_src srcs[MAX_MIDIINDRV];
static snd_seq_t *midi_seq;
static unsigned int seq_refs;
+static int port_in = -1;
static void seq_lock(void)
{
@@ -74,7 +75,7 @@ NTSTATUS midi_seq_lock(void *args)
return STATUS_SUCCESS;
}
-static int seq_open(void)
+static snd_seq_t *seq_open(int *port_in_ret)
{
static int midi_warn;
@@ -87,12 +88,28 @@ static int seq_open(void)
WARN("Error opening ALSA sequencer.\n");
midi_warn = 1;
seq_unlock();
- return -1;
+ return NULL;
}
+ snd_seq_set_client_name(midi_seq, "WINE midi driver");
}
seq_refs++;
+
+ if (port_in_ret)
+ {
+ if (port_in < 0)
+ {
+ port_in = snd_seq_create_simple_port(midi_seq, "WINE ALSA Input",
+ SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_SUBS_WRITE,
+ SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION);
+ if (port_in < 0)
+ TRACE("Unable to create input port\n");
+ else
+ TRACE("Input port %d created successfully\n", port_in);
+ }
+ *port_in_ret = port_in;
+ }
seq_unlock();
- return 0;
+ return midi_seq;
}
static void seq_close(void)
@@ -100,12 +117,29 @@ static void seq_close(void)
seq_lock();
if (--seq_refs == 0)
{
+ if (port_in >= 0)
+ {
+ snd_seq_delete_simple_port(midi_seq, port_in);
+ port_in = -1;
+ }
snd_seq_close(midi_seq);
midi_seq = NULL;
}
seq_unlock();
}
+NTSTATUS midi_seq_open(void *args)
+{
+ struct midi_seq_open_params *params = args;
+
+ if (!params->close)
+ params->seq = seq_open(params->port_in);
+ else
+ seq_close();
+
+ return STATUS_SUCCESS;
+}
+
static int alsa_to_win_device_type(unsigned int type)
{
/* MOD_MIDIPORT output port
@@ -270,6 +304,7 @@ NTSTATUS midi_init(void *args)
static BOOL init_done;
snd_seq_client_info_t *cinfo;
snd_seq_port_info_t *pinfo;
+ snd_seq_t *seq;
if (init_done) {
*params->err = ERROR_ALREADY_INITIALIZED;
@@ -280,7 +315,7 @@ NTSTATUS midi_init(void *args)
init_done = TRUE;
/* try to open device */
- if (seq_open() == -1) {
+ if (!(seq = seq_open(NULL))) {
*params->err = ERROR_OPEN_FAILED;
return STATUS_SUCCESS;
}
@@ -290,10 +325,10 @@ NTSTATUS midi_init(void *args)
/* First, search for all internal midi devices */
snd_seq_client_info_set_client(cinfo, -1);
- while (snd_seq_query_next_client(midi_seq, cinfo) >= 0) {
+ while (snd_seq_query_next_client(seq, cinfo) >= 0) {
snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo));
snd_seq_port_info_set_port(pinfo, -1);
- while (snd_seq_query_next_port(midi_seq, pinfo) >= 0) {
+ while (snd_seq_query_next_port(seq, pinfo) >= 0) {
unsigned int cap = snd_seq_port_info_get_capability(pinfo);
unsigned int type = snd_seq_port_info_get_type(pinfo);
if (!(type & SND_SEQ_PORT_TYPE_PORT))
@@ -303,10 +338,10 @@ NTSTATUS midi_init(void *args)
/* Second, search for all external ports */
snd_seq_client_info_set_client(cinfo, -1);
- while (snd_seq_query_next_client(midi_seq, cinfo) >= 0) {
+ while (snd_seq_query_next_client(seq, cinfo) >= 0) {
snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo));
snd_seq_port_info_set_port(pinfo, -1);
- while (snd_seq_query_next_port(midi_seq, pinfo) >= 0) {
+ while (snd_seq_query_next_port(seq, pinfo) >= 0) {
unsigned int cap = snd_seq_port_info_get_capability(pinfo);
unsigned int type = snd_seq_port_info_get_type(pinfo);
if (type & SND_SEQ_PORT_TYPE_PORT)
diff --git a/dlls/winealsa.drv/midi.c b/dlls/winealsa.drv/midi.c
index fae6ddf8615..535f3dbd348 100644
--- a/dlls/winealsa.drv/midi.c
+++ b/dlls/winealsa.drv/midi.c
@@ -55,12 +55,8 @@ static int MODM_NumDevs = 0;
/* this is the total number of MIDI out devices found */
static int MIDM_NumDevs = 0;
-static snd_seq_t* midiSeq = NULL;
-static int numOpenMidiSeq = 0;
static int numStartedMidiIn = 0;
-static int port_in;
-
static CRITICAL_SECTION crit_sect; /* protects all MidiIn buffer queues */
static CRITICAL_SECTION_DEBUG critsect_debug =
{
@@ -152,40 +148,18 @@ static void MIDI_NotifyClient(UINT wDevID, WORD wMsg,
DriverCallback(dwCallBack, uFlags, hDev, wMsg, dwInstance, dwParam1, dwParam2);
}
-static BOOL midi_warn = TRUE;
/**************************************************************************
* midiOpenSeq [internal]
*/
static snd_seq_t *midiOpenSeq(int *port_in_ret)
{
- seq_lock();
- if (numOpenMidiSeq == 0) {
- if (snd_seq_open(&midiSeq, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0)
- {
- if (midi_warn)
- {
- WARN("Error opening ALSA sequencer.\n");
- }
- midi_warn = FALSE;
- seq_unlock();
- return NULL;
- }
+ struct midi_seq_open_params params;
- /* Setting the client name is the only init to do */
- snd_seq_set_client_name(midiSeq, "WINE midi driver");
+ params.port_in = port_in_ret;
+ params.close = 0;
+ ALSA_CALL(midi_seq_open, ¶ms);
- port_in = snd_seq_create_simple_port(midiSeq, "WINE ALSA Input",
- SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_READ|SND_SEQ_PORT_CAP_SUBS_WRITE,
- SND_SEQ_PORT_TYPE_MIDI_GENERIC|SND_SEQ_PORT_TYPE_APPLICATION);
- if (port_in < 0)
- TRACE("Unable to create input port\n");
- else
- TRACE("Input port %d created successfully\n", port_in);
- }
- numOpenMidiSeq++;
- seq_unlock();
- if (port_in_ret) *port_in_ret = port_in;
- return midiSeq;
+ return params.seq;
}
/**************************************************************************
@@ -193,13 +167,12 @@ static snd_seq_t *midiOpenSeq(int *port_in_ret)
*/
static int midiCloseSeq(void)
{
- seq_lock();
- if (--numOpenMidiSeq == 0) {
- snd_seq_delete_simple_port(midiSeq, port_in);
- snd_seq_close(midiSeq);
- midiSeq = NULL;
- }
- seq_unlock();
+ struct midi_seq_open_params params;
+
+ params.port_in = NULL;
+ params.close = 1;
+ ALSA_CALL(midi_seq_open, ¶ms);
+
return 0;
}
diff --git a/dlls/winealsa.drv/unixlib.h b/dlls/winealsa.drv/unixlib.h
index e0ae16b97d9..d69ab980f42 100644
--- a/dlls/winealsa.drv/unixlib.h
+++ b/dlls/winealsa.drv/unixlib.h
@@ -241,6 +241,13 @@ struct midi_init_params
void *dests, *srcs;
};
+struct midi_seq_open_params
+{
+ int close;
+ snd_seq_t *seq;
+ int *port_in;
+};
+
enum alsa_funcs
{
alsa_get_endpoint_ids,
@@ -269,11 +276,13 @@ enum alsa_funcs
alsa_midi_init,
alsa_midi_seq_lock, /* temporary */
+ alsa_midi_seq_open,
};
NTSTATUS midi_init(void *args) DECLSPEC_HIDDEN;
NTSTATUS midi_seq_lock(void *args) DECLSPEC_HIDDEN;
+NTSTATUS midi_seq_open(void *args) DECLSPEC_HIDDEN;
extern unixlib_handle_t alsa_handle;
--
2.25.1
2
1
[PATCH v2 2/5] winealsa: Store the snd_seq handle and the input port in the device data.
by Huw Davies 16 Mar '22
by Huw Davies 16 Mar '22
16 Mar '22
This is to avoid accessing more global variables and generally
makes things a bit cleaner.
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/winealsa.drv/midi.c | 85 ++++++++++++++++++++-----------------
dlls/winealsa.drv/unixlib.h | 3 ++
2 files changed, 49 insertions(+), 39 deletions(-)
diff --git a/dlls/winealsa.drv/midi.c b/dlls/winealsa.drv/midi.c
index 988429ab934..fae6ddf8615 100644
--- a/dlls/winealsa.drv/midi.c
+++ b/dlls/winealsa.drv/midi.c
@@ -156,7 +156,7 @@ static BOOL midi_warn = TRUE;
/**************************************************************************
* midiOpenSeq [internal]
*/
-static int midiOpenSeq(BOOL create_client)
+static snd_seq_t *midiOpenSeq(int *port_in_ret)
{
seq_lock();
if (numOpenMidiSeq == 0) {
@@ -168,25 +168,24 @@ static int midiOpenSeq(BOOL create_client)
}
midi_warn = FALSE;
seq_unlock();
- return -1;
+ return NULL;
}
- if (create_client) {
- /* Setting the client name is the only init to do */
- snd_seq_set_client_name(midiSeq, "WINE midi driver");
-
- port_in = snd_seq_create_simple_port(midiSeq, "WINE ALSA Input",
- SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_READ|SND_SEQ_PORT_CAP_SUBS_WRITE,
- SND_SEQ_PORT_TYPE_MIDI_GENERIC|SND_SEQ_PORT_TYPE_APPLICATION);
- if (port_in < 0)
- TRACE("Unable to create input port\n");
- else
- TRACE("Input port %d created successfully\n", port_in);
- }
+ /* Setting the client name is the only init to do */
+ snd_seq_set_client_name(midiSeq, "WINE midi driver");
+
+ port_in = snd_seq_create_simple_port(midiSeq, "WINE ALSA Input",
+ SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_READ|SND_SEQ_PORT_CAP_SUBS_WRITE,
+ SND_SEQ_PORT_TYPE_MIDI_GENERIC|SND_SEQ_PORT_TYPE_APPLICATION);
+ if (port_in < 0)
+ TRACE("Unable to create input port\n");
+ else
+ TRACE("Input port %d created successfully\n", port_in);
}
numOpenMidiSeq++;
seq_unlock();
- return 0;
+ if (port_in_ret) *port_in_ret = port_in;
+ return midiSeq;
}
/**************************************************************************
@@ -314,8 +313,9 @@ static void handle_midi_event(snd_seq_event_t *ev)
}
}
-static DWORD WINAPI midRecThread(LPVOID arg)
+static DWORD WINAPI midRecThread(void *arg)
{
+ snd_seq_t *midi_seq = arg;
int npfd;
struct pollfd *pfd;
int ret;
@@ -325,9 +325,9 @@ static DWORD WINAPI midRecThread(LPVOID arg)
while(!end_thread) {
TRACE("Thread loop\n");
seq_lock();
- npfd = snd_seq_poll_descriptors_count(midiSeq, POLLIN);
+ npfd = snd_seq_poll_descriptors_count(midi_seq, POLLIN);
pfd = HeapAlloc(GetProcessHeap(), 0, npfd * sizeof(struct pollfd));
- snd_seq_poll_descriptors(midiSeq, pfd, npfd, POLLIN);
+ snd_seq_poll_descriptors(midi_seq, pfd, npfd, POLLIN);
seq_unlock();
/* Check if an event is present */
@@ -337,9 +337,9 @@ static DWORD WINAPI midRecThread(LPVOID arg)
}
/* Note: This definitely does not work.
- * while(snd_seq_event_input_pending(midiSeq, 0) > 0) {
+ * while(snd_seq_event_input_pending(midi_seq, 0) > 0) {
snd_seq_event_t* ev;
- snd_seq_event_input(midiSeq, &ev);
+ snd_seq_event_input(midi_seq, &ev);
....................
snd_seq_free_event(ev);
}*/
@@ -348,7 +348,7 @@ static DWORD WINAPI midRecThread(LPVOID arg)
snd_seq_event_t *ev;
seq_lock();
- snd_seq_event_input(midiSeq, &ev);
+ snd_seq_event_input(midi_seq, &ev);
seq_unlock();
if (ev) {
@@ -357,10 +357,10 @@ static DWORD WINAPI midRecThread(LPVOID arg)
}
seq_lock();
- ret = snd_seq_event_input_pending(midiSeq, 0);
+ ret = snd_seq_event_input_pending(midi_seq, 0);
seq_unlock();
} while(ret > 0);
-
+
HeapFree(GetProcessHeap(), 0, pfd);
}
return 0;
@@ -387,7 +387,8 @@ static DWORD midGetDevCaps(WORD wDevID, LPMIDIINCAPSW lpCaps, DWORD dwSize)
*/
static DWORD midOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
{
- int ret = 0;
+ int ret = 0, port_in;
+ snd_seq_t *midi_seq;
TRACE("(%04X, %p, %08X);\n", wDevID, lpDesc, dwFlags);
@@ -420,7 +421,7 @@ static DWORD midOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
return MMSYSERR_INVALFLAG;
}
- if (midiOpenSeq(TRUE) < 0) {
+ if (!(midi_seq = midiOpenSeq(&port_in))) {
return MMSYSERR_ERROR;
}
@@ -430,10 +431,12 @@ static DWORD midOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
MidiInDev[wDevID].midiDesc = *lpDesc;
MidiInDev[wDevID].state = 0;
MidiInDev[wDevID].startTime = 0;
+ MidiInDev[wDevID].seq = midi_seq;
+ MidiInDev[wDevID].port_in = port_in;
/* Connect our app port to the device port */
seq_lock();
- ret = snd_seq_connect_from(midiSeq, port_in, MidiInDev[wDevID].addr.client,
+ ret = snd_seq_connect_from(midi_seq, port_in, MidiInDev[wDevID].addr.client,
MidiInDev[wDevID].addr.port);
seq_unlock();
if (ret < 0)
@@ -443,7 +446,7 @@ static DWORD midOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
if (numStartedMidiIn++ == 0) {
end_thread = 0;
- hThread = CreateThread(NULL, 0, midRecThread, NULL, 0, NULL);
+ hThread = CreateThread(NULL, 0, midRecThread, midi_seq, 0, NULL);
if (!hThread) {
numStartedMidiIn = 0;
WARN("Couldn't create thread for midi-in\n");
@@ -479,7 +482,7 @@ static DWORD midClose(WORD wDevID)
return MIDIERR_STILLPLAYING;
}
- if (midiSeq == NULL) {
+ if (MidiInDev[wDevID].seq == NULL) {
WARN("ooops !\n");
return MMSYSERR_ERROR;
}
@@ -494,12 +497,13 @@ static DWORD midClose(WORD wDevID)
}
seq_lock();
- snd_seq_disconnect_from(midiSeq, port_in, MidiInDev[wDevID].addr.client, MidiInDev[wDevID].addr.port);
+ snd_seq_disconnect_from(MidiInDev[wDevID].seq, MidiInDev[wDevID].port_in, MidiInDev[wDevID].addr.client, MidiInDev[wDevID].addr.port);
seq_unlock();
midiCloseSeq();
MIDI_NotifyClient(wDevID, MIM_CLOSE, 0L, 0L);
MidiInDev[wDevID].midiDesc.hMidi = 0;
+ MidiInDev[wDevID].seq = NULL;
return ret;
}
@@ -655,6 +659,7 @@ static DWORD modOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
int ret;
int port_out;
char port_out_name[32];
+ snd_seq_t *midi_seq;
TRACE("(%04X, %p, %08X);\n", wDevID, lpDesc, dwFlags);
if (lpDesc == NULL) {
@@ -682,7 +687,7 @@ static DWORD modOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
case MOD_FMSYNTH:
case MOD_MIDIPORT:
case MOD_SYNTH:
- if (midiOpenSeq(TRUE) < 0) {
+ if (!(midi_seq = midiOpenSeq(NULL))) {
return MMSYSERR_ALLOCATED;
}
break;
@@ -694,6 +699,7 @@ static DWORD modOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
MidiOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
MidiOutDev[wDevID].midiDesc = *lpDesc;
+ MidiOutDev[wDevID].seq = midi_seq;
seq_lock();
/* Create a port dedicated to a specific device */
@@ -701,7 +707,7 @@ static DWORD modOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
if (wDevID)
sprintf(port_out_name, "WINE ALSA Output #%d", wDevID);
- port_out = snd_seq_create_simple_port(midiSeq, wDevID?port_out_name:"WINE ALSA Output",
+ port_out = snd_seq_create_simple_port(midi_seq, wDevID?port_out_name:"WINE ALSA Output",
SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ|SND_SEQ_PORT_CAP_SUBS_WRITE,
SND_SEQ_PORT_TYPE_MIDI_GENERIC|SND_SEQ_PORT_TYPE_APPLICATION);
@@ -713,7 +719,7 @@ static DWORD modOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
MidiOutDev[wDevID].port_out = port_out;
/* Connect our app port to the device port */
- ret = snd_seq_connect_to(midiSeq, port_out, MidiOutDev[wDevID].addr.client,
+ ret = snd_seq_connect_to(midi_seq, port_out, MidiOutDev[wDevID].addr.client,
MidiOutDev[wDevID].addr.port);
/* usually will happen when the port is already connected */
@@ -751,7 +757,7 @@ static DWORD modClose(WORD wDevID)
/* FIXME: should test that no pending buffer is still in the queue for
* playing */
- if (midiSeq == NULL) {
+ if (MidiOutDev[wDevID].seq == NULL) {
WARN("can't close !\n");
return MMSYSERR_ERROR;
}
@@ -762,10 +768,11 @@ static DWORD modClose(WORD wDevID)
case MOD_SYNTH:
seq_lock();
TRACE("Deleting port :%d, connected to %d:%d\n", MidiOutDev[wDevID].port_out, MidiOutDev[wDevID].addr.client, MidiOutDev[wDevID].addr.port);
- snd_seq_delete_simple_port(midiSeq, MidiOutDev[wDevID].port_out);
+ snd_seq_delete_simple_port(MidiOutDev[wDevID].seq, MidiOutDev[wDevID].port_out);
MidiOutDev[wDevID].port_out = -1;
seq_unlock();
- midiCloseSeq();
+ midiCloseSeq();
+ MidiOutDev[wDevID].seq = NULL;
break;
default:
WARN("Technology not supported (yet) %d !\n",
@@ -792,7 +799,7 @@ static DWORD modData(WORD wDevID, DWORD dwParam)
if (wDevID >= MODM_NumDevs) return MMSYSERR_BADDEVICEID;
if (!MidiOutDev[wDevID].bEnabled) return MIDIERR_NODEVICE;
- if (midiSeq == NULL) {
+ if (MidiOutDev[wDevID].seq == NULL) {
WARN("can't play !\n");
return MIDIERR_NODEVICE;
}
@@ -886,7 +893,7 @@ static DWORD modData(WORD wDevID, DWORD dwParam)
}
if (handled) {
seq_lock();
- snd_seq_event_output_direct(midiSeq, &event);
+ snd_seq_event_output_direct(MidiOutDev[wDevID].seq, &event);
seq_unlock();
}
}
@@ -919,7 +926,7 @@ static DWORD modLongData(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
if (wDevID >= MODM_NumDevs) return MMSYSERR_BADDEVICEID;
if (!MidiOutDev[wDevID].bEnabled) return MIDIERR_NODEVICE;
- if (midiSeq == NULL) {
+ if (MidiOutDev[wDevID].seq == NULL) {
WARN("can't play !\n");
return MIDIERR_NODEVICE;
}
@@ -977,7 +984,7 @@ static DWORD modLongData(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
snd_seq_ev_set_subs(&event);
snd_seq_ev_set_sysex(&event, lpMidiHdr->dwBufferLength + len_add, lpNewData ? lpNewData : lpData);
seq_lock();
- snd_seq_event_output_direct(midiSeq, &event);
+ snd_seq_event_output_direct(MidiOutDev[wDevID].seq, &event);
seq_unlock();
HeapFree(GetProcessHeap(), 0, lpNewData);
break;
diff --git a/dlls/winealsa.drv/unixlib.h b/dlls/winealsa.drv/unixlib.h
index adac72183ee..e0ae16b97d9 100644
--- a/dlls/winealsa.drv/unixlib.h
+++ b/dlls/winealsa.drv/unixlib.h
@@ -218,7 +218,9 @@ typedef struct midi_src
MIDIHDR *lpQueueHdr;
UINT startTime;
MIDIINCAPSW caps;
+ snd_seq_t *seq;
snd_seq_addr_t addr;
+ int port_in;
} WINE_MIDIIN;
typedef struct midi_dest
@@ -227,6 +229,7 @@ typedef struct midi_dest
MIDIOPENDESC midiDesc;
WORD wFlags;
MIDIOUTCAPSW caps;
+ snd_seq_t *seq;
snd_seq_addr_t addr;
int port_out;
} WINE_MIDIOUT;
--
2.25.1
2
1