pvr: Add vk_sync support and remove service winsys syncobjs interface.

Removing internal pvr_winsys_syncobj abstraction and porting
service winsys syncobj over to vk_sync_type.

Signed-off-by: Rajnesh Kanwal <rajnesh.kanwal@imgtec.com>
Reviewed-by: Karmjit Mahil <Karmjit.Mahil@imgtec.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/15709>
This commit is contained in:
Rajnesh Kanwal 2022-03-28 14:18:00 +01:00 committed by Marge Bot
parent 98cc4c3a20
commit d50418a4fc
21 changed files with 968 additions and 1020 deletions

View File

@ -85,9 +85,10 @@ if with_imagination_srv
'winsys/pvrsrvkm/pvr_srv_bridge.c',
'winsys/pvrsrvkm/pvr_srv_job_common.c',
'winsys/pvrsrvkm/pvr_srv_job_compute.c',
'winsys/pvrsrvkm/pvr_srv_job_null.c',
'winsys/pvrsrvkm/pvr_srv_job_render.c',
'winsys/pvrsrvkm/pvr_srv_job_transfer.c',
'winsys/pvrsrvkm/pvr_srv_syncobj.c',
'winsys/pvrsrvkm/pvr_srv_sync.c',
)
pvr_flags += '-DPVR_SUPPORT_SERVICES_DRIVER'
endif

View File

@ -356,6 +356,8 @@ static VkResult pvr_physical_device_init(struct pvr_physical_device *pdevice,
goto err_vk_free_master_path;
}
pdevice->vk.supported_sync_types = pdevice->ws->sync_types;
ret = pdevice->ws->ops->device_info_init(pdevice->ws,
&pdevice->dev_info,
&pdevice->dev_runtime_info);
@ -1128,6 +1130,8 @@ VkResult pvr_CreateDevice(VkPhysicalDevice physicalDevice,
else
device->master_fd = -1;
vk_device_set_drm_fd(&device->vk, device->render_fd);
device->instance = instance;
device->pdevice = pdevice;

View File

@ -37,8 +37,8 @@
static void pvr_compute_job_ws_submit_info_init(
struct pvr_compute_ctx *ctx,
struct pvr_sub_cmd *sub_cmd,
const VkSemaphore *semaphores,
uint32_t semaphore_count,
struct vk_sync **waits,
uint32_t wait_count,
uint32_t *stage_flags,
struct pvr_winsys_compute_submit_info *submit_info)
{
@ -48,8 +48,8 @@ static void pvr_compute_job_ws_submit_info_init(
submit_info->frame_num = ctx->device->global_queue_present_count;
submit_info->job_num = ctx->device->global_queue_job_count;
submit_info->semaphores = semaphores;
submit_info->semaphore_count = semaphore_count;
submit_info->waits = waits;
submit_info->wait_count = wait_count;
submit_info->stage_flags = stage_flags;
pvr_csb_pack (&submit_info->regs.cdm_ctx_state_base_addr,
@ -87,21 +87,21 @@ static void pvr_compute_job_ws_submit_info_init(
VkResult pvr_compute_job_submit(struct pvr_compute_ctx *ctx,
struct pvr_sub_cmd *sub_cmd,
const VkSemaphore *semaphores,
uint32_t semaphore_count,
struct vk_sync **waits,
uint32_t wait_count,
uint32_t *stage_flags,
struct pvr_winsys_syncobj **const syncobj_out)
struct vk_sync *signal_sync)
{
struct pvr_device *device = ctx->device;
pvr_compute_job_ws_submit_info_init(ctx,
sub_cmd,
semaphores,
semaphore_count,
waits,
wait_count,
stage_flags,
&sub_cmd->compute.submit_info);
return device->ws->ops->compute_submit(ctx->ws_ctx,
&sub_cmd->compute.submit_info,
syncobj_out);
signal_sync);
}

View File

@ -29,13 +29,13 @@
struct pvr_compute_ctx;
struct pvr_sub_cmd;
struct pvr_winsys_syncobj;
struct vk_sync;
VkResult pvr_compute_job_submit(struct pvr_compute_ctx *ctx,
struct pvr_sub_cmd *sub_cmd,
const VkSemaphore *semaphores,
uint32_t semaphore_count,
struct vk_sync **waits,
uint32_t wait_count,
uint32_t *stage_flags,
struct pvr_winsys_syncobj **const syncobj_out);
struct vk_sync *signal_sync);
#endif /* PVR_JOB_COMPUTE_H */

View File

@ -1515,8 +1515,8 @@ static void pvr_render_job_ws_submit_info_init(
struct pvr_render_job *job,
const struct pvr_winsys_job_bo *bos,
uint32_t bo_count,
const VkSemaphore *semaphores,
uint32_t semaphore_count,
struct vk_sync **waits,
uint32_t wait_count,
uint32_t *stage_flags,
struct pvr_winsys_render_submit_info *submit_info)
{
@ -1533,8 +1533,8 @@ static void pvr_render_job_ws_submit_info_init(
submit_info->bos = bos;
submit_info->bo_count = bo_count;
submit_info->semaphores = semaphores;
submit_info->semaphore_count = semaphore_count;
submit_info->waits = waits;
submit_info->wait_count = wait_count;
submit_info->stage_flags = stage_flags;
/* FIXME: add WSI image bos. */
@ -1546,16 +1546,15 @@ static void pvr_render_job_ws_submit_info_init(
assert(submit_info->geometry.regs.tpu == submit_info->fragment.regs.tpu);
}
VkResult
pvr_render_job_submit(struct pvr_render_ctx *ctx,
struct pvr_render_job *job,
const struct pvr_winsys_job_bo *bos,
uint32_t bo_count,
const VkSemaphore *semaphores,
uint32_t semaphore_count,
uint32_t *stage_flags,
struct pvr_winsys_syncobj **const syncobj_geom_out,
struct pvr_winsys_syncobj **const syncobj_frag_out)
VkResult pvr_render_job_submit(struct pvr_render_ctx *ctx,
struct pvr_render_job *job,
const struct pvr_winsys_job_bo *bos,
uint32_t bo_count,
struct vk_sync **waits,
uint32_t wait_count,
uint32_t *stage_flags,
struct vk_sync *signal_sync_geom,
struct vk_sync *signal_sync_frag)
{
struct pvr_rt_dataset *rt_dataset = job->rt_dataset;
struct pvr_winsys_render_submit_info submit_info;
@ -1566,15 +1565,15 @@ pvr_render_job_submit(struct pvr_render_ctx *ctx,
job,
bos,
bo_count,
semaphores,
semaphore_count,
waits,
wait_count,
stage_flags,
&submit_info);
result = device->ws->ops->render_submit(ctx->ws_ctx,
&submit_info,
syncobj_geom_out,
syncobj_frag_out);
signal_sync_geom,
signal_sync_frag);
if (result != VK_SUCCESS)
return result;

View File

@ -36,6 +36,7 @@ struct pvr_device;
struct pvr_free_list;
struct pvr_render_ctx;
struct pvr_rt_dataset;
struct vk_sync;
/* FIXME: Turn 'struct pvr_sub_cmd' into 'struct pvr_job' and change 'struct
* pvr_render_job' to subclass it? This is approximately what v3dv does
@ -114,15 +115,14 @@ pvr_render_target_dataset_create(struct pvr_device *device,
struct pvr_rt_dataset **const rt_dataset_out);
void pvr_render_target_dataset_destroy(struct pvr_rt_dataset *dataset);
VkResult
pvr_render_job_submit(struct pvr_render_ctx *ctx,
struct pvr_render_job *job,
const struct pvr_winsys_job_bo *bos,
uint32_t bo_count,
const VkSemaphore *semaphores,
uint32_t semaphore_count,
uint32_t *stage_flags,
struct pvr_winsys_syncobj **const syncobj_geom_out,
struct pvr_winsys_syncobj **const syncobj_frag_out);
VkResult pvr_render_job_submit(struct pvr_render_ctx *ctx,
struct pvr_render_job *job,
const struct pvr_winsys_job_bo *bos,
uint32_t bo_count,
struct vk_sync **waits,
uint32_t wait_count,
uint32_t *stage_flags,
struct vk_sync *signal_sync_geom,
struct vk_sync *signal_sync_frag);
#endif /* PVR_JOB_RENDER_H */

View File

@ -59,6 +59,7 @@
#include "vk_log.h"
#include "vk_physical_device.h"
#include "vk_queue.h"
#include "vk_sync.h"
#include "wsi_common.h"
#ifdef HAVE_VALGRIND
@ -232,19 +233,7 @@ struct pvr_queue {
struct pvr_compute_ctx *compute_ctx;
struct pvr_transfer_ctx *transfer_ctx;
struct pvr_winsys_syncobj *completion[PVR_JOB_TYPE_MAX];
};
struct pvr_semaphore {
struct vk_object_base base;
struct pvr_winsys_syncobj *syncobj;
};
struct pvr_fence {
struct vk_object_base base;
struct pvr_winsys_syncobj *syncobj;
struct vk_sync *completion[PVR_JOB_TYPE_MAX];
};
struct pvr_vertex_binding {
@ -1391,11 +1380,6 @@ VK_DEFINE_NONDISP_HANDLE_CASTS(pvr_sampler,
base,
VkSampler,
VK_OBJECT_TYPE_SAMPLER)
VK_DEFINE_NONDISP_HANDLE_CASTS(pvr_semaphore,
base,
VkSemaphore,
VK_OBJECT_TYPE_SEMAPHORE)
VK_DEFINE_NONDISP_HANDLE_CASTS(pvr_fence, base, VkFence, VK_OBJECT_TYPE_FENCE)
VK_DEFINE_NONDISP_HANDLE_CASTS(pvr_pipeline_layout,
base,
VkPipelineLayout,

View File

@ -44,9 +44,13 @@
#include "util/macros.h"
#include "util/u_atomic.h"
#include "vk_alloc.h"
#include "vk_fence.h"
#include "vk_log.h"
#include "vk_object.h"
#include "vk_queue.h"
#include "vk_semaphore.h"
#include "vk_sync.h"
#include "vk_sync_dummy.h"
#include "vk_util.h"
static VkResult pvr_queue_init(struct pvr_device *device,
@ -144,7 +148,7 @@ static void pvr_queue_finish(struct pvr_queue *queue)
{
for (uint32_t i = 0; i < ARRAY_SIZE(queue->completion); i++) {
if (queue->completion[i])
queue->device->ws->ops->syncobj_destroy(queue->completion[i]);
vk_sync_destroy(&queue->device->vk, queue->completion[i]);
}
pvr_render_ctx_destroy(queue->gfx_ctx);
@ -166,152 +170,26 @@ VkResult pvr_QueueWaitIdle(VkQueue _queue)
{
PVR_FROM_HANDLE(pvr_queue, queue, _queue);
return queue->device->ws->ops->syncobjs_wait(queue->device->ws,
queue->completion,
ARRAY_SIZE(queue->completion),
true,
UINT64_MAX);
}
for (int i = 0U; i < ARRAY_SIZE(queue->completion); i++) {
VkResult result;
VkResult pvr_CreateFence(VkDevice _device,
const VkFenceCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkFence *pFence)
{
PVR_FROM_HANDLE(pvr_device, device, _device);
struct pvr_fence *fence;
VkResult result;
if (!queue->completion[i])
continue;
fence = vk_object_alloc(&device->vk,
pAllocator,
sizeof(*fence),
VK_OBJECT_TYPE_FENCE);
if (!fence)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
/* We don't really need to create a syncobj here unless it's a signaled
* fence.
*/
if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {
result =
device->ws->ops->syncobj_create(device->ws, true, &fence->syncobj);
if (result != VK_SUCCESS) {
vk_object_free(&device->vk, pAllocator, fence);
result = vk_sync_wait(&queue->device->vk,
queue->completion[i],
0U,
VK_SYNC_WAIT_COMPLETE,
UINT64_MAX);
if (result != VK_SUCCESS)
return result;
}
} else {
fence->syncobj = NULL;
}
*pFence = pvr_fence_to_handle(fence);
return VK_SUCCESS;
}
void pvr_DestroyFence(VkDevice _device,
VkFence _fence,
const VkAllocationCallbacks *pAllocator)
{
PVR_FROM_HANDLE(pvr_device, device, _device);
PVR_FROM_HANDLE(pvr_fence, fence, _fence);
if (!fence)
return;
if (fence->syncobj)
device->ws->ops->syncobj_destroy(fence->syncobj);
vk_object_free(&device->vk, pAllocator, fence);
}
VkResult
pvr_ResetFences(VkDevice _device, uint32_t fenceCount, const VkFence *pFences)
{
struct pvr_winsys_syncobj *syncobjs[fenceCount];
PVR_FROM_HANDLE(pvr_device, device, _device);
for (uint32_t i = 0; i < fenceCount; i++) {
PVR_FROM_HANDLE(pvr_fence, fence, pFences[i]);
syncobjs[i] = fence->syncobj;
}
return device->ws->ops->syncobjs_reset(device->ws, syncobjs, fenceCount);
}
VkResult pvr_GetFenceStatus(VkDevice _device, VkFence _fence)
{
PVR_FROM_HANDLE(pvr_device, device, _device);
PVR_FROM_HANDLE(pvr_fence, fence, _fence);
VkResult result;
result =
device->ws->ops->syncobjs_wait(device->ws, &fence->syncobj, 1U, true, 0U);
if (result == VK_TIMEOUT)
return VK_NOT_READY;
return result;
}
VkResult pvr_WaitForFences(VkDevice _device,
uint32_t fenceCount,
const VkFence *pFences,
VkBool32 waitAll,
uint64_t timeout)
{
struct pvr_winsys_syncobj *syncobjs[fenceCount];
PVR_FROM_HANDLE(pvr_device, device, _device);
for (uint32_t i = 0; i < fenceCount; i++) {
PVR_FROM_HANDLE(pvr_fence, fence, pFences[i]);
syncobjs[i] = fence->syncobj;
}
return device->ws->ops->syncobjs_wait(device->ws,
syncobjs,
fenceCount,
!!waitAll,
timeout);
}
VkResult pvr_CreateSemaphore(VkDevice _device,
const VkSemaphoreCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkSemaphore *pSemaphore)
{
PVR_FROM_HANDLE(pvr_device, device, _device);
struct pvr_semaphore *semaphore;
semaphore = vk_object_alloc(&device->vk,
pAllocator,
sizeof(*semaphore),
VK_OBJECT_TYPE_SEMAPHORE);
if (!semaphore)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
semaphore->syncobj = NULL;
*pSemaphore = pvr_semaphore_to_handle(semaphore);
return VK_SUCCESS;
}
void pvr_DestroySemaphore(VkDevice _device,
VkSemaphore _semaphore,
const VkAllocationCallbacks *pAllocator)
{
PVR_FROM_HANDLE(pvr_device, device, _device);
PVR_FROM_HANDLE(pvr_semaphore, semaphore, _semaphore);
if (semaphore->syncobj)
device->ws->ops->syncobj_destroy(semaphore->syncobj);
vk_object_free(&device->vk, pAllocator, semaphore);
}
static enum pvr_pipeline_stage_bits
pvr_convert_stage_mask(VkPipelineStageFlags stage_mask)
pvr_convert_stage_mask(VkPipelineStageFlags2KHR stage_mask)
{
enum pvr_pipeline_stage_bits stages = 0;
@ -350,19 +228,19 @@ pvr_convert_stage_mask(VkPipelineStageFlags stage_mask)
return stages;
}
static VkResult pvr_process_graphics_cmd(
struct pvr_device *device,
struct pvr_queue *queue,
struct pvr_cmd_buffer *cmd_buffer,
struct pvr_sub_cmd *sub_cmd,
const VkSemaphore *semaphores,
uint32_t semaphore_count,
uint32_t *stage_flags,
struct pvr_winsys_syncobj *completions[static PVR_JOB_TYPE_MAX])
static VkResult
pvr_process_graphics_cmd(struct pvr_device *device,
struct pvr_queue *queue,
struct pvr_cmd_buffer *cmd_buffer,
struct pvr_sub_cmd *sub_cmd,
struct vk_sync **waits,
uint32_t wait_count,
uint32_t *stage_flags,
struct vk_sync *completions[static PVR_JOB_TYPE_MAX])
{
const struct pvr_framebuffer *framebuffer = sub_cmd->gfx.framebuffer;
struct pvr_winsys_syncobj *syncobj_geom = NULL;
struct pvr_winsys_syncobj *syncobj_frag = NULL;
struct vk_sync *sync_geom;
struct vk_sync *sync_frag;
uint32_t bo_count = 0;
VkResult result;
@ -370,6 +248,24 @@ static VkResult pvr_process_graphics_cmd(
if (!bos)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
result = vk_sync_create(&device->vk,
&device->pdevice->ws->syncobj_type,
0U,
0UL,
&sync_geom);
if (result != VK_SUCCESS)
return result;
result = vk_sync_create(&device->vk,
&device->pdevice->ws->syncobj_type,
0U,
0UL,
&sync_frag);
if (result != VK_SUCCESS) {
vk_sync_destroy(&device->vk, sync_geom);
return result;
}
/* FIXME: DoShadowLoadOrStore() */
/* FIXME: If the framebuffer being rendered to has multiple layers then we
@ -393,95 +289,96 @@ static VkResult pvr_process_graphics_cmd(
&sub_cmd->gfx.job,
bos,
bo_count,
semaphores,
semaphore_count,
waits,
wait_count,
stage_flags,
&syncobj_geom,
&syncobj_frag);
sync_geom,
sync_frag);
STACK_ARRAY_FINISH(bos);
if (result != VK_SUCCESS)
if (result != VK_SUCCESS) {
vk_sync_destroy(&device->vk, sync_geom);
vk_sync_destroy(&device->vk, sync_frag);
return result;
}
/* Replace the completion fences. */
if (syncobj_geom) {
if (completions[PVR_JOB_TYPE_GEOM])
device->ws->ops->syncobj_destroy(completions[PVR_JOB_TYPE_GEOM]);
if (completions[PVR_JOB_TYPE_GEOM])
vk_sync_destroy(&device->vk, completions[PVR_JOB_TYPE_GEOM]);
completions[PVR_JOB_TYPE_GEOM] = syncobj_geom;
}
completions[PVR_JOB_TYPE_GEOM] = sync_geom;
if (syncobj_frag) {
if (completions[PVR_JOB_TYPE_FRAG])
device->ws->ops->syncobj_destroy(completions[PVR_JOB_TYPE_FRAG]);
if (completions[PVR_JOB_TYPE_FRAG])
vk_sync_destroy(&device->vk, completions[PVR_JOB_TYPE_FRAG]);
completions[PVR_JOB_TYPE_FRAG] = syncobj_frag;
}
completions[PVR_JOB_TYPE_FRAG] = sync_frag;
/* FIXME: DoShadowLoadOrStore() */
return result;
}
static VkResult pvr_process_compute_cmd(
struct pvr_device *device,
struct pvr_queue *queue,
struct pvr_sub_cmd *sub_cmd,
const VkSemaphore *semaphores,
uint32_t semaphore_count,
uint32_t *stage_flags,
struct pvr_winsys_syncobj *completions[static PVR_JOB_TYPE_MAX])
static VkResult
pvr_process_compute_cmd(struct pvr_device *device,
struct pvr_queue *queue,
struct pvr_sub_cmd *sub_cmd,
struct vk_sync **waits,
uint32_t wait_count,
uint32_t *stage_flags,
struct vk_sync *completions[static PVR_JOB_TYPE_MAX])
{
struct pvr_winsys_syncobj *syncobj = NULL;
struct vk_sync *sync;
VkResult result;
result = vk_sync_create(&device->vk,
&device->pdevice->ws->syncobj_type,
0U,
0UL,
&sync);
if (result != VK_SUCCESS)
return result;
/* This passes ownership of the wait fences to pvr_compute_job_submit(). */
result = pvr_compute_job_submit(queue->compute_ctx,
sub_cmd,
semaphores,
semaphore_count,
waits,
wait_count,
stage_flags,
&syncobj);
if (result != VK_SUCCESS)
sync);
if (result != VK_SUCCESS) {
vk_sync_destroy(&device->vk, sync);
return result;
}
/* Replace the completion fences. */
if (syncobj) {
if (completions[PVR_JOB_TYPE_COMPUTE])
device->ws->ops->syncobj_destroy(completions[PVR_JOB_TYPE_COMPUTE]);
if (completions[PVR_JOB_TYPE_COMPUTE])
vk_sync_destroy(&device->vk, completions[PVR_JOB_TYPE_COMPUTE]);
completions[PVR_JOB_TYPE_COMPUTE] = syncobj;
}
completions[PVR_JOB_TYPE_COMPUTE] = sync;
return result;
}
/* FIXME: Implement gpu based transfer support. */
static VkResult pvr_process_transfer_cmds(
struct pvr_device *device,
struct pvr_sub_cmd *sub_cmd,
const VkSemaphore *semaphores,
uint32_t semaphore_count,
uint32_t *stage_flags,
struct pvr_winsys_syncobj *completions[static PVR_JOB_TYPE_MAX])
static VkResult
pvr_process_transfer_cmds(struct pvr_device *device,
struct pvr_sub_cmd *sub_cmd,
struct vk_sync **waits,
uint32_t wait_count,
uint32_t *stage_flags,
struct vk_sync *completions[static PVR_JOB_TYPE_MAX])
{
/* Wait for transfer semaphores here before doing any transfers. */
for (uint32_t i = 0; i < semaphore_count; i++) {
PVR_FROM_HANDLE(pvr_semaphore, sem, semaphores[i]);
if (sem->syncobj && stage_flags[i] & PVR_PIPELINE_STAGE_TRANSFER_BIT) {
VkResult result = device->ws->ops->syncobjs_wait(device->ws,
&sem->syncobj,
1,
true,
UINT64_MAX);
for (uint32_t i = 0U; i < wait_count; i++) {
if (stage_flags[i] & PVR_PIPELINE_STAGE_TRANSFER_BIT) {
VkResult result = vk_sync_wait(&device->vk,
waits[i],
0U,
VK_SYNC_WAIT_COMPLETE,
UINT64_MAX);
if (result != VK_SUCCESS)
return result;
stage_flags[i] &= ~PVR_PIPELINE_STAGE_TRANSFER_BIT;
if (stage_flags[i] == 0) {
device->ws->ops->syncobj_destroy(sem->syncobj);
sem->syncobj = NULL;
}
}
}
@ -530,91 +427,116 @@ static VkResult pvr_process_transfer_cmds(
device->ws->ops->buffer_unmap(transfer_cmd->dst->vma->bo);
}
/* Given we are doing CPU based copy, completion fence should always be -1.
* This should be fixed when GPU based copy is implemented.
/* Given we are doing CPU based copy, completion fence should always be
* signaled. This should be fixed when GPU based copy is implemented.
*/
assert(!completions[PVR_JOB_TYPE_TRANSFER]);
return VK_SUCCESS;
return vk_sync_create(&device->vk,
&device->pdevice->ws->syncobj_type,
0U,
1UL,
&completions[PVR_JOB_TYPE_TRANSFER]);
}
static VkResult pvr_set_semaphore_payloads(
struct pvr_device *device,
struct pvr_winsys_syncobj *completions[static PVR_JOB_TYPE_MAX],
const VkSemaphore *semaphores,
uint32_t semaphore_count)
static VkResult
pvr_set_semaphore_payloads(struct pvr_device *device,
struct vk_sync *completions[static PVR_JOB_TYPE_MAX],
const VkSemaphore *signals,
uint32_t signal_count)
{
struct pvr_winsys_syncobj *syncobj = NULL;
struct vk_sync *sync;
VkResult result;
int fd = -1;
if (!semaphore_count)
return VK_SUCCESS;
result = vk_sync_create(&device->vk,
&device->pdevice->ws->syncobj_type,
0U,
0UL,
&sync);
if (result != VK_SUCCESS)
return result;
for (uint32_t i = 0; i < PVR_JOB_TYPE_MAX; i++) {
if (completions[i]) {
result =
device->ws->ops->syncobjs_merge(completions[i], syncobj, &syncobj);
if (result != VK_SUCCESS)
goto err_destroy_syncobj;
}
result = device->ws->ops->null_job_submit(device->ws,
completions,
PVR_JOB_TYPE_MAX,
sync);
if (result != VK_SUCCESS)
goto end_set_semaphore_payloads;
/* If we have a single signal semaphore, we can simply move merged sync's
* payload to the signal semahpore's payload.
*/
if (signal_count == 1U) {
VK_FROM_HANDLE(vk_semaphore, sem, signals[0]);
struct vk_sync *sem_sync = vk_semaphore_get_active_sync(sem);
result = vk_sync_move(&device->vk, sem_sync, sync);
goto end_set_semaphore_payloads;
}
for (uint32_t i = 0; i < semaphore_count; i++) {
PVR_FROM_HANDLE(pvr_semaphore, semaphore, semaphores[i]);
struct pvr_winsys_syncobj *dup_signal_fence;
result = vk_sync_export_sync_file(&device->vk, sync, &fd);
if (result != VK_SUCCESS)
goto end_set_semaphore_payloads;
/* Duplicate signal_fence and store it in each signal semaphore. */
result =
device->ws->ops->syncobjs_merge(syncobj, NULL, &dup_signal_fence);
for (uint32_t i = 0U; i < signal_count; i++) {
VK_FROM_HANDLE(vk_semaphore, sem, signals[i]);
struct vk_sync *sem_sync = vk_semaphore_get_active_sync(sem);
result = vk_sync_import_sync_file(&device->vk, sem_sync, fd);
if (result != VK_SUCCESS)
goto err_destroy_syncobj;
if (semaphore->syncobj)
device->ws->ops->syncobj_destroy(semaphore->syncobj);
semaphore->syncobj = dup_signal_fence;
goto end_set_semaphore_payloads;
}
err_destroy_syncobj:
if (syncobj)
device->ws->ops->syncobj_destroy(syncobj);
end_set_semaphore_payloads:
if (fd != -1)
close(fd);
vk_sync_destroy(&device->vk, sync);
return result;
}
static VkResult pvr_set_fence_payload(
struct pvr_device *device,
struct pvr_winsys_syncobj *completions[static PVR_JOB_TYPE_MAX],
VkFence _fence)
static VkResult
pvr_set_fence_payload(struct pvr_device *device,
struct vk_sync *completions[static PVR_JOB_TYPE_MAX],
VkFence _fence)
{
PVR_FROM_HANDLE(pvr_fence, fence, _fence);
struct pvr_winsys_syncobj *syncobj = NULL;
VK_FROM_HANDLE(vk_fence, fence, _fence);
struct vk_sync *fence_sync;
struct vk_sync *sync;
VkResult result;
for (uint32_t i = 0; i < PVR_JOB_TYPE_MAX; i++) {
if (completions[i]) {
VkResult result =
device->ws->ops->syncobjs_merge(completions[i], syncobj, &syncobj);
if (result != VK_SUCCESS) {
device->ws->ops->syncobj_destroy(syncobj);
return result;
}
}
result = vk_sync_create(&device->vk,
&device->pdevice->ws->syncobj_type,
0U,
0UL,
&sync);
if (result != VK_SUCCESS)
return result;
result = device->ws->ops->null_job_submit(device->ws,
completions,
PVR_JOB_TYPE_MAX,
sync);
if (result != VK_SUCCESS) {
vk_sync_destroy(&device->vk, sync);
return result;
}
if (fence->syncobj)
device->ws->ops->syncobj_destroy(fence->syncobj);
fence->syncobj = syncobj;
fence_sync = vk_fence_get_active_sync(fence);
result = vk_sync_move(&device->vk, fence_sync, sync);
vk_sync_destroy(&device->vk, sync);
return VK_SUCCESS;
return result;
}
static VkResult pvr_process_cmd_buffer(
struct pvr_device *device,
struct pvr_queue *queue,
VkCommandBuffer commandBuffer,
const VkSemaphore *semaphores,
uint32_t semaphore_count,
uint32_t *stage_flags,
struct pvr_winsys_syncobj *completions[static PVR_JOB_TYPE_MAX])
static VkResult
pvr_process_cmd_buffer(struct pvr_device *device,
struct pvr_queue *queue,
VkCommandBuffer commandBuffer,
struct vk_sync **waits,
uint32_t wait_count,
uint32_t *stage_flags,
struct vk_sync *completions[static PVR_JOB_TYPE_MAX])
{
PVR_FROM_HANDLE(pvr_cmd_buffer, cmd_buffer, commandBuffer);
VkResult result;
@ -631,8 +553,8 @@ static VkResult pvr_process_cmd_buffer(
queue,
cmd_buffer,
sub_cmd,
semaphores,
semaphore_count,
waits,
wait_count,
stage_flags,
completions);
break;
@ -641,8 +563,8 @@ static VkResult pvr_process_cmd_buffer(
result = pvr_process_compute_cmd(device,
queue,
sub_cmd,
semaphores,
semaphore_count,
waits,
wait_count,
stage_flags,
completions);
break;
@ -650,8 +572,8 @@ static VkResult pvr_process_cmd_buffer(
case PVR_SUB_CMD_TYPE_TRANSFER:
result = pvr_process_transfer_cmds(device,
sub_cmd,
semaphores,
semaphore_count,
waits,
wait_count,
stage_flags,
completions);
break;
@ -672,48 +594,68 @@ static VkResult pvr_process_cmd_buffer(
return VK_SUCCESS;
}
static VkResult pvr_process_empty_job(
struct pvr_device *device,
const VkSemaphore *semaphores,
uint32_t semaphore_count,
uint32_t *stage_flags,
struct pvr_winsys_syncobj *completions[static PVR_JOB_TYPE_MAX])
static VkResult
pvr_submit_null_job(struct pvr_device *device,
struct vk_sync **waits,
uint32_t wait_count,
uint32_t *stage_flags,
struct vk_sync *completions[static PVR_JOB_TYPE_MAX])
{
VkResult result;
STATIC_ASSERT(PVR_JOB_TYPE_MAX >= PVR_NUM_SYNC_PIPELINE_STAGES);
for (uint32_t i = 0U; i < PVR_JOB_TYPE_MAX; i++) {
struct vk_sync *per_job_waits[wait_count];
uint32_t per_job_waits_count = 0;
for (uint32_t i = 0; i < semaphore_count; i++) {
PVR_FROM_HANDLE(pvr_semaphore, semaphore, semaphores[i]);
if (!semaphore->syncobj)
continue;
for (uint32_t j = 0; j < PVR_NUM_SYNC_PIPELINE_STAGES; j++) {
if (stage_flags[i] & (1U << j)) {
VkResult result =
device->ws->ops->syncobjs_merge(semaphore->syncobj,
completions[j],
&completions[j]);
if (result != VK_SUCCESS)
return result;
/* Get the waits specific to the job type. */
for (uint32_t j = 0U; j < wait_count; j++) {
if (stage_flags[j] & (1U << i)) {
per_job_waits[per_job_waits_count] = waits[j];
per_job_waits_count++;
}
}
device->ws->ops->syncobj_destroy(semaphore->syncobj);
semaphore->syncobj = NULL;
if (per_job_waits_count == 0U)
continue;
result = vk_sync_create(&device->vk,
&device->pdevice->ws->syncobj_type,
0U,
0UL,
&completions[i]);
if (result != VK_SUCCESS)
goto err_destroy_completion_syncs;
result = device->ws->ops->null_job_submit(device->ws,
per_job_waits,
per_job_waits_count,
completions[i]);
if (result != VK_SUCCESS)
goto err_destroy_completion_syncs;
}
return VK_SUCCESS;
err_destroy_completion_syncs:
for (uint32_t i = 0U; i < PVR_JOB_TYPE_MAX; i++) {
if (completions[i]) {
vk_sync_destroy(&device->vk, completions[i]);
completions[i] = NULL;
}
}
return result;
}
static void
pvr_update_syncobjs(struct pvr_device *device,
struct pvr_winsys_syncobj *src[static PVR_JOB_TYPE_MAX],
struct pvr_winsys_syncobj *dst[static PVR_JOB_TYPE_MAX])
static void pvr_update_syncobjs(struct pvr_device *device,
struct vk_sync *src[static PVR_JOB_TYPE_MAX],
struct vk_sync *dst[static PVR_JOB_TYPE_MAX])
{
for (uint32_t i = 0; i < PVR_JOB_TYPE_MAX; i++) {
if (src[i]) {
if (dst[i])
device->ws->ops->syncobj_destroy(dst[i]);
vk_sync_destroy(&device->vk, dst[i]);
dst[i] = src[i];
}
@ -726,37 +668,51 @@ VkResult pvr_QueueSubmit(VkQueue _queue,
VkFence fence)
{
PVR_FROM_HANDLE(pvr_queue, queue, _queue);
struct pvr_winsys_syncobj *completion_syncobjs[PVR_JOB_TYPE_MAX] = {};
struct vk_sync *completion_syncobjs[PVR_JOB_TYPE_MAX] = {};
struct pvr_device *device = queue->device;
VkResult result;
for (uint32_t i = 0; i < submitCount; i++) {
struct pvr_winsys_syncobj
*per_submit_completion_syncobjs[PVR_JOB_TYPE_MAX] = {};
for (uint32_t i = 0U; i < submitCount; i++) {
struct vk_sync *per_submit_completion_syncobjs[PVR_JOB_TYPE_MAX] = {};
const VkSubmitInfo *desc = &pSubmits[i];
struct vk_sync *waits[desc->waitSemaphoreCount];
uint32_t stage_flags[desc->waitSemaphoreCount];
uint32_t wait_count = 0;
for (uint32_t j = 0; j < desc->waitSemaphoreCount; j++)
stage_flags[j] = pvr_convert_stage_mask(desc->pWaitDstStageMask[j]);
for (uint32_t j = 0U; j < desc->waitSemaphoreCount; j++) {
VK_FROM_HANDLE(vk_semaphore, semaphore, desc->pWaitSemaphores[j]);
struct vk_sync *sync = vk_semaphore_get_active_sync(semaphore);
if (sync->type == &vk_sync_dummy_type)
continue;
/* We don't currently support timeline semaphores. */
assert(!(sync->flags & VK_SYNC_IS_TIMELINE));
stage_flags[wait_count] =
pvr_convert_stage_mask(desc->pWaitDstStageMask[j]);
waits[wait_count] = vk_semaphore_get_active_sync(semaphore);
wait_count++;
}
if (desc->commandBufferCount > 0U) {
for (uint32_t j = 0U; j < desc->commandBufferCount; j++) {
result = pvr_process_cmd_buffer(device,
queue,
desc->pCommandBuffers[j],
desc->pWaitSemaphores,
desc->waitSemaphoreCount,
waits,
wait_count,
stage_flags,
per_submit_completion_syncobjs);
if (result != VK_SUCCESS)
return result;
}
} else {
result = pvr_process_empty_job(device,
desc->pWaitSemaphores,
desc->waitSemaphoreCount,
stage_flags,
per_submit_completion_syncobjs);
result = pvr_submit_null_job(device,
waits,
wait_count,
stage_flags,
per_submit_completion_syncobjs);
if (result != VK_SUCCESS)
return result;
}

View File

@ -25,11 +25,16 @@
*/
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <vulkan/vulkan.h>
#include "pvr_private.h"
#include "pvr_winsys.h"
#include "util/u_atomic.h"
#include "vk_fence.h"
#include "vk_object.h"
#include "vk_semaphore.h"
#include "vk_sync_dummy.h"
#include "wsi_common.h"
static PFN_vkVoidFunction pvr_wsi_proc_addr(VkPhysicalDevice physicalDevice,
@ -89,9 +94,9 @@ VkResult pvr_AcquireNextImage2KHR(VkDevice _device,
const VkAcquireNextImageInfoKHR *pAcquireInfo,
uint32_t *pImageIndex)
{
VK_FROM_HANDLE(vk_semaphore, sem, pAcquireInfo->semaphore);
VK_FROM_HANDLE(vk_fence, fence, pAcquireInfo->fence);
PVR_FROM_HANDLE(pvr_device, device, _device);
struct pvr_winsys_syncobj *handles[2];
uint32_t count = 0U;
VkResult result;
VkResult ret;
@ -102,23 +107,27 @@ VkResult pvr_AcquireNextImage2KHR(VkDevice _device,
if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
return result;
if (pAcquireInfo->fence) {
PVR_FROM_HANDLE(pvr_fence, fence, pAcquireInfo->fence);
handles[count++] = fence->syncobj;
if (fence) {
vk_fence_reset_temporary(&device->vk, fence);
ret = vk_sync_create(&device->vk,
&vk_sync_dummy_type,
0U,
0UL,
&fence->temporary);
if (ret != VK_SUCCESS)
return ret;
}
if (pAcquireInfo->semaphore) {
PVR_FROM_HANDLE(pvr_semaphore, semaphore, pAcquireInfo->semaphore);
handles[count++] = semaphore->syncobj;
if (sem) {
vk_semaphore_reset_temporary(&device->vk, sem);
ret = vk_sync_create(&device->vk,
&vk_sync_dummy_type,
0U,
0UL,
&sem->temporary);
if (ret != VK_SUCCESS)
return ret;
}
if (count == 0U)
return result;
/* We need to preserve VK_SUBOPTIMAL_KHR status. */
ret = device->ws->ops->syncobjs_signal(device->ws, handles, count);
if (ret != VK_SUCCESS)
return ret;
return result;
}

View File

@ -38,6 +38,7 @@
#include "pvr_limits.h"
#include "util/macros.h"
#include "util/vma.h"
#include "vk_sync.h"
struct pvr_device_info;
struct pvr_device_runtime_info;
@ -141,10 +142,6 @@ struct pvr_winsys_vma {
uint64_t mapped_size;
};
struct pvr_winsys_syncobj {
struct pvr_winsys *ws;
};
struct pvr_winsys_free_list {
struct pvr_winsys *ws;
};
@ -262,10 +259,10 @@ struct pvr_winsys_compute_submit_info {
uint32_t frame_num;
uint32_t job_num;
/* semaphores and stage_flags are arrays of length semaphore_count. */
const VkSemaphore *semaphores;
/* waits and stage_flags are arrays of length wait_count. */
struct vk_sync **waits;
uint32_t wait_count;
uint32_t *stage_flags;
uint32_t semaphore_count;
struct {
uint64_t tpu_border_colour_table;
@ -311,10 +308,10 @@ struct pvr_winsys_render_submit_info {
/* FIXME: should this be flags instead? */
bool run_frag;
/* semaphores and stage_flags are arrays of length semaphore_count. */
const VkSemaphore *semaphores;
/* waits and stage_flags are arrays of length wait_count. */
struct vk_sync **waits;
uint32_t wait_count;
uint32_t *stage_flags;
uint32_t semaphore_count;
struct pvr_winsys_geometry_state {
struct {
@ -398,25 +395,6 @@ struct pvr_winsys_ops {
uint64_t size);
void (*vma_unmap)(struct pvr_winsys_vma *vma);
VkResult (*syncobj_create)(struct pvr_winsys *ws,
bool signaled,
struct pvr_winsys_syncobj **const syncobj_out);
void (*syncobj_destroy)(struct pvr_winsys_syncobj *syncobj);
VkResult (*syncobjs_reset)(struct pvr_winsys *ws,
struct pvr_winsys_syncobj **const syncobjs,
uint32_t count);
VkResult (*syncobjs_signal)(struct pvr_winsys *ws,
struct pvr_winsys_syncobj **const syncobjs,
uint32_t count);
VkResult (*syncobjs_wait)(struct pvr_winsys *ws,
struct pvr_winsys_syncobj **const syncobjs,
uint32_t count,
bool wait_all,
uint64_t timeout);
VkResult (*syncobjs_merge)(struct pvr_winsys_syncobj *src,
struct pvr_winsys_syncobj *target,
struct pvr_winsys_syncobj **out);
VkResult (*free_list_create)(
struct pvr_winsys *ws,
struct pvr_winsys_vma *free_list_vma,
@ -443,8 +421,8 @@ struct pvr_winsys_ops {
VkResult (*render_submit)(
const struct pvr_winsys_render_ctx *ctx,
const struct pvr_winsys_render_submit_info *submit_info,
struct pvr_winsys_syncobj **const syncobj_geom_out,
struct pvr_winsys_syncobj **const syncobj_frag_out);
struct vk_sync *signal_sync_geom,
struct vk_sync *signal_sync_frag);
VkResult (*compute_ctx_create)(
struct pvr_winsys *ws,
@ -454,19 +432,27 @@ struct pvr_winsys_ops {
VkResult (*compute_submit)(
const struct pvr_winsys_compute_ctx *ctx,
const struct pvr_winsys_compute_submit_info *submit_info,
struct pvr_winsys_syncobj **const syncobj_out);
struct vk_sync *signal_sync);
VkResult (*transfer_ctx_create)(
struct pvr_winsys *ws,
const struct pvr_winsys_transfer_ctx_create_info *create_info,
struct pvr_winsys_transfer_ctx **const ctx_out);
void (*transfer_ctx_destroy)(struct pvr_winsys_transfer_ctx *ctx);
VkResult (*null_job_submit)(struct pvr_winsys *ws,
struct vk_sync **waits,
uint32_t wait_count,
struct vk_sync *signal_sync);
};
struct pvr_winsys {
uint64_t page_size;
uint32_t log2_page_size;
const struct vk_sync_type *sync_types[2];
struct vk_sync_type syncobj_type;
const struct pvr_winsys_ops *ops;
};

View File

@ -36,7 +36,8 @@
#include "pvr_srv_job_render.h"
#include "pvr_srv_job_transfer.h"
#include "pvr_srv_public.h"
#include "pvr_srv_syncobj.h"
#include "pvr_srv_sync.h"
#include "pvr_srv_job_null.h"
#include "pvr_winsys.h"
#include "pvr_winsys_helper.h"
#include "util/log.h"
@ -414,12 +415,6 @@ static const struct pvr_winsys_ops srv_winsys_ops = {
.heap_free = pvr_srv_winsys_heap_free,
.vma_map = pvr_srv_winsys_vma_map,
.vma_unmap = pvr_srv_winsys_vma_unmap,
.syncobj_create = pvr_srv_winsys_syncobj_create,
.syncobj_destroy = pvr_srv_winsys_syncobj_destroy,
.syncobjs_reset = pvr_srv_winsys_syncobjs_reset,
.syncobjs_signal = pvr_srv_winsys_syncobjs_signal,
.syncobjs_wait = pvr_srv_winsys_syncobjs_wait,
.syncobjs_merge = pvr_srv_winsys_syncobjs_merge,
.free_list_create = pvr_srv_winsys_free_list_create,
.free_list_destroy = pvr_srv_winsys_free_list_destroy,
.render_target_dataset_create = pvr_srv_render_target_dataset_create,
@ -432,6 +427,7 @@ static const struct pvr_winsys_ops srv_winsys_ops = {
.compute_submit = pvr_srv_winsys_compute_submit,
.transfer_ctx_create = pvr_srv_winsys_transfer_ctx_create,
.transfer_ctx_destroy = pvr_srv_winsys_transfer_ctx_destroy,
.null_job_submit = pvr_srv_winsys_null_job_submit,
};
static bool pvr_is_driver_compatible(int render_fd)
@ -494,6 +490,10 @@ struct pvr_winsys *pvr_srv_winsys_create(int master_fd,
srv_ws->render_fd = render_fd;
srv_ws->alloc = alloc;
srv_ws->base.syncobj_type = pvr_srv_sync_type;
srv_ws->base.sync_types[0] = &srv_ws->base.syncobj_type;
srv_ws->base.sync_types[1] = NULL;
result = pvr_srv_memctx_init(srv_ws);
if (result != VK_SUCCESS)
goto err_vk_free_srv_ws;

View File

@ -33,10 +33,11 @@
#include "pvr_private.h"
#include "pvr_srv.h"
#include "pvr_srv_bridge.h"
#include "pvr_srv_job_compute.h"
#include "pvr_srv_job_common.h"
#include "pvr_srv_syncobj.h"
#include "pvr_srv_job_compute.h"
#include "pvr_srv_sync.h"
#include "pvr_winsys.h"
#include "util/libsync.h"
#include "util/macros.h"
#include "vk_alloc.h"
#include "vk_log.h"
@ -164,46 +165,37 @@ static void pvr_srv_compute_cmd_init(
VkResult pvr_srv_winsys_compute_submit(
const struct pvr_winsys_compute_ctx *ctx,
const struct pvr_winsys_compute_submit_info *submit_info,
struct pvr_winsys_syncobj **const syncobj_out)
struct vk_sync *signal_sync)
{
const struct pvr_srv_winsys_compute_ctx *srv_ctx =
to_pvr_srv_winsys_compute_ctx(ctx);
const struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ctx->ws);
struct pvr_winsys_syncobj *signal_syncobj = NULL;
struct pvr_winsys_syncobj *wait_syncobj = NULL;
struct pvr_srv_winsys_syncobj *srv_syncobj;
struct rogue_fwif_cmd_compute compute_cmd;
struct pvr_srv_sync *srv_signal_sync;
VkResult result;
int in_fd = -1;
int fence;
pvr_srv_compute_cmd_init(submit_info, &compute_cmd);
for (uint32_t i = 0U; i < submit_info->semaphore_count; i++) {
PVR_FROM_HANDLE(pvr_semaphore, sem, submit_info->semaphores[i]);
for (uint32_t i = 0U; i < submit_info->wait_count; i++) {
struct pvr_srv_sync *srv_wait_sync = to_srv_sync(submit_info->waits[i]);
int ret;
if (!sem->syncobj)
if (!submit_info->waits[i] || srv_wait_sync->fd < 0)
continue;
if (submit_info->stage_flags[i] & PVR_PIPELINE_STAGE_COMPUTE_BIT) {
result = pvr_srv_winsys_syncobjs_merge(sem->syncobj,
wait_syncobj,
&wait_syncobj);
if (result != VK_SUCCESS)
goto err_destroy_wait_syncobj;
ret = sync_accumulate("", &in_fd, srv_wait_sync->fd);
if (ret) {
result = vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
goto err_close_in_fd;
}
submit_info->stage_flags[i] &= ~PVR_PIPELINE_STAGE_COMPUTE_BIT;
}
if (submit_info->stage_flags[i] == 0U) {
pvr_srv_winsys_syncobj_destroy(sem->syncobj);
sem->syncobj = NULL;
}
}
srv_syncobj = to_pvr_srv_winsys_syncobj(wait_syncobj);
do {
result = pvr_srv_rgx_kick_compute2(srv_ws->render_fd,
srv_ctx->handle,
@ -211,7 +203,7 @@ VkResult pvr_srv_winsys_compute_submit(
NULL,
NULL,
NULL,
wait_syncobj ? srv_syncobj->fd : -1,
in_fd,
srv_ctx->timeline,
sizeof(compute_cmd),
(uint8_t *)&compute_cmd,
@ -228,27 +220,16 @@ VkResult pvr_srv_winsys_compute_submit(
} while (result == VK_NOT_READY);
if (result != VK_SUCCESS)
goto err_destroy_wait_syncobj;
goto err_close_in_fd;
/* Given job submission succeeded, we don't need to close wait fence and it
* should be consumed by the compute job itself.
*/
if (wait_syncobj)
srv_syncobj->fd = -1;
srv_signal_sync = to_srv_sync(signal_sync);
pvr_srv_set_sync_payload(srv_signal_sync, fence);
if (fence != -1) {
result = pvr_srv_winsys_syncobj_create(ctx->ws, false, &signal_syncobj);
if (result != VK_SUCCESS)
goto err_destroy_wait_syncobj;
return VK_SUCCESS;
pvr_srv_set_syncobj_payload(signal_syncobj, fence);
}
*syncobj_out = signal_syncobj;
err_destroy_wait_syncobj:
if (wait_syncobj)
pvr_srv_winsys_syncobj_destroy(wait_syncobj);
err_close_in_fd:
if (in_fd >= 0)
close(in_fd);
return result;
}

View File

@ -30,7 +30,7 @@ struct pvr_winsys;
struct pvr_winsys_compute_ctx;
struct pvr_winsys_compute_ctx_create_info;
struct pvr_winsys_compute_submit_info;
struct pvr_winsys_syncobj;
struct vk_sync;
/*******************************************
Function prototypes
@ -45,6 +45,6 @@ void pvr_srv_winsys_compute_ctx_destroy(struct pvr_winsys_compute_ctx *ctx);
VkResult pvr_srv_winsys_compute_submit(
const struct pvr_winsys_compute_ctx *ctx,
const struct pvr_winsys_compute_submit_info *submit_info,
struct pvr_winsys_syncobj **const syncobj_out);
struct vk_sync *signal_sync);
#endif /* PVR_SRV_JOB_COMPUTE_H */

View File

@ -0,0 +1,66 @@
/*
* Copyright © 2022 Imagination Technologies Ltd.
*
* 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, sublicense, 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 NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <unistd.h>
#include <vulkan/vulkan.h>
#include "pvr_srv_job_null.h"
#include "pvr_srv_sync.h"
#include "pvr_winsys.h"
#include "util/libsync.h"
#include "vk_log.h"
#include "vk_sync.h"
VkResult pvr_srv_winsys_null_job_submit(struct pvr_winsys *ws,
struct vk_sync **waits,
uint32_t wait_count,
struct vk_sync *signal_sync)
{
struct pvr_srv_sync *srv_signal_sync = to_srv_sync(signal_sync);
int fd = -1;
assert(signal_sync);
for (uint32_t i = 0; i < wait_count; i++) {
struct pvr_srv_sync *srv_wait_sync = to_srv_sync(waits[i]);
int ret;
if (!waits[i] || srv_wait_sync->fd < 0)
continue;
ret = sync_accumulate("", &fd, srv_wait_sync->fd);
if (ret) {
if (fd >= 0)
close(fd);
return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
}
}
pvr_srv_set_sync_payload(srv_signal_sync, fd);
return VK_SUCCESS;
}

View File

@ -0,0 +1,38 @@
/*
* Copyright © 2022 Imagination Technologies Ltd.
*
* 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, sublicense, 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 NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS 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 PVR_SRV_JOB_NULL_H
#define PVR_SRV_JOB_NULL_H
#include <stdint.h>
#include <vulkan/vulkan.h>
struct pvr_winsys;
struct vk_sync;
VkResult pvr_srv_winsys_null_job_submit(struct pvr_winsys *ws,
struct vk_sync **waits,
uint32_t wait_count,
struct vk_sync *signal_sync);
#endif /* PVR_SRV_JOB_NULL_H */

View File

@ -39,8 +39,9 @@
#include "pvr_srv_bridge.h"
#include "pvr_srv_job_common.h"
#include "pvr_srv_job_render.h"
#include "pvr_srv_syncobj.h"
#include "pvr_srv_sync.h"
#include "pvr_winsys.h"
#include "util/libsync.h"
#include "util/log.h"
#include "util/macros.h"
#include "vk_alloc.h"
@ -526,8 +527,8 @@ static void pvr_srv_fragment_cmd_init(
VkResult pvr_srv_winsys_render_submit(
const struct pvr_winsys_render_ctx *ctx,
const struct pvr_winsys_render_submit_info *submit_info,
struct pvr_winsys_syncobj **const syncobj_geom_out,
struct pvr_winsys_syncobj **const syncobj_frag_out)
struct vk_sync *signal_sync_geom,
struct vk_sync *signal_sync_frag)
{
const struct pvr_srv_winsys_rt_dataset *srv_rt_dataset =
to_pvr_srv_winsys_rt_dataset(submit_info->rt_dataset);
@ -543,16 +544,14 @@ VkResult pvr_srv_winsys_render_submit(
void *sync_pmrs[PVR_SRV_SYNC_MAX] = { NULL };
uint32_t sync_pmr_count;
struct pvr_winsys_syncobj *geom_signal_syncobj = NULL;
struct pvr_winsys_syncobj *frag_signal_syncobj = NULL;
struct pvr_winsys_syncobj *geom_wait_syncobj = NULL;
struct pvr_winsys_syncobj *frag_wait_syncobj = NULL;
struct pvr_srv_winsys_syncobj *srv_geom_syncobj;
struct pvr_srv_winsys_syncobj *srv_frag_syncobj;
struct pvr_srv_sync *srv_signal_sync_geom;
struct pvr_srv_sync *srv_signal_sync_frag;
struct rogue_fwif_cmd_ta geom_cmd;
struct rogue_fwif_cmd_3d frag_cmd;
int in_frag_fd = -1;
int in_geom_fd = -1;
int fence_frag;
int fence_geom;
@ -561,41 +560,34 @@ VkResult pvr_srv_winsys_render_submit(
pvr_srv_geometry_cmd_init(submit_info, sync_prim, &geom_cmd);
pvr_srv_fragment_cmd_init(submit_info, &frag_cmd);
for (uint32_t i = 0U; i < submit_info->semaphore_count; i++) {
PVR_FROM_HANDLE(pvr_semaphore, sem, submit_info->semaphores[i]);
for (uint32_t i = 0U; i < submit_info->wait_count; i++) {
struct pvr_srv_sync *srv_wait_sync = to_srv_sync(submit_info->waits[i]);
int ret;
if (!sem->syncobj)
if (!submit_info->waits[i] || srv_wait_sync->fd < 0)
continue;
if (submit_info->stage_flags[i] & PVR_PIPELINE_STAGE_GEOM_BIT) {
result = pvr_srv_winsys_syncobjs_merge(sem->syncobj,
geom_wait_syncobj,
&geom_wait_syncobj);
if (result != VK_SUCCESS)
goto err_destroy_wait_syncobjs;
ret = sync_accumulate("", &in_geom_fd, srv_wait_sync->fd);
if (ret) {
result = vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
goto err_close_in_fds;
}
submit_info->stage_flags[i] &= ~PVR_PIPELINE_STAGE_GEOM_BIT;
}
if (submit_info->stage_flags[i] & PVR_PIPELINE_STAGE_FRAG_BIT) {
result = pvr_srv_winsys_syncobjs_merge(sem->syncobj,
frag_wait_syncobj,
&frag_wait_syncobj);
if (result != VK_SUCCESS)
goto err_destroy_wait_syncobjs;
ret = sync_accumulate("", &in_frag_fd, srv_wait_sync->fd);
if (ret) {
result = vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
goto err_close_in_fds;
}
submit_info->stage_flags[i] &= ~PVR_PIPELINE_STAGE_FRAG_BIT;
}
if (submit_info->stage_flags[i] == 0U) {
pvr_srv_winsys_syncobj_destroy(sem->syncobj);
sem->syncobj = NULL;
}
}
srv_geom_syncobj = to_pvr_srv_winsys_syncobj(geom_wait_syncobj);
srv_frag_syncobj = to_pvr_srv_winsys_syncobj(frag_wait_syncobj);
if (submit_info->bo_count <= ARRAY_SIZE(sync_pmrs)) {
sync_pmr_count = submit_info->bo_count;
} else {
@ -629,105 +621,76 @@ VkResult pvr_srv_winsys_render_submit(
sync_prim->value++;
do {
result =
pvr_srv_rgx_kick_render2(srv_ws->render_fd,
srv_ctx->handle,
/* Currently no support for cache operations.
*/
0,
NULL,
NULL,
NULL,
1,
&sync_prim->srv_ws->sync_block_handle,
&sync_prim->offset,
&sync_prim->value,
0,
NULL,
NULL,
NULL,
sync_prim->srv_ws->sync_block_handle,
sync_prim->offset,
sync_prim->value,
geom_wait_syncobj ? srv_geom_syncobj->fd : -1,
srv_ctx->timeline_geom,
&fence_geom,
"GEOM",
frag_wait_syncobj ? srv_frag_syncobj->fd : -1,
srv_ctx->timeline_frag,
&fence_frag,
"FRAG",
sizeof(geom_cmd),
(uint8_t *)&geom_cmd,
/* Currently no support for PRs. */
0,
/* Currently no support for PRs. */
NULL,
sizeof(frag_cmd),
(uint8_t *)&frag_cmd,
submit_info->job_num,
true, /* Always kick the TA. */
true, /* Always kick a PR. */
submit_info->run_frag,
false,
0,
rt_data_handle,
/* Currently no support for PRs. */
NULL,
/* Currently no support for PRs. */
NULL,
sync_pmr_count,
sync_pmr_count ? sync_pmr_flags : NULL,
sync_pmr_count ? sync_pmrs : NULL,
0,
0,
0,
0,
0);
result = pvr_srv_rgx_kick_render2(srv_ws->render_fd,
srv_ctx->handle,
0,
NULL,
NULL,
NULL,
1,
&sync_prim->srv_ws->sync_block_handle,
&sync_prim->offset,
&sync_prim->value,
0,
NULL,
NULL,
NULL,
sync_prim->srv_ws->sync_block_handle,
sync_prim->offset,
sync_prim->value,
in_geom_fd,
srv_ctx->timeline_geom,
&fence_geom,
"GEOM",
in_frag_fd,
srv_ctx->timeline_frag,
&fence_frag,
"FRAG",
sizeof(geom_cmd),
(uint8_t *)&geom_cmd,
/* Currently no support for PRs. */
0,
/* Currently no support for PRs. */
NULL,
sizeof(frag_cmd),
(uint8_t *)&frag_cmd,
submit_info->job_num,
true, /* Always kick the TA. */
true, /* Always kick a PR. */
submit_info->run_frag,
false,
0,
rt_data_handle,
/* Currently no support for PRs. */
NULL,
/* Currently no support for PRs. */
NULL,
sync_pmr_count,
sync_pmr_count ? sync_pmr_flags : NULL,
sync_pmr_count ? sync_pmrs : NULL,
0,
0,
0,
0,
0);
} while (result == VK_NOT_READY);
if (result != VK_SUCCESS)
goto err_destroy_wait_syncobjs;
goto err_close_in_fds;
/* Given job submission succeeded, we don't need to close wait fences, these
* should be consumed by the render job itself.
*/
if (geom_wait_syncobj)
srv_geom_syncobj->fd = -1;
srv_signal_sync_geom = to_srv_sync(signal_sync_geom);
srv_signal_sync_frag = to_srv_sync(signal_sync_frag);
pvr_srv_set_sync_payload(srv_signal_sync_geom, fence_geom);
pvr_srv_set_sync_payload(srv_signal_sync_frag, fence_frag);
if (frag_wait_syncobj)
srv_frag_syncobj->fd = -1;
return VK_SUCCESS;
if (fence_geom != -1) {
result =
pvr_srv_winsys_syncobj_create(ctx->ws, false, &geom_signal_syncobj);
if (result != VK_SUCCESS)
goto err_destroy_wait_syncobjs;
err_close_in_fds:
if (in_geom_fd >= 0)
close(in_geom_fd);
pvr_srv_set_syncobj_payload(geom_signal_syncobj, fence_geom);
}
if (fence_frag != -1) {
result =
pvr_srv_winsys_syncobj_create(ctx->ws, false, &frag_signal_syncobj);
if (result != VK_SUCCESS) {
if (geom_signal_syncobj)
pvr_srv_winsys_syncobj_destroy(geom_signal_syncobj);
goto err_destroy_wait_syncobjs;
}
pvr_srv_set_syncobj_payload(frag_signal_syncobj, fence_frag);
}
*syncobj_geom_out = geom_signal_syncobj;
*syncobj_frag_out = frag_signal_syncobj;
err_destroy_wait_syncobjs:
if (geom_wait_syncobj)
pvr_srv_winsys_syncobj_destroy(geom_wait_syncobj);
if (frag_wait_syncobj)
pvr_srv_winsys_syncobj_destroy(frag_wait_syncobj);
if (in_frag_fd >= 0)
close(in_frag_fd);
return result;
}

View File

@ -34,8 +34,8 @@ struct pvr_winsys_render_ctx_create_info;
struct pvr_winsys_render_submit_info;
struct pvr_winsys_rt_dataset;
struct pvr_winsys_rt_dataset_create_info;
struct pvr_winsys_syncobj;
struct pvr_winsys_vma;
struct vk_sync;
/*******************************************
Function prototypes
@ -68,7 +68,7 @@ void pvr_srv_winsys_render_ctx_destroy(struct pvr_winsys_render_ctx *ctx);
VkResult pvr_srv_winsys_render_submit(
const struct pvr_winsys_render_ctx *ctx,
const struct pvr_winsys_render_submit_info *submit_info,
struct pvr_winsys_syncobj **const syncobj_geom_out,
struct pvr_winsys_syncobj **const syncobj_frag_out);
struct vk_sync *signal_sync_geom,
struct vk_sync *signal_sync_frag);
#endif /* PVR_SRV_JOB_RENDER_H */

View File

@ -0,0 +1,325 @@
/*
* Copyright © 2022 Imagination Technologies Ltd.
*
* 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, sublicense, 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 NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <unistd.h>
#include <poll.h>
#include <vulkan/vulkan.h>
#include "pvr_private.h"
#include "pvr_srv.h"
#include "pvr_srv_sync.h"
#include "util/libsync.h"
#include "util/macros.h"
#include "util/timespec.h"
#include "vk_alloc.h"
#include "vk_log.h"
#include "vk_sync.h"
#include "vk_util.h"
static VkResult pvr_srv_sync_init(struct vk_device *device,
struct vk_sync *sync,
uint64_t initial_value)
{
struct pvr_srv_sync *srv_sync = to_srv_sync(sync);
srv_sync->signaled = initial_value ? true : false;
srv_sync->fd = -1;
return VK_SUCCESS;
}
void pvr_srv_sync_finish(struct vk_device *device, struct vk_sync *sync)
{
struct pvr_srv_sync *srv_sync = to_srv_sync(sync);
if (srv_sync->fd != -1)
close(srv_sync->fd);
}
/* Note: function closes the fd. */
static void pvr_set_sync_state(struct pvr_srv_sync *srv_sync, bool signaled)
{
if (srv_sync->fd != -1) {
close(srv_sync->fd);
srv_sync->fd = -1;
}
srv_sync->signaled = signaled;
}
void pvr_srv_set_sync_payload(struct pvr_srv_sync *srv_sync, int payload)
{
if (srv_sync->fd != -1)
close(srv_sync->fd);
srv_sync->fd = payload;
srv_sync->signaled = (payload == -1);
}
static VkResult pvr_srv_sync_signal(struct vk_device *device,
struct vk_sync *sync,
UNUSED uint64_t value)
{
struct pvr_srv_sync *srv_sync = to_srv_sync(sync);
pvr_set_sync_state(srv_sync, true);
return VK_SUCCESS;
}
static VkResult pvr_srv_sync_reset(struct vk_device *device,
struct vk_sync *sync)
{
struct pvr_srv_sync *srv_sync = to_srv_sync(sync);
pvr_set_sync_state(srv_sync, false);
return VK_SUCCESS;
}
/* Careful, timeout might overflow. */
static inline void pvr_start_timeout(struct timespec *timeout,
uint64_t timeout_ns)
{
clock_gettime(CLOCK_MONOTONIC, timeout);
timespec_add_nsec(timeout, timeout, timeout_ns);
}
/* Careful, a negative value might be returned. */
static inline struct timespec
pvr_get_remaining_time(const struct timespec *timeout)
{
struct timespec time;
clock_gettime(CLOCK_MONOTONIC, &time);
timespec_sub(&time, timeout, &time);
return time;
}
/* abs_timeout_ns == 0 -> Get status without waiting.
* abs_timeout_ns == ~0 -> Wait infinitely.
* else wait for the given abs_timeout_ns in nanoseconds. */
static VkResult pvr_srv_sync_wait_many(struct vk_device *device,
uint32_t wait_count,
const struct vk_sync_wait *waits,
enum vk_sync_wait_flags wait_flags,
uint64_t abs_timeout_ns)
{
uint32_t unsignaled_count = 0U;
struct timespec end_time;
VkResult result;
int ppoll_ret;
STACK_ARRAY(struct pollfd, poll_fds, wait_count);
if (!poll_fds)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
if (abs_timeout_ns != 0U && abs_timeout_ns != ~0U) {
/* Syncobj timeouts are signed. */
abs_timeout_ns = MIN2(abs_timeout_ns, (uint64_t)INT64_MAX);
pvr_start_timeout(&end_time, abs_timeout_ns);
}
for (uint32_t i = 0U; i < wait_count; i++) {
struct pvr_srv_sync *srv_sync = to_srv_sync(waits[i].sync);
/* -1 in case if fence is signaled or uninitialized, ppoll will skip the
* fence.
*/
/* FIXME: We don't currently support wait-for-fd path, so the caller
* should make sure all the sync have been assigned before calling this
* function.
*/
if (srv_sync->signaled || srv_sync->fd == -1) {
poll_fds[i].fd = -1;
} else {
poll_fds[i].fd = srv_sync->fd;
unsignaled_count++;
}
poll_fds[i].events = POLLIN;
poll_fds[i].revents = 0U;
}
if (unsignaled_count == 0U) {
result = VK_SUCCESS;
goto end_wait_for_fences;
}
/* FIXME: Fix device loss handling. */
do {
if (abs_timeout_ns == ~0U) {
ppoll_ret = ppoll(poll_fds, wait_count, NULL, NULL);
} else {
struct timespec remaining_time;
if (abs_timeout_ns == 0U) {
remaining_time = (struct timespec){ 0UL, 0UL };
} else {
/* ppoll() returns EINVAL on negative timeout. Nothing to worry.
*/
remaining_time = pvr_get_remaining_time(&end_time);
}
ppoll_ret = ppoll(poll_fds, wait_count, &remaining_time, NULL);
}
if (ppoll_ret > 0U) {
/* ppoll_ret contains the amount of structs updated by poll(). */
unsignaled_count -= ppoll_ret;
/* ppoll_ret > 0 is for early loop termination. */
for (uint32_t i = 0; ppoll_ret > 0 && i < wait_count; i++) {
if (poll_fds[i].revents == 0)
continue;
if (poll_fds[i].revents & (POLLNVAL | POLLERR)) {
result = vk_error(NULL, VK_ERROR_DEVICE_LOST);
goto end_wait_for_fences;
}
pvr_srv_sync_signal(device, waits[i].sync, 0U);
if (wait_flags & VK_SYNC_WAIT_ANY) {
result = VK_SUCCESS;
goto end_wait_for_fences;
}
/* -1 makes ppoll ignore it and set revents to 0. */
poll_fds[i].fd = -1;
ppoll_ret--;
}
/* For zero timeout, just return even if we still have unsignaled
* syncs.
*/
if (abs_timeout_ns == 0U && unsignaled_count != 0U) {
result = VK_TIMEOUT;
goto end_wait_for_fences;
}
} else if (ppoll_ret == 0) {
result = VK_TIMEOUT;
goto end_wait_for_fences;
}
/* Careful as we might have decremented ppoll_ret to 0. */
} while ((ppoll_ret != -1 && unsignaled_count != 0) ||
(ppoll_ret == -1 && (errno == EINTR || errno == EAGAIN)));
/* We assume device loss in case of an unknown error or invalid fd. */
if (ppoll_ret != -1)
result = VK_SUCCESS;
else if (errno == EINVAL)
result = VK_TIMEOUT;
else if (errno == ENOMEM)
result = vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
else
result = vk_error(NULL, VK_ERROR_DEVICE_LOST);
end_wait_for_fences:
STACK_ARRAY_FINISH(poll_fds);
return result;
}
static VkResult pvr_srv_sync_move(struct vk_device *device,
struct vk_sync *dst,
struct vk_sync *src)
{
struct pvr_srv_sync *srv_dst_sync = to_srv_sync(dst);
struct pvr_srv_sync *srv_src_sync = to_srv_sync(src);
if (!(dst->flags & VK_SYNC_IS_SHARED) && !(src->flags & VK_SYNC_IS_SHARED)) {
pvr_srv_set_sync_payload(srv_dst_sync, srv_src_sync->fd);
srv_src_sync->fd = -1;
pvr_srv_sync_reset(device, src);
return VK_SUCCESS;
}
unreachable("srv_sync doesn't support move for shared sync objects.");
return VK_ERROR_UNKNOWN;
}
static VkResult pvr_srv_sync_import_sync_file(struct vk_device *device,
struct vk_sync *sync,
int sync_file)
{
struct pvr_srv_sync *srv_sync = to_srv_sync(sync);
int fd = -1;
if (sync_file >= 0) {
fd = dup(sync_file);
if (fd < 0)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
}
pvr_srv_set_sync_payload(srv_sync, fd);
return VK_SUCCESS;
}
static VkResult pvr_srv_sync_export_sync_file(struct vk_device *device,
struct vk_sync *sync,
int *sync_file)
{
struct pvr_srv_sync *srv_sync = to_srv_sync(sync);
int fd;
if (srv_sync->fd < 0) {
*sync_file = -1;
return VK_SUCCESS;
}
fd = dup(srv_sync->fd);
if (fd < 0)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
*sync_file = fd;
return VK_SUCCESS;
}
const struct vk_sync_type pvr_srv_sync_type = {
.size = sizeof(struct pvr_srv_sync),
/* clang-format off */
.features = VK_SYNC_FEATURE_BINARY |
VK_SYNC_FEATURE_GPU_WAIT |
VK_SYNC_FEATURE_GPU_MULTI_WAIT |
VK_SYNC_FEATURE_CPU_WAIT |
VK_SYNC_FEATURE_CPU_RESET |
VK_SYNC_FEATURE_CPU_SIGNAL |
VK_SYNC_FEATURE_WAIT_ANY,
/* clang-format on */
.init = pvr_srv_sync_init,
.finish = pvr_srv_sync_finish,
.signal = pvr_srv_sync_signal,
.reset = pvr_srv_sync_reset,
.wait_many = pvr_srv_sync_wait_many,
.move = pvr_srv_sync_move,
.import_sync_file = pvr_srv_sync_import_sync_file,
.export_sync_file = pvr_srv_sync_export_sync_file,
};

View File

@ -0,0 +1,61 @@
/*
* Copyright © 2022 Imagination Technologies Ltd.
*
* 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, sublicense, 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 NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS 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 PVR_SRV_SYNC_H
#define PVR_SRV_SYNC_H
#include <stdbool.h>
#include <stddef.h>
#include "pvr_winsys.h"
#include "util/macros.h"
#include "vk_sync.h"
struct vk_device;
struct pvr_srv_sync {
struct vk_sync base;
/* Cached version of completion. */
bool signaled;
int fd;
};
extern const struct vk_sync_type pvr_srv_sync_type;
void pvr_srv_sync_finish(struct vk_device *device, struct vk_sync *sync);
void pvr_srv_set_sync_payload(struct pvr_srv_sync *srv_sync, int payload);
static inline bool pvr_sync_type_is_srv_sync(const struct vk_sync_type *type)
{
return type->finish == pvr_srv_sync_finish;
}
static inline struct pvr_srv_sync *to_srv_sync(struct vk_sync *sync)
{
assert(!sync || pvr_sync_type_is_srv_sync(sync->type));
return container_of(sync, struct pvr_srv_sync, base);
}
#endif /* PVR_SRV_SYNC_H */

View File

@ -1,349 +0,0 @@
/*
* Copyright © 2022 Imagination Technologies Ltd.
*
* 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, sublicense, 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 NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include <fcntl.h>
#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>
#include "pvr_private.h"
#include "pvr_srv.h"
#include "pvr_srv_syncobj.h"
#include "pvr_winsys.h"
#include "util/libsync.h"
#include "util/macros.h"
#include "util/timespec.h"
#include "vk_alloc.h"
#include "vk_log.h"
VkResult
pvr_srv_winsys_syncobj_create(struct pvr_winsys *ws,
bool signaled,
struct pvr_winsys_syncobj **const syncobj_out)
{
struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ws);
struct pvr_srv_winsys_syncobj *srv_syncobj;
srv_syncobj = vk_alloc(srv_ws->alloc,
sizeof(*srv_syncobj),
8,
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
if (!srv_syncobj)
return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
srv_syncobj->base.ws = ws;
srv_syncobj->signaled = signaled;
srv_syncobj->fd = -1;
*syncobj_out = &srv_syncobj->base;
return VK_SUCCESS;
}
void pvr_srv_winsys_syncobj_destroy(struct pvr_winsys_syncobj *syncobj)
{
struct pvr_srv_winsys_syncobj *srv_syncobj;
struct pvr_srv_winsys *srv_ws;
assert(syncobj);
srv_ws = to_pvr_srv_winsys(syncobj->ws);
srv_syncobj = to_pvr_srv_winsys_syncobj(syncobj);
if (srv_syncobj->fd != -1)
close(srv_syncobj->fd);
vk_free(srv_ws->alloc, srv_syncobj);
}
/* Note: function closes the fd. */
static void pvr_set_syncobj_state(struct pvr_srv_winsys_syncobj *srv_syncobj,
bool signaled)
{
if (srv_syncobj->fd != -1) {
close(srv_syncobj->fd);
srv_syncobj->fd = -1;
}
srv_syncobj->signaled = signaled;
}
void pvr_srv_set_syncobj_payload(struct pvr_winsys_syncobj *syncobj,
int payload)
{
struct pvr_srv_winsys_syncobj *srv_syncobj =
to_pvr_srv_winsys_syncobj(syncobj);
if (srv_syncobj->fd != -1)
close(srv_syncobj->fd);
srv_syncobj->fd = payload;
/* FIXME: Is this valid? */
srv_syncobj->signaled = (payload == -1);
}
VkResult
pvr_srv_winsys_syncobjs_reset(struct pvr_winsys *ws,
struct pvr_winsys_syncobj **const syncobjs,
uint32_t count)
{
for (uint32_t i = 0; i < count; i++) {
struct pvr_srv_winsys_syncobj *srv_syncobj;
if (!syncobjs[i])
continue;
srv_syncobj = to_pvr_srv_winsys_syncobj(syncobjs[i]);
pvr_set_syncobj_state(srv_syncobj, false);
}
return VK_SUCCESS;
}
VkResult
pvr_srv_winsys_syncobjs_signal(struct pvr_winsys *ws,
struct pvr_winsys_syncobj **const syncobjs,
uint32_t count)
{
for (uint32_t i = 0; i < count; i++) {
struct pvr_srv_winsys_syncobj *srv_syncobj;
if (!syncobjs[i])
continue;
srv_syncobj = to_pvr_srv_winsys_syncobj(syncobjs[i]);
pvr_set_syncobj_state(srv_syncobj, true);
}
return VK_SUCCESS;
}
/* Careful, timeout might overflow. */
static inline void pvr_start_timeout(struct timespec *timeout,
uint64_t timeout_ns)
{
clock_gettime(CLOCK_MONOTONIC, timeout);
timespec_add_nsec(timeout, timeout, timeout_ns);
}
/* Careful, a negative value might be returned. */
static inline struct timespec
pvr_get_remaining_time(const struct timespec *timeout)
{
struct timespec time;
clock_gettime(CLOCK_MONOTONIC, &time);
timespec_sub(&time, timeout, &time);
return time;
}
/* timeout == 0 -> Get status without waiting.
* timeout == ~0 -> Wait infinitely
* else wait for the given timeout in nanoseconds. */
VkResult
pvr_srv_winsys_syncobjs_wait(struct pvr_winsys *ws,
struct pvr_winsys_syncobj **const syncobjs,
uint32_t count,
bool wait_all,
uint64_t timeout)
{
const struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ws);
uint32_t unsignaled_count = 0U;
struct timespec end_time;
struct pollfd *poll_fds;
VkResult result;
int ppoll_ret;
if (timeout != 0U && timeout != ~0U) {
/* We don't worry about overflow since ppoll() returns EINVAL on
* negative timeout.
*/
pvr_start_timeout(&end_time, timeout);
}
poll_fds = vk_alloc(srv_ws->alloc,
sizeof(*poll_fds) * count,
8,
VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
if (!poll_fds)
return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
for (uint32_t i = 0; i < count; i++) {
struct pvr_srv_winsys_syncobj *srv_syncobj =
to_pvr_srv_winsys_syncobj(syncobjs[i]);
/* -1 in case if fence is signaled or uninitialized, ppoll will skip the
* fence.
*/
if (!srv_syncobj || srv_syncobj->signaled || srv_syncobj->fd == -1) {
poll_fds[i].fd = -1;
} else {
poll_fds[i].fd = srv_syncobj->fd;
unsignaled_count++;
}
poll_fds[i].events = POLLIN;
poll_fds[i].revents = 0U;
}
if (unsignaled_count == 0U) {
result = VK_SUCCESS;
goto end_wait_for_fences;
}
/* TODO: Implement device loss handling like anvil: reporting the loss
* save the reported status, maybe abort() on env flag, etc.
*/
do {
if (timeout == ~0U) {
ppoll_ret = ppoll(poll_fds, count, NULL, NULL);
} else {
struct timespec remaining_time;
if (timeout == 0U) {
remaining_time = (struct timespec){ 0UL, 0UL };
} else {
/* ppoll() returns EINVAL on negative timeout. Nothing to worry.
*/
remaining_time = pvr_get_remaining_time(&end_time);
}
ppoll_ret = ppoll(poll_fds, count, &remaining_time, NULL);
}
if (ppoll_ret > 0U) {
/* ppoll_ret contains the amount of structs updated by poll(). */
unsignaled_count -= ppoll_ret;
/* ppoll_ret > 0 is for early loop termination. */
for (uint32_t i = 0; ppoll_ret > 0 && i < count; i++) {
struct pvr_srv_winsys_syncobj *srv_syncobj;
if (poll_fds[i].revents == 0)
continue;
if (poll_fds[i].revents & (POLLNVAL | POLLERR)) {
result = vk_error(NULL, VK_ERROR_DEVICE_LOST);
goto end_wait_for_fences;
}
srv_syncobj = to_pvr_srv_winsys_syncobj(syncobjs[i]);
pvr_set_syncobj_state(srv_syncobj, true);
if (!wait_all) {
result = VK_SUCCESS;
goto end_wait_for_fences;
}
/* -1 makes ppoll ignore it and set revents to 0. */
poll_fds[i].fd = -1;
ppoll_ret--;
}
/* For zero timeout, just return even if we still have unsignaled
* fences.
*/
if (timeout == 0U && unsignaled_count != 0U) {
result = VK_TIMEOUT;
goto end_wait_for_fences;
}
} else if (ppoll_ret == 0) {
result = VK_TIMEOUT;
goto end_wait_for_fences;
}
/* Careful as we might have decremented ppoll_ret to 0. */
} while ((ppoll_ret != -1 && unsignaled_count != 0) ||
(ppoll_ret == -1 && (errno == EINTR || errno == EAGAIN)));
/* We assume device loss in case of an unknown error or invalid fd. */
if (ppoll_ret != -1)
result = VK_SUCCESS;
else if (errno == EINVAL)
result = VK_TIMEOUT;
else if (errno == ENOMEM)
result = vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
else
result = vk_error(NULL, VK_ERROR_DEVICE_LOST);
end_wait_for_fences:
vk_free(srv_ws->alloc, poll_fds);
return result;
}
VkResult pvr_srv_winsys_syncobjs_merge(struct pvr_winsys_syncobj *src,
struct pvr_winsys_syncobj *target,
struct pvr_winsys_syncobj **syncobj_out)
{
struct pvr_srv_winsys_syncobj *srv_target =
to_pvr_srv_winsys_syncobj(target);
struct pvr_srv_winsys_syncobj *srv_src = to_pvr_srv_winsys_syncobj(src);
struct pvr_srv_winsys_syncobj *srv_output;
struct pvr_winsys_syncobj *output = NULL;
VkResult result;
if (!srv_src || srv_src->fd == -1) {
*syncobj_out = target;
return VK_SUCCESS;
}
result = pvr_srv_winsys_syncobj_create(src->ws, false, &output);
if (result != VK_SUCCESS)
return result;
srv_output = to_pvr_srv_winsys_syncobj(output);
if (!srv_target || srv_target->fd == -1) {
int fd = dup(srv_src->fd);
if (fd < 0) {
result = vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
goto err_syncobj_destroy;
}
pvr_srv_set_syncobj_payload(output, fd);
if (target)
pvr_srv_winsys_syncobj_destroy(target);
*syncobj_out = output;
return VK_SUCCESS;
}
srv_output->fd = sync_merge("", srv_src->fd, srv_target->fd);
if (srv_output->fd < 0) {
result = vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
goto err_syncobj_destroy;
}
pvr_srv_winsys_syncobj_destroy(target);
*syncobj_out = output;
return VK_SUCCESS;
err_syncobj_destroy:
pvr_srv_winsys_syncobj_destroy(output);
return result;
}

View File

@ -1,76 +0,0 @@
/*
* Copyright © 2022 Imagination Technologies Ltd.
*
* 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, sublicense, 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 NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS 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 PVR_SRV_SYNCOBJ_H
#define PVR_SRV_SYNCOBJ_H
#include <stdbool.h>
#include <stdint.h>
#include <vulkan/vulkan.h>
#include "pvr_winsys.h"
#include "util/macros.h"
struct pvr_srv_winsys_syncobj {
struct pvr_winsys_syncobj base;
/* Cached version of completion. */
bool signaled;
int fd;
};
#define to_pvr_srv_winsys_syncobj(syncobj) \
container_of(syncobj, struct pvr_srv_winsys_syncobj, base)
/*******************************************
function prototypes
*******************************************/
VkResult
pvr_srv_winsys_syncobj_create(struct pvr_winsys *ws,
bool signaled,
struct pvr_winsys_syncobj **const syncobj_out);
void pvr_srv_winsys_syncobj_destroy(struct pvr_winsys_syncobj *syncobj);
VkResult
pvr_srv_winsys_syncobjs_reset(struct pvr_winsys *ws,
struct pvr_winsys_syncobj **const syncobjs,
uint32_t count);
VkResult
pvr_srv_winsys_syncobjs_signal(struct pvr_winsys *ws,
struct pvr_winsys_syncobj **const syncobjs,
uint32_t count);
VkResult
pvr_srv_winsys_syncobjs_wait(struct pvr_winsys *ws,
struct pvr_winsys_syncobj **const syncobjs,
uint32_t count,
bool wait_all,
uint64_t timeout);
VkResult pvr_srv_winsys_syncobjs_merge(struct pvr_winsys_syncobj *src,
struct pvr_winsys_syncobj *target,
struct pvr_winsys_syncobj **out);
void pvr_srv_set_syncobj_payload(struct pvr_winsys_syncobj *syncobj,
int payload);
#endif /* PVR_SRV_SYNCOBJ_H */