libs/vkd3d: Wait for GPU fences in worker thread.

This could be implemented without a worker thread, if event objects
would be tightly coupled with ID3D12Fences.
This commit is contained in:
Józef Kucia 2016-10-08 14:31:57 +02:00
parent 2f76260857
commit 2a7b614278
3 changed files with 88 additions and 15 deletions

View File

@ -24,6 +24,51 @@
#include "vkd3d_private.h" #include "vkd3d_private.h"
/* Fence worker thread */ /* Fence worker thread */
static void vkd3d_wait_for_gpu_fences(struct vkd3d_fence_worker *worker)
{
struct d3d12_device *device = worker->device;
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
unsigned int i, j;
HRESULT hr;
int vr;
if (!worker->fence_count)
return;
vr = VK_CALL(vkWaitForFences(device->vk_device,
worker->fence_count, worker->vk_fences, VK_FALSE, 0));
if (vr == VK_TIMEOUT)
return;
if (vr != VK_SUCCESS)
{
ERR("Failed to wait for Vulkan fences, vr %d.\n", vr);
return;
}
for (i = 0, j = 0; i < worker->fence_count; ++i)
{
if (!(vr = VK_CALL(vkGetFenceStatus(device->vk_device, worker->vk_fences[i]))))
{
struct vkd3d_waiting_fence *current = &worker->fences[i];
if (FAILED(hr = ID3D12Fence_Signal(current->fence, current->value)))
ERR("Failed to signal D3D12 fence, hr %d.\n", hr);
VK_CALL(vkDestroyFence(device->vk_device, worker->vk_fences[i], NULL));
continue;
}
if (vr != VK_NOT_READY)
ERR("Failed to get Vulkan fence status, vr %d.\n", vr);
if (i != j)
{
worker->vk_fences[j] = worker->vk_fences[i];
worker->fences[j] = worker->fences[i];
}
++j;
}
worker->fence_count = j;
}
static void *vkd3d_fence_worker_main(void *arg) static void *vkd3d_fence_worker_main(void *arg)
{ {
struct vkd3d_fence_worker *worker = arg; struct vkd3d_fence_worker *worker = arg;
@ -37,32 +82,46 @@ static void *vkd3d_fence_worker_main(void *arg)
return NULL; return NULL;
} }
if (worker->should_exit) if (worker->should_exit && !worker->fence_count)
{ {
pthread_mutex_unlock(&worker->mutex); pthread_mutex_unlock(&worker->mutex);
break; break;
} }
if ((rc = pthread_cond_wait(&worker->cond, &worker->mutex))) if (!worker->fence_count)
{ {
ERR("Failed to wait on condition variable, error %d.\n", rc); if ((rc = pthread_cond_wait(&worker->cond, &worker->mutex)))
pthread_mutex_unlock(&worker->mutex); {
return NULL; ERR("Failed to wait on condition variable, error %d.\n", rc);
pthread_mutex_unlock(&worker->mutex);
return NULL;
}
} }
vkd3d_wait_for_gpu_fences(worker);
pthread_mutex_unlock(&worker->mutex); pthread_mutex_unlock(&worker->mutex);
} }
return NULL; return NULL;
} }
HRESULT vkd3d_start_fence_worker(struct vkd3d_fence_worker *worker) HRESULT vkd3d_start_fence_worker(struct vkd3d_fence_worker *worker,
struct d3d12_device *device)
{ {
int rc; int rc;
TRACE("worker %p.\n", worker); TRACE("worker %p.\n", worker);
worker->should_exit = false; worker->should_exit = false;
worker->device = device;
worker->fence_count = 0;
worker->vk_fences = NULL;
worker->vk_fences_size = 0;
worker->fences = NULL;
worker->fences_size = 0;
if ((rc = pthread_mutex_init(&worker->mutex, NULL))) if ((rc = pthread_mutex_init(&worker->mutex, NULL)))
{ {
@ -114,6 +173,9 @@ HRESULT vkd3d_stop_fence_worker(struct vkd3d_fence_worker *worker)
pthread_mutex_destroy(&worker->mutex); pthread_mutex_destroy(&worker->mutex);
pthread_cond_destroy(&worker->cond); pthread_cond_destroy(&worker->cond);
vkd3d_free(worker->vk_fences);
vkd3d_free(worker->fences);
return S_OK; return S_OK;
} }

View File

@ -1091,7 +1091,7 @@ static HRESULT d3d12_device_init(struct d3d12_device *device,
device->signal_event = create_info->signal_event_pfn; device->signal_event = create_info->signal_event_pfn;
if (FAILED(hr = vkd3d_start_fence_worker(&device->fence_worker))) if (FAILED(hr = vkd3d_start_fence_worker(&device->fence_worker, device)))
{ {
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
VK_CALL(vkDestroyDevice(device->vk_device, NULL)); VK_CALL(vkDestroyDevice(device->vk_device, NULL));

View File

@ -45,21 +45,28 @@ struct vkd3d_instance
struct vkd3d_vk_instance_procs vk_procs; struct vkd3d_vk_instance_procs vk_procs;
}; };
struct vkd3d_waiting_event
{
UINT64 value;
HANDLE event;
};
struct vkd3d_fence_worker struct vkd3d_fence_worker
{ {
pthread_t thread; pthread_t thread;
pthread_mutex_t mutex; pthread_mutex_t mutex;
pthread_cond_t cond; pthread_cond_t cond;
bool should_exit; bool should_exit;
size_t fence_count;
VkFence *vk_fences;
size_t vk_fences_size;
struct vkd3d_waiting_fence
{
ID3D12Fence *fence;
UINT64 value;
} *fences;
size_t fences_size;
struct d3d12_device *device;
}; };
HRESULT vkd3d_start_fence_worker(struct vkd3d_fence_worker *worker) DECLSPEC_HIDDEN; HRESULT vkd3d_start_fence_worker(struct vkd3d_fence_worker *worker,
struct d3d12_device *device) DECLSPEC_HIDDEN;
HRESULT vkd3d_stop_fence_worker(struct vkd3d_fence_worker *worker) DECLSPEC_HIDDEN; HRESULT vkd3d_stop_fence_worker(struct vkd3d_fence_worker *worker) DECLSPEC_HIDDEN;
/* ID3D12Fence */ /* ID3D12Fence */
@ -71,7 +78,11 @@ struct d3d12_fence
UINT64 value; UINT64 value;
pthread_mutex_t mutex; pthread_mutex_t mutex;
struct vkd3d_waiting_event *events; struct vkd3d_waiting_event
{
UINT64 value;
HANDLE event;
} *events;
size_t events_size; size_t events_size;
size_t event_count; size_t event_count;