mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-05 05:18:08 +02:00
vulkan: Add a vk_device_copy_semaphore_payloads() helper
This acts as a vkQueueSubmit() except that it doesn't take any command buffers or sparse binds and it doesn't act on a queue. Instead, it just copies semaphore payloads around using a new copy_sync_payloads vfunc on vk_device. Reviewed-by: Lars-Ivar Hesselberg Simonsen <lars-ivar.simonsen@arm.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36827>
This commit is contained in:
parent
379cffc3bb
commit
f4d00c1dbf
2 changed files with 201 additions and 0 deletions
|
|
@ -25,10 +25,12 @@
|
|||
|
||||
#include "vk_alloc.h"
|
||||
#include "vk_common_entrypoints.h"
|
||||
#include "vk_fence.h"
|
||||
#include "vk_instance.h"
|
||||
#include "vk_log.h"
|
||||
#include "vk_physical_device.h"
|
||||
#include "vk_queue.h"
|
||||
#include "vk_semaphore.h"
|
||||
#include "vk_sync.h"
|
||||
#include "vk_sync_timeline.h"
|
||||
#include "vk_util.h"
|
||||
|
|
@ -628,6 +630,170 @@ vk_common_DeviceWaitIdle(VkDevice _device)
|
|||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult
|
||||
vk_device_copy_semaphore_payloads(struct vk_device *device,
|
||||
uint32_t wait_semaphore_count,
|
||||
const VkSemaphoreSubmitInfo *wait_semaphores,
|
||||
uint32_t signal_semaphore_count,
|
||||
const VkSemaphoreSubmitInfo *signal_semaphores,
|
||||
uint32_t fence_count,
|
||||
const VkFence *fences)
|
||||
{
|
||||
if (device->copy_sync_payloads == NULL)
|
||||
return VK_ERROR_FEATURE_NOT_PRESENT;
|
||||
|
||||
STACK_ARRAY(struct vk_sync_wait, waits, wait_semaphore_count);
|
||||
STACK_ARRAY(struct vk_sync_timeline_point *, wait_points,
|
||||
wait_semaphore_count);
|
||||
STACK_ARRAY(struct vk_sync *, resets, wait_semaphore_count);
|
||||
STACK_ARRAY(struct vk_sync_signal, signals,
|
||||
signal_semaphore_count + fence_count);
|
||||
STACK_ARRAY(struct vk_sync_timeline_point *, signal_points,
|
||||
signal_semaphore_count + fence_count);
|
||||
uint32_t wait_count = 0, reset_count = 0, signal_count = 0;
|
||||
VkResult result = VK_SUCCESS;
|
||||
|
||||
for (uint32_t i = 0; i < wait_semaphore_count; i++) {
|
||||
VK_FROM_HANDLE(vk_semaphore, semaphore, wait_semaphores[i].semaphore);
|
||||
|
||||
struct vk_sync_wait wait = {
|
||||
.sync = vk_semaphore_get_active_sync(semaphore),
|
||||
.stage_mask = wait_semaphores[i].stageMask,
|
||||
.wait_value = semaphore->type == VK_SEMAPHORE_TYPE_TIMELINE ?
|
||||
wait_semaphores[i].value : 0,
|
||||
};
|
||||
struct vk_sync_timeline_point *wait_point = NULL;
|
||||
VkResult result = vk_sync_wait_unwrap(device, &wait, &wait_point);
|
||||
if (unlikely(result != VK_SUCCESS))
|
||||
goto fail;
|
||||
|
||||
if (wait.sync == NULL)
|
||||
continue;
|
||||
|
||||
wait_points[wait_count] = wait_point;
|
||||
waits[wait_count] = wait;
|
||||
wait_count++;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < signal_semaphore_count; i++) {
|
||||
VK_FROM_HANDLE(vk_semaphore, semaphore, signal_semaphores[i].semaphore);
|
||||
|
||||
if (semaphore->type == VK_SEMAPHORE_TYPE_TIMELINE &&
|
||||
signal_semaphores[i].value == 0) {
|
||||
result = vk_errorf(device, VK_ERROR_UNKNOWN,
|
||||
"Tried to signal a timeline with value 0");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
struct vk_sync_signal signal = {
|
||||
.sync = vk_semaphore_get_active_sync(semaphore),
|
||||
.stage_mask = signal_semaphores[i].stageMask,
|
||||
.signal_value = semaphore->type == VK_SEMAPHORE_TYPE_TIMELINE ?
|
||||
signal_semaphores[i].value : 0,
|
||||
};
|
||||
struct vk_sync_timeline_point *signal_point = NULL;
|
||||
VkResult result = vk_sync_signal_unwrap(device, &signal, &signal_point);
|
||||
if (unlikely(result != VK_SUCCESS))
|
||||
goto fail;
|
||||
|
||||
signal_points[signal_count] = signal_point;
|
||||
signals[signal_count] = signal;
|
||||
signal_count++;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < fence_count; i++) {
|
||||
VK_FROM_HANDLE(vk_fence, fence, fences[i]);
|
||||
|
||||
struct vk_sync_signal signal = {
|
||||
.sync = vk_fence_get_active_sync(fence),
|
||||
.stage_mask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
|
||||
};
|
||||
struct vk_sync_timeline_point *signal_point = NULL;
|
||||
VkResult result = vk_sync_signal_unwrap(device, &signal, &signal_point);
|
||||
if (unlikely(result != VK_SUCCESS))
|
||||
goto fail;
|
||||
|
||||
/* Timeline fences aren't a thing */
|
||||
assert(signal_point == NULL);
|
||||
|
||||
signal_points[signal_count] = signal_point;
|
||||
signals[signal_count] = signal;
|
||||
signal_count++;
|
||||
}
|
||||
|
||||
if (wait_count == 0) {
|
||||
/* Nothing to wait on. Just signal everything */
|
||||
result = vk_sync_signal_many(device, signal_count, signals);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail;
|
||||
} else if (signal_count > 0) {
|
||||
/* Wait for time points to materialize */
|
||||
result = vk_sync_wait_many(device, wait_count, waits,
|
||||
VK_SYNC_WAIT_PENDING, UINT64_MAX);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
/* Now do the copy */
|
||||
result = device->copy_sync_payloads(device, wait_count, waits,
|
||||
signal_count, signals);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Reset any syncs which were waited on but not signaled */
|
||||
for (uint32_t i = 0; i < wait_count; i++) {
|
||||
bool was_signaled;
|
||||
for (uint32_t j = 0; j < signal_count; j++) {
|
||||
if (signals[j].sync == waits[i].sync) {
|
||||
was_signaled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!was_signaled)
|
||||
resets[reset_count++] = waits[i].sync;
|
||||
}
|
||||
|
||||
if (reset_count > 0) {
|
||||
result = vk_sync_reset_many(device, reset_count, resets);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Reset any temporary semaphores we waited on */
|
||||
for (uint32_t i = 0; i < wait_semaphore_count; i++) {
|
||||
VK_FROM_HANDLE(vk_semaphore, semaphore, wait_semaphores[i].semaphore);
|
||||
|
||||
vk_semaphore_reset_temporary(device, semaphore);
|
||||
}
|
||||
|
||||
/* Install time points */
|
||||
for (uint32_t i = 0; i < signal_count; i++) {
|
||||
if (signal_points[i] == NULL)
|
||||
continue;
|
||||
|
||||
vk_sync_timeline_point_install(device, signal_points[i]);
|
||||
|
||||
/* Installing the point consumes our reference */
|
||||
signal_points[i] = NULL;
|
||||
}
|
||||
|
||||
fail:
|
||||
|
||||
for (uint32_t i = 0; i < signal_count; i++) {
|
||||
if (signal_points[i] != NULL)
|
||||
vk_sync_timeline_point_unref(device, signal_points[i]);
|
||||
}
|
||||
|
||||
STACK_ARRAY_FINISH(waits);
|
||||
STACK_ARRAY_FINISH(wait_points);
|
||||
STACK_ARRAY_FINISH(resets);
|
||||
STACK_ARRAY_FINISH(signals);
|
||||
STACK_ARRAY_FINISH(signal_points);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
VkResult
|
||||
vk_device_get_timestamp(struct vk_device *device, VkTimeDomainKHR domain,
|
||||
uint64_t *timestamp)
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ extern "C" {
|
|||
struct vk_acceleration_structure_build_ops;
|
||||
struct vk_command_buffer_ops;
|
||||
struct vk_device_shader_ops;
|
||||
struct vk_sync_signal;
|
||||
struct vk_sync_wait;
|
||||
|
||||
enum vk_queue_submit_mode {
|
||||
/** Submits happen immediately
|
||||
|
|
@ -217,6 +219,25 @@ struct vk_device {
|
|||
/** Period of VK_TIME_DOMAIN_DEVICE_KHR */
|
||||
uint64_t device_time_domain_period;
|
||||
|
||||
/** Copies the sync payloads from the set of waits to the set of signals
|
||||
*
|
||||
* This effectively does the same as a vk_queue::driver_submit() with the
|
||||
* given set of waits and signals and no command buffers, only without the
|
||||
* queue. Instead, the driver is expected to simply copy the sync payloads
|
||||
* from the wait set, merge them together into one, and apply that to the
|
||||
* signals. After this function returns, all of the signals are now
|
||||
* equivalent to all of the waits.
|
||||
*
|
||||
* This function MUST reset all binary syncs it waits on, unless that same
|
||||
* sync is also used as a signal. Otherwise, we risk breaking timeline
|
||||
* semaphore negotiation invariants.
|
||||
*/
|
||||
VkResult (*copy_sync_payloads)(struct vk_device *device,
|
||||
uint32_t wait_count,
|
||||
const struct vk_sync_wait *waits,
|
||||
uint32_t signal_count,
|
||||
const struct vk_sync_signal *signals);
|
||||
|
||||
/* Set by vk_device_set_drm_fd() */
|
||||
struct util_sync_provider *sync;
|
||||
|
||||
|
|
@ -405,6 +426,20 @@ vk_device_check_status(struct vk_device *device)
|
|||
return result;
|
||||
}
|
||||
|
||||
/** Copy semaphore payloads to other semaphores/fences
|
||||
*
|
||||
* This is equivalent to doing VkQueueSubmit without any command buffers or
|
||||
* sparse bind operations and without implicitly synchronizing on any queue.
|
||||
*/
|
||||
VkResult
|
||||
vk_device_copy_semaphore_payloads(struct vk_device *device,
|
||||
uint32_t wait_semaphore_count,
|
||||
const VkSemaphoreSubmitInfo *wait_semaphores,
|
||||
uint32_t signal_semaphore_count,
|
||||
const VkSemaphoreSubmitInfo *signal_semaphores,
|
||||
uint32_t fence_count,
|
||||
const VkFence *fences);
|
||||
|
||||
VkResult
|
||||
vk_device_get_timestamp(struct vk_device *device, VkTimeDomainKHR domain,
|
||||
uint64_t *timestamp);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue