turnip: Move remaining drm code to tu_drm.c

This moves the semaphore implementation and tu_QueueSubmit to
tu_drm.c, such that that's the only file including xf86drm.h and
msm_drm.h.  This way, the entire kernel interface is contained in
tu_drm.c

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5999>
This commit is contained in:
Kristian H. Kristensen 2020-07-20 12:47:57 -07:00 committed by Marge Bot
parent 7dfeae1a45
commit 4b9c0cd821
2 changed files with 378 additions and 383 deletions

View File

@ -47,10 +47,6 @@
/* for fd_get_driver/device_uuid() */
#include "freedreno/common/freedreno_uuid.h"
static void
tu_semaphore_remove_temp(struct tu_device *device,
struct tu_semaphore *sem);
static int
tu_device_get_cache_uuid(uint16_t family, void *uuid)
{
@ -1328,183 +1324,6 @@ tu_GetDeviceQueue(VkDevice _device,
tu_GetDeviceQueue2(_device, &info, pQueue);
}
static VkResult
tu_get_semaphore_syncobjs(const VkSemaphore *sems,
uint32_t sem_count,
bool wait,
struct drm_msm_gem_submit_syncobj **out,
uint32_t *out_count)
{
uint32_t syncobj_count = 0;
struct drm_msm_gem_submit_syncobj *syncobjs;
for (uint32_t i = 0; i < sem_count; ++i) {
TU_FROM_HANDLE(tu_semaphore, sem, sems[i]);
struct tu_semaphore_part *part =
sem->temporary.kind != TU_SEMAPHORE_NONE ?
&sem->temporary : &sem->permanent;
if (part->kind == TU_SEMAPHORE_SYNCOBJ)
++syncobj_count;
}
*out = NULL;
*out_count = syncobj_count;
if (!syncobj_count)
return VK_SUCCESS;
*out = syncobjs = calloc(syncobj_count, sizeof (*syncobjs));
if (!syncobjs)
return VK_ERROR_OUT_OF_HOST_MEMORY;
for (uint32_t i = 0, j = 0; i < sem_count; ++i) {
TU_FROM_HANDLE(tu_semaphore, sem, sems[i]);
struct tu_semaphore_part *part =
sem->temporary.kind != TU_SEMAPHORE_NONE ?
&sem->temporary : &sem->permanent;
if (part->kind == TU_SEMAPHORE_SYNCOBJ) {
syncobjs[j].handle = part->syncobj;
syncobjs[j].flags = wait ? MSM_SUBMIT_SYNCOBJ_RESET : 0;
++j;
}
}
return VK_SUCCESS;
}
static void
tu_semaphores_remove_temp(struct tu_device *device,
const VkSemaphore *sems,
uint32_t sem_count)
{
for (uint32_t i = 0; i < sem_count; ++i) {
TU_FROM_HANDLE(tu_semaphore, sem, sems[i]);
tu_semaphore_remove_temp(device, sem);
}
}
VkResult
tu_QueueSubmit(VkQueue _queue,
uint32_t submitCount,
const VkSubmitInfo *pSubmits,
VkFence _fence)
{
TU_FROM_HANDLE(tu_queue, queue, _queue);
VkResult result;
for (uint32_t i = 0; i < submitCount; ++i) {
const VkSubmitInfo *submit = pSubmits + i;
const bool last_submit = (i == submitCount - 1);
struct drm_msm_gem_submit_syncobj *in_syncobjs = NULL, *out_syncobjs = NULL;
uint32_t nr_in_syncobjs, nr_out_syncobjs;
struct tu_bo_list bo_list;
tu_bo_list_init(&bo_list);
result = tu_get_semaphore_syncobjs(pSubmits[i].pWaitSemaphores,
pSubmits[i].waitSemaphoreCount,
false, &in_syncobjs, &nr_in_syncobjs);
if (result != VK_SUCCESS) {
return tu_device_set_lost(queue->device,
"failed to allocate space for semaphore submission\n");
}
result = tu_get_semaphore_syncobjs(pSubmits[i].pSignalSemaphores,
pSubmits[i].signalSemaphoreCount,
false, &out_syncobjs, &nr_out_syncobjs);
if (result != VK_SUCCESS) {
free(in_syncobjs);
return tu_device_set_lost(queue->device,
"failed to allocate space for semaphore submission\n");
}
uint32_t entry_count = 0;
for (uint32_t j = 0; j < submit->commandBufferCount; ++j) {
TU_FROM_HANDLE(tu_cmd_buffer, cmdbuf, submit->pCommandBuffers[j]);
entry_count += cmdbuf->cs.entry_count;
}
struct drm_msm_gem_submit_cmd cmds[entry_count];
uint32_t entry_idx = 0;
for (uint32_t j = 0; j < submit->commandBufferCount; ++j) {
TU_FROM_HANDLE(tu_cmd_buffer, cmdbuf, submit->pCommandBuffers[j]);
struct tu_cs *cs = &cmdbuf->cs;
for (unsigned i = 0; i < cs->entry_count; ++i, ++entry_idx) {
cmds[entry_idx].type = MSM_SUBMIT_CMD_BUF;
cmds[entry_idx].submit_idx =
tu_bo_list_add(&bo_list, cs->entries[i].bo,
MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_DUMP);
cmds[entry_idx].submit_offset = cs->entries[i].offset;
cmds[entry_idx].size = cs->entries[i].size;
cmds[entry_idx].pad = 0;
cmds[entry_idx].nr_relocs = 0;
cmds[entry_idx].relocs = 0;
}
tu_bo_list_merge(&bo_list, &cmdbuf->bo_list);
}
uint32_t flags = MSM_PIPE_3D0;
if (nr_in_syncobjs) {
flags |= MSM_SUBMIT_SYNCOBJ_IN;
}
if (nr_out_syncobjs) {
flags |= MSM_SUBMIT_SYNCOBJ_OUT;
}
if (last_submit) {
flags |= MSM_SUBMIT_FENCE_FD_OUT;
}
struct drm_msm_gem_submit req = {
.flags = flags,
.queueid = queue->msm_queue_id,
.bos = (uint64_t)(uintptr_t) bo_list.bo_infos,
.nr_bos = bo_list.count,
.cmds = (uint64_t)(uintptr_t)cmds,
.nr_cmds = entry_count,
.in_syncobjs = (uint64_t)(uintptr_t)in_syncobjs,
.out_syncobjs = (uint64_t)(uintptr_t)out_syncobjs,
.nr_in_syncobjs = nr_in_syncobjs,
.nr_out_syncobjs = nr_out_syncobjs,
.syncobj_stride = sizeof(struct drm_msm_gem_submit_syncobj),
};
int ret = drmCommandWriteRead(queue->device->physical_device->local_fd,
DRM_MSM_GEM_SUBMIT,
&req, sizeof(req));
if (ret) {
free(in_syncobjs);
free(out_syncobjs);
return tu_device_set_lost(queue->device, "submit failed: %s\n",
strerror(errno));
}
tu_bo_list_destroy(&bo_list);
free(in_syncobjs);
free(out_syncobjs);
tu_semaphores_remove_temp(queue->device, pSubmits[i].pWaitSemaphores,
pSubmits[i].waitSemaphoreCount);
if (last_submit) {
/* no need to merge fences as queue execution is serialized */
tu_fence_update_fd(&queue->submit_fence, req.fence_fd);
} else if (last_submit) {
close(req.fence_fd);
}
}
if (_fence != VK_NULL_HANDLE) {
TU_FROM_HANDLE(tu_fence, fence, _fence);
tu_fence_copy(fence, &queue->submit_fence);
}
return VK_SUCCESS;
}
VkResult
tu_QueueWaitIdle(VkQueue _queue)
{
@ -1911,80 +1730,6 @@ tu_QueueBindSparse(VkQueue _queue,
return VK_SUCCESS;
}
// Queue semaphore functions
static void
tu_semaphore_part_destroy(struct tu_device *device,
struct tu_semaphore_part *part)
{
switch(part->kind) {
case TU_SEMAPHORE_NONE:
break;
case TU_SEMAPHORE_SYNCOBJ:
drmSyncobjDestroy(device->physical_device->local_fd, part->syncobj);
break;
}
part->kind = TU_SEMAPHORE_NONE;
}
static void
tu_semaphore_remove_temp(struct tu_device *device,
struct tu_semaphore *sem)
{
if (sem->temporary.kind != TU_SEMAPHORE_NONE) {
tu_semaphore_part_destroy(device, &sem->temporary);
}
}
VkResult
tu_CreateSemaphore(VkDevice _device,
const VkSemaphoreCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkSemaphore *pSemaphore)
{
TU_FROM_HANDLE(tu_device, device, _device);
struct tu_semaphore *sem =
vk_object_alloc(&device->vk, pAllocator, sizeof(*sem),
VK_OBJECT_TYPE_SEMAPHORE);
if (!sem)
return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
const VkExportSemaphoreCreateInfo *export =
vk_find_struct_const(pCreateInfo->pNext, EXPORT_SEMAPHORE_CREATE_INFO);
VkExternalSemaphoreHandleTypeFlags handleTypes =
export ? export->handleTypes : 0;
sem->permanent.kind = TU_SEMAPHORE_NONE;
sem->temporary.kind = TU_SEMAPHORE_NONE;
if (handleTypes) {
if (drmSyncobjCreate(device->physical_device->local_fd, 0, &sem->permanent.syncobj) < 0) {
vk_free2(&device->vk.alloc, pAllocator, sem);
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
sem->permanent.kind = TU_SEMAPHORE_SYNCOBJ;
}
*pSemaphore = tu_semaphore_to_handle(sem);
return VK_SUCCESS;
}
void
tu_DestroySemaphore(VkDevice _device,
VkSemaphore _semaphore,
const VkAllocationCallbacks *pAllocator)
{
TU_FROM_HANDLE(tu_device, device, _device);
TU_FROM_HANDLE(tu_semaphore, sem, _semaphore);
if (!_semaphore)
return;
tu_semaphore_part_destroy(device, &sem->permanent);
tu_semaphore_part_destroy(device, &sem->temporary);
vk_object_free(&device->vk, pAllocator, sem);
}
VkResult
tu_CreateEvent(VkDevice _device,
@ -2344,134 +2089,6 @@ tu_GetFenceFdKHR(VkDevice _device,
return VK_SUCCESS;
}
VkResult
tu_ImportSemaphoreFdKHR(VkDevice _device,
const VkImportSemaphoreFdInfoKHR *pImportSemaphoreFdInfo)
{
TU_FROM_HANDLE(tu_device, device, _device);
TU_FROM_HANDLE(tu_semaphore, sem, pImportSemaphoreFdInfo->semaphore);
int ret;
struct tu_semaphore_part *dst = NULL;
if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) {
dst = &sem->temporary;
} else {
dst = &sem->permanent;
}
uint32_t syncobj = dst->kind == TU_SEMAPHORE_SYNCOBJ ? dst->syncobj : 0;
switch(pImportSemaphoreFdInfo->handleType) {
case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT: {
uint32_t old_syncobj = syncobj;
ret = drmSyncobjFDToHandle(device->physical_device->local_fd, pImportSemaphoreFdInfo->fd, &syncobj);
if (ret == 0) {
close(pImportSemaphoreFdInfo->fd);
if (old_syncobj)
drmSyncobjDestroy(device->physical_device->local_fd, old_syncobj);
}
break;
}
case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT: {
if (!syncobj) {
ret = drmSyncobjCreate(device->physical_device->local_fd, 0, &syncobj);
if (ret)
break;
}
if (pImportSemaphoreFdInfo->fd == -1) {
ret = drmSyncobjSignal(device->physical_device->local_fd, &syncobj, 1);
} else {
ret = drmSyncobjImportSyncFile(device->physical_device->local_fd, syncobj, pImportSemaphoreFdInfo->fd);
}
if (!ret)
close(pImportSemaphoreFdInfo->fd);
break;
}
default:
unreachable("Unhandled semaphore handle type");
}
if (ret) {
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
}
dst->syncobj = syncobj;
dst->kind = TU_SEMAPHORE_SYNCOBJ;
return VK_SUCCESS;
}
VkResult
tu_GetSemaphoreFdKHR(VkDevice _device,
const VkSemaphoreGetFdInfoKHR *pGetFdInfo,
int *pFd)
{
TU_FROM_HANDLE(tu_device, device, _device);
TU_FROM_HANDLE(tu_semaphore, sem, pGetFdInfo->semaphore);
int ret;
uint32_t syncobj_handle;
if (sem->temporary.kind != TU_SEMAPHORE_NONE) {
assert(sem->temporary.kind == TU_SEMAPHORE_SYNCOBJ);
syncobj_handle = sem->temporary.syncobj;
} else {
assert(sem->permanent.kind == TU_SEMAPHORE_SYNCOBJ);
syncobj_handle = sem->permanent.syncobj;
}
switch(pGetFdInfo->handleType) {
case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:
ret = drmSyncobjHandleToFD(device->physical_device->local_fd, syncobj_handle, pFd);
break;
case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:
ret = drmSyncobjExportSyncFile(device->physical_device->local_fd, syncobj_handle, pFd);
if (!ret) {
if (sem->temporary.kind != TU_SEMAPHORE_NONE) {
tu_semaphore_part_destroy(device, &sem->temporary);
} else {
drmSyncobjReset(device->physical_device->local_fd, &syncobj_handle, 1);
}
}
break;
default:
unreachable("Unhandled semaphore handle type");
}
if (ret)
return vk_error(device->instance, VK_ERROR_INVALID_EXTERNAL_HANDLE);
return VK_SUCCESS;
}
static bool tu_has_syncobj(struct tu_physical_device *pdev)
{
uint64_t value;
if (drmGetCap(pdev->local_fd, DRM_CAP_SYNCOBJ, &value))
return false;
return value && pdev->msm_major_version == 1 && pdev->msm_minor_version >= 6;
}
void
tu_GetPhysicalDeviceExternalSemaphoreProperties(
VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo,
VkExternalSemaphoreProperties *pExternalSemaphoreProperties)
{
TU_FROM_HANDLE(tu_physical_device, pdev, physicalDevice);
if (tu_has_syncobj(pdev) &&
(pExternalSemaphoreInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT ||
pExternalSemaphoreInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT)) {
pExternalSemaphoreProperties->exportFromImportedHandleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT | VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
pExternalSemaphoreProperties->compatibleHandleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT | VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
pExternalSemaphoreProperties->externalSemaphoreFeatures = VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
} else {
pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
pExternalSemaphoreProperties->compatibleHandleTypes = 0;
pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
}
}
void
tu_GetPhysicalDeviceExternalFenceProperties(
VkPhysicalDevice physicalDevice,

View File

@ -31,6 +31,8 @@
#include <sys/mman.h>
#include <xf86drm.h>
#include "vk_util.h"
#include "drm-uapi/msm_drm.h"
static int
@ -386,3 +388,379 @@ tu_enumerate_devices(struct tu_instance *instance)
return result;
}
// Queue semaphore functions
static void
tu_semaphore_part_destroy(struct tu_device *device,
struct tu_semaphore_part *part)
{
switch(part->kind) {
case TU_SEMAPHORE_NONE:
break;
case TU_SEMAPHORE_SYNCOBJ:
drmSyncobjDestroy(device->physical_device->local_fd, part->syncobj);
break;
}
part->kind = TU_SEMAPHORE_NONE;
}
static void
tu_semaphore_remove_temp(struct tu_device *device,
struct tu_semaphore *sem)
{
if (sem->temporary.kind != TU_SEMAPHORE_NONE) {
tu_semaphore_part_destroy(device, &sem->temporary);
}
}
static VkResult
tu_get_semaphore_syncobjs(const VkSemaphore *sems,
uint32_t sem_count,
bool wait,
struct drm_msm_gem_submit_syncobj **out,
uint32_t *out_count)
{
uint32_t syncobj_count = 0;
struct drm_msm_gem_submit_syncobj *syncobjs;
for (uint32_t i = 0; i < sem_count; ++i) {
TU_FROM_HANDLE(tu_semaphore, sem, sems[i]);
struct tu_semaphore_part *part =
sem->temporary.kind != TU_SEMAPHORE_NONE ?
&sem->temporary : &sem->permanent;
if (part->kind == TU_SEMAPHORE_SYNCOBJ)
++syncobj_count;
}
*out = NULL;
*out_count = syncobj_count;
if (!syncobj_count)
return VK_SUCCESS;
*out = syncobjs = calloc(syncobj_count, sizeof (*syncobjs));
if (!syncobjs)
return VK_ERROR_OUT_OF_HOST_MEMORY;
for (uint32_t i = 0, j = 0; i < sem_count; ++i) {
TU_FROM_HANDLE(tu_semaphore, sem, sems[i]);
struct tu_semaphore_part *part =
sem->temporary.kind != TU_SEMAPHORE_NONE ?
&sem->temporary : &sem->permanent;
if (part->kind == TU_SEMAPHORE_SYNCOBJ) {
syncobjs[j].handle = part->syncobj;
syncobjs[j].flags = wait ? MSM_SUBMIT_SYNCOBJ_RESET : 0;
++j;
}
}
return VK_SUCCESS;
}
static void
tu_semaphores_remove_temp(struct tu_device *device,
const VkSemaphore *sems,
uint32_t sem_count)
{
for (uint32_t i = 0; i < sem_count; ++i) {
TU_FROM_HANDLE(tu_semaphore, sem, sems[i]);
tu_semaphore_remove_temp(device, sem);
}
}
VkResult
tu_CreateSemaphore(VkDevice _device,
const VkSemaphoreCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkSemaphore *pSemaphore)
{
TU_FROM_HANDLE(tu_device, device, _device);
struct tu_semaphore *sem =
vk_object_alloc(&device->vk, pAllocator, sizeof(*sem),
VK_OBJECT_TYPE_SEMAPHORE);
if (!sem)
return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
const VkExportSemaphoreCreateInfo *export =
vk_find_struct_const(pCreateInfo->pNext, EXPORT_SEMAPHORE_CREATE_INFO);
VkExternalSemaphoreHandleTypeFlags handleTypes =
export ? export->handleTypes : 0;
sem->permanent.kind = TU_SEMAPHORE_NONE;
sem->temporary.kind = TU_SEMAPHORE_NONE;
if (handleTypes) {
if (drmSyncobjCreate(device->physical_device->local_fd, 0, &sem->permanent.syncobj) < 0) {
vk_free2(&device->vk.alloc, pAllocator, sem);
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
sem->permanent.kind = TU_SEMAPHORE_SYNCOBJ;
}
*pSemaphore = tu_semaphore_to_handle(sem);
return VK_SUCCESS;
}
void
tu_DestroySemaphore(VkDevice _device,
VkSemaphore _semaphore,
const VkAllocationCallbacks *pAllocator)
{
TU_FROM_HANDLE(tu_device, device, _device);
TU_FROM_HANDLE(tu_semaphore, sem, _semaphore);
if (!_semaphore)
return;
tu_semaphore_part_destroy(device, &sem->permanent);
tu_semaphore_part_destroy(device, &sem->temporary);
vk_object_free(&device->vk, pAllocator, sem);
}
VkResult
tu_ImportSemaphoreFdKHR(VkDevice _device,
const VkImportSemaphoreFdInfoKHR *pImportSemaphoreFdInfo)
{
TU_FROM_HANDLE(tu_device, device, _device);
TU_FROM_HANDLE(tu_semaphore, sem, pImportSemaphoreFdInfo->semaphore);
int ret;
struct tu_semaphore_part *dst = NULL;
if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) {
dst = &sem->temporary;
} else {
dst = &sem->permanent;
}
uint32_t syncobj = dst->kind == TU_SEMAPHORE_SYNCOBJ ? dst->syncobj : 0;
switch(pImportSemaphoreFdInfo->handleType) {
case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT: {
uint32_t old_syncobj = syncobj;
ret = drmSyncobjFDToHandle(device->physical_device->local_fd, pImportSemaphoreFdInfo->fd, &syncobj);
if (ret == 0) {
close(pImportSemaphoreFdInfo->fd);
if (old_syncobj)
drmSyncobjDestroy(device->physical_device->local_fd, old_syncobj);
}
break;
}
case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT: {
if (!syncobj) {
ret = drmSyncobjCreate(device->physical_device->local_fd, 0, &syncobj);
if (ret)
break;
}
if (pImportSemaphoreFdInfo->fd == -1) {
ret = drmSyncobjSignal(device->physical_device->local_fd, &syncobj, 1);
} else {
ret = drmSyncobjImportSyncFile(device->physical_device->local_fd, syncobj, pImportSemaphoreFdInfo->fd);
}
if (!ret)
close(pImportSemaphoreFdInfo->fd);
break;
}
default:
unreachable("Unhandled semaphore handle type");
}
if (ret) {
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
}
dst->syncobj = syncobj;
dst->kind = TU_SEMAPHORE_SYNCOBJ;
return VK_SUCCESS;
}
VkResult
tu_GetSemaphoreFdKHR(VkDevice _device,
const VkSemaphoreGetFdInfoKHR *pGetFdInfo,
int *pFd)
{
TU_FROM_HANDLE(tu_device, device, _device);
TU_FROM_HANDLE(tu_semaphore, sem, pGetFdInfo->semaphore);
int ret;
uint32_t syncobj_handle;
if (sem->temporary.kind != TU_SEMAPHORE_NONE) {
assert(sem->temporary.kind == TU_SEMAPHORE_SYNCOBJ);
syncobj_handle = sem->temporary.syncobj;
} else {
assert(sem->permanent.kind == TU_SEMAPHORE_SYNCOBJ);
syncobj_handle = sem->permanent.syncobj;
}
switch(pGetFdInfo->handleType) {
case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:
ret = drmSyncobjHandleToFD(device->physical_device->local_fd, syncobj_handle, pFd);
break;
case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:
ret = drmSyncobjExportSyncFile(device->physical_device->local_fd, syncobj_handle, pFd);
if (!ret) {
if (sem->temporary.kind != TU_SEMAPHORE_NONE) {
tu_semaphore_part_destroy(device, &sem->temporary);
} else {
drmSyncobjReset(device->physical_device->local_fd, &syncobj_handle, 1);
}
}
break;
default:
unreachable("Unhandled semaphore handle type");
}
if (ret)
return vk_error(device->instance, VK_ERROR_INVALID_EXTERNAL_HANDLE);
return VK_SUCCESS;
}
static bool tu_has_syncobj(struct tu_physical_device *pdev)
{
uint64_t value;
if (drmGetCap(pdev->local_fd, DRM_CAP_SYNCOBJ, &value))
return false;
return value && pdev->msm_major_version == 1 && pdev->msm_minor_version >= 6;
}
void
tu_GetPhysicalDeviceExternalSemaphoreProperties(
VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo,
VkExternalSemaphoreProperties *pExternalSemaphoreProperties)
{
TU_FROM_HANDLE(tu_physical_device, pdev, physicalDevice);
if (tu_has_syncobj(pdev) &&
(pExternalSemaphoreInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT ||
pExternalSemaphoreInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT)) {
pExternalSemaphoreProperties->exportFromImportedHandleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT | VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
pExternalSemaphoreProperties->compatibleHandleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT | VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
pExternalSemaphoreProperties->externalSemaphoreFeatures = VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
} else {
pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
pExternalSemaphoreProperties->compatibleHandleTypes = 0;
pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
}
}
VkResult
tu_QueueSubmit(VkQueue _queue,
uint32_t submitCount,
const VkSubmitInfo *pSubmits,
VkFence _fence)
{
TU_FROM_HANDLE(tu_queue, queue, _queue);
VkResult result;
for (uint32_t i = 0; i < submitCount; ++i) {
const VkSubmitInfo *submit = pSubmits + i;
const bool last_submit = (i == submitCount - 1);
struct drm_msm_gem_submit_syncobj *in_syncobjs = NULL, *out_syncobjs = NULL;
uint32_t nr_in_syncobjs, nr_out_syncobjs;
struct tu_bo_list bo_list;
tu_bo_list_init(&bo_list);
result = tu_get_semaphore_syncobjs(pSubmits[i].pWaitSemaphores,
pSubmits[i].waitSemaphoreCount,
false, &in_syncobjs, &nr_in_syncobjs);
if (result != VK_SUCCESS) {
return tu_device_set_lost(queue->device,
"failed to allocate space for semaphore submission\n");
}
result = tu_get_semaphore_syncobjs(pSubmits[i].pSignalSemaphores,
pSubmits[i].signalSemaphoreCount,
false, &out_syncobjs, &nr_out_syncobjs);
if (result != VK_SUCCESS) {
free(in_syncobjs);
return tu_device_set_lost(queue->device,
"failed to allocate space for semaphore submission\n");
}
uint32_t entry_count = 0;
for (uint32_t j = 0; j < submit->commandBufferCount; ++j) {
TU_FROM_HANDLE(tu_cmd_buffer, cmdbuf, submit->pCommandBuffers[j]);
entry_count += cmdbuf->cs.entry_count;
}
struct drm_msm_gem_submit_cmd cmds[entry_count];
uint32_t entry_idx = 0;
for (uint32_t j = 0; j < submit->commandBufferCount; ++j) {
TU_FROM_HANDLE(tu_cmd_buffer, cmdbuf, submit->pCommandBuffers[j]);
struct tu_cs *cs = &cmdbuf->cs;
for (unsigned i = 0; i < cs->entry_count; ++i, ++entry_idx) {
cmds[entry_idx].type = MSM_SUBMIT_CMD_BUF;
cmds[entry_idx].submit_idx =
tu_bo_list_add(&bo_list, cs->entries[i].bo,
MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_DUMP);
cmds[entry_idx].submit_offset = cs->entries[i].offset;
cmds[entry_idx].size = cs->entries[i].size;
cmds[entry_idx].pad = 0;
cmds[entry_idx].nr_relocs = 0;
cmds[entry_idx].relocs = 0;
}
tu_bo_list_merge(&bo_list, &cmdbuf->bo_list);
}
uint32_t flags = MSM_PIPE_3D0;
if (nr_in_syncobjs) {
flags |= MSM_SUBMIT_SYNCOBJ_IN;
}
if (nr_out_syncobjs) {
flags |= MSM_SUBMIT_SYNCOBJ_OUT;
}
if (last_submit) {
flags |= MSM_SUBMIT_FENCE_FD_OUT;
}
struct drm_msm_gem_submit req = {
.flags = flags,
.queueid = queue->msm_queue_id,
.bos = (uint64_t)(uintptr_t) bo_list.bo_infos,
.nr_bos = bo_list.count,
.cmds = (uint64_t)(uintptr_t)cmds,
.nr_cmds = entry_count,
.in_syncobjs = (uint64_t)(uintptr_t)in_syncobjs,
.out_syncobjs = (uint64_t)(uintptr_t)out_syncobjs,
.nr_in_syncobjs = nr_in_syncobjs,
.nr_out_syncobjs = nr_out_syncobjs,
.syncobj_stride = sizeof(struct drm_msm_gem_submit_syncobj),
};
int ret = drmCommandWriteRead(queue->device->physical_device->local_fd,
DRM_MSM_GEM_SUBMIT,
&req, sizeof(req));
if (ret) {
free(in_syncobjs);
free(out_syncobjs);
return tu_device_set_lost(queue->device, "submit failed: %s\n",
strerror(errno));
}
tu_bo_list_destroy(&bo_list);
free(in_syncobjs);
free(out_syncobjs);
tu_semaphores_remove_temp(queue->device, pSubmits[i].pWaitSemaphores,
pSubmits[i].waitSemaphoreCount);
if (last_submit) {
/* no need to merge fences as queue execution is serialized */
tu_fence_update_fd(&queue->submit_fence, req.fence_fd);
} else if (last_submit) {
close(req.fence_fd);
}
}
if (_fence != VK_NULL_HANDLE) {
TU_FROM_HANDLE(tu_fence, fence, _fence);
tu_fence_copy(fence, &queue->submit_fence);
}
return VK_SUCCESS;
}