mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-01-12 05:40:15 +01:00
turnip: implement timestamp fences/semaphores for kgsl backend
This gets fences and semaphores working for kgsl (minus import/export). Signed-off-by: Jonathan Marek <jonathan@marek.ca> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7000>
This commit is contained in:
parent
462d62351d
commit
8163c818e3
5 changed files with 304 additions and 100 deletions
|
|
@ -26,7 +26,6 @@
|
|||
#include <hardware/gralloc.h>
|
||||
#include <hardware/hardware.h>
|
||||
#include <hardware/hwvulkan.h>
|
||||
#include <libsync.h>
|
||||
|
||||
#include <vulkan/vk_android_native_buffer.h>
|
||||
#include <vulkan/vk_icd.h>
|
||||
|
|
@ -322,55 +321,3 @@ tu_AcquireImageANDROID(VkDevice device,
|
|||
return semaphore_result;
|
||||
return fence_result;
|
||||
}
|
||||
|
||||
VkResult
|
||||
tu_QueueSignalReleaseImageANDROID(VkQueue _queue,
|
||||
uint32_t waitSemaphoreCount,
|
||||
const VkSemaphore *pWaitSemaphores,
|
||||
VkImage image,
|
||||
int *pNativeFenceFd)
|
||||
{
|
||||
TU_FROM_HANDLE(tu_queue, queue, _queue);
|
||||
VkResult result = VK_SUCCESS;
|
||||
|
||||
if (waitSemaphoreCount == 0) {
|
||||
if (pNativeFenceFd)
|
||||
*pNativeFenceFd = -1;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
int fd = -1;
|
||||
|
||||
for (uint32_t i = 0; i < waitSemaphoreCount; ++i) {
|
||||
int tmp_fd;
|
||||
result = tu_GetSemaphoreFdKHR(
|
||||
tu_device_to_handle(queue->device),
|
||||
&(VkSemaphoreGetFdInfoKHR) {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
|
||||
.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
|
||||
.semaphore = pWaitSemaphores[i],
|
||||
},
|
||||
&tmp_fd);
|
||||
if (result != VK_SUCCESS) {
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (fd < 0)
|
||||
fd = tmp_fd;
|
||||
else if (tmp_fd >= 0) {
|
||||
sync_accumulate("tu", &fd, tmp_fd);
|
||||
close(tmp_fd);
|
||||
}
|
||||
}
|
||||
|
||||
if (pNativeFenceFd) {
|
||||
*pNativeFenceFd = fd;
|
||||
} else if (fd >= 0) {
|
||||
close(fd);
|
||||
/* We still need to do the exports, to reset the semaphores, but
|
||||
* otherwise we don't wait on them. */
|
||||
}
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,11 @@
|
|||
|
||||
#include "tu_private.h"
|
||||
|
||||
struct tu_syncobj {
|
||||
struct vk_object_base base;
|
||||
uint32_t permanent, temporary;
|
||||
};
|
||||
|
||||
static int
|
||||
tu_drm_get_param(const struct tu_physical_device *dev,
|
||||
uint32_t param,
|
||||
|
|
@ -894,3 +899,72 @@ tu_signal_fences(struct tu_device *device, struct tu_syncobj *fence1, struct tu_
|
|||
.count_handles = count
|
||||
});
|
||||
}
|
||||
|
||||
int
|
||||
tu_syncobj_to_fd(struct tu_device *device, struct tu_syncobj *sync)
|
||||
{
|
||||
struct drm_syncobj_handle handle = { .handle = sync->permanent };
|
||||
int ret;
|
||||
|
||||
ret = ioctl(device->fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &handle);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
return ret ? -1 : handle.fd;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <libsync.h>
|
||||
|
||||
VkResult
|
||||
tu_QueueSignalReleaseImageANDROID(VkQueue _queue,
|
||||
uint32_t waitSemaphoreCount,
|
||||
const VkSemaphore *pWaitSemaphores,
|
||||
VkImage image,
|
||||
int *pNativeFenceFd)
|
||||
{
|
||||
TU_FROM_HANDLE(tu_queue, queue, _queue);
|
||||
VkResult result = VK_SUCCESS;
|
||||
|
||||
if (waitSemaphoreCount == 0) {
|
||||
if (pNativeFenceFd)
|
||||
*pNativeFenceFd = -1;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
int fd = -1;
|
||||
|
||||
for (uint32_t i = 0; i < waitSemaphoreCount; ++i) {
|
||||
int tmp_fd;
|
||||
result = tu_GetSemaphoreFdKHR(
|
||||
tu_device_to_handle(queue->device),
|
||||
&(VkSemaphoreGetFdInfoKHR) {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
|
||||
.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
|
||||
.semaphore = pWaitSemaphores[i],
|
||||
},
|
||||
&tmp_fd);
|
||||
if (result != VK_SUCCESS) {
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (fd < 0)
|
||||
fd = tmp_fd;
|
||||
else if (tmp_fd >= 0) {
|
||||
sync_accumulate("tu", &fd, tmp_fd);
|
||||
close(tmp_fd);
|
||||
}
|
||||
}
|
||||
|
||||
if (pNativeFenceFd) {
|
||||
*pNativeFenceFd = fd;
|
||||
} else if (fd >= 0) {
|
||||
close(fd);
|
||||
/* We still need to do the exports, to reset the semaphores, but
|
||||
* otherwise we don't wait on them. */
|
||||
}
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -31,6 +31,12 @@
|
|||
|
||||
#include "msm_kgsl.h"
|
||||
|
||||
struct tu_syncobj {
|
||||
struct vk_object_base base;
|
||||
uint32_t timestamp;
|
||||
bool timestamp_valid;
|
||||
};
|
||||
|
||||
static int
|
||||
safe_ioctl(int fd, unsigned long request, void *arg)
|
||||
{
|
||||
|
|
@ -214,6 +220,75 @@ fail:
|
|||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
static int
|
||||
timestamp_to_fd(struct tu_queue *queue, uint32_t timestamp)
|
||||
{
|
||||
int fd;
|
||||
struct kgsl_timestamp_event event = {
|
||||
.type = KGSL_TIMESTAMP_EVENT_FENCE,
|
||||
.context_id = queue->msm_queue_id,
|
||||
.timestamp = timestamp,
|
||||
.priv = &fd,
|
||||
.len = sizeof(fd),
|
||||
};
|
||||
|
||||
int ret = safe_ioctl(queue->device->fd, IOCTL_KGSL_TIMESTAMP_EVENT, &event);
|
||||
if (ret)
|
||||
return -1;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* return true if timestamp a is greater (more recent) then b
|
||||
* this relies on timestamps never having a difference > (1<<31)
|
||||
*/
|
||||
static inline bool
|
||||
timestamp_cmp(uint32_t a, uint32_t b)
|
||||
{
|
||||
return (int32_t) (a - b) >= 0;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
max_ts(uint32_t a, uint32_t b)
|
||||
{
|
||||
return timestamp_cmp(a, b) ? a : b;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
min_ts(uint32_t a, uint32_t b)
|
||||
{
|
||||
return timestamp_cmp(a, b) ? b : a;
|
||||
}
|
||||
|
||||
static struct tu_syncobj
|
||||
sync_merge(const VkSemaphore *syncobjs, uint32_t count, bool wait_all, bool reset)
|
||||
{
|
||||
struct tu_syncobj ret;
|
||||
|
||||
ret.timestamp_valid = false;
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
TU_FROM_HANDLE(tu_syncobj, sync, syncobjs[i]);
|
||||
|
||||
/* TODO: this means the fence is unsignaled and will never become signaled */
|
||||
if (!sync->timestamp_valid)
|
||||
continue;
|
||||
|
||||
if (!ret.timestamp_valid)
|
||||
ret.timestamp = sync->timestamp;
|
||||
else if (wait_all)
|
||||
ret.timestamp = max_ts(ret.timestamp, sync->timestamp);
|
||||
else
|
||||
ret.timestamp = min_ts(ret.timestamp, sync->timestamp);
|
||||
|
||||
ret.timestamp_valid = true;
|
||||
if (reset)
|
||||
sync->timestamp_value = false;
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
VkResult
|
||||
tu_QueueSubmit(VkQueue _queue,
|
||||
uint32_t submitCount,
|
||||
|
|
@ -221,6 +296,7 @@ tu_QueueSubmit(VkQueue _queue,
|
|||
VkFence _fence)
|
||||
{
|
||||
TU_FROM_HANDLE(tu_queue, queue, _queue);
|
||||
TU_FROM_HANDLE(tu_syncobj, fence, _fence);
|
||||
VkResult result = VK_SUCCESS;
|
||||
|
||||
uint32_t max_entry_count = 0;
|
||||
|
|
@ -261,12 +337,29 @@ tu_QueueSubmit(VkQueue _queue,
|
|||
}
|
||||
}
|
||||
|
||||
struct tu_syncobj s = sync_merge(submit->pWaitSemaphores,
|
||||
submit->waitSemaphoreCount,
|
||||
true, true);
|
||||
|
||||
struct kgsl_cmd_syncpoint_timestamp ts = {
|
||||
.context_id = queue->msm_queue_id,
|
||||
.timestamp = s.timestamp,
|
||||
};
|
||||
struct kgsl_command_syncpoint sync = {
|
||||
.type = KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP,
|
||||
.size = sizeof(ts),
|
||||
.priv = (uintptr_t) &ts,
|
||||
};
|
||||
|
||||
struct kgsl_gpu_command req = {
|
||||
.flags = KGSL_CMDBATCH_SUBMIT_IB_LIST,
|
||||
.context_id = queue->msm_queue_id,
|
||||
.cmdlist = (uint64_t) (uintptr_t) cmds,
|
||||
.numcmds = entry_idx,
|
||||
.cmdsize = sizeof(struct kgsl_command_object),
|
||||
.synclist = (uintptr_t) &sync,
|
||||
.syncsize = sizeof(struct kgsl_command_syncpoint),
|
||||
.numsyncs = s.timestamp_valid ? 1 : 0,
|
||||
};
|
||||
|
||||
int ret = safe_ioctl(queue->device->physical_device->local_fd,
|
||||
|
|
@ -277,20 +370,16 @@ tu_QueueSubmit(VkQueue _queue,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < submit->signalSemaphoreCount; i++) {
|
||||
TU_FROM_HANDLE(tu_syncobj, sem, submit->pSignalSemaphores[i]);
|
||||
sem->timestamp = req.timestamp;
|
||||
sem->timestamp_valid = true;
|
||||
}
|
||||
|
||||
/* no need to merge fences as queue execution is serialized */
|
||||
if (i == submitCount - 1) {
|
||||
int fd;
|
||||
struct kgsl_timestamp_event event = {
|
||||
.type = KGSL_TIMESTAMP_EVENT_FENCE,
|
||||
.context_id = queue->msm_queue_id,
|
||||
.timestamp = req.timestamp,
|
||||
.priv = &fd,
|
||||
.len = sizeof(fd),
|
||||
};
|
||||
|
||||
int ret = safe_ioctl(queue->device->physical_device->local_fd,
|
||||
IOCTL_KGSL_TIMESTAMP_EVENT, &event);
|
||||
if (ret != 0) {
|
||||
int fd = timestamp_to_fd(queue, req.timestamp);
|
||||
if (fd < 0) {
|
||||
result = tu_device_set_lost(queue->device,
|
||||
"Failed to create sync file for timestamp: %s\n",
|
||||
strerror(errno));
|
||||
|
|
@ -300,6 +389,11 @@ tu_QueueSubmit(VkQueue _queue,
|
|||
if (queue->fence >= 0)
|
||||
close(queue->fence);
|
||||
queue->fence = fd;
|
||||
|
||||
if (fence) {
|
||||
fence->timestamp = req.timestamp;
|
||||
fence->timestamp_valid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
fail:
|
||||
|
|
@ -308,6 +402,30 @@ fail:
|
|||
return result;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
sync_create(VkDevice _device,
|
||||
bool signaled,
|
||||
bool fence,
|
||||
const VkAllocationCallbacks *pAllocator,
|
||||
void **p_sync)
|
||||
{
|
||||
TU_FROM_HANDLE(tu_device, device, _device);
|
||||
|
||||
struct tu_syncobj *sync =
|
||||
vk_object_alloc(&device->vk, pAllocator, sizeof(*sync),
|
||||
fence ? VK_OBJECT_TYPE_FENCE : VK_OBJECT_TYPE_SEMAPHORE);
|
||||
if (!sync)
|
||||
return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
|
||||
if (signaled)
|
||||
tu_finishme("CREATE FENCE SIGNALED");
|
||||
|
||||
sync->timestamp_valid = false;
|
||||
*p_sync = sync;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult
|
||||
tu_ImportSemaphoreFdKHR(VkDevice _device,
|
||||
const VkImportSemaphoreFdInfoKHR *pImportSemaphoreFdInfo)
|
||||
|
|
@ -326,21 +444,26 @@ tu_GetSemaphoreFdKHR(VkDevice _device,
|
|||
}
|
||||
|
||||
VkResult
|
||||
tu_CreateSemaphore(VkDevice _device,
|
||||
tu_CreateSemaphore(VkDevice device,
|
||||
const VkSemaphoreCreateInfo *pCreateInfo,
|
||||
const VkAllocationCallbacks *pAllocator,
|
||||
VkSemaphore *pSemaphore)
|
||||
{
|
||||
tu_finishme("CreateSemaphore");
|
||||
return VK_SUCCESS;
|
||||
return sync_create(device, false, false, pAllocator, (void**) pSemaphore);
|
||||
}
|
||||
|
||||
void
|
||||
tu_DestroySemaphore(VkDevice _device,
|
||||
VkSemaphore _semaphore,
|
||||
VkSemaphore semaphore,
|
||||
const VkAllocationCallbacks *pAllocator)
|
||||
{
|
||||
tu_finishme("DestroySemaphore");
|
||||
TU_FROM_HANDLE(tu_device, device, _device);
|
||||
TU_FROM_HANDLE(tu_syncobj, sync, semaphore);
|
||||
|
||||
if (!sync)
|
||||
return;
|
||||
|
||||
vk_object_free(&device->vk, pAllocator, sync);
|
||||
}
|
||||
|
||||
VkResult
|
||||
|
|
@ -363,43 +486,84 @@ tu_GetFenceFdKHR(VkDevice _device,
|
|||
}
|
||||
|
||||
VkResult
|
||||
tu_CreateFence(VkDevice _device,
|
||||
const VkFenceCreateInfo *pCreateInfo,
|
||||
tu_CreateFence(VkDevice device,
|
||||
const VkFenceCreateInfo *info,
|
||||
const VkAllocationCallbacks *pAllocator,
|
||||
VkFence *pFence)
|
||||
{
|
||||
tu_finishme("CreateFence");
|
||||
return VK_SUCCESS;
|
||||
return sync_create(device, info->flags & VK_FENCE_CREATE_SIGNALED_BIT, true,
|
||||
pAllocator, (void**) pFence);
|
||||
}
|
||||
|
||||
void
|
||||
tu_DestroyFence(VkDevice _device, VkFence _fence, const VkAllocationCallbacks *pAllocator)
|
||||
tu_DestroyFence(VkDevice _device, VkFence fence, const VkAllocationCallbacks *pAllocator)
|
||||
{
|
||||
tu_finishme("DestroyFence");
|
||||
TU_FROM_HANDLE(tu_device, device, _device);
|
||||
TU_FROM_HANDLE(tu_syncobj, sync, fence);
|
||||
|
||||
if (!sync)
|
||||
return;
|
||||
|
||||
vk_object_free(&device->vk, pAllocator, sync);
|
||||
}
|
||||
|
||||
VkResult
|
||||
tu_WaitForFences(VkDevice _device,
|
||||
uint32_t fenceCount,
|
||||
uint32_t count,
|
||||
const VkFence *pFences,
|
||||
VkBool32 waitAll,
|
||||
uint64_t timeout)
|
||||
{
|
||||
tu_finishme("WaitForFences");
|
||||
TU_FROM_HANDLE(tu_device, device, _device);
|
||||
struct tu_syncobj s = sync_merge((const VkSemaphore*) pFences, count, waitAll, false);
|
||||
|
||||
if (!s.timestamp_valid)
|
||||
return VK_SUCCESS;
|
||||
|
||||
int ret = ioctl(device->fd, IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID,
|
||||
&(struct kgsl_device_waittimestamp_ctxtid) {
|
||||
.context_id = device->queues[0]->msm_queue_id,
|
||||
.timestamp = s.timestamp,
|
||||
.timeout = timeout / 1000000,
|
||||
});
|
||||
if (ret) {
|
||||
assert(errno == ETIME);
|
||||
return VK_TIMEOUT;
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult
|
||||
tu_ResetFences(VkDevice _device, uint32_t fenceCount, const VkFence *pFences)
|
||||
tu_ResetFences(VkDevice _device, uint32_t count, const VkFence *pFences)
|
||||
{
|
||||
tu_finishme("ResetFences");
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
TU_FROM_HANDLE(tu_syncobj, sync, pFences[i]);
|
||||
sync->timestamp_valid = false;
|
||||
}
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult
|
||||
tu_GetFenceStatus(VkDevice _device, VkFence _fence)
|
||||
{
|
||||
tu_finishme("GetFenceStatus");
|
||||
TU_FROM_HANDLE(tu_device, device, _device);
|
||||
TU_FROM_HANDLE(tu_syncobj, sync, _fence);
|
||||
|
||||
if (!sync->timestamp_valid)
|
||||
return VK_NOT_READY;
|
||||
|
||||
int ret = ioctl(device->fd, IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID,
|
||||
&(struct kgsl_device_waittimestamp_ctxtid) {
|
||||
.context_id = device->queues[0]->msm_queue_id,
|
||||
.timestamp = sync->timestamp,
|
||||
.timeout = 0,
|
||||
});
|
||||
if (ret) {
|
||||
assert(errno == ETIME);
|
||||
return VK_NOT_READY;
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -409,3 +573,35 @@ tu_signal_fences(struct tu_device *device, struct tu_syncobj *fence1, struct tu_
|
|||
tu_finishme("tu_signal_fences");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
tu_syncobj_to_fd(struct tu_device *device, struct tu_syncobj *sync)
|
||||
{
|
||||
tu_finishme("tu_syncobj_to_fd");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
VkResult
|
||||
tu_QueueSignalReleaseImageANDROID(VkQueue _queue,
|
||||
uint32_t waitSemaphoreCount,
|
||||
const VkSemaphore *pWaitSemaphores,
|
||||
VkImage image,
|
||||
int *pNativeFenceFd)
|
||||
{
|
||||
TU_FROM_HANDLE(tu_queue, queue, _queue);
|
||||
if (!pNativeFenceFd)
|
||||
return VK_SUCCESS;
|
||||
|
||||
struct tu_syncobj s = sync_merge(pWaitSemaphores, waitSemaphoreCount, true, true);
|
||||
|
||||
if (!s.timestamp_valid) {
|
||||
*pNativeFenceFd = -1;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
*pNativeFenceFd = timestamp_to_fd(queue, s.timestamp);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -289,10 +289,7 @@ struct tu_pipeline_key
|
|||
|
||||
#define TU_MAX_QUEUE_FAMILIES 1
|
||||
|
||||
struct tu_syncobj {
|
||||
struct vk_object_base base;
|
||||
uint32_t permanent, temporary;
|
||||
};
|
||||
struct tu_syncobj;
|
||||
|
||||
struct tu_queue
|
||||
{
|
||||
|
|
@ -1546,6 +1543,9 @@ tu_drm_submitqueue_close(const struct tu_device *dev, uint32_t queue_id);
|
|||
int
|
||||
tu_signal_fences(struct tu_device *device, struct tu_syncobj *fence1, struct tu_syncobj *fence2);
|
||||
|
||||
int
|
||||
tu_syncobj_to_fd(struct tu_device *device, struct tu_syncobj *sync);
|
||||
|
||||
#define TU_DEFINE_HANDLE_CASTS(__tu_type, __VkType) \
|
||||
\
|
||||
static inline struct __tu_type *__tu_type##_from_handle(__VkType _handle) \
|
||||
|
|
|
|||
|
|
@ -259,19 +259,6 @@ tu_DisplayPowerControlEXT(VkDevice _device,
|
|||
display_power_info);
|
||||
}
|
||||
|
||||
static int
|
||||
import_syncobj(int fd, uint32_t syncobj)
|
||||
{
|
||||
struct drm_syncobj_handle handle = { .handle = syncobj };
|
||||
int ret;
|
||||
|
||||
ret = ioctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &handle);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
return ret ? -1 : handle.fd;
|
||||
}
|
||||
|
||||
VkResult
|
||||
tu_RegisterDeviceEventEXT(VkDevice _device,
|
||||
const VkDeviceEventInfoEXT *device_event_info,
|
||||
|
|
@ -287,7 +274,7 @@ tu_RegisterDeviceEventEXT(VkDevice _device,
|
|||
|
||||
TU_FROM_HANDLE(tu_syncobj, fence, *_fence);
|
||||
|
||||
int sync_fd = import_syncobj(device->fd, fence->permanent);
|
||||
int sync_fd = tu_syncobj_to_fd(device, fence);
|
||||
if (sync_fd >= 0) {
|
||||
ret = wsi_register_device_event(_device,
|
||||
&device->physical_device->wsi_device,
|
||||
|
|
@ -323,7 +310,7 @@ tu_RegisterDisplayEventEXT(VkDevice _device,
|
|||
|
||||
TU_FROM_HANDLE(tu_syncobj, fence, *_fence);
|
||||
|
||||
int sync_fd = import_syncobj(device->fd, fence->permanent);
|
||||
int sync_fd = tu_syncobj_to_fd(device, fence);
|
||||
if (sync_fd >= 0) {
|
||||
ret = wsi_register_display_event(_device,
|
||||
&device->physical_device->wsi_device,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue