diff --git a/src/amd/vulkan/radv_device.c b/src/amd/vulkan/radv_device.c index b71ea73cdcc..81172a62956 100644 --- a/src/amd/vulkan/radv_device.c +++ b/src/amd/vulkan/radv_device.c @@ -86,14 +86,9 @@ static void radv_destroy_semaphore_part(struct radv_device *device, struct radv_semaphore_part *part); -static VkResult -radv_create_pthread_cond(pthread_cond_t *cond); - uint64_t radv_get_current_time(void) { - struct timespec tv; - clock_gettime(CLOCK_MONOTONIC, &tv); - return tv.tv_nsec + tv.tv_sec*1000000000ull; + return os_time_get_nano(); } static uint64_t radv_get_absolute_timeout(uint64_t timeout) @@ -2363,9 +2358,10 @@ radv_queue_init(struct radv_device *device, struct radv_queue *queue, pthread_mutex_init(&queue->pending_mutex, NULL); pthread_mutex_init(&queue->thread_mutex, NULL); - result = radv_create_pthread_cond(&queue->thread_cond); - if (result != VK_SUCCESS) + if (u_cnd_monotonic_init(&queue->thread_cond)) { + result = VK_ERROR_INITIALIZATION_FAILED; return vk_error(device->instance, result); + } queue->cond_created = true; return VK_SUCCESS; @@ -2378,11 +2374,11 @@ radv_queue_finish(struct radv_queue *queue) if (queue->cond_created) { if (queue->thread_running) { p_atomic_set(&queue->thread_exit, true); - pthread_cond_broadcast(&queue->thread_cond); + u_cnd_monotonic_broadcast(&queue->thread_cond); pthread_join(queue->submission_thread, NULL); } - pthread_cond_destroy(&queue->thread_cond); + u_cnd_monotonic_destroy(&queue->thread_cond); } pthread_mutex_destroy(&queue->pending_mutex); @@ -2560,26 +2556,6 @@ radv_device_init_dispatch(struct radv_device *device) } } -static VkResult -radv_create_pthread_cond(pthread_cond_t *cond) -{ - pthread_condattr_t condattr; - if (pthread_condattr_init(&condattr)) { - return VK_ERROR_INITIALIZATION_FAILED; - } - - if (pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC)) { - pthread_condattr_destroy(&condattr); - return VK_ERROR_INITIALIZATION_FAILED; - } - if (pthread_cond_init(cond, &condattr)) { - pthread_condattr_destroy(&condattr); - return VK_ERROR_INITIALIZATION_FAILED; - } - pthread_condattr_destroy(&condattr); - return VK_SUCCESS; -} - static VkResult check_physical_device_features(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceFeatures *features) @@ -2943,9 +2919,10 @@ VkResult radv_CreateDevice( device->mem_cache = radv_pipeline_cache_from_handle(pc); - result = radv_create_pthread_cond(&device->timeline_cond); - if (result != VK_SUCCESS) + if (u_cnd_monotonic_init(&device->timeline_cond)) { + result = VK_ERROR_INITIALIZATION_FAILED; goto fail_mem_cache; + } device->force_aniso = MIN2(16, radv_get_int_debug_option("RADV_TEX_ANISO", -1)); @@ -3022,7 +2999,7 @@ void radv_DestroyDevice( radv_destroy_shader_slabs(device); - pthread_cond_destroy(&device->timeline_cond); + u_cnd_monotonic_destroy(&device->timeline_cond); radv_bo_list_finish(&device->bo_list); free(device->thread_trace_trigger_file); @@ -4503,7 +4480,7 @@ radv_queue_submission_update_queue(struct radv_deferred_queue_submission *submis } pthread_mutex_unlock(&submission->queue->pending_mutex); - pthread_cond_broadcast(&submission->queue->device->timeline_cond); + u_cnd_monotonic_broadcast(&submission->queue->device->timeline_cond); } static VkResult @@ -4745,7 +4722,7 @@ static void* radv_queue_submission_thread_run(void *q) struct list_head processing_list; VkResult result = VK_SUCCESS; if (!submission) { - pthread_cond_wait(&queue->thread_cond, &queue->thread_mutex); + u_cnd_monotonic_wait(&queue->thread_cond, &queue->thread_mutex); continue; } pthread_mutex_unlock(&queue->thread_mutex); @@ -4813,7 +4790,7 @@ radv_queue_trigger_submission(struct radv_deferred_queue_submission *submission, queue->thread_submission = submission; pthread_mutex_unlock(&queue->thread_mutex); - pthread_cond_signal(&queue->thread_cond); + u_cnd_monotonic_signal(&queue->thread_cond); return VK_SUCCESS; } @@ -4965,7 +4942,7 @@ VkResult radv_QueueWaitIdle( pthread_mutex_lock(&queue->pending_mutex); while (!list_is_empty(&queue->pending_submissions)) { - pthread_cond_wait(&queue->device->timeline_cond, &queue->pending_mutex); + u_cnd_monotonic_wait(&queue->device->timeline_cond, &queue->pending_mutex); } pthread_mutex_unlock(&queue->pending_mutex); @@ -6136,7 +6113,7 @@ radv_timeline_wait(struct radv_device *device, struct timespec abstime; timespec_from_nsec(&abstime, abs_timeout); - pthread_cond_timedwait(&device->timeline_cond, &timeline->mutex, &abstime); + u_cnd_monotonic_timedwait(&device->timeline_cond, &timeline->mutex, &abstime); if (radv_get_current_time() >= abs_timeout && timeline->highest_submitted < value) { pthread_mutex_unlock(&timeline->mutex); @@ -6417,7 +6394,7 @@ radv_SignalSemaphore(VkDevice _device, * processed before we wake the application. This way we * ensure that any binary semaphores that are now unblocked * are usable by the application. */ - pthread_cond_broadcast(&device->timeline_cond); + u_cnd_monotonic_broadcast(&device->timeline_cond); return result; } diff --git a/src/amd/vulkan/radv_private.h b/src/amd/vulkan/radv_private.h index 6ef7801add3..e9f16deb6da 100644 --- a/src/amd/vulkan/radv_private.h +++ b/src/amd/vulkan/radv_private.h @@ -46,6 +46,7 @@ #include "c11/threads.h" #include #include "compiler/shader_enums.h" +#include "util/cnd_monotonic.h" #include "util/macros.h" #include "util/list.h" #include "util/rwlock.h" @@ -730,7 +731,7 @@ struct radv_queue { pthread_mutex_t pending_mutex; pthread_mutex_t thread_mutex; - pthread_cond_t thread_cond; + struct u_cnd_monotonic thread_cond; struct radv_deferred_queue_submission *thread_submission; pthread_t submission_thread; bool thread_exit; @@ -837,7 +838,7 @@ struct radv_device { /* Condition variable for legacy timelines, to notify waiters when a * new point gets submitted. */ - pthread_cond_t timeline_cond; + struct u_cnd_monotonic timeline_cond; /* Thread trace. */ struct radeon_cmdbuf *thread_trace_start_cs[2]; diff --git a/src/util/cnd_monotonic.h b/src/util/cnd_monotonic.h new file mode 100644 index 00000000000..983dfb8e55c --- /dev/null +++ b/src/util/cnd_monotonic.h @@ -0,0 +1,149 @@ +/************************************************************************** + * + * Copyright 2020 Lag Free Games, LLC + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef CND_MONOTONIC_H +#define CND_MONOTONIC_H + +#include "c11/threads.h" +#include "util/os_time.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct u_cnd_monotonic +{ +#ifdef _WIN32 + CONDITION_VARIABLE condvar; +#else + pthread_cond_t cond; +#endif +}; + +static inline int +u_cnd_monotonic_init(struct u_cnd_monotonic *cond) +{ + assert(cond != NULL); + +#ifdef _WIN32 + InitializeConditionVariable(&cond->condvar); + return thrd_success; +#else + int ret = thrd_error; + pthread_condattr_t condattr; + if (pthread_condattr_init(&condattr) == 0) { + if ((pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC) == 0) && + (pthread_cond_init(&cond->cond, &condattr) == 0)) { + ret = thrd_success; + } + + pthread_condattr_destroy(&condattr); + } + + return ret; +#endif +} + +static inline void +u_cnd_monotonic_destroy(struct u_cnd_monotonic *cond) +{ + assert(cond != NULL); + +#ifdef _WIN32 + // Do nothing +#else + pthread_cond_destroy(&cond->cond); +#endif +} + +static inline int +u_cnd_monotonic_broadcast(struct u_cnd_monotonic *cond) +{ + assert(cond != NULL); + +#ifdef _WIN32 + WakeAllConditionVariable(&cond->condvar); + return thrd_success; +#else + return (pthread_cond_broadcast(&cond->cond) == 0) ? thrd_success : thrd_error; +#endif +} + +static inline int +u_cnd_monotonic_signal(struct u_cnd_monotonic *cond) +{ + assert(cond != NULL); + +#ifdef _WIN32 + WakeConditionVariable(&cond->condvar); + return thrd_success; +#else + return (pthread_cond_signal(&cond->cond) == 0) ? thrd_success : thrd_error; +#endif +} + +static inline int +u_cnd_monotonic_timedwait(struct u_cnd_monotonic *cond, mtx_t *mtx, const struct timespec *abs_time) +{ + assert(cond != NULL); + assert(mtx != NULL); + assert(abs_time != NULL); + +#ifdef _WIN32 + const uint64_t future = (abs_time->tv_sec * 1000) + (abs_time->tv_nsec / 1000000); + const uint64_t now = os_time_get_nano() / 1000000; + const DWORD timeout = (future > now) ? (DWORD)(future - now) : 0; + if (SleepConditionVariableCS(&cond->condvar, mtx, timeout)) + return thrd_success; + return (GetLastError() == ERROR_TIMEOUT) ? thrd_busy : thrd_error; +#else + int rt = pthread_cond_timedwait(&cond->cond, mtx, abs_time); + if (rt == ETIMEDOUT) + return thrd_busy; + return (rt == 0) ? thrd_success : thrd_error; +#endif +} + +static inline int +u_cnd_monotonic_wait(struct u_cnd_monotonic *cond, mtx_t *mtx) +{ + assert(cond != NULL); + assert(mtx != NULL); + +#ifdef _WIN32 + SleepConditionVariableCS(&cond->condvar, mtx, INFINITE); + return thrd_success; +#else + return (pthread_cond_wait(&cond->cond, mtx) == 0) ? thrd_success : thrd_error; +#endif +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/util/meson.build b/src/util/meson.build index 188ff1d3c6c..f9f9fee9c71 100644 --- a/src/util/meson.build +++ b/src/util/meson.build @@ -33,6 +33,7 @@ files_mesa_util = files( 'blob.h', 'build_id.c', 'build_id.h', + 'cnd_monotonic.h', 'compiler.h', 'crc32.c', 'crc32.h',