#include "vk_sync_dummy.h"
#include "vk_util.h"
+static VkResult pvr_driver_queue_submit(struct vk_queue *queue,
+ struct vk_queue_submit *submit);
+
static VkResult pvr_queue_init(struct pvr_device *device,
struct pvr_queue *queue,
const VkDeviceQueueCreateInfo *pCreateInfo,
queue->query_ctx = query_ctx;
queue->transfer_ctx = transfer_ctx;
+ queue->vk.driver_submit = pvr_driver_queue_submit;
+
return VK_SUCCESS;
err_query_ctx_destroy:
static void pvr_queue_finish(struct pvr_queue *queue)
{
- for (uint32_t i = 0; i < ARRAY_SIZE(queue->job_dependancy); i++) {
- if (queue->job_dependancy[i])
- vk_sync_destroy(&queue->device->vk, queue->job_dependancy[i]);
+ for (uint32_t i = 0; i < ARRAY_SIZE(queue->next_job_wait_sync); i++) {
+ if (queue->next_job_wait_sync[i])
+ vk_sync_destroy(&queue->device->vk, queue->next_job_wait_sync[i]);
}
- for (uint32_t i = 0; i < ARRAY_SIZE(queue->completion); i++) {
- if (queue->completion[i])
- vk_sync_destroy(&queue->device->vk, queue->completion[i]);
+ for (uint32_t i = 0; i < ARRAY_SIZE(queue->last_job_signal_sync); i++) {
+ if (queue->last_job_signal_sync[i])
+ vk_sync_destroy(&queue->device->vk, queue->last_job_signal_sync[i]);
}
pvr_render_ctx_destroy(queue->gfx_ctx);
vk_free(&device->vk.alloc, device->queues);
}
-VkResult pvr_QueueWaitIdle(VkQueue _queue)
-{
- PVR_FROM_HANDLE(pvr_queue, queue, _queue);
-
- for (int i = 0U; i < ARRAY_SIZE(queue->completion); i++) {
- VkResult result;
-
- if (!queue->completion[i])
- continue;
-
- result = vk_sync_wait(&queue->device->vk,
- queue->completion[i],
- 0U,
- VK_SYNC_WAIT_COMPLETE,
- UINT64_MAX);
- if (result != VK_SUCCESS)
- return result;
- }
-
- return VK_SUCCESS;
-}
-
-static VkResult
-pvr_process_graphics_cmd_part(struct pvr_device *const device,
- struct pvr_render_ctx *const gfx_ctx,
- struct pvr_render_job *const job,
- struct vk_sync *const geom_barrier,
- struct vk_sync *const frag_barrier,
- struct vk_sync **const geom_completion,
- struct vk_sync **const frag_completion,
- struct vk_sync **const waits,
- const uint32_t wait_count,
- uint32_t *const stage_flags)
+static VkResult pvr_process_graphics_cmd(struct pvr_device *device,
+ struct pvr_queue *queue,
+ struct pvr_cmd_buffer *cmd_buffer,
+ struct pvr_sub_cmd_gfx *sub_cmd)
{
- struct vk_sync *geom_sync = NULL;
- struct vk_sync *frag_sync = NULL;
+ pvr_dev_addr_t original_ctrl_stream_addr = { 0 };
+ struct vk_sync *geom_signal_sync;
+ struct vk_sync *frag_signal_sync;
VkResult result;
- /* For each of geom and frag, a completion sync is optional but only allowed
- * iff barrier is present.
- */
- assert(geom_barrier || !geom_completion);
- assert(frag_barrier || !frag_completion);
-
- if (geom_barrier) {
- result = vk_sync_create(&device->vk,
- &device->pdevice->ws->syncobj_type,
- 0U,
- 0UL,
- &geom_sync);
- if (result != VK_SUCCESS)
- goto err_out;
- }
-
- if (frag_barrier) {
- result = vk_sync_create(&device->vk,
- &device->pdevice->ws->syncobj_type,
- 0U,
- 0UL,
- &frag_sync);
- if (result != VK_SUCCESS)
- goto err_destroy_sync_geom;
- }
+ result = vk_sync_create(&device->vk,
+ &device->pdevice->ws->syncobj_type,
+ 0U,
+ 0UL,
+ &geom_signal_sync);
+ if (result != VK_SUCCESS)
+ return result;
- result = pvr_render_job_submit(gfx_ctx,
- job,
- geom_barrier,
- frag_barrier,
- waits,
- wait_count,
- stage_flags,
- geom_sync,
- frag_sync);
+ result = vk_sync_create(&device->vk,
+ &device->pdevice->ws->syncobj_type,
+ 0U,
+ 0UL,
+ &frag_signal_sync);
if (result != VK_SUCCESS)
- goto err_destroy_sync_frag;
+ goto err_destroy_geom_sync;
- /* Replace the completion fences. */
- if (geom_sync) {
- if (*geom_completion)
- vk_sync_destroy(&device->vk, *geom_completion);
+ /* FIXME: DoShadowLoadOrStore() */
- *geom_completion = geom_sync;
- }
+ /* Perform two render submits when using multiple framebuffer layers. The
+ * first submit contains just geometry, while the second only terminates
+ * (and triggers the fragment render if originally specified). This is needed
+ * because the render target cache gets cleared on terminating submits, which
+ * could result in missing primitives.
+ */
+ if (pvr_sub_cmd_gfx_requires_split_submit(sub_cmd)) {
+ /* If fragment work shouldn't be run there's no need for a split,
+ * and if geometry_terminate is false this kick can't have a fragment
+ * stage without another terminating geometry kick.
+ */
+ assert(sub_cmd->job.geometry_terminate && sub_cmd->job.run_frag);
- if (frag_sync) {
- if (*frag_completion)
- vk_sync_destroy(&device->vk, *frag_completion);
+ /* First submit must not touch fragment work. */
+ sub_cmd->job.geometry_terminate = false;
+ sub_cmd->job.run_frag = false;
- *frag_completion = frag_sync;
- }
+ result =
+ pvr_render_job_submit(queue->gfx_ctx,
+ &sub_cmd->job,
+ queue->next_job_wait_sync[PVR_JOB_TYPE_GEOM],
+ NULL,
+ NULL,
+ NULL);
- return VK_SUCCESS;
+ sub_cmd->job.geometry_terminate = true;
+ sub_cmd->job.run_frag = true;
-err_destroy_sync_frag:
- if (frag_sync)
- vk_sync_destroy(&device->vk, frag_sync);
+ if (result != VK_SUCCESS)
+ goto err_destroy_frag_sync;
-err_destroy_sync_geom:
- if (geom_sync)
- vk_sync_destroy(&device->vk, geom_sync);
+ original_ctrl_stream_addr = sub_cmd->job.ctrl_stream_addr;
-err_out:
- return result;
-}
+ /* Second submit contains only a trivial control stream to terminate the
+ * geometry work.
+ */
+ assert(sub_cmd->terminate_ctrl_stream);
+ sub_cmd->job.ctrl_stream_addr =
+ sub_cmd->terminate_ctrl_stream->vma->dev_addr;
+ }
-static VkResult
-pvr_process_split_graphics_cmd(struct pvr_device *const device,
- struct pvr_render_ctx *const gfx_ctx,
- struct pvr_sub_cmd_gfx *sub_cmd,
- struct vk_sync *const geom_barrier,
- struct vk_sync *const frag_barrier,
- struct vk_sync **const geom_completion,
- struct vk_sync **const frag_completion,
- struct vk_sync **const waits,
- const uint32_t wait_count,
- uint32_t *const stage_flags)
-{
- struct pvr_render_job *const job = &sub_cmd->job;
- const pvr_dev_addr_t original_ctrl_stream_addr = job->ctrl_stream_addr;
- const bool original_geometry_terminate = job->geometry_terminate;
- const bool original_run_frag = job->run_frag;
- VkResult result;
+ result = pvr_render_job_submit(queue->gfx_ctx,
+ &sub_cmd->job,
+ queue->next_job_wait_sync[PVR_JOB_TYPE_GEOM],
+ queue->next_job_wait_sync[PVR_JOB_TYPE_FRAG],
+ geom_signal_sync,
+ frag_signal_sync);
- /* First submit must not touch fragment work. */
- job->geometry_terminate = false;
- job->run_frag = false;
+ if (original_ctrl_stream_addr.addr > 0)
+ sub_cmd->job.ctrl_stream_addr = original_ctrl_stream_addr;
- result = pvr_process_graphics_cmd_part(device,
- gfx_ctx,
- job,
- geom_barrier,
- NULL,
- geom_completion,
- NULL,
- waits,
- wait_count,
- stage_flags);
+ if (result != VK_SUCCESS)
+ goto err_destroy_frag_sync;
- job->geometry_terminate = original_geometry_terminate;
- job->run_frag = original_run_frag;
+ /* Replace the completion fences. */
+ if (queue->last_job_signal_sync[PVR_JOB_TYPE_GEOM]) {
+ vk_sync_destroy(&device->vk,
+ queue->last_job_signal_sync[PVR_JOB_TYPE_GEOM]);
+ }
- if (result != VK_SUCCESS)
- return result;
+ queue->last_job_signal_sync[PVR_JOB_TYPE_GEOM] = geom_signal_sync;
- /* Second submit contains only a trivial control stream to terminate the
- * geometry work.
- */
- assert(sub_cmd->terminate_ctrl_stream);
- job->ctrl_stream_addr = sub_cmd->terminate_ctrl_stream->vma->dev_addr;
-
- result = pvr_process_graphics_cmd_part(device,
- gfx_ctx,
- job,
- NULL,
- frag_barrier,
- NULL,
- frag_completion,
- waits,
- wait_count,
- stage_flags);
-
- job->ctrl_stream_addr = original_ctrl_stream_addr;
+ if (queue->last_job_signal_sync[PVR_JOB_TYPE_FRAG]) {
+ vk_sync_destroy(&device->vk,
+ queue->last_job_signal_sync[PVR_JOB_TYPE_FRAG]);
+ }
- return result;
-}
+ queue->last_job_signal_sync[PVR_JOB_TYPE_FRAG] = frag_signal_sync;
-static VkResult
-pvr_process_graphics_cmd(struct pvr_device *device,
- struct pvr_queue *queue,
- struct pvr_cmd_buffer *cmd_buffer,
- struct pvr_sub_cmd_gfx *sub_cmd,
- struct vk_sync *barrier_geom,
- struct vk_sync *barrier_frag,
- struct vk_sync **waits,
- uint32_t wait_count,
- uint32_t *stage_flags,
- struct vk_sync *completions[static PVR_JOB_TYPE_MAX])
-{
/* FIXME: DoShadowLoadOrStore() */
- /* Perform two render submits when using multiple framebuffer layers. The
- * first submit contains just geometry, while the second only terminates
- * (and triggers the fragment render if originally specified). This is needed
- * because the render target cache gets cleared on terminating submits, which
- * could result in missing primitives.
- */
- if (pvr_sub_cmd_gfx_requires_split_submit(sub_cmd)) {
- return pvr_process_split_graphics_cmd(device,
- queue->gfx_ctx,
- sub_cmd,
- barrier_geom,
- barrier_frag,
- &completions[PVR_JOB_TYPE_GEOM],
- &completions[PVR_JOB_TYPE_FRAG],
- waits,
- wait_count,
- stage_flags);
- }
+ return VK_SUCCESS;
- return pvr_process_graphics_cmd_part(device,
- queue->gfx_ctx,
- &sub_cmd->job,
- barrier_geom,
- barrier_frag,
- &completions[PVR_JOB_TYPE_GEOM],
- &completions[PVR_JOB_TYPE_FRAG],
- waits,
- wait_count,
- stage_flags);
+err_destroy_frag_sync:
+ vk_sync_destroy(&device->vk, frag_signal_sync);
+err_destroy_geom_sync:
+ vk_sync_destroy(&device->vk, geom_signal_sync);
- /* FIXME: DoShadowLoadOrStore() */
+ return result;
}
-static VkResult
-pvr_process_compute_cmd(struct pvr_device *device,
- struct pvr_queue *queue,
- struct pvr_sub_cmd_compute *sub_cmd,
- struct vk_sync *barrier,
- struct vk_sync **waits,
- uint32_t wait_count,
- uint32_t *stage_flags,
- struct vk_sync *completions[static PVR_JOB_TYPE_MAX])
+static VkResult pvr_process_compute_cmd(struct pvr_device *device,
+ struct pvr_queue *queue,
+ struct pvr_sub_cmd_compute *sub_cmd)
{
struct vk_sync *sync;
VkResult result;
if (result != VK_SUCCESS)
return result;
- result = pvr_compute_job_submit(queue->compute_ctx,
- sub_cmd,
- barrier,
- waits,
- wait_count,
- stage_flags,
- sync);
+ result =
+ pvr_compute_job_submit(queue->compute_ctx,
+ sub_cmd,
+ queue->next_job_wait_sync[PVR_JOB_TYPE_COMPUTE],
+ sync);
if (result != VK_SUCCESS) {
vk_sync_destroy(&device->vk, sync);
return result;
}
- /* Replace the completion fences. */
- if (completions[PVR_JOB_TYPE_COMPUTE])
- vk_sync_destroy(&device->vk, completions[PVR_JOB_TYPE_COMPUTE]);
+ /* Replace the signal fence. */
+ if (queue->last_job_signal_sync[PVR_JOB_TYPE_COMPUTE]) {
+ vk_sync_destroy(&device->vk,
+ queue->last_job_signal_sync[PVR_JOB_TYPE_COMPUTE]);
+ }
- completions[PVR_JOB_TYPE_COMPUTE] = sync;
+ queue->last_job_signal_sync[PVR_JOB_TYPE_COMPUTE] = sync;
return result;
}
-static VkResult
-pvr_process_transfer_cmds(struct pvr_device *device,
- struct pvr_queue *queue,
- struct pvr_sub_cmd_transfer *sub_cmd,
- struct vk_sync *barrier,
- struct vk_sync **waits,
- uint32_t wait_count,
- uint32_t *stage_flags,
- struct vk_sync *completions[static PVR_JOB_TYPE_MAX])
+static VkResult pvr_process_transfer_cmds(struct pvr_device *device,
+ struct pvr_queue *queue,
+ struct pvr_sub_cmd_transfer *sub_cmd)
{
struct vk_sync *sync;
VkResult result;
if (result != VK_SUCCESS)
return result;
- result = pvr_transfer_job_submit(device,
- queue->transfer_ctx,
- sub_cmd,
- barrier,
- waits,
- wait_count,
- stage_flags,
- sync);
+ result =
+ pvr_transfer_job_submit(device,
+ queue->transfer_ctx,
+ sub_cmd,
+ queue->next_job_wait_sync[PVR_JOB_TYPE_TRANSFER],
+ sync);
if (result != VK_SUCCESS) {
vk_sync_destroy(&device->vk, sync);
return result;
}
- /* Replace the completion fences. */
- if (completions[PVR_JOB_TYPE_TRANSFER])
- vk_sync_destroy(&device->vk, completions[PVR_JOB_TYPE_TRANSFER]);
+ /* Replace the signal syncs. */
+ if (queue->last_job_signal_sync[PVR_JOB_TYPE_TRANSFER]) {
+ vk_sync_destroy(&device->vk,
+ queue->last_job_signal_sync[PVR_JOB_TYPE_TRANSFER]);
+ }
- completions[PVR_JOB_TYPE_TRANSFER] = sync;
+ queue->last_job_signal_sync[PVR_JOB_TYPE_TRANSFER] = sync;
return result;
}
-static VkResult pvr_process_occlusion_query_cmd(
- struct pvr_device *device,
- struct pvr_queue *queue,
- struct pvr_sub_cmd_compute *sub_cmd,
- struct vk_sync *barrier,
- struct vk_sync **waits,
- uint32_t wait_count,
- uint32_t *stage_flags,
- struct vk_sync *completions[static PVR_JOB_TYPE_MAX])
+static VkResult
+pvr_process_occlusion_query_cmd(struct pvr_device *device,
+ struct pvr_queue *queue,
+ struct pvr_sub_cmd_compute *sub_cmd)
{
struct vk_sync *sync;
VkResult result;
if (result != VK_SUCCESS)
return result;
- result = pvr_compute_job_submit(queue->query_ctx,
- sub_cmd,
- barrier,
- waits,
- wait_count,
- stage_flags,
- sync);
+ result = pvr_compute_job_submit(
+ queue->query_ctx,
+ sub_cmd,
+ queue->next_job_wait_sync[PVR_JOB_TYPE_OCCLUSION_QUERY],
+ sync);
if (result != VK_SUCCESS) {
vk_sync_destroy(&device->vk, sync);
return result;
}
- if (completions[PVR_JOB_TYPE_OCCLUSION_QUERY])
- vk_sync_destroy(&device->vk, completions[PVR_JOB_TYPE_OCCLUSION_QUERY]);
+ if (queue->last_job_signal_sync[PVR_JOB_TYPE_OCCLUSION_QUERY]) {
+ vk_sync_destroy(
+ &device->vk,
+ queue->last_job_signal_sync[PVR_JOB_TYPE_OCCLUSION_QUERY]);
+ }
- completions[PVR_JOB_TYPE_OCCLUSION_QUERY] = sync;
+ queue->last_job_signal_sync[PVR_JOB_TYPE_OCCLUSION_QUERY] = sync;
return result;
}
-static VkResult pvr_process_event_cmd_barrier(
- struct pvr_device *device,
- struct pvr_sub_cmd_event *sub_cmd,
- struct vk_sync *barriers[static PVR_JOB_TYPE_MAX],
- struct vk_sync *per_cmd_buffer_syncobjs[static PVR_JOB_TYPE_MAX],
- struct vk_sync *per_submit_syncobjs[static PVR_JOB_TYPE_MAX],
- struct vk_sync *queue_syncobjs[static PVR_JOB_TYPE_MAX],
- struct vk_sync *previous_queue_syncobjs[static PVR_JOB_TYPE_MAX])
+static VkResult pvr_process_event_cmd_barrier(struct pvr_device *device,
+ struct pvr_queue *queue,
+ struct pvr_sub_cmd_event *sub_cmd)
{
const uint32_t src_mask = sub_cmd->barrier.wait_for_stage_mask;
const uint32_t dst_mask = sub_cmd->barrier.wait_at_stage_mask;
- const bool in_render_pass = sub_cmd->barrier.in_render_pass;
- struct vk_sync *new_barriers[PVR_JOB_TYPE_MAX] = { 0 };
- struct vk_sync *completions[PVR_JOB_TYPE_MAX] = { 0 };
- struct vk_sync *src_syncobjs[PVR_JOB_TYPE_MAX];
- uint32_t src_syncobj_count = 0;
+ struct vk_sync_wait wait_syncs[PVR_JOB_TYPE_MAX + 1];
+ uint32_t src_wait_count = 0;
VkResult result;
assert(sub_cmd->type == PVR_EVENT_TYPE_BARRIER);
assert(!(src_mask & ~PVR_PIPELINE_STAGE_ALL_BITS));
assert(!(dst_mask & ~PVR_PIPELINE_STAGE_ALL_BITS));
- /* TODO: We're likely over synchronizing here, but the kernel doesn't
- * guarantee that jobs submitted on a context will execute and complete in
- * order, even though in practice they will, so we play it safe and don't
- * make any assumptions. If the kernel starts to offer this guarantee then
- * remove the extra dependencies being added here.
- */
-
u_foreach_bit (stage, src_mask) {
- struct vk_sync *syncobj;
-
- syncobj = per_cmd_buffer_syncobjs[stage];
-
- if (!in_render_pass & !syncobj) {
- if (per_submit_syncobjs[stage])
- syncobj = per_submit_syncobjs[stage];
- else if (queue_syncobjs[stage])
- syncobj = queue_syncobjs[stage];
- else if (previous_queue_syncobjs[stage])
- syncobj = previous_queue_syncobjs[stage];
+ if (queue->last_job_signal_sync[stage]) {
+ wait_syncs[src_wait_count++] = (struct vk_sync_wait){
+ .sync = queue->last_job_signal_sync[stage],
+ .stage_mask = ~(VkPipelineStageFlags2)0,
+ .wait_value = 0,
+ };
}
-
- if (!syncobj)
- continue;
-
- src_syncobjs[src_syncobj_count++] = syncobj;
}
/* No previous src jobs that need finishing so no need for a barrier. */
- if (src_syncobj_count == 0)
+ if (src_wait_count == 0)
return VK_SUCCESS;
u_foreach_bit (stage, dst_mask) {
- struct vk_sync *completion;
+ uint32_t wait_count = src_wait_count;
+ struct vk_sync_signal signal;
+ struct vk_sync *signal_sync;
result = vk_sync_create(&device->vk,
&device->pdevice->ws->syncobj_type,
0U,
0UL,
- &completion);
+ &signal_sync);
if (result != VK_SUCCESS)
- goto err_destroy_completions;
-
- result = device->ws->ops->null_job_submit(device->ws,
- src_syncobjs,
- src_syncobj_count,
- completion);
- if (result != VK_SUCCESS) {
- vk_sync_destroy(&device->vk, completion);
+ return result;
- goto err_destroy_completions;
+ signal = (struct vk_sync_signal){
+ .sync = signal_sync,
+ .stage_mask = ~(VkPipelineStageFlags2)0,
+ .signal_value = 0,
+ };
+
+ if (queue->next_job_wait_sync[stage]) {
+ wait_syncs[wait_count++] = (struct vk_sync_wait){
+ .sync = queue->next_job_wait_sync[stage],
+ .stage_mask = ~(VkPipelineStageFlags2)0,
+ .wait_value = 0,
+ };
}
- completions[stage] = completion;
- }
-
- u_foreach_bit (stage, dst_mask) {
- struct vk_sync *barrier_src_syncobjs[2];
- uint32_t barrier_src_syncobj_count = 0;
- struct vk_sync *barrier;
- VkResult result;
-
- assert(completions[stage]);
- barrier_src_syncobjs[barrier_src_syncobj_count++] = completions[stage];
-
- /* If there is a previous barrier we want to merge it with the new one.
- *
- * E.g.
- * A <compute>, B <compute>,
- * X <barrier src=compute, dst=graphics>,
- * C <transfer>
- * Y <barrier src=transfer, dst=graphics>,
- * D <graphics>
- *
- * X barriers A and B at D. Y barriers C at D. So we want to merge both
- * X and Y graphics vk_sync barriers to pass to D.
- *
- * Note that this is the same as:
- * A <compute>, B <compute>, C <transfer>
- * X <barrier src=compute, dst=graphics>,
- * Y <barrier src=transfer, dst=graphics>,
- * D <graphics>
- *
- */
- if (barriers[stage])
- barrier_src_syncobjs[barrier_src_syncobj_count++] = barriers[stage];
-
- result = vk_sync_create(&device->vk,
- &device->pdevice->ws->syncobj_type,
- 0U,
- 0UL,
- &barrier);
- if (result != VK_SUCCESS)
- goto err_destroy_new_barriers;
-
result = device->ws->ops->null_job_submit(device->ws,
- barrier_src_syncobjs,
- barrier_src_syncobj_count,
- barrier);
+ wait_syncs,
+ wait_count,
+ &signal);
if (result != VK_SUCCESS) {
- vk_sync_destroy(&device->vk, barrier);
-
- goto err_destroy_new_barriers;
+ vk_sync_destroy(&device->vk, signal_sync);
+ return result;
}
- new_barriers[stage] = barrier;
- }
-
- u_foreach_bit (stage, dst_mask) {
- if (per_cmd_buffer_syncobjs[stage])
- vk_sync_destroy(&device->vk, per_cmd_buffer_syncobjs[stage]);
-
- per_cmd_buffer_syncobjs[stage] = completions[stage];
+ if (queue->next_job_wait_sync[stage])
+ vk_sync_destroy(&device->vk, queue->next_job_wait_sync[stage]);
- if (barriers[stage])
- vk_sync_destroy(&device->vk, barriers[stage]);
-
- barriers[stage] = new_barriers[stage];
+ queue->next_job_wait_sync[stage] = signal_sync;
}
return VK_SUCCESS;
-
-err_destroy_new_barriers:
- u_foreach_bit (stage, dst_mask) {
- if (new_barriers[stage])
- vk_sync_destroy(&device->vk, new_barriers[stage]);
- }
-
-err_destroy_completions:
- u_foreach_bit (stage, dst_mask) {
- if (completions[stage])
- vk_sync_destroy(&device->vk, completions[stage]);
- }
-
- return result;
}
-static VkResult pvr_process_event_cmd_set_or_reset(
- struct pvr_device *device,
- struct pvr_sub_cmd_event *sub_cmd,
- struct vk_sync *per_cmd_buffer_syncobjs[static PVR_JOB_TYPE_MAX])
+static VkResult
+pvr_process_event_cmd_set_or_reset(struct pvr_device *device,
+ struct pvr_queue *queue,
+ struct pvr_sub_cmd_event *sub_cmd)
{
/* Not PVR_JOB_TYPE_MAX since that also includes
* PVR_JOB_TYPE_OCCLUSION_QUERY so no stage in the src mask.
*/
- struct vk_sync *src_syncobjs[PVR_NUM_SYNC_PIPELINE_STAGES];
- struct vk_sync *new_event_syncobj;
- uint32_t src_syncobj_count = 0;
+ struct vk_sync_wait waits[PVR_NUM_SYNC_PIPELINE_STAGES];
+ struct vk_sync_signal signal;
+ struct vk_sync *signal_sync;
+
uint32_t wait_for_stage_mask;
+ uint32_t wait_count = 0;
VkResult result;
assert(sub_cmd->type == PVR_EVENT_TYPE_SET ||
assert(!(wait_for_stage_mask & ~PVR_PIPELINE_STAGE_ALL_BITS));
u_foreach_bit (stage, wait_for_stage_mask) {
- if (!per_cmd_buffer_syncobjs[stage])
+ if (!queue->last_job_signal_sync[stage])
continue;
- src_syncobjs[src_syncobj_count++] = per_cmd_buffer_syncobjs[stage];
+ waits[wait_count++] = (struct vk_sync_wait){
+ .sync = queue->last_job_signal_sync[stage],
+ .stage_mask = ~(VkPipelineStageFlags2)0,
+ .wait_value = 0,
+ };
}
- assert(src_syncobj_count <= ARRAY_SIZE(src_syncobjs));
-
result = vk_sync_create(&device->vk,
&device->pdevice->ws->syncobj_type,
0U,
0UL,
- &new_event_syncobj);
+ &signal_sync);
if (result != VK_SUCCESS)
return result;
- result = device->ws->ops->null_job_submit(device->ws,
- src_syncobjs,
- src_syncobj_count,
- new_event_syncobj);
- if (result != VK_SUCCESS) {
- vk_sync_destroy(&device->vk, new_event_syncobj);
+ signal = (struct vk_sync_signal){
+ .sync = signal_sync,
+ .stage_mask = ~(VkPipelineStageFlags2)0,
+ .signal_value = 0,
+ };
+ result =
+ device->ws->ops->null_job_submit(device->ws, waits, wait_count, &signal);
+ if (result != VK_SUCCESS) {
+ vk_sync_destroy(&device->vk, signal_sync);
return result;
}
if (sub_cmd->set.event->sync)
vk_sync_destroy(&device->vk, sub_cmd->set.event->sync);
- sub_cmd->set.event->sync = new_event_syncobj;
+ sub_cmd->set.event->sync = signal_sync;
sub_cmd->set.event->state = PVR_EVENT_STATE_SET_BY_DEVICE;
} else {
if (sub_cmd->reset.event->sync)
vk_sync_destroy(&device->vk, sub_cmd->reset.event->sync);
- sub_cmd->reset.event->sync = new_event_syncobj;
+ sub_cmd->reset.event->sync = signal_sync;
sub_cmd->reset.event->state = PVR_EVENT_STATE_RESET_BY_DEVICE;
}
* \parma[in,out] per_cmd_buffer_syncobjs Completion syncobjs for the command
* buffer being processed.
*/
-static VkResult pvr_process_event_cmd_wait(
- struct pvr_device *device,
- struct pvr_sub_cmd_event *sub_cmd,
- struct vk_sync *barriers[static PVR_JOB_TYPE_MAX],
- struct vk_sync *per_cmd_buffer_syncobjs[static PVR_JOB_TYPE_MAX])
+static VkResult pvr_process_event_cmd_wait(struct pvr_device *device,
+ struct pvr_queue *queue,
+ struct pvr_sub_cmd_event *sub_cmd)
{
- /* +1 if there's a previous barrier which we need to merge. */
- struct vk_sync *new_barriers[PVR_JOB_TYPE_MAX];
- struct vk_sync *completions[PVR_JOB_TYPE_MAX];
uint32_t dst_mask = 0;
+ VkResult result;
- STACK_ARRAY(struct vk_sync *, src_syncobjs, sub_cmd->wait.count + 1);
- if (!src_syncobjs)
+ STACK_ARRAY(struct vk_sync_wait, waits, sub_cmd->wait.count + 1);
+ if (!waits)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
for (uint32_t i = 0; i < sub_cmd->wait.count; i++)
dst_mask |= sub_cmd->wait.wait_at_stage_masks[i];
u_foreach_bit (stage, dst_mask) {
- uint32_t src_syncobj_count = 0;
- struct vk_sync *completion;
- struct vk_sync *barrier;
- VkResult result;
-
- if (barriers[stage])
- src_syncobjs[src_syncobj_count++] = barriers[stage];
+ struct vk_sync_signal signal;
+ struct vk_sync *signal_sync;
+ uint32_t wait_count = 0;
for (uint32_t i = 0; i < sub_cmd->wait.count; i++) {
- if (sub_cmd->wait.wait_at_stage_masks[i] & stage)
- src_syncobjs[src_syncobj_count++] = sub_cmd->wait.events[i]->sync;
+ if (sub_cmd->wait.wait_at_stage_masks[i] & stage) {
+ waits[wait_count++] = (struct vk_sync_wait){
+ .sync = sub_cmd->wait.events[i]->sync,
+ .stage_mask = ~(VkPipelineStageFlags2)0,
+ .wait_value = 0,
+ };
+ }
}
- /* Create completion. */
+ if (!wait_count)
+ continue;
- result = vk_sync_create(&device->vk,
- &device->pdevice->ws->syncobj_type,
- 0U,
- 0UL,
- &completion);
- if (result != VK_SUCCESS) {
- STACK_ARRAY_FINISH(src_syncobjs);
- return result;
+ if (queue->next_job_wait_sync[stage]) {
+ waits[wait_count++] = (struct vk_sync_wait){
+ .sync = queue->next_job_wait_sync[stage],
+ .stage_mask = ~(VkPipelineStageFlags2)0,
+ .wait_value = 0,
+ };
}
- result = device->ws->ops->null_job_submit(device->ws,
- src_syncobjs,
- src_syncobj_count,
- completion);
- if (result != VK_SUCCESS) {
- vk_sync_destroy(&device->vk, completion);
- STACK_ARRAY_FINISH(src_syncobjs);
- return result;
- }
-
- completions[stage] = completion;
-
- /* Create barrier. */
-
- /* We can't reuse the completion as a barrier since a barrier can be
- * passed into multiple job submissions based on the dst mask while the
- * completion gets replaced on each job submission so we'd end up in a
- * case where the completion is replaced but other job submissions (of
- * different type, i.e. different stages in the dst mask) get fed the
- * freed barrier resulting in a use after free.
- */
+ assert(wait_count <= (sub_cmd->wait.count + 1));
result = vk_sync_create(&device->vk,
&device->pdevice->ws->syncobj_type,
0U,
0UL,
- &barrier);
- if (result != VK_SUCCESS) {
- vk_sync_destroy(&device->vk, completion);
- STACK_ARRAY_FINISH(src_syncobjs);
- return result;
- }
+ &signal_sync);
+ if (result != VK_SUCCESS)
+ goto err_free_waits;
- result =
- device->ws->ops->null_job_submit(device->ws, &completion, 1, barrier);
+ signal = (struct vk_sync_signal){
+ .sync = signal_sync,
+ .stage_mask = ~(VkPipelineStageFlags2)0,
+ .signal_value = 0,
+ };
+
+ result = device->ws->ops->null_job_submit(device->ws,
+ waits,
+ wait_count,
+ &signal);
if (result != VK_SUCCESS) {
- vk_sync_destroy(&device->vk, barrier);
- vk_sync_destroy(&device->vk, completion);
- STACK_ARRAY_FINISH(src_syncobjs);
- return result;
+ vk_sync_destroy(&device->vk, signal.sync);
+ goto err_free_waits;
}
- new_barriers[stage] = barrier;
- }
-
- u_foreach_bit (stage, dst_mask) {
- if (per_cmd_buffer_syncobjs[stage])
- vk_sync_destroy(&device->vk, per_cmd_buffer_syncobjs[stage]);
-
- per_cmd_buffer_syncobjs[stage] = completions[stage];
-
- if (barriers[stage])
- vk_sync_destroy(&device->vk, barriers[stage]);
+ if (queue->next_job_wait_sync[stage])
+ vk_sync_destroy(&device->vk, queue->next_job_wait_sync[stage]);
- barriers[stage] = new_barriers[stage];
+ queue->next_job_wait_sync[stage] = signal.sync;
}
- STACK_ARRAY_FINISH(src_syncobjs);
+ STACK_ARRAY_FINISH(waits);
return VK_SUCCESS;
+
+err_free_waits:
+ STACK_ARRAY_FINISH(waits);
+
+ return result;
}
-static VkResult pvr_process_event_cmd(
- struct pvr_device *device,
- struct pvr_sub_cmd_event *sub_cmd,
- struct vk_sync *barriers[static PVR_JOB_TYPE_MAX],
- struct vk_sync *per_cmd_buffer_syncobjs[static PVR_JOB_TYPE_MAX],
- struct vk_sync *per_submit_syncobjs[static PVR_JOB_TYPE_MAX],
- struct vk_sync *queue_syncobjs[static PVR_JOB_TYPE_MAX],
- struct vk_sync *previous_queue_syncobjs[static PVR_JOB_TYPE_MAX])
+static VkResult pvr_process_event_cmd(struct pvr_device *device,
+ struct pvr_queue *queue,
+ struct pvr_sub_cmd_event *sub_cmd)
{
switch (sub_cmd->type) {
case PVR_EVENT_TYPE_SET:
case PVR_EVENT_TYPE_RESET:
- return pvr_process_event_cmd_set_or_reset(device,
- sub_cmd,
- per_cmd_buffer_syncobjs);
-
+ return pvr_process_event_cmd_set_or_reset(device, queue, sub_cmd);
case PVR_EVENT_TYPE_WAIT:
- return pvr_process_event_cmd_wait(device,
- sub_cmd,
- barriers,
- per_cmd_buffer_syncobjs);
-
+ return pvr_process_event_cmd_wait(device, queue, sub_cmd);
case PVR_EVENT_TYPE_BARRIER:
- return pvr_process_event_cmd_barrier(device,
- sub_cmd,
- barriers,
- per_cmd_buffer_syncobjs,
- per_submit_syncobjs,
- queue_syncobjs,
- previous_queue_syncobjs);
-
+ return pvr_process_event_cmd_barrier(device, queue, sub_cmd);
default:
unreachable("Invalid event sub-command type.");
};
}
-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 vk_sync *sync;
- VkResult result;
- int fd = -1;
-
- 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)
- 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;
- }
-
- result = vk_sync_export_sync_file(&device->vk, sync, &fd);
- if (result != VK_SUCCESS)
- goto end_set_semaphore_payloads;
-
- 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 end_set_semaphore_payloads;
- }
-
-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 vk_sync *completions[static PVR_JOB_TYPE_MAX],
- VkFence _fence)
-{
- VK_FROM_HANDLE(vk_fence, fence, _fence);
- struct vk_sync *fence_sync;
- 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;
-
- 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;
- }
-
- fence_sync = vk_fence_get_active_sync(fence);
- result = vk_sync_move(&device->vk, fence_sync, sync);
- vk_sync_destroy(&device->vk, sync);
-
- return result;
-}
-
-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])
- vk_sync_destroy(&device->vk, dst[i]);
-
- dst[i] = src[i];
- }
- }
-}
-
-static VkResult pvr_process_cmd_buffer(
- struct pvr_device *device,
- struct pvr_queue *queue,
- VkCommandBuffer commandBuffer,
- struct vk_sync *barriers[static PVR_JOB_TYPE_MAX],
- struct vk_sync **waits,
- uint32_t wait_count,
- uint32_t *stage_flags,
- struct vk_sync *per_submit_syncobjs[static PVR_JOB_TYPE_MAX],
- struct vk_sync *queue_syncobjs[static PVR_JOB_TYPE_MAX],
- struct vk_sync *previous_queue_syncobjs[static PVR_JOB_TYPE_MAX])
+static VkResult pvr_process_cmd_buffer(struct pvr_device *device,
+ struct pvr_queue *queue,
+ struct pvr_cmd_buffer *cmd_buffer)
{
- struct vk_sync *per_cmd_buffer_syncobjs[PVR_JOB_TYPE_MAX] = {};
- PVR_FROM_HANDLE(pvr_cmd_buffer, cmd_buffer, commandBuffer);
VkResult result;
- assert(cmd_buffer->vk.state == MESA_VK_COMMAND_BUFFER_STATE_EXECUTABLE);
-
list_for_each_entry_safe (struct pvr_sub_cmd,
sub_cmd,
&cmd_buffer->sub_cmds,
*/
result = pvr_process_event_cmd_barrier(device,
- &frag_to_transfer_barrier,
- barriers,
- per_cmd_buffer_syncobjs,
- per_submit_syncobjs,
- queue_syncobjs,
- previous_queue_syncobjs);
+ queue,
+ &frag_to_transfer_barrier);
if (result != VK_SUCCESS)
break;
}
- result = pvr_process_graphics_cmd(device,
- queue,
- cmd_buffer,
- &sub_cmd->gfx,
- barriers[PVR_JOB_TYPE_GEOM],
- barriers[PVR_JOB_TYPE_FRAG],
- waits,
- wait_count,
- stage_flags,
- per_cmd_buffer_syncobjs);
+ result =
+ pvr_process_graphics_cmd(device, queue, cmd_buffer, &sub_cmd->gfx);
break;
}
case PVR_SUB_CMD_TYPE_COMPUTE:
- result = pvr_process_compute_cmd(device,
- queue,
- &sub_cmd->compute,
- barriers[PVR_JOB_TYPE_COMPUTE],
- waits,
- wait_count,
- stage_flags,
- per_cmd_buffer_syncobjs);
+ result = pvr_process_compute_cmd(device, queue, &sub_cmd->compute);
break;
case PVR_SUB_CMD_TYPE_TRANSFER: {
};
result = pvr_process_event_cmd_barrier(device,
- &frag_to_transfer_barrier,
- barriers,
- per_cmd_buffer_syncobjs,
- per_submit_syncobjs,
- queue_syncobjs,
- previous_queue_syncobjs);
+ queue,
+ &frag_to_transfer_barrier);
if (result != VK_SUCCESS)
break;
}
- result = pvr_process_transfer_cmds(device,
- queue,
- &sub_cmd->transfer,
- barriers[PVR_JOB_TYPE_TRANSFER],
- waits,
- wait_count,
- stage_flags,
- per_cmd_buffer_syncobjs);
+ result = pvr_process_transfer_cmds(device, queue, &sub_cmd->transfer);
if (serialize_with_frag) {
struct pvr_sub_cmd_event transfer_to_frag_barrier = {
break;
result = pvr_process_event_cmd_barrier(device,
- &transfer_to_frag_barrier,
- barriers,
- per_cmd_buffer_syncobjs,
- per_submit_syncobjs,
- queue_syncobjs,
- previous_queue_syncobjs);
+ queue,
+ &transfer_to_frag_barrier);
}
break;
}
case PVR_SUB_CMD_TYPE_OCCLUSION_QUERY:
- result = pvr_process_occlusion_query_cmd(
- device,
- queue,
- &sub_cmd->compute,
- barriers[PVR_JOB_TYPE_OCCLUSION_QUERY],
- waits,
- wait_count,
- stage_flags,
- per_cmd_buffer_syncobjs);
+ result =
+ pvr_process_occlusion_query_cmd(device, queue, &sub_cmd->compute);
break;
case PVR_SUB_CMD_TYPE_EVENT:
- result = pvr_process_event_cmd(device,
- &sub_cmd->event,
- barriers,
- per_cmd_buffer_syncobjs,
- per_submit_syncobjs,
- queue_syncobjs,
- previous_queue_syncobjs);
+ result = pvr_process_event_cmd(device, queue, &sub_cmd->event);
break;
default:
p_atomic_inc(&device->global_cmd_buffer_submit_count);
}
- pvr_update_syncobjs(device, per_cmd_buffer_syncobjs, per_submit_syncobjs);
-
return VK_SUCCESS;
}
-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])
+static VkResult pvr_clear_last_submits_syncs(struct pvr_queue *queue)
{
+ struct vk_sync_wait waits[PVR_JOB_TYPE_MAX * 2];
+ uint32_t wait_count = 0;
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 < PVR_JOB_TYPE_MAX; i++) {
+ if (queue->next_job_wait_sync[i]) {
+ waits[wait_count++] = (struct vk_sync_wait){
+ .sync = queue->next_job_wait_sync[i],
+ .stage_mask = ~(VkPipelineStageFlags2)0,
+ .wait_value = 0,
+ };
+ }
- /* 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++;
- }
+ if (queue->last_job_signal_sync[i]) {
+ waits[wait_count++] = (struct vk_sync_wait){
+ .sync = queue->last_job_signal_sync[i],
+ .stage_mask = ~(VkPipelineStageFlags2)0,
+ .wait_value = 0,
+ };
}
+ }
- if (per_job_waits_count == 0U)
- continue;
+ result = vk_sync_wait_many(&queue->device->vk,
+ wait_count,
+ waits,
+ VK_SYNC_WAIT_COMPLETE,
+ UINT64_MAX);
- result = vk_sync_create(&device->vk,
- &device->pdevice->ws->syncobj_type,
- 0U,
- 0UL,
- &completions[i]);
- if (result != VK_SUCCESS)
- goto err_destroy_completion_syncs;
+ if (result != VK_SUCCESS)
+ return vk_error(queue, result);
- 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;
+ for (uint32_t i = 0; i < PVR_JOB_TYPE_MAX; i++) {
+ if (queue->next_job_wait_sync[i]) {
+ vk_sync_destroy(&queue->device->vk, queue->next_job_wait_sync[i]);
+ queue->next_job_wait_sync[i] = NULL;
+ }
+
+ if (queue->last_job_signal_sync[i]) {
+ vk_sync_destroy(&queue->device->vk, queue->last_job_signal_sync[i]);
+ queue->last_job_signal_sync[i] = NULL;
+ }
}
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;
+static VkResult pvr_process_queue_signals(struct pvr_queue *queue,
+ struct vk_sync_signal *signals,
+ uint32_t signal_count)
+{
+ struct vk_sync_wait signal_waits[PVR_JOB_TYPE_MAX];
+ struct pvr_device *device = queue->device;
+ VkResult result;
+
+ for (uint32_t signal_idx = 0; signal_idx < signal_count; signal_idx++) {
+ struct vk_sync_signal *signal = &signals[signal_idx];
+ const enum pvr_pipeline_stage_bits signal_stage_src =
+ pvr_stage_mask_src(signal->stage_mask);
+ uint32_t wait_count = 0;
+
+ for (uint32_t i = 0; i < PVR_JOB_TYPE_MAX; i++) {
+ if (!(signal_stage_src & BITFIELD_BIT(i)) ||
+ !queue->last_job_signal_sync[i])
+ continue;
+
+ signal_waits[wait_count++] = (struct vk_sync_wait){
+ .sync = queue->last_job_signal_sync[i],
+ .stage_mask = ~(VkPipelineStageFlags2)0,
+ .wait_value = 0,
+ };
}
+
+ result = device->ws->ops->null_job_submit(device->ws,
+ signal_waits,
+ wait_count,
+ signal);
+ if (result != VK_SUCCESS)
+ return result;
}
- return result;
+ return VK_SUCCESS;
}
-VkResult pvr_QueueSubmit(VkQueue _queue,
- uint32_t submitCount,
- const VkSubmitInfo *pSubmits,
- VkFence fence)
+static VkResult pvr_process_queue_waits(struct pvr_queue *queue,
+ struct vk_sync_wait *waits,
+ uint32_t wait_count)
{
- PVR_FROM_HANDLE(pvr_queue, queue, _queue);
- struct vk_sync *completion_syncobjs[PVR_JOB_TYPE_MAX] = {};
struct pvr_device *device = queue->device;
VkResult result;
- 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;
+ STACK_ARRAY(struct vk_sync_wait, stage_waits, wait_count);
+ if (!stage_waits)
+ return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
- 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);
+ for (uint32_t i = 0; i < PVR_JOB_TYPE_MAX; i++) {
+ struct vk_sync_signal next_job_wait_signal_sync;
+ uint32_t stage_wait_count = 0;
- if (sync->type == &vk_sync_dummy_type)
+ for (uint32_t wait_idx = 0; wait_idx < wait_count; wait_idx++) {
+ if (!(pvr_stage_mask(waits[wait_idx].stage_mask) & BITFIELD_BIT(i)))
continue;
- /* We don't currently support timeline semaphores. */
- assert(!(sync->flags & VK_SYNC_IS_TIMELINE));
-
- stage_flags[wait_count] =
- pvr_stage_mask_dst(desc->pWaitDstStageMask[j]);
- waits[wait_count] = vk_semaphore_get_active_sync(semaphore);
- wait_count++;
+ stage_waits[stage_wait_count++] = (struct vk_sync_wait){
+ .sync = waits[wait_idx].sync,
+ .stage_mask = ~(VkPipelineStageFlags2)0,
+ .wait_value = waits[wait_idx].wait_value,
+ };
}
- if (desc->commandBufferCount > 0U) {
- for (uint32_t j = 0U; j < desc->commandBufferCount; j++) {
- result = pvr_process_cmd_buffer(device,
- queue,
- desc->pCommandBuffers[j],
- queue->job_dependancy,
- waits,
- wait_count,
- stage_flags,
- per_submit_completion_syncobjs,
- completion_syncobjs,
- queue->completion);
- if (result != VK_SUCCESS)
- return result;
- }
- } else {
- result = pvr_submit_null_job(device,
- waits,
- wait_count,
- stage_flags,
- per_submit_completion_syncobjs);
- if (result != VK_SUCCESS)
- return result;
- }
+ result = vk_sync_create(&device->vk,
+ &device->pdevice->ws->syncobj_type,
+ 0U,
+ 0UL,
+ &queue->next_job_wait_sync[i]);
+ if (result != VK_SUCCESS)
+ goto err_free_waits;
- if (desc->signalSemaphoreCount) {
- result = pvr_set_semaphore_payloads(device,
- per_submit_completion_syncobjs,
- desc->pSignalSemaphores,
- desc->signalSemaphoreCount);
- if (result != VK_SUCCESS)
- return result;
- }
+ next_job_wait_signal_sync = (struct vk_sync_signal){
+ .sync = queue->next_job_wait_sync[i],
+ .stage_mask = ~(VkPipelineStageFlags2)0,
+ .signal_value = 0,
+ };
- pvr_update_syncobjs(device,
- per_submit_completion_syncobjs,
- completion_syncobjs);
+ result = device->ws->ops->null_job_submit(device->ws,
+ stage_waits,
+ stage_wait_count,
+ &next_job_wait_signal_sync);
+ if (result != VK_SUCCESS)
+ goto err_free_waits;
}
- if (fence) {
- result = pvr_set_fence_payload(device, completion_syncobjs, fence);
+ STACK_ARRAY_FINISH(stage_waits);
+
+ return VK_SUCCESS;
+
+err_free_waits:
+ STACK_ARRAY_FINISH(stage_waits);
+
+ return result;
+}
+
+static VkResult pvr_driver_queue_submit(struct vk_queue *queue,
+ struct vk_queue_submit *submit)
+{
+ struct pvr_queue *driver_queue = container_of(queue, struct pvr_queue, vk);
+ struct pvr_device *device = driver_queue->device;
+ VkResult result;
+
+ result = pvr_clear_last_submits_syncs(driver_queue);
+ if (result != VK_SUCCESS)
+ return result;
+
+ result =
+ pvr_process_queue_waits(driver_queue, submit->waits, submit->wait_count);
+ if (result != VK_SUCCESS)
+ return result;
+
+ for (uint32_t i = 0U; i < submit->command_buffer_count; i++) {
+ result = pvr_process_cmd_buffer(
+ device,
+ driver_queue,
+ container_of(submit->command_buffers[i], struct pvr_cmd_buffer, vk));
if (result != VK_SUCCESS)
return result;
}
- pvr_update_syncobjs(device, completion_syncobjs, queue->completion);
+ result = pvr_process_queue_signals(driver_queue,
+ submit->signals,
+ submit->signal_count);
+ if (result != VK_SUCCESS)
+ return result;
return VK_SUCCESS;
}